diff options
Diffstat (limited to 'drivers')
712 files changed, 25208 insertions, 10300 deletions
diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c index 43a95e5640d..5b73f6a2cd8 100644 --- a/drivers/acpi/ac.c +++ b/drivers/acpi/ac.c @@ -92,6 +92,7 @@ struct acpi_ac { #ifdef CONFIG_ACPI_PROCFS_POWER static const struct file_operations acpi_ac_fops = { + .owner = THIS_MODULE, .open = acpi_ac_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -195,16 +196,11 @@ static int acpi_ac_add_fs(struct acpi_device *device) } /* 'state' [R] */ - entry = create_proc_entry(ACPI_AC_FILE_STATE, - S_IRUGO, acpi_device_dir(device)); + entry = proc_create_data(ACPI_AC_FILE_STATE, + S_IRUGO, acpi_device_dir(device), + &acpi_ac_fops, acpi_driver_data(device)); if (!entry) return -ENODEV; - else { - entry->proc_fops = &acpi_ac_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } - return 0; } diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index d5729d5dc19..b1c723f9f58 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -741,15 +741,13 @@ static int acpi_battery_add_fs(struct acpi_device *device) } for (i = 0; i < ACPI_BATTERY_NUMFILES; ++i) { - entry = create_proc_entry(acpi_battery_file[i].name, - acpi_battery_file[i].mode, acpi_device_dir(device)); + entry = proc_create_data(acpi_battery_file[i].name, + acpi_battery_file[i].mode, + acpi_device_dir(device), + &acpi_battery_file[i].ops, + acpi_driver_data(device)); if (!entry) return -ENODEV; - else { - entry->proc_fops = &acpi_battery_file[i].ops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } } return 0; } diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 2d1955c1183..a6dbcf4d9ef 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -35,6 +35,7 @@ #ifdef CONFIG_X86 #include <asm/mpspec.h> #endif +#include <linux/pci.h> #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h> @@ -784,6 +785,7 @@ static int __init acpi_init(void) result = acpi_bus_init(); if (!result) { + pci_mmcfg_late_init(); if (!(pm_flags & PM_APM)) pm_flags |= PM_ACPI; else { diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index 6c5da83cdb6..1dfec413588 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -102,6 +102,7 @@ struct acpi_button { }; static const struct file_operations acpi_button_info_fops = { + .owner = THIS_MODULE, .open = acpi_button_info_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -109,6 +110,7 @@ static const struct file_operations acpi_button_info_fops = { }; static const struct file_operations acpi_button_state_fops = { + .owner = THIS_MODULE, .open = acpi_button_state_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -207,27 +209,21 @@ static int acpi_button_add_fs(struct acpi_device *device) acpi_device_dir(device)->owner = THIS_MODULE; /* 'info' [R] */ - entry = create_proc_entry(ACPI_BUTTON_FILE_INFO, - S_IRUGO, acpi_device_dir(device)); + entry = proc_create_data(ACPI_BUTTON_FILE_INFO, + S_IRUGO, acpi_device_dir(device), + &acpi_button_info_fops, + acpi_driver_data(device)); if (!entry) return -ENODEV; - else { - entry->proc_fops = &acpi_button_info_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } /* show lid state [R] */ if (button->type == ACPI_BUTTON_TYPE_LID) { - entry = create_proc_entry(ACPI_BUTTON_FILE_STATE, - S_IRUGO, acpi_device_dir(device)); + entry = proc_create_data(ACPI_BUTTON_FILE_STATE, + S_IRUGO, acpi_device_dir(device), + &acpi_button_state_fops, + acpi_driver_data(device)); if (!entry) return -ENODEV; - else { - entry->proc_fops = &acpi_button_state_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } } return 0; diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 7222a18a031..e3f04b272f3 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -669,16 +669,11 @@ static int acpi_ec_add_fs(struct acpi_device *device) return -ENODEV; } - entry = create_proc_entry(ACPI_EC_FILE_INFO, S_IRUGO, - acpi_device_dir(device)); + entry = proc_create_data(ACPI_EC_FILE_INFO, S_IRUGO, + acpi_device_dir(device), + &acpi_ec_info_ops, acpi_driver_data(device)); if (!entry) return -ENODEV; - else { - entry->proc_fops = &acpi_ec_info_ops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } - return 0; } diff --git a/drivers/acpi/event.c b/drivers/acpi/event.c index abec1ca94cf..0c24bd4d656 100644 --- a/drivers/acpi/event.c +++ b/drivers/acpi/event.c @@ -102,6 +102,7 @@ static unsigned int acpi_system_poll_event(struct file *file, poll_table * wait) } static const struct file_operations acpi_system_event_ops = { + .owner = THIS_MODULE, .open = acpi_system_open_event, .read = acpi_system_read_event, .release = acpi_system_close_event, @@ -294,10 +295,9 @@ static int __init acpi_event_init(void) #ifdef CONFIG_ACPI_PROC_EVENT /* 'event' [R] */ - entry = create_proc_entry("event", S_IRUSR, acpi_root_dir); - if (entry) - entry->proc_fops = &acpi_system_event_ops; - else + entry = proc_create("event", S_IRUSR, acpi_root_dir, + &acpi_system_event_ops); + if (!entry) return -ENODEV; #endif diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c index c8e3cba423e..194077ab9b8 100644 --- a/drivers/acpi/fan.c +++ b/drivers/acpi/fan.c @@ -192,17 +192,13 @@ static int acpi_fan_add_fs(struct acpi_device *device) } /* 'status' [R/W] */ - entry = create_proc_entry(ACPI_FAN_FILE_STATE, - S_IFREG | S_IRUGO | S_IWUSR, - acpi_device_dir(device)); + entry = proc_create_data(ACPI_FAN_FILE_STATE, + S_IFREG | S_IRUGO | S_IWUSR, + acpi_device_dir(device), + &acpi_fan_state_ops, + device); if (!entry) return -ENODEV; - else { - entry->proc_fops = &acpi_fan_state_ops; - entry->data = device; - entry->owner = THIS_MODULE; - } - return 0; } diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 76bf6d90c70..21fc8bf0d31 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -93,6 +93,7 @@ struct acpi_power_resource { static struct list_head acpi_power_resource_list; static const struct file_operations acpi_power_fops = { + .owner = THIS_MODULE, .open = acpi_power_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -543,15 +544,11 @@ static int acpi_power_add_fs(struct acpi_device *device) } /* 'status' [R] */ - entry = create_proc_entry(ACPI_POWER_FILE_STATUS, - S_IRUGO, acpi_device_dir(device)); + entry = proc_create_data(ACPI_POWER_FILE_STATUS, + S_IRUGO, acpi_device_dir(device), + &acpi_power_fops, acpi_driver_data(device)); if (!entry) return -EIO; - else { - entry->proc_fops = &acpi_power_fops; - entry->data = acpi_driver_data(device); - } - return 0; } diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index a825b431b64..dd28c912e84 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -112,6 +112,7 @@ static struct acpi_driver acpi_processor_driver = { #define UNINSTALL_NOTIFY_HANDLER 2 static const struct file_operations acpi_processor_info_fops = { + .owner = THIS_MODULE, .open = acpi_processor_info_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -326,40 +327,30 @@ static int acpi_processor_add_fs(struct acpi_device *device) acpi_device_dir(device)->owner = THIS_MODULE; /* 'info' [R] */ - entry = create_proc_entry(ACPI_PROCESSOR_FILE_INFO, - S_IRUGO, acpi_device_dir(device)); + entry = proc_create_data(ACPI_PROCESSOR_FILE_INFO, + S_IRUGO, acpi_device_dir(device), + &acpi_processor_info_fops, + acpi_driver_data(device)); if (!entry) return -EIO; - else { - entry->proc_fops = &acpi_processor_info_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } /* 'throttling' [R/W] */ - entry = create_proc_entry(ACPI_PROCESSOR_FILE_THROTTLING, - S_IFREG | S_IRUGO | S_IWUSR, - acpi_device_dir(device)); + entry = proc_create_data(ACPI_PROCESSOR_FILE_THROTTLING, + S_IFREG | S_IRUGO | S_IWUSR, + acpi_device_dir(device), + &acpi_processor_throttling_fops, + acpi_driver_data(device)); if (!entry) return -EIO; - else { - entry->proc_fops = &acpi_processor_throttling_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } /* 'limit' [R/W] */ - entry = create_proc_entry(ACPI_PROCESSOR_FILE_LIMIT, - S_IFREG | S_IRUGO | S_IWUSR, - acpi_device_dir(device)); + entry = proc_create_data(ACPI_PROCESSOR_FILE_LIMIT, + S_IFREG | S_IRUGO | S_IWUSR, + acpi_device_dir(device), + &acpi_processor_limit_fops, + acpi_driver_data(device)); if (!entry) return -EIO; - else { - entry->proc_fops = &acpi_processor_limit_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } - return 0; } diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 0d90ff5fd11..789d4947ed3 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -1282,6 +1282,7 @@ static int acpi_processor_power_open_fs(struct inode *inode, struct file *file) } static const struct file_operations acpi_processor_power_fops = { + .owner = THIS_MODULE, .open = acpi_processor_power_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -1822,16 +1823,12 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr, } /* 'power' [R] */ - entry = create_proc_entry(ACPI_PROCESSOR_FILE_POWER, - S_IRUGO, acpi_device_dir(device)); + entry = proc_create_data(ACPI_PROCESSOR_FILE_POWER, + S_IRUGO, acpi_device_dir(device), + &acpi_processor_power_fops, + acpi_driver_data(device)); if (!entry) return -EIO; - else { - entry->proc_fops = &acpi_processor_power_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } - return 0; } diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index b477a4be8a6..d80b2d1441a 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c @@ -411,6 +411,7 @@ EXPORT_SYMBOL(acpi_processor_notify_smm); static int acpi_processor_perf_open_fs(struct inode *inode, struct file *file); static struct file_operations acpi_processor_perf_fops = { + .owner = THIS_MODULE, .open = acpi_processor_perf_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -456,7 +457,6 @@ static int acpi_processor_perf_open_fs(struct inode *inode, struct file *file) static void acpi_cpufreq_add_file(struct acpi_processor *pr) { - struct proc_dir_entry *entry = NULL; struct acpi_device *device = NULL; @@ -464,14 +464,9 @@ static void acpi_cpufreq_add_file(struct acpi_processor *pr) return; /* add file 'performance' [R/W] */ - entry = create_proc_entry(ACPI_PROCESSOR_FILE_PERFORMANCE, - S_IFREG | S_IRUGO, - acpi_device_dir(device)); - if (entry){ - entry->proc_fops = &acpi_processor_perf_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } + proc_create_data(ACPI_PROCESSOR_FILE_PERFORMANCE, S_IFREG | S_IRUGO, + acpi_device_dir(device), + &acpi_processor_perf_fops, acpi_driver_data(device)); return; } diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c index 9cb43f52f7b..ef34b18f95c 100644 --- a/drivers/acpi/processor_thermal.c +++ b/drivers/acpi/processor_thermal.c @@ -97,7 +97,7 @@ static int acpi_processor_apply_limit(struct acpi_processor *pr) #define CPUFREQ_THERMAL_MIN_STEP 0 #define CPUFREQ_THERMAL_MAX_STEP 3 -static unsigned int cpufreq_thermal_reduction_pctg[NR_CPUS]; +static DEFINE_PER_CPU(unsigned int, cpufreq_thermal_reduction_pctg); static unsigned int acpi_thermal_cpufreq_is_init = 0; static int cpu_has_cpufreq(unsigned int cpu) @@ -113,9 +113,9 @@ static int acpi_thermal_cpufreq_increase(unsigned int cpu) if (!cpu_has_cpufreq(cpu)) return -ENODEV; - if (cpufreq_thermal_reduction_pctg[cpu] < + if (per_cpu(cpufreq_thermal_reduction_pctg, cpu) < CPUFREQ_THERMAL_MAX_STEP) { - cpufreq_thermal_reduction_pctg[cpu]++; + per_cpu(cpufreq_thermal_reduction_pctg, cpu)++; cpufreq_update_policy(cpu); return 0; } @@ -128,14 +128,14 @@ static int acpi_thermal_cpufreq_decrease(unsigned int cpu) if (!cpu_has_cpufreq(cpu)) return -ENODEV; - if (cpufreq_thermal_reduction_pctg[cpu] > + if (per_cpu(cpufreq_thermal_reduction_pctg, cpu) > (CPUFREQ_THERMAL_MIN_STEP + 1)) - cpufreq_thermal_reduction_pctg[cpu]--; + per_cpu(cpufreq_thermal_reduction_pctg, cpu)--; else - cpufreq_thermal_reduction_pctg[cpu] = 0; + per_cpu(cpufreq_thermal_reduction_pctg, cpu) = 0; cpufreq_update_policy(cpu); /* We reached max freq again and can leave passive mode */ - return !cpufreq_thermal_reduction_pctg[cpu]; + return !per_cpu(cpufreq_thermal_reduction_pctg, cpu); } static int acpi_thermal_cpufreq_notifier(struct notifier_block *nb, @@ -147,9 +147,10 @@ static int acpi_thermal_cpufreq_notifier(struct notifier_block *nb, if (event != CPUFREQ_ADJUST) goto out; - max_freq = - (policy->cpuinfo.max_freq * - (100 - cpufreq_thermal_reduction_pctg[policy->cpu] * 20)) / 100; + max_freq = ( + policy->cpuinfo.max_freq * + (100 - per_cpu(cpufreq_thermal_reduction_pctg, policy->cpu) * 20) + ) / 100; cpufreq_verify_within_limits(policy, 0, max_freq); @@ -174,7 +175,7 @@ static int cpufreq_get_cur_state(unsigned int cpu) if (!cpu_has_cpufreq(cpu)) return 0; - return cpufreq_thermal_reduction_pctg[cpu]; + return per_cpu(cpufreq_thermal_reduction_pctg, cpu); } static int cpufreq_set_cur_state(unsigned int cpu, int state) @@ -182,7 +183,7 @@ static int cpufreq_set_cur_state(unsigned int cpu, int state) if (!cpu_has_cpufreq(cpu)) return 0; - cpufreq_thermal_reduction_pctg[cpu] = state; + per_cpu(cpufreq_thermal_reduction_pctg, cpu) = state; cpufreq_update_policy(cpu); return 0; } @@ -191,8 +192,9 @@ void acpi_thermal_cpufreq_init(void) { int i; - for (i = 0; i < NR_CPUS; i++) - cpufreq_thermal_reduction_pctg[i] = 0; + for (i = 0; i < nr_cpu_ids; i++) + if (cpu_present(i)) + per_cpu(cpufreq_thermal_reduction_pctg, i) = 0; i = cpufreq_register_notifier(&acpi_thermal_cpufreq_notifier_block, CPUFREQ_POLICY_NOTIFIER); @@ -507,6 +509,7 @@ static ssize_t acpi_processor_write_limit(struct file * file, } struct file_operations acpi_processor_limit_fops = { + .owner = THIS_MODULE, .open = acpi_processor_limit_open_fs, .read = seq_read, .write = acpi_processor_write_limit, diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c index 0bba3a914e8..bb06738860c 100644 --- a/drivers/acpi/processor_throttling.c +++ b/drivers/acpi/processor_throttling.c @@ -1252,6 +1252,7 @@ static ssize_t acpi_processor_write_throttling(struct file *file, } struct file_operations acpi_processor_throttling_fops = { + .owner = THIS_MODULE, .open = acpi_processor_throttling_open_fs, .read = seq_read, .write = acpi_processor_write_throttling, diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c index 585ae3c9c8e..10a36512647 100644 --- a/drivers/acpi/sbs.c +++ b/drivers/acpi/sbs.c @@ -483,8 +483,6 @@ acpi_sbs_add_fs(struct proc_dir_entry **dir, struct file_operations *state_fops, struct file_operations *alarm_fops, void *data) { - struct proc_dir_entry *entry = NULL; - if (!*dir) { *dir = proc_mkdir(dir_name, parent_dir); if (!*dir) { @@ -494,34 +492,19 @@ acpi_sbs_add_fs(struct proc_dir_entry **dir, } /* 'info' [R] */ - if (info_fops) { - entry = create_proc_entry(ACPI_SBS_FILE_INFO, S_IRUGO, *dir); - if (entry) { - entry->proc_fops = info_fops; - entry->data = data; - entry->owner = THIS_MODULE; - } - } + if (info_fops) + proc_create_data(ACPI_SBS_FILE_INFO, S_IRUGO, *dir, + info_fops, data); /* 'state' [R] */ - if (state_fops) { - entry = create_proc_entry(ACPI_SBS_FILE_STATE, S_IRUGO, *dir); - if (entry) { - entry->proc_fops = state_fops; - entry->data = data; - entry->owner = THIS_MODULE; - } - } + if (state_fops) + proc_create_data(ACPI_SBS_FILE_STATE, S_IRUGO, *dir, + state_fops, data); /* 'alarm' [R/W] */ - if (alarm_fops) { - entry = create_proc_entry(ACPI_SBS_FILE_ALARM, S_IRUGO, *dir); - if (entry) { - entry->proc_fops = alarm_fops; - entry->data = data; - entry->owner = THIS_MODULE; - } - } + if (alarm_fops) + proc_create_data(ACPI_SBS_FILE_ALARM, S_IRUGO, *dir, + alarm_fops, data); return 0; } diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/sleep/proc.c index f8df5217d47..8a5fe871051 100644 --- a/drivers/acpi/sleep/proc.c +++ b/drivers/acpi/sleep/proc.c @@ -440,6 +440,7 @@ acpi_system_wakeup_device_open_fs(struct inode *inode, struct file *file) } static const struct file_operations acpi_system_wakeup_device_fops = { + .owner = THIS_MODULE, .open = acpi_system_wakeup_device_open_fs, .read = seq_read, .write = acpi_system_write_wakeup_device, @@ -449,6 +450,7 @@ static const struct file_operations acpi_system_wakeup_device_fops = { #ifdef CONFIG_ACPI_PROCFS static const struct file_operations acpi_system_sleep_fops = { + .owner = THIS_MODULE, .open = acpi_system_sleep_open_fs, .read = seq_read, .write = acpi_system_write_sleep, @@ -459,6 +461,7 @@ static const struct file_operations acpi_system_sleep_fops = { #ifdef HAVE_ACPI_LEGACY_ALARM static const struct file_operations acpi_system_alarm_fops = { + .owner = THIS_MODULE, .open = acpi_system_alarm_open_fs, .read = seq_read, .write = acpi_system_write_alarm, @@ -477,37 +480,26 @@ static u32 rtc_handler(void *context) static int __init acpi_sleep_proc_init(void) { - struct proc_dir_entry *entry = NULL; - if (acpi_disabled) return 0; #ifdef CONFIG_ACPI_PROCFS /* 'sleep' [R/W] */ - entry = - create_proc_entry("sleep", S_IFREG | S_IRUGO | S_IWUSR, - acpi_root_dir); - if (entry) - entry->proc_fops = &acpi_system_sleep_fops; + proc_create("sleep", S_IFREG | S_IRUGO | S_IWUSR, + acpi_root_dir, &acpi_system_sleep_fops); #endif /* CONFIG_ACPI_PROCFS */ #ifdef HAVE_ACPI_LEGACY_ALARM /* 'alarm' [R/W] */ - entry = - create_proc_entry("alarm", S_IFREG | S_IRUGO | S_IWUSR, - acpi_root_dir); - if (entry) - entry->proc_fops = &acpi_system_alarm_fops; + proc_create("alarm", S_IFREG | S_IRUGO | S_IWUSR, + acpi_root_dir, &acpi_system_alarm_fops); acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, NULL); #endif /* HAVE_ACPI_LEGACY_ALARM */ /* 'wakeup device' [R/W] */ - entry = - create_proc_entry("wakeup", S_IFREG | S_IRUGO | S_IWUSR, - acpi_root_dir); - if (entry) - entry->proc_fops = &acpi_system_wakeup_device_fops; + proc_create("wakeup", S_IFREG | S_IRUGO | S_IWUSR, + acpi_root_dir, &acpi_system_wakeup_device_fops); return 0; } diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c index 4749f379a91..769f24855eb 100644 --- a/drivers/acpi/system.c +++ b/drivers/acpi/system.c @@ -396,6 +396,7 @@ static int acpi_system_info_open_fs(struct inode *inode, struct file *file) } static const struct file_operations acpi_system_info_ops = { + .owner = THIS_MODULE, .open = acpi_system_info_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -406,6 +407,7 @@ static ssize_t acpi_system_read_dsdt(struct file *, char __user *, size_t, loff_t *); static const struct file_operations acpi_system_dsdt_ops = { + .owner = THIS_MODULE, .read = acpi_system_read_dsdt, }; @@ -430,6 +432,7 @@ static ssize_t acpi_system_read_fadt(struct file *, char __user *, size_t, loff_t *); static const struct file_operations acpi_system_fadt_ops = { + .owner = THIS_MODULE, .read = acpi_system_read_fadt, }; @@ -454,31 +457,23 @@ static int acpi_system_procfs_init(void) { struct proc_dir_entry *entry; int error = 0; - char *name; /* 'info' [R] */ - name = ACPI_SYSTEM_FILE_INFO; - entry = create_proc_entry(name, S_IRUGO, acpi_root_dir); + entry = proc_create(ACPI_SYSTEM_FILE_INFO, S_IRUGO, acpi_root_dir, + &acpi_system_info_ops); if (!entry) goto Error; - else { - entry->proc_fops = &acpi_system_info_ops; - } /* 'dsdt' [R] */ - name = ACPI_SYSTEM_FILE_DSDT; - entry = create_proc_entry(name, S_IRUSR, acpi_root_dir); - if (entry) - entry->proc_fops = &acpi_system_dsdt_ops; - else + entry = proc_create(ACPI_SYSTEM_FILE_DSDT, S_IRUSR, acpi_root_dir, + &acpi_system_dsdt_ops); + if (!entry) goto Error; /* 'fadt' [R] */ - name = ACPI_SYSTEM_FILE_FADT; - entry = create_proc_entry(name, S_IRUSR, acpi_root_dir); - if (entry) - entry->proc_fops = &acpi_system_fadt_ops; - else + entry = proc_create(ACPI_SYSTEM_FILE_FADT, S_IRUSR, acpi_root_dir, + &acpi_system_fadt_ops); + if (!entry) goto Error; Done: diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 1bcecc7dd2c..0815ac3ae3d 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -198,6 +198,7 @@ struct acpi_thermal { }; static const struct file_operations acpi_thermal_state_fops = { + .owner = THIS_MODULE, .open = acpi_thermal_state_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -205,6 +206,7 @@ static const struct file_operations acpi_thermal_state_fops = { }; static const struct file_operations acpi_thermal_temp_fops = { + .owner = THIS_MODULE, .open = acpi_thermal_temp_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -212,6 +214,7 @@ static const struct file_operations acpi_thermal_temp_fops = { }; static const struct file_operations acpi_thermal_trip_fops = { + .owner = THIS_MODULE, .open = acpi_thermal_trip_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -219,6 +222,7 @@ static const struct file_operations acpi_thermal_trip_fops = { }; static const struct file_operations acpi_thermal_cooling_fops = { + .owner = THIS_MODULE, .open = acpi_thermal_cooling_open_fs, .read = seq_read, .write = acpi_thermal_write_cooling_mode, @@ -227,6 +231,7 @@ static const struct file_operations acpi_thermal_cooling_fops = { }; static const struct file_operations acpi_thermal_polling_fops = { + .owner = THIS_MODULE, .open = acpi_thermal_polling_open_fs, .read = seq_read, .write = acpi_thermal_write_polling, @@ -1419,63 +1424,47 @@ static int acpi_thermal_add_fs(struct acpi_device *device) } /* 'state' [R] */ - entry = create_proc_entry(ACPI_THERMAL_FILE_STATE, - S_IRUGO, acpi_device_dir(device)); + entry = proc_create_data(ACPI_THERMAL_FILE_STATE, + S_IRUGO, acpi_device_dir(device), + &acpi_thermal_state_fops, + acpi_driver_data(device)); if (!entry) return -ENODEV; - else { - entry->proc_fops = &acpi_thermal_state_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } /* 'temperature' [R] */ - entry = create_proc_entry(ACPI_THERMAL_FILE_TEMPERATURE, - S_IRUGO, acpi_device_dir(device)); + entry = proc_create_data(ACPI_THERMAL_FILE_TEMPERATURE, + S_IRUGO, acpi_device_dir(device), + &acpi_thermal_temp_fops, + acpi_driver_data(device)); if (!entry) return -ENODEV; - else { - entry->proc_fops = &acpi_thermal_temp_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } /* 'trip_points' [R] */ - entry = create_proc_entry(ACPI_THERMAL_FILE_TRIP_POINTS, - S_IRUGO, - acpi_device_dir(device)); + entry = proc_create_data(ACPI_THERMAL_FILE_TRIP_POINTS, + S_IRUGO, + acpi_device_dir(device), + &acpi_thermal_trip_fops, + acpi_driver_data(device)); if (!entry) return -ENODEV; - else { - entry->proc_fops = &acpi_thermal_trip_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } /* 'cooling_mode' [R/W] */ - entry = create_proc_entry(ACPI_THERMAL_FILE_COOLING_MODE, - S_IFREG | S_IRUGO | S_IWUSR, - acpi_device_dir(device)); + entry = proc_create_data(ACPI_THERMAL_FILE_COOLING_MODE, + S_IFREG | S_IRUGO | S_IWUSR, + acpi_device_dir(device), + &acpi_thermal_cooling_fops, + acpi_driver_data(device)); if (!entry) return -ENODEV; - else { - entry->proc_fops = &acpi_thermal_cooling_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } /* 'polling_frequency' [R/W] */ - entry = create_proc_entry(ACPI_THERMAL_FILE_POLLING_FREQ, - S_IFREG | S_IRUGO | S_IWUSR, - acpi_device_dir(device)); + entry = proc_create_data(ACPI_THERMAL_FILE_POLLING_FREQ, + S_IFREG | S_IRUGO | S_IWUSR, + acpi_device_dir(device), + &acpi_thermal_polling_fops, + acpi_driver_data(device)); if (!entry) return -ENODEV; - else { - entry->proc_fops = &acpi_thermal_polling_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } - return 0; } @@ -1710,7 +1699,6 @@ static int acpi_thermal_resume(struct acpi_device *device) return AE_OK; } -#ifdef CONFIG_DMI static int thermal_act(const struct dmi_system_id *d) { if (act == 0) { @@ -1785,7 +1773,6 @@ static struct dmi_system_id thermal_dmi_table[] __initdata = { }, {} }; -#endif /* CONFIG_DMI */ static int __init acpi_thermal_init(void) { diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 980a7418878..43b228314a8 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -192,6 +192,7 @@ struct acpi_video_device { /* bus */ static int acpi_video_bus_info_open_fs(struct inode *inode, struct file *file); static struct file_operations acpi_video_bus_info_fops = { + .owner = THIS_MODULE, .open = acpi_video_bus_info_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -200,6 +201,7 @@ static struct file_operations acpi_video_bus_info_fops = { static int acpi_video_bus_ROM_open_fs(struct inode *inode, struct file *file); static struct file_operations acpi_video_bus_ROM_fops = { + .owner = THIS_MODULE, .open = acpi_video_bus_ROM_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -209,6 +211,7 @@ static struct file_operations acpi_video_bus_ROM_fops = { static int acpi_video_bus_POST_info_open_fs(struct inode *inode, struct file *file); static struct file_operations acpi_video_bus_POST_info_fops = { + .owner = THIS_MODULE, .open = acpi_video_bus_POST_info_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -217,6 +220,7 @@ static struct file_operations acpi_video_bus_POST_info_fops = { static int acpi_video_bus_POST_open_fs(struct inode *inode, struct file *file); static struct file_operations acpi_video_bus_POST_fops = { + .owner = THIS_MODULE, .open = acpi_video_bus_POST_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -225,6 +229,7 @@ static struct file_operations acpi_video_bus_POST_fops = { static int acpi_video_bus_DOS_open_fs(struct inode *inode, struct file *file); static struct file_operations acpi_video_bus_DOS_fops = { + .owner = THIS_MODULE, .open = acpi_video_bus_DOS_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -235,6 +240,7 @@ static struct file_operations acpi_video_bus_DOS_fops = { static int acpi_video_device_info_open_fs(struct inode *inode, struct file *file); static struct file_operations acpi_video_device_info_fops = { + .owner = THIS_MODULE, .open = acpi_video_device_info_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -244,6 +250,7 @@ static struct file_operations acpi_video_device_info_fops = { static int acpi_video_device_state_open_fs(struct inode *inode, struct file *file); static struct file_operations acpi_video_device_state_fops = { + .owner = THIS_MODULE, .open = acpi_video_device_state_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -253,6 +260,7 @@ static struct file_operations acpi_video_device_state_fops = { static int acpi_video_device_brightness_open_fs(struct inode *inode, struct file *file); static struct file_operations acpi_video_device_brightness_fops = { + .owner = THIS_MODULE, .open = acpi_video_device_brightness_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -262,6 +270,7 @@ static struct file_operations acpi_video_device_brightness_fops = { static int acpi_video_device_EDID_open_fs(struct inode *inode, struct file *file); static struct file_operations acpi_video_device_EDID_fops = { + .owner = THIS_MODULE, .open = acpi_video_device_EDID_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -1070,51 +1079,36 @@ static int acpi_video_device_add_fs(struct acpi_device *device) } /* 'info' [R] */ - entry = create_proc_entry("info", S_IRUGO, acpi_device_dir(device)); + entry = proc_create_data("info", S_IRUGO, acpi_device_dir(device), + &acpi_video_device_info_fops, acpi_driver_data(device)); if (!entry) return -ENODEV; - else { - entry->proc_fops = &acpi_video_device_info_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } /* 'state' [R/W] */ - entry = - create_proc_entry("state", S_IFREG | S_IRUGO | S_IWUSR, - acpi_device_dir(device)); + acpi_video_device_state_fops.write = acpi_video_device_write_state; + entry = proc_create_data("state", S_IFREG | S_IRUGO | S_IWUSR, + acpi_device_dir(device), + &acpi_video_device_state_fops, + acpi_driver_data(device)); if (!entry) return -ENODEV; - else { - acpi_video_device_state_fops.write = acpi_video_device_write_state; - entry->proc_fops = &acpi_video_device_state_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } /* 'brightness' [R/W] */ - entry = - create_proc_entry("brightness", S_IFREG | S_IRUGO | S_IWUSR, - acpi_device_dir(device)); + acpi_video_device_brightness_fops.write = + acpi_video_device_write_brightness; + entry = proc_create_data("brightness", S_IFREG | S_IRUGO | S_IWUSR, + acpi_device_dir(device), + &acpi_video_device_brightness_fops, + acpi_driver_data(device)); if (!entry) return -ENODEV; - else { - acpi_video_device_brightness_fops.write = acpi_video_device_write_brightness; - entry->proc_fops = &acpi_video_device_brightness_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } /* 'EDID' [R] */ - entry = create_proc_entry("EDID", S_IRUGO, acpi_device_dir(device)); + entry = proc_create_data("EDID", S_IRUGO, acpi_device_dir(device), + &acpi_video_device_EDID_fops, + acpi_driver_data(device)); if (!entry) return -ENODEV; - else { - entry->proc_fops = &acpi_video_device_EDID_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } - return 0; } @@ -1353,61 +1347,43 @@ static int acpi_video_bus_add_fs(struct acpi_device *device) } /* 'info' [R] */ - entry = create_proc_entry("info", S_IRUGO, acpi_device_dir(device)); + entry = proc_create_data("info", S_IRUGO, acpi_device_dir(device), + &acpi_video_bus_info_fops, + acpi_driver_data(device)); if (!entry) return -ENODEV; - else { - entry->proc_fops = &acpi_video_bus_info_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } /* 'ROM' [R] */ - entry = create_proc_entry("ROM", S_IRUGO, acpi_device_dir(device)); + entry = proc_create_data("ROM", S_IRUGO, acpi_device_dir(device), + &acpi_video_bus_ROM_fops, + acpi_driver_data(device)); if (!entry) return -ENODEV; - else { - entry->proc_fops = &acpi_video_bus_ROM_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } /* 'POST_info' [R] */ - entry = - create_proc_entry("POST_info", S_IRUGO, acpi_device_dir(device)); + entry = proc_create_data("POST_info", S_IRUGO, acpi_device_dir(device), + &acpi_video_bus_POST_info_fops, + acpi_driver_data(device)); if (!entry) return -ENODEV; - else { - entry->proc_fops = &acpi_video_bus_POST_info_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } /* 'POST' [R/W] */ - entry = - create_proc_entry("POST", S_IFREG | S_IRUGO | S_IRUSR, - acpi_device_dir(device)); + acpi_video_bus_POST_fops.write = acpi_video_bus_write_POST; + entry = proc_create_data("POST", S_IFREG | S_IRUGO | S_IRUSR, + acpi_device_dir(device), + &acpi_video_bus_POST_fops, + acpi_driver_data(device)); if (!entry) return -ENODEV; - else { - acpi_video_bus_POST_fops.write = acpi_video_bus_write_POST; - entry->proc_fops = &acpi_video_bus_POST_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } /* 'DOS' [R/W] */ - entry = - create_proc_entry("DOS", S_IFREG | S_IRUGO | S_IRUSR, - acpi_device_dir(device)); + acpi_video_bus_DOS_fops.write = acpi_video_bus_write_DOS; + entry = proc_create_data("DOS", S_IFREG | S_IRUGO | S_IRUSR, + acpi_device_dir(device), + &acpi_video_bus_DOS_fops, + acpi_driver_data(device)); if (!entry) return -ENODEV; - else { - acpi_video_bus_DOS_fops.write = acpi_video_bus_write_DOS; - entry->proc_fops = &acpi_video_bus_DOS_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } return 0; } diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 292aa9a0f02..1c11df9a5f3 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -566,11 +566,11 @@ config PATA_RADISYS If unsure, say N. -config PATA_RB500 - tristate "RouterBoard 500 PATA CompactFlash support" - depends on MIKROTIK_RB500 +config PATA_RB532 + tristate "RouterBoard 532 PATA CompactFlash support" + depends on MIKROTIK_RB532 help - This option enables support for the RouterBoard 500 + This option enables support for the RouterBoard 532 PATA CompactFlash controller. If unsure, say N. diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index 1fbc2aa648b..b693d829383 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -55,7 +55,7 @@ obj-$(CONFIG_PATA_PDC2027X) += pata_pdc2027x.o obj-$(CONFIG_PATA_PDC_OLD) += pata_pdc202xx_old.o obj-$(CONFIG_PATA_QDI) += pata_qdi.o obj-$(CONFIG_PATA_RADISYS) += pata_radisys.o -obj-$(CONFIG_PATA_RB500) += pata_rb500_cf.o +obj-$(CONFIG_PATA_RB532) += pata_rb532_cf.o obj-$(CONFIG_PATA_RZ1000) += pata_rz1000.o obj-$(CONFIG_PATA_SC1200) += pata_sc1200.o obj-$(CONFIG_PATA_SERVERWORKS) += pata_serverworks.o diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index a34f32442ed..3ce43920e45 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -49,7 +49,11 @@ #include "libata.h" -#define SECTOR_SIZE 512 +#define SECTOR_SIZE 512 +#define ATA_SCSI_RBUF_SIZE 4096 + +static DEFINE_SPINLOCK(ata_scsi_rbuf_lock); +static u8 ata_scsi_rbuf[ATA_SCSI_RBUF_SIZE]; typedef unsigned int (*ata_xlat_func_t)(struct ata_queued_cmd *qc); @@ -179,6 +183,13 @@ DEVICE_ATTR(link_power_management_policy, S_IRUGO | S_IWUSR, ata_scsi_lpm_show, ata_scsi_lpm_put); EXPORT_SYMBOL_GPL(dev_attr_link_power_management_policy); +static void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq) +{ + cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; + + scsi_build_sense_buffer(0, cmd->sense_buffer, sk, asc, ascq); +} + static void ata_scsi_invalid_field(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) { @@ -1632,53 +1643,48 @@ defer: /** * ata_scsi_rbuf_get - Map response buffer. - * @cmd: SCSI command containing buffer to be mapped. - * @buf_out: Pointer to mapped area. + * @flags: unsigned long variable to store irq enable status + * @copy_in: copy in from user buffer * - * Maps buffer contained within SCSI command @cmd. + * Prepare buffer for simulated SCSI commands. * * LOCKING: - * spin_lock_irqsave(host lock) + * spin_lock_irqsave(ata_scsi_rbuf_lock) on success * * RETURNS: - * Length of response buffer. + * Pointer to response buffer. */ - -static unsigned int ata_scsi_rbuf_get(struct scsi_cmnd *cmd, u8 **buf_out) +static void *ata_scsi_rbuf_get(struct scsi_cmnd *cmd, bool copy_in, + unsigned long *flags) { - u8 *buf; - unsigned int buflen; - - struct scatterlist *sg = scsi_sglist(cmd); + spin_lock_irqsave(&ata_scsi_rbuf_lock, *flags); - if (sg) { - buf = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset; - buflen = sg->length; - } else { - buf = NULL; - buflen = 0; - } - - *buf_out = buf; - return buflen; + memset(ata_scsi_rbuf, 0, ATA_SCSI_RBUF_SIZE); + if (copy_in) + sg_copy_to_buffer(scsi_sglist(cmd), scsi_sg_count(cmd), + ata_scsi_rbuf, ATA_SCSI_RBUF_SIZE); + return ata_scsi_rbuf; } /** * ata_scsi_rbuf_put - Unmap response buffer. * @cmd: SCSI command containing buffer to be unmapped. - * @buf: buffer to unmap + * @copy_out: copy out result + * @flags: @flags passed to ata_scsi_rbuf_get() * - * Unmaps response buffer contained within @cmd. + * Returns rbuf buffer. The result is copied to @cmd's buffer if + * @copy_back is true. * * LOCKING: - * spin_lock_irqsave(host lock) + * Unlocks ata_scsi_rbuf_lock. */ - -static inline void ata_scsi_rbuf_put(struct scsi_cmnd *cmd, u8 *buf) +static inline void ata_scsi_rbuf_put(struct scsi_cmnd *cmd, bool copy_out, + unsigned long *flags) { - struct scatterlist *sg = scsi_sglist(cmd); - if (sg) - kunmap_atomic(buf - sg->offset, KM_IRQ0); + if (copy_out) + sg_copy_from_buffer(scsi_sglist(cmd), scsi_sg_count(cmd), + ata_scsi_rbuf, ATA_SCSI_RBUF_SIZE); + spin_unlock_irqrestore(&ata_scsi_rbuf_lock, *flags); } /** @@ -1696,24 +1702,17 @@ static inline void ata_scsi_rbuf_put(struct scsi_cmnd *cmd, u8 *buf) * LOCKING: * spin_lock_irqsave(host lock) */ - -void ata_scsi_rbuf_fill(struct ata_scsi_args *args, - unsigned int (*actor) (struct ata_scsi_args *args, - u8 *rbuf, unsigned int buflen)) +static void ata_scsi_rbuf_fill(struct ata_scsi_args *args, + unsigned int (*actor)(struct ata_scsi_args *args, u8 *rbuf)) { u8 *rbuf; - unsigned int buflen, rc; + unsigned int rc; struct scsi_cmnd *cmd = args->cmd; unsigned long flags; - local_irq_save(flags); - - buflen = ata_scsi_rbuf_get(cmd, &rbuf); - memset(rbuf, 0, buflen); - rc = actor(args, rbuf, buflen); - ata_scsi_rbuf_put(cmd, rbuf); - - local_irq_restore(flags); + rbuf = ata_scsi_rbuf_get(cmd, false, &flags); + rc = actor(args, rbuf); + ata_scsi_rbuf_put(cmd, rc == 0, &flags); if (rc == 0) cmd->result = SAM_STAT_GOOD; @@ -1721,26 +1720,9 @@ void ata_scsi_rbuf_fill(struct ata_scsi_args *args, } /** - * ATA_SCSI_RBUF_SET - helper to set values in SCSI response buffer - * @idx: byte index into SCSI response buffer - * @val: value to set - * - * To be used by SCSI command simulator functions. This macros - * expects two local variables, u8 *rbuf and unsigned int buflen, - * are in scope. - * - * LOCKING: - * None. - */ -#define ATA_SCSI_RBUF_SET(idx, val) do { \ - if ((idx) < buflen) rbuf[(idx)] = (u8)(val); \ - } while (0) - -/** * ata_scsiop_inq_std - Simulate INQUIRY command * @args: device IDENTIFY data / SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. - * @buflen: Response buffer length. * * Returns standard device identification data associated * with non-VPD INQUIRY command output. @@ -1748,10 +1730,17 @@ void ata_scsi_rbuf_fill(struct ata_scsi_args *args, * LOCKING: * spin_lock_irqsave(host lock) */ - -unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen) +static unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf) { + const u8 versions[] = { + 0x60, /* SAM-3 (no version claimed) */ + + 0x03, + 0x20, /* SBC-2 (no version claimed) */ + + 0x02, + 0x60 /* SPC-3 (no version claimed) */ + }; u8 hdr[] = { TYPE_DISK, 0, @@ -1760,35 +1749,21 @@ unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf, 95 - 4 }; + VPRINTK("ENTER\n"); + /* set scsi removeable (RMB) bit per ata bit */ if (ata_id_removeable(args->id)) hdr[1] |= (1 << 7); - VPRINTK("ENTER\n"); - memcpy(rbuf, hdr, sizeof(hdr)); + memcpy(&rbuf[8], "ATA ", 8); + ata_id_string(args->id, &rbuf[16], ATA_ID_PROD, 16); + ata_id_string(args->id, &rbuf[32], ATA_ID_FW_REV, 4); - if (buflen > 35) { - memcpy(&rbuf[8], "ATA ", 8); - ata_id_string(args->id, &rbuf[16], ATA_ID_PROD, 16); - ata_id_string(args->id, &rbuf[32], ATA_ID_FW_REV, 4); - if (rbuf[32] == 0 || rbuf[32] == ' ') - memcpy(&rbuf[32], "n/a ", 4); - } - - if (buflen > 63) { - const u8 versions[] = { - 0x60, /* SAM-3 (no version claimed) */ - - 0x03, - 0x20, /* SBC-2 (no version claimed) */ + if (rbuf[32] == 0 || rbuf[32] == ' ') + memcpy(&rbuf[32], "n/a ", 4); - 0x02, - 0x60 /* SPC-3 (no version claimed) */ - }; - - memcpy(rbuf + 59, versions, sizeof(versions)); - } + memcpy(rbuf + 59, versions, sizeof(versions)); return 0; } @@ -1797,27 +1772,22 @@ unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf, * ata_scsiop_inq_00 - Simulate INQUIRY VPD page 0, list of pages * @args: device IDENTIFY data / SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. - * @buflen: Response buffer length. * * Returns list of inquiry VPD pages available. * * LOCKING: * spin_lock_irqsave(host lock) */ - -unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen) +static unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf) { const u8 pages[] = { 0x00, /* page 0x00, this page */ 0x80, /* page 0x80, unit serial no page */ 0x83 /* page 0x83, device ident page */ }; - rbuf[3] = sizeof(pages); /* number of supported VPD pages */ - - if (buflen > 6) - memcpy(rbuf + 4, pages, sizeof(pages)); + rbuf[3] = sizeof(pages); /* number of supported VPD pages */ + memcpy(rbuf + 4, pages, sizeof(pages)); return 0; } @@ -1825,16 +1795,13 @@ unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf, * ata_scsiop_inq_80 - Simulate INQUIRY VPD page 80, device serial number * @args: device IDENTIFY data / SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. - * @buflen: Response buffer length. * * Returns ATA device serial number. * * LOCKING: * spin_lock_irqsave(host lock) */ - -unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen) +static unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf) { const u8 hdr[] = { 0, @@ -1842,12 +1809,10 @@ unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf, 0, ATA_ID_SERNO_LEN, /* page len */ }; - memcpy(rbuf, hdr, sizeof(hdr)); - - if (buflen > (ATA_ID_SERNO_LEN + 4 - 1)) - ata_id_string(args->id, (unsigned char *) &rbuf[4], - ATA_ID_SERNO, ATA_ID_SERNO_LEN); + memcpy(rbuf, hdr, sizeof(hdr)); + ata_id_string(args->id, (unsigned char *) &rbuf[4], + ATA_ID_SERNO, ATA_ID_SERNO_LEN); return 0; } @@ -1855,7 +1820,6 @@ unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf, * ata_scsiop_inq_83 - Simulate INQUIRY VPD page 83, device identity * @args: device IDENTIFY data / SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. - * @buflen: Response buffer length. * * Yields two logical unit device identification designators: * - vendor specific ASCII containing the ATA serial number @@ -1865,41 +1829,37 @@ unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf, * LOCKING: * spin_lock_irqsave(host lock) */ - -unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen) +static unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf) { - int num; const int sat_model_serial_desc_len = 68; + int num; rbuf[1] = 0x83; /* this page code */ num = 4; - if (buflen > (ATA_ID_SERNO_LEN + num + 3)) { - /* piv=0, assoc=lu, code_set=ACSII, designator=vendor */ - rbuf[num + 0] = 2; - rbuf[num + 3] = ATA_ID_SERNO_LEN; - num += 4; - ata_id_string(args->id, (unsigned char *) rbuf + num, - ATA_ID_SERNO, ATA_ID_SERNO_LEN); - num += ATA_ID_SERNO_LEN; - } - if (buflen > (sat_model_serial_desc_len + num + 3)) { - /* SAT defined lu model and serial numbers descriptor */ - /* piv=0, assoc=lu, code_set=ACSII, designator=t10 vendor id */ - rbuf[num + 0] = 2; - rbuf[num + 1] = 1; - rbuf[num + 3] = sat_model_serial_desc_len; - num += 4; - memcpy(rbuf + num, "ATA ", 8); - num += 8; - ata_id_string(args->id, (unsigned char *) rbuf + num, - ATA_ID_PROD, ATA_ID_PROD_LEN); - num += ATA_ID_PROD_LEN; - ata_id_string(args->id, (unsigned char *) rbuf + num, - ATA_ID_SERNO, ATA_ID_SERNO_LEN); - num += ATA_ID_SERNO_LEN; - } + /* piv=0, assoc=lu, code_set=ACSII, designator=vendor */ + rbuf[num + 0] = 2; + rbuf[num + 3] = ATA_ID_SERNO_LEN; + num += 4; + ata_id_string(args->id, (unsigned char *) rbuf + num, + ATA_ID_SERNO, ATA_ID_SERNO_LEN); + num += ATA_ID_SERNO_LEN; + + /* SAT defined lu model and serial numbers descriptor */ + /* piv=0, assoc=lu, code_set=ACSII, designator=t10 vendor id */ + rbuf[num + 0] = 2; + rbuf[num + 1] = 1; + rbuf[num + 3] = sat_model_serial_desc_len; + num += 4; + memcpy(rbuf + num, "ATA ", 8); + num += 8; + ata_id_string(args->id, (unsigned char *) rbuf + num, ATA_ID_PROD, + ATA_ID_PROD_LEN); + num += ATA_ID_PROD_LEN; + ata_id_string(args->id, (unsigned char *) rbuf + num, ATA_ID_SERNO, + ATA_ID_SERNO_LEN); + num += ATA_ID_SERNO_LEN; + rbuf[3] = num - 4; /* page len (assume less than 256 bytes) */ return 0; } @@ -1908,35 +1868,26 @@ unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf, * ata_scsiop_inq_89 - Simulate INQUIRY VPD page 89, ATA info * @args: device IDENTIFY data / SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. - * @buflen: Response buffer length. * * Yields SAT-specified ATA VPD page. * * LOCKING: * spin_lock_irqsave(host lock) */ - -static unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen) +static unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf) { - u8 pbuf[60]; struct ata_taskfile tf; - unsigned int i; - if (!buflen) - return 0; - - memset(&pbuf, 0, sizeof(pbuf)); memset(&tf, 0, sizeof(tf)); - pbuf[1] = 0x89; /* our page code */ - pbuf[2] = (0x238 >> 8); /* page size fixed at 238h */ - pbuf[3] = (0x238 & 0xff); + rbuf[1] = 0x89; /* our page code */ + rbuf[2] = (0x238 >> 8); /* page size fixed at 238h */ + rbuf[3] = (0x238 & 0xff); - memcpy(&pbuf[8], "linux ", 8); - memcpy(&pbuf[16], "libata ", 16); - memcpy(&pbuf[32], DRV_VERSION, 4); - ata_id_string(args->id, &pbuf[32], ATA_ID_FW_REV, 4); + memcpy(&rbuf[8], "linux ", 8); + memcpy(&rbuf[16], "libata ", 16); + memcpy(&rbuf[32], DRV_VERSION, 4); + ata_id_string(args->id, &rbuf[32], ATA_ID_FW_REV, 4); /* we don't store the ATA device signature, so we fake it */ @@ -1944,19 +1895,12 @@ static unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf, tf.lbal = 0x1; tf.nsect = 0x1; - ata_tf_to_fis(&tf, 0, 1, &pbuf[36]); /* TODO: PMP? */ - pbuf[36] = 0x34; /* force D2H Reg FIS (34h) */ + ata_tf_to_fis(&tf, 0, 1, &rbuf[36]); /* TODO: PMP? */ + rbuf[36] = 0x34; /* force D2H Reg FIS (34h) */ - pbuf[56] = ATA_CMD_ID_ATA; + rbuf[56] = ATA_CMD_ID_ATA; - i = min(buflen, 60U); - memcpy(rbuf, &pbuf[0], i); - buflen -= i; - - if (!buflen) - return 0; - - memcpy(&rbuf[60], &args->id[0], min(buflen, 512U)); + memcpy(&rbuf[60], &args->id[0], 512); return 0; } @@ -1964,7 +1908,6 @@ static unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf, * ata_scsiop_noop - Command handler that simply returns success. * @args: device IDENTIFY data / SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. - * @buflen: Response buffer length. * * No operation. Simply returns success to caller, to indicate * that the caller should successfully complete this SCSI command. @@ -1972,47 +1915,16 @@ static unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf, * LOCKING: * spin_lock_irqsave(host lock) */ - -unsigned int ata_scsiop_noop(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen) +static unsigned int ata_scsiop_noop(struct ata_scsi_args *args, u8 *rbuf) { VPRINTK("ENTER\n"); return 0; } /** - * ata_msense_push - Push data onto MODE SENSE data output buffer - * @ptr_io: (input/output) Location to store more output data - * @last: End of output data buffer - * @buf: Pointer to BLOB being added to output buffer - * @buflen: Length of BLOB - * - * Store MODE SENSE data on an output buffer. - * - * LOCKING: - * None. - */ - -static void ata_msense_push(u8 **ptr_io, const u8 *last, - const u8 *buf, unsigned int buflen) -{ - u8 *ptr = *ptr_io; - - if ((ptr + buflen - 1) > last) - return; - - memcpy(ptr, buf, buflen); - - ptr += buflen; - - *ptr_io = ptr; -} - -/** * ata_msense_caching - Simulate MODE SENSE caching info page * @id: device IDENTIFY data - * @ptr_io: (input/output) Location to store more output data - * @last: End of output data buffer + * @buf: output buffer * * Generate a caching info page, which conditionally indicates * write caching to the SCSI layer, depending on device @@ -2021,58 +1933,43 @@ static void ata_msense_push(u8 **ptr_io, const u8 *last, * LOCKING: * None. */ - -static unsigned int ata_msense_caching(u16 *id, u8 **ptr_io, - const u8 *last) +static unsigned int ata_msense_caching(u16 *id, u8 *buf) { - u8 page[CACHE_MPAGE_LEN]; - - memcpy(page, def_cache_mpage, sizeof(page)); + memcpy(buf, def_cache_mpage, sizeof(def_cache_mpage)); if (ata_id_wcache_enabled(id)) - page[2] |= (1 << 2); /* write cache enable */ + buf[2] |= (1 << 2); /* write cache enable */ if (!ata_id_rahead_enabled(id)) - page[12] |= (1 << 5); /* disable read ahead */ - - ata_msense_push(ptr_io, last, page, sizeof(page)); - return sizeof(page); + buf[12] |= (1 << 5); /* disable read ahead */ + return sizeof(def_cache_mpage); } /** * ata_msense_ctl_mode - Simulate MODE SENSE control mode page - * @dev: Device associated with this MODE SENSE command - * @ptr_io: (input/output) Location to store more output data - * @last: End of output data buffer + * @buf: output buffer * * Generate a generic MODE SENSE control mode page. * * LOCKING: * None. */ - -static unsigned int ata_msense_ctl_mode(u8 **ptr_io, const u8 *last) +static unsigned int ata_msense_ctl_mode(u8 *buf) { - ata_msense_push(ptr_io, last, def_control_mpage, - sizeof(def_control_mpage)); + memcpy(buf, def_control_mpage, sizeof(def_control_mpage)); return sizeof(def_control_mpage); } /** * ata_msense_rw_recovery - Simulate MODE SENSE r/w error recovery page - * @dev: Device associated with this MODE SENSE command - * @ptr_io: (input/output) Location to store more output data - * @last: End of output data buffer + * @bufp: output buffer * * Generate a generic MODE SENSE r/w error recovery page. * * LOCKING: * None. */ - -static unsigned int ata_msense_rw_recovery(u8 **ptr_io, const u8 *last) +static unsigned int ata_msense_rw_recovery(u8 *buf) { - - ata_msense_push(ptr_io, last, def_rw_recovery_mpage, - sizeof(def_rw_recovery_mpage)); + memcpy(buf, def_rw_recovery_mpage, sizeof(def_rw_recovery_mpage)); return sizeof(def_rw_recovery_mpage); } @@ -2104,7 +2001,6 @@ static int ata_dev_supports_fua(u16 *id) * ata_scsiop_mode_sense - Simulate MODE SENSE 6, 10 commands * @args: device IDENTIFY data / SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. - * @buflen: Response buffer length. * * Simulate MODE SENSE commands. Assume this is invoked for direct * access devices (e.g. disks) only. There should be no block @@ -2113,19 +2009,17 @@ static int ata_dev_supports_fua(u16 *id) * LOCKING: * spin_lock_irqsave(host lock) */ - -unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen) +static unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf) { struct ata_device *dev = args->dev; - u8 *scsicmd = args->cmd->cmnd, *p, *last; + u8 *scsicmd = args->cmd->cmnd, *p = rbuf; const u8 sat_blk_desc[] = { 0, 0, 0, 0, /* number of blocks: sat unspecified */ 0, 0, 0x2, 0x0 /* block length: 512 bytes */ }; u8 pg, spg; - unsigned int ebd, page_control, six_byte, output_len, alloc_len, minlen; + unsigned int ebd, page_control, six_byte; u8 dpofua; VPRINTK("ENTER\n"); @@ -2148,17 +2042,10 @@ unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf, goto invalid_fld; } - if (six_byte) { - output_len = 4 + (ebd ? 8 : 0); - alloc_len = scsicmd[4]; - } else { - output_len = 8 + (ebd ? 8 : 0); - alloc_len = (scsicmd[7] << 8) + scsicmd[8]; - } - minlen = (alloc_len < buflen) ? alloc_len : buflen; - - p = rbuf + output_len; - last = rbuf + minlen - 1; + if (six_byte) + p += 4 + (ebd ? 8 : 0); + else + p += 8 + (ebd ? 8 : 0); pg = scsicmd[2] & 0x3f; spg = scsicmd[3]; @@ -2171,61 +2058,48 @@ unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf, switch(pg) { case RW_RECOVERY_MPAGE: - output_len += ata_msense_rw_recovery(&p, last); + p += ata_msense_rw_recovery(p); break; case CACHE_MPAGE: - output_len += ata_msense_caching(args->id, &p, last); + p += ata_msense_caching(args->id, p); break; - case CONTROL_MPAGE: { - output_len += ata_msense_ctl_mode(&p, last); + case CONTROL_MPAGE: + p += ata_msense_ctl_mode(p); break; - } case ALL_MPAGES: - output_len += ata_msense_rw_recovery(&p, last); - output_len += ata_msense_caching(args->id, &p, last); - output_len += ata_msense_ctl_mode(&p, last); + p += ata_msense_rw_recovery(p); + p += ata_msense_caching(args->id, p); + p += ata_msense_ctl_mode(p); break; default: /* invalid page code */ goto invalid_fld; } - if (minlen < 1) - return 0; - dpofua = 0; if (ata_dev_supports_fua(args->id) && (dev->flags & ATA_DFLAG_LBA48) && (!(dev->flags & ATA_DFLAG_PIO) || dev->multi_count)) dpofua = 1 << 4; if (six_byte) { - output_len--; - rbuf[0] = output_len; - if (minlen > 2) - rbuf[2] |= dpofua; + rbuf[0] = p - rbuf - 1; + rbuf[2] |= dpofua; if (ebd) { - if (minlen > 3) - rbuf[3] = sizeof(sat_blk_desc); - if (minlen > 11) - memcpy(rbuf + 4, sat_blk_desc, - sizeof(sat_blk_desc)); + rbuf[3] = sizeof(sat_blk_desc); + memcpy(rbuf + 4, sat_blk_desc, sizeof(sat_blk_desc)); } } else { - output_len -= 2; + unsigned int output_len = p - rbuf - 2; + rbuf[0] = output_len >> 8; - if (minlen > 1) - rbuf[1] = output_len; - if (minlen > 3) - rbuf[3] |= dpofua; + rbuf[1] = output_len; + rbuf[3] |= dpofua; if (ebd) { - if (minlen > 7) - rbuf[7] = sizeof(sat_blk_desc); - if (minlen > 15) - memcpy(rbuf + 8, sat_blk_desc, - sizeof(sat_blk_desc)); + rbuf[7] = sizeof(sat_blk_desc); + memcpy(rbuf + 8, sat_blk_desc, sizeof(sat_blk_desc)); } } return 0; @@ -2245,15 +2119,13 @@ saving_not_supp: * ata_scsiop_read_cap - Simulate READ CAPACITY[ 16] commands * @args: device IDENTIFY data / SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. - * @buflen: Response buffer length. * * Simulate READ CAPACITY commands. * * LOCKING: * None. */ -unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen) +static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf) { u64 last_lba = args->dev->n_sectors - 1; /* LBA of the last block */ @@ -2264,28 +2136,28 @@ unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf, last_lba = 0xffffffff; /* sector count, 32-bit */ - ATA_SCSI_RBUF_SET(0, last_lba >> (8 * 3)); - ATA_SCSI_RBUF_SET(1, last_lba >> (8 * 2)); - ATA_SCSI_RBUF_SET(2, last_lba >> (8 * 1)); - ATA_SCSI_RBUF_SET(3, last_lba); + rbuf[0] = last_lba >> (8 * 3); + rbuf[1] = last_lba >> (8 * 2); + rbuf[2] = last_lba >> (8 * 1); + rbuf[3] = last_lba; /* sector size */ - ATA_SCSI_RBUF_SET(6, ATA_SECT_SIZE >> 8); - ATA_SCSI_RBUF_SET(7, ATA_SECT_SIZE & 0xff); + rbuf[6] = ATA_SECT_SIZE >> 8; + rbuf[7] = ATA_SECT_SIZE & 0xff; } else { /* sector count, 64-bit */ - ATA_SCSI_RBUF_SET(0, last_lba >> (8 * 7)); - ATA_SCSI_RBUF_SET(1, last_lba >> (8 * 6)); - ATA_SCSI_RBUF_SET(2, last_lba >> (8 * 5)); - ATA_SCSI_RBUF_SET(3, last_lba >> (8 * 4)); - ATA_SCSI_RBUF_SET(4, last_lba >> (8 * 3)); - ATA_SCSI_RBUF_SET(5, last_lba >> (8 * 2)); - ATA_SCSI_RBUF_SET(6, last_lba >> (8 * 1)); - ATA_SCSI_RBUF_SET(7, last_lba); + rbuf[0] = last_lba >> (8 * 7); + rbuf[1] = last_lba >> (8 * 6); + rbuf[2] = last_lba >> (8 * 5); + rbuf[3] = last_lba >> (8 * 4); + rbuf[4] = last_lba >> (8 * 3); + rbuf[5] = last_lba >> (8 * 2); + rbuf[6] = last_lba >> (8 * 1); + rbuf[7] = last_lba; /* sector size */ - ATA_SCSI_RBUF_SET(10, ATA_SECT_SIZE >> 8); - ATA_SCSI_RBUF_SET(11, ATA_SECT_SIZE & 0xff); + rbuf[10] = ATA_SECT_SIZE >> 8; + rbuf[11] = ATA_SECT_SIZE & 0xff; } return 0; @@ -2295,16 +2167,13 @@ unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf, * ata_scsiop_report_luns - Simulate REPORT LUNS command * @args: device IDENTIFY data / SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. - * @buflen: Response buffer length. * * Simulate REPORT LUNS command. * * LOCKING: * spin_lock_irqsave(host lock) */ - -unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen) +static unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf) { VPRINTK("ENTER\n"); rbuf[3] = 8; /* just one lun, LUN 0, size 8 bytes */ @@ -2312,53 +2181,6 @@ unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf, return 0; } -/** - * ata_scsi_set_sense - Set SCSI sense data and status - * @cmd: SCSI request to be handled - * @sk: SCSI-defined sense key - * @asc: SCSI-defined additional sense code - * @ascq: SCSI-defined additional sense code qualifier - * - * Helper function that builds a valid fixed format, current - * response code and the given sense key (sk), additional sense - * code (asc) and additional sense code qualifier (ascq) with - * a SCSI command status of %SAM_STAT_CHECK_CONDITION and - * DRIVER_SENSE set in the upper bits of scsi_cmnd::result . - * - * LOCKING: - * Not required - */ - -void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq) -{ - cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; - - scsi_build_sense_buffer(0, cmd->sense_buffer, sk, asc, ascq); -} - -/** - * ata_scsi_badcmd - End a SCSI request with an error - * @cmd: SCSI request to be handled - * @done: SCSI command completion function - * @asc: SCSI-defined additional sense code - * @ascq: SCSI-defined additional sense code qualifier - * - * Helper function that completes a SCSI command with - * %SAM_STAT_CHECK_CONDITION, with a sense key %ILLEGAL_REQUEST - * and the specified additional sense codes. - * - * LOCKING: - * spin_lock_irqsave(host lock) - */ - -void ata_scsi_badcmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), u8 asc, u8 ascq) -{ - DPRINTK("ENTER\n"); - ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, asc, ascq); - - done(cmd); -} - static void atapi_sense_complete(struct ata_queued_cmd *qc) { if (qc->err_mask && ((qc->err_mask & AC_ERR_DEV) == 0)) { @@ -2485,13 +2307,10 @@ static void atapi_qc_complete(struct ata_queued_cmd *qc) u8 *scsicmd = cmd->cmnd; if ((scsicmd[0] == INQUIRY) && ((scsicmd[1] & 0x03) == 0)) { - u8 *buf = NULL; - unsigned int buflen; unsigned long flags; + u8 *buf; - local_irq_save(flags); - - buflen = ata_scsi_rbuf_get(cmd, &buf); + buf = ata_scsi_rbuf_get(cmd, true, &flags); /* ATAPI devices typically report zero for their SCSI version, * and sometimes deviate from the spec WRT response data @@ -2506,9 +2325,7 @@ static void atapi_qc_complete(struct ata_queued_cmd *qc) buf[3] = 0x32; } - ata_scsi_rbuf_put(cmd, buf); - - local_irq_restore(flags); + ata_scsi_rbuf_put(cmd, true, &flags); } cmd->result = SAM_STAT_GOOD; diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index ae2cfd95d43..4514283937e 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -146,34 +146,6 @@ extern void ata_scsi_scan_host(struct ata_port *ap, int sync); extern int ata_scsi_offline_dev(struct ata_device *dev); extern void ata_scsi_media_change_notify(struct ata_device *dev); extern void ata_scsi_hotplug(struct work_struct *work); -extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen); - -extern unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen); - -extern unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen); -extern unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen); -extern unsigned int ata_scsiop_noop(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen); -extern unsigned int ata_scsiop_sync_cache(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen); -extern unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen); -extern unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen); -extern unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen); -extern void ata_scsi_badcmd(struct scsi_cmnd *cmd, - void (*done)(struct scsi_cmnd *), - u8 asc, u8 ascq); -extern void ata_scsi_set_sense(struct scsi_cmnd *cmd, - u8 sk, u8 asc, u8 ascq); -extern void ata_scsi_rbuf_fill(struct ata_scsi_args *args, - unsigned int (*actor) (struct ata_scsi_args *args, - u8 *rbuf, unsigned int buflen)); extern void ata_schedule_scsi_eh(struct Scsi_Host *shost); extern void ata_scsi_dev_rescan(struct work_struct *work); extern int ata_bus_probe(struct ata_port *ap); diff --git a/drivers/ata/pata_bf54x.c b/drivers/ata/pata_bf54x.c index a75de0684c1..9ab89732cf9 100644 --- a/drivers/ata/pata_bf54x.c +++ b/drivers/ata/pata_bf54x.c @@ -1272,8 +1272,8 @@ static void bfin_freeze(struct ata_port *ap) void bfin_thaw(struct ata_port *ap) { + dev_dbg(ap->dev, "in atapi dma thaw\n"); bfin_check_status(ap); - bfin_irq_clear(ap); bfin_irq_on(ap); } @@ -1339,13 +1339,130 @@ static int bfin_port_start(struct ata_port *ap) return 0; } +static unsigned int bfin_ata_host_intr(struct ata_port *ap, + struct ata_queued_cmd *qc) +{ + struct ata_eh_info *ehi = &ap->link.eh_info; + u8 status, host_stat = 0; + + VPRINTK("ata%u: protocol %d task_state %d\n", + ap->print_id, qc->tf.protocol, ap->hsm_task_state); + + /* Check whether we are expecting interrupt in this state */ + switch (ap->hsm_task_state) { + case HSM_ST_FIRST: + /* Some pre-ATAPI-4 devices assert INTRQ + * at this state when ready to receive CDB. + */ + + /* Check the ATA_DFLAG_CDB_INTR flag is enough here. + * The flag was turned on only for atapi devices. + * No need to check is_atapi_taskfile(&qc->tf) again. + */ + if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) + goto idle_irq; + break; + case HSM_ST_LAST: + if (qc->tf.protocol == ATA_PROT_DMA || + qc->tf.protocol == ATAPI_PROT_DMA) { + /* check status of DMA engine */ + host_stat = ap->ops->bmdma_status(ap); + VPRINTK("ata%u: host_stat 0x%X\n", + ap->print_id, host_stat); + + /* if it's not our irq... */ + if (!(host_stat & ATA_DMA_INTR)) + goto idle_irq; + + /* before we do anything else, clear DMA-Start bit */ + ap->ops->bmdma_stop(qc); + + if (unlikely(host_stat & ATA_DMA_ERR)) { + /* error when transfering data to/from memory */ + qc->err_mask |= AC_ERR_HOST_BUS; + ap->hsm_task_state = HSM_ST_ERR; + } + } + break; + case HSM_ST: + break; + default: + goto idle_irq; + } + + /* check altstatus */ + status = ap->ops->sff_check_altstatus(ap); + if (status & ATA_BUSY) + goto busy_ata; + + /* check main status, clearing INTRQ */ + status = ap->ops->sff_check_status(ap); + if (unlikely(status & ATA_BUSY)) + goto busy_ata; + + /* ack bmdma irq events */ + ap->ops->sff_irq_clear(ap); + + ata_sff_hsm_move(ap, qc, status, 0); + + if (unlikely(qc->err_mask) && (qc->tf.protocol == ATA_PROT_DMA || + qc->tf.protocol == ATAPI_PROT_DMA)) + ata_ehi_push_desc(ehi, "BMDMA stat 0x%x", host_stat); + +busy_ata: + return 1; /* irq handled */ + +idle_irq: + ap->stats.idle_irq++; + +#ifdef ATA_IRQ_TRAP + if ((ap->stats.idle_irq % 1000) == 0) { + ap->ops->irq_ack(ap, 0); /* debug trap */ + ata_port_printk(ap, KERN_WARNING, "irq trap\n"); + return 1; + } +#endif + return 0; /* irq not handled */ +} + +static irqreturn_t bfin_ata_interrupt(int irq, void *dev_instance) +{ + struct ata_host *host = dev_instance; + unsigned int i; + unsigned int handled = 0; + unsigned long flags; + + /* TODO: make _irqsave conditional on x86 PCI IDE legacy mode */ + spin_lock_irqsave(&host->lock, flags); + + for (i = 0; i < host->n_ports; i++) { + struct ata_port *ap; + + ap = host->ports[i]; + if (ap && + !(ap->flags & ATA_FLAG_DISABLED)) { + struct ata_queued_cmd *qc; + + qc = ata_qc_from_tag(ap, ap->link.active_tag); + if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)) && + (qc->flags & ATA_QCFLAG_ACTIVE)) + handled |= bfin_ata_host_intr(ap, qc); + } + } + + spin_unlock_irqrestore(&host->lock, flags); + + return IRQ_RETVAL(handled); +} + + static struct scsi_host_template bfin_sht = { ATA_BASE_SHT(DRV_NAME), .sg_tablesize = SG_NONE, .dma_boundary = ATA_DMA_BOUNDARY, }; -static const struct ata_port_operations bfin_pata_ops = { +static struct ata_port_operations bfin_pata_ops = { .inherits = &ata_sff_port_ops, .set_piomode = bfin_set_piomode, @@ -1370,7 +1487,6 @@ static const struct ata_port_operations bfin_pata_ops = { .thaw = bfin_thaw, .softreset = bfin_softreset, .postreset = bfin_postreset, - .post_internal_cmd = bfin_bmdma_stop, .sff_irq_clear = bfin_irq_clear, .sff_irq_on = bfin_irq_on, @@ -1507,7 +1623,7 @@ static int __devinit bfin_atapi_probe(struct platform_device *pdev) } if (ata_host_activate(host, platform_get_irq(pdev, 0), - ata_sff_interrupt, IRQF_SHARED, &bfin_sht) != 0) { + bfin_ata_interrupt, IRQF_SHARED, &bfin_sht) != 0) { peripheral_free_list(atapi_io_port); dev_err(&pdev->dev, "Fail to attach ATAPI device\n"); return -ENODEV; diff --git a/drivers/ata/pata_rb500_cf.c b/drivers/ata/pata_rb532_cf.c index 4345174aaee..a108d259f19 100644 --- a/drivers/ata/pata_rb500_cf.c +++ b/drivers/ata/pata_rb532_cf.c @@ -32,7 +32,7 @@ #include <asm/gpio.h> -#define DRV_NAME "pata-rb500-cf" +#define DRV_NAME "pata-rb532-cf" #define DRV_VERSION "0.1.0" #define DRV_DESC "PATA driver for RouterBOARD 532 Compact Flash" @@ -43,7 +43,7 @@ #define RB500_CF_REG_CTRL 0x080E #define RB500_CF_REG_DATA 0x0C00 -struct rb500_cf_info { +struct rb532_cf_info { void __iomem *iobase; unsigned int gpio_line; int frozen; @@ -52,10 +52,10 @@ struct rb500_cf_info { /* ------------------------------------------------------------------------ */ -static inline void rb500_pata_finish_io(struct ata_port *ap) +static inline void rb532_pata_finish_io(struct ata_port *ap) { struct ata_host *ah = ap->host; - struct rb500_cf_info *info = ah->private_data; + struct rb532_cf_info *info = ah->private_data; ata_sff_altstatus(ap); ndelay(RB500_CF_IO_DELAY); @@ -63,14 +63,14 @@ static inline void rb500_pata_finish_io(struct ata_port *ap) set_irq_type(info->irq, IRQ_TYPE_LEVEL_HIGH); } -static void rb500_pata_exec_command(struct ata_port *ap, +static void rb532_pata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf) { writeb(tf->command, ap->ioaddr.command_addr); - rb500_pata_finish_io(ap); + rb532_pata_finish_io(ap); } -static void rb500_pata_data_xfer(struct ata_device *adev, unsigned char *buf, +static void rb532_pata_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data) { struct ata_port *ap = adev->link->ap; @@ -84,27 +84,27 @@ static void rb500_pata_data_xfer(struct ata_device *adev, unsigned char *buf, *buf = readb(ioaddr); } - rb500_pata_finish_io(adev->link->ap); + rb532_pata_finish_io(adev->link->ap); } -static void rb500_pata_freeze(struct ata_port *ap) +static void rb532_pata_freeze(struct ata_port *ap) { - struct rb500_cf_info *info = ap->host->private_data; + struct rb532_cf_info *info = ap->host->private_data; info->frozen = 1; } -static void rb500_pata_thaw(struct ata_port *ap) +static void rb532_pata_thaw(struct ata_port *ap) { - struct rb500_cf_info *info = ap->host->private_data; + struct rb532_cf_info *info = ap->host->private_data; info->frozen = 0; } -static irqreturn_t rb500_pata_irq_handler(int irq, void *dev_instance) +static irqreturn_t rb532_pata_irq_handler(int irq, void *dev_instance) { struct ata_host *ah = dev_instance; - struct rb500_cf_info *info = ah->private_data; + struct rb532_cf_info *info = ah->private_data; if (gpio_get_value(info->gpio_line)) { set_irq_type(info->irq, IRQ_TYPE_LEVEL_LOW); @@ -117,30 +117,30 @@ static irqreturn_t rb500_pata_irq_handler(int irq, void *dev_instance) return IRQ_HANDLED; } -static struct ata_port_operations rb500_pata_port_ops = { +static struct ata_port_operations rb532_pata_port_ops = { .inherits = &ata_sff_port_ops, - .sff_exec_command = rb500_pata_exec_command, - .sff_data_xfer = rb500_pata_data_xfer, - .freeze = rb500_pata_freeze, - .thaw = rb500_pata_thaw, + .sff_exec_command = rb532_pata_exec_command, + .sff_data_xfer = rb532_pata_data_xfer, + .freeze = rb532_pata_freeze, + .thaw = rb532_pata_thaw, }; /* ------------------------------------------------------------------------ */ -static struct scsi_host_template rb500_pata_sht = { +static struct scsi_host_template rb532_pata_sht = { ATA_PIO_SHT(DRV_NAME), }; /* ------------------------------------------------------------------------ */ -static void rb500_pata_setup_ports(struct ata_host *ah) +static void rb532_pata_setup_ports(struct ata_host *ah) { - struct rb500_cf_info *info = ah->private_data; + struct rb532_cf_info *info = ah->private_data; struct ata_port *ap; ap = ah->ports[0]; - ap->ops = &rb500_pata_port_ops; + ap->ops = &rb532_pata_port_ops; ap->pio_mask = 0x1f; /* PIO4 */ ap->flags = ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO; @@ -153,13 +153,13 @@ static void rb500_pata_setup_ports(struct ata_host *ah) ap->ioaddr.data_addr = info->iobase + RB500_CF_REG_DATA; } -static __devinit int rb500_pata_driver_probe(struct platform_device *pdev) +static __devinit int rb532_pata_driver_probe(struct platform_device *pdev) { unsigned int irq; int gpio; struct resource *res; struct ata_host *ah; - struct rb500_cf_info *info; + struct rb532_cf_info *info; int ret; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -213,10 +213,10 @@ static __devinit int rb500_pata_driver_probe(struct platform_device *pdev) goto err_free_gpio; } - rb500_pata_setup_ports(ah); + rb532_pata_setup_ports(ah); - ret = ata_host_activate(ah, irq, rb500_pata_irq_handler, - IRQF_TRIGGER_LOW, &rb500_pata_sht); + ret = ata_host_activate(ah, irq, rb532_pata_irq_handler, + IRQF_TRIGGER_LOW, &rb532_pata_sht); if (ret) goto err_free_gpio; @@ -228,10 +228,10 @@ err_free_gpio: return ret; } -static __devexit int rb500_pata_driver_remove(struct platform_device *pdev) +static __devexit int rb532_pata_driver_remove(struct platform_device *pdev) { struct ata_host *ah = platform_get_drvdata(pdev); - struct rb500_cf_info *info = ah->private_data; + struct rb532_cf_info *info = ah->private_data; ata_host_detach(ah); gpio_free(info->gpio_line); @@ -242,9 +242,9 @@ static __devexit int rb500_pata_driver_remove(struct platform_device *pdev) /* work with hotplug and coldplug */ MODULE_ALIAS("platform:" DRV_NAME); -static struct platform_driver rb500_pata_platform_driver = { - .probe = rb500_pata_driver_probe, - .remove = __devexit_p(rb500_pata_driver_remove), +static struct platform_driver rb532_pata_platform_driver = { + .probe = rb532_pata_driver_probe, + .remove = __devexit_p(rb532_pata_driver_remove), .driver = { .name = DRV_NAME, .owner = THIS_MODULE, @@ -255,16 +255,16 @@ static struct platform_driver rb500_pata_platform_driver = { #define DRV_INFO DRV_DESC " version " DRV_VERSION -static int __init rb500_pata_module_init(void) +static int __init rb532_pata_module_init(void) { printk(KERN_INFO DRV_INFO "\n"); - return platform_driver_register(&rb500_pata_platform_driver); + return platform_driver_register(&rb532_pata_platform_driver); } -static void __exit rb500_pata_module_exit(void) +static void __exit rb532_pata_module_exit(void) { - platform_driver_unregister(&rb500_pata_platform_driver); + platform_driver_unregister(&rb532_pata_platform_driver); } MODULE_AUTHOR("Gabor Juhos <juhosg at openwrt.org>"); @@ -273,5 +273,5 @@ MODULE_DESCRIPTION(DRV_DESC); MODULE_VERSION(DRV_VERSION); MODULE_LICENSE("GPL"); -module_init(rb500_pata_module_init); -module_exit(rb500_pata_module_exit); +module_init(rb532_pata_module_init); +module_exit(rb532_pata_module_exit); diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c index fddd346b1d5..853559e3231 100644 --- a/drivers/ata/sata_fsl.c +++ b/drivers/ata/sata_fsl.c @@ -678,7 +678,7 @@ static unsigned int sata_fsl_dev_classify(struct ata_port *ap) return ata_dev_classify(&tf); } -static int sata_fsl_prereset(struct ata_linke *link, unsigned long deadline) +static int sata_fsl_prereset(struct ata_link *link, unsigned long deadline) { /* FIXME: Never skip softreset, sata_fsl_softreset() is * combination of soft and hard resets. sata_fsl_softreset() diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 26a6337195b..842b1a15b78 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -172,10 +172,11 @@ enum { PCIE_IRQ_MASK_OFS = 0x1910, PCIE_UNMASK_ALL_IRQS = 0x40a, /* assorted bits */ - HC_MAIN_IRQ_CAUSE_OFS = 0x1d60, - HC_MAIN_IRQ_MASK_OFS = 0x1d64, - HC_SOC_MAIN_IRQ_CAUSE_OFS = 0x20020, - HC_SOC_MAIN_IRQ_MASK_OFS = 0x20024, + /* Host Controller Main Interrupt Cause/Mask registers (1 per-chip) */ + PCI_HC_MAIN_IRQ_CAUSE_OFS = 0x1d60, + PCI_HC_MAIN_IRQ_MASK_OFS = 0x1d64, + SOC_HC_MAIN_IRQ_CAUSE_OFS = 0x20020, + SOC_HC_MAIN_IRQ_MASK_OFS = 0x20024, ERR_IRQ = (1 << 0), /* shift by port # */ DONE_IRQ = (1 << 1), /* shift by port # */ HC0_IRQ_PEND = 0x1ff, /* bits 0-8 = HC0's ports */ @@ -445,8 +446,8 @@ struct mv_host_priv { const struct mv_hw_ops *ops; int n_ports; void __iomem *base; - void __iomem *main_cause_reg_addr; - void __iomem *main_mask_reg_addr; + void __iomem *main_irq_cause_addr; + void __iomem *main_irq_mask_addr; u32 irq_cause_ofs; u32 irq_mask_ofs; u32 unmask_all_irqs; @@ -727,8 +728,8 @@ static inline unsigned int mv_hardport_from_port(unsigned int port) * Simple code, with two return values, so macro rather than inline. * * port is the sole input, in range 0..7. - * shift is one output, for use with the main_cause and main_mask registers. - * hardport is the other output, in range 0..3 + * shift is one output, for use with main_irq_cause / main_irq_mask registers. + * hardport is the other output, in range 0..3. * * Note that port and hardport may be the same variable in some cases. */ @@ -1679,12 +1680,12 @@ static void mv_process_crpb_entries(struct ata_port *ap, struct mv_port_priv *pp /** * mv_host_intr - Handle all interrupts on the given host controller * @host: host specific structure - * @main_cause: Main interrupt cause register for the chip. + * @main_irq_cause: Main interrupt cause register for the chip. * * LOCKING: * Inherited from caller. */ -static int mv_host_intr(struct ata_host *host, u32 main_cause) +static int mv_host_intr(struct ata_host *host, u32 main_irq_cause) { struct mv_host_priv *hpriv = host->private_data; void __iomem *mmio = hpriv->base, *hc_mmio = NULL; @@ -1705,7 +1706,7 @@ static int mv_host_intr(struct ata_host *host, u32 main_cause) * Do nothing if port is not interrupting or is disabled: */ MV_PORT_TO_SHIFT_AND_HARDPORT(port, shift, hardport); - port_cause = (main_cause >> shift) & (DONE_IRQ | ERR_IRQ); + port_cause = (main_irq_cause >> shift) & (DONE_IRQ | ERR_IRQ); if (!port_cause || !ap || (ap->flags & ATA_FLAG_DISABLED)) continue; /* @@ -1811,20 +1812,20 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance) struct ata_host *host = dev_instance; struct mv_host_priv *hpriv = host->private_data; unsigned int handled = 0; - u32 main_cause, main_mask; + u32 main_irq_cause, main_irq_mask; spin_lock(&host->lock); - main_cause = readl(hpriv->main_cause_reg_addr); - main_mask = readl(hpriv->main_mask_reg_addr); + main_irq_cause = readl(hpriv->main_irq_cause_addr); + main_irq_mask = readl(hpriv->main_irq_mask_addr); /* * Deal with cases where we either have nothing pending, or have read * a bogus register value which can indicate HW removal or PCI fault. */ - if ((main_cause & main_mask) && (main_cause != 0xffffffffU)) { - if (unlikely((main_cause & PCI_ERR) && HAS_PCI(host))) + if ((main_irq_cause & main_irq_mask) && (main_irq_cause != 0xffffffffU)) { + if (unlikely((main_irq_cause & PCI_ERR) && HAS_PCI(host))) handled = mv_pci_error(host, hpriv->base); else - handled = mv_host_intr(host, main_cause); + handled = mv_host_intr(host, main_irq_cause); } spin_unlock(&host->lock); return IRQ_RETVAL(handled); @@ -2027,7 +2028,7 @@ static void mv_reset_pci_bus(struct ata_host *host, void __iomem *mmio) ZERO(MV_PCI_DISC_TIMER); ZERO(MV_PCI_MSI_TRIGGER); writel(0x000100ff, mmio + MV_PCI_XBAR_TMOUT); - ZERO(HC_MAIN_IRQ_MASK_OFS); + ZERO(PCI_HC_MAIN_IRQ_MASK_OFS); ZERO(MV_PCI_SERR_MASK); ZERO(hpriv->irq_cause_ofs); ZERO(hpriv->irq_mask_ofs); @@ -2404,7 +2405,7 @@ static void mv_eh_freeze(struct ata_port *ap) { struct mv_host_priv *hpriv = ap->host->private_data; unsigned int shift, hardport, port = ap->port_no; - u32 main_mask; + u32 main_irq_mask; /* FIXME: handle coalescing completion events properly */ @@ -2412,9 +2413,9 @@ static void mv_eh_freeze(struct ata_port *ap) MV_PORT_TO_SHIFT_AND_HARDPORT(port, shift, hardport); /* disable assertion of portN err, done events */ - main_mask = readl(hpriv->main_mask_reg_addr); - main_mask &= ~((DONE_IRQ | ERR_IRQ) << shift); - writelfl(main_mask, hpriv->main_mask_reg_addr); + main_irq_mask = readl(hpriv->main_irq_mask_addr); + main_irq_mask &= ~((DONE_IRQ | ERR_IRQ) << shift); + writelfl(main_irq_mask, hpriv->main_irq_mask_addr); } static void mv_eh_thaw(struct ata_port *ap) @@ -2423,7 +2424,7 @@ static void mv_eh_thaw(struct ata_port *ap) unsigned int shift, hardport, port = ap->port_no; void __iomem *hc_mmio = mv_hc_base_from_port(hpriv->base, port); void __iomem *port_mmio = mv_ap_base(ap); - u32 main_mask, hc_irq_cause; + u32 main_irq_mask, hc_irq_cause; /* FIXME: handle coalescing completion events properly */ @@ -2438,9 +2439,9 @@ static void mv_eh_thaw(struct ata_port *ap) writelfl(hc_irq_cause, hc_mmio + HC_IRQ_CAUSE_OFS); /* enable assertion of portN err, done events */ - main_mask = readl(hpriv->main_mask_reg_addr); - main_mask |= ((DONE_IRQ | ERR_IRQ) << shift); - writelfl(main_mask, hpriv->main_mask_reg_addr); + main_irq_mask = readl(hpriv->main_irq_mask_addr); + main_irq_mask |= ((DONE_IRQ | ERR_IRQ) << shift); + writelfl(main_irq_mask, hpriv->main_irq_mask_addr); } /** @@ -2654,15 +2655,15 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx) goto done; if (HAS_PCI(host)) { - hpriv->main_cause_reg_addr = mmio + HC_MAIN_IRQ_CAUSE_OFS; - hpriv->main_mask_reg_addr = mmio + HC_MAIN_IRQ_MASK_OFS; + hpriv->main_irq_cause_addr = mmio + PCI_HC_MAIN_IRQ_CAUSE_OFS; + hpriv->main_irq_mask_addr = mmio + PCI_HC_MAIN_IRQ_MASK_OFS; } else { - hpriv->main_cause_reg_addr = mmio + HC_SOC_MAIN_IRQ_CAUSE_OFS; - hpriv->main_mask_reg_addr = mmio + HC_SOC_MAIN_IRQ_MASK_OFS; + hpriv->main_irq_cause_addr = mmio + SOC_HC_MAIN_IRQ_CAUSE_OFS; + hpriv->main_irq_mask_addr = mmio + SOC_HC_MAIN_IRQ_MASK_OFS; } /* global interrupt mask: 0 == mask everything */ - writel(0, hpriv->main_mask_reg_addr); + writel(0, hpriv->main_irq_mask_addr); n_hc = mv_get_hc_count(host->ports[0]->flags); @@ -2712,23 +2713,23 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx) writelfl(hpriv->unmask_all_irqs, mmio + hpriv->irq_mask_ofs); if (IS_GEN_I(hpriv)) writelfl(~HC_MAIN_MASKED_IRQS_5, - hpriv->main_mask_reg_addr); + hpriv->main_irq_mask_addr); else writelfl(~HC_MAIN_MASKED_IRQS, - hpriv->main_mask_reg_addr); + hpriv->main_irq_mask_addr); VPRINTK("HC MAIN IRQ cause/mask=0x%08x/0x%08x " "PCI int cause/mask=0x%08x/0x%08x\n", - readl(hpriv->main_cause_reg_addr), - readl(hpriv->main_mask_reg_addr), + readl(hpriv->main_irq_cause_addr), + readl(hpriv->main_irq_mask_addr), readl(mmio + hpriv->irq_cause_ofs), readl(mmio + hpriv->irq_mask_ofs)); } else { writelfl(~HC_MAIN_MASKED_IRQS_SOC, - hpriv->main_mask_reg_addr); + hpriv->main_irq_mask_addr); VPRINTK("HC MAIN IRQ cause/mask=0x%08x/0x%08x\n", - readl(hpriv->main_cause_reg_addr), - readl(hpriv->main_mask_reg_addr)); + readl(hpriv->main_irq_cause_addr), + readl(hpriv->main_irq_mask_addr)); } done: return rc; diff --git a/drivers/atm/nicstar.c b/drivers/atm/nicstar.c index 38c769f8d2b..3da804b1627 100644 --- a/drivers/atm/nicstar.c +++ b/drivers/atm/nicstar.c @@ -415,7 +415,7 @@ static int __devinit ns_init_card(int i, struct pci_dev *pcidev) card->pcidev = pcidev; membase = pci_resource_start(pcidev, 1); card->membase = ioremap(membase, NS_IOREMAP_SIZE); - if (card->membase == 0) + if (!card->membase) { printk("nicstar%d: can't ioremap() membase.\n",i); error = 3; diff --git a/drivers/base/core.c b/drivers/base/core.c index 9248e0927d0..be288b5e418 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -787,6 +787,10 @@ int device_add(struct device *dev) parent = get_device(dev->parent); setup_parent(dev, parent); + /* use parent numa_node */ + if (parent) + set_dev_node(dev, dev_to_node(parent)); + /* first, register with generic layer. */ error = kobject_add(&dev->kobj, dev->kobj.parent, "%s", dev->bus_id); if (error) @@ -1306,8 +1310,11 @@ int device_move(struct device *dev, struct device *new_parent) dev->parent = new_parent; if (old_parent) klist_remove(&dev->knode_parent); - if (new_parent) + if (new_parent) { klist_add_tail(&dev->knode_parent, &new_parent->klist_children); + set_dev_node(dev, dev_to_node(new_parent)); + } + if (!dev->class) goto out_put; error = device_move_class_links(dev, old_parent, new_parent); @@ -1317,9 +1324,12 @@ int device_move(struct device *dev, struct device *new_parent) if (!kobject_move(&dev->kobj, &old_parent->kobj)) { if (new_parent) klist_remove(&dev->knode_parent); - if (old_parent) + dev->parent = old_parent; + if (old_parent) { klist_add_tail(&dev->knode_parent, &old_parent->klist_children); + set_dev_node(dev, dev_to_node(old_parent)); + } } cleanup_glue_dir(dev, new_parent_kobj); put_device(new_parent); diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 1fef7df8c9d..9fd4a853414 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -396,6 +396,8 @@ _request_firmware(const struct firmware **firmware_p, const char *name, if (!firmware_p) return -EINVAL; + printk(KERN_INFO "firmware: requesting %s\n", name); + *firmware_p = firmware = kzalloc(sizeof(*firmware), GFP_KERNEL); if (!firmware) { printk(KERN_ERR "%s: kmalloc(struct firmware) failed\n", diff --git a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h index 280e71ee744..5b4c6e649c1 100644 --- a/drivers/block/aoe/aoe.h +++ b/drivers/block/aoe/aoe.h @@ -195,7 +195,6 @@ void aoedev_exit(void); struct aoedev *aoedev_by_aoeaddr(int maj, int min); struct aoedev *aoedev_by_sysminor_m(ulong sysminor); void aoedev_downdev(struct aoedev *d); -int aoedev_isbusy(struct aoedev *d); int aoedev_flush(const char __user *str, size_t size); int aoenet_init(void); diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index d00293ba3b4..8fc429cf82b 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -668,16 +668,16 @@ ataid_complete(struct aoedev *d, struct aoetgt *t, unsigned char *id) u16 n; /* word 83: command set supported */ - n = le16_to_cpu(get_unaligned((__le16 *) &id[83<<1])); + n = get_unaligned_le16(&id[83 << 1]); /* word 86: command set/feature enabled */ - n |= le16_to_cpu(get_unaligned((__le16 *) &id[86<<1])); + n |= get_unaligned_le16(&id[86 << 1]); if (n & (1<<10)) { /* bit 10: LBA 48 */ d->flags |= DEVFL_EXT; /* word 100: number lba48 sectors */ - ssize = le64_to_cpu(get_unaligned((__le64 *) &id[100<<1])); + ssize = get_unaligned_le64(&id[100 << 1]); /* set as in ide-disk.c:init_idedisk_capacity */ d->geo.cylinders = ssize; @@ -688,12 +688,12 @@ ataid_complete(struct aoedev *d, struct aoetgt *t, unsigned char *id) d->flags &= ~DEVFL_EXT; /* number lba28 sectors */ - ssize = le32_to_cpu(get_unaligned((__le32 *) &id[60<<1])); + ssize = get_unaligned_le32(&id[60 << 1]); /* NOTE: obsolete in ATA 6 */ - d->geo.cylinders = le16_to_cpu(get_unaligned((__le16 *) &id[54<<1])); - d->geo.heads = le16_to_cpu(get_unaligned((__le16 *) &id[55<<1])); - d->geo.sectors = le16_to_cpu(get_unaligned((__le16 *) &id[56<<1])); + d->geo.cylinders = get_unaligned_le16(&id[54 << 1]); + d->geo.heads = get_unaligned_le16(&id[55 << 1]); + d->geo.sectors = get_unaligned_le16(&id[56 << 1]); } if (d->ssize != ssize) @@ -779,7 +779,7 @@ aoecmd_ata_rsp(struct sk_buff *skb) u16 aoemajor; hin = (struct aoe_hdr *) skb_mac_header(skb); - aoemajor = be16_to_cpu(get_unaligned(&hin->major)); + aoemajor = get_unaligned_be16(&hin->major); d = aoedev_by_aoeaddr(aoemajor, hin->minor); if (d == NULL) { snprintf(ebuf, sizeof ebuf, "aoecmd_ata_rsp: ata response " @@ -791,7 +791,7 @@ aoecmd_ata_rsp(struct sk_buff *skb) spin_lock_irqsave(&d->lock, flags); - n = be32_to_cpu(get_unaligned(&hin->tag)); + n = get_unaligned_be32(&hin->tag); t = gettgt(d, hin->src); if (t == NULL) { printk(KERN_INFO "aoe: can't find target e%ld.%d:%012llx\n", @@ -806,9 +806,9 @@ aoecmd_ata_rsp(struct sk_buff *skb) snprintf(ebuf, sizeof ebuf, "%15s e%d.%d tag=%08x@%08lx\n", "unexpected rsp", - be16_to_cpu(get_unaligned(&hin->major)), + get_unaligned_be16(&hin->major), hin->minor, - be32_to_cpu(get_unaligned(&hin->tag)), + get_unaligned_be32(&hin->tag), jiffies); aoechr_error(ebuf); return; @@ -873,7 +873,7 @@ aoecmd_ata_rsp(struct sk_buff *skb) printk(KERN_INFO "aoe: unrecognized ata command %2.2Xh for %d.%d\n", ahout->cmdstat, - be16_to_cpu(get_unaligned(&hin->major)), + get_unaligned_be16(&hin->major), hin->minor); } } diff --git a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c index f9a1cd9edb7..a1d813ab0d6 100644 --- a/drivers/block/aoe/aoedev.c +++ b/drivers/block/aoe/aoedev.c @@ -18,24 +18,6 @@ static void skbpoolfree(struct aoedev *d); static struct aoedev *devlist; static DEFINE_SPINLOCK(devlist_lock); -int -aoedev_isbusy(struct aoedev *d) -{ - struct aoetgt **t, **te; - struct frame *f, *e; - - t = d->targets; - te = t + NTARGETS; - for (; t < te && *t; t++) { - f = (*t)->frames; - e = f + (*t)->nframes; - for (; f < e; f++) - if (f->tag != FREETAG) - return 1; - } - return 0; -} - struct aoedev * aoedev_by_aoeaddr(int maj, int min) { diff --git a/drivers/block/aoe/aoenet.c b/drivers/block/aoe/aoenet.c index 18d243c73ee..d625169c8e4 100644 --- a/drivers/block/aoe/aoenet.c +++ b/drivers/block/aoe/aoenet.c @@ -128,7 +128,7 @@ aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt, skb_push(skb, ETH_HLEN); /* (1) */ h = (struct aoe_hdr *) skb_mac_header(skb); - n = be32_to_cpu(get_unaligned(&h->tag)); + n = get_unaligned_be32(&h->tag); if ((h->verfl & AOEFL_RSP) == 0 || (n & 1<<31)) goto exit; @@ -140,7 +140,7 @@ aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt, printk(KERN_ERR "%s%d.%d@%s; ecode=%d '%s'\n", "aoe: error packet from ", - be16_to_cpu(get_unaligned(&h->major)), + get_unaligned_be16(&h->major), h->minor, skb->dev->name, h->err, aoe_errlist[n]); goto exit; diff --git a/drivers/block/brd.c b/drivers/block/brd.c index 7bd76639544..e8e38faeafd 100644 --- a/drivers/block/brd.c +++ b/drivers/block/brd.c @@ -319,7 +319,7 @@ out: #ifdef CONFIG_BLK_DEV_XIP static int brd_direct_access (struct block_device *bdev, sector_t sector, - unsigned long *data) + void **kaddr, unsigned long *pfn) { struct brd_device *brd = bdev->bd_disk->private_data; struct page *page; @@ -333,7 +333,8 @@ static int brd_direct_access (struct block_device *bdev, sector_t sector, page = brd_insert_page(brd, sector); if (!page) return -ENOMEM; - *data = (unsigned long)page_address(page); + *kaddr = page_address(page); + *pfn = page_to_pfn(page); return 0; } diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index cf6083a1f92..e539be5750d 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -425,7 +425,7 @@ static void __devinit cciss_procinit(int i) struct proc_dir_entry *pde; if (proc_cciss == NULL) - proc_cciss = proc_mkdir("cciss", proc_root_driver); + proc_cciss = proc_mkdir("driver/cciss", NULL); if (!proc_cciss) return; pde = proc_create(hba[i]->devname, S_IWUSR | S_IRUSR | S_IRGRP | @@ -3700,7 +3700,7 @@ static void __exit cciss_cleanup(void) cciss_remove_one(hba[i]->pdev); } } - remove_proc_entry("cciss", proc_root_driver); + remove_proc_entry("driver/cciss", NULL); } static void fail_all_cmds(unsigned long ctlr) diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c index 69199185ff4..09c14341e6e 100644 --- a/drivers/block/cpqarray.c +++ b/drivers/block/cpqarray.c @@ -214,7 +214,7 @@ static struct proc_dir_entry *proc_array; static void __init ida_procinit(int i) { if (proc_array == NULL) { - proc_array = proc_mkdir("cpqarray", proc_root_driver); + proc_array = proc_mkdir("driver/cpqarray", NULL); if (!proc_array) return; } @@ -1796,7 +1796,7 @@ static void __exit cpqarray_exit(void) } } - remove_proc_entry("cpqarray", proc_root_driver); + remove_proc_entry("driver/cpqarray", NULL); } module_init(cpqarray_init) diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 7652e87d60c..395f8ea7981 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -4526,14 +4526,15 @@ static void __init parse_floppy_cfg_string(char *cfg) } } -int __init init_module(void) +static int __init floppy_module_init(void) { if (floppy) parse_floppy_cfg_string(floppy); return floppy_init(); } +module_init(floppy_module_init); -void cleanup_module(void) +static void __exit floppy_module_exit(void) { int drive; @@ -4562,6 +4563,7 @@ void cleanup_module(void) /* eject disk, if any */ fd_eject(0); } +module_exit(floppy_module_exit); module_param(floppy, charp, 0); module_param(FLOPPY_IRQ, int, 0); diff --git a/drivers/block/loop.c b/drivers/block/loop.c index f7f163557aa..d3a25b027ff 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -546,7 +546,7 @@ static void loop_unplug(struct request_queue *q) { struct loop_device *lo = q->queuedata; - clear_bit(QUEUE_FLAG_PLUGGED, &q->queue_flags); + queue_flag_clear_unlocked(QUEUE_FLAG_PLUGGED, q); blk_run_address_space(lo->lo_backing_file->f_mapping); } diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 60cc54368b6..ad98dda6037 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -29,6 +29,7 @@ #include <linux/kernel.h> #include <net/sock.h> #include <linux/net.h> +#include <linux/kthread.h> #include <asm/uaccess.h> #include <asm/system.h> @@ -55,6 +56,7 @@ static unsigned int debugflags; static unsigned int nbds_max = 16; static struct nbd_device *nbd_dev; +static int max_part; /* * Use just one lock (or at most 1 per NIC). Two arguments for this: @@ -337,7 +339,7 @@ static struct request *nbd_read_stat(struct nbd_device *lo) } req = nbd_find_request(lo, *(struct request **)reply.handle); - if (unlikely(IS_ERR(req))) { + if (IS_ERR(req)) { result = PTR_ERR(req); if (result != -ENOENT) goto harderror; @@ -441,6 +443,85 @@ static void nbd_clear_que(struct nbd_device *lo) } +static void nbd_handle_req(struct nbd_device *lo, struct request *req) +{ + if (!blk_fs_request(req)) + goto error_out; + + nbd_cmd(req) = NBD_CMD_READ; + if (rq_data_dir(req) == WRITE) { + nbd_cmd(req) = NBD_CMD_WRITE; + if (lo->flags & NBD_READ_ONLY) { + printk(KERN_ERR "%s: Write on read-only\n", + lo->disk->disk_name); + goto error_out; + } + } + + req->errors = 0; + + mutex_lock(&lo->tx_lock); + if (unlikely(!lo->sock)) { + mutex_unlock(&lo->tx_lock); + printk(KERN_ERR "%s: Attempted send on closed socket\n", + lo->disk->disk_name); + req->errors++; + nbd_end_request(req); + return; + } + + lo->active_req = req; + + if (nbd_send_req(lo, req) != 0) { + printk(KERN_ERR "%s: Request send failed\n", + lo->disk->disk_name); + req->errors++; + nbd_end_request(req); + } else { + spin_lock(&lo->queue_lock); + list_add(&req->queuelist, &lo->queue_head); + spin_unlock(&lo->queue_lock); + } + + lo->active_req = NULL; + mutex_unlock(&lo->tx_lock); + wake_up_all(&lo->active_wq); + + return; + +error_out: + req->errors++; + nbd_end_request(req); +} + +static int nbd_thread(void *data) +{ + struct nbd_device *lo = data; + struct request *req; + + set_user_nice(current, -20); + while (!kthread_should_stop() || !list_empty(&lo->waiting_queue)) { + /* wait for something to do */ + wait_event_interruptible(lo->waiting_wq, + kthread_should_stop() || + !list_empty(&lo->waiting_queue)); + + /* extract request */ + if (list_empty(&lo->waiting_queue)) + continue; + + spin_lock_irq(&lo->queue_lock); + req = list_entry(lo->waiting_queue.next, struct request, + queuelist); + list_del_init(&req->queuelist); + spin_unlock_irq(&lo->queue_lock); + + /* handle request */ + nbd_handle_req(lo, req); + } + return 0; +} + /* * We always wait for result of write, for now. It would be nice to make it optional * in future @@ -456,65 +537,23 @@ static void do_nbd_request(struct request_queue * q) struct nbd_device *lo; blkdev_dequeue_request(req); + + spin_unlock_irq(q->queue_lock); + dprintk(DBG_BLKDEV, "%s: request %p: dequeued (flags=%x)\n", req->rq_disk->disk_name, req, req->cmd_type); - if (!blk_fs_request(req)) - goto error_out; - lo = req->rq_disk->private_data; BUG_ON(lo->magic != LO_MAGIC); - nbd_cmd(req) = NBD_CMD_READ; - if (rq_data_dir(req) == WRITE) { - nbd_cmd(req) = NBD_CMD_WRITE; - if (lo->flags & NBD_READ_ONLY) { - printk(KERN_ERR "%s: Write on read-only\n", - lo->disk->disk_name); - goto error_out; - } - } - - req->errors = 0; - spin_unlock_irq(q->queue_lock); - - mutex_lock(&lo->tx_lock); - if (unlikely(!lo->sock)) { - mutex_unlock(&lo->tx_lock); - printk(KERN_ERR "%s: Attempted send on closed socket\n", - lo->disk->disk_name); - req->errors++; - nbd_end_request(req); - spin_lock_irq(q->queue_lock); - continue; - } - - lo->active_req = req; + spin_lock_irq(&lo->queue_lock); + list_add_tail(&req->queuelist, &lo->waiting_queue); + spin_unlock_irq(&lo->queue_lock); - if (nbd_send_req(lo, req) != 0) { - printk(KERN_ERR "%s: Request send failed\n", - lo->disk->disk_name); - req->errors++; - nbd_end_request(req); - } else { - spin_lock(&lo->queue_lock); - list_add(&req->queuelist, &lo->queue_head); - spin_unlock(&lo->queue_lock); - } - - lo->active_req = NULL; - mutex_unlock(&lo->tx_lock); - wake_up_all(&lo->active_wq); + wake_up(&lo->waiting_wq); spin_lock_irq(q->queue_lock); - continue; - -error_out: - req->errors++; - spin_unlock(q->queue_lock); - nbd_end_request(req); - spin_lock(q->queue_lock); } } @@ -524,6 +563,7 @@ static int nbd_ioctl(struct inode *inode, struct file *file, struct nbd_device *lo = inode->i_bdev->bd_disk->private_data; int error; struct request sreq ; + struct task_struct *thread; if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -537,6 +577,7 @@ static int nbd_ioctl(struct inode *inode, struct file *file, switch (cmd) { case NBD_DISCONNECT: printk(KERN_INFO "%s: NBD_DISCONNECT\n", lo->disk->disk_name); + blk_rq_init(NULL, &sreq); sreq.cmd_type = REQ_TYPE_SPECIAL; nbd_cmd(&sreq) = NBD_CMD_DISC; /* @@ -571,10 +612,13 @@ static int nbd_ioctl(struct inode *inode, struct file *file, error = -EINVAL; file = fget(arg); if (file) { + struct block_device *bdev = inode->i_bdev; inode = file->f_path.dentry->d_inode; if (S_ISSOCK(inode->i_mode)) { lo->file = file; lo->sock = SOCKET_I(inode); + if (max_part > 0) + bdev->bd_invalidated = 1; error = 0; } else { fput(file); @@ -606,7 +650,12 @@ static int nbd_ioctl(struct inode *inode, struct file *file, case NBD_DO_IT: if (!lo->file) return -EINVAL; + thread = kthread_create(nbd_thread, lo, lo->disk->disk_name); + if (IS_ERR(thread)) + return PTR_ERR(thread); + wake_up_process(thread); error = nbd_do_it(lo); + kthread_stop(thread); if (error) return error; sock_shutdown(lo, 1); @@ -619,6 +668,8 @@ static int nbd_ioctl(struct inode *inode, struct file *file, lo->bytesize = 0; inode->i_bdev->bd_inode->i_size = 0; set_capacity(lo->disk, 0); + if (max_part > 0) + ioctl_by_bdev(inode->i_bdev, BLKRRPART, 0); return lo->harderror; case NBD_CLEAR_QUE: /* @@ -652,6 +703,7 @@ static int __init nbd_init(void) { int err = -ENOMEM; int i; + int part_shift; BUILD_BUG_ON(sizeof(struct nbd_request) != 28); @@ -659,8 +711,17 @@ static int __init nbd_init(void) if (!nbd_dev) return -ENOMEM; + if (max_part < 0) { + printk(KERN_CRIT "nbd: max_part must be >= 0\n"); + return -EINVAL; + } + + part_shift = 0; + if (max_part > 0) + part_shift = fls(max_part); + for (i = 0; i < nbds_max; i++) { - struct gendisk *disk = alloc_disk(1); + struct gendisk *disk = alloc_disk(1 << part_shift); elevator_t *old_e; if (!disk) goto out; @@ -695,17 +756,18 @@ static int __init nbd_init(void) nbd_dev[i].file = NULL; nbd_dev[i].magic = LO_MAGIC; nbd_dev[i].flags = 0; + INIT_LIST_HEAD(&nbd_dev[i].waiting_queue); spin_lock_init(&nbd_dev[i].queue_lock); INIT_LIST_HEAD(&nbd_dev[i].queue_head); mutex_init(&nbd_dev[i].tx_lock); init_waitqueue_head(&nbd_dev[i].active_wq); + init_waitqueue_head(&nbd_dev[i].waiting_wq); nbd_dev[i].blksize = 1024; nbd_dev[i].bytesize = 0; disk->major = NBD_MAJOR; - disk->first_minor = i; + disk->first_minor = i << part_shift; disk->fops = &nbd_fops; disk->private_data = &nbd_dev[i]; - disk->flags |= GENHD_FL_SUPPRESS_PARTITION_INFO; sprintf(disk->disk_name, "nbd%d", i); set_capacity(disk, 0); add_disk(disk); @@ -743,7 +805,9 @@ MODULE_DESCRIPTION("Network Block Device"); MODULE_LICENSE("GPL"); module_param(nbds_max, int, 0444); -MODULE_PARM_DESC(nbds_max, "How many network block devices to initialize."); +MODULE_PARM_DESC(nbds_max, "number of network block devices to initialize (default: 16)"); +module_param(max_part, int, 0444); +MODULE_PARM_DESC(max_part, "number of partitions per device (default: 0)"); #ifndef NDEBUG module_param(debugflags, int, 0644); MODULE_PARM_DESC(debugflags, "flags for controlling debug output"); diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c index df819f8a95a..570f3b70dce 100644 --- a/drivers/block/paride/pd.c +++ b/drivers/block/paride/pd.c @@ -716,10 +716,8 @@ static int pd_special_command(struct pd_unit *disk, struct request rq; int err = 0; - memset(&rq, 0, sizeof(rq)); - rq.errors = 0; + blk_rq_init(NULL, &rq); rq.rq_disk = disk->gd; - rq.ref_count = 1; rq.end_io_data = &wait; rq.end_io = blk_end_sync_rq; blk_insert_request(disk->gd->queue, &rq, 0, func); diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 18feb1c7c33..3ba1df93e9e 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -776,8 +776,6 @@ static int pkt_generic_packet(struct pktcdvd_device *pd, struct packet_command * rq->cmd_len = COMMAND_SIZE(cgc->cmd[0]); memcpy(rq->cmd, cgc->cmd, CDROM_PACKET_SIZE); - if (sizeof(rq->cmd) > CDROM_PACKET_SIZE) - memset(rq->cmd + CDROM_PACKET_SIZE, 0, sizeof(rq->cmd) - CDROM_PACKET_SIZE); rq->timeout = 60*HZ; rq->cmd_type = REQ_TYPE_BLOCK_PC; @@ -2744,7 +2742,6 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev) int i; int ret = 0; char b[BDEVNAME_SIZE]; - struct proc_dir_entry *proc; struct block_device *bdev; if (pd->pkt_dev == dev) { @@ -2788,11 +2785,7 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev) goto out_mem; } - proc = create_proc_entry(pd->name, 0, pkt_proc); - if (proc) { - proc->data = pd; - proc->proc_fops = &pkt_proc_fops; - } + proc_create_data(pd->name, 0, pkt_proc, &pkt_proc_fops, pd); DPRINTK(DRIVER_NAME": writer %s mapped to %s\n", pd->name, bdevname(bdev, b)); return 0; @@ -3101,7 +3094,7 @@ static int __init pkt_init(void) goto out_misc; } - pkt_proc = proc_mkdir(DRIVER_NAME, proc_root_driver); + pkt_proc = proc_mkdir("driver/"DRIVER_NAME, NULL); return 0; @@ -3117,7 +3110,7 @@ out2: static void __exit pkt_exit(void) { - remove_proc_entry(DRIVER_NAME, proc_root_driver); + remove_proc_entry("driver/"DRIVER_NAME, NULL); misc_deregister(&pkt_misc); pkt_debugfs_cleanup(); diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c index 7483f947f0e..d797e209951 100644 --- a/drivers/block/ps3disk.c +++ b/drivers/block/ps3disk.c @@ -102,8 +102,7 @@ static void ps3disk_scatter_gather(struct ps3_storage_device *dev, dev_dbg(&dev->sbd.core, "%s:%u: bio %u: %u segs %u sectors from %lu\n", __func__, __LINE__, i, bio_segments(iter.bio), - bio_sectors(iter.bio), - (unsigned long)iter.bio->bi_sector); + bio_sectors(iter.bio), iter.bio->bi_sector); size = bvec->bv_len; buf = bvec_kmap_irq(bvec, &flags); @@ -406,7 +405,6 @@ static void ps3disk_prepare_flush(struct request_queue *q, struct request *req) dev_dbg(&dev->sbd.core, "%s:%u\n", __func__, __LINE__); - memset(req->cmd, 0, sizeof(req->cmd)); req->cmd_type = REQ_TYPE_FLUSH; } diff --git a/drivers/block/ub.c b/drivers/block/ub.c index 27bfe72aab5..e322cce8c12 100644 --- a/drivers/block/ub.c +++ b/drivers/block/ub.c @@ -2399,7 +2399,7 @@ static void ub_disconnect(struct usb_interface *intf) del_gendisk(lun->disk); /* * I wish I could do: - * set_bit(QUEUE_FLAG_DEAD, &q->queue_flags); + * queue_flag_set(QUEUE_FLAG_DEAD, q); * As it is, we rely on our internal poisoning and let * the upper levels to spin furiously failing all the I/O. */ diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index d771da816d9..f2fff5799dd 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -137,7 +137,7 @@ static void blkif_restart_queue_callback(void *arg) schedule_work(&info->work); } -int blkif_getgeo(struct block_device *bd, struct hd_geometry *hg) +static int blkif_getgeo(struct block_device *bd, struct hd_geometry *hg) { /* We don't have real geometry info, but let's at least return values consistent with the size of the device */ diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index ac3829030ac..69f26eb6415 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -2194,7 +2194,6 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf, if (ret) break; - memset(rq->cmd, 0, sizeof(rq->cmd)); rq->cmd[0] = GPCMD_READ_CD; rq->cmd[1] = 1 << 2; rq->cmd[2] = (lba >> 24) & 0xff; diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c index b74b6c2768a..5245a4a0ba7 100644 --- a/drivers/cdrom/viocd.c +++ b/drivers/cdrom/viocd.c @@ -144,6 +144,7 @@ static int proc_viocd_open(struct inode *inode, struct file *file) } static const struct file_operations proc_viocd_operations = { + .owner = THIS_MODULE, .open = proc_viocd_open, .read = seq_read, .llseek = seq_lseek, @@ -679,7 +680,6 @@ static struct vio_driver viocd_driver = { static int __init viocd_init(void) { - struct proc_dir_entry *e; int ret = 0; if (!firmware_has_feature(FW_FEATURE_ISERIES)) @@ -719,12 +719,8 @@ static int __init viocd_init(void) if (ret) goto out_free_info; - e = create_proc_entry("iSeries/viocd", S_IFREG|S_IRUGO, NULL); - if (e) { - e->owner = THIS_MODULE; - e->proc_fops = &proc_viocd_operations; - } - + proc_create("iSeries/viocd", S_IFREG|S_IRUGO, NULL, + &proc_viocd_operations); return 0; out_free_info: diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 2906ee7bd29..5dce3877eee 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -80,6 +80,15 @@ config VT_HW_CONSOLE_BINDING information. For framebuffer console users, please refer to <file:Documentation/fb/fbcon.txt>. +config DEVKMEM + bool "/dev/kmem virtual device support" + default y + help + Say Y here if you want to support the /dev/kmem device. The + /dev/kmem device is rarely used, but can be used for certain + kind of kernel debugging operations. + When in doubt, say "N". + config SERIAL_NONSTANDARD bool "Non-standard serial port support" depends on HAS_IOMEM @@ -732,9 +741,16 @@ config NVRAM To compile this driver as a module, choose M here: the module will be called nvram. +# +# These legacy RTC drivers just cause too many conflicts with the generic +# RTC framework ... let's not even try to coexist any more. +# +if RTC_LIB=n + config RTC tristate "Enhanced Real Time Clock Support" - depends on !PPC && !PARISC && !IA64 && !M68K && !SPARC && !FRV && !ARM && !SUPERH && !S390 && !AVR32 + depends on !PPC && !PARISC && !IA64 && !M68K && !SPARC && !FRV \ + && !ARM && !SUPERH && !S390 && !AVR32 ---help--- If you say Y here and create a character special file /dev/rtc with major number 10 and minor number 135 using mknod ("man mknod"), you @@ -840,6 +856,8 @@ config DS1302 will get access to the real time clock (or hardware clock) built into your computer. +endif # RTC_LIB + config COBALT_LCD bool "Support for Cobalt LCD" depends on MIPS_COBALT diff --git a/drivers/char/apm-emulation.c b/drivers/char/apm-emulation.c index 17d54315e14..cdd876dbb2b 100644 --- a/drivers/char/apm-emulation.c +++ b/drivers/char/apm-emulation.c @@ -14,6 +14,7 @@ #include <linux/poll.h> #include <linux/slab.h> #include <linux/proc_fs.h> +#include <linux/seq_file.h> #include <linux/miscdevice.h> #include <linux/apm_bios.h> #include <linux/capability.h> @@ -493,11 +494,10 @@ static struct miscdevice apm_device = { * -1: Unknown * 8) min = minutes; sec = seconds */ -static int apm_get_info(char *buf, char **start, off_t fpos, int length) +static int proc_apm_show(struct seq_file *m, void *v) { struct apm_power_info info; char *units; - int ret; info.ac_line_status = 0xff; info.battery_status = 0xff; @@ -515,14 +515,27 @@ static int apm_get_info(char *buf, char **start, off_t fpos, int length) case 1: units = "sec"; break; } - ret = sprintf(buf, "%s 1.2 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n", + seq_printf(m, "%s 1.2 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n", driver_version, APM_32_BIT_SUPPORT, info.ac_line_status, info.battery_status, info.battery_flag, info.battery_life, info.time, units); - return ret; + return 0; } + +static int proc_apm_open(struct inode *inode, struct file *file) +{ + return single_open(file, proc_apm_show, NULL); +} + +static const struct file_operations apm_proc_fops = { + .owner = THIS_MODULE, + .open = proc_apm_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; #endif static int kapmd(void *arg) @@ -593,7 +606,7 @@ static int __init apm_init(void) wake_up_process(kapmd_tsk); #ifdef CONFIG_PROC_FS - create_proc_info_entry("apm", 0, NULL, apm_get_info); + proc_create("apm", 0, NULL, &apm_proc_fops); #endif ret = misc_register(&apm_device); diff --git a/drivers/char/cs5535_gpio.c b/drivers/char/cs5535_gpio.c index c2d23cae951..c0a4a0bb509 100644 --- a/drivers/char/cs5535_gpio.c +++ b/drivers/char/cs5535_gpio.c @@ -215,7 +215,7 @@ static int __init cs5535_gpio_init(void) else mask = 0x0b003c66; - if (request_region(gpio_base, CS5535_GPIO_SIZE, NAME) == 0) { + if (!request_region(gpio_base, CS5535_GPIO_SIZE, NAME)) { printk(KERN_ERR NAME ": can't allocate I/O for GPIO\n"); return -ENODEV; } diff --git a/drivers/char/drm/r128_cce.c b/drivers/char/drm/r128_cce.c index f36adbd3aaf..c31afbde62e 100644 --- a/drivers/char/drm/r128_cce.c +++ b/drivers/char/drm/r128_cce.c @@ -817,7 +817,7 @@ static struct drm_buf *r128_freelist_get(struct drm_device * dev) for (i = 0; i < dma->buf_count; i++) { buf = dma->buflist[i]; buf_priv = buf->dev_private; - if (buf->file_priv == 0) + if (!buf->file_priv) return buf; } diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c index 8609b8236c6..f49037b744f 100644 --- a/drivers/char/i8k.c +++ b/drivers/char/i8k.c @@ -82,6 +82,7 @@ static int i8k_ioctl(struct inode *, struct file *, unsigned int, unsigned long); static const struct file_operations i8k_fops = { + .owner = THIS_MODULE, .open = i8k_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -554,13 +555,10 @@ static int __init i8k_init(void) return -ENODEV; /* Register the proc entry */ - proc_i8k = create_proc_entry("i8k", 0, NULL); + proc_i8k = proc_create("i8k", 0, NULL, &i8k_fops); if (!proc_i8k) return -ENOENT; - proc_i8k->proc_fops = &i8k_fops; - proc_i8k->owner = THIS_MODULE; - printk(KERN_INFO "Dell laptop SMM driver v%s Massimo Dal Zotto (dz@debian.org)\n", I8K_VERSION); diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c index b1d6cad8428..0a61856c631 100644 --- a/drivers/char/ip2/ip2main.c +++ b/drivers/char/ip2/ip2main.c @@ -133,8 +133,9 @@ *****************/ #include <linux/proc_fs.h> +#include <linux/seq_file.h> -static int ip2_read_procmem(char *, char **, off_t, int); +static const struct file_operations ip2mem_proc_fops; static int ip2_read_proc(char *, char **, off_t, int, int *, void * ); /********************/ @@ -423,7 +424,7 @@ cleanup_module(void) } put_tty_driver(ip2_tty_driver); unregister_chrdev(IP2_IPL_MAJOR, pcIpl); - remove_proc_entry("ip2mem", &proc_root); + remove_proc_entry("ip2mem", NULL); // free memory for (i = 0; i < IP2_MAX_BOARDS; i++) { @@ -695,7 +696,7 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize) } } /* Register the read_procmem thing */ - if (!create_proc_info_entry("ip2mem",0,&proc_root,ip2_read_procmem)) { + if (!proc_create("ip2mem",0,NULL,&ip2mem_proc_fops)) { printk(KERN_ERR "IP2: failed to register read_procmem\n"); } else { @@ -2967,65 +2968,61 @@ ip2_ipl_open( struct inode *pInode, struct file *pFile ) } return 0; } -/******************************************************************************/ -/* Function: ip2_read_procmem */ -/* Parameters: */ -/* */ -/* Returns: Length of output */ -/* */ -/* Description: */ -/* Supplies some driver operating parameters */ -/* Not real useful unless your debugging the fifo */ -/* */ -/******************************************************************************/ - -#define LIMIT (PAGE_SIZE - 120) static int -ip2_read_procmem(char *buf, char **start, off_t offset, int len) +proc_ip2mem_show(struct seq_file *m, void *v) { i2eBordStrPtr pB; i2ChanStrPtr pCh; PTTY tty; int i; - len = 0; - #define FMTLINE "%3d: 0x%08x 0x%08x 0%011o 0%011o\n" #define FMTLIN2 " 0x%04x 0x%04x tx flow 0x%x\n" #define FMTLIN3 " 0x%04x 0x%04x rc flow\n" - len += sprintf(buf+len,"\n"); + seq_printf(m,"\n"); for( i = 0; i < IP2_MAX_BOARDS; ++i ) { pB = i2BoardPtrTable[i]; if ( pB ) { - len += sprintf(buf+len,"board %d:\n",i); - len += sprintf(buf+len,"\tFifo rem: %d mty: %x outM %x\n", + seq_printf(m,"board %d:\n",i); + seq_printf(m,"\tFifo rem: %d mty: %x outM %x\n", pB->i2eFifoRemains,pB->i2eWaitingForEmptyFifo,pB->i2eOutMailWaiting); } } - len += sprintf(buf+len,"#: tty flags, port flags, cflags, iflags\n"); + seq_printf(m,"#: tty flags, port flags, cflags, iflags\n"); for (i=0; i < IP2_MAX_PORTS; i++) { - if (len > LIMIT) - break; pCh = DevTable[i]; if (pCh) { tty = pCh->pTTY; if (tty && tty->count) { - len += sprintf(buf+len,FMTLINE,i,(int)tty->flags,pCh->flags, + seq_printf(m,FMTLINE,i,(int)tty->flags,pCh->flags, tty->termios->c_cflag,tty->termios->c_iflag); - len += sprintf(buf+len,FMTLIN2, + seq_printf(m,FMTLIN2, pCh->outfl.asof,pCh->outfl.room,pCh->channelNeeds); - len += sprintf(buf+len,FMTLIN3,pCh->infl.asof,pCh->infl.room); + seq_printf(m,FMTLIN3,pCh->infl.asof,pCh->infl.room); } } } - return len; + return 0; +} + +static int proc_ip2mem_open(struct inode *inode, struct file *file) +{ + return single_open(file, proc_ip2mem_show, NULL); } +static const struct file_operations ip2mem_proc_fops = { + .owner = THIS_MODULE, + .open = proc_ip2mem_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + /* * This is the handler for /proc/tty/driver/ip2 * diff --git a/drivers/char/ipmi/Makefile b/drivers/char/ipmi/Makefile index 553f0a408ed..eb8a1a8c188 100644 --- a/drivers/char/ipmi/Makefile +++ b/drivers/char/ipmi/Makefile @@ -9,7 +9,3 @@ obj-$(CONFIG_IPMI_DEVICE_INTERFACE) += ipmi_devintf.o obj-$(CONFIG_IPMI_SI) += ipmi_si.o obj-$(CONFIG_IPMI_WATCHDOG) += ipmi_watchdog.o obj-$(CONFIG_IPMI_POWEROFF) += ipmi_poweroff.o - -ipmi_si.o: $(ipmi_si-objs) - $(LD) -r -o $@ $(ipmi_si-objs) - diff --git a/drivers/char/ipmi/ipmi_bt_sm.c b/drivers/char/ipmi/ipmi_bt_sm.c index e736119b649..7b98c067190 100644 --- a/drivers/char/ipmi/ipmi_bt_sm.c +++ b/drivers/char/ipmi/ipmi_bt_sm.c @@ -37,26 +37,32 @@ #define BT_DEBUG_ENABLE 1 /* Generic messages */ #define BT_DEBUG_MSG 2 /* Prints all request/response buffers */ #define BT_DEBUG_STATES 4 /* Verbose look at state changes */ -/* BT_DEBUG_OFF must be zero to correspond to the default uninitialized - value */ +/* + * BT_DEBUG_OFF must be zero to correspond to the default uninitialized + * value + */ static int bt_debug; /* 0 == BT_DEBUG_OFF */ module_param(bt_debug, int, 0644); MODULE_PARM_DESC(bt_debug, "debug bitmask, 1=enable, 2=messages, 4=states"); -/* Typical "Get BT Capabilities" values are 2-3 retries, 5-10 seconds, - and 64 byte buffers. However, one HP implementation wants 255 bytes of - buffer (with a documented message of 160 bytes) so go for the max. - Since the Open IPMI architecture is single-message oriented at this - stage, the queue depth of BT is of no concern. */ +/* + * Typical "Get BT Capabilities" values are 2-3 retries, 5-10 seconds, + * and 64 byte buffers. However, one HP implementation wants 255 bytes of + * buffer (with a documented message of 160 bytes) so go for the max. + * Since the Open IPMI architecture is single-message oriented at this + * stage, the queue depth of BT is of no concern. + */ #define BT_NORMAL_TIMEOUT 5 /* seconds */ #define BT_NORMAL_RETRY_LIMIT 2 #define BT_RESET_DELAY 6 /* seconds after warm reset */ -/* States are written in chronological order and usually cover - multiple rows of the state table discussion in the IPMI spec. */ +/* + * States are written in chronological order and usually cover + * multiple rows of the state table discussion in the IPMI spec. + */ enum bt_states { BT_STATE_IDLE = 0, /* Order is critical in this list */ @@ -76,10 +82,12 @@ enum bt_states { BT_STATE_LONG_BUSY /* BT doesn't get hosed :-) */ }; -/* Macros seen at the end of state "case" blocks. They help with legibility - and debugging. */ +/* + * Macros seen at the end of state "case" blocks. They help with legibility + * and debugging. + */ -#define BT_STATE_CHANGE(X,Y) { bt->state = X; return Y; } +#define BT_STATE_CHANGE(X, Y) { bt->state = X; return Y; } #define BT_SI_SM_RETURN(Y) { last_printed = BT_STATE_PRINTME; return Y; } @@ -110,11 +118,13 @@ struct si_sm_data { #define BT_H_BUSY 0x40 #define BT_B_BUSY 0x80 -/* Some bits are toggled on each write: write once to set it, once - more to clear it; writing a zero does nothing. To absolutely - clear it, check its state and write if set. This avoids the "get - current then use as mask" scheme to modify one bit. Note that the - variable "bt" is hardcoded into these macros. */ +/* + * Some bits are toggled on each write: write once to set it, once + * more to clear it; writing a zero does nothing. To absolutely + * clear it, check its state and write if set. This avoids the "get + * current then use as mask" scheme to modify one bit. Note that the + * variable "bt" is hardcoded into these macros. + */ #define BT_STATUS bt->io->inputb(bt->io, 0) #define BT_CONTROL(x) bt->io->outputb(bt->io, 0, x) @@ -125,8 +135,10 @@ struct si_sm_data { #define BT_INTMASK_R bt->io->inputb(bt->io, 2) #define BT_INTMASK_W(x) bt->io->outputb(bt->io, 2, x) -/* Convenience routines for debugging. These are not multi-open safe! - Note the macros have hardcoded variables in them. */ +/* + * Convenience routines for debugging. These are not multi-open safe! + * Note the macros have hardcoded variables in them. + */ static char *state2txt(unsigned char state) { @@ -182,7 +194,8 @@ static char *status2txt(unsigned char status) static unsigned int bt_init_data(struct si_sm_data *bt, struct si_sm_io *io) { memset(bt, 0, sizeof(struct si_sm_data)); - if (bt->io != io) { /* external: one-time only things */ + if (bt->io != io) { + /* external: one-time only things */ bt->io = io; bt->seq = 0; } @@ -229,7 +242,7 @@ static int bt_start_transaction(struct si_sm_data *bt, printk(KERN_WARNING "BT: +++++++++++++++++ New command\n"); printk(KERN_WARNING "BT: NetFn/LUN CMD [%d data]:", size - 2); for (i = 0; i < size; i ++) - printk (" %02x", data[i]); + printk(" %02x", data[i]); printk("\n"); } bt->write_data[0] = size + 1; /* all data plus seq byte */ @@ -246,8 +259,10 @@ static int bt_start_transaction(struct si_sm_data *bt, return 0; } -/* After the upper state machine has been told SI_SM_TRANSACTION_COMPLETE - it calls this. Strip out the length and seq bytes. */ +/* + * After the upper state machine has been told SI_SM_TRANSACTION_COMPLETE + * it calls this. Strip out the length and seq bytes. + */ static int bt_get_result(struct si_sm_data *bt, unsigned char *data, @@ -269,10 +284,10 @@ static int bt_get_result(struct si_sm_data *bt, memcpy(data + 2, bt->read_data + 4, msg_len - 2); if (bt_debug & BT_DEBUG_MSG) { - printk (KERN_WARNING "BT: result %d bytes:", msg_len); + printk(KERN_WARNING "BT: result %d bytes:", msg_len); for (i = 0; i < msg_len; i++) printk(" %02x", data[i]); - printk ("\n"); + printk("\n"); } return msg_len; } @@ -292,8 +307,10 @@ static void reset_flags(struct si_sm_data *bt) BT_INTMASK_W(BT_BMC_HWRST); } -/* Get rid of an unwanted/stale response. This should only be needed for - BMCs that support multiple outstanding requests. */ +/* + * Get rid of an unwanted/stale response. This should only be needed for + * BMCs that support multiple outstanding requests. + */ static void drain_BMC2HOST(struct si_sm_data *bt) { @@ -326,8 +343,8 @@ static inline void write_all_bytes(struct si_sm_data *bt) printk(KERN_WARNING "BT: write %d bytes seq=0x%02X", bt->write_count, bt->seq); for (i = 0; i < bt->write_count; i++) - printk (" %02x", bt->write_data[i]); - printk ("\n"); + printk(" %02x", bt->write_data[i]); + printk("\n"); } for (i = 0; i < bt->write_count; i++) HOST2BMC(bt->write_data[i]); @@ -337,8 +354,10 @@ static inline int read_all_bytes(struct si_sm_data *bt) { unsigned char i; - /* length is "framing info", minimum = 4: NetFn, Seq, Cmd, cCode. - Keep layout of first four bytes aligned with write_data[] */ + /* + * length is "framing info", minimum = 4: NetFn, Seq, Cmd, cCode. + * Keep layout of first four bytes aligned with write_data[] + */ bt->read_data[0] = BMC2HOST; bt->read_count = bt->read_data[0]; @@ -362,8 +381,8 @@ static inline int read_all_bytes(struct si_sm_data *bt) if (max > 16) max = 16; for (i = 0; i < max; i++) - printk (" %02x", bt->read_data[i]); - printk ("%s\n", bt->read_count == max ? "" : " ..."); + printk(KERN_CONT " %02x", bt->read_data[i]); + printk(KERN_CONT "%s\n", bt->read_count == max ? "" : " ..."); } /* per the spec, the (NetFn[1], Seq[2], Cmd[3]) tuples must match */ @@ -402,8 +421,10 @@ static enum si_sm_result error_recovery(struct si_sm_data *bt, printk(KERN_WARNING "IPMI BT: %s in %s %s ", /* open-ended line */ reason, STATE2TXT, STATUS2TXT); - /* Per the IPMI spec, retries are based on the sequence number - known only to this module, so manage a restart here. */ + /* + * Per the IPMI spec, retries are based on the sequence number + * known only to this module, so manage a restart here. + */ (bt->error_retries)++; if (bt->error_retries < bt->BT_CAP_retries) { printk("%d retries left\n", @@ -412,8 +433,8 @@ static enum si_sm_result error_recovery(struct si_sm_data *bt, return SI_SM_CALL_WITHOUT_DELAY; } - printk("failed %d retries, sending error response\n", - bt->BT_CAP_retries); + printk(KERN_WARNING "failed %d retries, sending error response\n", + bt->BT_CAP_retries); if (!bt->nonzero_status) printk(KERN_ERR "IPMI BT: stuck, try power cycle\n"); @@ -424,8 +445,10 @@ static enum si_sm_result error_recovery(struct si_sm_data *bt, return SI_SM_CALL_WITHOUT_DELAY; } - /* Concoct a useful error message, set up the next state, and - be done with this sequence. */ + /* + * Concoct a useful error message, set up the next state, and + * be done with this sequence. + */ bt->state = BT_STATE_IDLE; switch (cCode) { @@ -461,10 +484,12 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time) last_printed = bt->state; } - /* Commands that time out may still (eventually) provide a response. - This stale response will get in the way of a new response so remove - it if possible (hopefully during IDLE). Even if it comes up later - it will be rejected by its (now-forgotten) seq number. */ + /* + * Commands that time out may still (eventually) provide a response. + * This stale response will get in the way of a new response so remove + * it if possible (hopefully during IDLE). Even if it comes up later + * it will be rejected by its (now-forgotten) seq number. + */ if ((bt->state < BT_STATE_WRITE_BYTES) && (status & BT_B2H_ATN)) { drain_BMC2HOST(bt); @@ -472,7 +497,8 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time) } if ((bt->state != BT_STATE_IDLE) && - (bt->state < BT_STATE_PRINTME)) { /* check timeout */ + (bt->state < BT_STATE_PRINTME)) { + /* check timeout */ bt->timeout -= time; if ((bt->timeout < 0) && (bt->state < BT_STATE_RESET1)) return error_recovery(bt, @@ -482,8 +508,10 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time) switch (bt->state) { - /* Idle state first checks for asynchronous messages from another - channel, then does some opportunistic housekeeping. */ + /* + * Idle state first checks for asynchronous messages from another + * channel, then does some opportunistic housekeeping. + */ case BT_STATE_IDLE: if (status & BT_SMS_ATN) { @@ -531,16 +559,19 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time) BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY); BT_CONTROL(BT_H_BUSY); /* set */ - /* Uncached, ordered writes should just proceeed serially but - some BMCs don't clear B2H_ATN with one hit. Fast-path a - workaround without too much penalty to the general case. */ + /* + * Uncached, ordered writes should just proceeed serially but + * some BMCs don't clear B2H_ATN with one hit. Fast-path a + * workaround without too much penalty to the general case. + */ BT_CONTROL(BT_B2H_ATN); /* clear it to ACK the BMC */ BT_STATE_CHANGE(BT_STATE_CLEAR_B2H, SI_SM_CALL_WITHOUT_DELAY); case BT_STATE_CLEAR_B2H: - if (status & BT_B2H_ATN) { /* keep hitting it */ + if (status & BT_B2H_ATN) { + /* keep hitting it */ BT_CONTROL(BT_B2H_ATN); BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY); } @@ -548,7 +579,8 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time) SI_SM_CALL_WITHOUT_DELAY); case BT_STATE_READ_BYTES: - if (!(status & BT_H_BUSY)) /* check in case of retry */ + if (!(status & BT_H_BUSY)) + /* check in case of retry */ BT_CONTROL(BT_H_BUSY); BT_CONTROL(BT_CLR_RD_PTR); /* start of BMC2HOST buffer */ i = read_all_bytes(bt); /* true == packet seq match */ @@ -599,8 +631,10 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time) BT_STATE_CHANGE(BT_STATE_XACTION_START, SI_SM_CALL_WITH_DELAY); - /* Get BT Capabilities, using timing of upper level state machine. - Set outreqs to prevent infinite loop on timeout. */ + /* + * Get BT Capabilities, using timing of upper level state machine. + * Set outreqs to prevent infinite loop on timeout. + */ case BT_STATE_CAPABILITIES_BEGIN: bt->BT_CAP_outreqs = 1; { @@ -638,10 +672,12 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time) static int bt_detect(struct si_sm_data *bt) { - /* It's impossible for the BT status and interrupt registers to be - all 1's, (assuming a properly functioning, self-initialized BMC) - but that's what you get from reading a bogus address, so we - test that first. The calling routine uses negative logic. */ + /* + * It's impossible for the BT status and interrupt registers to be + * all 1's, (assuming a properly functioning, self-initialized BMC) + * but that's what you get from reading a bogus address, so we + * test that first. The calling routine uses negative logic. + */ if ((BT_STATUS == 0xFF) && (BT_INTMASK_R == 0xFF)) return 1; @@ -658,8 +694,7 @@ static int bt_size(void) return sizeof(struct si_sm_data); } -struct si_sm_handlers bt_smi_handlers = -{ +struct si_sm_handlers bt_smi_handlers = { .init_data = bt_init_data, .start_transaction = bt_start_transaction, .get_result = bt_get_result, diff --git a/drivers/char/ipmi/ipmi_kcs_sm.c b/drivers/char/ipmi/ipmi_kcs_sm.c index c1b8228cb7b..80704875794 100644 --- a/drivers/char/ipmi/ipmi_kcs_sm.c +++ b/drivers/char/ipmi/ipmi_kcs_sm.c @@ -60,37 +60,58 @@ MODULE_PARM_DESC(kcs_debug, "debug bitmask, 1=enable, 2=messages, 4=states"); /* The states the KCS driver may be in. */ enum kcs_states { - KCS_IDLE, /* The KCS interface is currently - doing nothing. */ - KCS_START_OP, /* We are starting an operation. The - data is in the output buffer, but - nothing has been done to the - interface yet. This was added to - the state machine in the spec to - wait for the initial IBF. */ - KCS_WAIT_WRITE_START, /* We have written a write cmd to the - interface. */ - KCS_WAIT_WRITE, /* We are writing bytes to the - interface. */ - KCS_WAIT_WRITE_END, /* We have written the write end cmd - to the interface, and still need to - write the last byte. */ - KCS_WAIT_READ, /* We are waiting to read data from - the interface. */ - KCS_ERROR0, /* State to transition to the error - handler, this was added to the - state machine in the spec to be - sure IBF was there. */ - KCS_ERROR1, /* First stage error handler, wait for - the interface to respond. */ - KCS_ERROR2, /* The abort cmd has been written, - wait for the interface to - respond. */ - KCS_ERROR3, /* We wrote some data to the - interface, wait for it to switch to - read mode. */ - KCS_HOSED /* The hardware failed to follow the - state machine. */ + /* The KCS interface is currently doing nothing. */ + KCS_IDLE, + + /* + * We are starting an operation. The data is in the output + * buffer, but nothing has been done to the interface yet. This + * was added to the state machine in the spec to wait for the + * initial IBF. + */ + KCS_START_OP, + + /* We have written a write cmd to the interface. */ + KCS_WAIT_WRITE_START, + + /* We are writing bytes to the interface. */ + KCS_WAIT_WRITE, + + /* + * We have written the write end cmd to the interface, and + * still need to write the last byte. + */ + KCS_WAIT_WRITE_END, + + /* We are waiting to read data from the interface. */ + KCS_WAIT_READ, + + /* + * State to transition to the error handler, this was added to + * the state machine in the spec to be sure IBF was there. + */ + KCS_ERROR0, + + /* + * First stage error handler, wait for the interface to + * respond. + */ + KCS_ERROR1, + + /* + * The abort cmd has been written, wait for the interface to + * respond. + */ + KCS_ERROR2, + + /* + * We wrote some data to the interface, wait for it to switch + * to read mode. + */ + KCS_ERROR3, + + /* The hardware failed to follow the state machine. */ + KCS_HOSED }; #define MAX_KCS_READ_SIZE IPMI_MAX_MSG_LENGTH @@ -102,8 +123,7 @@ enum kcs_states { #define MAX_ERROR_RETRIES 10 #define ERROR0_OBF_WAIT_JIFFIES (2*HZ) -struct si_sm_data -{ +struct si_sm_data { enum kcs_states state; struct si_sm_io *io; unsigned char write_data[MAX_KCS_WRITE_SIZE]; @@ -187,7 +207,8 @@ static inline void start_error_recovery(struct si_sm_data *kcs, char *reason) (kcs->error_retries)++; if (kcs->error_retries > MAX_ERROR_RETRIES) { if (kcs_debug & KCS_DEBUG_ENABLE) - printk(KERN_DEBUG "ipmi_kcs_sm: kcs hosed: %s\n", reason); + printk(KERN_DEBUG "ipmi_kcs_sm: kcs hosed: %s\n", + reason); kcs->state = KCS_HOSED; } else { kcs->error0_timeout = jiffies + ERROR0_OBF_WAIT_JIFFIES; @@ -271,10 +292,9 @@ static int start_kcs_transaction(struct si_sm_data *kcs, unsigned char *data, if (kcs_debug & KCS_DEBUG_MSG) { printk(KERN_DEBUG "start_kcs_transaction -"); - for (i = 0; i < size; i ++) { + for (i = 0; i < size; i++) printk(" %02x", (unsigned char) (data [i])); - } - printk ("\n"); + printk("\n"); } kcs->error_retries = 0; memcpy(kcs->write_data, data, size); @@ -305,9 +325,11 @@ static int get_kcs_result(struct si_sm_data *kcs, unsigned char *data, kcs->read_pos = 3; } if (kcs->truncated) { - /* Report a truncated error. We might overwrite - another error, but that's too bad, the user needs - to know it was truncated. */ + /* + * Report a truncated error. We might overwrite + * another error, but that's too bad, the user needs + * to know it was truncated. + */ data[2] = IPMI_ERR_MSG_TRUNCATED; kcs->truncated = 0; } @@ -315,9 +337,11 @@ static int get_kcs_result(struct si_sm_data *kcs, unsigned char *data, return kcs->read_pos; } -/* This implements the state machine defined in the IPMI manual, see - that for details on how this works. Divide that flowchart into - sections delimited by "Wait for IBF" and this will become clear. */ +/* + * This implements the state machine defined in the IPMI manual, see + * that for details on how this works. Divide that flowchart into + * sections delimited by "Wait for IBF" and this will become clear. + */ static enum si_sm_result kcs_event(struct si_sm_data *kcs, long time) { unsigned char status; @@ -388,11 +412,12 @@ static enum si_sm_result kcs_event(struct si_sm_data *kcs, long time) write_next_byte(kcs); } break; - + case KCS_WAIT_WRITE_END: if (state != KCS_WRITE_STATE) { start_error_recovery(kcs, - "Not in write state for write end"); + "Not in write state" + " for write end"); break; } clear_obf(kcs, status); @@ -413,13 +438,15 @@ static enum si_sm_result kcs_event(struct si_sm_data *kcs, long time) return SI_SM_CALL_WITH_DELAY; read_next_byte(kcs); } else { - /* We don't implement this exactly like the state - machine in the spec. Some broken hardware - does not write the final dummy byte to the - read register. Thus obf will never go high - here. We just go straight to idle, and we - handle clearing out obf in idle state if it - happens to come in. */ + /* + * We don't implement this exactly like the state + * machine in the spec. Some broken hardware + * does not write the final dummy byte to the + * read register. Thus obf will never go high + * here. We just go straight to idle, and we + * handle clearing out obf in idle state if it + * happens to come in. + */ clear_obf(kcs, status); kcs->orig_write_count = 0; kcs->state = KCS_IDLE; @@ -430,7 +457,8 @@ static enum si_sm_result kcs_event(struct si_sm_data *kcs, long time) case KCS_ERROR0: clear_obf(kcs, status); status = read_status(kcs); - if (GET_STATUS_OBF(status)) /* controller isn't responding */ + if (GET_STATUS_OBF(status)) + /* controller isn't responding */ if (time_before(jiffies, kcs->error0_timeout)) return SI_SM_CALL_WITH_TICK_DELAY; write_cmd(kcs, KCS_GET_STATUS_ABORT); @@ -442,7 +470,7 @@ static enum si_sm_result kcs_event(struct si_sm_data *kcs, long time) write_data(kcs, 0); kcs->state = KCS_ERROR2; break; - + case KCS_ERROR2: if (state != KCS_READ_STATE) { start_error_recovery(kcs, @@ -456,7 +484,7 @@ static enum si_sm_result kcs_event(struct si_sm_data *kcs, long time) write_data(kcs, KCS_READ_BYTE); kcs->state = KCS_ERROR3; break; - + case KCS_ERROR3: if (state != KCS_IDLE_STATE) { start_error_recovery(kcs, @@ -475,7 +503,7 @@ static enum si_sm_result kcs_event(struct si_sm_data *kcs, long time) return SI_SM_TRANSACTION_COMPLETE; } break; - + case KCS_HOSED: break; } @@ -495,10 +523,12 @@ static int kcs_size(void) static int kcs_detect(struct si_sm_data *kcs) { - /* It's impossible for the KCS status register to be all 1's, - (assuming a properly functioning, self-initialized BMC) - but that's what you get from reading a bogus address, so we - test that first. */ + /* + * It's impossible for the KCS status register to be all 1's, + * (assuming a properly functioning, self-initialized BMC) + * but that's what you get from reading a bogus address, so we + * test that first. + */ if (read_status(kcs) == 0xff) return 1; @@ -509,8 +539,7 @@ static void kcs_cleanup(struct si_sm_data *kcs) { } -struct si_sm_handlers kcs_smi_handlers = -{ +struct si_sm_handlers kcs_smi_handlers = { .init_data = init_kcs_data, .start_transaction = start_kcs_transaction, .get_result = get_kcs_result, diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 32b2b22996d..8a59aaa21be 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -47,7 +47,7 @@ #define PFX "IPMI message handler: " -#define IPMI_DRIVER_VERSION "39.1" +#define IPMI_DRIVER_VERSION "39.2" static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void); static int ipmi_init_msghandler(void); @@ -63,16 +63,16 @@ static struct proc_dir_entry *proc_ipmi_root; #define MAX_EVENTS_IN_QUEUE 25 -/* Don't let a message sit in a queue forever, always time it with at lest - the max message timer. This is in milliseconds. */ +/* + * Don't let a message sit in a queue forever, always time it with at lest + * the max message timer. This is in milliseconds. + */ #define MAX_MSG_TIMEOUT 60000 - /* * The main "user" data structure. */ -struct ipmi_user -{ +struct ipmi_user { struct list_head link; /* Set to "0" when the user is destroyed. */ @@ -91,8 +91,7 @@ struct ipmi_user int gets_events; }; -struct cmd_rcvr -{ +struct cmd_rcvr { struct list_head link; ipmi_user_t user; @@ -106,12 +105,12 @@ struct cmd_rcvr * or change any data until the RCU period completes. So we * use this next variable during mass deletion so we can have * a list and don't have to wait and restart the search on - * every individual deletion of a command. */ + * every individual deletion of a command. + */ struct cmd_rcvr *next; }; -struct seq_table -{ +struct seq_table { unsigned int inuse : 1; unsigned int broadcast : 1; @@ -119,53 +118,60 @@ struct seq_table unsigned long orig_timeout; unsigned int retries_left; - /* To verify on an incoming send message response that this is - the message that the response is for, we keep a sequence id - and increment it every time we send a message. */ + /* + * To verify on an incoming send message response that this is + * the message that the response is for, we keep a sequence id + * and increment it every time we send a message. + */ long seqid; - /* This is held so we can properly respond to the message on a - timeout, and it is used to hold the temporary data for - retransmission, too. */ + /* + * This is held so we can properly respond to the message on a + * timeout, and it is used to hold the temporary data for + * retransmission, too. + */ struct ipmi_recv_msg *recv_msg; }; -/* Store the information in a msgid (long) to allow us to find a - sequence table entry from the msgid. */ +/* + * Store the information in a msgid (long) to allow us to find a + * sequence table entry from the msgid. + */ #define STORE_SEQ_IN_MSGID(seq, seqid) (((seq&0xff)<<26) | (seqid&0x3ffffff)) #define GET_SEQ_FROM_MSGID(msgid, seq, seqid) \ do { \ seq = ((msgid >> 26) & 0x3f); \ seqid = (msgid & 0x3fffff); \ - } while (0) + } while (0) #define NEXT_SEQID(seqid) (((seqid) + 1) & 0x3fffff) -struct ipmi_channel -{ +struct ipmi_channel { unsigned char medium; unsigned char protocol; - /* My slave address. This is initialized to IPMI_BMC_SLAVE_ADDR, - but may be changed by the user. */ + /* + * My slave address. This is initialized to IPMI_BMC_SLAVE_ADDR, + * but may be changed by the user. + */ unsigned char address; - /* My LUN. This should generally stay the SMS LUN, but just in - case... */ + /* + * My LUN. This should generally stay the SMS LUN, but just in + * case... + */ unsigned char lun; }; #ifdef CONFIG_PROC_FS -struct ipmi_proc_entry -{ +struct ipmi_proc_entry { char *name; struct ipmi_proc_entry *next; }; #endif -struct bmc_device -{ +struct bmc_device { struct platform_device *dev; struct ipmi_device_id id; unsigned char guid[16]; @@ -186,10 +192,108 @@ struct bmc_device struct device_attribute aux_firmware_rev_attr; }; +/* + * Various statistics for IPMI, these index stats[] in the ipmi_smi + * structure. + */ +enum ipmi_stat_indexes { + /* Commands we got from the user that were invalid. */ + IPMI_STAT_sent_invalid_commands = 0, + + /* Commands we sent to the MC. */ + IPMI_STAT_sent_local_commands, + + /* Responses from the MC that were delivered to a user. */ + IPMI_STAT_handled_local_responses, + + /* Responses from the MC that were not delivered to a user. */ + IPMI_STAT_unhandled_local_responses, + + /* Commands we sent out to the IPMB bus. */ + IPMI_STAT_sent_ipmb_commands, + + /* Commands sent on the IPMB that had errors on the SEND CMD */ + IPMI_STAT_sent_ipmb_command_errs, + + /* Each retransmit increments this count. */ + IPMI_STAT_retransmitted_ipmb_commands, + + /* + * When a message times out (runs out of retransmits) this is + * incremented. + */ + IPMI_STAT_timed_out_ipmb_commands, + + /* + * This is like above, but for broadcasts. Broadcasts are + * *not* included in the above count (they are expected to + * time out). + */ + IPMI_STAT_timed_out_ipmb_broadcasts, + + /* Responses I have sent to the IPMB bus. */ + IPMI_STAT_sent_ipmb_responses, + + /* The response was delivered to the user. */ + IPMI_STAT_handled_ipmb_responses, + + /* The response had invalid data in it. */ + IPMI_STAT_invalid_ipmb_responses, + + /* The response didn't have anyone waiting for it. */ + IPMI_STAT_unhandled_ipmb_responses, + + /* Commands we sent out to the IPMB bus. */ + IPMI_STAT_sent_lan_commands, + + /* Commands sent on the IPMB that had errors on the SEND CMD */ + IPMI_STAT_sent_lan_command_errs, + + /* Each retransmit increments this count. */ + IPMI_STAT_retransmitted_lan_commands, + + /* + * When a message times out (runs out of retransmits) this is + * incremented. + */ + IPMI_STAT_timed_out_lan_commands, + + /* Responses I have sent to the IPMB bus. */ + IPMI_STAT_sent_lan_responses, + + /* The response was delivered to the user. */ + IPMI_STAT_handled_lan_responses, + + /* The response had invalid data in it. */ + IPMI_STAT_invalid_lan_responses, + + /* The response didn't have anyone waiting for it. */ + IPMI_STAT_unhandled_lan_responses, + + /* The command was delivered to the user. */ + IPMI_STAT_handled_commands, + + /* The command had invalid data in it. */ + IPMI_STAT_invalid_commands, + + /* The command didn't have anyone waiting for it. */ + IPMI_STAT_unhandled_commands, + + /* Invalid data in an event. */ + IPMI_STAT_invalid_events, + + /* Events that were received with the proper format. */ + IPMI_STAT_events, + + + /* This *must* remain last, add new values above this. */ + IPMI_NUM_STATS +}; + + #define IPMI_IPMB_NUM_SEQ 64 #define IPMI_MAX_CHANNELS 16 -struct ipmi_smi -{ +struct ipmi_smi { /* What interface number are we? */ int intf_num; @@ -198,8 +302,10 @@ struct ipmi_smi /* Used for a list of interfaces. */ struct list_head link; - /* The list of upper layers that are using me. seq_lock - * protects this. */ + /* + * The list of upper layers that are using me. seq_lock + * protects this. + */ struct list_head users; /* Information to supply to users. */ @@ -213,10 +319,12 @@ struct ipmi_smi char *my_dev_name; char *sysfs_name; - /* This is the lower-layer's sender routine. Note that you + /* + * This is the lower-layer's sender routine. Note that you * must either be holding the ipmi_interfaces_mutex or be in * an umpreemptible region to use this. You must fetch the - * value into a local variable and make sure it is not NULL. */ + * value into a local variable and make sure it is not NULL. + */ struct ipmi_smi_handlers *handlers; void *send_info; @@ -229,34 +337,45 @@ struct ipmi_smi /* Driver-model device for the system interface. */ struct device *si_dev; - /* A table of sequence numbers for this interface. We use the - sequence numbers for IPMB messages that go out of the - interface to match them up with their responses. A routine - is called periodically to time the items in this list. */ + /* + * A table of sequence numbers for this interface. We use the + * sequence numbers for IPMB messages that go out of the + * interface to match them up with their responses. A routine + * is called periodically to time the items in this list. + */ spinlock_t seq_lock; struct seq_table seq_table[IPMI_IPMB_NUM_SEQ]; int curr_seq; - /* Messages that were delayed for some reason (out of memory, - for instance), will go in here to be processed later in a - periodic timer interrupt. */ + /* + * Messages that were delayed for some reason (out of memory, + * for instance), will go in here to be processed later in a + * periodic timer interrupt. + */ spinlock_t waiting_msgs_lock; struct list_head waiting_msgs; - /* The list of command receivers that are registered for commands - on this interface. */ + /* + * The list of command receivers that are registered for commands + * on this interface. + */ struct mutex cmd_rcvrs_mutex; struct list_head cmd_rcvrs; - /* Events that were queues because no one was there to receive - them. */ + /* + * Events that were queues because no one was there to receive + * them. + */ spinlock_t events_lock; /* For dealing with event stuff. */ struct list_head waiting_events; unsigned int waiting_events_count; /* How many events in queue? */ - int delivering_events; + char delivering_events; + char event_msg_printed; - /* The event receiver for my BMC, only really used at panic - shutdown as a place to store this. */ + /* + * The event receiver for my BMC, only really used at panic + * shutdown as a place to store this. + */ unsigned char event_receiver; unsigned char event_receiver_lun; unsigned char local_sel_device; @@ -268,14 +387,18 @@ struct ipmi_smi int auto_maintenance_timeout; spinlock_t maintenance_mode_lock; /* Used in a timer... */ - /* A cheap hack, if this is non-null and a message to an - interface comes in with a NULL user, call this routine with - it. Note that the message will still be freed by the - caller. This only works on the system interface. */ + /* + * A cheap hack, if this is non-null and a message to an + * interface comes in with a NULL user, call this routine with + * it. Note that the message will still be freed by the + * caller. This only works on the system interface. + */ void (*null_user_handler)(ipmi_smi_t intf, struct ipmi_recv_msg *msg); - /* When we are scanning the channels for an SMI, this will - tell which channel we are scanning. */ + /* + * When we are scanning the channels for an SMI, this will + * tell which channel we are scanning. + */ int curr_channel; /* Channel information */ @@ -285,74 +408,14 @@ struct ipmi_smi struct proc_dir_entry *proc_dir; char proc_dir_name[10]; - spinlock_t counter_lock; /* For making counters atomic. */ - - /* Commands we got that were invalid. */ - unsigned int sent_invalid_commands; - - /* Commands we sent to the MC. */ - unsigned int sent_local_commands; - /* Responses from the MC that were delivered to a user. */ - unsigned int handled_local_responses; - /* Responses from the MC that were not delivered to a user. */ - unsigned int unhandled_local_responses; - - /* Commands we sent out to the IPMB bus. */ - unsigned int sent_ipmb_commands; - /* Commands sent on the IPMB that had errors on the SEND CMD */ - unsigned int sent_ipmb_command_errs; - /* Each retransmit increments this count. */ - unsigned int retransmitted_ipmb_commands; - /* When a message times out (runs out of retransmits) this is - incremented. */ - unsigned int timed_out_ipmb_commands; - - /* This is like above, but for broadcasts. Broadcasts are - *not* included in the above count (they are expected to - time out). */ - unsigned int timed_out_ipmb_broadcasts; + atomic_t stats[IPMI_NUM_STATS]; - /* Responses I have sent to the IPMB bus. */ - unsigned int sent_ipmb_responses; - - /* The response was delivered to the user. */ - unsigned int handled_ipmb_responses; - /* The response had invalid data in it. */ - unsigned int invalid_ipmb_responses; - /* The response didn't have anyone waiting for it. */ - unsigned int unhandled_ipmb_responses; - - /* Commands we sent out to the IPMB bus. */ - unsigned int sent_lan_commands; - /* Commands sent on the IPMB that had errors on the SEND CMD */ - unsigned int sent_lan_command_errs; - /* Each retransmit increments this count. */ - unsigned int retransmitted_lan_commands; - /* When a message times out (runs out of retransmits) this is - incremented. */ - unsigned int timed_out_lan_commands; - - /* Responses I have sent to the IPMB bus. */ - unsigned int sent_lan_responses; - - /* The response was delivered to the user. */ - unsigned int handled_lan_responses; - /* The response had invalid data in it. */ - unsigned int invalid_lan_responses; - /* The response didn't have anyone waiting for it. */ - unsigned int unhandled_lan_responses; - - /* The command was delivered to the user. */ - unsigned int handled_commands; - /* The command had invalid data in it. */ - unsigned int invalid_commands; - /* The command didn't have anyone waiting for it. */ - unsigned int unhandled_commands; - - /* Invalid data in an event. */ - unsigned int invalid_events; - /* Events that were received with the proper format. */ - unsigned int events; + /* + * run_to_completion duplicate of smb_info, smi_info + * and ipmi_serial_info structures. Used to decrease numbers of + * parameters passed by "low" level IPMI code. + */ + int run_to_completion; }; #define to_si_intf_from_dev(device) container_of(device, struct ipmi_smi, dev) @@ -368,12 +431,19 @@ static DEFINE_MUTEX(ipmidriver_mutex); static LIST_HEAD(ipmi_interfaces); static DEFINE_MUTEX(ipmi_interfaces_mutex); -/* List of watchers that want to know when smi's are added and - deleted. */ +/* + * List of watchers that want to know when smi's are added and deleted. + */ static LIST_HEAD(smi_watchers); static DEFINE_MUTEX(smi_watchers_mutex); +#define ipmi_inc_stat(intf, stat) \ + atomic_inc(&(intf)->stats[IPMI_STAT_ ## stat]) +#define ipmi_get_stat(intf, stat) \ + ((unsigned int) atomic_read(&(intf)->stats[IPMI_STAT_ ## stat])) + + static void free_recv_msg_list(struct list_head *q) { struct ipmi_recv_msg *msg, *msg2; @@ -417,10 +487,8 @@ static void clean_up_interface_data(ipmi_smi_t intf) for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) { if ((intf->seq_table[i].inuse) - && (intf->seq_table[i].recv_msg)) - { + && (intf->seq_table[i].recv_msg)) ipmi_free_recv_msg(intf->seq_table[i].recv_msg); - } } } @@ -487,6 +555,7 @@ int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher) } return -ENOMEM; } +EXPORT_SYMBOL(ipmi_smi_watcher_register); int ipmi_smi_watcher_unregister(struct ipmi_smi_watcher *watcher) { @@ -495,6 +564,7 @@ int ipmi_smi_watcher_unregister(struct ipmi_smi_watcher *watcher) mutex_unlock(&smi_watchers_mutex); return 0; } +EXPORT_SYMBOL(ipmi_smi_watcher_unregister); /* * Must be called with smi_watchers_mutex held. @@ -530,8 +600,7 @@ ipmi_addr_equal(struct ipmi_addr *addr1, struct ipmi_addr *addr2) } if ((addr1->addr_type == IPMI_IPMB_ADDR_TYPE) - || (addr1->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)) - { + || (addr1->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)) { struct ipmi_ipmb_addr *ipmb_addr1 = (struct ipmi_ipmb_addr *) addr1; struct ipmi_ipmb_addr *ipmb_addr2 @@ -559,9 +628,8 @@ ipmi_addr_equal(struct ipmi_addr *addr1, struct ipmi_addr *addr2) int ipmi_validate_addr(struct ipmi_addr *addr, int len) { - if (len < sizeof(struct ipmi_system_interface_addr)) { + if (len < sizeof(struct ipmi_system_interface_addr)) return -EINVAL; - } if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) { if (addr->channel != IPMI_BMC_CHANNEL) @@ -575,23 +643,21 @@ int ipmi_validate_addr(struct ipmi_addr *addr, int len) return -EINVAL; if ((addr->addr_type == IPMI_IPMB_ADDR_TYPE) - || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)) - { - if (len < sizeof(struct ipmi_ipmb_addr)) { + || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)) { + if (len < sizeof(struct ipmi_ipmb_addr)) return -EINVAL; - } return 0; } if (addr->addr_type == IPMI_LAN_ADDR_TYPE) { - if (len < sizeof(struct ipmi_lan_addr)) { + if (len < sizeof(struct ipmi_lan_addr)) return -EINVAL; - } return 0; } return -EINVAL; } +EXPORT_SYMBOL(ipmi_validate_addr); unsigned int ipmi_addr_length(int addr_type) { @@ -599,34 +665,28 @@ unsigned int ipmi_addr_length(int addr_type) return sizeof(struct ipmi_system_interface_addr); if ((addr_type == IPMI_IPMB_ADDR_TYPE) - || (addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)) - { + || (addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)) return sizeof(struct ipmi_ipmb_addr); - } if (addr_type == IPMI_LAN_ADDR_TYPE) return sizeof(struct ipmi_lan_addr); return 0; } +EXPORT_SYMBOL(ipmi_addr_length); static void deliver_response(struct ipmi_recv_msg *msg) { if (!msg->user) { ipmi_smi_t intf = msg->user_msg_data; - unsigned long flags; /* Special handling for NULL users. */ if (intf->null_user_handler) { intf->null_user_handler(intf, msg); - spin_lock_irqsave(&intf->counter_lock, flags); - intf->handled_local_responses++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, handled_local_responses); } else { /* No handler, so give up. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->unhandled_local_responses++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, unhandled_local_responses); } ipmi_free_recv_msg(msg); } else { @@ -646,9 +706,11 @@ deliver_err_response(struct ipmi_recv_msg *msg, int err) deliver_response(msg); } -/* Find the next sequence number not being used and add the given - message with the given timeout to the sequence table. This must be - called with the interface's seq_lock held. */ +/* + * Find the next sequence number not being used and add the given + * message with the given timeout to the sequence table. This must be + * called with the interface's seq_lock held. + */ static int intf_next_seq(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg, unsigned long timeout, @@ -660,10 +722,8 @@ static int intf_next_seq(ipmi_smi_t intf, int rv = 0; unsigned int i; - for (i = intf->curr_seq; - (i+1)%IPMI_IPMB_NUM_SEQ != intf->curr_seq; - i = (i+1)%IPMI_IPMB_NUM_SEQ) - { + for (i = intf->curr_seq; (i+1)%IPMI_IPMB_NUM_SEQ != intf->curr_seq; + i = (i+1)%IPMI_IPMB_NUM_SEQ) { if (!intf->seq_table[i].inuse) break; } @@ -671,8 +731,10 @@ static int intf_next_seq(ipmi_smi_t intf, if (!intf->seq_table[i].inuse) { intf->seq_table[i].recv_msg = recv_msg; - /* Start with the maximum timeout, when the send response - comes in we will start the real timer. */ + /* + * Start with the maximum timeout, when the send response + * comes in we will start the real timer. + */ intf->seq_table[i].timeout = MAX_MSG_TIMEOUT; intf->seq_table[i].orig_timeout = timeout; intf->seq_table[i].retries_left = retries; @@ -685,15 +747,17 @@ static int intf_next_seq(ipmi_smi_t intf, } else { rv = -EAGAIN; } - + return rv; } -/* Return the receive message for the given sequence number and - release the sequence number so it can be reused. Some other data - is passed in to be sure the message matches up correctly (to help - guard against message coming in after their timeout and the - sequence number being reused). */ +/* + * Return the receive message for the given sequence number and + * release the sequence number so it can be reused. Some other data + * is passed in to be sure the message matches up correctly (to help + * guard against message coming in after their timeout and the + * sequence number being reused). + */ static int intf_find_seq(ipmi_smi_t intf, unsigned char seq, short channel, @@ -712,11 +776,9 @@ static int intf_find_seq(ipmi_smi_t intf, if (intf->seq_table[seq].inuse) { struct ipmi_recv_msg *msg = intf->seq_table[seq].recv_msg; - if ((msg->addr.channel == channel) - && (msg->msg.cmd == cmd) - && (msg->msg.netfn == netfn) - && (ipmi_addr_equal(addr, &(msg->addr)))) - { + if ((msg->addr.channel == channel) && (msg->msg.cmd == cmd) + && (msg->msg.netfn == netfn) + && (ipmi_addr_equal(addr, &(msg->addr)))) { *recv_msg = msg; intf->seq_table[seq].inuse = 0; rv = 0; @@ -741,11 +803,12 @@ static int intf_start_seq_timer(ipmi_smi_t intf, GET_SEQ_FROM_MSGID(msgid, seq, seqid); spin_lock_irqsave(&(intf->seq_lock), flags); - /* We do this verification because the user can be deleted - while a message is outstanding. */ + /* + * We do this verification because the user can be deleted + * while a message is outstanding. + */ if ((intf->seq_table[seq].inuse) - && (intf->seq_table[seq].seqid == seqid)) - { + && (intf->seq_table[seq].seqid == seqid)) { struct seq_table *ent = &(intf->seq_table[seq]); ent->timeout = ent->orig_timeout; rv = 0; @@ -770,11 +833,12 @@ static int intf_err_seq(ipmi_smi_t intf, GET_SEQ_FROM_MSGID(msgid, seq, seqid); spin_lock_irqsave(&(intf->seq_lock), flags); - /* We do this verification because the user can be deleted - while a message is outstanding. */ + /* + * We do this verification because the user can be deleted + * while a message is outstanding. + */ if ((intf->seq_table[seq].inuse) - && (intf->seq_table[seq].seqid == seqid)) - { + && (intf->seq_table[seq].seqid == seqid)) { struct seq_table *ent = &(intf->seq_table[seq]); ent->inuse = 0; @@ -800,24 +864,30 @@ int ipmi_create_user(unsigned int if_num, int rv = 0; ipmi_smi_t intf; - /* There is no module usecount here, because it's not - required. Since this can only be used by and called from - other modules, they will implicitly use this module, and - thus this can't be removed unless the other modules are - removed. */ + /* + * There is no module usecount here, because it's not + * required. Since this can only be used by and called from + * other modules, they will implicitly use this module, and + * thus this can't be removed unless the other modules are + * removed. + */ if (handler == NULL) return -EINVAL; - /* Make sure the driver is actually initialized, this handles - problems with initialization order. */ + /* + * Make sure the driver is actually initialized, this handles + * problems with initialization order. + */ if (!initialized) { rv = ipmi_init_msghandler(); if (rv) return rv; - /* The init code doesn't return an error if it was turned - off, but it won't initialize. Check that. */ + /* + * The init code doesn't return an error if it was turned + * off, but it won't initialize. Check that. + */ if (!initialized) return -ENODEV; } @@ -858,8 +928,10 @@ int ipmi_create_user(unsigned int if_num, } } - /* Hold the lock so intf->handlers is guaranteed to be good - * until now */ + /* + * Hold the lock so intf->handlers is guaranteed to be good + * until now + */ mutex_unlock(&ipmi_interfaces_mutex); new_user->valid = 1; @@ -876,6 +948,7 @@ out_kfree: kfree(new_user); return rv; } +EXPORT_SYMBOL(ipmi_create_user); static void free_user(struct kref *ref) { @@ -899,8 +972,7 @@ int ipmi_destroy_user(ipmi_user_t user) for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) { if (intf->seq_table[i].inuse - && (intf->seq_table[i].recv_msg->user == user)) - { + && (intf->seq_table[i].recv_msg->user == user)) { intf->seq_table[i].inuse = 0; ipmi_free_recv_msg(intf->seq_table[i].recv_msg); } @@ -943,6 +1015,7 @@ int ipmi_destroy_user(ipmi_user_t user) return 0; } +EXPORT_SYMBOL(ipmi_destroy_user); void ipmi_get_version(ipmi_user_t user, unsigned char *major, @@ -951,6 +1024,7 @@ void ipmi_get_version(ipmi_user_t user, *major = user->intf->ipmi_version_major; *minor = user->intf->ipmi_version_minor; } +EXPORT_SYMBOL(ipmi_get_version); int ipmi_set_my_address(ipmi_user_t user, unsigned int channel, @@ -961,6 +1035,7 @@ int ipmi_set_my_address(ipmi_user_t user, user->intf->channels[channel].address = address; return 0; } +EXPORT_SYMBOL(ipmi_set_my_address); int ipmi_get_my_address(ipmi_user_t user, unsigned int channel, @@ -971,6 +1046,7 @@ int ipmi_get_my_address(ipmi_user_t user, *address = user->intf->channels[channel].address; return 0; } +EXPORT_SYMBOL(ipmi_get_my_address); int ipmi_set_my_LUN(ipmi_user_t user, unsigned int channel, @@ -981,6 +1057,7 @@ int ipmi_set_my_LUN(ipmi_user_t user, user->intf->channels[channel].lun = LUN & 0x3; return 0; } +EXPORT_SYMBOL(ipmi_set_my_LUN); int ipmi_get_my_LUN(ipmi_user_t user, unsigned int channel, @@ -991,6 +1068,7 @@ int ipmi_get_my_LUN(ipmi_user_t user, *address = user->intf->channels[channel].lun; return 0; } +EXPORT_SYMBOL(ipmi_get_my_LUN); int ipmi_get_maintenance_mode(ipmi_user_t user) { @@ -1075,6 +1153,11 @@ int ipmi_set_gets_events(ipmi_user_t user, int val) list_for_each_entry_safe(msg, msg2, &intf->waiting_events, link) list_move_tail(&msg->link, &msgs); intf->waiting_events_count = 0; + if (intf->event_msg_printed) { + printk(KERN_WARNING PFX "Event queue no longer" + " full\n"); + intf->event_msg_printed = 0; + } intf->delivering_events = 1; spin_unlock_irqrestore(&intf->events_lock, flags); @@ -1094,6 +1177,7 @@ int ipmi_set_gets_events(ipmi_user_t user, int val) return 0; } +EXPORT_SYMBOL(ipmi_set_gets_events); static struct cmd_rcvr *find_cmd_rcvr(ipmi_smi_t intf, unsigned char netfn, @@ -1159,6 +1243,7 @@ int ipmi_register_for_cmd(ipmi_user_t user, return rv; } +EXPORT_SYMBOL(ipmi_register_for_cmd); int ipmi_unregister_for_cmd(ipmi_user_t user, unsigned char netfn, @@ -1196,19 +1281,13 @@ int ipmi_unregister_for_cmd(ipmi_user_t user, } return rv; } - -void ipmi_user_set_run_to_completion(ipmi_user_t user, int val) -{ - ipmi_smi_t intf = user->intf; - if (intf->handlers) - intf->handlers->set_run_to_completion(intf->send_info, val); -} +EXPORT_SYMBOL(ipmi_unregister_for_cmd); static unsigned char ipmb_checksum(unsigned char *data, int size) { unsigned char csum = 0; - + for (; size > 0; size--, data++) csum += *data; @@ -1250,8 +1329,10 @@ static inline void format_ipmb_msg(struct ipmi_smi_msg *smi_msg, = ipmb_checksum(&(smi_msg->data[i+6]), smi_msg->data_size-6); - /* Add on the checksum size and the offset from the - broadcast. */ + /* + * Add on the checksum size and the offset from the + * broadcast. + */ smi_msg->data_size += 1 + i; smi_msg->msgid = msgid; @@ -1287,17 +1368,21 @@ static inline void format_lan_msg(struct ipmi_smi_msg *smi_msg, = ipmb_checksum(&(smi_msg->data[7]), smi_msg->data_size-7); - /* Add on the checksum size and the offset from the - broadcast. */ + /* + * Add on the checksum size and the offset from the + * broadcast. + */ smi_msg->data_size += 1; smi_msg->msgid = msgid; } -/* Separate from ipmi_request so that the user does not have to be - supplied in certain circumstances (mainly at panic time). If - messages are supplied, they will be freed, even if an error - occurs. */ +/* + * Separate from ipmi_request so that the user does not have to be + * supplied in certain circumstances (mainly at panic time). If + * messages are supplied, they will be freed, even if an error + * occurs. + */ static int i_ipmi_request(ipmi_user_t user, ipmi_smi_t intf, struct ipmi_addr *addr, @@ -1319,19 +1404,18 @@ static int i_ipmi_request(ipmi_user_t user, struct ipmi_smi_handlers *handlers; - if (supplied_recv) { + if (supplied_recv) recv_msg = supplied_recv; - } else { + else { recv_msg = ipmi_alloc_recv_msg(); - if (recv_msg == NULL) { + if (recv_msg == NULL) return -ENOMEM; - } } recv_msg->user_msg_data = user_msg_data; - if (supplied_smi) { + if (supplied_smi) smi_msg = (struct ipmi_smi_msg *) supplied_smi; - } else { + else { smi_msg = ipmi_alloc_smi_msg(); if (smi_msg == NULL) { ipmi_free_recv_msg(recv_msg); @@ -1350,8 +1434,10 @@ static int i_ipmi_request(ipmi_user_t user, if (user) kref_get(&user->refcount); recv_msg->msgid = msgid; - /* Store the message to send in the receive message so timeout - responses can get the proper response data. */ + /* + * Store the message to send in the receive message so timeout + * responses can get the proper response data. + */ recv_msg->msg = *msg; if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) { @@ -1365,9 +1451,7 @@ static int i_ipmi_request(ipmi_user_t user, smi_addr = (struct ipmi_system_interface_addr *) addr; if (smi_addr->lun > 3) { - spin_lock_irqsave(&intf->counter_lock, flags); - intf->sent_invalid_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, sent_invalid_commands); rv = -EINVAL; goto out_err; } @@ -1377,13 +1461,12 @@ static int i_ipmi_request(ipmi_user_t user, if ((msg->netfn == IPMI_NETFN_APP_REQUEST) && ((msg->cmd == IPMI_SEND_MSG_CMD) || (msg->cmd == IPMI_GET_MSG_CMD) - || (msg->cmd == IPMI_READ_EVENT_MSG_BUFFER_CMD))) - { - /* We don't let the user do these, since we manage - the sequence numbers. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->sent_invalid_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + || (msg->cmd == IPMI_READ_EVENT_MSG_BUFFER_CMD))) { + /* + * We don't let the user do these, since we manage + * the sequence numbers. + */ + ipmi_inc_stat(intf, sent_invalid_commands); rv = -EINVAL; goto out_err; } @@ -1391,14 +1474,12 @@ static int i_ipmi_request(ipmi_user_t user, if (((msg->netfn == IPMI_NETFN_APP_REQUEST) && ((msg->cmd == IPMI_COLD_RESET_CMD) || (msg->cmd == IPMI_WARM_RESET_CMD))) - || (msg->netfn == IPMI_NETFN_FIRMWARE_REQUEST)) - { + || (msg->netfn == IPMI_NETFN_FIRMWARE_REQUEST)) { spin_lock_irqsave(&intf->maintenance_mode_lock, flags); intf->auto_maintenance_timeout = IPMI_MAINTENANCE_MODE_TIMEOUT; if (!intf->maintenance_mode - && !intf->maintenance_mode_enable) - { + && !intf->maintenance_mode_enable) { intf->maintenance_mode_enable = 1; maintenance_mode_update(intf); } @@ -1407,9 +1488,7 @@ static int i_ipmi_request(ipmi_user_t user, } if ((msg->data_len + 2) > IPMI_MAX_MSG_LENGTH) { - spin_lock_irqsave(&intf->counter_lock, flags); - intf->sent_invalid_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, sent_invalid_commands); rv = -EMSGSIZE; goto out_err; } @@ -1421,31 +1500,23 @@ static int i_ipmi_request(ipmi_user_t user, if (msg->data_len > 0) memcpy(&(smi_msg->data[2]), msg->data, msg->data_len); smi_msg->data_size = msg->data_len + 2; - spin_lock_irqsave(&intf->counter_lock, flags); - intf->sent_local_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, sent_local_commands); } else if ((addr->addr_type == IPMI_IPMB_ADDR_TYPE) - || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)) - { + || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)) { struct ipmi_ipmb_addr *ipmb_addr; unsigned char ipmb_seq; long seqid; int broadcast = 0; if (addr->channel >= IPMI_MAX_CHANNELS) { - spin_lock_irqsave(&intf->counter_lock, flags); - intf->sent_invalid_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, sent_invalid_commands); rv = -EINVAL; goto out_err; } if (intf->channels[addr->channel].medium - != IPMI_CHANNEL_MEDIUM_IPMB) - { - spin_lock_irqsave(&intf->counter_lock, flags); - intf->sent_invalid_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + != IPMI_CHANNEL_MEDIUM_IPMB) { + ipmi_inc_stat(intf, sent_invalid_commands); rv = -EINVAL; goto out_err; } @@ -1457,9 +1528,11 @@ static int i_ipmi_request(ipmi_user_t user, retries = 4; } if (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE) { - /* Broadcasts add a zero at the beginning of the - message, but otherwise is the same as an IPMB - address. */ + /* + * Broadcasts add a zero at the beginning of the + * message, but otherwise is the same as an IPMB + * address. + */ addr->addr_type = IPMI_IPMB_ADDR_TYPE; broadcast = 1; } @@ -1469,21 +1542,19 @@ static int i_ipmi_request(ipmi_user_t user, if (retry_time_ms == 0) retry_time_ms = 1000; - /* 9 for the header and 1 for the checksum, plus - possibly one for the broadcast. */ + /* + * 9 for the header and 1 for the checksum, plus + * possibly one for the broadcast. + */ if ((msg->data_len + 10 + broadcast) > IPMI_MAX_MSG_LENGTH) { - spin_lock_irqsave(&intf->counter_lock, flags); - intf->sent_invalid_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, sent_invalid_commands); rv = -EMSGSIZE; goto out_err; } ipmb_addr = (struct ipmi_ipmb_addr *) addr; if (ipmb_addr->lun > 3) { - spin_lock_irqsave(&intf->counter_lock, flags); - intf->sent_invalid_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, sent_invalid_commands); rv = -EINVAL; goto out_err; } @@ -1491,29 +1562,31 @@ static int i_ipmi_request(ipmi_user_t user, memcpy(&recv_msg->addr, ipmb_addr, sizeof(*ipmb_addr)); if (recv_msg->msg.netfn & 0x1) { - /* It's a response, so use the user's sequence - from msgid. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->sent_ipmb_responses++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + /* + * It's a response, so use the user's sequence + * from msgid. + */ + ipmi_inc_stat(intf, sent_ipmb_responses); format_ipmb_msg(smi_msg, msg, ipmb_addr, msgid, msgid, broadcast, source_address, source_lun); - /* Save the receive message so we can use it - to deliver the response. */ + /* + * Save the receive message so we can use it + * to deliver the response. + */ smi_msg->user_data = recv_msg; } else { /* It's a command, so get a sequence for it. */ spin_lock_irqsave(&(intf->seq_lock), flags); - spin_lock(&intf->counter_lock); - intf->sent_ipmb_commands++; - spin_unlock(&intf->counter_lock); + ipmi_inc_stat(intf, sent_ipmb_commands); - /* Create a sequence number with a 1 second - timeout and 4 retries. */ + /* + * Create a sequence number with a 1 second + * timeout and 4 retries. + */ rv = intf_next_seq(intf, recv_msg, retry_time_ms, @@ -1522,34 +1595,42 @@ static int i_ipmi_request(ipmi_user_t user, &ipmb_seq, &seqid); if (rv) { - /* We have used up all the sequence numbers, - probably, so abort. */ + /* + * We have used up all the sequence numbers, + * probably, so abort. + */ spin_unlock_irqrestore(&(intf->seq_lock), flags); goto out_err; } - /* Store the sequence number in the message, - so that when the send message response - comes back we can start the timer. */ + /* + * Store the sequence number in the message, + * so that when the send message response + * comes back we can start the timer. + */ format_ipmb_msg(smi_msg, msg, ipmb_addr, STORE_SEQ_IN_MSGID(ipmb_seq, seqid), ipmb_seq, broadcast, source_address, source_lun); - /* Copy the message into the recv message data, so we - can retransmit it later if necessary. */ + /* + * Copy the message into the recv message data, so we + * can retransmit it later if necessary. + */ memcpy(recv_msg->msg_data, smi_msg->data, smi_msg->data_size); recv_msg->msg.data = recv_msg->msg_data; recv_msg->msg.data_len = smi_msg->data_size; - /* We don't unlock until here, because we need - to copy the completed message into the - recv_msg before we release the lock. - Otherwise, race conditions may bite us. I - know that's pretty paranoid, but I prefer - to be correct. */ + /* + * We don't unlock until here, because we need + * to copy the completed message into the + * recv_msg before we release the lock. + * Otherwise, race conditions may bite us. I + * know that's pretty paranoid, but I prefer + * to be correct. + */ spin_unlock_irqrestore(&(intf->seq_lock), flags); } } else if (addr->addr_type == IPMI_LAN_ADDR_TYPE) { @@ -1558,21 +1639,16 @@ static int i_ipmi_request(ipmi_user_t user, long seqid; if (addr->channel >= IPMI_MAX_CHANNELS) { - spin_lock_irqsave(&intf->counter_lock, flags); - intf->sent_invalid_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, sent_invalid_commands); rv = -EINVAL; goto out_err; } if ((intf->channels[addr->channel].medium - != IPMI_CHANNEL_MEDIUM_8023LAN) + != IPMI_CHANNEL_MEDIUM_8023LAN) && (intf->channels[addr->channel].medium - != IPMI_CHANNEL_MEDIUM_ASYNC)) - { - spin_lock_irqsave(&intf->counter_lock, flags); - intf->sent_invalid_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + != IPMI_CHANNEL_MEDIUM_ASYNC)) { + ipmi_inc_stat(intf, sent_invalid_commands); rv = -EINVAL; goto out_err; } @@ -1585,18 +1661,14 @@ static int i_ipmi_request(ipmi_user_t user, /* 11 for the header and 1 for the checksum. */ if ((msg->data_len + 12) > IPMI_MAX_MSG_LENGTH) { - spin_lock_irqsave(&intf->counter_lock, flags); - intf->sent_invalid_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, sent_invalid_commands); rv = -EMSGSIZE; goto out_err; } lan_addr = (struct ipmi_lan_addr *) addr; if (lan_addr->lun > 3) { - spin_lock_irqsave(&intf->counter_lock, flags); - intf->sent_invalid_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, sent_invalid_commands); rv = -EINVAL; goto out_err; } @@ -1604,28 +1676,30 @@ static int i_ipmi_request(ipmi_user_t user, memcpy(&recv_msg->addr, lan_addr, sizeof(*lan_addr)); if (recv_msg->msg.netfn & 0x1) { - /* It's a response, so use the user's sequence - from msgid. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->sent_lan_responses++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + /* + * It's a response, so use the user's sequence + * from msgid. + */ + ipmi_inc_stat(intf, sent_lan_responses); format_lan_msg(smi_msg, msg, lan_addr, msgid, msgid, source_lun); - /* Save the receive message so we can use it - to deliver the response. */ + /* + * Save the receive message so we can use it + * to deliver the response. + */ smi_msg->user_data = recv_msg; } else { /* It's a command, so get a sequence for it. */ spin_lock_irqsave(&(intf->seq_lock), flags); - spin_lock(&intf->counter_lock); - intf->sent_lan_commands++; - spin_unlock(&intf->counter_lock); + ipmi_inc_stat(intf, sent_lan_commands); - /* Create a sequence number with a 1 second - timeout and 4 retries. */ + /* + * Create a sequence number with a 1 second + * timeout and 4 retries. + */ rv = intf_next_seq(intf, recv_msg, retry_time_ms, @@ -1634,40 +1708,46 @@ static int i_ipmi_request(ipmi_user_t user, &ipmb_seq, &seqid); if (rv) { - /* We have used up all the sequence numbers, - probably, so abort. */ + /* + * We have used up all the sequence numbers, + * probably, so abort. + */ spin_unlock_irqrestore(&(intf->seq_lock), flags); goto out_err; } - /* Store the sequence number in the message, - so that when the send message response - comes back we can start the timer. */ + /* + * Store the sequence number in the message, + * so that when the send message response + * comes back we can start the timer. + */ format_lan_msg(smi_msg, msg, lan_addr, STORE_SEQ_IN_MSGID(ipmb_seq, seqid), ipmb_seq, source_lun); - /* Copy the message into the recv message data, so we - can retransmit it later if necessary. */ + /* + * Copy the message into the recv message data, so we + * can retransmit it later if necessary. + */ memcpy(recv_msg->msg_data, smi_msg->data, smi_msg->data_size); recv_msg->msg.data = recv_msg->msg_data; recv_msg->msg.data_len = smi_msg->data_size; - /* We don't unlock until here, because we need - to copy the completed message into the - recv_msg before we release the lock. - Otherwise, race conditions may bite us. I - know that's pretty paranoid, but I prefer - to be correct. */ + /* + * We don't unlock until here, because we need + * to copy the completed message into the + * recv_msg before we release the lock. + * Otherwise, race conditions may bite us. I + * know that's pretty paranoid, but I prefer + * to be correct. + */ spin_unlock_irqrestore(&(intf->seq_lock), flags); } } else { /* Unknown address type. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->sent_invalid_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, sent_invalid_commands); rv = -EINVAL; goto out_err; } @@ -1735,6 +1815,7 @@ int ipmi_request_settime(ipmi_user_t user, retries, retry_time_ms); } +EXPORT_SYMBOL(ipmi_request_settime); int ipmi_request_supply_msgs(ipmi_user_t user, struct ipmi_addr *addr, @@ -1766,6 +1847,7 @@ int ipmi_request_supply_msgs(ipmi_user_t user, lun, -1, 0); } +EXPORT_SYMBOL(ipmi_request_supply_msgs); #ifdef CONFIG_PROC_FS static int ipmb_file_read_proc(char *page, char **start, off_t off, @@ -1790,7 +1872,7 @@ static int version_file_read_proc(char *page, char **start, off_t off, char *out = (char *) page; ipmi_smi_t intf = data; - return sprintf(out, "%d.%d\n", + return sprintf(out, "%u.%u\n", ipmi_version_major(&intf->bmc->id), ipmi_version_minor(&intf->bmc->id)); } @@ -1801,65 +1883,65 @@ static int stat_file_read_proc(char *page, char **start, off_t off, char *out = (char *) page; ipmi_smi_t intf = data; - out += sprintf(out, "sent_invalid_commands: %d\n", - intf->sent_invalid_commands); - out += sprintf(out, "sent_local_commands: %d\n", - intf->sent_local_commands); - out += sprintf(out, "handled_local_responses: %d\n", - intf->handled_local_responses); - out += sprintf(out, "unhandled_local_responses: %d\n", - intf->unhandled_local_responses); - out += sprintf(out, "sent_ipmb_commands: %d\n", - intf->sent_ipmb_commands); - out += sprintf(out, "sent_ipmb_command_errs: %d\n", - intf->sent_ipmb_command_errs); - out += sprintf(out, "retransmitted_ipmb_commands: %d\n", - intf->retransmitted_ipmb_commands); - out += sprintf(out, "timed_out_ipmb_commands: %d\n", - intf->timed_out_ipmb_commands); - out += sprintf(out, "timed_out_ipmb_broadcasts: %d\n", - intf->timed_out_ipmb_broadcasts); - out += sprintf(out, "sent_ipmb_responses: %d\n", - intf->sent_ipmb_responses); - out += sprintf(out, "handled_ipmb_responses: %d\n", - intf->handled_ipmb_responses); - out += sprintf(out, "invalid_ipmb_responses: %d\n", - intf->invalid_ipmb_responses); - out += sprintf(out, "unhandled_ipmb_responses: %d\n", - intf->unhandled_ipmb_responses); - out += sprintf(out, "sent_lan_commands: %d\n", - intf->sent_lan_commands); - out += sprintf(out, "sent_lan_command_errs: %d\n", - intf->sent_lan_command_errs); - out += sprintf(out, "retransmitted_lan_commands: %d\n", - intf->retransmitted_lan_commands); - out += sprintf(out, "timed_out_lan_commands: %d\n", - intf->timed_out_lan_commands); - out += sprintf(out, "sent_lan_responses: %d\n", - intf->sent_lan_responses); - out += sprintf(out, "handled_lan_responses: %d\n", - intf->handled_lan_responses); - out += sprintf(out, "invalid_lan_responses: %d\n", - intf->invalid_lan_responses); - out += sprintf(out, "unhandled_lan_responses: %d\n", - intf->unhandled_lan_responses); - out += sprintf(out, "handled_commands: %d\n", - intf->handled_commands); - out += sprintf(out, "invalid_commands: %d\n", - intf->invalid_commands); - out += sprintf(out, "unhandled_commands: %d\n", - intf->unhandled_commands); - out += sprintf(out, "invalid_events: %d\n", - intf->invalid_events); - out += sprintf(out, "events: %d\n", - intf->events); + out += sprintf(out, "sent_invalid_commands: %u\n", + ipmi_get_stat(intf, sent_invalid_commands)); + out += sprintf(out, "sent_local_commands: %u\n", + ipmi_get_stat(intf, sent_local_commands)); + out += sprintf(out, "handled_local_responses: %u\n", + ipmi_get_stat(intf, handled_local_responses)); + out += sprintf(out, "unhandled_local_responses: %u\n", + ipmi_get_stat(intf, unhandled_local_responses)); + out += sprintf(out, "sent_ipmb_commands: %u\n", + ipmi_get_stat(intf, sent_ipmb_commands)); + out += sprintf(out, "sent_ipmb_command_errs: %u\n", + ipmi_get_stat(intf, sent_ipmb_command_errs)); + out += sprintf(out, "retransmitted_ipmb_commands: %u\n", + ipmi_get_stat(intf, retransmitted_ipmb_commands)); + out += sprintf(out, "timed_out_ipmb_commands: %u\n", + ipmi_get_stat(intf, timed_out_ipmb_commands)); + out += sprintf(out, "timed_out_ipmb_broadcasts: %u\n", + ipmi_get_stat(intf, timed_out_ipmb_broadcasts)); + out += sprintf(out, "sent_ipmb_responses: %u\n", + ipmi_get_stat(intf, sent_ipmb_responses)); + out += sprintf(out, "handled_ipmb_responses: %u\n", + ipmi_get_stat(intf, handled_ipmb_responses)); + out += sprintf(out, "invalid_ipmb_responses: %u\n", + ipmi_get_stat(intf, invalid_ipmb_responses)); + out += sprintf(out, "unhandled_ipmb_responses: %u\n", + ipmi_get_stat(intf, unhandled_ipmb_responses)); + out += sprintf(out, "sent_lan_commands: %u\n", + ipmi_get_stat(intf, sent_lan_commands)); + out += sprintf(out, "sent_lan_command_errs: %u\n", + ipmi_get_stat(intf, sent_lan_command_errs)); + out += sprintf(out, "retransmitted_lan_commands: %u\n", + ipmi_get_stat(intf, retransmitted_lan_commands)); + out += sprintf(out, "timed_out_lan_commands: %u\n", + ipmi_get_stat(intf, timed_out_lan_commands)); + out += sprintf(out, "sent_lan_responses: %u\n", + ipmi_get_stat(intf, sent_lan_responses)); + out += sprintf(out, "handled_lan_responses: %u\n", + ipmi_get_stat(intf, handled_lan_responses)); + out += sprintf(out, "invalid_lan_responses: %u\n", + ipmi_get_stat(intf, invalid_lan_responses)); + out += sprintf(out, "unhandled_lan_responses: %u\n", + ipmi_get_stat(intf, unhandled_lan_responses)); + out += sprintf(out, "handled_commands: %u\n", + ipmi_get_stat(intf, handled_commands)); + out += sprintf(out, "invalid_commands: %u\n", + ipmi_get_stat(intf, invalid_commands)); + out += sprintf(out, "unhandled_commands: %u\n", + ipmi_get_stat(intf, unhandled_commands)); + out += sprintf(out, "invalid_events: %u\n", + ipmi_get_stat(intf, invalid_events)); + out += sprintf(out, "events: %u\n", + ipmi_get_stat(intf, events)); return (out - ((char *) page)); } #endif /* CONFIG_PROC_FS */ int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name, - read_proc_t *read_proc, write_proc_t *write_proc, + read_proc_t *read_proc, void *data, struct module *owner) { int rv = 0; @@ -1886,7 +1968,6 @@ int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name, } else { file->data = data; file->read_proc = read_proc; - file->write_proc = write_proc; file->owner = owner; mutex_lock(&smi->proc_entry_lock); @@ -1899,6 +1980,7 @@ int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name, return rv; } +EXPORT_SYMBOL(ipmi_smi_add_proc_entry); static int add_proc_entries(ipmi_smi_t smi, int num) { @@ -1909,23 +1991,22 @@ static int add_proc_entries(ipmi_smi_t smi, int num) smi->proc_dir = proc_mkdir(smi->proc_dir_name, proc_ipmi_root); if (!smi->proc_dir) rv = -ENOMEM; - else { + else smi->proc_dir->owner = THIS_MODULE; - } if (rv == 0) rv = ipmi_smi_add_proc_entry(smi, "stats", - stat_file_read_proc, NULL, + stat_file_read_proc, smi, THIS_MODULE); if (rv == 0) rv = ipmi_smi_add_proc_entry(smi, "ipmb", - ipmb_file_read_proc, NULL, + ipmb_file_read_proc, smi, THIS_MODULE); if (rv == 0) rv = ipmi_smi_add_proc_entry(smi, "version", - version_file_read_proc, NULL, + version_file_read_proc, smi, THIS_MODULE); #endif /* CONFIG_PROC_FS */ @@ -2210,37 +2291,47 @@ static int create_files(struct bmc_device *bmc) err = device_create_file(&bmc->dev->dev, &bmc->device_id_attr); - if (err) goto out; + if (err) + goto out; err = device_create_file(&bmc->dev->dev, &bmc->provides_dev_sdrs_attr); - if (err) goto out_devid; + if (err) + goto out_devid; err = device_create_file(&bmc->dev->dev, &bmc->revision_attr); - if (err) goto out_sdrs; + if (err) + goto out_sdrs; err = device_create_file(&bmc->dev->dev, &bmc->firmware_rev_attr); - if (err) goto out_rev; + if (err) + goto out_rev; err = device_create_file(&bmc->dev->dev, &bmc->version_attr); - if (err) goto out_firm; + if (err) + goto out_firm; err = device_create_file(&bmc->dev->dev, &bmc->add_dev_support_attr); - if (err) goto out_version; + if (err) + goto out_version; err = device_create_file(&bmc->dev->dev, &bmc->manufacturer_id_attr); - if (err) goto out_add_dev; + if (err) + goto out_add_dev; err = device_create_file(&bmc->dev->dev, &bmc->product_id_attr); - if (err) goto out_manu; + if (err) + goto out_manu; if (bmc->id.aux_firmware_revision_set) { err = device_create_file(&bmc->dev->dev, &bmc->aux_firmware_rev_attr); - if (err) goto out_prod_id; + if (err) + goto out_prod_id; } if (bmc->guid_set) { err = device_create_file(&bmc->dev->dev, &bmc->guid_attr); - if (err) goto out_aux_firm; + if (err) + goto out_aux_firm; } return 0; @@ -2368,8 +2459,10 @@ static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum, "ipmi_msghandler:" " Unable to register bmc device: %d\n", rv); - /* Don't go to out_err, you can only do that if - the device is registered already. */ + /* + * Don't go to out_err, you can only do that if + * the device is registered already. + */ return rv; } @@ -2560,17 +2653,18 @@ channel_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg) if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE) - && (msg->msg.cmd == IPMI_GET_CHANNEL_INFO_CMD)) - { + && (msg->msg.cmd == IPMI_GET_CHANNEL_INFO_CMD)) { /* It's the one we want */ if (msg->msg.data[0] != 0) { /* Got an error from the channel, just go on. */ if (msg->msg.data[0] == IPMI_INVALID_COMMAND_ERR) { - /* If the MC does not support this - command, that is legal. We just - assume it has one IPMB at channel - zero. */ + /* + * If the MC does not support this + * command, that is legal. We just + * assume it has one IPMB at channel + * zero. + */ intf->channels[0].medium = IPMI_CHANNEL_MEDIUM_IPMB; intf->channels[0].protocol @@ -2591,7 +2685,7 @@ channel_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg) intf->channels[chan].medium = msg->msg.data[2] & 0x7f; intf->channels[chan].protocol = msg->msg.data[3] & 0x1f; - next_channel: + next_channel: intf->curr_channel++; if (intf->curr_channel >= IPMI_MAX_CHANNELS) wake_up(&intf->waitq); @@ -2619,6 +2713,7 @@ void ipmi_poll_interface(ipmi_user_t user) if (intf->handlers->poll) intf->handlers->poll(intf->send_info); } +EXPORT_SYMBOL(ipmi_poll_interface); int ipmi_register_smi(struct ipmi_smi_handlers *handlers, void *send_info, @@ -2633,14 +2728,18 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, ipmi_smi_t tintf; struct list_head *link; - /* Make sure the driver is actually initialized, this handles - problems with initialization order. */ + /* + * Make sure the driver is actually initialized, this handles + * problems with initialization order. + */ if (!initialized) { rv = ipmi_init_msghandler(); if (rv) return rv; - /* The init code doesn't return an error if it was turned - off, but it won't initialize. Check that. */ + /* + * The init code doesn't return an error if it was turned + * off, but it won't initialize. Check that. + */ if (!initialized) return -ENODEV; } @@ -2688,8 +2787,9 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, spin_lock_init(&intf->maintenance_mode_lock); INIT_LIST_HEAD(&intf->cmd_rcvrs); init_waitqueue_head(&intf->waitq); + for (i = 0; i < IPMI_NUM_STATS; i++) + atomic_set(&intf->stats[i], 0); - spin_lock_init(&intf->counter_lock); intf->proc_dir = NULL; mutex_lock(&smi_watchers_mutex); @@ -2717,11 +2817,12 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, get_guid(intf); if ((intf->ipmi_version_major > 1) - || ((intf->ipmi_version_major == 1) - && (intf->ipmi_version_minor >= 5))) - { - /* Start scanning the channels to see what is - available. */ + || ((intf->ipmi_version_major == 1) + && (intf->ipmi_version_minor >= 5))) { + /* + * Start scanning the channels to see what is + * available. + */ intf->null_user_handler = channel_handler; intf->curr_channel = 0; rv = send_channel_info_cmd(intf, 0); @@ -2769,6 +2870,7 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, return rv; } +EXPORT_SYMBOL(ipmi_register_smi); static void cleanup_smi_msgs(ipmi_smi_t intf) { @@ -2803,8 +2905,10 @@ int ipmi_unregister_smi(ipmi_smi_t intf) remove_proc_entries(intf); - /* Call all the watcher interfaces to tell them that - an interface is gone. */ + /* + * Call all the watcher interfaces to tell them that + * an interface is gone. + */ list_for_each_entry(w, &smi_watchers, link) w->smi_gone(intf_num); mutex_unlock(&smi_watchers_mutex); @@ -2812,22 +2916,21 @@ int ipmi_unregister_smi(ipmi_smi_t intf) kref_put(&intf->refcount, intf_free); return 0; } +EXPORT_SYMBOL(ipmi_unregister_smi); static int handle_ipmb_get_msg_rsp(ipmi_smi_t intf, struct ipmi_smi_msg *msg) { struct ipmi_ipmb_addr ipmb_addr; struct ipmi_recv_msg *recv_msg; - unsigned long flags; - - /* This is 11, not 10, because the response must contain a - * completion code. */ + /* + * This is 11, not 10, because the response must contain a + * completion code. + */ if (msg->rsp_size < 11) { /* Message not big enough, just ignore it. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->invalid_ipmb_responses++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, invalid_ipmb_responses); return 0; } @@ -2841,37 +2944,38 @@ static int handle_ipmb_get_msg_rsp(ipmi_smi_t intf, ipmb_addr.channel = msg->rsp[3] & 0x0f; ipmb_addr.lun = msg->rsp[7] & 3; - /* It's a response from a remote entity. Look up the sequence - number and handle the response. */ + /* + * It's a response from a remote entity. Look up the sequence + * number and handle the response. + */ if (intf_find_seq(intf, msg->rsp[7] >> 2, msg->rsp[3] & 0x0f, msg->rsp[8], (msg->rsp[4] >> 2) & (~1), (struct ipmi_addr *) &(ipmb_addr), - &recv_msg)) - { - /* We were unable to find the sequence number, - so just nuke the message. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->unhandled_ipmb_responses++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + &recv_msg)) { + /* + * We were unable to find the sequence number, + * so just nuke the message. + */ + ipmi_inc_stat(intf, unhandled_ipmb_responses); return 0; } memcpy(recv_msg->msg_data, &(msg->rsp[9]), msg->rsp_size - 9); - /* THe other fields matched, so no need to set them, except - for netfn, which needs to be the response that was - returned, not the request value. */ + /* + * The other fields matched, so no need to set them, except + * for netfn, which needs to be the response that was + * returned, not the request value. + */ recv_msg->msg.netfn = msg->rsp[4] >> 2; recv_msg->msg.data = recv_msg->msg_data; recv_msg->msg.data_len = msg->rsp_size - 10; recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE; - spin_lock_irqsave(&intf->counter_lock, flags); - intf->handled_ipmb_responses++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, handled_ipmb_responses); deliver_response(recv_msg); return 0; @@ -2888,14 +2992,11 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf, ipmi_user_t user = NULL; struct ipmi_ipmb_addr *ipmb_addr; struct ipmi_recv_msg *recv_msg; - unsigned long flags; struct ipmi_smi_handlers *handlers; if (msg->rsp_size < 10) { /* Message not big enough, just ignore it. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->invalid_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, invalid_commands); return 0; } @@ -2919,19 +3020,17 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf, if (user == NULL) { /* We didn't find a user, deliver an error response. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->unhandled_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, unhandled_commands); msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2); msg->data[1] = IPMI_SEND_MSG_CMD; msg->data[2] = msg->rsp[3]; msg->data[3] = msg->rsp[6]; - msg->data[4] = ((netfn + 1) << 2) | (msg->rsp[7] & 0x3); + msg->data[4] = ((netfn + 1) << 2) | (msg->rsp[7] & 0x3); msg->data[5] = ipmb_checksum(&(msg->data[3]), 2); msg->data[6] = intf->channels[msg->rsp[3] & 0xf].address; - /* rqseq/lun */ - msg->data[7] = (msg->rsp[7] & 0xfc) | (msg->rsp[4] & 0x3); + /* rqseq/lun */ + msg->data[7] = (msg->rsp[7] & 0xfc) | (msg->rsp[4] & 0x3); msg->data[8] = msg->rsp[8]; /* cmd */ msg->data[9] = IPMI_INVALID_CMD_COMPLETION_CODE; msg->data[10] = ipmb_checksum(&(msg->data[6]), 4); @@ -2950,23 +3049,25 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf, handlers = intf->handlers; if (handlers) { handlers->sender(intf->send_info, msg, 0); - /* We used the message, so return the value - that causes it to not be freed or - queued. */ + /* + * We used the message, so return the value + * that causes it to not be freed or + * queued. + */ rv = -1; } rcu_read_unlock(); } else { /* Deliver the message to the user. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->handled_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, handled_commands); recv_msg = ipmi_alloc_recv_msg(); if (!recv_msg) { - /* We couldn't allocate memory for the - message, so requeue it for handling - later. */ + /* + * We couldn't allocate memory for the + * message, so requeue it for handling + * later. + */ rv = 1; kref_put(&user->refcount, free_user); } else { @@ -2977,8 +3078,10 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf, ipmb_addr->lun = msg->rsp[7] & 3; ipmb_addr->channel = msg->rsp[3] & 0xf; - /* Extract the rest of the message information - from the IPMB header.*/ + /* + * Extract the rest of the message information + * from the IPMB header. + */ recv_msg->user = user; recv_msg->recv_type = IPMI_CMD_RECV_TYPE; recv_msg->msgid = msg->rsp[7] >> 2; @@ -2986,8 +3089,10 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf, recv_msg->msg.cmd = msg->rsp[8]; recv_msg->msg.data = recv_msg->msg_data; - /* We chop off 10, not 9 bytes because the checksum - at the end also needs to be removed. */ + /* + * We chop off 10, not 9 bytes because the checksum + * at the end also needs to be removed. + */ recv_msg->msg.data_len = msg->rsp_size - 10; memcpy(recv_msg->msg_data, &(msg->rsp[9]), @@ -3004,16 +3109,15 @@ static int handle_lan_get_msg_rsp(ipmi_smi_t intf, { struct ipmi_lan_addr lan_addr; struct ipmi_recv_msg *recv_msg; - unsigned long flags; - /* This is 13, not 12, because the response must contain a - * completion code. */ + /* + * This is 13, not 12, because the response must contain a + * completion code. + */ if (msg->rsp_size < 13) { /* Message not big enough, just ignore it. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->invalid_lan_responses++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, invalid_lan_responses); return 0; } @@ -3030,37 +3134,38 @@ static int handle_lan_get_msg_rsp(ipmi_smi_t intf, lan_addr.privilege = msg->rsp[3] >> 4; lan_addr.lun = msg->rsp[9] & 3; - /* It's a response from a remote entity. Look up the sequence - number and handle the response. */ + /* + * It's a response from a remote entity. Look up the sequence + * number and handle the response. + */ if (intf_find_seq(intf, msg->rsp[9] >> 2, msg->rsp[3] & 0x0f, msg->rsp[10], (msg->rsp[6] >> 2) & (~1), (struct ipmi_addr *) &(lan_addr), - &recv_msg)) - { - /* We were unable to find the sequence number, - so just nuke the message. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->unhandled_lan_responses++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + &recv_msg)) { + /* + * We were unable to find the sequence number, + * so just nuke the message. + */ + ipmi_inc_stat(intf, unhandled_lan_responses); return 0; } memcpy(recv_msg->msg_data, &(msg->rsp[11]), msg->rsp_size - 11); - /* The other fields matched, so no need to set them, except - for netfn, which needs to be the response that was - returned, not the request value. */ + /* + * The other fields matched, so no need to set them, except + * for netfn, which needs to be the response that was + * returned, not the request value. + */ recv_msg->msg.netfn = msg->rsp[6] >> 2; recv_msg->msg.data = recv_msg->msg_data; recv_msg->msg.data_len = msg->rsp_size - 12; recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE; - spin_lock_irqsave(&intf->counter_lock, flags); - intf->handled_lan_responses++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, handled_lan_responses); deliver_response(recv_msg); return 0; @@ -3077,13 +3182,10 @@ static int handle_lan_get_msg_cmd(ipmi_smi_t intf, ipmi_user_t user = NULL; struct ipmi_lan_addr *lan_addr; struct ipmi_recv_msg *recv_msg; - unsigned long flags; if (msg->rsp_size < 12) { /* Message not big enough, just ignore it. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->invalid_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, invalid_commands); return 0; } @@ -3107,23 +3209,23 @@ static int handle_lan_get_msg_cmd(ipmi_smi_t intf, if (user == NULL) { /* We didn't find a user, just give up. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->unhandled_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, unhandled_commands); - rv = 0; /* Don't do anything with these messages, just - allow them to be freed. */ + /* + * Don't do anything with these messages, just allow + * them to be freed. + */ + rv = 0; } else { /* Deliver the message to the user. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->handled_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, handled_commands); recv_msg = ipmi_alloc_recv_msg(); if (!recv_msg) { - /* We couldn't allocate memory for the - message, so requeue it for handling - later. */ + /* + * We couldn't allocate memory for the + * message, so requeue it for handling later. + */ rv = 1; kref_put(&user->refcount, free_user); } else { @@ -3137,8 +3239,10 @@ static int handle_lan_get_msg_cmd(ipmi_smi_t intf, lan_addr->channel = msg->rsp[3] & 0xf; lan_addr->privilege = msg->rsp[3] >> 4; - /* Extract the rest of the message information - from the IPMB header.*/ + /* + * Extract the rest of the message information + * from the IPMB header. + */ recv_msg->user = user; recv_msg->recv_type = IPMI_CMD_RECV_TYPE; recv_msg->msgid = msg->rsp[9] >> 2; @@ -3146,8 +3250,10 @@ static int handle_lan_get_msg_cmd(ipmi_smi_t intf, recv_msg->msg.cmd = msg->rsp[10]; recv_msg->msg.data = recv_msg->msg_data; - /* We chop off 12, not 11 bytes because the checksum - at the end also needs to be removed. */ + /* + * We chop off 12, not 11 bytes because the checksum + * at the end also needs to be removed. + */ recv_msg->msg.data_len = msg->rsp_size - 12; memcpy(recv_msg->msg_data, &(msg->rsp[11]), @@ -3163,7 +3269,7 @@ static void copy_event_into_recv_msg(struct ipmi_recv_msg *recv_msg, struct ipmi_smi_msg *msg) { struct ipmi_system_interface_addr *smi_addr; - + recv_msg->msgid = 0; smi_addr = (struct ipmi_system_interface_addr *) &(recv_msg->addr); smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; @@ -3189,9 +3295,7 @@ static int handle_read_event_rsp(ipmi_smi_t intf, if (msg->rsp_size < 19) { /* Message is too small to be an IPMB event. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->invalid_events++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, invalid_events); return 0; } @@ -3204,12 +3308,12 @@ static int handle_read_event_rsp(ipmi_smi_t intf, spin_lock_irqsave(&intf->events_lock, flags); - spin_lock(&intf->counter_lock); - intf->events++; - spin_unlock(&intf->counter_lock); + ipmi_inc_stat(intf, events); - /* Allocate and fill in one message for every user that is getting - events. */ + /* + * Allocate and fill in one message for every user that is + * getting events. + */ rcu_read_lock(); list_for_each_entry_rcu(user, &intf->users, link) { if (!user->gets_events) @@ -3223,9 +3327,11 @@ static int handle_read_event_rsp(ipmi_smi_t intf, list_del(&recv_msg->link); ipmi_free_recv_msg(recv_msg); } - /* We couldn't allocate memory for the - message, so requeue it for handling - later. */ + /* + * We couldn't allocate memory for the + * message, so requeue it for handling + * later. + */ rv = 1; goto out; } @@ -3246,13 +3352,17 @@ static int handle_read_event_rsp(ipmi_smi_t intf, deliver_response(recv_msg); } } else if (intf->waiting_events_count < MAX_EVENTS_IN_QUEUE) { - /* No one to receive the message, put it in queue if there's - not already too many things in the queue. */ + /* + * No one to receive the message, put it in queue if there's + * not already too many things in the queue. + */ recv_msg = ipmi_alloc_recv_msg(); if (!recv_msg) { - /* We couldn't allocate memory for the - message, so requeue it for handling - later. */ + /* + * We couldn't allocate memory for the + * message, so requeue it for handling + * later. + */ rv = 1; goto out; } @@ -3260,11 +3370,14 @@ static int handle_read_event_rsp(ipmi_smi_t intf, copy_event_into_recv_msg(recv_msg, msg); list_add_tail(&(recv_msg->link), &(intf->waiting_events)); intf->waiting_events_count++; - } else { - /* There's too many things in the queue, discard this - message. */ - printk(KERN_WARNING PFX "Event queue full, discarding an" - " incoming event\n"); + } else if (!intf->event_msg_printed) { + /* + * There's too many things in the queue, discard this + * message. + */ + printk(KERN_WARNING PFX "Event queue full, discarding" + " incoming events\n"); + intf->event_msg_printed = 1; } out: @@ -3277,16 +3390,15 @@ static int handle_bmc_rsp(ipmi_smi_t intf, struct ipmi_smi_msg *msg) { struct ipmi_recv_msg *recv_msg; - unsigned long flags; struct ipmi_user *user; recv_msg = (struct ipmi_recv_msg *) msg->user_data; - if (recv_msg == NULL) - { - printk(KERN_WARNING"IPMI message received with no owner. This\n" - "could be because of a malformed message, or\n" - "because of a hardware error. Contact your\n" - "hardware vender for assistance\n"); + if (recv_msg == NULL) { + printk(KERN_WARNING + "IPMI message received with no owner. This\n" + "could be because of a malformed message, or\n" + "because of a hardware error. Contact your\n" + "hardware vender for assistance\n"); return 0; } @@ -3294,16 +3406,12 @@ static int handle_bmc_rsp(ipmi_smi_t intf, /* Make sure the user still exists. */ if (user && !user->valid) { /* The user for the message went away, so give up. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->unhandled_local_responses++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, unhandled_local_responses); ipmi_free_recv_msg(recv_msg); } else { struct ipmi_system_interface_addr *smi_addr; - spin_lock_irqsave(&intf->counter_lock, flags); - intf->handled_local_responses++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, handled_local_responses); recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE; recv_msg->msgid = msg->msgid; smi_addr = ((struct ipmi_system_interface_addr *) @@ -3324,9 +3432,11 @@ static int handle_bmc_rsp(ipmi_smi_t intf, return 0; } -/* Handle a new message. Return 1 if the message should be requeued, - 0 if the message should be freed, or -1 if the message should not - be freed or requeued. */ +/* + * Handle a new message. Return 1 if the message should be requeued, + * 0 if the message should be freed, or -1 if the message should not + * be freed or requeued. + */ static int handle_new_recv_msg(ipmi_smi_t intf, struct ipmi_smi_msg *msg) { @@ -3351,10 +3461,12 @@ static int handle_new_recv_msg(ipmi_smi_t intf, msg->rsp[1] = msg->data[1]; msg->rsp[2] = IPMI_ERR_UNSPECIFIED; msg->rsp_size = 3; - } else if (((msg->rsp[0] >> 2) != ((msg->data[0] >> 2) | 1))/* Netfn */ - || (msg->rsp[1] != msg->data[1])) /* Command */ - { - /* The response is not even marginally correct. */ + } else if (((msg->rsp[0] >> 2) != ((msg->data[0] >> 2) | 1)) + || (msg->rsp[1] != msg->data[1])) { + /* + * The NetFN and Command in the response is not even + * marginally correct. + */ printk(KERN_WARNING PFX "BMC returned incorrect response," " expected netfn %x cmd %x, got netfn %x cmd %x\n", (msg->data[0] >> 2) | 1, msg->data[1], @@ -3369,10 +3481,11 @@ static int handle_new_recv_msg(ipmi_smi_t intf, if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2)) && (msg->rsp[1] == IPMI_SEND_MSG_CMD) - && (msg->user_data != NULL)) - { - /* It's a response to a response we sent. For this we - deliver a send message response to the user. */ + && (msg->user_data != NULL)) { + /* + * It's a response to a response we sent. For this we + * deliver a send message response to the user. + */ struct ipmi_recv_msg *recv_msg = msg->user_data; requeue = 0; @@ -3398,8 +3511,7 @@ static int handle_new_recv_msg(ipmi_smi_t intf, recv_msg->msg_data[0] = msg->rsp[2]; deliver_response(recv_msg); } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2)) - && (msg->rsp[1] == IPMI_GET_MSG_CMD)) - { + && (msg->rsp[1] == IPMI_GET_MSG_CMD)) { /* It's from the receive queue. */ chan = msg->rsp[3] & 0xf; if (chan >= IPMI_MAX_CHANNELS) { @@ -3411,12 +3523,16 @@ static int handle_new_recv_msg(ipmi_smi_t intf, switch (intf->channels[chan].medium) { case IPMI_CHANNEL_MEDIUM_IPMB: if (msg->rsp[4] & 0x04) { - /* It's a response, so find the - requesting message and send it up. */ + /* + * It's a response, so find the + * requesting message and send it up. + */ requeue = handle_ipmb_get_msg_rsp(intf, msg); } else { - /* It's a command to the SMS from some other - entity. Handle that. */ + /* + * It's a command to the SMS from some other + * entity. Handle that. + */ requeue = handle_ipmb_get_msg_cmd(intf, msg); } break; @@ -3424,25 +3540,30 @@ static int handle_new_recv_msg(ipmi_smi_t intf, case IPMI_CHANNEL_MEDIUM_8023LAN: case IPMI_CHANNEL_MEDIUM_ASYNC: if (msg->rsp[6] & 0x04) { - /* It's a response, so find the - requesting message and send it up. */ + /* + * It's a response, so find the + * requesting message and send it up. + */ requeue = handle_lan_get_msg_rsp(intf, msg); } else { - /* It's a command to the SMS from some other - entity. Handle that. */ + /* + * It's a command to the SMS from some other + * entity. Handle that. + */ requeue = handle_lan_get_msg_cmd(intf, msg); } break; default: - /* We don't handle the channel type, so just - * free the message. */ + /* + * We don't handle the channel type, so just + * free the message. + */ requeue = 0; } } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2)) - && (msg->rsp[1] == IPMI_READ_EVENT_MSG_BUFFER_CMD)) - { + && (msg->rsp[1] == IPMI_READ_EVENT_MSG_BUFFER_CMD)) { /* It's an asyncronous event. */ requeue = handle_read_event_rsp(intf, msg); } else { @@ -3458,71 +3579,82 @@ static int handle_new_recv_msg(ipmi_smi_t intf, void ipmi_smi_msg_received(ipmi_smi_t intf, struct ipmi_smi_msg *msg) { - unsigned long flags; + unsigned long flags = 0; /* keep us warning-free. */ int rv; + int run_to_completion; if ((msg->data_size >= 2) && (msg->data[0] == (IPMI_NETFN_APP_REQUEST << 2)) && (msg->data[1] == IPMI_SEND_MSG_CMD) - && (msg->user_data == NULL)) - { - /* This is the local response to a command send, start - the timer for these. The user_data will not be - NULL if this is a response send, and we will let - response sends just go through. */ - - /* Check for errors, if we get certain errors (ones - that mean basically we can try again later), we - ignore them and start the timer. Otherwise we - report the error immediately. */ + && (msg->user_data == NULL)) { + /* + * This is the local response to a command send, start + * the timer for these. The user_data will not be + * NULL if this is a response send, and we will let + * response sends just go through. + */ + + /* + * Check for errors, if we get certain errors (ones + * that mean basically we can try again later), we + * ignore them and start the timer. Otherwise we + * report the error immediately. + */ if ((msg->rsp_size >= 3) && (msg->rsp[2] != 0) && (msg->rsp[2] != IPMI_NODE_BUSY_ERR) && (msg->rsp[2] != IPMI_LOST_ARBITRATION_ERR) && (msg->rsp[2] != IPMI_BUS_ERR) - && (msg->rsp[2] != IPMI_NAK_ON_WRITE_ERR)) - { + && (msg->rsp[2] != IPMI_NAK_ON_WRITE_ERR)) { int chan = msg->rsp[3] & 0xf; /* Got an error sending the message, handle it. */ - spin_lock_irqsave(&intf->counter_lock, flags); if (chan >= IPMI_MAX_CHANNELS) ; /* This shouldn't happen */ else if ((intf->channels[chan].medium == IPMI_CHANNEL_MEDIUM_8023LAN) || (intf->channels[chan].medium == IPMI_CHANNEL_MEDIUM_ASYNC)) - intf->sent_lan_command_errs++; + ipmi_inc_stat(intf, sent_lan_command_errs); else - intf->sent_ipmb_command_errs++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, sent_ipmb_command_errs); intf_err_seq(intf, msg->msgid, msg->rsp[2]); - } else { + } else /* The message was sent, start the timer. */ intf_start_seq_timer(intf, msg->msgid); - } ipmi_free_smi_msg(msg); goto out; } - /* To preserve message order, if the list is not empty, we - tack this message onto the end of the list. */ - spin_lock_irqsave(&intf->waiting_msgs_lock, flags); + /* + * To preserve message order, if the list is not empty, we + * tack this message onto the end of the list. + */ + run_to_completion = intf->run_to_completion; + if (!run_to_completion) + spin_lock_irqsave(&intf->waiting_msgs_lock, flags); if (!list_empty(&intf->waiting_msgs)) { list_add_tail(&msg->link, &intf->waiting_msgs); - spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags); + if (!run_to_completion) + spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags); goto out; } - spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags); - + if (!run_to_completion) + spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags); + rv = handle_new_recv_msg(intf, msg); if (rv > 0) { - /* Could not handle the message now, just add it to a - list to handle later. */ - spin_lock_irqsave(&intf->waiting_msgs_lock, flags); + /* + * Could not handle the message now, just add it to a + * list to handle later. + */ + run_to_completion = intf->run_to_completion; + if (!run_to_completion) + spin_lock_irqsave(&intf->waiting_msgs_lock, flags); list_add_tail(&msg->link, &intf->waiting_msgs); - spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags); + if (!run_to_completion) + spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags); } else if (rv == 0) { ipmi_free_smi_msg(msg); } @@ -3530,6 +3662,7 @@ void ipmi_smi_msg_received(ipmi_smi_t intf, out: return; } +EXPORT_SYMBOL(ipmi_smi_msg_received); void ipmi_smi_watchdog_pretimeout(ipmi_smi_t intf) { @@ -3544,7 +3677,7 @@ void ipmi_smi_watchdog_pretimeout(ipmi_smi_t intf) } rcu_read_unlock(); } - +EXPORT_SYMBOL(ipmi_smi_watchdog_pretimeout); static struct ipmi_smi_msg * smi_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg, @@ -3552,14 +3685,16 @@ smi_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg, { struct ipmi_smi_msg *smi_msg = ipmi_alloc_smi_msg(); if (!smi_msg) - /* If we can't allocate the message, then just return, we - get 4 retries, so this should be ok. */ + /* + * If we can't allocate the message, then just return, we + * get 4 retries, so this should be ok. + */ return NULL; memcpy(smi_msg->data, recv_msg->msg.data, recv_msg->msg.data_len); smi_msg->data_size = recv_msg->msg.data_len; smi_msg->msgid = STORE_SEQ_IN_MSGID(seq, seqid); - + #ifdef DEBUG_MSGING { int m; @@ -3594,28 +3729,26 @@ static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent, ent->inuse = 0; msg = ent->recv_msg; list_add_tail(&msg->link, timeouts); - spin_lock(&intf->counter_lock); if (ent->broadcast) - intf->timed_out_ipmb_broadcasts++; + ipmi_inc_stat(intf, timed_out_ipmb_broadcasts); else if (ent->recv_msg->addr.addr_type == IPMI_LAN_ADDR_TYPE) - intf->timed_out_lan_commands++; + ipmi_inc_stat(intf, timed_out_lan_commands); else - intf->timed_out_ipmb_commands++; - spin_unlock(&intf->counter_lock); + ipmi_inc_stat(intf, timed_out_ipmb_commands); } else { struct ipmi_smi_msg *smi_msg; /* More retries, send again. */ - /* Start with the max timer, set to normal - timer after the message is sent. */ + /* + * Start with the max timer, set to normal timer after + * the message is sent. + */ ent->timeout = MAX_MSG_TIMEOUT; ent->retries_left--; - spin_lock(&intf->counter_lock); if (ent->recv_msg->addr.addr_type == IPMI_LAN_ADDR_TYPE) - intf->retransmitted_lan_commands++; + ipmi_inc_stat(intf, retransmitted_lan_commands); else - intf->retransmitted_ipmb_commands++; - spin_unlock(&intf->counter_lock); + ipmi_inc_stat(intf, retransmitted_ipmb_commands); smi_msg = smi_from_recv_msg(intf, ent->recv_msg, slot, ent->seqid); @@ -3624,11 +3757,13 @@ static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent, spin_unlock_irqrestore(&intf->seq_lock, *flags); - /* Send the new message. We send with a zero - * priority. It timed out, I doubt time is - * that critical now, and high priority - * messages are really only for messages to the - * local MC, which don't get resent. */ + /* + * Send the new message. We send with a zero + * priority. It timed out, I doubt time is that + * critical now, and high priority messages are really + * only for messages to the local MC, which don't get + * resent. + */ handlers = intf->handlers; if (handlers) intf->handlers->sender(intf->send_info, @@ -3659,16 +3794,20 @@ static void ipmi_timeout_handler(long timeout_period) list_del(&smi_msg->link); ipmi_free_smi_msg(smi_msg); } else { - /* To preserve message order, quit if we - can't handle a message. */ + /* + * To preserve message order, quit if we + * can't handle a message. + */ break; } } spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags); - /* Go through the seq table and find any messages that - have timed out, putting them in the timeouts - list. */ + /* + * Go through the seq table and find any messages that + * have timed out, putting them in the timeouts + * list. + */ INIT_LIST_HEAD(&timeouts); spin_lock_irqsave(&intf->seq_lock, flags); for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) @@ -3694,8 +3833,7 @@ static void ipmi_timeout_handler(long timeout_period) intf->auto_maintenance_timeout -= timeout_period; if (!intf->maintenance_mode - && (intf->auto_maintenance_timeout <= 0)) - { + && (intf->auto_maintenance_timeout <= 0)) { intf->maintenance_mode_enable = 0; maintenance_mode_update(intf); } @@ -3713,8 +3851,10 @@ static void ipmi_request_event(void) struct ipmi_smi_handlers *handlers; rcu_read_lock(); - /* Called from the timer, no need to check if handlers is - * valid. */ + /* + * Called from the timer, no need to check if handlers is + * valid. + */ list_for_each_entry_rcu(intf, &ipmi_interfaces, link) { /* No event requests when in maintenance mode. */ if (intf->maintenance_mode_enable) @@ -3735,10 +3875,12 @@ static struct timer_list ipmi_timer; /* How many jiffies does it take to get to the timeout time. */ #define IPMI_TIMEOUT_JIFFIES ((IPMI_TIMEOUT_TIME * HZ) / 1000) -/* Request events from the queue every second (this is the number of - IPMI_TIMEOUT_TIMES between event requests). Hopefully, in the - future, IPMI will add a way to know immediately if an event is in - the queue and this silliness can go away. */ +/* + * Request events from the queue every second (this is the number of + * IPMI_TIMEOUT_TIMES between event requests). Hopefully, in the + * future, IPMI will add a way to know immediately if an event is in + * the queue and this silliness can go away. + */ #define IPMI_REQUEST_EV_TIME (1000 / (IPMI_TIMEOUT_TIME)) static atomic_t stop_operation; @@ -3782,6 +3924,7 @@ struct ipmi_smi_msg *ipmi_alloc_smi_msg(void) } return rv; } +EXPORT_SYMBOL(ipmi_alloc_smi_msg); static void free_recv_msg(struct ipmi_recv_msg *msg) { @@ -3789,7 +3932,7 @@ static void free_recv_msg(struct ipmi_recv_msg *msg) kfree(msg); } -struct ipmi_recv_msg *ipmi_alloc_recv_msg(void) +static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void) { struct ipmi_recv_msg *rv; @@ -3808,6 +3951,7 @@ void ipmi_free_recv_msg(struct ipmi_recv_msg *msg) kref_put(&msg->user->refcount, free_user); msg->done(msg); } +EXPORT_SYMBOL(ipmi_free_recv_msg); #ifdef CONFIG_IPMI_PANIC_EVENT @@ -3825,8 +3969,7 @@ static void event_receiver_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg) if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) && (msg->msg.netfn == IPMI_NETFN_SENSOR_EVENT_RESPONSE) && (msg->msg.cmd == IPMI_GET_EVENT_RECEIVER_CMD) - && (msg->msg.data[0] == IPMI_CC_NO_ERROR)) - { + && (msg->msg.data[0] == IPMI_CC_NO_ERROR)) { /* A get event receiver command, save it. */ intf->event_receiver = msg->msg.data[1]; intf->event_receiver_lun = msg->msg.data[2] & 0x3; @@ -3838,10 +3981,11 @@ static void device_id_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg) if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE) && (msg->msg.cmd == IPMI_GET_DEVICE_ID_CMD) - && (msg->msg.data[0] == IPMI_CC_NO_ERROR)) - { - /* A get device id command, save if we are an event - receiver or generator. */ + && (msg->msg.data[0] == IPMI_CC_NO_ERROR)) { + /* + * A get device id command, save if we are an event + * receiver or generator. + */ intf->local_sel_device = (msg->msg.data[6] >> 2) & 1; intf->local_event_generator = (msg->msg.data[6] >> 5) & 1; } @@ -3874,8 +4018,10 @@ static void send_panic_events(char *str) data[4] = 0x6f; /* Sensor specific, IPMI table 36-1 */ data[5] = 0xa1; /* Runtime stop OEM bytes 2 & 3. */ - /* Put a few breadcrumbs in. Hopefully later we can add more things - to make the panic events more useful. */ + /* + * Put a few breadcrumbs in. Hopefully later we can add more things + * to make the panic events more useful. + */ if (str) { data[3] = str[0]; data[6] = str[1]; @@ -3891,6 +4037,7 @@ static void send_panic_events(char *str) /* Interface is not ready. */ continue; + intf->run_to_completion = 1; /* Send the event announcing the panic. */ intf->handlers->set_run_to_completion(intf->send_info, 1); i_ipmi_request(NULL, @@ -3908,9 +4055,11 @@ static void send_panic_events(char *str) } #ifdef CONFIG_IPMI_PANIC_STRING - /* On every interface, dump a bunch of OEM event holding the - string. */ - if (!str) + /* + * On every interface, dump a bunch of OEM event holding the + * string. + */ + if (!str) return; /* For every registered interface, send the event. */ @@ -3931,11 +4080,13 @@ static void send_panic_events(char *str) */ smp_rmb(); - /* First job here is to figure out where to send the - OEM events. There's no way in IPMI to send OEM - events using an event send command, so we have to - find the SEL to put them in and stick them in - there. */ + /* + * First job here is to figure out where to send the + * OEM events. There's no way in IPMI to send OEM + * events using an event send command, so we have to + * find the SEL to put them in and stick them in + * there. + */ /* Get capabilities from the get device id. */ intf->local_sel_device = 0; @@ -3983,24 +4134,29 @@ static void send_panic_events(char *str) } intf->null_user_handler = NULL; - /* Validate the event receiver. The low bit must not - be 1 (it must be a valid IPMB address), it cannot - be zero, and it must not be my address. */ - if (((intf->event_receiver & 1) == 0) + /* + * Validate the event receiver. The low bit must not + * be 1 (it must be a valid IPMB address), it cannot + * be zero, and it must not be my address. + */ + if (((intf->event_receiver & 1) == 0) && (intf->event_receiver != 0) - && (intf->event_receiver != intf->channels[0].address)) - { - /* The event receiver is valid, send an IPMB - message. */ + && (intf->event_receiver != intf->channels[0].address)) { + /* + * The event receiver is valid, send an IPMB + * message. + */ ipmb = (struct ipmi_ipmb_addr *) &addr; ipmb->addr_type = IPMI_IPMB_ADDR_TYPE; ipmb->channel = 0; /* FIXME - is this right? */ ipmb->lun = intf->event_receiver_lun; ipmb->slave_addr = intf->event_receiver; } else if (intf->local_sel_device) { - /* The event receiver was not valid (or was - me), but I am an SEL device, just dump it - in my SEL. */ + /* + * The event receiver was not valid (or was + * me), but I am an SEL device, just dump it + * in my SEL. + */ si = (struct ipmi_system_interface_addr *) &addr; si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; si->channel = IPMI_BMC_CHANNEL; @@ -4008,7 +4164,6 @@ static void send_panic_events(char *str) } else continue; /* No where to send the event. */ - msg.netfn = IPMI_NETFN_STORAGE_REQUEST; /* Storage. */ msg.cmd = IPMI_ADD_SEL_ENTRY_CMD; msg.data = data; @@ -4025,8 +4180,10 @@ static void send_panic_events(char *str) data[2] = 0xf0; /* OEM event without timestamp. */ data[3] = intf->channels[0].address; data[4] = j++; /* sequence # */ - /* Always give 11 bytes, so strncpy will fill - it with zeroes for me. */ + /* + * Always give 11 bytes, so strncpy will fill + * it with zeroes for me. + */ strncpy(data+5, p, 11); p += size; @@ -4043,7 +4200,7 @@ static void send_panic_events(char *str) intf->channels[0].lun, 0, 1); /* no retry, and no wait. */ } - } + } #endif /* CONFIG_IPMI_PANIC_STRING */ } #endif /* CONFIG_IPMI_PANIC_EVENT */ @@ -4052,7 +4209,7 @@ static int has_panicked; static int panic_event(struct notifier_block *this, unsigned long event, - void *ptr) + void *ptr) { ipmi_smi_t intf; @@ -4066,6 +4223,7 @@ static int panic_event(struct notifier_block *this, /* Interface is not ready. */ continue; + intf->run_to_completion = 1; intf->handlers->set_run_to_completion(intf->send_info, 1); } @@ -4133,11 +4291,16 @@ static __exit void cleanup_ipmi(void) atomic_notifier_chain_unregister(&panic_notifier_list, &panic_block); - /* This can't be called if any interfaces exist, so no worry about - shutting down the interfaces. */ + /* + * This can't be called if any interfaces exist, so no worry + * about shutting down the interfaces. + */ - /* Tell the timer to stop, then wait for it to stop. This avoids - problems with race conditions removing the timer here. */ + /* + * Tell the timer to stop, then wait for it to stop. This + * avoids problems with race conditions removing the timer + * here. + */ atomic_inc(&stop_operation); del_timer_sync(&ipmi_timer); @@ -4164,31 +4327,6 @@ module_exit(cleanup_ipmi); module_init(ipmi_init_msghandler_mod); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>"); -MODULE_DESCRIPTION("Incoming and outgoing message routing for an IPMI interface."); +MODULE_DESCRIPTION("Incoming and outgoing message routing for an IPMI" + " interface."); MODULE_VERSION(IPMI_DRIVER_VERSION); - -EXPORT_SYMBOL(ipmi_create_user); -EXPORT_SYMBOL(ipmi_destroy_user); -EXPORT_SYMBOL(ipmi_get_version); -EXPORT_SYMBOL(ipmi_request_settime); -EXPORT_SYMBOL(ipmi_request_supply_msgs); -EXPORT_SYMBOL(ipmi_poll_interface); -EXPORT_SYMBOL(ipmi_register_smi); -EXPORT_SYMBOL(ipmi_unregister_smi); -EXPORT_SYMBOL(ipmi_register_for_cmd); -EXPORT_SYMBOL(ipmi_unregister_for_cmd); -EXPORT_SYMBOL(ipmi_smi_msg_received); -EXPORT_SYMBOL(ipmi_smi_watchdog_pretimeout); -EXPORT_SYMBOL(ipmi_alloc_smi_msg); -EXPORT_SYMBOL(ipmi_addr_length); -EXPORT_SYMBOL(ipmi_validate_addr); -EXPORT_SYMBOL(ipmi_set_gets_events); -EXPORT_SYMBOL(ipmi_smi_watcher_register); -EXPORT_SYMBOL(ipmi_smi_watcher_unregister); -EXPORT_SYMBOL(ipmi_set_my_address); -EXPORT_SYMBOL(ipmi_get_my_address); -EXPORT_SYMBOL(ipmi_set_my_LUN); -EXPORT_SYMBOL(ipmi_get_my_LUN); -EXPORT_SYMBOL(ipmi_smi_add_proc_entry); -EXPORT_SYMBOL(ipmi_user_set_run_to_completion); -EXPORT_SYMBOL(ipmi_free_recv_msg); diff --git a/drivers/char/ipmi/ipmi_poweroff.c b/drivers/char/ipmi/ipmi_poweroff.c index b86186de7f0..a261bd735df 100644 --- a/drivers/char/ipmi/ipmi_poweroff.c +++ b/drivers/char/ipmi/ipmi_poweroff.c @@ -87,7 +87,10 @@ MODULE_PARM_DESC(ifnum_to_use, "The interface number to use for the watchdog " /* parameter definition to allow user to flag power cycle */ module_param(poweroff_powercycle, int, 0644); -MODULE_PARM_DESC(poweroff_powercycle, " Set to non-zero to enable power cycle instead of power down. Power cycle is contingent on hardware support, otherwise it defaults back to power down."); +MODULE_PARM_DESC(poweroff_powercycle, + " Set to non-zero to enable power cycle instead of power" + " down. Power cycle is contingent on hardware support," + " otherwise it defaults back to power down."); /* Stuff from the get device id command. */ static unsigned int mfg_id; @@ -95,22 +98,25 @@ static unsigned int prod_id; static unsigned char capabilities; static unsigned char ipmi_version; -/* We use our own messages for this operation, we don't let the system - allocate them, since we may be in a panic situation. The whole - thing is single-threaded, anyway, so multiple messages are not - required. */ +/* + * We use our own messages for this operation, we don't let the system + * allocate them, since we may be in a panic situation. The whole + * thing is single-threaded, anyway, so multiple messages are not + * required. + */ +static atomic_t dummy_count = ATOMIC_INIT(0); static void dummy_smi_free(struct ipmi_smi_msg *msg) { + atomic_dec(&dummy_count); } static void dummy_recv_free(struct ipmi_recv_msg *msg) { + atomic_dec(&dummy_count); } -static struct ipmi_smi_msg halt_smi_msg = -{ +static struct ipmi_smi_msg halt_smi_msg = { .done = dummy_smi_free }; -static struct ipmi_recv_msg halt_recv_msg = -{ +static struct ipmi_recv_msg halt_recv_msg = { .done = dummy_recv_free }; @@ -127,8 +133,7 @@ static void receive_handler(struct ipmi_recv_msg *recv_msg, void *handler_data) complete(comp); } -static struct ipmi_user_hndl ipmi_poweroff_handler = -{ +static struct ipmi_user_hndl ipmi_poweroff_handler = { .ipmi_recv_hndl = receive_handler }; @@ -152,17 +157,28 @@ static int ipmi_request_wait_for_response(ipmi_user_t user, return halt_recv_msg.msg.data[0]; } -/* We are in run-to-completion mode, no completion is desired. */ +/* Wait for message to complete, spinning. */ static int ipmi_request_in_rc_mode(ipmi_user_t user, struct ipmi_addr *addr, struct kernel_ipmi_msg *send_msg) { int rv; + atomic_set(&dummy_count, 2); rv = ipmi_request_supply_msgs(user, addr, 0, send_msg, NULL, &halt_smi_msg, &halt_recv_msg, 0); - if (rv) + if (rv) { + atomic_set(&dummy_count, 0); return rv; + } + + /* + * Spin until our message is done. + */ + while (atomic_read(&dummy_count) > 0) { + ipmi_poll_interface(user); + cpu_relax(); + } return halt_recv_msg.msg.data[0]; } @@ -184,47 +200,47 @@ static int ipmi_request_in_rc_mode(ipmi_user_t user, static void (*atca_oem_poweroff_hook)(ipmi_user_t user); -static void pps_poweroff_atca (ipmi_user_t user) +static void pps_poweroff_atca(ipmi_user_t user) { - struct ipmi_system_interface_addr smi_addr; - struct kernel_ipmi_msg send_msg; - int rv; - /* - * Configure IPMI address for local access - */ - smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; - smi_addr.channel = IPMI_BMC_CHANNEL; - smi_addr.lun = 0; - - printk(KERN_INFO PFX "PPS powerdown hook used"); - - send_msg.netfn = IPMI_NETFN_OEM; - send_msg.cmd = IPMI_ATCA_PPS_GRACEFUL_RESTART; - send_msg.data = IPMI_ATCA_PPS_IANA; - send_msg.data_len = 3; - rv = ipmi_request_in_rc_mode(user, - (struct ipmi_addr *) &smi_addr, - &send_msg); - if (rv && rv != IPMI_UNKNOWN_ERR_COMPLETION_CODE) { - printk(KERN_ERR PFX "Unable to send ATCA ," - " IPMI error 0x%x\n", rv); - } + struct ipmi_system_interface_addr smi_addr; + struct kernel_ipmi_msg send_msg; + int rv; + /* + * Configure IPMI address for local access + */ + smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + smi_addr.channel = IPMI_BMC_CHANNEL; + smi_addr.lun = 0; + + printk(KERN_INFO PFX "PPS powerdown hook used"); + + send_msg.netfn = IPMI_NETFN_OEM; + send_msg.cmd = IPMI_ATCA_PPS_GRACEFUL_RESTART; + send_msg.data = IPMI_ATCA_PPS_IANA; + send_msg.data_len = 3; + rv = ipmi_request_in_rc_mode(user, + (struct ipmi_addr *) &smi_addr, + &send_msg); + if (rv && rv != IPMI_UNKNOWN_ERR_COMPLETION_CODE) { + printk(KERN_ERR PFX "Unable to send ATCA ," + " IPMI error 0x%x\n", rv); + } return; } -static int ipmi_atca_detect (ipmi_user_t user) +static int ipmi_atca_detect(ipmi_user_t user) { struct ipmi_system_interface_addr smi_addr; struct kernel_ipmi_msg send_msg; int rv; unsigned char data[1]; - /* - * Configure IPMI address for local access - */ - smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; - smi_addr.channel = IPMI_BMC_CHANNEL; - smi_addr.lun = 0; + /* + * Configure IPMI address for local access + */ + smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + smi_addr.channel = IPMI_BMC_CHANNEL; + smi_addr.lun = 0; /* * Use get address info to check and see if we are ATCA @@ -238,28 +254,30 @@ static int ipmi_atca_detect (ipmi_user_t user) (struct ipmi_addr *) &smi_addr, &send_msg); - printk(KERN_INFO PFX "ATCA Detect mfg 0x%X prod 0x%X\n", mfg_id, prod_id); - if((mfg_id == IPMI_MOTOROLA_MANUFACTURER_ID) - && (prod_id == IPMI_MOTOROLA_PPS_IPMC_PRODUCT_ID)) { - printk(KERN_INFO PFX "Installing Pigeon Point Systems Poweroff Hook\n"); + printk(KERN_INFO PFX "ATCA Detect mfg 0x%X prod 0x%X\n", + mfg_id, prod_id); + if ((mfg_id == IPMI_MOTOROLA_MANUFACTURER_ID) + && (prod_id == IPMI_MOTOROLA_PPS_IPMC_PRODUCT_ID)) { + printk(KERN_INFO PFX + "Installing Pigeon Point Systems Poweroff Hook\n"); atca_oem_poweroff_hook = pps_poweroff_atca; } return !rv; } -static void ipmi_poweroff_atca (ipmi_user_t user) +static void ipmi_poweroff_atca(ipmi_user_t user) { struct ipmi_system_interface_addr smi_addr; struct kernel_ipmi_msg send_msg; int rv; unsigned char data[4]; - /* - * Configure IPMI address for local access - */ - smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; - smi_addr.channel = IPMI_BMC_CHANNEL; - smi_addr.lun = 0; + /* + * Configure IPMI address for local access + */ + smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + smi_addr.channel = IPMI_BMC_CHANNEL; + smi_addr.lun = 0; printk(KERN_INFO PFX "Powering down via ATCA power command\n"); @@ -273,23 +291,24 @@ static void ipmi_poweroff_atca (ipmi_user_t user) data[2] = 0; /* Power Level */ data[3] = 0; /* Don't change saved presets */ send_msg.data = data; - send_msg.data_len = sizeof (data); + send_msg.data_len = sizeof(data); rv = ipmi_request_in_rc_mode(user, (struct ipmi_addr *) &smi_addr, &send_msg); - /** At this point, the system may be shutting down, and most - ** serial drivers (if used) will have interrupts turned off - ** it may be better to ignore IPMI_UNKNOWN_ERR_COMPLETION_CODE - ** return code - **/ - if (rv && rv != IPMI_UNKNOWN_ERR_COMPLETION_CODE) { + /* + * At this point, the system may be shutting down, and most + * serial drivers (if used) will have interrupts turned off + * it may be better to ignore IPMI_UNKNOWN_ERR_COMPLETION_CODE + * return code + */ + if (rv && rv != IPMI_UNKNOWN_ERR_COMPLETION_CODE) { printk(KERN_ERR PFX "Unable to send ATCA powerdown message," " IPMI error 0x%x\n", rv); goto out; } - if(atca_oem_poweroff_hook) - return atca_oem_poweroff_hook(user); + if (atca_oem_poweroff_hook) + atca_oem_poweroff_hook(user); out: return; } @@ -310,13 +329,13 @@ static void ipmi_poweroff_atca (ipmi_user_t user) #define IPMI_CPI1_PRODUCT_ID 0x000157 #define IPMI_CPI1_MANUFACTURER_ID 0x0108 -static int ipmi_cpi1_detect (ipmi_user_t user) +static int ipmi_cpi1_detect(ipmi_user_t user) { return ((mfg_id == IPMI_CPI1_MANUFACTURER_ID) && (prod_id == IPMI_CPI1_PRODUCT_ID)); } -static void ipmi_poweroff_cpi1 (ipmi_user_t user) +static void ipmi_poweroff_cpi1(ipmi_user_t user) { struct ipmi_system_interface_addr smi_addr; struct ipmi_ipmb_addr ipmb_addr; @@ -328,12 +347,12 @@ static void ipmi_poweroff_cpi1 (ipmi_user_t user) unsigned char aer_addr; unsigned char aer_lun; - /* - * Configure IPMI address for local access - */ - smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; - smi_addr.channel = IPMI_BMC_CHANNEL; - smi_addr.lun = 0; + /* + * Configure IPMI address for local access + */ + smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + smi_addr.channel = IPMI_BMC_CHANNEL; + smi_addr.lun = 0; printk(KERN_INFO PFX "Powering down via CPI1 power command\n"); @@ -425,7 +444,7 @@ static void ipmi_poweroff_cpi1 (ipmi_user_t user) */ #define DELL_IANA_MFR_ID {0xA2, 0x02, 0x00} -static int ipmi_dell_chassis_detect (ipmi_user_t user) +static int ipmi_dell_chassis_detect(ipmi_user_t user) { const char ipmi_version_major = ipmi_version & 0xF; const char ipmi_version_minor = (ipmi_version >> 4) & 0xF; @@ -444,25 +463,25 @@ static int ipmi_dell_chassis_detect (ipmi_user_t user) #define IPMI_NETFN_CHASSIS_REQUEST 0 #define IPMI_CHASSIS_CONTROL_CMD 0x02 -static int ipmi_chassis_detect (ipmi_user_t user) +static int ipmi_chassis_detect(ipmi_user_t user) { /* Chassis support, use it. */ return (capabilities & 0x80); } -static void ipmi_poweroff_chassis (ipmi_user_t user) +static void ipmi_poweroff_chassis(ipmi_user_t user) { struct ipmi_system_interface_addr smi_addr; struct kernel_ipmi_msg send_msg; int rv; unsigned char data[1]; - /* - * Configure IPMI address for local access - */ - smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; - smi_addr.channel = IPMI_BMC_CHANNEL; - smi_addr.lun = 0; + /* + * Configure IPMI address for local access + */ + smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + smi_addr.channel = IPMI_BMC_CHANNEL; + smi_addr.lun = 0; powercyclefailed: printk(KERN_INFO PFX "Powering %s via IPMI chassis control command\n", @@ -525,15 +544,13 @@ static struct poweroff_function poweroff_functions[] = { /* Called on a powerdown request. */ -static void ipmi_poweroff_function (void) +static void ipmi_poweroff_function(void) { if (!ready) return; /* Use run-to-completion mode, since interrupts may be off. */ - ipmi_user_set_run_to_completion(ipmi_user, 1); specific_poweroff_func(ipmi_user); - ipmi_user_set_run_to_completion(ipmi_user, 0); } /* Wait for an IPMI interface to be installed, the first one installed @@ -561,13 +578,13 @@ static void ipmi_po_new_smi(int if_num, struct device *device) ipmi_ifnum = if_num; - /* - * Do a get device ide and store some results, since this is + /* + * Do a get device ide and store some results, since this is * used by several functions. - */ - smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; - smi_addr.channel = IPMI_BMC_CHANNEL; - smi_addr.lun = 0; + */ + smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + smi_addr.channel = IPMI_BMC_CHANNEL; + smi_addr.lun = 0; send_msg.netfn = IPMI_NETFN_APP_REQUEST; send_msg.cmd = IPMI_GET_DEVICE_ID_CMD; @@ -632,8 +649,7 @@ static void ipmi_po_smi_gone(int if_num) pm_power_off = old_poweroff_func; } -static struct ipmi_smi_watcher smi_watcher = -{ +static struct ipmi_smi_watcher smi_watcher = { .owner = THIS_MODULE, .new_smi = ipmi_po_new_smi, .smi_gone = ipmi_po_smi_gone @@ -675,12 +691,12 @@ static struct ctl_table_header *ipmi_table_header; /* * Startup and shutdown functions. */ -static int ipmi_poweroff_init (void) +static int ipmi_poweroff_init(void) { int rv; - printk (KERN_INFO "Copyright (C) 2004 MontaVista Software -" - " IPMI Powerdown via sys_reboot.\n"); + printk(KERN_INFO "Copyright (C) 2004 MontaVista Software -" + " IPMI Powerdown via sys_reboot.\n"); if (poweroff_powercycle) printk(KERN_INFO PFX "Power cycle is enabled.\n"); diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 4f560d0bb80..5a5455585c1 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -80,7 +80,7 @@ #define SI_USEC_PER_JIFFY (1000000/HZ) #define SI_TIMEOUT_JIFFIES (SI_TIMEOUT_TIME_USEC/SI_USEC_PER_JIFFY) #define SI_SHORT_TIMEOUT_USEC 250 /* .25ms when the SM request a - short timeout */ + short timeout */ /* Bit for BMC global enables. */ #define IPMI_BMC_RCV_MSG_INTR 0x01 @@ -114,14 +114,61 @@ static char *si_to_str[] = { "kcs", "smic", "bt" }; #define DEVICE_NAME "ipmi_si" -static struct device_driver ipmi_driver = -{ +static struct device_driver ipmi_driver = { .name = DEVICE_NAME, .bus = &platform_bus_type }; -struct smi_info -{ + +/* + * Indexes into stats[] in smi_info below. + */ +enum si_stat_indexes { + /* + * Number of times the driver requested a timer while an operation + * was in progress. + */ + SI_STAT_short_timeouts = 0, + + /* + * Number of times the driver requested a timer while nothing was in + * progress. + */ + SI_STAT_long_timeouts, + + /* Number of times the interface was idle while being polled. */ + SI_STAT_idles, + + /* Number of interrupts the driver handled. */ + SI_STAT_interrupts, + + /* Number of time the driver got an ATTN from the hardware. */ + SI_STAT_attentions, + + /* Number of times the driver requested flags from the hardware. */ + SI_STAT_flag_fetches, + + /* Number of times the hardware didn't follow the state machine. */ + SI_STAT_hosed_count, + + /* Number of completed messages. */ + SI_STAT_complete_transactions, + + /* Number of IPMI events received from the hardware. */ + SI_STAT_events, + + /* Number of watchdog pretimeouts. */ + SI_STAT_watchdog_pretimeouts, + + /* Number of asyncronous messages received. */ + SI_STAT_incoming_messages, + + + /* This *must* remain last, add new values above this. */ + SI_NUM_STATS +}; + +struct smi_info { int intf_num; ipmi_smi_t intf; struct si_sm_data *si_sm; @@ -134,8 +181,10 @@ struct smi_info struct ipmi_smi_msg *curr_msg; enum si_intf_state si_state; - /* Used to handle the various types of I/O that can occur with - IPMI */ + /* + * Used to handle the various types of I/O that can occur with + * IPMI + */ struct si_sm_io io; int (*io_setup)(struct smi_info *info); void (*io_cleanup)(struct smi_info *info); @@ -146,15 +195,18 @@ struct smi_info void (*addr_source_cleanup)(struct smi_info *info); void *addr_source_data; - /* Per-OEM handler, called from handle_flags(). - Returns 1 when handle_flags() needs to be re-run - or 0 indicating it set si_state itself. - */ + /* + * Per-OEM handler, called from handle_flags(). Returns 1 + * when handle_flags() needs to be re-run or 0 indicating it + * set si_state itself. + */ int (*oem_data_avail_handler)(struct smi_info *smi_info); - /* Flags from the last GET_MSG_FLAGS command, used when an ATTN - is set to hold the flags until we are done handling everything - from the flags. */ + /* + * Flags from the last GET_MSG_FLAGS command, used when an ATTN + * is set to hold the flags until we are done handling everything + * from the flags. + */ #define RECEIVE_MSG_AVAIL 0x01 #define EVENT_MSG_BUFFER_FULL 0x02 #define WDT_PRE_TIMEOUT_INT 0x08 @@ -162,25 +214,31 @@ struct smi_info #define OEM1_DATA_AVAIL 0x40 #define OEM2_DATA_AVAIL 0x80 #define OEM_DATA_AVAIL (OEM0_DATA_AVAIL | \ - OEM1_DATA_AVAIL | \ - OEM2_DATA_AVAIL) + OEM1_DATA_AVAIL | \ + OEM2_DATA_AVAIL) unsigned char msg_flags; - /* If set to true, this will request events the next time the - state machine is idle. */ + /* + * If set to true, this will request events the next time the + * state machine is idle. + */ atomic_t req_events; - /* If true, run the state machine to completion on every send - call. Generally used after a panic to make sure stuff goes - out. */ + /* + * If true, run the state machine to completion on every send + * call. Generally used after a panic to make sure stuff goes + * out. + */ int run_to_completion; /* The I/O port of an SI interface. */ int port; - /* The space between start addresses of the two ports. For - instance, if the first port is 0xca2 and the spacing is 4, then - the second port is 0xca6. */ + /* + * The space between start addresses of the two ports. For + * instance, if the first port is 0xca2 and the spacing is 4, then + * the second port is 0xca6. + */ unsigned int spacing; /* zero if no irq; */ @@ -195,10 +253,12 @@ struct smi_info /* Used to gracefully stop the timer without race conditions. */ atomic_t stop_operation; - /* The driver will disable interrupts when it gets into a - situation where it cannot handle messages due to lack of - memory. Once that situation clears up, it will re-enable - interrupts. */ + /* + * The driver will disable interrupts when it gets into a + * situation where it cannot handle messages due to lack of + * memory. Once that situation clears up, it will re-enable + * interrupts. + */ int interrupt_disabled; /* From the get device id response... */ @@ -208,33 +268,28 @@ struct smi_info struct device *dev; struct platform_device *pdev; - /* True if we allocated the device, false if it came from - * someplace else (like PCI). */ + /* + * True if we allocated the device, false if it came from + * someplace else (like PCI). + */ int dev_registered; /* Slave address, could be reported from DMI. */ unsigned char slave_addr; /* Counters and things for the proc filesystem. */ - spinlock_t count_lock; - unsigned long short_timeouts; - unsigned long long_timeouts; - unsigned long timeout_restarts; - unsigned long idles; - unsigned long interrupts; - unsigned long attentions; - unsigned long flag_fetches; - unsigned long hosed_count; - unsigned long complete_transactions; - unsigned long events; - unsigned long watchdog_pretimeouts; - unsigned long incoming_messages; - - struct task_struct *thread; + atomic_t stats[SI_NUM_STATS]; + + struct task_struct *thread; struct list_head link; }; +#define smi_inc_stat(smi, stat) \ + atomic_inc(&(smi)->stats[SI_STAT_ ## stat]) +#define smi_get_stat(smi, stat) \ + ((unsigned int) atomic_read(&(smi)->stats[SI_STAT_ ## stat])) + #define SI_MAX_PARMS 4 static int force_kipmid[SI_MAX_PARMS]; @@ -246,7 +301,7 @@ static int try_smi_init(struct smi_info *smi); static void cleanup_one_si(struct smi_info *to_clean); static ATOMIC_NOTIFIER_HEAD(xaction_notifier_list); -static int register_xaction_notifier(struct notifier_block * nb) +static int register_xaction_notifier(struct notifier_block *nb) { return atomic_notifier_chain_register(&xaction_notifier_list, nb); } @@ -255,7 +310,7 @@ static void deliver_recv_msg(struct smi_info *smi_info, struct ipmi_smi_msg *msg) { /* Deliver the message to the upper layer with the lock - released. */ + released. */ spin_unlock(&(smi_info->si_lock)); ipmi_smi_msg_received(smi_info->intf, msg); spin_lock(&(smi_info->si_lock)); @@ -287,9 +342,12 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info) struct timeval t; #endif - /* No need to save flags, we aleady have interrupts off and we - already hold the SMI lock. */ - spin_lock(&(smi_info->msg_lock)); + /* + * No need to save flags, we aleady have interrupts off and we + * already hold the SMI lock. + */ + if (!smi_info->run_to_completion) + spin_lock(&(smi_info->msg_lock)); /* Pick the high priority queue first. */ if (!list_empty(&(smi_info->hp_xmit_msgs))) { @@ -310,7 +368,7 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info) link); #ifdef DEBUG_TIMING do_gettimeofday(&t); - printk("**Start2: %d.%9.9d\n", t.tv_sec, t.tv_usec); + printk(KERN_DEBUG "**Start2: %d.%9.9d\n", t.tv_sec, t.tv_usec); #endif err = atomic_notifier_call_chain(&xaction_notifier_list, 0, smi_info); @@ -322,14 +380,14 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info) smi_info->si_sm, smi_info->curr_msg->data, smi_info->curr_msg->data_size); - if (err) { + if (err) return_hosed_msg(smi_info, err); - } rv = SI_SM_CALL_WITHOUT_DELAY; } - out: - spin_unlock(&(smi_info->msg_lock)); + out: + if (!smi_info->run_to_completion) + spin_unlock(&(smi_info->msg_lock)); return rv; } @@ -338,8 +396,10 @@ static void start_enable_irq(struct smi_info *smi_info) { unsigned char msg[2]; - /* If we are enabling interrupts, we have to tell the - BMC to use them. */ + /* + * If we are enabling interrupts, we have to tell the + * BMC to use them. + */ msg[0] = (IPMI_NETFN_APP_REQUEST << 2); msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD; @@ -371,10 +431,12 @@ static void start_clear_flags(struct smi_info *smi_info) smi_info->si_state = SI_CLEARING_FLAGS; } -/* When we have a situtaion where we run out of memory and cannot - allocate messages, we just leave them in the BMC and run the system - polled until we can allocate some memory. Once we have some - memory, we will re-enable the interrupt. */ +/* + * When we have a situtaion where we run out of memory and cannot + * allocate messages, we just leave them in the BMC and run the system + * polled until we can allocate some memory. Once we have some + * memory, we will re-enable the interrupt. + */ static inline void disable_si_irq(struct smi_info *smi_info) { if ((smi_info->irq) && (!smi_info->interrupt_disabled)) { @@ -396,9 +458,7 @@ static void handle_flags(struct smi_info *smi_info) retry: if (smi_info->msg_flags & WDT_PRE_TIMEOUT_INT) { /* Watchdog pre-timeout */ - spin_lock(&smi_info->count_lock); - smi_info->watchdog_pretimeouts++; - spin_unlock(&smi_info->count_lock); + smi_inc_stat(smi_info, watchdog_pretimeouts); start_clear_flags(smi_info); smi_info->msg_flags &= ~WDT_PRE_TIMEOUT_INT; @@ -444,12 +504,11 @@ static void handle_flags(struct smi_info *smi_info) smi_info->curr_msg->data_size); smi_info->si_state = SI_GETTING_EVENTS; } else if (smi_info->msg_flags & OEM_DATA_AVAIL && - smi_info->oem_data_avail_handler) { + smi_info->oem_data_avail_handler) { if (smi_info->oem_data_avail_handler(smi_info)) goto retry; - } else { + } else smi_info->si_state = SI_NORMAL; - } } static void handle_transaction_done(struct smi_info *smi_info) @@ -459,7 +518,7 @@ static void handle_transaction_done(struct smi_info *smi_info) struct timeval t; do_gettimeofday(&t); - printk("**Done: %d.%9.9d\n", t.tv_sec, t.tv_usec); + printk(KERN_DEBUG "**Done: %d.%9.9d\n", t.tv_sec, t.tv_usec); #endif switch (smi_info->si_state) { case SI_NORMAL: @@ -472,9 +531,11 @@ static void handle_transaction_done(struct smi_info *smi_info) smi_info->curr_msg->rsp, IPMI_MAX_MSG_LENGTH); - /* Do this here becase deliver_recv_msg() releases the - lock, and a new message can be put in during the - time the lock is released. */ + /* + * Do this here becase deliver_recv_msg() releases the + * lock, and a new message can be put in during the + * time the lock is released. + */ msg = smi_info->curr_msg; smi_info->curr_msg = NULL; deliver_recv_msg(smi_info, msg); @@ -488,12 +549,13 @@ static void handle_transaction_done(struct smi_info *smi_info) /* We got the flags from the SMI, now handle them. */ len = smi_info->handlers->get_result(smi_info->si_sm, msg, 4); if (msg[2] != 0) { - /* Error fetching flags, just give up for - now. */ + /* Error fetching flags, just give up for now. */ smi_info->si_state = SI_NORMAL; } else if (len < 4) { - /* Hmm, no flags. That's technically illegal, but - don't use uninitialized data. */ + /* + * Hmm, no flags. That's technically illegal, but + * don't use uninitialized data. + */ smi_info->si_state = SI_NORMAL; } else { smi_info->msg_flags = msg[3]; @@ -530,9 +592,11 @@ static void handle_transaction_done(struct smi_info *smi_info) smi_info->curr_msg->rsp, IPMI_MAX_MSG_LENGTH); - /* Do this here becase deliver_recv_msg() releases the - lock, and a new message can be put in during the - time the lock is released. */ + /* + * Do this here becase deliver_recv_msg() releases the + * lock, and a new message can be put in during the + * time the lock is released. + */ msg = smi_info->curr_msg; smi_info->curr_msg = NULL; if (msg->rsp[2] != 0) { @@ -543,14 +607,14 @@ static void handle_transaction_done(struct smi_info *smi_info) smi_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL; handle_flags(smi_info); } else { - spin_lock(&smi_info->count_lock); - smi_info->events++; - spin_unlock(&smi_info->count_lock); - - /* Do this before we deliver the message - because delivering the message releases the - lock and something else can mess with the - state. */ + smi_inc_stat(smi_info, events); + + /* + * Do this before we deliver the message + * because delivering the message releases the + * lock and something else can mess with the + * state. + */ handle_flags(smi_info); deliver_recv_msg(smi_info, msg); @@ -566,9 +630,11 @@ static void handle_transaction_done(struct smi_info *smi_info) smi_info->curr_msg->rsp, IPMI_MAX_MSG_LENGTH); - /* Do this here becase deliver_recv_msg() releases the - lock, and a new message can be put in during the - time the lock is released. */ + /* + * Do this here becase deliver_recv_msg() releases the + * lock, and a new message can be put in during the + * time the lock is released. + */ msg = smi_info->curr_msg; smi_info->curr_msg = NULL; if (msg->rsp[2] != 0) { @@ -579,14 +645,14 @@ static void handle_transaction_done(struct smi_info *smi_info) smi_info->msg_flags &= ~RECEIVE_MSG_AVAIL; handle_flags(smi_info); } else { - spin_lock(&smi_info->count_lock); - smi_info->incoming_messages++; - spin_unlock(&smi_info->count_lock); - - /* Do this before we deliver the message - because delivering the message releases the - lock and something else can mess with the - state. */ + smi_inc_stat(smi_info, incoming_messages); + + /* + * Do this before we deliver the message + * because delivering the message releases the + * lock and something else can mess with the + * state. + */ handle_flags(smi_info); deliver_recv_msg(smi_info, msg); @@ -674,69 +740,70 @@ static void handle_transaction_done(struct smi_info *smi_info) } } -/* Called on timeouts and events. Timeouts should pass the elapsed - time, interrupts should pass in zero. Must be called with - si_lock held and interrupts disabled. */ +/* + * Called on timeouts and events. Timeouts should pass the elapsed + * time, interrupts should pass in zero. Must be called with + * si_lock held and interrupts disabled. + */ static enum si_sm_result smi_event_handler(struct smi_info *smi_info, int time) { enum si_sm_result si_sm_result; restart: - /* There used to be a loop here that waited a little while - (around 25us) before giving up. That turned out to be - pointless, the minimum delays I was seeing were in the 300us - range, which is far too long to wait in an interrupt. So - we just run until the state machine tells us something - happened or it needs a delay. */ + /* + * There used to be a loop here that waited a little while + * (around 25us) before giving up. That turned out to be + * pointless, the minimum delays I was seeing were in the 300us + * range, which is far too long to wait in an interrupt. So + * we just run until the state machine tells us something + * happened or it needs a delay. + */ si_sm_result = smi_info->handlers->event(smi_info->si_sm, time); time = 0; while (si_sm_result == SI_SM_CALL_WITHOUT_DELAY) - { si_sm_result = smi_info->handlers->event(smi_info->si_sm, 0); - } - if (si_sm_result == SI_SM_TRANSACTION_COMPLETE) - { - spin_lock(&smi_info->count_lock); - smi_info->complete_transactions++; - spin_unlock(&smi_info->count_lock); + if (si_sm_result == SI_SM_TRANSACTION_COMPLETE) { + smi_inc_stat(smi_info, complete_transactions); handle_transaction_done(smi_info); si_sm_result = smi_info->handlers->event(smi_info->si_sm, 0); - } - else if (si_sm_result == SI_SM_HOSED) - { - spin_lock(&smi_info->count_lock); - smi_info->hosed_count++; - spin_unlock(&smi_info->count_lock); + } else if (si_sm_result == SI_SM_HOSED) { + smi_inc_stat(smi_info, hosed_count); - /* Do the before return_hosed_msg, because that - releases the lock. */ + /* + * Do the before return_hosed_msg, because that + * releases the lock. + */ smi_info->si_state = SI_NORMAL; if (smi_info->curr_msg != NULL) { - /* If we were handling a user message, format - a response to send to the upper layer to - tell it about the error. */ + /* + * If we were handling a user message, format + * a response to send to the upper layer to + * tell it about the error. + */ return_hosed_msg(smi_info, IPMI_ERR_UNSPECIFIED); } si_sm_result = smi_info->handlers->event(smi_info->si_sm, 0); } - /* We prefer handling attn over new messages. */ - if (si_sm_result == SI_SM_ATTN) - { + /* + * We prefer handling attn over new messages. But don't do + * this if there is not yet an upper layer to handle anything. + */ + if (likely(smi_info->intf) && si_sm_result == SI_SM_ATTN) { unsigned char msg[2]; - spin_lock(&smi_info->count_lock); - smi_info->attentions++; - spin_unlock(&smi_info->count_lock); + smi_inc_stat(smi_info, attentions); - /* Got a attn, send down a get message flags to see - what's causing it. It would be better to handle - this in the upper layer, but due to the way - interrupts work with the SMI, that's not really - possible. */ + /* + * Got a attn, send down a get message flags to see + * what's causing it. It would be better to handle + * this in the upper layer, but due to the way + * interrupts work with the SMI, that's not really + * possible. + */ msg[0] = (IPMI_NETFN_APP_REQUEST << 2); msg[1] = IPMI_GET_MSG_FLAGS_CMD; @@ -748,20 +815,19 @@ static enum si_sm_result smi_event_handler(struct smi_info *smi_info, /* If we are currently idle, try to start the next message. */ if (si_sm_result == SI_SM_IDLE) { - spin_lock(&smi_info->count_lock); - smi_info->idles++; - spin_unlock(&smi_info->count_lock); + smi_inc_stat(smi_info, idles); si_sm_result = start_next_msg(smi_info); if (si_sm_result != SI_SM_IDLE) goto restart; - } + } if ((si_sm_result == SI_SM_IDLE) - && (atomic_read(&smi_info->req_events))) - { - /* We are idle and the upper layer requested that I fetch - events, so do so. */ + && (atomic_read(&smi_info->req_events))) { + /* + * We are idle and the upper layer requested that I fetch + * events, so do so. + */ atomic_set(&smi_info->req_events, 0); smi_info->curr_msg = ipmi_alloc_smi_msg(); @@ -803,56 +869,50 @@ static void sender(void *send_info, return; } - spin_lock_irqsave(&(smi_info->msg_lock), flags); #ifdef DEBUG_TIMING do_gettimeofday(&t); printk("**Enqueue: %d.%9.9d\n", t.tv_sec, t.tv_usec); #endif if (smi_info->run_to_completion) { - /* If we are running to completion, then throw it in - the list and run transactions until everything is - clear. Priority doesn't matter here. */ + /* + * If we are running to completion, then throw it in + * the list and run transactions until everything is + * clear. Priority doesn't matter here. + */ + + /* + * Run to completion means we are single-threaded, no + * need for locks. + */ list_add_tail(&(msg->link), &(smi_info->xmit_msgs)); - /* We have to release the msg lock and claim the smi - lock in this case, because of race conditions. */ - spin_unlock_irqrestore(&(smi_info->msg_lock), flags); - - spin_lock_irqsave(&(smi_info->si_lock), flags); result = smi_event_handler(smi_info, 0); while (result != SI_SM_IDLE) { udelay(SI_SHORT_TIMEOUT_USEC); result = smi_event_handler(smi_info, SI_SHORT_TIMEOUT_USEC); } - spin_unlock_irqrestore(&(smi_info->si_lock), flags); return; - } else { - if (priority > 0) { - list_add_tail(&(msg->link), &(smi_info->hp_xmit_msgs)); - } else { - list_add_tail(&(msg->link), &(smi_info->xmit_msgs)); - } } - spin_unlock_irqrestore(&(smi_info->msg_lock), flags); - spin_lock_irqsave(&(smi_info->si_lock), flags); - if ((smi_info->si_state == SI_NORMAL) - && (smi_info->curr_msg == NULL)) - { + spin_lock_irqsave(&smi_info->msg_lock, flags); + if (priority > 0) + list_add_tail(&msg->link, &smi_info->hp_xmit_msgs); + else + list_add_tail(&msg->link, &smi_info->xmit_msgs); + spin_unlock_irqrestore(&smi_info->msg_lock, flags); + + spin_lock_irqsave(&smi_info->si_lock, flags); + if (smi_info->si_state == SI_NORMAL && smi_info->curr_msg == NULL) start_next_msg(smi_info); - } - spin_unlock_irqrestore(&(smi_info->si_lock), flags); + spin_unlock_irqrestore(&smi_info->si_lock, flags); } static void set_run_to_completion(void *send_info, int i_run_to_completion) { struct smi_info *smi_info = send_info; enum si_sm_result result; - unsigned long flags; - - spin_lock_irqsave(&(smi_info->si_lock), flags); smi_info->run_to_completion = i_run_to_completion; if (i_run_to_completion) { @@ -863,8 +923,6 @@ static void set_run_to_completion(void *send_info, int i_run_to_completion) SI_SHORT_TIMEOUT_USEC); } } - - spin_unlock_irqrestore(&(smi_info->si_lock), flags); } static int ipmi_thread(void *data) @@ -878,9 +936,8 @@ static int ipmi_thread(void *data) spin_lock_irqsave(&(smi_info->si_lock), flags); smi_result = smi_event_handler(smi_info, 0); spin_unlock_irqrestore(&(smi_info->si_lock), flags); - if (smi_result == SI_SM_CALL_WITHOUT_DELAY) { - /* do nothing */ - } + if (smi_result == SI_SM_CALL_WITHOUT_DELAY) + ; /* do nothing */ else if (smi_result == SI_SM_CALL_WITH_DELAY) schedule(); else @@ -931,7 +988,7 @@ static void smi_timeout(unsigned long data) spin_lock_irqsave(&(smi_info->si_lock), flags); #ifdef DEBUG_TIMING do_gettimeofday(&t); - printk("**Timer: %d.%9.9d\n", t.tv_sec, t.tv_usec); + printk(KERN_DEBUG "**Timer: %d.%9.9d\n", t.tv_sec, t.tv_usec); #endif jiffies_now = jiffies; time_diff = (((long)jiffies_now - (long)smi_info->last_timeout_jiffies) @@ -945,23 +1002,19 @@ static void smi_timeout(unsigned long data) if ((smi_info->irq) && (!smi_info->interrupt_disabled)) { /* Running with interrupts, only do long timeouts. */ smi_info->si_timer.expires = jiffies + SI_TIMEOUT_JIFFIES; - spin_lock_irqsave(&smi_info->count_lock, flags); - smi_info->long_timeouts++; - spin_unlock_irqrestore(&smi_info->count_lock, flags); + smi_inc_stat(smi_info, long_timeouts); goto do_add_timer; } - /* If the state machine asks for a short delay, then shorten - the timer timeout. */ + /* + * If the state machine asks for a short delay, then shorten + * the timer timeout. + */ if (smi_result == SI_SM_CALL_WITH_DELAY) { - spin_lock_irqsave(&smi_info->count_lock, flags); - smi_info->short_timeouts++; - spin_unlock_irqrestore(&smi_info->count_lock, flags); + smi_inc_stat(smi_info, short_timeouts); smi_info->si_timer.expires = jiffies + 1; } else { - spin_lock_irqsave(&smi_info->count_lock, flags); - smi_info->long_timeouts++; - spin_unlock_irqrestore(&smi_info->count_lock, flags); + smi_inc_stat(smi_info, long_timeouts); smi_info->si_timer.expires = jiffies + SI_TIMEOUT_JIFFIES; } @@ -979,13 +1032,11 @@ static irqreturn_t si_irq_handler(int irq, void *data) spin_lock_irqsave(&(smi_info->si_lock), flags); - spin_lock(&smi_info->count_lock); - smi_info->interrupts++; - spin_unlock(&smi_info->count_lock); + smi_inc_stat(smi_info, interrupts); #ifdef DEBUG_TIMING do_gettimeofday(&t); - printk("**Interrupt: %d.%9.9d\n", t.tv_sec, t.tv_usec); + printk(KERN_DEBUG "**Interrupt: %d.%9.9d\n", t.tv_sec, t.tv_usec); #endif smi_event_handler(smi_info, 0); spin_unlock_irqrestore(&(smi_info->si_lock), flags); @@ -1028,7 +1079,7 @@ static int smi_start_processing(void *send_info, * The BT interface is efficient enough to not need a thread, * and there is no need for a thread if we have interrupts. */ - else if ((new_smi->si_type != SI_BT) && (!new_smi->irq)) + else if ((new_smi->si_type != SI_BT) && (!new_smi->irq)) enable = 1; if (enable) { @@ -1054,8 +1105,7 @@ static void set_maintenance_mode(void *send_info, int enable) atomic_set(&smi_info->req_events, 0); } -static struct ipmi_smi_handlers handlers = -{ +static struct ipmi_smi_handlers handlers = { .owner = THIS_MODULE, .start_processing = smi_start_processing, .sender = sender, @@ -1065,8 +1115,10 @@ static struct ipmi_smi_handlers handlers = .poll = poll, }; -/* There can be 4 IO ports passed in (with or without IRQs), 4 addresses, - a default IO port, and 1 ACPI/SPMI address. That sets SI_MAX_DRIVERS */ +/* + * There can be 4 IO ports passed in (with or without IRQs), 4 addresses, + * a default IO port, and 1 ACPI/SPMI address. That sets SI_MAX_DRIVERS. + */ static LIST_HEAD(smi_infos); static DEFINE_MUTEX(smi_infos_lock); @@ -1257,10 +1309,9 @@ static void port_cleanup(struct smi_info *info) int idx; if (addr) { - for (idx = 0; idx < info->io_size; idx++) { + for (idx = 0; idx < info->io_size; idx++) release_region(addr + idx * info->io.regspacing, info->io.regsize); - } } } @@ -1274,8 +1325,10 @@ static int port_setup(struct smi_info *info) info->io_cleanup = port_cleanup; - /* Figure out the actual inb/inw/inl/etc routine to use based - upon the register size. */ + /* + * Figure out the actual inb/inw/inl/etc routine to use based + * upon the register size. + */ switch (info->io.regsize) { case 1: info->io.inputb = port_inb; @@ -1290,17 +1343,18 @@ static int port_setup(struct smi_info *info) info->io.outputb = port_outl; break; default: - printk("ipmi_si: Invalid register size: %d\n", + printk(KERN_WARNING "ipmi_si: Invalid register size: %d\n", info->io.regsize); return -EINVAL; } - /* Some BIOSes reserve disjoint I/O regions in their ACPI + /* + * Some BIOSes reserve disjoint I/O regions in their ACPI * tables. This causes problems when trying to register the * entire I/O region. Therefore we must register each I/O * port separately. */ - for (idx = 0; idx < info->io_size; idx++) { + for (idx = 0; idx < info->io_size; idx++) { if (request_region(addr + idx * info->io.regspacing, info->io.regsize, DEVICE_NAME) == NULL) { /* Undo allocations */ @@ -1388,8 +1442,10 @@ static int mem_setup(struct smi_info *info) info->io_cleanup = mem_cleanup; - /* Figure out the actual readb/readw/readl/etc routine to use based - upon the register size. */ + /* + * Figure out the actual readb/readw/readl/etc routine to use based + * upon the register size. + */ switch (info->io.regsize) { case 1: info->io.inputb = intf_mem_inb; @@ -1410,16 +1466,18 @@ static int mem_setup(struct smi_info *info) break; #endif default: - printk("ipmi_si: Invalid register size: %d\n", + printk(KERN_WARNING "ipmi_si: Invalid register size: %d\n", info->io.regsize); return -EINVAL; } - /* Calculate the total amount of memory to claim. This is an + /* + * Calculate the total amount of memory to claim. This is an * unusual looking calculation, but it avoids claiming any * more memory than it has to. It will claim everything * between the first address to the end of the last full - * register. */ + * register. + */ mapsize = ((info->io_size * info->io.regspacing) - (info->io.regspacing - info->io.regsize)); @@ -1749,9 +1807,11 @@ static __devinit void hardcode_find_bmc(void) #include <linux/acpi.h> -/* Once we get an ACPI failure, we don't try any more, because we go - through the tables sequentially. Once we don't find a table, there - are no more. */ +/* + * Once we get an ACPI failure, we don't try any more, because we go + * through the tables sequentially. Once we don't find a table, there + * are no more. + */ static int acpi_failure; /* For GPE-type interrupts. */ @@ -1765,9 +1825,7 @@ static u32 ipmi_acpi_gpe(void *context) spin_lock_irqsave(&(smi_info->si_lock), flags); - spin_lock(&smi_info->count_lock); - smi_info->interrupts++; - spin_unlock(&smi_info->count_lock); + smi_inc_stat(smi_info, interrupts); #ifdef DEBUG_TIMING do_gettimeofday(&t); @@ -1816,7 +1874,8 @@ static int acpi_gpe_irq_setup(struct smi_info *info) /* * Defined at - * http://h21007.www2.hp.com/dspp/files/unprotected/devresource/Docs/TechPapers/IA64/hpspmi.pdf + * http://h21007.www2.hp.com/dspp/files/unprotected/devresource/ + * Docs/TechPapers/IA64/hpspmi.pdf */ struct SPMITable { s8 Signature[4]; @@ -1838,14 +1897,18 @@ struct SPMITable { */ u8 InterruptType; - /* If bit 0 of InterruptType is set, then this is the SCI - interrupt in the GPEx_STS register. */ + /* + * If bit 0 of InterruptType is set, then this is the SCI + * interrupt in the GPEx_STS register. + */ u8 GPE; s16 Reserved; - /* If bit 1 of InterruptType is set, then this is the I/O - APIC/SAPIC interrupt. */ + /* + * If bit 1 of InterruptType is set, then this is the I/O + * APIC/SAPIC interrupt. + */ u32 GlobalSystemInterrupt; /* The actual register address. */ @@ -1863,7 +1926,7 @@ static __devinit int try_init_acpi(struct SPMITable *spmi) if (spmi->IPMIlegacy != 1) { printk(KERN_INFO "IPMI: Bad SPMI legacy %d\n", spmi->IPMIlegacy); - return -ENODEV; + return -ENODEV; } if (spmi->addr.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) @@ -1880,8 +1943,7 @@ static __devinit int try_init_acpi(struct SPMITable *spmi) info->addr_source = "ACPI"; /* Figure out the interface type. */ - switch (spmi->InterfaceType) - { + switch (spmi->InterfaceType) { case 1: /* KCS */ info->si_type = SI_KCS; break; @@ -1929,7 +1991,8 @@ static __devinit int try_init_acpi(struct SPMITable *spmi) info->io.addr_type = IPMI_IO_ADDR_SPACE; } else { kfree(info); - printk("ipmi_si: Unknown ACPI I/O Address type\n"); + printk(KERN_WARNING + "ipmi_si: Unknown ACPI I/O Address type\n"); return -EIO; } info->io.addr_data = spmi->addr.address; @@ -1963,8 +2026,7 @@ static __devinit void acpi_find_bmc(void) #endif #ifdef CONFIG_DMI -struct dmi_ipmi_data -{ +struct dmi_ipmi_data { u8 type; u8 addr_space; unsigned long base_addr; @@ -1989,11 +2051,10 @@ static int __devinit decode_dmi(const struct dmi_header *dm, /* I/O */ base_addr &= 0xFFFE; dmi->addr_space = IPMI_IO_ADDR_SPACE; - } - else { + } else /* Memory */ dmi->addr_space = IPMI_MEM_ADDR_SPACE; - } + /* If bit 4 of byte 0x10 is set, then the lsb for the address is odd. */ dmi->base_addr = base_addr | ((data[0x10] & 0x10) >> 4); @@ -2002,7 +2063,7 @@ static int __devinit decode_dmi(const struct dmi_header *dm, /* The top two bits of byte 0x10 hold the register spacing. */ reg_spacing = (data[0x10] & 0xC0) >> 6; - switch(reg_spacing){ + switch (reg_spacing) { case 0x00: /* Byte boundaries */ dmi->offset = 1; break; @@ -2018,12 +2079,14 @@ static int __devinit decode_dmi(const struct dmi_header *dm, } } else { /* Old DMI spec. */ - /* Note that technically, the lower bit of the base + /* + * Note that technically, the lower bit of the base * address should be 1 if the address is I/O and 0 if * the address is in memory. So many systems get that * wrong (and all that I have seen are I/O) so we just * ignore that bit and assume I/O. Systems that use - * memory should use the newer spec, anyway. */ + * memory should use the newer spec, anyway. + */ dmi->base_addr = base_addr & 0xfffe; dmi->addr_space = IPMI_IO_ADDR_SPACE; dmi->offset = 1; @@ -2230,13 +2293,13 @@ static struct pci_device_id ipmi_pci_devices[] = { MODULE_DEVICE_TABLE(pci, ipmi_pci_devices); static struct pci_driver ipmi_pci_driver = { - .name = DEVICE_NAME, - .id_table = ipmi_pci_devices, - .probe = ipmi_pci_probe, - .remove = __devexit_p(ipmi_pci_remove), + .name = DEVICE_NAME, + .id_table = ipmi_pci_devices, + .probe = ipmi_pci_probe, + .remove = __devexit_p(ipmi_pci_remove), #ifdef CONFIG_PM - .suspend = ipmi_pci_suspend, - .resume = ipmi_pci_resume, + .suspend = ipmi_pci_suspend, + .resume = ipmi_pci_resume, #endif }; #endif /* CONFIG_PCI */ @@ -2306,7 +2369,7 @@ static int __devinit ipmi_of_probe(struct of_device *dev, info->io.addr_data, info->io.regsize, info->io.regspacing, info->irq); - dev->dev.driver_data = (void*) info; + dev->dev.driver_data = (void *) info; return try_smi_init(info); } @@ -2319,14 +2382,16 @@ static int __devexit ipmi_of_remove(struct of_device *dev) static struct of_device_id ipmi_match[] = { - { .type = "ipmi", .compatible = "ipmi-kcs", .data = (void *)(unsigned long) SI_KCS }, - { .type = "ipmi", .compatible = "ipmi-smic", .data = (void *)(unsigned long) SI_SMIC }, - { .type = "ipmi", .compatible = "ipmi-bt", .data = (void *)(unsigned long) SI_BT }, + { .type = "ipmi", .compatible = "ipmi-kcs", + .data = (void *)(unsigned long) SI_KCS }, + { .type = "ipmi", .compatible = "ipmi-smic", + .data = (void *)(unsigned long) SI_SMIC }, + { .type = "ipmi", .compatible = "ipmi-bt", + .data = (void *)(unsigned long) SI_BT }, {}, }; -static struct of_platform_driver ipmi_of_platform_driver = -{ +static struct of_platform_driver ipmi_of_platform_driver = { .name = "ipmi", .match_table = ipmi_match, .probe = ipmi_of_probe, @@ -2347,32 +2412,32 @@ static int try_get_dev_id(struct smi_info *smi_info) if (!resp) return -ENOMEM; - /* Do a Get Device ID command, since it comes back with some - useful info. */ + /* + * Do a Get Device ID command, since it comes back with some + * useful info. + */ msg[0] = IPMI_NETFN_APP_REQUEST << 2; msg[1] = IPMI_GET_DEVICE_ID_CMD; smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2); smi_result = smi_info->handlers->event(smi_info->si_sm, 0); - for (;;) - { + for (;;) { if (smi_result == SI_SM_CALL_WITH_DELAY || smi_result == SI_SM_CALL_WITH_TICK_DELAY) { schedule_timeout_uninterruptible(1); smi_result = smi_info->handlers->event( smi_info->si_sm, 100); - } - else if (smi_result == SI_SM_CALL_WITHOUT_DELAY) - { + } else if (smi_result == SI_SM_CALL_WITHOUT_DELAY) { smi_result = smi_info->handlers->event( smi_info->si_sm, 0); - } - else + } else break; } if (smi_result == SI_SM_HOSED) { - /* We couldn't get the state machine to run, so whatever's at - the port is probably not an IPMI SMI interface. */ + /* + * We couldn't get the state machine to run, so whatever's at + * the port is probably not an IPMI SMI interface. + */ rv = -ENODEV; goto out; } @@ -2405,30 +2470,28 @@ static int stat_file_read_proc(char *page, char **start, off_t off, out += sprintf(out, "interrupts_enabled: %d\n", smi->irq && !smi->interrupt_disabled); - out += sprintf(out, "short_timeouts: %ld\n", - smi->short_timeouts); - out += sprintf(out, "long_timeouts: %ld\n", - smi->long_timeouts); - out += sprintf(out, "timeout_restarts: %ld\n", - smi->timeout_restarts); - out += sprintf(out, "idles: %ld\n", - smi->idles); - out += sprintf(out, "interrupts: %ld\n", - smi->interrupts); - out += sprintf(out, "attentions: %ld\n", - smi->attentions); - out += sprintf(out, "flag_fetches: %ld\n", - smi->flag_fetches); - out += sprintf(out, "hosed_count: %ld\n", - smi->hosed_count); - out += sprintf(out, "complete_transactions: %ld\n", - smi->complete_transactions); - out += sprintf(out, "events: %ld\n", - smi->events); - out += sprintf(out, "watchdog_pretimeouts: %ld\n", - smi->watchdog_pretimeouts); - out += sprintf(out, "incoming_messages: %ld\n", - smi->incoming_messages); + out += sprintf(out, "short_timeouts: %u\n", + smi_get_stat(smi, short_timeouts)); + out += sprintf(out, "long_timeouts: %u\n", + smi_get_stat(smi, long_timeouts)); + out += sprintf(out, "idles: %u\n", + smi_get_stat(smi, idles)); + out += sprintf(out, "interrupts: %u\n", + smi_get_stat(smi, interrupts)); + out += sprintf(out, "attentions: %u\n", + smi_get_stat(smi, attentions)); + out += sprintf(out, "flag_fetches: %u\n", + smi_get_stat(smi, flag_fetches)); + out += sprintf(out, "hosed_count: %u\n", + smi_get_stat(smi, hosed_count)); + out += sprintf(out, "complete_transactions: %u\n", + smi_get_stat(smi, complete_transactions)); + out += sprintf(out, "events: %u\n", + smi_get_stat(smi, events)); + out += sprintf(out, "watchdog_pretimeouts: %u\n", + smi_get_stat(smi, watchdog_pretimeouts)); + out += sprintf(out, "incoming_messages: %u\n", + smi_get_stat(smi, incoming_messages)); return out - page; } @@ -2460,7 +2523,7 @@ static int param_read_proc(char *page, char **start, off_t off, static int oem_data_avail_to_receive_msg_avail(struct smi_info *smi_info) { smi_info->msg_flags = ((smi_info->msg_flags & ~OEM_DATA_AVAIL) | - RECEIVE_MSG_AVAIL); + RECEIVE_MSG_AVAIL); return 1; } @@ -2502,10 +2565,9 @@ static void setup_dell_poweredge_oem_data_handler(struct smi_info *smi_info) id->ipmi_version == DELL_POWEREDGE_8G_BMC_IPMI_VERSION) { smi_info->oem_data_avail_handler = oem_data_avail_to_receive_msg_avail; - } - else if (ipmi_version_major(id) < 1 || - (ipmi_version_major(id) == 1 && - ipmi_version_minor(id) < 5)) { + } else if (ipmi_version_major(id) < 1 || + (ipmi_version_major(id) == 1 && + ipmi_version_minor(id) < 5)) { smi_info->oem_data_avail_handler = oem_data_avail_to_receive_msg_avail; } @@ -2597,8 +2659,10 @@ static void setup_xaction_handlers(struct smi_info *smi_info) static inline void wait_for_timer_and_thread(struct smi_info *smi_info) { if (smi_info->intf) { - /* The timer and thread are only running if the - interface has been started up and registered. */ + /* + * The timer and thread are only running if the + * interface has been started up and registered. + */ if (smi_info->thread != NULL) kthread_stop(smi_info->thread); del_timer_sync(&smi_info->si_timer); @@ -2676,6 +2740,7 @@ static int is_new_interface(struct smi_info *info) static int try_smi_init(struct smi_info *new_smi) { int rv; + int i; if (new_smi->addr_source) { printk(KERN_INFO "ipmi_si: Trying %s-specified %s state" @@ -2722,7 +2787,7 @@ static int try_smi_init(struct smi_info *new_smi) /* Allocate the state machine's data and initialize it. */ new_smi->si_sm = kmalloc(new_smi->handlers->size(), GFP_KERNEL); if (!new_smi->si_sm) { - printk(" Could not allocate state machine memory\n"); + printk(KERN_ERR "Could not allocate state machine memory\n"); rv = -ENOMEM; goto out_err; } @@ -2732,13 +2797,12 @@ static int try_smi_init(struct smi_info *new_smi) /* Now that we know the I/O size, we can set up the I/O. */ rv = new_smi->io_setup(new_smi); if (rv) { - printk(" Could not set up I/O space\n"); + printk(KERN_ERR "Could not set up I/O space\n"); goto out_err; } spin_lock_init(&(new_smi->si_lock)); spin_lock_init(&(new_smi->msg_lock)); - spin_lock_init(&(new_smi->count_lock)); /* Do low-level detection first. */ if (new_smi->handlers->detect(new_smi->si_sm)) { @@ -2749,8 +2813,10 @@ static int try_smi_init(struct smi_info *new_smi) goto out_err; } - /* Attempt a get device id command. If it fails, we probably - don't have a BMC here. */ + /* + * Attempt a get device id command. If it fails, we probably + * don't have a BMC here. + */ rv = try_get_dev_id(new_smi); if (rv) { if (new_smi->addr_source) @@ -2767,22 +2833,28 @@ static int try_smi_init(struct smi_info *new_smi) new_smi->curr_msg = NULL; atomic_set(&new_smi->req_events, 0); new_smi->run_to_completion = 0; + for (i = 0; i < SI_NUM_STATS; i++) + atomic_set(&new_smi->stats[i], 0); new_smi->interrupt_disabled = 0; atomic_set(&new_smi->stop_operation, 0); new_smi->intf_num = smi_num; smi_num++; - /* Start clearing the flags before we enable interrupts or the - timer to avoid racing with the timer. */ + /* + * Start clearing the flags before we enable interrupts or the + * timer to avoid racing with the timer. + */ start_clear_flags(new_smi); /* IRQ is defined to be set when non-zero. */ if (new_smi->irq) new_smi->si_state = SI_CLEARING_FLAGS_THEN_SET_IRQ; if (!new_smi->dev) { - /* If we don't already have a device from something - * else (like PCI), then register a new one. */ + /* + * If we don't already have a device from something + * else (like PCI), then register a new one. + */ new_smi->pdev = platform_device_alloc("ipmi_si", new_smi->intf_num); if (rv) { @@ -2820,7 +2892,7 @@ static int try_smi_init(struct smi_info *new_smi) } rv = ipmi_smi_add_proc_entry(new_smi->intf, "type", - type_file_read_proc, NULL, + type_file_read_proc, new_smi, THIS_MODULE); if (rv) { printk(KERN_ERR @@ -2830,7 +2902,7 @@ static int try_smi_init(struct smi_info *new_smi) } rv = ipmi_smi_add_proc_entry(new_smi->intf, "si_stats", - stat_file_read_proc, NULL, + stat_file_read_proc, new_smi, THIS_MODULE); if (rv) { printk(KERN_ERR @@ -2840,7 +2912,7 @@ static int try_smi_init(struct smi_info *new_smi) } rv = ipmi_smi_add_proc_entry(new_smi->intf, "params", - param_read_proc, NULL, + param_read_proc, new_smi, THIS_MODULE); if (rv) { printk(KERN_ERR @@ -2853,7 +2925,8 @@ static int try_smi_init(struct smi_info *new_smi) mutex_unlock(&smi_infos_lock); - printk(KERN_INFO "IPMI %s interface initialized\n",si_to_str[new_smi->si_type]); + printk(KERN_INFO "IPMI %s interface initialized\n", + si_to_str[new_smi->si_type]); return 0; @@ -2868,9 +2941,11 @@ static int try_smi_init(struct smi_info *new_smi) if (new_smi->irq_cleanup) new_smi->irq_cleanup(new_smi); - /* Wait until we know that we are out of any interrupt - handlers might have been running before we freed the - interrupt. */ + /* + * Wait until we know that we are out of any interrupt + * handlers might have been running before we freed the + * interrupt. + */ synchronize_sched(); if (new_smi->si_sm) { @@ -2942,11 +3017,10 @@ static __devinit int init_ipmi_si(void) #ifdef CONFIG_PCI rv = pci_register_driver(&ipmi_pci_driver); - if (rv){ + if (rv) printk(KERN_ERR "init_ipmi_si: Unable to register PCI driver: %d\n", rv); - } #endif #ifdef CONFIG_PPC_OF @@ -2975,7 +3049,8 @@ static __devinit int init_ipmi_si(void) of_unregister_platform_driver(&ipmi_of_platform_driver); #endif driver_unregister(&ipmi_driver); - printk("ipmi_si: Unable to find any System Interface(s)\n"); + printk(KERN_WARNING + "ipmi_si: Unable to find any System Interface(s)\n"); return -ENODEV; } else { mutex_unlock(&smi_infos_lock); @@ -2997,13 +3072,17 @@ static void cleanup_one_si(struct smi_info *to_clean) /* Tell the driver that we are shutting down. */ atomic_inc(&to_clean->stop_operation); - /* Make sure the timer and thread are stopped and will not run - again. */ + /* + * Make sure the timer and thread are stopped and will not run + * again. + */ wait_for_timer_and_thread(to_clean); - /* Timeouts are stopped, now make sure the interrupts are off - for the device. A little tricky with locks to make sure - there are no races. */ + /* + * Timeouts are stopped, now make sure the interrupts are off + * for the device. A little tricky with locks to make sure + * there are no races. + */ spin_lock_irqsave(&to_clean->si_lock, flags); while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) { spin_unlock_irqrestore(&to_clean->si_lock, flags); @@ -3074,4 +3153,5 @@ module_exit(cleanup_ipmi_si); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>"); -MODULE_DESCRIPTION("Interface to the IPMI driver for the KCS, SMIC, and BT system interfaces."); +MODULE_DESCRIPTION("Interface to the IPMI driver for the KCS, SMIC, and BT" + " system interfaces."); diff --git a/drivers/char/ipmi/ipmi_si_sm.h b/drivers/char/ipmi/ipmi_si_sm.h index 4b731b24dc1..df89f73475f 100644 --- a/drivers/char/ipmi/ipmi_si_sm.h +++ b/drivers/char/ipmi/ipmi_si_sm.h @@ -34,22 +34,27 @@ * 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* This is defined by the state machines themselves, it is an opaque - data type for them to use. */ +/* + * This is defined by the state machines themselves, it is an opaque + * data type for them to use. + */ struct si_sm_data; -/* The structure for doing I/O in the state machine. The state - machine doesn't have the actual I/O routines, they are done through - this interface. */ -struct si_sm_io -{ +/* + * The structure for doing I/O in the state machine. The state + * machine doesn't have the actual I/O routines, they are done through + * this interface. + */ +struct si_sm_io { unsigned char (*inputb)(struct si_sm_io *io, unsigned int offset); void (*outputb)(struct si_sm_io *io, unsigned int offset, unsigned char b); - /* Generic info used by the actual handling routines, the - state machine shouldn't touch these. */ + /* + * Generic info used by the actual handling routines, the + * state machine shouldn't touch these. + */ void __iomem *addr; int regspacing; int regsize; @@ -59,53 +64,67 @@ struct si_sm_io }; /* Results of SMI events. */ -enum si_sm_result -{ +enum si_sm_result { SI_SM_CALL_WITHOUT_DELAY, /* Call the driver again immediately */ SI_SM_CALL_WITH_DELAY, /* Delay some before calling again. */ - SI_SM_CALL_WITH_TICK_DELAY, /* Delay at least 1 tick before calling again. */ + SI_SM_CALL_WITH_TICK_DELAY,/* Delay >=1 tick before calling again. */ SI_SM_TRANSACTION_COMPLETE, /* A transaction is finished. */ SI_SM_IDLE, /* The SM is in idle state. */ SI_SM_HOSED, /* The hardware violated the state machine. */ - SI_SM_ATTN /* The hardware is asserting attn and the - state machine is idle. */ + + /* + * The hardware is asserting attn and the state machine is + * idle. + */ + SI_SM_ATTN }; /* Handlers for the SMI state machine. */ -struct si_sm_handlers -{ - /* Put the version number of the state machine here so the - upper layer can print it. */ +struct si_sm_handlers { + /* + * Put the version number of the state machine here so the + * upper layer can print it. + */ char *version; - /* Initialize the data and return the amount of I/O space to - reserve for the space. */ + /* + * Initialize the data and return the amount of I/O space to + * reserve for the space. + */ unsigned int (*init_data)(struct si_sm_data *smi, struct si_sm_io *io); - /* Start a new transaction in the state machine. This will - return -2 if the state machine is not idle, -1 if the size - is invalid (to large or too small), or 0 if the transaction - is successfully completed. */ + /* + * Start a new transaction in the state machine. This will + * return -2 if the state machine is not idle, -1 if the size + * is invalid (to large or too small), or 0 if the transaction + * is successfully completed. + */ int (*start_transaction)(struct si_sm_data *smi, unsigned char *data, unsigned int size); - /* Return the results after the transaction. This will return - -1 if the buffer is too small, zero if no transaction is - present, or the actual length of the result data. */ + /* + * Return the results after the transaction. This will return + * -1 if the buffer is too small, zero if no transaction is + * present, or the actual length of the result data. + */ int (*get_result)(struct si_sm_data *smi, unsigned char *data, unsigned int length); - /* Call this periodically (for a polled interface) or upon - receiving an interrupt (for a interrupt-driven interface). - If interrupt driven, you should probably poll this - periodically when not in idle state. This should be called - with the time that passed since the last call, if it is - significant. Time is in microseconds. */ + /* + * Call this periodically (for a polled interface) or upon + * receiving an interrupt (for a interrupt-driven interface). + * If interrupt driven, you should probably poll this + * periodically when not in idle state. This should be called + * with the time that passed since the last call, if it is + * significant. Time is in microseconds. + */ enum si_sm_result (*event)(struct si_sm_data *smi, long time); - /* Attempt to detect an SMI. Returns 0 on success or nonzero - on failure. */ + /* + * Attempt to detect an SMI. Returns 0 on success or nonzero + * on failure. + */ int (*detect)(struct si_sm_data *smi); /* The interface is shutting down, so clean it up. */ diff --git a/drivers/char/ipmi/ipmi_smic_sm.c b/drivers/char/ipmi/ipmi_smic_sm.c index e64ea7d25d2..faed9297190 100644 --- a/drivers/char/ipmi/ipmi_smic_sm.c +++ b/drivers/char/ipmi/ipmi_smic_sm.c @@ -85,6 +85,7 @@ enum smic_states { /* SMIC Flags Register Bits */ #define SMIC_RX_DATA_READY 0x80 #define SMIC_TX_DATA_READY 0x40 + /* * SMIC_SMI and SMIC_EVM_DATA_AVAIL are only used by * a few systems, and then only by Systems Management @@ -104,23 +105,22 @@ enum smic_states { #define EC_ILLEGAL_COMMAND 0x04 #define EC_BUFFER_FULL 0x05 -struct si_sm_data -{ +struct si_sm_data { enum smic_states state; struct si_sm_io *io; - unsigned char write_data[MAX_SMIC_WRITE_SIZE]; - int write_pos; - int write_count; - int orig_write_count; - unsigned char read_data[MAX_SMIC_READ_SIZE]; - int read_pos; - int truncated; - unsigned int error_retries; - long smic_timeout; + unsigned char write_data[MAX_SMIC_WRITE_SIZE]; + int write_pos; + int write_count; + int orig_write_count; + unsigned char read_data[MAX_SMIC_READ_SIZE]; + int read_pos; + int truncated; + unsigned int error_retries; + long smic_timeout; }; -static unsigned int init_smic_data (struct si_sm_data *smic, - struct si_sm_io *io) +static unsigned int init_smic_data(struct si_sm_data *smic, + struct si_sm_io *io) { smic->state = SMIC_IDLE; smic->io = io; @@ -150,11 +150,10 @@ static int start_smic_transaction(struct si_sm_data *smic, return IPMI_NOT_IN_MY_STATE_ERR; if (smic_debug & SMIC_DEBUG_MSG) { - printk(KERN_INFO "start_smic_transaction -"); - for (i = 0; i < size; i ++) { - printk (" %02x", (unsigned char) (data [i])); - } - printk ("\n"); + printk(KERN_DEBUG "start_smic_transaction -"); + for (i = 0; i < size; i++) + printk(" %02x", (unsigned char) data[i]); + printk("\n"); } smic->error_retries = 0; memcpy(smic->write_data, data, size); @@ -173,11 +172,10 @@ static int smic_get_result(struct si_sm_data *smic, int i; if (smic_debug & SMIC_DEBUG_MSG) { - printk (KERN_INFO "smic_get result -"); - for (i = 0; i < smic->read_pos; i ++) { - printk (" %02x", (smic->read_data [i])); - } - printk ("\n"); + printk(KERN_DEBUG "smic_get result -"); + for (i = 0; i < smic->read_pos; i++) + printk(" %02x", smic->read_data[i]); + printk("\n"); } if (length < smic->read_pos) { smic->read_pos = length; @@ -223,8 +221,8 @@ static inline void write_smic_control(struct si_sm_data *smic, smic->io->outputb(smic->io, 1, control); } -static inline void write_si_sm_data (struct si_sm_data *smic, - unsigned char data) +static inline void write_si_sm_data(struct si_sm_data *smic, + unsigned char data) { smic->io->outputb(smic->io, 0, data); } @@ -233,10 +231,9 @@ static inline void start_error_recovery(struct si_sm_data *smic, char *reason) { (smic->error_retries)++; if (smic->error_retries > SMIC_MAX_ERROR_RETRIES) { - if (smic_debug & SMIC_DEBUG_ENABLE) { + if (smic_debug & SMIC_DEBUG_ENABLE) printk(KERN_WARNING "ipmi_smic_drv: smic hosed: %s\n", reason); - } smic->state = SMIC_HOSED; } else { smic->write_count = smic->orig_write_count; @@ -254,14 +251,14 @@ static inline void write_next_byte(struct si_sm_data *smic) (smic->write_count)--; } -static inline void read_next_byte (struct si_sm_data *smic) +static inline void read_next_byte(struct si_sm_data *smic) { if (smic->read_pos >= MAX_SMIC_READ_SIZE) { - read_smic_data (smic); + read_smic_data(smic); smic->truncated = 1; } else { smic->read_data[smic->read_pos] = read_smic_data(smic); - (smic->read_pos)++; + smic->read_pos++; } } @@ -336,7 +333,7 @@ static inline void read_next_byte (struct si_sm_data *smic) SMIC_SC_SMS_RD_END 0xC6 */ -static enum si_sm_result smic_event (struct si_sm_data *smic, long time) +static enum si_sm_result smic_event(struct si_sm_data *smic, long time) { unsigned char status; unsigned char flags; @@ -347,13 +344,15 @@ static enum si_sm_result smic_event (struct si_sm_data *smic, long time) return SI_SM_HOSED; } if (smic->state != SMIC_IDLE) { - if (smic_debug & SMIC_DEBUG_STATES) { - printk(KERN_INFO + if (smic_debug & SMIC_DEBUG_STATES) + printk(KERN_DEBUG "smic_event - smic->smic_timeout = %ld," " time = %ld\n", smic->smic_timeout, time); - } -/* FIXME: smic_event is sometimes called with time > SMIC_RETRY_TIMEOUT */ + /* + * FIXME: smic_event is sometimes called with time > + * SMIC_RETRY_TIMEOUT + */ if (time < SMIC_RETRY_TIMEOUT) { smic->smic_timeout -= time; if (smic->smic_timeout < 0) { @@ -366,9 +365,9 @@ static enum si_sm_result smic_event (struct si_sm_data *smic, long time) if (flags & SMIC_FLAG_BSY) return SI_SM_CALL_WITH_DELAY; - status = read_smic_status (smic); + status = read_smic_status(smic); if (smic_debug & SMIC_DEBUG_STATES) - printk(KERN_INFO + printk(KERN_DEBUG "smic_event - state = %d, flags = 0x%02x," " status = 0x%02x\n", smic->state, flags, status); @@ -377,9 +376,7 @@ static enum si_sm_result smic_event (struct si_sm_data *smic, long time) case SMIC_IDLE: /* in IDLE we check for available messages */ if (flags & SMIC_SMS_DATA_AVAIL) - { return SI_SM_ATTN; - } return SI_SM_IDLE; case SMIC_START_OP: @@ -391,7 +388,7 @@ static enum si_sm_result smic_event (struct si_sm_data *smic, long time) case SMIC_OP_OK: if (status != SMIC_SC_SMS_READY) { - /* this should not happen */ + /* this should not happen */ start_error_recovery(smic, "state = SMIC_OP_OK," " status != SMIC_SC_SMS_READY"); @@ -411,8 +408,10 @@ static enum si_sm_result smic_event (struct si_sm_data *smic, long time) "status != SMIC_SC_SMS_WR_START"); return SI_SM_CALL_WITH_DELAY; } - /* we must not issue WR_(NEXT|END) unless - TX_DATA_READY is set */ + /* + * we must not issue WR_(NEXT|END) unless + * TX_DATA_READY is set + * */ if (flags & SMIC_TX_DATA_READY) { if (smic->write_count == 1) { /* last byte */ @@ -424,10 +423,8 @@ static enum si_sm_result smic_event (struct si_sm_data *smic, long time) } write_next_byte(smic); write_smic_flags(smic, flags | SMIC_FLAG_BSY); - } - else { + } else return SI_SM_CALL_WITH_DELAY; - } break; case SMIC_WRITE_NEXT: @@ -442,52 +439,48 @@ static enum si_sm_result smic_event (struct si_sm_data *smic, long time) if (smic->write_count == 1) { write_smic_control(smic, SMIC_CC_SMS_WR_END); smic->state = SMIC_WRITE_END; - } - else { + } else { write_smic_control(smic, SMIC_CC_SMS_WR_NEXT); smic->state = SMIC_WRITE_NEXT; } write_next_byte(smic); write_smic_flags(smic, flags | SMIC_FLAG_BSY); - } - else { + } else return SI_SM_CALL_WITH_DELAY; - } break; case SMIC_WRITE_END: if (status != SMIC_SC_SMS_WR_END) { - start_error_recovery (smic, - "state = SMIC_WRITE_END, " - "status != SMIC_SC_SMS_WR_END"); + start_error_recovery(smic, + "state = SMIC_WRITE_END, " + "status != SMIC_SC_SMS_WR_END"); return SI_SM_CALL_WITH_DELAY; } /* data register holds an error code */ data = read_smic_data(smic); if (data != 0) { - if (smic_debug & SMIC_DEBUG_ENABLE) { - printk(KERN_INFO + if (smic_debug & SMIC_DEBUG_ENABLE) + printk(KERN_DEBUG "SMIC_WRITE_END: data = %02x\n", data); - } start_error_recovery(smic, "state = SMIC_WRITE_END, " "data != SUCCESS"); return SI_SM_CALL_WITH_DELAY; - } else { + } else smic->state = SMIC_WRITE2READ; - } break; case SMIC_WRITE2READ: - /* we must wait for RX_DATA_READY to be set before we - can continue */ + /* + * we must wait for RX_DATA_READY to be set before we + * can continue + */ if (flags & SMIC_RX_DATA_READY) { write_smic_control(smic, SMIC_CC_SMS_RD_START); write_smic_flags(smic, flags | SMIC_FLAG_BSY); smic->state = SMIC_READ_START; - } else { + } else return SI_SM_CALL_WITH_DELAY; - } break; case SMIC_READ_START: @@ -502,15 +495,16 @@ static enum si_sm_result smic_event (struct si_sm_data *smic, long time) write_smic_control(smic, SMIC_CC_SMS_RD_NEXT); write_smic_flags(smic, flags | SMIC_FLAG_BSY); smic->state = SMIC_READ_NEXT; - } else { + } else return SI_SM_CALL_WITH_DELAY; - } break; case SMIC_READ_NEXT: switch (status) { - /* smic tells us that this is the last byte to be read - --> clean up */ + /* + * smic tells us that this is the last byte to be read + * --> clean up + */ case SMIC_SC_SMS_RD_END: read_next_byte(smic); write_smic_control(smic, SMIC_CC_SMS_RD_END); @@ -523,9 +517,8 @@ static enum si_sm_result smic_event (struct si_sm_data *smic, long time) write_smic_control(smic, SMIC_CC_SMS_RD_NEXT); write_smic_flags(smic, flags | SMIC_FLAG_BSY); smic->state = SMIC_READ_NEXT; - } else { + } else return SI_SM_CALL_WITH_DELAY; - } break; default: start_error_recovery( @@ -546,10 +539,9 @@ static enum si_sm_result smic_event (struct si_sm_data *smic, long time) data = read_smic_data(smic); /* data register holds an error code */ if (data != 0) { - if (smic_debug & SMIC_DEBUG_ENABLE) { - printk(KERN_INFO + if (smic_debug & SMIC_DEBUG_ENABLE) + printk(KERN_DEBUG "SMIC_READ_END: data = %02x\n", data); - } start_error_recovery(smic, "state = SMIC_READ_END, " "data != SUCCESS"); @@ -565,7 +557,7 @@ static enum si_sm_result smic_event (struct si_sm_data *smic, long time) default: if (smic_debug & SMIC_DEBUG_ENABLE) { - printk(KERN_WARNING "smic->state = %d\n", smic->state); + printk(KERN_DEBUG "smic->state = %d\n", smic->state); start_error_recovery(smic, "state = UNKNOWN"); return SI_SM_CALL_WITH_DELAY; } @@ -576,10 +568,12 @@ static enum si_sm_result smic_event (struct si_sm_data *smic, long time) static int smic_detect(struct si_sm_data *smic) { - /* It's impossible for the SMIC fnags register to be all 1's, - (assuming a properly functioning, self-initialized BMC) - but that's what you get from reading a bogus address, so we - test that first. */ + /* + * It's impossible for the SMIC fnags register to be all 1's, + * (assuming a properly functioning, self-initialized BMC) + * but that's what you get from reading a bogus address, so we + * test that first. + */ if (read_smic_flags(smic) == 0xff) return 1; @@ -595,8 +589,7 @@ static int smic_size(void) return sizeof(struct si_sm_data); } -struct si_sm_handlers smic_smi_handlers = -{ +struct si_sm_handlers smic_smi_handlers = { .init_data = init_smic_data, .start_transaction = start_smic_transaction, .get_result = smic_get_result, diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c index 8f45ca9235a..1b9a8704781 100644 --- a/drivers/char/ipmi/ipmi_watchdog.c +++ b/drivers/char/ipmi/ipmi_watchdog.c @@ -54,13 +54,15 @@ #include <asm/atomic.h> #ifdef CONFIG_X86 -/* This is ugly, but I've determined that x86 is the only architecture - that can reasonably support the IPMI NMI watchdog timeout at this - time. If another architecture adds this capability somehow, it - will have to be a somewhat different mechanism and I have no idea - how it will work. So in the unlikely event that another - architecture supports this, we can figure out a good generic - mechanism for it at that time. */ +/* + * This is ugly, but I've determined that x86 is the only architecture + * that can reasonably support the IPMI NMI watchdog timeout at this + * time. If another architecture adds this capability somehow, it + * will have to be a somewhat different mechanism and I have no idea + * how it will work. So in the unlikely event that another + * architecture supports this, we can figure out a good generic + * mechanism for it at that time. + */ #include <asm/kdebug.h> #define HAVE_DIE_NMI #endif @@ -95,9 +97,8 @@ /* Operations that can be performed on a pretimout. */ #define WDOG_PREOP_NONE 0 #define WDOG_PREOP_PANIC 1 -#define WDOG_PREOP_GIVE_DATA 2 /* Cause data to be available to - read. Doesn't work in NMI - mode. */ +/* Cause data to be available to read. Doesn't work in NMI mode. */ +#define WDOG_PREOP_GIVE_DATA 2 /* Actions to perform on a full timeout. */ #define WDOG_SET_TIMEOUT_ACT(byte, use) \ @@ -108,8 +109,10 @@ #define WDOG_TIMEOUT_POWER_DOWN 2 #define WDOG_TIMEOUT_POWER_CYCLE 3 -/* Byte 3 of the get command, byte 4 of the get response is the - pre-timeout in seconds. */ +/* + * Byte 3 of the get command, byte 4 of the get response is the + * pre-timeout in seconds. + */ /* Bits for setting byte 4 of the set command, byte 5 of the get response. */ #define WDOG_EXPIRE_CLEAR_BIOS_FRB2 (1 << 1) @@ -118,11 +121,13 @@ #define WDOG_EXPIRE_CLEAR_SMS_OS (1 << 4) #define WDOG_EXPIRE_CLEAR_OEM (1 << 5) -/* Setting/getting the watchdog timer value. This is for bytes 5 and - 6 (the timeout time) of the set command, and bytes 6 and 7 (the - timeout time) and 8 and 9 (the current countdown value) of the - response. The timeout value is given in seconds (in the command it - is 100ms intervals). */ +/* + * Setting/getting the watchdog timer value. This is for bytes 5 and + * 6 (the timeout time) of the set command, and bytes 6 and 7 (the + * timeout time) and 8 and 9 (the current countdown value) of the + * response. The timeout value is given in seconds (in the command it + * is 100ms intervals). + */ #define WDOG_SET_TIMEOUT(byte1, byte2, val) \ (byte1) = (((val) * 10) & 0xff), (byte2) = (((val) * 10) >> 8) #define WDOG_GET_TIMEOUT(byte1, byte2) \ @@ -184,8 +189,10 @@ static int ipmi_set_timeout(int do_heartbeat); static void ipmi_register_watchdog(int ipmi_intf); static void ipmi_unregister_watchdog(int ipmi_intf); -/* If true, the driver will start running as soon as it is configured - and ready. */ +/* + * If true, the driver will start running as soon as it is configured + * and ready. + */ static int start_now; static int set_param_int(const char *val, struct kernel_param *kp) @@ -309,10 +316,12 @@ static int ipmi_ignore_heartbeat; /* Is someone using the watchdog? Only one user is allowed. */ static unsigned long ipmi_wdog_open; -/* If set to 1, the heartbeat command will set the state to reset and - start the timer. The timer doesn't normally run when the driver is - first opened until the heartbeat is set the first time, this - variable is used to accomplish this. */ +/* + * If set to 1, the heartbeat command will set the state to reset and + * start the timer. The timer doesn't normally run when the driver is + * first opened until the heartbeat is set the first time, this + * variable is used to accomplish this. + */ static int ipmi_start_timer_on_heartbeat; /* IPMI version of the BMC. */ @@ -329,10 +338,12 @@ static int nmi_handler_registered; static int ipmi_heartbeat(void); -/* We use a mutex to make sure that only one thing can send a set - timeout at one time, because we only have one copy of the data. - The mutex is claimed when the set_timeout is sent and freed - when both messages are free. */ +/* + * We use a mutex to make sure that only one thing can send a set + * timeout at one time, because we only have one copy of the data. + * The mutex is claimed when the set_timeout is sent and freed + * when both messages are free. + */ static atomic_t set_timeout_tofree = ATOMIC_INIT(0); static DEFINE_MUTEX(set_timeout_lock); static DECLARE_COMPLETION(set_timeout_wait); @@ -346,15 +357,13 @@ static void set_timeout_free_recv(struct ipmi_recv_msg *msg) if (atomic_dec_and_test(&set_timeout_tofree)) complete(&set_timeout_wait); } -static struct ipmi_smi_msg set_timeout_smi_msg = -{ +static struct ipmi_smi_msg set_timeout_smi_msg = { .done = set_timeout_free_smi }; -static struct ipmi_recv_msg set_timeout_recv_msg = -{ +static struct ipmi_recv_msg set_timeout_recv_msg = { .done = set_timeout_free_recv }; - + static int i_ipmi_set_timeout(struct ipmi_smi_msg *smi_msg, struct ipmi_recv_msg *recv_msg, int *send_heartbeat_now) @@ -373,13 +382,14 @@ static int i_ipmi_set_timeout(struct ipmi_smi_msg *smi_msg, WDOG_SET_TIMER_USE(data[0], WDOG_TIMER_USE_SMS_OS); if ((ipmi_version_major > 1) - || ((ipmi_version_major == 1) && (ipmi_version_minor >= 5))) - { + || ((ipmi_version_major == 1) && (ipmi_version_minor >= 5))) { /* This is an IPMI 1.5-only feature. */ data[0] |= WDOG_DONT_STOP_ON_SET; } else if (ipmi_watchdog_state != WDOG_TIMEOUT_NONE) { - /* In ipmi 1.0, setting the timer stops the watchdog, we - need to start it back up again. */ + /* + * In ipmi 1.0, setting the timer stops the watchdog, we + * need to start it back up again. + */ hbnow = 1; } @@ -465,12 +475,10 @@ static void panic_recv_free(struct ipmi_recv_msg *msg) atomic_dec(&panic_done_count); } -static struct ipmi_smi_msg panic_halt_heartbeat_smi_msg = -{ +static struct ipmi_smi_msg panic_halt_heartbeat_smi_msg = { .done = panic_smi_free }; -static struct ipmi_recv_msg panic_halt_heartbeat_recv_msg = -{ +static struct ipmi_recv_msg panic_halt_heartbeat_recv_msg = { .done = panic_recv_free }; @@ -480,8 +488,10 @@ static void panic_halt_ipmi_heartbeat(void) struct ipmi_system_interface_addr addr; int rv; - /* Don't reset the timer if we have the timer turned off, that - re-enables the watchdog. */ + /* + * Don't reset the timer if we have the timer turned off, that + * re-enables the watchdog. + */ if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE) return; @@ -505,19 +515,19 @@ static void panic_halt_ipmi_heartbeat(void) atomic_add(2, &panic_done_count); } -static struct ipmi_smi_msg panic_halt_smi_msg = -{ +static struct ipmi_smi_msg panic_halt_smi_msg = { .done = panic_smi_free }; -static struct ipmi_recv_msg panic_halt_recv_msg = -{ +static struct ipmi_recv_msg panic_halt_recv_msg = { .done = panic_recv_free }; -/* Special call, doesn't claim any locks. This is only to be called - at panic or halt time, in run-to-completion mode, when the caller - is the only CPU and the only thing that will be going is these IPMI - calls. */ +/* + * Special call, doesn't claim any locks. This is only to be called + * at panic or halt time, in run-to-completion mode, when the caller + * is the only CPU and the only thing that will be going is these IPMI + * calls. + */ static void panic_halt_ipmi_set_timeout(void) { int send_heartbeat_now; @@ -540,10 +550,12 @@ static void panic_halt_ipmi_set_timeout(void) ipmi_poll_interface(watchdog_user); } -/* We use a semaphore to make sure that only one thing can send a - heartbeat at one time, because we only have one copy of the data. - The semaphore is claimed when the set_timeout is sent and freed - when both messages are free. */ +/* + * We use a mutex to make sure that only one thing can send a + * heartbeat at one time, because we only have one copy of the data. + * The semaphore is claimed when the set_timeout is sent and freed + * when both messages are free. + */ static atomic_t heartbeat_tofree = ATOMIC_INIT(0); static DEFINE_MUTEX(heartbeat_lock); static DECLARE_COMPLETION(heartbeat_wait); @@ -557,15 +569,13 @@ static void heartbeat_free_recv(struct ipmi_recv_msg *msg) if (atomic_dec_and_test(&heartbeat_tofree)) complete(&heartbeat_wait); } -static struct ipmi_smi_msg heartbeat_smi_msg = -{ +static struct ipmi_smi_msg heartbeat_smi_msg = { .done = heartbeat_free_smi }; -static struct ipmi_recv_msg heartbeat_recv_msg = -{ +static struct ipmi_recv_msg heartbeat_recv_msg = { .done = heartbeat_free_recv }; - + static int ipmi_heartbeat(void) { struct kernel_ipmi_msg msg; @@ -580,10 +590,12 @@ static int ipmi_heartbeat(void) ipmi_watchdog_state = action_val; return ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB); } else if (pretimeout_since_last_heartbeat) { - /* A pretimeout occurred, make sure we set the timeout. - We don't want to set the action, though, we want to - leave that alone (thus it can't be combined with the - above operation. */ + /* + * A pretimeout occurred, make sure we set the timeout. + * We don't want to set the action, though, we want to + * leave that alone (thus it can't be combined with the + * above operation. + */ return ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY); } @@ -591,8 +603,10 @@ static int ipmi_heartbeat(void) atomic_set(&heartbeat_tofree, 2); - /* Don't reset the timer if we have the timer turned off, that - re-enables the watchdog. */ + /* + * Don't reset the timer if we have the timer turned off, that + * re-enables the watchdog. + */ if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE) { mutex_unlock(&heartbeat_lock); return 0; @@ -625,10 +639,12 @@ static int ipmi_heartbeat(void) wait_for_completion(&heartbeat_wait); if (heartbeat_recv_msg.msg.data[0] != 0) { - /* Got an error in the heartbeat response. It was already - reported in ipmi_wdog_msg_handler, but we should return - an error here. */ - rv = -EINVAL; + /* + * Got an error in the heartbeat response. It was already + * reported in ipmi_wdog_msg_handler, but we should return + * an error here. + */ + rv = -EINVAL; } mutex_unlock(&heartbeat_lock); @@ -636,8 +652,7 @@ static int ipmi_heartbeat(void) return rv; } -static struct watchdog_info ident = -{ +static struct watchdog_info ident = { .options = 0, /* WDIOF_SETTIMEOUT, */ .firmware_version = 1, .identity = "IPMI" @@ -650,7 +665,7 @@ static int ipmi_ioctl(struct inode *inode, struct file *file, int i; int val; - switch(cmd) { + switch (cmd) { case WDIOC_GETSUPPORT: i = copy_to_user(argp, &ident, sizeof(ident)); return i ? -EFAULT : 0; @@ -690,15 +705,13 @@ static int ipmi_ioctl(struct inode *inode, struct file *file, i = copy_from_user(&val, argp, sizeof(int)); if (i) return -EFAULT; - if (val & WDIOS_DISABLECARD) - { + if (val & WDIOS_DISABLECARD) { ipmi_watchdog_state = WDOG_TIMEOUT_NONE; ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB); ipmi_start_timer_on_heartbeat = 0; } - if (val & WDIOS_ENABLECARD) - { + if (val & WDIOS_ENABLECARD) { ipmi_watchdog_state = action_val; ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB); } @@ -724,13 +737,13 @@ static ssize_t ipmi_write(struct file *file, int rv; if (len) { - if (!nowayout) { - size_t i; + if (!nowayout) { + size_t i; /* In case it was set long ago */ expect_close = 0; - for (i = 0; i != len; i++) { + for (i = 0; i != len; i++) { char c; if (get_user(c, buf + i)) @@ -758,15 +771,17 @@ static ssize_t ipmi_read(struct file *file, if (count <= 0) return 0; - /* Reading returns if the pretimeout has gone off, and it only does - it once per pretimeout. */ + /* + * Reading returns if the pretimeout has gone off, and it only does + * it once per pretimeout. + */ spin_lock(&ipmi_read_lock); if (!data_to_read) { if (file->f_flags & O_NONBLOCK) { rv = -EAGAIN; goto out; } - + init_waitqueue_entry(&wait, current); add_wait_queue(&read_q, &wait); while (!data_to_read) { @@ -776,7 +791,7 @@ static ssize_t ipmi_read(struct file *file, spin_lock(&ipmi_read_lock); } remove_wait_queue(&read_q, &wait); - + if (signal_pending(current)) { rv = -ERESTARTSYS; goto out; @@ -799,25 +814,27 @@ static ssize_t ipmi_read(struct file *file, static int ipmi_open(struct inode *ino, struct file *filep) { - switch (iminor(ino)) { - case WATCHDOG_MINOR: + switch (iminor(ino)) { + case WATCHDOG_MINOR: if (test_and_set_bit(0, &ipmi_wdog_open)) - return -EBUSY; + return -EBUSY; - /* Don't start the timer now, let it start on the - first heartbeat. */ + /* + * Don't start the timer now, let it start on the + * first heartbeat. + */ ipmi_start_timer_on_heartbeat = 1; return nonseekable_open(ino, filep); default: return (-ENODEV); - } + } } static unsigned int ipmi_poll(struct file *file, poll_table *wait) { unsigned int mask = 0; - + poll_wait(file, &read_q, wait); spin_lock(&ipmi_read_lock); @@ -851,7 +868,7 @@ static int ipmi_close(struct inode *ino, struct file *filep) clear_bit(0, &ipmi_wdog_open); } - ipmi_fasync (-1, filep, 0); + ipmi_fasync(-1, filep, 0); expect_close = 0; return 0; @@ -882,7 +899,7 @@ static void ipmi_wdog_msg_handler(struct ipmi_recv_msg *msg, msg->msg.data[0], msg->msg.cmd); } - + ipmi_free_recv_msg(msg); } @@ -902,14 +919,14 @@ static void ipmi_wdog_pretimeout_handler(void *handler_data) } } - /* On some machines, the heartbeat will give - an error and not work unless we re-enable - the timer. So do so. */ + /* + * On some machines, the heartbeat will give an error and not + * work unless we re-enable the timer. So do so. + */ pretimeout_since_last_heartbeat = 1; } -static struct ipmi_user_hndl ipmi_hndlrs = -{ +static struct ipmi_user_hndl ipmi_hndlrs = { .ipmi_recv_hndl = ipmi_wdog_msg_handler, .ipmi_watchdog_pretimeout = ipmi_wdog_pretimeout_handler }; @@ -949,8 +966,10 @@ static void ipmi_register_watchdog(int ipmi_intf) int old_timeout = timeout; int old_preop_val = preop_val; - /* Set the pretimeout to go off in a second and give - ourselves plenty of time to stop the timer. */ + /* + * Set the pretimeout to go off in a second and give + * ourselves plenty of time to stop the timer. + */ ipmi_watchdog_state = WDOG_TIMEOUT_RESET; preop_val = WDOG_PREOP_NONE; /* Make sure nothing happens */ pretimeout = 99; @@ -974,7 +993,7 @@ static void ipmi_register_watchdog(int ipmi_intf) " occur. The NMI pretimeout will" " likely not work\n"); } - out_restore: + out_restore: testing_nmi = 0; preop_val = old_preop_val; pretimeout = old_pretimeout; @@ -1009,9 +1028,11 @@ static void ipmi_unregister_watchdog(int ipmi_intf) /* Make sure no one can call us any more. */ misc_deregister(&ipmi_wdog_miscdev); - /* Wait to make sure the message makes it out. The lower layer has - pointers to our buffers, we want to make sure they are done before - we release our memory. */ + /* + * Wait to make sure the message makes it out. The lower layer has + * pointers to our buffers, we want to make sure they are done before + * we release our memory. + */ while (atomic_read(&set_timeout_tofree)) schedule_timeout_uninterruptible(1); @@ -1052,15 +1073,17 @@ ipmi_nmi(struct notifier_block *self, unsigned long val, void *data) return NOTIFY_STOP; } - /* If we are not expecting a timeout, ignore it. */ + /* If we are not expecting a timeout, ignore it. */ if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE) return NOTIFY_OK; if (preaction_val != WDOG_PRETIMEOUT_NMI) return NOTIFY_OK; - /* If no one else handled the NMI, we assume it was the IPMI - watchdog. */ + /* + * If no one else handled the NMI, we assume it was the IPMI + * watchdog. + */ if (preop_val == WDOG_PREOP_PANIC) { /* On some machines, the heartbeat will give an error and not work unless we re-enable @@ -1082,7 +1105,7 @@ static int wdog_reboot_handler(struct notifier_block *this, unsigned long code, void *unused) { - static int reboot_event_handled = 0; + static int reboot_event_handled; if ((watchdog_user) && (!reboot_event_handled)) { /* Make sure we only do this once. */ @@ -1115,7 +1138,7 @@ static int wdog_panic_handler(struct notifier_block *this, unsigned long event, void *unused) { - static int panic_event_handled = 0; + static int panic_event_handled; /* On a panic, if we have a panic timeout, make sure to extend the watchdog timer to a reasonable value to complete the @@ -1125,7 +1148,7 @@ static int wdog_panic_handler(struct notifier_block *this, ipmi_watchdog_state != WDOG_TIMEOUT_NONE) { /* Make sure we do this only once. */ panic_event_handled = 1; - + timeout = 255; pretimeout = 0; panic_halt_ipmi_set_timeout(); @@ -1151,8 +1174,7 @@ static void ipmi_smi_gone(int if_num) ipmi_unregister_watchdog(if_num); } -static struct ipmi_smi_watcher smi_watcher = -{ +static struct ipmi_smi_watcher smi_watcher = { .owner = THIS_MODULE, .new_smi = ipmi_new_smi, .smi_gone = ipmi_smi_gone diff --git a/drivers/char/mem.c b/drivers/char/mem.c index e83623ead44..934ffafedae 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -364,6 +364,7 @@ static int mmap_mem(struct file * file, struct vm_area_struct * vma) return 0; } +#ifdef CONFIG_DEVKMEM static int mmap_kmem(struct file * file, struct vm_area_struct * vma) { unsigned long pfn; @@ -384,6 +385,7 @@ static int mmap_kmem(struct file * file, struct vm_area_struct * vma) vma->vm_pgoff = pfn; return mmap_mem(file, vma); } +#endif #ifdef CONFIG_CRASH_DUMP /* @@ -422,6 +424,7 @@ static ssize_t read_oldmem(struct file *file, char __user *buf, extern long vread(char *buf, char *addr, unsigned long count); extern long vwrite(char *buf, char *addr, unsigned long count); +#ifdef CONFIG_DEVKMEM /* * This function reads the *virtual* memory as seen by the kernel. */ @@ -626,6 +629,7 @@ static ssize_t write_kmem(struct file * file, const char __user * buf, *ppos = p; return virtr + wrote; } +#endif #ifdef CONFIG_DEVPORT static ssize_t read_port(struct file * file, char __user * buf, @@ -803,6 +807,7 @@ static const struct file_operations mem_fops = { .get_unmapped_area = get_unmapped_area_mem, }; +#ifdef CONFIG_DEVKMEM static const struct file_operations kmem_fops = { .llseek = memory_lseek, .read = read_kmem, @@ -811,6 +816,7 @@ static const struct file_operations kmem_fops = { .open = open_kmem, .get_unmapped_area = get_unmapped_area_mem, }; +#endif static const struct file_operations null_fops = { .llseek = null_lseek, @@ -889,11 +895,13 @@ static int memory_open(struct inode * inode, struct file * filp) filp->f_mapping->backing_dev_info = &directly_mappable_cdev_bdi; break; +#ifdef CONFIG_DEVKMEM case 2: filp->f_op = &kmem_fops; filp->f_mapping->backing_dev_info = &directly_mappable_cdev_bdi; break; +#endif case 3: filp->f_op = &null_fops; break; @@ -942,7 +950,9 @@ static const struct { const struct file_operations *fops; } devlist[] = { /* list of minor devices */ {1, "mem", S_IRUSR | S_IWUSR | S_IRGRP, &mem_fops}, +#ifdef CONFIG_DEVKMEM {2, "kmem", S_IRUSR | S_IWUSR | S_IRGRP, &kmem_fops}, +#endif {3, "null", S_IRUGO | S_IWUGO, &null_fops}, #ifdef CONFIG_DEVPORT {4, "port", S_IRUSR | S_IWUSR | S_IRGRP, &port_fops}, diff --git a/drivers/char/misc.c b/drivers/char/misc.c index 4d058dadbfc..eaace0db0ff 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -263,23 +263,26 @@ EXPORT_SYMBOL(misc_deregister); static int __init misc_init(void) { -#ifdef CONFIG_PROC_FS - struct proc_dir_entry *ent; + int err; - ent = create_proc_entry("misc", 0, NULL); - if (ent) - ent->proc_fops = &misc_proc_fops; +#ifdef CONFIG_PROC_FS + proc_create("misc", 0, NULL, &misc_proc_fops); #endif misc_class = class_create(THIS_MODULE, "misc"); + err = PTR_ERR(misc_class); if (IS_ERR(misc_class)) - return PTR_ERR(misc_class); + goto fail_remove; - if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) { - printk("unable to get major %d for misc devices\n", - MISC_MAJOR); - class_destroy(misc_class); - return -EIO; - } + err = -EIO; + if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) + goto fail_printk; return 0; + +fail_printk: + printk("unable to get major %d for misc devices\n", MISC_MAJOR); + class_destroy(misc_class); +fail_remove: + remove_proc_entry("misc", NULL); + return err; } subsys_initcall(misc_init); diff --git a/drivers/char/n_hdlc.c b/drivers/char/n_hdlc.c index 82bcfb9c839..06803ed5568 100644 --- a/drivers/char/n_hdlc.c +++ b/drivers/char/n_hdlc.c @@ -501,7 +501,7 @@ static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data, __FILE__,__LINE__, count); /* This can happen if stuff comes in on the backup tty */ - if (n_hdlc == 0 || tty != n_hdlc->tty) + if (!n_hdlc || tty != n_hdlc->tty) return; /* verify line is using HDLC discipline */ diff --git a/drivers/char/pcmcia/ipwireless/hardware.c b/drivers/char/pcmcia/ipwireless/hardware.c index 1f978ff87fa..fa9d3c945f3 100644 --- a/drivers/char/pcmcia/ipwireless/hardware.c +++ b/drivers/char/pcmcia/ipwireless/hardware.c @@ -354,32 +354,6 @@ struct ipw_rx_packet { unsigned int channel_idx; }; -#ifdef IPWIRELESS_STATE_DEBUG -int ipwireless_dump_hardware_state(char *p, size_t limit, - struct ipw_hardware *hw) -{ - return snprintf(p, limit, - "debug: initializing=%d\n" - "debug: tx_ready=%d\n" - "debug: tx_queued=%d\n" - "debug: rx_ready=%d\n" - "debug: rx_bytes_queued=%d\n" - "debug: blocking_rx=%d\n" - "debug: removed=%d\n" - "debug: hardware.shutting_down=%d\n" - "debug: to_setup=%d\n", - hw->initializing, - hw->tx_ready, - hw->tx_queued, - hw->rx_ready, - hw->rx_bytes_queued, - hw->blocking_rx, - hw->removed, - hw->shutting_down, - hw->to_setup); -} -#endif - static char *data_type(const unsigned char *buf, unsigned length) { struct nl_packet_header *hdr = (struct nl_packet_header *) buf; diff --git a/drivers/char/pcmcia/ipwireless/hardware.h b/drivers/char/pcmcia/ipwireless/hardware.h index c83190ffb0e..19ce5eb266b 100644 --- a/drivers/char/pcmcia/ipwireless/hardware.h +++ b/drivers/char/pcmcia/ipwireless/hardware.h @@ -58,7 +58,5 @@ void ipwireless_init_hardware_v1(struct ipw_hardware *hw, void *reboot_cb_data); void ipwireless_init_hardware_v2_v3(struct ipw_hardware *hw); void ipwireless_sleep(unsigned int tenths); -int ipwireless_dump_hardware_state(char *p, size_t limit, - struct ipw_hardware *hw); #endif diff --git a/drivers/char/pcmcia/ipwireless/network.c b/drivers/char/pcmcia/ipwireless/network.c index d793e68b3e0..fe914d34f7f 100644 --- a/drivers/char/pcmcia/ipwireless/network.c +++ b/drivers/char/pcmcia/ipwireless/network.c @@ -63,21 +63,6 @@ struct ipw_network { struct work_struct work_go_offline; }; - -#ifdef IPWIRELESS_STATE_DEBUG -int ipwireless_dump_network_state(char *p, size_t limit, - struct ipw_network *network) -{ - return snprintf(p, limit, - "debug: ppp_blocked=%d\n" - "debug: outgoing_packets_queued=%d\n" - "debug: network.shutting_down=%d\n", - network->ppp_blocked, - network->outgoing_packets_queued, - network->shutting_down); -} -#endif - static void notify_packet_sent(void *callback_data, unsigned int packet_length) { struct ipw_network *network = callback_data; diff --git a/drivers/char/pcmcia/ipwireless/network.h b/drivers/char/pcmcia/ipwireless/network.h index b0e1e952fd1..ccacd26fc7e 100644 --- a/drivers/char/pcmcia/ipwireless/network.h +++ b/drivers/char/pcmcia/ipwireless/network.h @@ -49,7 +49,4 @@ void ipwireless_ppp_close(struct ipw_network *net); int ipwireless_ppp_channel_index(struct ipw_network *net); int ipwireless_ppp_unit_number(struct ipw_network *net); -int ipwireless_dump_network_state(char *p, size_t limit, - struct ipw_network *net); - #endif diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 4e84d233e5a..583356426df 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -189,20 +189,20 @@ typedef struct _mgslpc_info { u32 pending_bh; - int bh_running; - int bh_requested; + bool bh_running; + bool bh_requested; int dcd_chkcount; /* check counts to prevent */ int cts_chkcount; /* too many IRQs if a signal */ int dsr_chkcount; /* is floating */ int ri_chkcount; - int rx_enabled; - int rx_overflow; + bool rx_enabled; + bool rx_overflow; - int tx_enabled; - int tx_active; - int tx_aborting; + bool tx_enabled; + bool tx_active; + bool tx_aborting; u32 idle_mode; int if_mode; /* serial interface selection (RS-232, v.35 etc) */ @@ -216,12 +216,12 @@ typedef struct _mgslpc_info { unsigned char serial_signals; /* current serial signal states */ - char irq_occurred; /* for diagnostics use */ + bool irq_occurred; /* for diagnostics use */ char testing_irq; unsigned int init_error; /* startup error (DIAGS) */ char flag_buf[MAX_ASYNC_BUFFER_SIZE]; - BOOLEAN drop_rts_on_tx_done; + bool drop_rts_on_tx_done; struct _input_signal_events input_signal_events; @@ -402,8 +402,8 @@ static void hdlcdev_exit(MGSLPC_INFO *info); static void trace_block(MGSLPC_INFO *info,const char* data, int count, int xmit); -static BOOLEAN register_test(MGSLPC_INFO *info); -static BOOLEAN irq_test(MGSLPC_INFO *info); +static bool register_test(MGSLPC_INFO *info); +static bool irq_test(MGSLPC_INFO *info); static int adapter_test(MGSLPC_INFO *info); static int claim_resources(MGSLPC_INFO *info); @@ -411,7 +411,7 @@ static void release_resources(MGSLPC_INFO *info); static void mgslpc_add_device(MGSLPC_INFO *info); static void mgslpc_remove_device(MGSLPC_INFO *info); -static int rx_get_frame(MGSLPC_INFO *info); +static bool rx_get_frame(MGSLPC_INFO *info); static void rx_reset_buffers(MGSLPC_INFO *info); static int rx_alloc_buffers(MGSLPC_INFO *info); static void rx_free_buffers(MGSLPC_INFO *info); @@ -719,7 +719,7 @@ static int mgslpc_resume(struct pcmcia_device *link) } -static inline int mgslpc_paranoia_check(MGSLPC_INFO *info, +static inline bool mgslpc_paranoia_check(MGSLPC_INFO *info, char *name, const char *routine) { #ifdef MGSLPC_PARANOIA_CHECK @@ -730,17 +730,17 @@ static inline int mgslpc_paranoia_check(MGSLPC_INFO *info, if (!info) { printk(badinfo, name, routine); - return 1; + return true; } if (info->magic != MGSLPC_MAGIC) { printk(badmagic, name, routine); - return 1; + return true; } #else if (!info) - return 1; + return true; #endif - return 0; + return false; } @@ -752,16 +752,16 @@ static inline int mgslpc_paranoia_check(MGSLPC_INFO *info, #define CMD_TXEOM BIT1 // transmit end message #define CMD_TXRESET BIT0 // transmit reset -static BOOLEAN wait_command_complete(MGSLPC_INFO *info, unsigned char channel) +static bool wait_command_complete(MGSLPC_INFO *info, unsigned char channel) { int i = 0; /* wait for command completion */ while (read_reg(info, (unsigned char)(channel+STAR)) & BIT2) { udelay(1); if (i++ == 1000) - return FALSE; + return false; } - return TRUE; + return true; } static void issue_command(MGSLPC_INFO *info, unsigned char channel, unsigned char cmd) @@ -825,8 +825,8 @@ static int bh_action(MGSLPC_INFO *info) if (!rc) { /* Mark BH routine as complete */ - info->bh_running = 0; - info->bh_requested = 0; + info->bh_running = false; + info->bh_requested = false; } spin_unlock_irqrestore(&info->lock,flags); @@ -846,7 +846,7 @@ static void bh_handler(struct work_struct *work) printk( "%s(%d):bh_handler(%s) entry\n", __FILE__,__LINE__,info->device_name); - info->bh_running = 1; + info->bh_running = true; while((action = bh_action(info)) != 0) { @@ -913,7 +913,7 @@ static void rx_ready_hdlc(MGSLPC_INFO *info, int eom) /* no more free buffers */ issue_command(info, CHA, CMD_RXRESET); info->pending_bh |= BH_RECEIVE; - info->rx_overflow = 1; + info->rx_overflow = true; info->icount.buf_overrun++; return; } @@ -1032,8 +1032,8 @@ static void tx_done(MGSLPC_INFO *info) if (!info->tx_active) return; - info->tx_active = 0; - info->tx_aborting = 0; + info->tx_active = false; + info->tx_aborting = false; if (info->params.mode == MGSL_MODE_ASYNC) return; @@ -1047,7 +1047,7 @@ static void tx_done(MGSLPC_INFO *info) info->serial_signals &= ~SerialSignal_RTS; set_signals(info); } - info->drop_rts_on_tx_done = 0; + info->drop_rts_on_tx_done = false; } #if SYNCLINK_GENERIC_HDLC @@ -1081,7 +1081,7 @@ static void tx_ready(MGSLPC_INFO *info) return; } if (!info->tx_count) - info->tx_active = 0; + info->tx_active = false; } if (!info->tx_count) @@ -1261,7 +1261,7 @@ static irqreturn_t mgslpc_isr(int dummy, void *dev_id) { isr = read_reg16(info, CHA + ISR); if (isr & IRQ_TIMER) { - info->irq_occurred = 1; + info->irq_occurred = true; irq_disable(info, CHA, IRQ_TIMER); } @@ -1318,7 +1318,7 @@ static irqreturn_t mgslpc_isr(int dummy, void *dev_id) printk("%s(%d):%s queueing bh task.\n", __FILE__,__LINE__,info->device_name); schedule_work(&info->task); - info->bh_requested = 1; + info->bh_requested = true; } spin_unlock(&info->lock); @@ -1990,7 +1990,7 @@ static int tx_abort(MGSLPC_INFO * info) * This results in underrun and abort transmission. */ info->tx_count = info->tx_put = info->tx_get = 0; - info->tx_aborting = TRUE; + info->tx_aborting = true; } spin_unlock_irqrestore(&info->lock,flags); return 0; @@ -2589,7 +2589,8 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, { DECLARE_WAITQUEUE(wait, current); int retval; - int do_clocal = 0, extra_count = 0; + bool do_clocal = false; + bool extra_count = false; unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) @@ -2604,7 +2605,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, } if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; + do_clocal = true; /* Wait for carrier detect and the line to become * free (i.e., not in use by the callout). While we are in @@ -2622,7 +2623,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, spin_lock_irqsave(&info->lock, flags); if (!tty_hung_up_p(filp)) { - extra_count = 1; + extra_count = true; info->count--; } spin_unlock_irqrestore(&info->lock, flags); @@ -3493,8 +3494,8 @@ static void rx_stop(MGSLPC_INFO *info) /* MODE:03 RAC Receiver Active, 0=inactive */ clear_reg_bits(info, CHA + MODE, BIT3); - info->rx_enabled = 0; - info->rx_overflow = 0; + info->rx_enabled = false; + info->rx_overflow = false; } static void rx_start(MGSLPC_INFO *info) @@ -3504,13 +3505,13 @@ static void rx_start(MGSLPC_INFO *info) __FILE__,__LINE__, info->device_name ); rx_reset_buffers(info); - info->rx_enabled = 0; - info->rx_overflow = 0; + info->rx_enabled = false; + info->rx_overflow = false; /* MODE:03 RAC Receiver Active, 1=active */ set_reg_bits(info, CHA + MODE, BIT3); - info->rx_enabled = 1; + info->rx_enabled = true; } static void tx_start(MGSLPC_INFO *info) @@ -3523,24 +3524,24 @@ static void tx_start(MGSLPC_INFO *info) /* If auto RTS enabled and RTS is inactive, then assert */ /* RTS and set a flag indicating that the driver should */ /* negate RTS when the transmission completes. */ - info->drop_rts_on_tx_done = 0; + info->drop_rts_on_tx_done = false; if (info->params.flags & HDLC_FLAG_AUTO_RTS) { get_signals(info); if (!(info->serial_signals & SerialSignal_RTS)) { info->serial_signals |= SerialSignal_RTS; set_signals(info); - info->drop_rts_on_tx_done = 1; + info->drop_rts_on_tx_done = true; } } if (info->params.mode == MGSL_MODE_ASYNC) { if (!info->tx_active) { - info->tx_active = 1; + info->tx_active = true; tx_ready(info); } } else { - info->tx_active = 1; + info->tx_active = true; tx_ready(info); mod_timer(&info->tx_timer, jiffies + msecs_to_jiffies(5000)); @@ -3548,7 +3549,7 @@ static void tx_start(MGSLPC_INFO *info) } if (!info->tx_enabled) - info->tx_enabled = 1; + info->tx_enabled = true; } static void tx_stop(MGSLPC_INFO *info) @@ -3559,8 +3560,8 @@ static void tx_stop(MGSLPC_INFO *info) del_timer(&info->tx_timer); - info->tx_enabled = 0; - info->tx_active = 0; + info->tx_enabled = false; + info->tx_active = false; } /* Reset the adapter to a known state and prepare it for further use. @@ -3860,19 +3861,19 @@ static void rx_reset_buffers(MGSLPC_INFO *info) /* Attempt to return a received HDLC frame * Only frames received without errors are returned. * - * Returns 1 if frame returned, otherwise 0 + * Returns true if frame returned, otherwise false */ -static int rx_get_frame(MGSLPC_INFO *info) +static bool rx_get_frame(MGSLPC_INFO *info) { unsigned short status; RXBUF *buf; unsigned int framesize = 0; unsigned long flags; struct tty_struct *tty = info->tty; - int return_frame = 0; + bool return_frame = false; if (info->rx_frame_count == 0) - return 0; + return false; buf = (RXBUF*)(info->rx_buf + (info->rx_get * info->rx_buf_size)); @@ -3891,7 +3892,7 @@ static int rx_get_frame(MGSLPC_INFO *info) else if (!(status & BIT5)) { info->icount.rxcrc++; if (info->params.crc_type & HDLC_CRC_RETURN_EX) - return_frame = 1; + return_frame = true; } framesize = 0; #if SYNCLINK_GENERIC_HDLC @@ -3902,7 +3903,7 @@ static int rx_get_frame(MGSLPC_INFO *info) } #endif } else - return_frame = 1; + return_frame = true; if (return_frame) framesize = buf->count; @@ -3945,16 +3946,16 @@ static int rx_get_frame(MGSLPC_INFO *info) info->rx_get = 0; spin_unlock_irqrestore(&info->lock,flags); - return 1; + return true; } -static BOOLEAN register_test(MGSLPC_INFO *info) +static bool register_test(MGSLPC_INFO *info) { static unsigned char patterns[] = { 0x00, 0xff, 0xaa, 0x55, 0x69, 0x96, 0x0f }; static unsigned int count = ARRAY_SIZE(patterns); unsigned int i; - BOOLEAN rc = TRUE; + bool rc = true; unsigned long flags; spin_lock_irqsave(&info->lock,flags); @@ -3965,7 +3966,7 @@ static BOOLEAN register_test(MGSLPC_INFO *info) write_reg(info, XAD2, patterns[(i + 1) % count]); if ((read_reg(info, XAD1) != patterns[i]) || (read_reg(info, XAD2) != patterns[(i + 1) % count])) { - rc = FALSE; + rc = false; break; } } @@ -3974,7 +3975,7 @@ static BOOLEAN register_test(MGSLPC_INFO *info) return rc; } -static BOOLEAN irq_test(MGSLPC_INFO *info) +static bool irq_test(MGSLPC_INFO *info) { unsigned long end_time; unsigned long flags; @@ -3982,10 +3983,10 @@ static BOOLEAN irq_test(MGSLPC_INFO *info) spin_lock_irqsave(&info->lock,flags); reset_device(info); - info->testing_irq = TRUE; + info->testing_irq = true; hdlc_mode(info); - info->irq_occurred = FALSE; + info->irq_occurred = false; /* init hdlc mode */ @@ -4000,13 +4001,13 @@ static BOOLEAN irq_test(MGSLPC_INFO *info) msleep_interruptible(10); } - info->testing_irq = FALSE; + info->testing_irq = false; spin_lock_irqsave(&info->lock,flags); reset_device(info); spin_unlock_irqrestore(&info->lock,flags); - return info->irq_occurred ? TRUE : FALSE; + return info->irq_occurred; } static int adapter_test(MGSLPC_INFO *info) @@ -4079,7 +4080,7 @@ static void tx_timeout(unsigned long context) info->icount.txtimeout++; } spin_lock_irqsave(&info->lock,flags); - info->tx_active = 0; + info->tx_active = false; info->tx_count = info->tx_put = info->tx_get = 0; spin_unlock_irqrestore(&info->lock,flags); diff --git a/drivers/char/random.c b/drivers/char/random.c index f43c89f7c44..0cf98bd4f2d 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -272,7 +272,7 @@ static int random_write_wakeup_thresh = 128; static int trickle_thresh __read_mostly = INPUT_POOL_WORDS * 28; -static DEFINE_PER_CPU(int, trickle_count) = 0; +static DEFINE_PER_CPU(int, trickle_count); /* * A pool of size .poolwords is stirred with a primitive polynomial @@ -370,17 +370,19 @@ static struct poolinfo { */ static DECLARE_WAIT_QUEUE_HEAD(random_read_wait); static DECLARE_WAIT_QUEUE_HEAD(random_write_wait); +static struct fasync_struct *fasync; #if 0 -static int debug = 0; +static int debug; module_param(debug, bool, 0644); -#define DEBUG_ENT(fmt, arg...) do { if (debug) \ - printk(KERN_DEBUG "random %04d %04d %04d: " \ - fmt,\ - input_pool.entropy_count,\ - blocking_pool.entropy_count,\ - nonblocking_pool.entropy_count,\ - ## arg); } while (0) +#define DEBUG_ENT(fmt, arg...) do { \ + if (debug) \ + printk(KERN_DEBUG "random %04d %04d %04d: " \ + fmt,\ + input_pool.entropy_count,\ + blocking_pool.entropy_count,\ + nonblocking_pool.entropy_count,\ + ## arg); } while (0) #else #define DEBUG_ENT(fmt, arg...) do {} while (0) #endif @@ -394,7 +396,7 @@ module_param(debug, bool, 0644); struct entropy_store; struct entropy_store { - /* mostly-read data: */ + /* read-only data: */ struct poolinfo *poolinfo; __u32 *pool; const char *name; @@ -402,7 +404,7 @@ struct entropy_store { struct entropy_store *pull; /* read-write data: */ - spinlock_t lock ____cacheline_aligned_in_smp; + spinlock_t lock; unsigned add_ptr; int entropy_count; int input_rotate; @@ -438,25 +440,26 @@ static struct entropy_store nonblocking_pool = { }; /* - * This function adds a byte into the entropy "pool". It does not + * This function adds bytes into the entropy "pool". It does not * update the entropy estimate. The caller should call - * credit_entropy_store if this is appropriate. + * credit_entropy_bits if this is appropriate. * * The pool is stirred with a primitive polynomial of the appropriate * degree, and then twisted. We twist by three bits at a time because * it's cheap to do so and helps slightly in the expected case where * the entropy is concentrated in the low-order bits. */ -static void __add_entropy_words(struct entropy_store *r, const __u32 *in, - int nwords, __u32 out[16]) +static void mix_pool_bytes_extract(struct entropy_store *r, const void *in, + int nbytes, __u8 out[64]) { static __u32 const twist_table[8] = { 0x00000000, 0x3b6e20c8, 0x76dc4190, 0x4db26158, 0xedb88320, 0xd6d6a3e8, 0x9b64c2b0, 0xa00ae278 }; - unsigned long i, add_ptr, tap1, tap2, tap3, tap4, tap5; - int new_rotate, input_rotate; + unsigned long i, j, tap1, tap2, tap3, tap4, tap5; + int input_rotate; int wordmask = r->poolinfo->poolwords - 1; - __u32 w, next_w; + const char *bytes = in; + __u32 w; unsigned long flags; /* Taps are constant, so we can load them without holding r->lock. */ @@ -465,78 +468,76 @@ static void __add_entropy_words(struct entropy_store *r, const __u32 *in, tap3 = r->poolinfo->tap3; tap4 = r->poolinfo->tap4; tap5 = r->poolinfo->tap5; - next_w = *in++; spin_lock_irqsave(&r->lock, flags); - prefetch_range(r->pool, wordmask); input_rotate = r->input_rotate; - add_ptr = r->add_ptr; + i = r->add_ptr; - while (nwords--) { - w = rol32(next_w, input_rotate); - if (nwords > 0) - next_w = *in++; - i = add_ptr = (add_ptr - 1) & wordmask; - /* - * Normally, we add 7 bits of rotation to the pool. - * At the beginning of the pool, add an extra 7 bits - * rotation, so that successive passes spread the - * input bits across the pool evenly. - */ - new_rotate = input_rotate + 14; - if (i) - new_rotate = input_rotate + 7; - input_rotate = new_rotate & 31; + /* mix one byte at a time to simplify size handling and churn faster */ + while (nbytes--) { + w = rol32(*bytes++, input_rotate & 31); + i = (i - 1) & wordmask; /* XOR in the various taps */ + w ^= r->pool[i]; w ^= r->pool[(i + tap1) & wordmask]; w ^= r->pool[(i + tap2) & wordmask]; w ^= r->pool[(i + tap3) & wordmask]; w ^= r->pool[(i + tap4) & wordmask]; w ^= r->pool[(i + tap5) & wordmask]; - w ^= r->pool[i]; + + /* Mix the result back in with a twist */ r->pool[i] = (w >> 3) ^ twist_table[w & 7]; + + /* + * Normally, we add 7 bits of rotation to the pool. + * At the beginning of the pool, add an extra 7 bits + * rotation, so that successive passes spread the + * input bits across the pool evenly. + */ + input_rotate += i ? 7 : 14; } r->input_rotate = input_rotate; - r->add_ptr = add_ptr; + r->add_ptr = i; - if (out) { - for (i = 0; i < 16; i++) { - out[i] = r->pool[add_ptr]; - add_ptr = (add_ptr - 1) & wordmask; - } - } + if (out) + for (j = 0; j < 16; j++) + ((__u32 *)out)[j] = r->pool[(i - j) & wordmask]; spin_unlock_irqrestore(&r->lock, flags); } -static inline void add_entropy_words(struct entropy_store *r, const __u32 *in, - int nwords) +static void mix_pool_bytes(struct entropy_store *r, const void *in, int bytes) { - __add_entropy_words(r, in, nwords, NULL); + mix_pool_bytes_extract(r, in, bytes, NULL); } /* * Credit (or debit) the entropy store with n bits of entropy */ -static void credit_entropy_store(struct entropy_store *r, int nbits) +static void credit_entropy_bits(struct entropy_store *r, int nbits) { unsigned long flags; + if (!nbits) + return; + spin_lock_irqsave(&r->lock, flags); - if (r->entropy_count + nbits < 0) { - DEBUG_ENT("negative entropy/overflow (%d+%d)\n", - r->entropy_count, nbits); + DEBUG_ENT("added %d entropy credits to %s\n", nbits, r->name); + r->entropy_count += nbits; + if (r->entropy_count < 0) { + DEBUG_ENT("negative entropy/overflow\n"); r->entropy_count = 0; - } else if (r->entropy_count + nbits > r->poolinfo->POOLBITS) { + } else if (r->entropy_count > r->poolinfo->POOLBITS) r->entropy_count = r->poolinfo->POOLBITS; - } else { - r->entropy_count += nbits; - if (nbits) - DEBUG_ENT("added %d entropy credits to %s\n", - nbits, r->name); + + /* should we wake readers? */ + if (r == &input_pool && + r->entropy_count >= random_read_wakeup_thresh) { + wake_up_interruptible(&random_read_wait); + kill_fasync(&fasync, SIGIO, POLL_IN); } spin_unlock_irqrestore(&r->lock, flags); @@ -551,7 +552,7 @@ static void credit_entropy_store(struct entropy_store *r, int nbits) /* There is one of these per entropy source */ struct timer_rand_state { cycles_t last_time; - long last_delta,last_delta2; + long last_delta, last_delta2; unsigned dont_count_entropy:1; }; @@ -586,7 +587,7 @@ static void add_timer_randomness(struct timer_rand_state *state, unsigned num) sample.jiffies = jiffies; sample.cycles = get_cycles(); sample.num = num; - add_entropy_words(&input_pool, (u32 *)&sample, sizeof(sample)/4); + mix_pool_bytes(&input_pool, &sample, sizeof(sample)); /* * Calculate number of bits of randomness we probably added. @@ -620,13 +621,9 @@ static void add_timer_randomness(struct timer_rand_state *state, unsigned num) * Round down by 1 bit on general principles, * and limit entropy entimate to 12 bits. */ - credit_entropy_store(&input_pool, - min_t(int, fls(delta>>1), 11)); + credit_entropy_bits(&input_pool, + min_t(int, fls(delta>>1), 11)); } - - if(input_pool.entropy_count >= random_read_wakeup_thresh) - wake_up_interruptible(&random_read_wait); - out: preempt_enable(); } @@ -677,7 +674,7 @@ void add_disk_randomness(struct gendisk *disk) * *********************************************************************/ -static ssize_t extract_entropy(struct entropy_store *r, void * buf, +static ssize_t extract_entropy(struct entropy_store *r, void *buf, size_t nbytes, int min, int rsvd); /* @@ -704,10 +701,10 @@ static void xfer_secondary_pool(struct entropy_store *r, size_t nbytes) "(%d of %d requested)\n", r->name, bytes * 8, nbytes * 8, r->entropy_count); - bytes=extract_entropy(r->pull, tmp, bytes, - random_read_wakeup_thresh / 8, rsvd); - add_entropy_words(r, tmp, (bytes + 3) / 4); - credit_entropy_store(r, bytes*8); + bytes = extract_entropy(r->pull, tmp, bytes, + random_read_wakeup_thresh / 8, rsvd); + mix_pool_bytes(r, tmp, bytes); + credit_entropy_bits(r, bytes*8); } } @@ -744,13 +741,15 @@ static size_t account(struct entropy_store *r, size_t nbytes, int min, if (r->limit && nbytes + reserved >= r->entropy_count / 8) nbytes = r->entropy_count/8 - reserved; - if(r->entropy_count / 8 >= nbytes + reserved) + if (r->entropy_count / 8 >= nbytes + reserved) r->entropy_count -= nbytes*8; else r->entropy_count = reserved; - if (r->entropy_count < random_write_wakeup_thresh) + if (r->entropy_count < random_write_wakeup_thresh) { wake_up_interruptible(&random_write_wait); + kill_fasync(&fasync, SIGIO, POLL_OUT); + } } DEBUG_ENT("debiting %d entropy credits from %s%s\n", @@ -764,45 +763,46 @@ static size_t account(struct entropy_store *r, size_t nbytes, int min, static void extract_buf(struct entropy_store *r, __u8 *out) { int i; - __u32 data[16], buf[5 + SHA_WORKSPACE_WORDS]; + __u32 hash[5], workspace[SHA_WORKSPACE_WORDS]; + __u8 extract[64]; + + /* Generate a hash across the pool, 16 words (512 bits) at a time */ + sha_init(hash); + for (i = 0; i < r->poolinfo->poolwords; i += 16) + sha_transform(hash, (__u8 *)(r->pool + i), workspace); - sha_init(buf); /* - * As we hash the pool, we mix intermediate values of - * the hash back into the pool. This eliminates - * backtracking attacks (where the attacker knows - * the state of the pool plus the current outputs, and - * attempts to find previous ouputs), unless the hash - * function can be inverted. + * We mix the hash back into the pool to prevent backtracking + * attacks (where the attacker knows the state of the pool + * plus the current outputs, and attempts to find previous + * ouputs), unless the hash function can be inverted. By + * mixing at least a SHA1 worth of hash data back, we make + * brute-forcing the feedback as hard as brute-forcing the + * hash. */ - for (i = 0; i < r->poolinfo->poolwords; i += 16) { - /* hash blocks of 16 words = 512 bits */ - sha_transform(buf, (__u8 *)(r->pool + i), buf + 5); - /* feed back portion of the resulting hash */ - add_entropy_words(r, &buf[i % 5], 1); - } + mix_pool_bytes_extract(r, hash, sizeof(hash), extract); /* - * To avoid duplicates, we atomically extract a - * portion of the pool while mixing, and hash one - * final time. + * To avoid duplicates, we atomically extract a portion of the + * pool while mixing, and hash one final time. */ - __add_entropy_words(r, &buf[i % 5], 1, data); - sha_transform(buf, (__u8 *)data, buf + 5); + sha_transform(hash, extract, workspace); + memset(extract, 0, sizeof(extract)); + memset(workspace, 0, sizeof(workspace)); /* - * In case the hash function has some recognizable - * output pattern, we fold it in half. + * In case the hash function has some recognizable output + * pattern, we fold it in half. Thus, we always feed back + * twice as much data as we output. */ - - buf[0] ^= buf[3]; - buf[1] ^= buf[4]; - buf[2] ^= rol32(buf[2], 16); - memcpy(out, buf, EXTRACT_SIZE); - memset(buf, 0, sizeof(buf)); + hash[0] ^= hash[3]; + hash[1] ^= hash[4]; + hash[2] ^= rol32(hash[2], 16); + memcpy(out, hash, EXTRACT_SIZE); + memset(hash, 0, sizeof(hash)); } -static ssize_t extract_entropy(struct entropy_store *r, void * buf, +static ssize_t extract_entropy(struct entropy_store *r, void *buf, size_t nbytes, int min, int reserved) { ssize_t ret = 0, i; @@ -872,7 +872,6 @@ void get_random_bytes(void *buf, int nbytes) { extract_entropy(&nonblocking_pool, buf, nbytes, 0, 0); } - EXPORT_SYMBOL(get_random_bytes); /* @@ -894,12 +893,11 @@ static void init_std_data(struct entropy_store *r) spin_unlock_irqrestore(&r->lock, flags); now = ktime_get_real(); - add_entropy_words(r, (__u32 *)&now, sizeof(now)/4); - add_entropy_words(r, (__u32 *)utsname(), - sizeof(*(utsname()))/4); + mix_pool_bytes(r, &now, sizeof(now)); + mix_pool_bytes(r, utsname(), sizeof(*(utsname()))); } -static int __init rand_initialize(void) +static int rand_initialize(void) { init_std_data(&input_pool); init_std_data(&blocking_pool); @@ -940,7 +938,7 @@ void rand_initialize_disk(struct gendisk *disk) #endif static ssize_t -random_read(struct file * file, char __user * buf, size_t nbytes, loff_t *ppos) +random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) { ssize_t n, retval = 0, count = 0; @@ -1002,8 +1000,7 @@ random_read(struct file * file, char __user * buf, size_t nbytes, loff_t *ppos) } static ssize_t -urandom_read(struct file * file, char __user * buf, - size_t nbytes, loff_t *ppos) +urandom_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) { return extract_entropy_user(&nonblocking_pool, buf, nbytes); } @@ -1038,16 +1035,15 @@ write_pool(struct entropy_store *r, const char __user *buffer, size_t count) count -= bytes; p += bytes; - add_entropy_words(r, buf, (bytes + 3) / 4); + mix_pool_bytes(r, buf, bytes); cond_resched(); } return 0; } -static ssize_t -random_write(struct file * file, const char __user * buffer, - size_t count, loff_t *ppos) +static ssize_t random_write(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos) { size_t ret; struct inode *inode = file->f_path.dentry->d_inode; @@ -1064,9 +1060,7 @@ random_write(struct file * file, const char __user * buffer, return (ssize_t)count; } -static int -random_ioctl(struct inode * inode, struct file * file, - unsigned int cmd, unsigned long arg) +static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg) { int size, ent_count; int __user *p = (int __user *)arg; @@ -1074,8 +1068,8 @@ random_ioctl(struct inode * inode, struct file * file, switch (cmd) { case RNDGETENTCNT: - ent_count = input_pool.entropy_count; - if (put_user(ent_count, p)) + /* inherently racy, no point locking */ + if (put_user(input_pool.entropy_count, p)) return -EFAULT; return 0; case RNDADDTOENTCNT: @@ -1083,13 +1077,7 @@ random_ioctl(struct inode * inode, struct file * file, return -EPERM; if (get_user(ent_count, p)) return -EFAULT; - credit_entropy_store(&input_pool, ent_count); - /* - * Wake up waiting processes if we have enough - * entropy. - */ - if (input_pool.entropy_count >= random_read_wakeup_thresh) - wake_up_interruptible(&random_read_wait); + credit_entropy_bits(&input_pool, ent_count); return 0; case RNDADDENTROPY: if (!capable(CAP_SYS_ADMIN)) @@ -1104,39 +1092,45 @@ random_ioctl(struct inode * inode, struct file * file, size); if (retval < 0) return retval; - credit_entropy_store(&input_pool, ent_count); - /* - * Wake up waiting processes if we have enough - * entropy. - */ - if (input_pool.entropy_count >= random_read_wakeup_thresh) - wake_up_interruptible(&random_read_wait); + credit_entropy_bits(&input_pool, ent_count); return 0; case RNDZAPENTCNT: case RNDCLEARPOOL: /* Clear the entropy pool counters. */ if (!capable(CAP_SYS_ADMIN)) return -EPERM; - init_std_data(&input_pool); - init_std_data(&blocking_pool); - init_std_data(&nonblocking_pool); + rand_initialize(); return 0; default: return -EINVAL; } } +static int random_fasync(int fd, struct file *filp, int on) +{ + return fasync_helper(fd, filp, on, &fasync); +} + +static int random_release(struct inode *inode, struct file *filp) +{ + return fasync_helper(-1, filp, 0, &fasync); +} + const struct file_operations random_fops = { .read = random_read, .write = random_write, .poll = random_poll, - .ioctl = random_ioctl, + .unlocked_ioctl = random_ioctl, + .fasync = random_fasync, + .release = random_release, }; const struct file_operations urandom_fops = { .read = urandom_read, .write = random_write, - .ioctl = random_ioctl, + .unlocked_ioctl = random_ioctl, + .fasync = random_fasync, + .release = random_release, }; /*************************************************************** @@ -1157,7 +1151,6 @@ void generate_random_uuid(unsigned char uuid_out[16]) /* Set the UUID variant to DCE */ uuid_out[8] = (uuid_out[8] & 0x3F) | 0x80; } - EXPORT_SYMBOL(generate_random_uuid); /******************************************************************** @@ -1339,7 +1332,7 @@ ctl_table random_table[] = { #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) -static __u32 twothirdsMD4Transform (__u32 const buf[4], __u32 const in[12]) +static __u32 twothirdsMD4Transform(__u32 const buf[4], __u32 const in[12]) { __u32 a = buf[0], b = buf[1], c = buf[2], d = buf[3]; @@ -1487,8 +1480,8 @@ __u32 secure_tcpv6_sequence_number(__be32 *saddr, __be32 *daddr, */ memcpy(hash, saddr, 16); - hash[4]=((__force u16)sport << 16) + (__force u16)dport; - memcpy(&hash[5],keyptr->secret,sizeof(__u32) * 7); + hash[4] = ((__force u16)sport << 16) + (__force u16)dport; + memcpy(&hash[5], keyptr->secret, sizeof(__u32) * 7); seq = twothirdsMD4Transform((const __u32 *)daddr, hash) & HASH_MASK; seq += keyptr->count; @@ -1538,10 +1531,10 @@ __u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr, * Note that the words are placed into the starting vector, which is * then mixed with a partial MD4 over random data. */ - hash[0]=(__force u32)saddr; - hash[1]=(__force u32)daddr; - hash[2]=((__force u16)sport << 16) + (__force u16)dport; - hash[3]=keyptr->secret[11]; + hash[0] = (__force u32)saddr; + hash[1] = (__force u32)daddr; + hash[2] = ((__force u16)sport << 16) + (__force u16)dport; + hash[3] = keyptr->secret[11]; seq = half_md4_transform(hash, keyptr->secret) & HASH_MASK; seq += keyptr->count; @@ -1556,10 +1549,7 @@ __u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr, * Choosing a clock of 64 ns period is OK. (period of 274 s) */ seq += ktime_to_ns(ktime_get_real()) >> 6; -#if 0 - printk("init_seq(%lx, %lx, %d, %d) = %d\n", - saddr, daddr, sport, dport, seq); -#endif + return seq; } @@ -1582,14 +1572,15 @@ u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport) } #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) -u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr, __be16 dport) +u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr, + __be16 dport) { struct keydata *keyptr = get_keyptr(); u32 hash[12]; memcpy(hash, saddr, 16); hash[4] = (__force u32)dport; - memcpy(&hash[5],keyptr->secret,sizeof(__u32) * 7); + memcpy(&hash[5], keyptr->secret, sizeof(__u32) * 7); return twothirdsMD4Transform((const __u32 *)daddr, hash); } @@ -1617,13 +1608,9 @@ u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr, seq += ktime_to_ns(ktime_get_real()); seq &= (1ull << 48) - 1; -#if 0 - printk("dccp init_seq(%lx, %lx, %d, %d) = %d\n", - saddr, daddr, sport, dport, seq); -#endif + return seq; } - EXPORT_SYMBOL(secure_dccp_sequence_number); #endif diff --git a/drivers/char/rio/rioroute.c b/drivers/char/rio/rioroute.c index 85091ff74d9..7a9df7dcf9a 100644 --- a/drivers/char/rio/rioroute.c +++ b/drivers/char/rio/rioroute.c @@ -526,7 +526,7 @@ void RIOFixPhbs(struct rio_info *p, struct Host *HostP, unsigned int unit) ** If RTA is not powered on, the tx packets will be ** unset, so go no further. */ - if (PortP->TxStart == 0) { + if (!PortP->TxStart) { rio_dprintk(RIO_DEBUG_ROUTE, "Tx pkts not set up yet\n"); rio_spin_unlock_irqrestore(&PortP->portSem, flags); break; diff --git a/drivers/char/rocket_int.h b/drivers/char/rocket_int.h index b01d38125a8..143cc432fdb 100644 --- a/drivers/char/rocket_int.h +++ b/drivers/char/rocket_int.h @@ -55,7 +55,7 @@ static inline void sOutW(unsigned short port, unsigned short value) static inline void out32(unsigned short port, Byte_t *p) { - u32 value = le32_to_cpu(get_unaligned((__le32 *)p)); + u32 value = get_unaligned_le32(p); #ifdef ROCKET_DEBUG_IO printk(KERN_DEBUG "out32(%x, %lx)...\n", port, value); #endif diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index 5c3142b6f1f..5f80a9dff57 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -88,6 +88,7 @@ #ifdef CONFIG_SPARC32 #include <linux/pci.h> +#include <linux/jiffies.h> #include <asm/ebus.h> static unsigned long rtc_port; @@ -1068,10 +1069,8 @@ no_irq: } #ifdef CONFIG_PROC_FS - ent = create_proc_entry("driver/rtc", 0, NULL); - if (ent) - ent->proc_fops = &rtc_proc_fops; - else + ent = proc_create("driver/rtc", 0, NULL, &rtc_proc_fops); + if (!ent) printk(KERN_WARNING "rtc: Failed to register with procfs.\n"); #endif @@ -1316,7 +1315,8 @@ void rtc_get_rtc_time(struct rtc_time *rtc_tm) * Once the read clears, read the RTC time (again via ioctl). Easy. */ - while (rtc_is_updating() != 0 && jiffies - uip_watchdog < 2*HZ/100) + while (rtc_is_updating() != 0 && + time_before(jiffies, uip_watchdog + 2*HZ/100)) cpu_relax(); /* diff --git a/drivers/char/snsc_event.c b/drivers/char/snsc_event.c index 1b75b0b7d54..31a7765eaf7 100644 --- a/drivers/char/snsc_event.c +++ b/drivers/char/snsc_event.c @@ -63,16 +63,13 @@ static int scdrv_parse_event(char *event, int *src, int *code, int *esp_code, char *desc) { char *desc_end; - __be32 from_buf; /* record event source address */ - from_buf = get_unaligned((__be32 *)event); - *src = be32_to_cpup(&from_buf); + *src = get_unaligned_be32(event); event += 4; /* move on to event code */ /* record the system controller's event code */ - from_buf = get_unaligned((__be32 *)event); - *code = be32_to_cpup(&from_buf); + *code = get_unaligned_be32(event); event += 4; /* move on to event arguments */ /* how many arguments are in the packet? */ @@ -86,8 +83,7 @@ scdrv_parse_event(char *event, int *src, int *code, int *esp_code, char *desc) /* not an integer argument, so give up */ return -1; } - from_buf = get_unaligned((__be32 *)event); - *esp_code = be32_to_cpup(&from_buf); + *esp_code = get_unaligned_be32(event); event += 4; /* parse out the event description */ diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c index a3237d48a58..fadab1d9510 100644 --- a/drivers/char/synclink.c +++ b/drivers/char/synclink.c @@ -218,9 +218,9 @@ struct mgsl_struct { u32 pending_bh; - int bh_running; /* Protection from multiple */ + bool bh_running; /* Protection from multiple */ int isr_overflow; - int bh_requested; + bool bh_requested; int dcd_chkcount; /* check counts to prevent */ int cts_chkcount; /* too many IRQs if a signal */ @@ -250,12 +250,12 @@ struct mgsl_struct { int tx_holding_count; /* number of tx holding buffers waiting */ struct tx_holding_buffer tx_holding_buffers[MAX_TX_HOLDING_BUFFERS]; - int rx_enabled; - int rx_overflow; - int rx_rcc_underrun; + bool rx_enabled; + bool rx_overflow; + bool rx_rcc_underrun; - int tx_enabled; - int tx_active; + bool tx_enabled; + bool tx_active; u32 idle_mode; u16 cmr_value; @@ -269,14 +269,14 @@ struct mgsl_struct { unsigned int io_base; /* base I/O address of adapter */ unsigned int io_addr_size; /* size of the I/O address range */ - int io_addr_requested; /* nonzero if I/O address requested */ + bool io_addr_requested; /* true if I/O address requested */ unsigned int irq_level; /* interrupt level */ unsigned long irq_flags; - int irq_requested; /* nonzero if IRQ requested */ + bool irq_requested; /* true if IRQ requested */ unsigned int dma_level; /* DMA channel */ - int dma_requested; /* nonzero if dma channel requested */ + bool dma_requested; /* true if dma channel requested */ u16 mbre_bit; u16 loopback_bits; @@ -286,27 +286,27 @@ struct mgsl_struct { unsigned char serial_signals; /* current serial signal states */ - int irq_occurred; /* for diagnostics use */ + bool irq_occurred; /* for diagnostics use */ unsigned int init_error; /* Initialization startup error (DIAGS) */ int fDiagnosticsmode; /* Driver in Diagnostic mode? (DIAGS) */ u32 last_mem_alloc; unsigned char* memory_base; /* shared memory address (PCI only) */ u32 phys_memory_base; - int shared_mem_requested; + bool shared_mem_requested; unsigned char* lcr_base; /* local config registers (PCI only) */ u32 phys_lcr_base; u32 lcr_offset; - int lcr_mem_requested; + bool lcr_mem_requested; u32 misc_ctrl_value; char flag_buf[MAX_ASYNC_BUFFER_SIZE]; char char_buf[MAX_ASYNC_BUFFER_SIZE]; - BOOLEAN drop_rts_on_tx_done; + bool drop_rts_on_tx_done; - BOOLEAN loopmode_insert_requested; - BOOLEAN loopmode_send_done_requested; + bool loopmode_insert_requested; + bool loopmode_send_done_requested; struct _input_signal_events input_signal_events; @@ -752,10 +752,10 @@ static void mgsl_trace_block(struct mgsl_struct *info,const char* data, int coun /* * Adapter diagnostic routines */ -static BOOLEAN mgsl_register_test( struct mgsl_struct *info ); -static BOOLEAN mgsl_irq_test( struct mgsl_struct *info ); -static BOOLEAN mgsl_dma_test( struct mgsl_struct *info ); -static BOOLEAN mgsl_memory_test( struct mgsl_struct *info ); +static bool mgsl_register_test( struct mgsl_struct *info ); +static bool mgsl_irq_test( struct mgsl_struct *info ); +static bool mgsl_dma_test( struct mgsl_struct *info ); +static bool mgsl_memory_test( struct mgsl_struct *info ); static int mgsl_adapter_test( struct mgsl_struct *info ); /* @@ -770,8 +770,8 @@ static struct mgsl_struct* mgsl_allocate_device(void); * DMA buffer manupulation functions. */ static void mgsl_free_rx_frame_buffers( struct mgsl_struct *info, unsigned int StartIndex, unsigned int EndIndex ); -static int mgsl_get_rx_frame( struct mgsl_struct *info ); -static int mgsl_get_raw_rx_frame( struct mgsl_struct *info ); +static bool mgsl_get_rx_frame( struct mgsl_struct *info ); +static bool mgsl_get_raw_rx_frame( struct mgsl_struct *info ); static void mgsl_reset_rx_dma_buffers( struct mgsl_struct *info ); static void mgsl_reset_tx_dma_buffers( struct mgsl_struct *info ); static int num_free_tx_dma_buffers(struct mgsl_struct *info); @@ -791,7 +791,7 @@ static int mgsl_alloc_intermediate_rxbuffer_memory(struct mgsl_struct *info); static void mgsl_free_intermediate_rxbuffer_memory(struct mgsl_struct *info); static int mgsl_alloc_intermediate_txbuffer_memory(struct mgsl_struct *info); static void mgsl_free_intermediate_txbuffer_memory(struct mgsl_struct *info); -static int load_next_tx_holding_buffer(struct mgsl_struct *info); +static bool load_next_tx_holding_buffer(struct mgsl_struct *info); static int save_tx_buffer_request(struct mgsl_struct *info,const char *Buffer, unsigned int BufferSize); /* @@ -847,7 +847,7 @@ static int mgsl_wait_event(struct mgsl_struct * info, int __user *mask); static int mgsl_loopmode_send_done( struct mgsl_struct * info ); /* set non-zero on successful registration with PCI subsystem */ -static int pci_registered; +static bool pci_registered; /* * Global linked list of SyncLink devices @@ -1054,8 +1054,8 @@ static int mgsl_bh_action(struct mgsl_struct *info) if (!rc) { /* Mark BH routine as complete */ - info->bh_running = 0; - info->bh_requested = 0; + info->bh_running = false; + info->bh_requested = false; } spin_unlock_irqrestore(&info->irq_spinlock,flags); @@ -1079,7 +1079,7 @@ static void mgsl_bh_handler(struct work_struct *work) printk( "%s(%d):mgsl_bh_handler(%s) entry\n", __FILE__,__LINE__,info->device_name); - info->bh_running = 1; + info->bh_running = true; while((action = mgsl_bh_action(info)) != 0) { @@ -1113,7 +1113,7 @@ static void mgsl_bh_handler(struct work_struct *work) static void mgsl_bh_receive(struct mgsl_struct *info) { - int (*get_rx_frame)(struct mgsl_struct *info) = + bool (*get_rx_frame)(struct mgsl_struct *info) = (info->params.mode == MGSL_MODE_HDLC ? mgsl_get_rx_frame : mgsl_get_raw_rx_frame); if ( debug_level >= DEBUG_LEVEL_BH ) @@ -1187,7 +1187,7 @@ static void mgsl_isr_receive_status( struct mgsl_struct *info ) usc_loopmode_active(info) ) { ++info->icount.rxabort; - info->loopmode_insert_requested = FALSE; + info->loopmode_insert_requested = false; /* clear CMR:13 to start echoing RxD to TxD */ info->cmr_value &= ~BIT13; @@ -1257,7 +1257,7 @@ static void mgsl_isr_transmit_status( struct mgsl_struct *info ) else info->icount.txunder++; - info->tx_active = 0; + info->tx_active = false; info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; del_timer(&info->tx_timer); @@ -1267,7 +1267,7 @@ static void mgsl_isr_transmit_status( struct mgsl_struct *info ) info->serial_signals &= ~SerialSignal_RTS; usc_set_serial_signals( info ); } - info->drop_rts_on_tx_done = 0; + info->drop_rts_on_tx_done = false; } #if SYNCLINK_GENERIC_HDLC @@ -1403,7 +1403,7 @@ static void mgsl_isr_io_pin( struct mgsl_struct *info ) usc_OutReg( info, SICR, (unsigned short)(usc_InReg(info,SICR) & ~(SICR_TXC_ACTIVE+SICR_TXC_INACTIVE)) ); usc_UnlatchIostatusBits( info, MISCSTATUS_TXC_LATCHED ); - info->irq_occurred = 1; + info->irq_occurred = true; } } /* end of mgsl_isr_io_pin() */ @@ -1431,7 +1431,7 @@ static void mgsl_isr_transmit_data( struct mgsl_struct *info ) if ( info->xmit_cnt ) usc_load_txfifo( info ); else - info->tx_active = 0; + info->tx_active = false; if (info->xmit_cnt < WAKEUP_CHARS) info->pending_bh |= BH_TRANSMIT; @@ -1568,7 +1568,7 @@ static void mgsl_isr_misc( struct mgsl_struct *info ) /* schedule BH handler to restart receiver */ info->pending_bh |= BH_RECEIVE; - info->rx_rcc_underrun = 1; + info->rx_rcc_underrun = true; } usc_ClearIrqPendingBits( info, MISC ); @@ -1626,7 +1626,7 @@ static void mgsl_isr_receive_dma( struct mgsl_struct *info ) info->pending_bh |= BH_RECEIVE; if ( status & BIT3 ) { - info->rx_overflow = 1; + info->rx_overflow = true; info->icount.buf_overrun++; } @@ -1745,7 +1745,7 @@ static irqreturn_t mgsl_interrupt(int dummy, void *dev_id) printk("%s(%d):%s queueing bh task.\n", __FILE__,__LINE__,info->device_name); schedule_work(&info->task); - info->bh_requested = 1; + info->bh_requested = true; } spin_unlock(&info->irq_spinlock); @@ -3303,7 +3303,8 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, { DECLARE_WAITQUEUE(wait, current); int retval; - int do_clocal = 0, extra_count = 0; + bool do_clocal = false; + bool extra_count = false; unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) @@ -3317,7 +3318,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, } if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; + do_clocal = true; /* Wait for carrier detect and the line to become * free (i.e., not in use by the callout). While we are in @@ -3335,7 +3336,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, spin_lock_irqsave(&info->irq_spinlock, flags); if (!tty_hung_up_p(filp)) { - extra_count = 1; + extra_count = true; info->count--; } spin_unlock_irqrestore(&info->irq_spinlock, flags); @@ -4043,13 +4044,13 @@ static void mgsl_free_intermediate_txbuffer_memory(struct mgsl_struct *info) * * info pointer to device instance data * - * Return Value: 1 if next buffered tx request loaded + * Return Value: true if next buffered tx request loaded * into adapter's tx dma buffer, - * 0 otherwise + * false otherwise */ -static int load_next_tx_holding_buffer(struct mgsl_struct *info) +static bool load_next_tx_holding_buffer(struct mgsl_struct *info) { - int ret = 0; + bool ret = false; if ( info->tx_holding_count ) { /* determine if we have enough tx dma buffers @@ -4073,7 +4074,7 @@ static int load_next_tx_holding_buffer(struct mgsl_struct *info) /* restart transmit timer */ mod_timer(&info->tx_timer, jiffies + msecs_to_jiffies(5000)); - ret = 1; + ret = true; } } @@ -4119,7 +4120,7 @@ static int mgsl_claim_resources(struct mgsl_struct *info) __FILE__,__LINE__,info->device_name, info->io_base); return -ENODEV; } - info->io_addr_requested = 1; + info->io_addr_requested = true; if ( request_irq(info->irq_level,mgsl_interrupt,info->irq_flags, info->device_name, info ) < 0 ) { @@ -4127,7 +4128,7 @@ static int mgsl_claim_resources(struct mgsl_struct *info) __FILE__,__LINE__,info->device_name, info->irq_level ); goto errout; } - info->irq_requested = 1; + info->irq_requested = true; if ( info->bus_type == MGSL_BUS_TYPE_PCI ) { if (request_mem_region(info->phys_memory_base,0x40000,"synclink") == NULL) { @@ -4135,13 +4136,13 @@ static int mgsl_claim_resources(struct mgsl_struct *info) __FILE__,__LINE__,info->device_name, info->phys_memory_base); goto errout; } - info->shared_mem_requested = 1; + info->shared_mem_requested = true; if (request_mem_region(info->phys_lcr_base + info->lcr_offset,128,"synclink") == NULL) { printk( "%s(%d):lcr mem addr conflict device %s Addr=%08X\n", __FILE__,__LINE__,info->device_name, info->phys_lcr_base + info->lcr_offset); goto errout; } - info->lcr_mem_requested = 1; + info->lcr_mem_requested = true; info->memory_base = ioremap(info->phys_memory_base,0x40000); if (!info->memory_base) { @@ -4172,7 +4173,7 @@ static int mgsl_claim_resources(struct mgsl_struct *info) mgsl_release_resources( info ); return -ENODEV; } - info->dma_requested = 1; + info->dma_requested = true; /* ISA adapter uses bus master DMA */ set_dma_mode(info->dma_level,DMA_MODE_CASCADE); @@ -4200,12 +4201,12 @@ static void mgsl_release_resources(struct mgsl_struct *info) if ( info->irq_requested ) { free_irq(info->irq_level, info); - info->irq_requested = 0; + info->irq_requested = false; } if ( info->dma_requested ) { disable_dma(info->dma_level); free_dma(info->dma_level); - info->dma_requested = 0; + info->dma_requested = false; } mgsl_free_dma_buffers(info); mgsl_free_intermediate_rxbuffer_memory(info); @@ -4213,15 +4214,15 @@ static void mgsl_release_resources(struct mgsl_struct *info) if ( info->io_addr_requested ) { release_region(info->io_base,info->io_addr_size); - info->io_addr_requested = 0; + info->io_addr_requested = false; } if ( info->shared_mem_requested ) { release_mem_region(info->phys_memory_base,0x40000); - info->shared_mem_requested = 0; + info->shared_mem_requested = false; } if ( info->lcr_mem_requested ) { release_mem_region(info->phys_lcr_base + info->lcr_offset,128); - info->lcr_mem_requested = 0; + info->lcr_mem_requested = false; } if (info->memory_base){ iounmap(info->memory_base); @@ -4486,7 +4487,7 @@ static int __init synclink_init(void) if ((rc = pci_register_driver(&synclink_pci_driver)) < 0) printk("%s:failed to register PCI driver, error=%d\n",__FILE__,rc); else - pci_registered = 1; + pci_registered = true; if ((rc = mgsl_init_tty()) < 0) goto error; @@ -4679,7 +4680,7 @@ static u16 usc_InReg( struct mgsl_struct *info, u16 RegAddr ) static void usc_set_sdlc_mode( struct mgsl_struct *info ) { u16 RegValue; - int PreSL1660; + bool PreSL1660; /* * determine if the IUSC on the adapter is pre-SL1660. If @@ -4692,11 +4693,7 @@ static void usc_set_sdlc_mode( struct mgsl_struct *info ) */ usc_OutReg(info,TMCR,0x1f); RegValue=usc_InReg(info,TMDR); - if ( RegValue == IUSC_PRE_SL1660 ) - PreSL1660 = 1; - else - PreSL1660 = 0; - + PreSL1660 = (RegValue == IUSC_PRE_SL1660); if ( info->params.flags & HDLC_FLAG_HDLC_LOOPMODE ) { @@ -5382,9 +5379,9 @@ static void usc_process_rxoverrun_sync( struct mgsl_struct *info ) int start_index; int end_index; int frame_start_index; - int start_of_frame_found = FALSE; - int end_of_frame_found = FALSE; - int reprogram_dma = FALSE; + bool start_of_frame_found = false; + bool end_of_frame_found = false; + bool reprogram_dma = false; DMABUFFERENTRY *buffer_list = info->rx_buffer_list; u32 phys_addr; @@ -5410,9 +5407,9 @@ static void usc_process_rxoverrun_sync( struct mgsl_struct *info ) if ( !start_of_frame_found ) { - start_of_frame_found = TRUE; + start_of_frame_found = true; frame_start_index = end_index; - end_of_frame_found = FALSE; + end_of_frame_found = false; } if ( buffer_list[end_index].status ) @@ -5423,8 +5420,8 @@ static void usc_process_rxoverrun_sync( struct mgsl_struct *info ) /* We want to leave the buffers for this frame intact. */ /* Move on to next possible frame. */ - start_of_frame_found = FALSE; - end_of_frame_found = TRUE; + start_of_frame_found = false; + end_of_frame_found = true; } /* advance to next buffer entry in linked list */ @@ -5439,8 +5436,8 @@ static void usc_process_rxoverrun_sync( struct mgsl_struct *info ) /* completely screwed, reset all receive buffers! */ mgsl_reset_rx_dma_buffers( info ); frame_start_index = 0; - start_of_frame_found = FALSE; - reprogram_dma = TRUE; + start_of_frame_found = false; + reprogram_dma = true; break; } } @@ -5466,7 +5463,7 @@ static void usc_process_rxoverrun_sync( struct mgsl_struct *info ) } while( start_index != end_index ); - reprogram_dma = TRUE; + reprogram_dma = true; } if ( reprogram_dma ) @@ -5536,9 +5533,9 @@ static void usc_stop_receiver( struct mgsl_struct *info ) usc_OutReg( info, CCSR, (u16)(usc_InReg(info,CCSR) | BIT13) ); usc_RTCmd( info, RTCmd_PurgeRxFifo ); - info->rx_enabled = 0; - info->rx_overflow = 0; - info->rx_rcc_underrun = 0; + info->rx_enabled = false; + info->rx_overflow = false; + info->rx_rcc_underrun = false; } /* end of stop_receiver() */ @@ -5601,7 +5598,7 @@ static void usc_start_receiver( struct mgsl_struct *info ) usc_OutReg( info, CCSR, 0x1020 ); - info->rx_enabled = 1; + info->rx_enabled = true; } /* end of usc_start_receiver() */ @@ -5628,14 +5625,14 @@ static void usc_start_transmitter( struct mgsl_struct *info ) /* RTS and set a flag indicating that the driver should */ /* negate RTS when the transmission completes. */ - info->drop_rts_on_tx_done = 0; + info->drop_rts_on_tx_done = false; if ( info->params.flags & HDLC_FLAG_AUTO_RTS ) { usc_get_serial_signals( info ); if ( !(info->serial_signals & SerialSignal_RTS) ) { info->serial_signals |= SerialSignal_RTS; usc_set_serial_signals( info ); - info->drop_rts_on_tx_done = 1; + info->drop_rts_on_tx_done = true; } } @@ -5699,11 +5696,11 @@ static void usc_start_transmitter( struct mgsl_struct *info ) mod_timer(&info->tx_timer, jiffies + msecs_to_jiffies(5000)); } - info->tx_active = 1; + info->tx_active = true; } if ( !info->tx_enabled ) { - info->tx_enabled = 1; + info->tx_enabled = true; if ( info->params.flags & HDLC_FLAG_AUTO_CTS ) usc_EnableTransmitter(info,ENABLE_AUTO_CTS); else @@ -5735,8 +5732,8 @@ static void usc_stop_transmitter( struct mgsl_struct *info ) usc_DmaCmd( info, DmaCmd_ResetTxChannel ); usc_RTCmd( info, RTCmd_PurgeTxFifo ); - info->tx_enabled = 0; - info->tx_active = 0; + info->tx_enabled = false; + info->tx_active = false; } /* end of usc_stop_transmitter() */ @@ -6520,7 +6517,7 @@ static void mgsl_reset_rx_dma_buffers( struct mgsl_struct *info ) */ static void mgsl_free_rx_frame_buffers( struct mgsl_struct *info, unsigned int StartIndex, unsigned int EndIndex ) { - int Done = 0; + bool Done = false; DMABUFFERENTRY *pBufEntry; unsigned int Index; @@ -6534,7 +6531,7 @@ static void mgsl_free_rx_frame_buffers( struct mgsl_struct *info, unsigned int S if ( Index == EndIndex ) { /* This is the last buffer of the frame! */ - Done = 1; + Done = true; } /* reset current buffer for reuse */ @@ -6559,18 +6556,18 @@ static void mgsl_free_rx_frame_buffers( struct mgsl_struct *info, unsigned int S * receive DMA buffers. Only frames received without errors are returned. * * Arguments: info pointer to device extension - * Return Value: 1 if frame returned, otherwise 0 + * Return Value: true if frame returned, otherwise false */ -static int mgsl_get_rx_frame(struct mgsl_struct *info) +static bool mgsl_get_rx_frame(struct mgsl_struct *info) { unsigned int StartIndex, EndIndex; /* index of 1st and last buffers of Rx frame */ unsigned short status; DMABUFFERENTRY *pBufEntry; unsigned int framesize = 0; - int ReturnCode = 0; + bool ReturnCode = false; unsigned long flags; struct tty_struct *tty = info->tty; - int return_frame = 0; + bool return_frame = false; /* * current_rx_buffer points to the 1st buffer of the next available @@ -6629,7 +6626,7 @@ static int mgsl_get_rx_frame(struct mgsl_struct *info) else { info->icount.rxcrc++; if ( info->params.crc_type & HDLC_CRC_RETURN_EX ) - return_frame = 1; + return_frame = true; } framesize = 0; #if SYNCLINK_GENERIC_HDLC @@ -6640,7 +6637,7 @@ static int mgsl_get_rx_frame(struct mgsl_struct *info) } #endif } else - return_frame = 1; + return_frame = true; if ( return_frame ) { /* receive frame has no errors, get frame size. @@ -6719,7 +6716,7 @@ static int mgsl_get_rx_frame(struct mgsl_struct *info) /* Free the buffers used by this frame. */ mgsl_free_rx_frame_buffers( info, StartIndex, EndIndex ); - ReturnCode = 1; + ReturnCode = true; Cleanup: @@ -6758,15 +6755,15 @@ Cleanup: * last Rx DMA buffer and return that last portion of the frame. * * Arguments: info pointer to device extension - * Return Value: 1 if frame returned, otherwise 0 + * Return Value: true if frame returned, otherwise false */ -static int mgsl_get_raw_rx_frame(struct mgsl_struct *info) +static bool mgsl_get_raw_rx_frame(struct mgsl_struct *info) { unsigned int CurrentIndex, NextIndex; unsigned short status; DMABUFFERENTRY *pBufEntry; unsigned int framesize = 0; - int ReturnCode = 0; + bool ReturnCode = false; unsigned long flags; struct tty_struct *tty = info->tty; @@ -6891,7 +6888,7 @@ static int mgsl_get_raw_rx_frame(struct mgsl_struct *info) /* Free the buffers used by this frame. */ mgsl_free_rx_frame_buffers( info, CurrentIndex, CurrentIndex ); - ReturnCode = 1; + ReturnCode = true; } @@ -7000,15 +6997,15 @@ static void mgsl_load_tx_dma_buffer(struct mgsl_struct *info, * Performs a register test of the 16C32. * * Arguments: info pointer to device instance data - * Return Value: TRUE if test passed, otherwise FALSE + * Return Value: true if test passed, otherwise false */ -static BOOLEAN mgsl_register_test( struct mgsl_struct *info ) +static bool mgsl_register_test( struct mgsl_struct *info ) { static unsigned short BitPatterns[] = { 0x0000, 0xffff, 0xaaaa, 0x5555, 0x1234, 0x6969, 0x9696, 0x0f0f }; static unsigned int Patterncount = ARRAY_SIZE(BitPatterns); unsigned int i; - BOOLEAN rc = TRUE; + bool rc = true; unsigned long flags; spin_lock_irqsave(&info->irq_spinlock,flags); @@ -7019,10 +7016,10 @@ static BOOLEAN mgsl_register_test( struct mgsl_struct *info ) if ( (usc_InReg( info, SICR ) != 0) || (usc_InReg( info, IVR ) != 0) || (usc_InDmaReg( info, DIVR ) != 0) ){ - rc = FALSE; + rc = false; } - if ( rc == TRUE ){ + if ( rc ){ /* Write bit patterns to various registers but do it out of */ /* sync, then read back and verify values. */ @@ -7040,7 +7037,7 @@ static BOOLEAN mgsl_register_test( struct mgsl_struct *info ) (usc_InReg( info, RCLR ) != BitPatterns[(i+3)%Patterncount]) || (usc_InReg( info, RSR ) != BitPatterns[(i+4)%Patterncount]) || (usc_InDmaReg( info, TBCR ) != BitPatterns[(i+5)%Patterncount]) ){ - rc = FALSE; + rc = false; break; } } @@ -7056,9 +7053,9 @@ static BOOLEAN mgsl_register_test( struct mgsl_struct *info ) /* mgsl_irq_test() Perform interrupt test of the 16C32. * * Arguments: info pointer to device instance data - * Return Value: TRUE if test passed, otherwise FALSE + * Return Value: true if test passed, otherwise false */ -static BOOLEAN mgsl_irq_test( struct mgsl_struct *info ) +static bool mgsl_irq_test( struct mgsl_struct *info ) { unsigned long EndTime; unsigned long flags; @@ -7068,10 +7065,10 @@ static BOOLEAN mgsl_irq_test( struct mgsl_struct *info ) /* * Setup 16C32 to interrupt on TxC pin (14MHz clock) transition. - * The ISR sets irq_occurred to 1. + * The ISR sets irq_occurred to true. */ - info->irq_occurred = FALSE; + info->irq_occurred = false; /* Enable INTEN gate for ISA adapter (Port 6, Bit12) */ /* Enable INTEN (Port 6, Bit12) */ @@ -7097,10 +7094,7 @@ static BOOLEAN mgsl_irq_test( struct mgsl_struct *info ) usc_reset(info); spin_unlock_irqrestore(&info->irq_spinlock,flags); - if ( !info->irq_occurred ) - return FALSE; - else - return TRUE; + return info->irq_occurred; } /* end of mgsl_irq_test() */ @@ -7111,16 +7105,16 @@ static BOOLEAN mgsl_irq_test( struct mgsl_struct *info ) * using single buffer DMA mode. * * Arguments: info pointer to device instance data - * Return Value: TRUE if test passed, otherwise FALSE + * Return Value: true if test passed, otherwise false */ -static BOOLEAN mgsl_dma_test( struct mgsl_struct *info ) +static bool mgsl_dma_test( struct mgsl_struct *info ) { unsigned short FifoLevel; unsigned long phys_addr; unsigned int FrameSize; unsigned int i; char *TmpPtr; - BOOLEAN rc = TRUE; + bool rc = true; unsigned short status=0; unsigned long EndTime; unsigned long flags; @@ -7233,7 +7227,7 @@ static BOOLEAN mgsl_dma_test( struct mgsl_struct *info ) for(;;) { if (time_after(jiffies, EndTime)) { - rc = FALSE; + rc = false; break; } @@ -7289,7 +7283,7 @@ static BOOLEAN mgsl_dma_test( struct mgsl_struct *info ) for(;;) { if (time_after(jiffies, EndTime)) { - rc = FALSE; + rc = false; break; } @@ -7309,7 +7303,7 @@ static BOOLEAN mgsl_dma_test( struct mgsl_struct *info ) } - if ( rc == TRUE ) + if ( rc ) { /* Enable 16C32 transmitter. */ @@ -7337,7 +7331,7 @@ static BOOLEAN mgsl_dma_test( struct mgsl_struct *info ) while ( !(status & (BIT6+BIT5+BIT4+BIT2+BIT1)) ) { if (time_after(jiffies, EndTime)) { - rc = FALSE; + rc = false; break; } @@ -7348,13 +7342,13 @@ static BOOLEAN mgsl_dma_test( struct mgsl_struct *info ) } - if ( rc == TRUE ){ + if ( rc ){ /* CHECK FOR TRANSMIT ERRORS */ if ( status & (BIT5 + BIT1) ) - rc = FALSE; + rc = false; } - if ( rc == TRUE ) { + if ( rc ) { /* WAIT FOR RECEIVE COMPLETE */ /* Wait 100ms */ @@ -7364,7 +7358,7 @@ static BOOLEAN mgsl_dma_test( struct mgsl_struct *info ) status=info->rx_buffer_list[0].status; while ( status == 0 ) { if (time_after(jiffies, EndTime)) { - rc = FALSE; + rc = false; break; } status=info->rx_buffer_list[0].status; @@ -7372,17 +7366,17 @@ static BOOLEAN mgsl_dma_test( struct mgsl_struct *info ) } - if ( rc == TRUE ) { + if ( rc ) { /* CHECK FOR RECEIVE ERRORS */ status = info->rx_buffer_list[0].status; if ( status & (BIT8 + BIT3 + BIT1) ) { /* receive error has occurred */ - rc = FALSE; + rc = false; } else { if ( memcmp( info->tx_buffer_list[0].virt_addr , info->rx_buffer_list[0].virt_addr, FrameSize ) ){ - rc = FALSE; + rc = false; } } } @@ -7445,9 +7439,9 @@ static int mgsl_adapter_test( struct mgsl_struct *info ) * Test the shared memory on a PCI adapter. * * Arguments: info pointer to device instance data - * Return Value: TRUE if test passed, otherwise FALSE + * Return Value: true if test passed, otherwise false */ -static BOOLEAN mgsl_memory_test( struct mgsl_struct *info ) +static bool mgsl_memory_test( struct mgsl_struct *info ) { static unsigned long BitPatterns[] = { 0x0, 0x55555555, 0xaaaaaaaa, 0x66666666, 0x99999999, 0xffffffff, 0x12345678 }; @@ -7457,7 +7451,7 @@ static BOOLEAN mgsl_memory_test( struct mgsl_struct *info ) unsigned long * TestAddr; if ( info->bus_type != MGSL_BUS_TYPE_PCI ) - return TRUE; + return true; TestAddr = (unsigned long *)info->memory_base; @@ -7466,7 +7460,7 @@ static BOOLEAN mgsl_memory_test( struct mgsl_struct *info ) for ( i = 0 ; i < Patterncount ; i++ ) { *TestAddr = BitPatterns[i]; if ( *TestAddr != BitPatterns[i] ) - return FALSE; + return false; } /* Test address lines with incrementing pattern over */ @@ -7481,13 +7475,13 @@ static BOOLEAN mgsl_memory_test( struct mgsl_struct *info ) for ( i = 0 ; i < TestLimit ; i++ ) { if ( *TestAddr != i * 4 ) - return FALSE; + return false; TestAddr++; } memset( info->memory_base, 0, SHARED_MEM_ADDRESS_SIZE ); - return TRUE; + return true; } /* End Of mgsl_memory_test() */ @@ -7604,7 +7598,7 @@ static void mgsl_tx_timeout(unsigned long context) info->icount.txtimeout++; } spin_lock_irqsave(&info->irq_spinlock,flags); - info->tx_active = 0; + info->tx_active = false; info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; if ( info->params.flags & HDLC_FLAG_HDLC_LOOPMODE ) @@ -7632,7 +7626,7 @@ static int mgsl_loopmode_send_done( struct mgsl_struct * info ) spin_lock_irqsave(&info->irq_spinlock,flags); if (info->params.flags & HDLC_FLAG_HDLC_LOOPMODE) { if (info->tx_active) - info->loopmode_send_done_requested = TRUE; + info->loopmode_send_done_requested = true; else usc_loopmode_send_done(info); } @@ -7646,7 +7640,7 @@ static int mgsl_loopmode_send_done( struct mgsl_struct * info ) */ static void usc_loopmode_send_done( struct mgsl_struct * info ) { - info->loopmode_send_done_requested = FALSE; + info->loopmode_send_done_requested = false; /* clear CMR:13 to 0 to start echoing RxData to TxData */ info->cmr_value &= ~BIT13; usc_OutReg(info, CMR, info->cmr_value); @@ -7668,7 +7662,7 @@ static void usc_loopmode_cancel_transmit( struct mgsl_struct * info ) */ static void usc_loopmode_insert_request( struct mgsl_struct * info ) { - info->loopmode_insert_requested = TRUE; + info->loopmode_insert_requested = true; /* enable RxAbort irq. On next RxAbort, clear CMR:13 to * begin repeating TxData on RxData (complete insertion) diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c index 3c89266c825..f3d8d72e5ea 100644 --- a/drivers/char/synclink_gt.c +++ b/drivers/char/synclink_gt.c @@ -117,7 +117,7 @@ static struct pci_driver pci_driver = { .remove = __devexit_p(remove_one), }; -static int pci_registered; +static bool pci_registered; /* * module configuration and status @@ -289,12 +289,12 @@ struct slgt_info { struct work_struct task; u32 pending_bh; - int bh_requested; - int bh_running; + bool bh_requested; + bool bh_running; int isr_overflow; - int irq_requested; /* nonzero if IRQ requested */ - int irq_occurred; /* for diagnostics use */ + bool irq_requested; /* true if IRQ requested */ + bool irq_occurred; /* for diagnostics use */ /* device configuration */ @@ -304,7 +304,7 @@ struct slgt_info { unsigned char __iomem * reg_addr; /* memory mapped registers address */ u32 phys_reg_addr; - int reg_addr_requested; + bool reg_addr_requested; MGSL_PARAMS params; /* communications parameters */ u32 idle_mode; @@ -315,11 +315,11 @@ struct slgt_info { /* device status */ - int rx_enabled; - int rx_restart; + bool rx_enabled; + bool rx_restart; - int tx_enabled; - int tx_active; + bool tx_enabled; + bool tx_active; unsigned char signals; /* serial signal states */ int init_error; /* initialization error */ @@ -329,7 +329,7 @@ struct slgt_info { char flag_buf[MAX_ASYNC_BUFFER_SIZE]; char char_buf[MAX_ASYNC_BUFFER_SIZE]; - BOOLEAN drop_rts_on_tx_done; + bool drop_rts_on_tx_done; struct _input_signal_events input_signal_events; int dcd_chkcount; /* check counts to prevent */ @@ -467,8 +467,8 @@ static void rx_start(struct slgt_info *info); static void reset_rbufs(struct slgt_info *info); static void free_rbufs(struct slgt_info *info, unsigned int first, unsigned int last); static void rdma_reset(struct slgt_info *info); -static int rx_get_frame(struct slgt_info *info); -static int rx_get_buf(struct slgt_info *info); +static bool rx_get_frame(struct slgt_info *info); +static bool rx_get_buf(struct slgt_info *info); static void tx_start(struct slgt_info *info); static void tx_stop(struct slgt_info *info); @@ -1968,8 +1968,8 @@ static int bh_action(struct slgt_info *info) rc = BH_STATUS; } else { /* Mark BH routine as complete */ - info->bh_running = 0; - info->bh_requested = 0; + info->bh_running = false; + info->bh_requested = false; rc = 0; } @@ -1988,7 +1988,7 @@ static void bh_handler(struct work_struct *work) if (!info) return; - info->bh_running = 1; + info->bh_running = true; while((action = bh_action(info))) { switch (action) { @@ -2158,7 +2158,7 @@ static void isr_serial(struct slgt_info *info) wr_reg16(info, SSR, status); /* clear pending */ - info->irq_occurred = 1; + info->irq_occurred = true; if (info->params.mode == MGSL_MODE_ASYNC) { if (status & IRQ_TXIDLE) { @@ -2225,7 +2225,7 @@ static void isr_rdma(struct slgt_info *info) if (status & (BIT5 + BIT4)) { DBGISR(("%s isr_rdma rx_restart=1\n", info->device_name)); - info->rx_restart = 1; + info->rx_restart = true; } info->pending_bh |= BH_RECEIVE; } @@ -2276,14 +2276,14 @@ static void isr_txeom(struct slgt_info *info, unsigned short status) info->icount.txok++; } - info->tx_active = 0; + info->tx_active = false; info->tx_count = 0; del_timer(&info->tx_timer); if (info->params.mode != MGSL_MODE_ASYNC && info->drop_rts_on_tx_done) { info->signals &= ~SerialSignal_RTS; - info->drop_rts_on_tx_done = 0; + info->drop_rts_on_tx_done = false; set_signals(info); } @@ -2337,7 +2337,7 @@ static irqreturn_t slgt_interrupt(int dummy, void *dev_id) while((gsr = rd_reg32(info, GSR) & 0xffffff00)) { DBGISR(("%s gsr=%08x\n", info->device_name, gsr)); - info->irq_occurred = 1; + info->irq_occurred = true; for(i=0; i < info->port_count ; i++) { if (info->port_array[i] == NULL) continue; @@ -2374,7 +2374,7 @@ static irqreturn_t slgt_interrupt(int dummy, void *dev_id) !port->bh_requested) { DBGISR(("%s bh queued\n", port->device_name)); schedule_work(&port->task); - port->bh_requested = 1; + port->bh_requested = true; } } @@ -3110,7 +3110,8 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, { DECLARE_WAITQUEUE(wait, current); int retval; - int do_clocal = 0, extra_count = 0; + bool do_clocal = false; + bool extra_count = false; unsigned long flags; DBGINFO(("%s block_til_ready\n", tty->driver->name)); @@ -3122,7 +3123,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, } if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; + do_clocal = true; /* Wait for carrier detect and the line to become * free (i.e., not in use by the callout). While we are in @@ -3136,7 +3137,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, spin_lock_irqsave(&info->lock, flags); if (!tty_hung_up_p(filp)) { - extra_count = 1; + extra_count = true; info->count--; } spin_unlock_irqrestore(&info->lock, flags); @@ -3321,7 +3322,7 @@ static int claim_resources(struct slgt_info *info) goto errout; } else - info->reg_addr_requested = 1; + info->reg_addr_requested = true; info->reg_addr = ioremap(info->phys_reg_addr, SLGT_REG_SIZE); if (!info->reg_addr) { @@ -3341,12 +3342,12 @@ static void release_resources(struct slgt_info *info) { if (info->irq_requested) { free_irq(info->irq_level, info); - info->irq_requested = 0; + info->irq_requested = false; } if (info->reg_addr_requested) { release_mem_region(info->phys_reg_addr, SLGT_REG_SIZE); - info->reg_addr_requested = 0; + info->reg_addr_requested = false; } if (info->reg_addr) { @@ -3511,7 +3512,7 @@ static void device_init(int adapter_num, struct pci_dev *pdev) port_array[0]->device_name, port_array[0]->irq_level)); } else { - port_array[0]->irq_requested = 1; + port_array[0]->irq_requested = true; adapter_test(port_array[0]); for (i=1 ; i < port_count ; i++) { port_array[i]->init_error = port_array[0]->init_error; @@ -3654,7 +3655,7 @@ static int __init slgt_init(void) printk("%s pci_register_driver error=%d\n", driver_name, rc); goto error; } - pci_registered = 1; + pci_registered = true; if (!slgt_device_list) printk("%s no devices found\n",driver_name); @@ -3812,8 +3813,8 @@ static void rx_stop(struct slgt_info *info) rdma_reset(info); - info->rx_enabled = 0; - info->rx_restart = 0; + info->rx_enabled = false; + info->rx_restart = false; } static void rx_start(struct slgt_info *info) @@ -3849,8 +3850,8 @@ static void rx_start(struct slgt_info *info) /* enable receiver */ wr_reg16(info, RCR, (unsigned short)(rd_reg16(info, RCR) | BIT1)); - info->rx_restart = 0; - info->rx_enabled = 1; + info->rx_restart = false; + info->rx_enabled = true; } static void tx_start(struct slgt_info *info) @@ -3858,11 +3859,11 @@ static void tx_start(struct slgt_info *info) if (!info->tx_enabled) { wr_reg16(info, TCR, (unsigned short)((rd_reg16(info, TCR) | BIT1) & ~BIT2)); - info->tx_enabled = TRUE; + info->tx_enabled = true; } if (info->tx_count) { - info->drop_rts_on_tx_done = 0; + info->drop_rts_on_tx_done = false; if (info->params.mode != MGSL_MODE_ASYNC) { if (info->params.flags & HDLC_FLAG_AUTO_RTS) { @@ -3870,7 +3871,7 @@ static void tx_start(struct slgt_info *info) if (!(info->signals & SerialSignal_RTS)) { info->signals |= SerialSignal_RTS; set_signals(info); - info->drop_rts_on_tx_done = 1; + info->drop_rts_on_tx_done = true; } } @@ -3888,7 +3889,7 @@ static void tx_start(struct slgt_info *info) wr_reg16(info, SSR, IRQ_TXIDLE); } tdma_start(info); - info->tx_active = 1; + info->tx_active = true; } } @@ -3949,8 +3950,8 @@ static void tx_stop(struct slgt_info *info) reset_tbufs(info); - info->tx_enabled = 0; - info->tx_active = 0; + info->tx_enabled = false; + info->tx_active = false; } static void reset_port(struct slgt_info *info) @@ -4470,14 +4471,13 @@ static void reset_rbufs(struct slgt_info *info) /* * pass receive HDLC frame to upper layer * - * return 1 if frame available, otherwise 0 + * return true if frame available, otherwise false */ -static int rx_get_frame(struct slgt_info *info) +static bool rx_get_frame(struct slgt_info *info) { unsigned int start, end; unsigned short status; unsigned int framesize = 0; - int rc = 0; unsigned long flags; struct tty_struct *tty = info->tty; unsigned char addr_field = 0xff; @@ -4601,23 +4601,23 @@ check_again: } } free_rbufs(info, start, end); - rc = 1; + return true; cleanup: - return rc; + return false; } /* * pass receive buffer (RAW synchronous mode) to tty layer - * return 1 if buffer available, otherwise 0 + * return true if buffer available, otherwise false */ -static int rx_get_buf(struct slgt_info *info) +static bool rx_get_buf(struct slgt_info *info) { unsigned int i = info->rbuf_current; unsigned int count; if (!desc_complete(info->rbufs[i])) - return 0; + return false; count = desc_count(info->rbufs[i]); switch(info->params.mode) { case MGSL_MODE_MONOSYNC: @@ -4633,7 +4633,7 @@ static int rx_get_buf(struct slgt_info *info) ldisc_receive_buf(info->tty, info->rbufs[i].buf, info->flag_buf, count); free_rbufs(info, i, i); - return 1; + return true; } static void reset_tbufs(struct slgt_info *info) @@ -4758,7 +4758,7 @@ static int irq_test(struct slgt_info *info) /* assume failure */ info->init_error = DiagStatus_IrqFailure; - info->irq_occurred = FALSE; + info->irq_occurred = false; spin_unlock_irqrestore(&info->lock, flags); @@ -4891,7 +4891,7 @@ static void tx_timeout(unsigned long context) info->icount.txtimeout++; } spin_lock_irqsave(&info->lock,flags); - info->tx_active = 0; + info->tx_active = false; info->tx_count = 0; spin_unlock_irqrestore(&info->lock,flags); diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c index c96062ea72b..e98c3e6f821 100644 --- a/drivers/char/synclinkmp.c +++ b/drivers/char/synclinkmp.c @@ -188,9 +188,9 @@ typedef struct _synclinkmp_info { u32 pending_bh; - int bh_running; /* Protection from multiple */ + bool bh_running; /* Protection from multiple */ int isr_overflow; - int bh_requested; + bool bh_requested; int dcd_chkcount; /* check counts to prevent */ int cts_chkcount; /* too many IRQs if a signal */ @@ -213,11 +213,11 @@ typedef struct _synclinkmp_info { unsigned char *tmp_rx_buf; unsigned int tmp_rx_buf_count; - int rx_enabled; - int rx_overflow; + bool rx_enabled; + bool rx_overflow; - int tx_enabled; - int tx_active; + bool tx_enabled; + bool tx_active; u32 idle_mode; unsigned char ie0_value; @@ -238,13 +238,13 @@ typedef struct _synclinkmp_info { unsigned int irq_level; /* interrupt level */ unsigned long irq_flags; - int irq_requested; /* nonzero if IRQ requested */ + bool irq_requested; /* true if IRQ requested */ MGSL_PARAMS params; /* communications parameters */ unsigned char serial_signals; /* current serial signal states */ - int irq_occurred; /* for diagnostics use */ + bool irq_occurred; /* for diagnostics use */ unsigned int init_error; /* Initialization startup error */ u32 last_mem_alloc; @@ -255,7 +255,7 @@ typedef struct _synclinkmp_info { unsigned char* sca_base; /* HD64570 SCA Memory address */ u32 phys_sca_base; u32 sca_offset; - int sca_base_requested; + bool sca_base_requested; unsigned char* lcr_base; /* local config registers (PCI only) */ u32 phys_lcr_base; @@ -265,12 +265,12 @@ typedef struct _synclinkmp_info { unsigned char* statctrl_base; /* status/control register memory */ u32 phys_statctrl_base; u32 statctrl_offset; - int sca_statctrl_requested; + bool sca_statctrl_requested; u32 misc_ctrl_value; char flag_buf[MAX_ASYNC_BUFFER_SIZE]; char char_buf[MAX_ASYNC_BUFFER_SIZE]; - BOOLEAN drop_rts_on_tx_done; + bool drop_rts_on_tx_done; struct _input_signal_events input_signal_events; @@ -571,12 +571,12 @@ static void shutdown(SLMP_INFO *info); static void program_hw(SLMP_INFO *info); static void change_params(SLMP_INFO *info); -static int init_adapter(SLMP_INFO *info); -static int register_test(SLMP_INFO *info); -static int irq_test(SLMP_INFO *info); -static int loopback_test(SLMP_INFO *info); +static bool init_adapter(SLMP_INFO *info); +static bool register_test(SLMP_INFO *info); +static bool irq_test(SLMP_INFO *info); +static bool loopback_test(SLMP_INFO *info); static int adapter_test(SLMP_INFO *info); -static int memory_test(SLMP_INFO *info); +static bool memory_test(SLMP_INFO *info); static void reset_adapter(SLMP_INFO *info); static void reset_port(SLMP_INFO *info); @@ -587,7 +587,7 @@ static void rx_stop(SLMP_INFO *info); static void rx_start(SLMP_INFO *info); static void rx_reset_buffers(SLMP_INFO *info); static void rx_free_frame_buffers(SLMP_INFO *info, unsigned int first, unsigned int last); -static int rx_get_frame(SLMP_INFO *info); +static bool rx_get_frame(SLMP_INFO *info); static void tx_start(SLMP_INFO *info); static void tx_stop(SLMP_INFO *info); @@ -1473,7 +1473,7 @@ static inline int line_info(char *buf, SLMP_INFO *info) /* Called to print information about devices */ -int read_proc(char *page, char **start, off_t off, int count, +static int read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) { int len = 0, l; @@ -2024,7 +2024,7 @@ static void hdlcdev_exit(SLMP_INFO *info) /* Return next bottom half action to perform. * Return Value: BH action code or 0 if nothing to do. */ -int bh_action(SLMP_INFO *info) +static int bh_action(SLMP_INFO *info) { unsigned long flags; int rc = 0; @@ -2044,8 +2044,8 @@ int bh_action(SLMP_INFO *info) if (!rc) { /* Mark BH routine as complete */ - info->bh_running = 0; - info->bh_requested = 0; + info->bh_running = false; + info->bh_requested = false; } spin_unlock_irqrestore(&info->lock,flags); @@ -2055,7 +2055,7 @@ int bh_action(SLMP_INFO *info) /* Perform bottom half processing of work items queued by ISR. */ -void bh_handler(struct work_struct *work) +static void bh_handler(struct work_struct *work) { SLMP_INFO *info = container_of(work, SLMP_INFO, task); int action; @@ -2067,7 +2067,7 @@ void bh_handler(struct work_struct *work) printk( "%s(%d):%s bh_handler() entry\n", __FILE__,__LINE__,info->device_name); - info->bh_running = 1; + info->bh_running = true; while((action = bh_action(info)) != 0) { @@ -2100,7 +2100,7 @@ void bh_handler(struct work_struct *work) __FILE__,__LINE__,info->device_name); } -void bh_receive(SLMP_INFO *info) +static void bh_receive(SLMP_INFO *info) { if ( debug_level >= DEBUG_LEVEL_BH ) printk( "%s(%d):%s bh_receive()\n", @@ -2109,7 +2109,7 @@ void bh_receive(SLMP_INFO *info) while( rx_get_frame(info) ); } -void bh_transmit(SLMP_INFO *info) +static void bh_transmit(SLMP_INFO *info) { struct tty_struct *tty = info->tty; @@ -2121,7 +2121,7 @@ void bh_transmit(SLMP_INFO *info) tty_wakeup(tty); } -void bh_status(SLMP_INFO *info) +static void bh_status(SLMP_INFO *info) { if ( debug_level >= DEBUG_LEVEL_BH ) printk( "%s(%d):%s bh_status() entry\n", @@ -2133,7 +2133,7 @@ void bh_status(SLMP_INFO *info) info->cts_chkcount = 0; } -void isr_timer(SLMP_INFO * info) +static void isr_timer(SLMP_INFO * info) { unsigned char timer = (info->port_num & 1) ? TIMER2 : TIMER0; @@ -2152,14 +2152,14 @@ void isr_timer(SLMP_INFO * info) */ write_reg(info, (unsigned char)(timer + TMCS), 0); - info->irq_occurred = TRUE; + info->irq_occurred = true; if ( debug_level >= DEBUG_LEVEL_ISR ) printk("%s(%d):%s isr_timer()\n", __FILE__,__LINE__,info->device_name); } -void isr_rxint(SLMP_INFO * info) +static void isr_rxint(SLMP_INFO * info) { struct tty_struct *tty = info->tty; struct mgsl_icount *icount = &info->icount; @@ -2218,7 +2218,7 @@ void isr_rxint(SLMP_INFO * info) /* * handle async rx data interrupts */ -void isr_rxrdy(SLMP_INFO * info) +static void isr_rxrdy(SLMP_INFO * info) { u16 status; unsigned char DataByte; @@ -2232,7 +2232,7 @@ void isr_rxrdy(SLMP_INFO * info) while((status = read_reg(info,CST0)) & BIT0) { int flag = 0; - int over = 0; + bool over = false; DataByte = read_reg(info,TRB); icount->rx++; @@ -2265,7 +2265,7 @@ void isr_rxrdy(SLMP_INFO * info) * reported immediately, and doesn't * affect the current character */ - over = 1; + over = true; } } } /* end of if (error) */ @@ -2318,14 +2318,14 @@ static void isr_txeom(SLMP_INFO * info, unsigned char status) info->icount.txok++; } - info->tx_active = 0; + info->tx_active = false; info->tx_count = info->tx_put = info->tx_get = 0; del_timer(&info->tx_timer); if (info->params.mode != MGSL_MODE_ASYNC && info->drop_rts_on_tx_done ) { info->serial_signals &= ~SerialSignal_RTS; - info->drop_rts_on_tx_done = 0; + info->drop_rts_on_tx_done = false; set_signals(info); } @@ -2348,7 +2348,7 @@ static void isr_txeom(SLMP_INFO * info, unsigned char status) /* * handle tx status interrupts */ -void isr_txint(SLMP_INFO * info) +static void isr_txint(SLMP_INFO * info) { unsigned char status = read_reg(info, SR1) & info->ie1_value & (UDRN + IDLE + CCTS); @@ -2376,7 +2376,7 @@ void isr_txint(SLMP_INFO * info) /* * handle async tx data interrupts */ -void isr_txrdy(SLMP_INFO * info) +static void isr_txrdy(SLMP_INFO * info) { if ( debug_level >= DEBUG_LEVEL_ISR ) printk("%s(%d):%s isr_txrdy() tx_count=%d\n", @@ -2398,7 +2398,7 @@ void isr_txrdy(SLMP_INFO * info) if ( info->tx_count ) tx_load_fifo( info ); else { - info->tx_active = 0; + info->tx_active = false; info->ie0_value &= ~TXRDYE; write_reg(info, IE0, info->ie0_value); } @@ -2407,7 +2407,7 @@ void isr_txrdy(SLMP_INFO * info) info->pending_bh |= BH_TRANSMIT; } -void isr_rxdmaok(SLMP_INFO * info) +static void isr_rxdmaok(SLMP_INFO * info) { /* BIT7 = EOT (end of transfer) * BIT6 = EOM (end of message/frame) @@ -2424,7 +2424,7 @@ void isr_rxdmaok(SLMP_INFO * info) info->pending_bh |= BH_RECEIVE; } -void isr_rxdmaerror(SLMP_INFO * info) +static void isr_rxdmaerror(SLMP_INFO * info) { /* BIT5 = BOF (buffer overflow) * BIT4 = COF (counter overflow) @@ -2438,11 +2438,11 @@ void isr_rxdmaerror(SLMP_INFO * info) printk("%s(%d):%s isr_rxdmaerror(), status=%02x\n", __FILE__,__LINE__,info->device_name,status); - info->rx_overflow = TRUE; + info->rx_overflow = true; info->pending_bh |= BH_RECEIVE; } -void isr_txdmaok(SLMP_INFO * info) +static void isr_txdmaok(SLMP_INFO * info) { unsigned char status_reg1 = read_reg(info, SR1); @@ -2460,7 +2460,7 @@ void isr_txdmaok(SLMP_INFO * info) write_reg(info, IE0, info->ie0_value); } -void isr_txdmaerror(SLMP_INFO * info) +static void isr_txdmaerror(SLMP_INFO * info) { /* BIT5 = BOF (buffer overflow) * BIT4 = COF (counter overflow) @@ -2477,7 +2477,7 @@ void isr_txdmaerror(SLMP_INFO * info) /* handle input serial signal changes */ -void isr_io_pin( SLMP_INFO *info, u16 status ) +static void isr_io_pin( SLMP_INFO *info, u16 status ) { struct mgsl_icount *icount; @@ -2691,7 +2691,7 @@ static irqreturn_t synclinkmp_interrupt(int dummy, void *dev_id) printk("%s(%d):%s queueing bh task.\n", __FILE__,__LINE__,port->device_name); schedule_work(&port->task); - port->bh_requested = 1; + port->bh_requested = true; } } @@ -3320,7 +3320,8 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, { DECLARE_WAITQUEUE(wait, current); int retval; - int do_clocal = 0, extra_count = 0; + bool do_clocal = false; + bool extra_count = false; unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) @@ -3335,7 +3336,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, } if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; + do_clocal = true; /* Wait for carrier detect and the line to become * free (i.e., not in use by the callout). While we are in @@ -3353,7 +3354,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, spin_lock_irqsave(&info->lock, flags); if (!tty_hung_up_p(filp)) { - extra_count = 1; + extra_count = true; info->count--; } spin_unlock_irqrestore(&info->lock, flags); @@ -3413,7 +3414,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, return retval; } -int alloc_dma_bufs(SLMP_INFO *info) +static int alloc_dma_bufs(SLMP_INFO *info) { unsigned short BuffersPerFrame; unsigned short BufferCount; @@ -3487,7 +3488,7 @@ int alloc_dma_bufs(SLMP_INFO *info) /* Allocate DMA buffers for the transmit and receive descriptor lists. */ -int alloc_buf_list(SLMP_INFO *info) +static int alloc_buf_list(SLMP_INFO *info) { unsigned int i; @@ -3546,7 +3547,7 @@ int alloc_buf_list(SLMP_INFO *info) /* Allocate the frame DMA buffers used by the specified buffer list. */ -int alloc_frame_bufs(SLMP_INFO *info, SCADESC *buf_list,SCADESC_EX *buf_list_ex,int count) +static int alloc_frame_bufs(SLMP_INFO *info, SCADESC *buf_list,SCADESC_EX *buf_list_ex,int count) { int i; unsigned long phys_addr; @@ -3563,7 +3564,7 @@ int alloc_frame_bufs(SLMP_INFO *info, SCADESC *buf_list,SCADESC_EX *buf_list_ex, return 0; } -void free_dma_bufs(SLMP_INFO *info) +static void free_dma_bufs(SLMP_INFO *info) { info->buffer_list = NULL; info->rx_buf_list = NULL; @@ -3573,7 +3574,7 @@ void free_dma_bufs(SLMP_INFO *info) /* allocate buffer large enough to hold max_frame_size. * This buffer is used to pass an assembled frame to the line discipline. */ -int alloc_tmp_rx_buf(SLMP_INFO *info) +static int alloc_tmp_rx_buf(SLMP_INFO *info) { info->tmp_rx_buf = kmalloc(info->max_frame_size, GFP_KERNEL); if (info->tmp_rx_buf == NULL) @@ -3581,13 +3582,13 @@ int alloc_tmp_rx_buf(SLMP_INFO *info) return 0; } -void free_tmp_rx_buf(SLMP_INFO *info) +static void free_tmp_rx_buf(SLMP_INFO *info) { kfree(info->tmp_rx_buf); info->tmp_rx_buf = NULL; } -int claim_resources(SLMP_INFO *info) +static int claim_resources(SLMP_INFO *info) { if (request_mem_region(info->phys_memory_base,SCA_MEM_SIZE,"synclinkmp") == NULL) { printk( "%s(%d):%s mem addr conflict, Addr=%08X\n", @@ -3596,7 +3597,7 @@ int claim_resources(SLMP_INFO *info) goto errout; } else - info->shared_mem_requested = 1; + info->shared_mem_requested = true; if (request_mem_region(info->phys_lcr_base + info->lcr_offset,128,"synclinkmp") == NULL) { printk( "%s(%d):%s lcr mem addr conflict, Addr=%08X\n", @@ -3605,7 +3606,7 @@ int claim_resources(SLMP_INFO *info) goto errout; } else - info->lcr_mem_requested = 1; + info->lcr_mem_requested = true; if (request_mem_region(info->phys_sca_base + info->sca_offset,SCA_BASE_SIZE,"synclinkmp") == NULL) { printk( "%s(%d):%s sca mem addr conflict, Addr=%08X\n", @@ -3614,7 +3615,7 @@ int claim_resources(SLMP_INFO *info) goto errout; } else - info->sca_base_requested = 1; + info->sca_base_requested = true; if (request_mem_region(info->phys_statctrl_base + info->statctrl_offset,SCA_REG_SIZE,"synclinkmp") == NULL) { printk( "%s(%d):%s stat/ctrl mem addr conflict, Addr=%08X\n", @@ -3623,7 +3624,7 @@ int claim_resources(SLMP_INFO *info) goto errout; } else - info->sca_statctrl_requested = 1; + info->sca_statctrl_requested = true; info->memory_base = ioremap(info->phys_memory_base,SCA_MEM_SIZE); if (!info->memory_base) { @@ -3674,7 +3675,7 @@ errout: return -ENODEV; } -void release_resources(SLMP_INFO *info) +static void release_resources(SLMP_INFO *info) { if ( debug_level >= DEBUG_LEVEL_INFO ) printk( "%s(%d):%s release_resources() entry\n", @@ -3682,24 +3683,24 @@ void release_resources(SLMP_INFO *info) if ( info->irq_requested ) { free_irq(info->irq_level, info); - info->irq_requested = 0; + info->irq_requested = false; } if ( info->shared_mem_requested ) { release_mem_region(info->phys_memory_base,SCA_MEM_SIZE); - info->shared_mem_requested = 0; + info->shared_mem_requested = false; } if ( info->lcr_mem_requested ) { release_mem_region(info->phys_lcr_base + info->lcr_offset,128); - info->lcr_mem_requested = 0; + info->lcr_mem_requested = false; } if ( info->sca_base_requested ) { release_mem_region(info->phys_sca_base + info->sca_offset,SCA_BASE_SIZE); - info->sca_base_requested = 0; + info->sca_base_requested = false; } if ( info->sca_statctrl_requested ) { release_mem_region(info->phys_statctrl_base + info->statctrl_offset,SCA_REG_SIZE); - info->sca_statctrl_requested = 0; + info->sca_statctrl_requested = false; } if (info->memory_base){ @@ -3730,7 +3731,7 @@ void release_resources(SLMP_INFO *info) /* Add the specified device instance data structure to the * global linked list of devices and increment the device count. */ -void add_device(SLMP_INFO *info) +static void add_device(SLMP_INFO *info) { info->next_device = NULL; info->line = synclinkmp_device_count; @@ -3853,7 +3854,7 @@ static SLMP_INFO *alloc_dev(int adapter_num, int port_num, struct pci_dev *pdev) return info; } -void device_init(int adapter_num, struct pci_dev *pdev) +static void device_init(int adapter_num, struct pci_dev *pdev) { SLMP_INFO *port_array[SCA_MAX_PORTS]; int port; @@ -3902,7 +3903,7 @@ void device_init(int adapter_num, struct pci_dev *pdev) port_array[0]->irq_level ); } else { - port_array[0]->irq_requested = 1; + port_array[0]->irq_requested = true; adapter_test(port_array[0]); } } @@ -4047,7 +4048,7 @@ module_exit(synclinkmp_exit); * The TxCLK and RxCLK signals are generated from the BRG and * the TxD is looped back to the RxD internally. */ -void enable_loopback(SLMP_INFO *info, int enable) +static void enable_loopback(SLMP_INFO *info, int enable) { if (enable) { /* MD2 (Mode Register 2) @@ -4094,7 +4095,7 @@ void enable_loopback(SLMP_INFO *info, int enable) * data_rate data rate of clock in bits per second * A data rate of 0 disables the AUX clock. */ -void set_rate( SLMP_INFO *info, u32 data_rate ) +static void set_rate( SLMP_INFO *info, u32 data_rate ) { u32 TMCValue; unsigned char BRValue; @@ -4140,7 +4141,7 @@ void set_rate( SLMP_INFO *info, u32 data_rate ) /* Disable receiver */ -void rx_stop(SLMP_INFO *info) +static void rx_stop(SLMP_INFO *info) { if (debug_level >= DEBUG_LEVEL_ISR) printk("%s(%d):%s rx_stop()\n", @@ -4155,13 +4156,13 @@ void rx_stop(SLMP_INFO *info) write_reg(info, RXDMA + DCMD, SWABORT); /* reset/init Rx DMA */ write_reg(info, RXDMA + DIR, 0); /* disable Rx DMA interrupts */ - info->rx_enabled = 0; - info->rx_overflow = 0; + info->rx_enabled = false; + info->rx_overflow = false; } /* enable the receiver */ -void rx_start(SLMP_INFO *info) +static void rx_start(SLMP_INFO *info) { int i; @@ -4211,14 +4212,14 @@ void rx_start(SLMP_INFO *info) write_reg(info, CMD, RXENABLE); - info->rx_overflow = FALSE; - info->rx_enabled = 1; + info->rx_overflow = false; + info->rx_enabled = true; } /* Enable the transmitter and send a transmit frame if * one is loaded in the DMA buffers. */ -void tx_start(SLMP_INFO *info) +static void tx_start(SLMP_INFO *info) { if (debug_level >= DEBUG_LEVEL_ISR) printk("%s(%d):%s tx_start() tx_count=%d\n", @@ -4227,7 +4228,7 @@ void tx_start(SLMP_INFO *info) if (!info->tx_enabled ) { write_reg(info, CMD, TXRESET); write_reg(info, CMD, TXENABLE); - info->tx_enabled = TRUE; + info->tx_enabled = true; } if ( info->tx_count ) { @@ -4236,7 +4237,7 @@ void tx_start(SLMP_INFO *info) /* RTS and set a flag indicating that the driver should */ /* negate RTS when the transmission completes. */ - info->drop_rts_on_tx_done = 0; + info->drop_rts_on_tx_done = false; if (info->params.mode != MGSL_MODE_ASYNC) { @@ -4245,7 +4246,7 @@ void tx_start(SLMP_INFO *info) if ( !(info->serial_signals & SerialSignal_RTS) ) { info->serial_signals |= SerialSignal_RTS; set_signals( info ); - info->drop_rts_on_tx_done = 1; + info->drop_rts_on_tx_done = true; } } @@ -4282,13 +4283,13 @@ void tx_start(SLMP_INFO *info) write_reg(info, IE0, info->ie0_value); } - info->tx_active = 1; + info->tx_active = true; } } /* stop the transmitter and DMA */ -void tx_stop( SLMP_INFO *info ) +static void tx_stop( SLMP_INFO *info ) { if (debug_level >= DEBUG_LEVEL_ISR) printk("%s(%d):%s tx_stop()\n", @@ -4308,14 +4309,14 @@ void tx_stop( SLMP_INFO *info ) info->ie0_value &= ~TXRDYE; write_reg(info, IE0, info->ie0_value); /* disable tx data interrupts */ - info->tx_enabled = 0; - info->tx_active = 0; + info->tx_enabled = false; + info->tx_active = false; } /* Fill the transmit FIFO until the FIFO is full or * there is no more data to load. */ -void tx_load_fifo(SLMP_INFO *info) +static void tx_load_fifo(SLMP_INFO *info) { u8 TwoBytes[2]; @@ -4364,7 +4365,7 @@ void tx_load_fifo(SLMP_INFO *info) /* Reset a port to a known state */ -void reset_port(SLMP_INFO *info) +static void reset_port(SLMP_INFO *info) { if (info->sca_base) { @@ -4388,7 +4389,7 @@ void reset_port(SLMP_INFO *info) /* Reset all the ports to a known state. */ -void reset_adapter(SLMP_INFO *info) +static void reset_adapter(SLMP_INFO *info) { int i; @@ -4400,7 +4401,7 @@ void reset_adapter(SLMP_INFO *info) /* Program port for asynchronous communications. */ -void async_mode(SLMP_INFO *info) +static void async_mode(SLMP_INFO *info) { unsigned char RegValue; @@ -4539,7 +4540,7 @@ void async_mode(SLMP_INFO *info) /* Program the SCA for HDLC communications. */ -void hdlc_mode(SLMP_INFO *info) +static void hdlc_mode(SLMP_INFO *info) { unsigned char RegValue; u32 DpllDivisor; @@ -4741,7 +4742,7 @@ void hdlc_mode(SLMP_INFO *info) /* Set the transmit HDLC idle mode */ -void tx_set_idle(SLMP_INFO *info) +static void tx_set_idle(SLMP_INFO *info) { unsigned char RegValue = 0xff; @@ -4761,7 +4762,7 @@ void tx_set_idle(SLMP_INFO *info) /* Query the adapter for the state of the V24 status (input) signals. */ -void get_signals(SLMP_INFO *info) +static void get_signals(SLMP_INFO *info) { u16 status = read_reg(info, SR3); u16 gpstatus = read_status_reg(info); @@ -4790,7 +4791,7 @@ void get_signals(SLMP_INFO *info) /* Set the state of DTR and RTS based on contents of * serial_signals member of device context. */ -void set_signals(SLMP_INFO *info) +static void set_signals(SLMP_INFO *info) { unsigned char RegValue; u16 EnableBit; @@ -4819,7 +4820,7 @@ void set_signals(SLMP_INFO *info) * and set the current buffer to the first buffer. This effectively * makes all buffers free and discards any data in buffers. */ -void rx_reset_buffers(SLMP_INFO *info) +static void rx_reset_buffers(SLMP_INFO *info) { rx_free_frame_buffers(info, 0, info->rx_buf_count - 1); } @@ -4830,16 +4831,16 @@ void rx_reset_buffers(SLMP_INFO *info) * first index of 1st receive buffer of frame * last index of last receive buffer of frame */ -void rx_free_frame_buffers(SLMP_INFO *info, unsigned int first, unsigned int last) +static void rx_free_frame_buffers(SLMP_INFO *info, unsigned int first, unsigned int last) { - int done = 0; + bool done = false; while(!done) { /* reset current buffer for reuse */ info->rx_buf_list[first].status = 0xff; if (first == last) { - done = 1; + done = true; /* set new last rx descriptor address */ write_reg16(info, RXDMA + EDA, info->rx_buf_list_ex[first].phys_entry); } @@ -4856,14 +4857,14 @@ void rx_free_frame_buffers(SLMP_INFO *info, unsigned int first, unsigned int las /* Return a received frame from the receive DMA buffers. * Only frames received without errors are returned. * - * Return Value: 1 if frame returned, otherwise 0 + * Return Value: true if frame returned, otherwise false */ -int rx_get_frame(SLMP_INFO *info) +static bool rx_get_frame(SLMP_INFO *info) { unsigned int StartIndex, EndIndex; /* index of 1st and last buffers of Rx frame */ unsigned short status; unsigned int framesize = 0; - int ReturnCode = 0; + bool ReturnCode = false; unsigned long flags; struct tty_struct *tty = info->tty; unsigned char addr_field = 0xff; @@ -5014,7 +5015,7 @@ CheckAgain: /* Free the buffers used by this frame. */ rx_free_frame_buffers( info, StartIndex, EndIndex ); - ReturnCode = 1; + ReturnCode = true; Cleanup: if ( info->rx_enabled && info->rx_overflow ) { @@ -5033,7 +5034,7 @@ Cleanup: /* load the transmit DMA buffer with data */ -void tx_load_dma_buffer(SLMP_INFO *info, const char *buf, unsigned int count) +static void tx_load_dma_buffer(SLMP_INFO *info, const char *buf, unsigned int count) { unsigned short copy_count; unsigned int i = 0; @@ -5073,12 +5074,12 @@ void tx_load_dma_buffer(SLMP_INFO *info, const char *buf, unsigned int count) info->last_tx_buf = ++i; } -int register_test(SLMP_INFO *info) +static bool register_test(SLMP_INFO *info) { static unsigned char testval[] = {0x00, 0xff, 0xaa, 0x55, 0x69, 0x96}; static unsigned int count = ARRAY_SIZE(testval); unsigned int i; - int rc = TRUE; + bool rc = true; unsigned long flags; spin_lock_irqsave(&info->lock,flags); @@ -5101,7 +5102,7 @@ int register_test(SLMP_INFO *info) (read_reg(info, SA0) != testval[(i+2)%count]) || (read_reg(info, SA1) != testval[(i+3)%count]) ) { - rc = FALSE; + rc = false; break; } } @@ -5112,7 +5113,7 @@ int register_test(SLMP_INFO *info) return rc; } -int irq_test(SLMP_INFO *info) +static bool irq_test(SLMP_INFO *info) { unsigned long timeout; unsigned long flags; @@ -5124,7 +5125,7 @@ int irq_test(SLMP_INFO *info) /* assume failure */ info->init_error = DiagStatus_IrqFailure; - info->irq_occurred = FALSE; + info->irq_occurred = false; /* setup timer0 on SCA0 to interrupt */ @@ -5163,7 +5164,7 @@ int irq_test(SLMP_INFO *info) /* initialize individual SCA device (2 ports) */ -static int sca_init(SLMP_INFO *info) +static bool sca_init(SLMP_INFO *info) { /* set wait controller to single mem partition (low), no wait states */ write_reg(info, PABR0, 0); /* wait controller addr boundary 0 */ @@ -5199,12 +5200,12 @@ static int sca_init(SLMP_INFO *info) */ write_reg(info, ITCR, 0); - return TRUE; + return true; } /* initialize adapter hardware */ -int init_adapter(SLMP_INFO *info) +static bool init_adapter(SLMP_INFO *info) { int i; @@ -5257,20 +5258,20 @@ int init_adapter(SLMP_INFO *info) sca_init(info->port_array[0]); sca_init(info->port_array[2]); - return TRUE; + return true; } /* Loopback an HDLC frame to test the hardware * interrupt and DMA functions. */ -int loopback_test(SLMP_INFO *info) +static bool loopback_test(SLMP_INFO *info) { #define TESTFRAMESIZE 20 unsigned long timeout; u16 count = TESTFRAMESIZE; unsigned char buf[TESTFRAMESIZE]; - int rc = FALSE; + bool rc = false; unsigned long flags; struct tty_struct *oldtty = info->tty; @@ -5304,16 +5305,16 @@ int loopback_test(SLMP_INFO *info) msleep_interruptible(10); if (rx_get_frame(info)) { - rc = TRUE; + rc = true; break; } } /* verify received frame length and contents */ - if (rc == TRUE && - ( info->tmp_rx_buf_count != count || - memcmp(buf, info->tmp_rx_buf,count))) { - rc = FALSE; + if (rc && + ( info->tmp_rx_buf_count != count || + memcmp(buf, info->tmp_rx_buf,count))) { + rc = false; } spin_lock_irqsave(&info->lock,flags); @@ -5328,7 +5329,7 @@ int loopback_test(SLMP_INFO *info) /* Perform diagnostics on hardware */ -int adapter_test( SLMP_INFO *info ) +static int adapter_test( SLMP_INFO *info ) { unsigned long flags; if ( debug_level >= DEBUG_LEVEL_INFO ) @@ -5390,7 +5391,7 @@ int adapter_test( SLMP_INFO *info ) /* Test the shared memory on a PCI adapter. */ -int memory_test(SLMP_INFO *info) +static bool memory_test(SLMP_INFO *info) { static unsigned long testval[] = { 0x0, 0x55555555, 0xaaaaaaaa, 0x66666666, 0x99999999, 0xffffffff, 0x12345678 }; @@ -5404,7 +5405,7 @@ int memory_test(SLMP_INFO *info) for ( i = 0 ; i < count ; i++ ) { *addr = testval[i]; if ( *addr != testval[i] ) - return FALSE; + return false; } /* Test address lines with incrementing pattern over */ @@ -5419,12 +5420,12 @@ int memory_test(SLMP_INFO *info) for ( i = 0 ; i < limit ; i++ ) { if ( *addr != i * 4 ) - return FALSE; + return false; addr++; } memset( info->memory_base, 0, SCA_MEM_SIZE ); - return TRUE; + return true; } /* Load data into PCI adapter shared memory. @@ -5442,7 +5443,7 @@ int memory_test(SLMP_INFO *info) * the write transation. This allows any pending DMA request to gain control * of the local bus in a timely fasion. */ -void load_pci_memory(SLMP_INFO *info, char* dest, const char* src, unsigned short count) +static void load_pci_memory(SLMP_INFO *info, char* dest, const char* src, unsigned short count) { /* A load interval of 16 allows for 4 32-bit writes at */ /* 136ns each for a maximum latency of 542ns on the local bus.*/ @@ -5461,7 +5462,7 @@ void load_pci_memory(SLMP_INFO *info, char* dest, const char* src, unsigned shor memcpy(dest, src, count % sca_pci_load_interval); } -void trace_block(SLMP_INFO *info,const char* data, int count, int xmit) +static void trace_block(SLMP_INFO *info,const char* data, int count, int xmit) { int i; int linecount; @@ -5496,7 +5497,7 @@ void trace_block(SLMP_INFO *info,const char* data, int count, int xmit) /* called when HDLC frame times out * update stats and do tx completion processing */ -void tx_timeout(unsigned long context) +static void tx_timeout(unsigned long context) { SLMP_INFO *info = (SLMP_INFO*)context; unsigned long flags; @@ -5508,7 +5509,7 @@ void tx_timeout(unsigned long context) info->icount.txtimeout++; } spin_lock_irqsave(&info->lock,flags); - info->tx_active = 0; + info->tx_active = false; info->tx_count = info->tx_put = info->tx_get = 0; spin_unlock_irqrestore(&info->lock,flags); @@ -5523,7 +5524,7 @@ void tx_timeout(unsigned long context) /* called to periodically check the DSR/RI modem signal input status */ -void status_timeout(unsigned long context) +static void status_timeout(unsigned long context) { u16 status = 0; SLMP_INFO *info = (SLMP_INFO*)context; @@ -5574,36 +5575,36 @@ void status_timeout(unsigned long context) } -unsigned char read_reg(SLMP_INFO * info, unsigned char Addr) +static unsigned char read_reg(SLMP_INFO * info, unsigned char Addr) { CALC_REGADDR(); return *RegAddr; } -void write_reg(SLMP_INFO * info, unsigned char Addr, unsigned char Value) +static void write_reg(SLMP_INFO * info, unsigned char Addr, unsigned char Value) { CALC_REGADDR(); *RegAddr = Value; } -u16 read_reg16(SLMP_INFO * info, unsigned char Addr) +static u16 read_reg16(SLMP_INFO * info, unsigned char Addr) { CALC_REGADDR(); return *((u16 *)RegAddr); } -void write_reg16(SLMP_INFO * info, unsigned char Addr, u16 Value) +static void write_reg16(SLMP_INFO * info, unsigned char Addr, u16 Value) { CALC_REGADDR(); *((u16 *)RegAddr) = Value; } -unsigned char read_status_reg(SLMP_INFO * info) +static unsigned char read_status_reg(SLMP_INFO * info) { unsigned char *RegAddr = (unsigned char *)info->statctrl_base; return *RegAddr; } -void write_control_reg(SLMP_INFO * info) +static void write_control_reg(SLMP_INFO * info) { unsigned char *RegAddr = (unsigned char *)info->statctrl_base; *RegAddr = info->port_array[0]->ctrlreg_value; diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c index de60e1ea4fb..9e9bad8bdcf 100644 --- a/drivers/char/sysrq.c +++ b/drivers/char/sysrq.c @@ -196,6 +196,48 @@ static struct sysrq_key_op sysrq_showlocks_op = { #define sysrq_showlocks_op (*(struct sysrq_key_op *)0) #endif +#ifdef CONFIG_SMP +static DEFINE_SPINLOCK(show_lock); + +static void showacpu(void *dummy) +{ + unsigned long flags; + + /* Idle CPUs have no interesting backtrace. */ + if (idle_cpu(smp_processor_id())) + return; + + spin_lock_irqsave(&show_lock, flags); + printk(KERN_INFO "CPU%d:\n", smp_processor_id()); + show_stack(NULL, NULL); + spin_unlock_irqrestore(&show_lock, flags); +} + +static void sysrq_showregs_othercpus(struct work_struct *dummy) +{ + smp_call_function(showacpu, NULL, 0, 0); +} + +static DECLARE_WORK(sysrq_showallcpus, sysrq_showregs_othercpus); + +static void sysrq_handle_showallcpus(int key, struct tty_struct *tty) +{ + struct pt_regs *regs = get_irq_regs(); + if (regs) { + printk(KERN_INFO "CPU%d:\n", smp_processor_id()); + show_regs(regs); + } + schedule_work(&sysrq_showallcpus); +} + +static struct sysrq_key_op sysrq_showallcpus_op = { + .handler = sysrq_handle_showallcpus, + .help_msg = "aLlcpus", + .action_msg = "Show backtrace of all active CPUs", + .enable_mask = SYSRQ_ENABLE_DUMP, +}; +#endif + static void sysrq_handle_showregs(int key, struct tty_struct *tty) { struct pt_regs *regs = get_irq_regs(); @@ -271,8 +313,7 @@ static struct sysrq_key_op sysrq_term_op = { static void moom_callback(struct work_struct *ignored) { - out_of_memory(&NODE_DATA(0)->node_zonelists[ZONE_NORMAL], - GFP_KERNEL, 0); + out_of_memory(node_zonelist(0, GFP_KERNEL), GFP_KERNEL, 0); } static DECLARE_WORK(moom_work, moom_callback); @@ -341,7 +382,11 @@ static struct sysrq_key_op *sysrq_key_table[36] = { &sysrq_kill_op, /* i */ NULL, /* j */ &sysrq_SAK_op, /* k */ +#ifdef CONFIG_SMP + &sysrq_showallcpus_op, /* l */ +#else NULL, /* l */ +#endif &sysrq_showmem_op, /* m */ &sysrq_unrt_op, /* n */ /* o: This will often be registered as 'Off' at init time */ diff --git a/drivers/char/toshiba.c b/drivers/char/toshiba.c index ce5ebe3b168..64f1ceed0b2 100644 --- a/drivers/char/toshiba.c +++ b/drivers/char/toshiba.c @@ -520,12 +520,11 @@ static int __init toshiba_init(void) { struct proc_dir_entry *pde; - pde = create_proc_entry("toshiba", 0, NULL); + pde = proc_create("toshiba", 0, NULL, &proc_toshiba_fops); if (!pde) { misc_deregister(&tosh_device); return -ENOMEM; } - pde->proc_fops = &proc_toshiba_fops; } #endif diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig index 8f3f7620f95..3738cfa209f 100644 --- a/drivers/char/tpm/Kconfig +++ b/drivers/char/tpm/Kconfig @@ -23,7 +23,7 @@ if TCG_TPM config TCG_TIS tristate "TPM Interface Specification 1.2 Interface" - depends on PNPACPI + depends on PNP ---help--- If you have a TPM security chip that is compliant with the TCG TIS 1.2 TPM specification say Yes and it will be accessible @@ -32,7 +32,6 @@ config TCG_TIS config TCG_NSC tristate "National Semiconductor TPM Interface" - depends on PNPACPI ---help--- If you have a TPM security chip from National Semiconductor say Yes and it will be accessible from within Linux. To @@ -48,7 +47,7 @@ config TCG_ATMEL config TCG_INFINEON tristate "Infineon Technologies TPM Interface" - depends on PNPACPI + depends on PNP ---help--- If you have a TPM security chip from Infineon Technologies (either SLD 9630 TT 1.1 or SLB 9635 TT 1.2) say Yes and it diff --git a/drivers/char/tpm/tpm_nsc.c b/drivers/char/tpm/tpm_nsc.c index 6313326bc41..ab18c1e7b11 100644 --- a/drivers/char/tpm/tpm_nsc.c +++ b/drivers/char/tpm/tpm_nsc.c @@ -264,7 +264,7 @@ static const struct tpm_vendor_specific tpm_nsc = { static struct platform_device *pdev = NULL; -static void __devexit tpm_nsc_remove(struct device *dev) +static void tpm_nsc_remove(struct device *dev) { struct tpm_chip *chip = dev_get_drvdata(dev); if ( chip ) { diff --git a/drivers/char/tty_audit.c b/drivers/char/tty_audit.c index 7722466e052..6342b0534f4 100644 --- a/drivers/char/tty_audit.c +++ b/drivers/char/tty_audit.c @@ -92,7 +92,7 @@ static void tty_audit_buf_push(struct task_struct *tsk, uid_t loginuid, get_task_comm(name, tsk); audit_log_untrustedstring(ab, name); audit_log_format(ab, " data="); - audit_log_n_untrustedstring(ab, buf->valid, buf->data); + audit_log_n_untrustedstring(ab, buf->data, buf->valid); audit_log_end(ab); } buf->valid = 0; @@ -151,14 +151,9 @@ void tty_audit_fork(struct signal_struct *sig) /** * tty_audit_push_task - Flush task's pending audit data */ -void tty_audit_push_task(struct task_struct *tsk, uid_t loginuid) +void tty_audit_push_task(struct task_struct *tsk, uid_t loginuid, u32 sessionid) { struct tty_audit_buf *buf; - /* FIXME I think this is correct. Check against netlink once that is - * I really need to read this code more closely. But that's for - * another patch. - */ - unsigned int sessionid = audit_get_sessionid(tsk); spin_lock_irq(&tsk->sighand->siglock); buf = tsk->signal->tty_audit_buf; @@ -238,6 +233,10 @@ void tty_audit_add_data(struct tty_struct *tty, unsigned char *data, if (unlikely(size == 0)) return; + if (tty->driver->type == TTY_DRIVER_TYPE_PTY + && tty->driver->subtype == PTY_TYPE_MASTER) + return; + buf = tty_audit_buf_get(tty); if (!buf) return; @@ -300,53 +299,3 @@ void tty_audit_push(struct tty_struct *tty) tty_audit_buf_put(buf); } } - -/** - * tty_audit_opening - A TTY is being opened. - * - * As a special hack, tasks that close all their TTYs and open new ones - * are assumed to be system daemons (e.g. getty) and auditing is - * automatically disabled for them. - */ -void tty_audit_opening(void) -{ - int disable; - - disable = 1; - spin_lock_irq(¤t->sighand->siglock); - if (current->signal->audit_tty == 0) - disable = 0; - spin_unlock_irq(¤t->sighand->siglock); - if (!disable) - return; - - task_lock(current); - if (current->files) { - struct fdtable *fdt; - unsigned i; - - /* - * We don't take a ref to the file, so we must hold ->file_lock - * instead. - */ - spin_lock(¤t->files->file_lock); - fdt = files_fdtable(current->files); - for (i = 0; i < fdt->max_fds; i++) { - struct file *filp; - - filp = fcheck_files(current->files, i); - if (filp && is_tty(filp)) { - disable = 0; - break; - } - } - spin_unlock(¤t->files->file_lock); - } - task_unlock(current); - if (!disable) - return; - - spin_lock_irq(¤t->sighand->siglock); - current->signal->audit_tty = 0; - spin_unlock_irq(¤t->sighand->siglock); -} diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 4d3c7018f0c..2fa6856706a 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -1180,7 +1180,7 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line) if (*str == ',') str++; if (*str == '\0') - str = 0; + str = NULL; if (tty_line >= 0 && tty_line <= p->num && p->poll_init && !p->poll_init(p, tty_line, str)) { @@ -2755,7 +2755,6 @@ got_driver: __proc_set_tty(current, tty); spin_unlock_irq(¤t->sighand->siglock); mutex_unlock(&tty_mutex); - tty_audit_opening(); return 0; } @@ -2818,10 +2817,8 @@ static int ptmx_open(struct inode *inode, struct file *filp) check_tty_count(tty, "tty_open"); retval = ptm_driver->open(tty, filp); - if (!retval) { - tty_audit_opening(); + if (!retval) return 0; - } out1: release_dev(filp); return retval; diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c index db7a731e236..58aad63831f 100644 --- a/drivers/char/viotape.c +++ b/drivers/char/viotape.c @@ -249,6 +249,7 @@ static int proc_viotape_open(struct inode *inode, struct file *file) } static const struct file_operations proc_viotape_operations = { + .owner = THIS_MODULE, .open = proc_viotape_open, .read = seq_read, .llseek = seq_lseek, @@ -915,7 +916,6 @@ static struct vio_driver viotape_driver = { int __init viotap_init(void) { int ret; - struct proc_dir_entry *e; if (!firmware_has_feature(FW_FEATURE_ISERIES)) return -ENODEV; @@ -968,11 +968,8 @@ int __init viotap_init(void) if (ret) goto unreg_class; - e = create_proc_entry("iSeries/viotape", S_IFREG|S_IRUGO, NULL); - if (e) { - e->owner = THIS_MODULE; - e->proc_fops = &proc_viotape_operations; - } + proc_create("iSeries/viotape", S_IFREG|S_IRUGO, NULL, + &proc_viotape_operations); return 0; diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 9b58b894f82..1c266047713 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -301,7 +301,7 @@ static void scrup(struct vc_data *vc, unsigned int t, unsigned int b, int nr) d = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t); s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * (t + nr)); scr_memmovew(d, s, (b - t - nr) * vc->vc_size_row); - scr_memsetw(d + (b - t - nr) * vc->vc_cols, vc->vc_video_erase_char, + scr_memsetw(d + (b - t - nr) * vc->vc_cols, vc->vc_scrl_erase_char, vc->vc_size_row * nr); } @@ -319,7 +319,7 @@ static void scrdown(struct vc_data *vc, unsigned int t, unsigned int b, int nr) s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t); step = vc->vc_cols * nr; scr_memmovew(s + step, s, (b - t - nr) * vc->vc_size_row); - scr_memsetw(s, vc->vc_video_erase_char, 2 * step); + scr_memsetw(s, vc->vc_scrl_erase_char, 2 * step); } static void do_update_region(struct vc_data *vc, unsigned long start, int count) @@ -400,7 +400,7 @@ static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink, * Bit 7 : blink */ { - u8 a = vc->vc_color; + u8 a = _color; if (!vc->vc_can_do_color) return _intensity | (_italic ? 2 : 0) | @@ -434,6 +434,7 @@ static void update_attr(struct vc_data *vc) vc->vc_blink, vc->vc_underline, vc->vc_reverse ^ vc->vc_decscnm, vc->vc_italic); vc->vc_video_erase_char = (build_attr(vc, vc->vc_color, 1, vc->vc_blink, 0, vc->vc_decscnm, 0) << 8) | ' '; + vc->vc_scrl_erase_char = (build_attr(vc, vc->vc_def_color, 1, false, false, false, false) << 8) | ' '; } /* Note: inverting the screen twice should revert to the original state */ @@ -2054,6 +2055,7 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co unsigned long draw_from = 0, draw_to = 0; struct vc_data *vc; unsigned char vc_attr; + struct vt_notifier_param param; uint8_t rescan; uint8_t inverse; uint8_t width; @@ -2113,6 +2115,8 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co if (IS_FG(vc)) hide_cursor(vc); + param.vc = vc; + while (!tty->stopped && count) { int orig = *buf; c = orig; @@ -2201,6 +2205,11 @@ rescan_last_byte: tc = vc->vc_translate[vc->vc_toggle_meta ? (c | 0x80) : c]; } + param.c = tc; + if (atomic_notifier_call_chain(&vt_notifier_list, VT_PREWRITE, + ¶m) == NOTIFY_STOP) + continue; + /* If the original code was a control character we * only allow a glyph to be displayed if the code is * not normally used (such as for cursor movement) or diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index c159ae64eeb..5f076aef74f 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -69,6 +69,15 @@ config CPU_FREQ_DEFAULT_GOV_PERFORMANCE the frequency statically to the highest frequency supported by the CPU. +config CPU_FREQ_DEFAULT_GOV_POWERSAVE + bool "powersave" + depends on EMBEDDED + select CPU_FREQ_GOV_POWERSAVE + help + Use the CPUFreq governor 'powersave' as default. This sets + the frequency statically to the lowest frequency supported by + the CPU. + config CPU_FREQ_DEFAULT_GOV_USERSPACE bool "userspace" select CPU_FREQ_GOV_USERSPACE diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 35a26a3e5f6..7fce038fa57 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -118,9 +118,11 @@ static void handle_update(struct work_struct *work); static BLOCKING_NOTIFIER_HEAD(cpufreq_policy_notifier_list); static struct srcu_notifier_head cpufreq_transition_notifier_list; +static bool init_cpufreq_transition_notifier_list_called; static int __init init_cpufreq_transition_notifier_list(void) { srcu_init_notifier_head(&cpufreq_transition_notifier_list); + init_cpufreq_transition_notifier_list_called = true; return 0; } pure_initcall(init_cpufreq_transition_notifier_list); @@ -216,7 +218,7 @@ static void cpufreq_debug_disable_ratelimit(void) } void cpufreq_debug_printk(unsigned int type, const char *prefix, - const char *fmt, ...) + const char *fmt, ...) { char s[256]; va_list args; @@ -378,7 +380,7 @@ static struct cpufreq_governor *__find_governor(const char *str_governor) /** * cpufreq_parse_governor - parse a governor string */ -static int cpufreq_parse_governor (char *str_governor, unsigned int *policy, +static int cpufreq_parse_governor(char *str_governor, unsigned int *policy, struct cpufreq_governor **governor) { int err = -EINVAL; @@ -446,7 +448,7 @@ extern struct sysdev_class cpu_sysdev_class; #define show_one(file_name, object) \ static ssize_t show_##file_name \ -(struct cpufreq_policy * policy, char *buf) \ +(struct cpufreq_policy *policy, char *buf) \ { \ return sprintf (buf, "%u\n", policy->object); \ } @@ -465,7 +467,7 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data, */ #define store_one(file_name, object) \ static ssize_t store_##file_name \ -(struct cpufreq_policy * policy, const char *buf, size_t count) \ +(struct cpufreq_policy *policy, const char *buf, size_t count) \ { \ unsigned int ret = -EINVAL; \ struct cpufreq_policy new_policy; \ @@ -490,8 +492,8 @@ store_one(scaling_max_freq,max); /** * show_cpuinfo_cur_freq - current CPU frequency as detected by hardware */ -static ssize_t show_cpuinfo_cur_freq (struct cpufreq_policy * policy, - char *buf) +static ssize_t show_cpuinfo_cur_freq(struct cpufreq_policy *policy, + char *buf) { unsigned int cur_freq = __cpufreq_get(policy->cpu); if (!cur_freq) @@ -503,8 +505,7 @@ static ssize_t show_cpuinfo_cur_freq (struct cpufreq_policy * policy, /** * show_scaling_governor - show the current policy for the specified CPU */ -static ssize_t show_scaling_governor (struct cpufreq_policy * policy, - char *buf) +static ssize_t show_scaling_governor(struct cpufreq_policy *policy, char *buf) { if(policy->policy == CPUFREQ_POLICY_POWERSAVE) return sprintf(buf, "powersave\n"); @@ -519,8 +520,8 @@ static ssize_t show_scaling_governor (struct cpufreq_policy * policy, /** * store_scaling_governor - store policy for the specified CPU */ -static ssize_t store_scaling_governor (struct cpufreq_policy * policy, - const char *buf, size_t count) +static ssize_t store_scaling_governor(struct cpufreq_policy *policy, + const char *buf, size_t count) { unsigned int ret = -EINVAL; char str_governor[16]; @@ -554,7 +555,7 @@ static ssize_t store_scaling_governor (struct cpufreq_policy * policy, /** * show_scaling_driver - show the cpufreq driver currently loaded */ -static ssize_t show_scaling_driver (struct cpufreq_policy * policy, char *buf) +static ssize_t show_scaling_driver(struct cpufreq_policy *policy, char *buf) { return scnprintf(buf, CPUFREQ_NAME_LEN, "%s\n", cpufreq_driver->name); } @@ -562,8 +563,8 @@ static ssize_t show_scaling_driver (struct cpufreq_policy * policy, char *buf) /** * show_scaling_available_governors - show the available CPUfreq governors */ -static ssize_t show_scaling_available_governors (struct cpufreq_policy *policy, - char *buf) +static ssize_t show_scaling_available_governors(struct cpufreq_policy *policy, + char *buf) { ssize_t i = 0; struct cpufreq_governor *t; @@ -582,15 +583,13 @@ out: i += sprintf(&buf[i], "\n"); return i; } -/** - * show_affected_cpus - show the CPUs affected by each transition - */ -static ssize_t show_affected_cpus (struct cpufreq_policy * policy, char *buf) + +static ssize_t show_cpus(cpumask_t mask, char *buf) { ssize_t i = 0; unsigned int cpu; - for_each_cpu_mask(cpu, policy->cpus) { + for_each_cpu_mask(cpu, mask) { if (i) i += scnprintf(&buf[i], (PAGE_SIZE - i - 2), " "); i += scnprintf(&buf[i], (PAGE_SIZE - i - 2), "%u", cpu); @@ -601,8 +600,27 @@ static ssize_t show_affected_cpus (struct cpufreq_policy * policy, char *buf) return i; } +/** + * show_related_cpus - show the CPUs affected by each transition even if + * hw coordination is in use + */ +static ssize_t show_related_cpus(struct cpufreq_policy *policy, char *buf) +{ + if (cpus_empty(policy->related_cpus)) + return show_cpus(policy->cpus, buf); + return show_cpus(policy->related_cpus, buf); +} + +/** + * show_affected_cpus - show the CPUs affected by each transition + */ +static ssize_t show_affected_cpus(struct cpufreq_policy *policy, char *buf) +{ + return show_cpus(policy->cpus, buf); +} + static ssize_t store_scaling_setspeed(struct cpufreq_policy *policy, - const char *buf, size_t count) + const char *buf, size_t count) { unsigned int freq = 0; unsigned int ret; @@ -645,18 +663,20 @@ define_one_ro(cpuinfo_max_freq); define_one_ro(scaling_available_governors); define_one_ro(scaling_driver); define_one_ro(scaling_cur_freq); +define_one_ro(related_cpus); define_one_ro(affected_cpus); define_one_rw(scaling_min_freq); define_one_rw(scaling_max_freq); define_one_rw(scaling_governor); define_one_rw(scaling_setspeed); -static struct attribute * default_attrs[] = { +static struct attribute *default_attrs[] = { &cpuinfo_min_freq.attr, &cpuinfo_max_freq.attr, &scaling_min_freq.attr, &scaling_max_freq.attr, &affected_cpus.attr, + &related_cpus.attr, &scaling_governor.attr, &scaling_driver.attr, &scaling_available_governors.attr, @@ -667,10 +687,10 @@ static struct attribute * default_attrs[] = { #define to_policy(k) container_of(k,struct cpufreq_policy,kobj) #define to_attr(a) container_of(a,struct freq_attr,attr) -static ssize_t show(struct kobject * kobj, struct attribute * attr ,char * buf) +static ssize_t show(struct kobject *kobj, struct attribute *attr ,char *buf) { - struct cpufreq_policy * policy = to_policy(kobj); - struct freq_attr * fattr = to_attr(attr); + struct cpufreq_policy *policy = to_policy(kobj); + struct freq_attr *fattr = to_attr(attr); ssize_t ret = -EINVAL; policy = cpufreq_cpu_get(policy->cpu); if (!policy) @@ -691,11 +711,11 @@ no_policy: return ret; } -static ssize_t store(struct kobject * kobj, struct attribute * attr, - const char * buf, size_t count) +static ssize_t store(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t count) { - struct cpufreq_policy * policy = to_policy(kobj); - struct freq_attr * fattr = to_attr(attr); + struct cpufreq_policy *policy = to_policy(kobj); + struct freq_attr *fattr = to_attr(attr); ssize_t ret = -EINVAL; policy = cpufreq_cpu_get(policy->cpu); if (!policy) @@ -716,9 +736,9 @@ no_policy: return ret; } -static void cpufreq_sysfs_release(struct kobject * kobj) +static void cpufreq_sysfs_release(struct kobject *kobj) { - struct cpufreq_policy * policy = to_policy(kobj); + struct cpufreq_policy *policy = to_policy(kobj); dprintk("last reference is dropped\n"); complete(&policy->kobj_unregister); } @@ -740,7 +760,7 @@ static struct kobj_type ktype_cpufreq = { * * Adds the cpufreq interface for a CPU device. */ -static int cpufreq_add_dev (struct sys_device * sys_dev) +static int cpufreq_add_dev(struct sys_device *sys_dev) { unsigned int cpu = sys_dev->id; int ret = 0; @@ -800,7 +820,6 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) ret = cpufreq_driver->init(policy); if (ret) { dprintk("initialization failed\n"); - unlock_policy_rwsem_write(cpu); goto err_out; } policy->user_policy.min = policy->cpuinfo.min_freq; @@ -823,7 +842,7 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) /* check for existing affected CPUs. They may not be aware * of it due to CPU Hotplug. */ - managed_policy = cpufreq_cpu_get(j); + managed_policy = cpufreq_cpu_get(j); // FIXME: Where is this released? What about error paths? if (unlikely(managed_policy)) { /* Set proper policy_cpu */ @@ -842,14 +861,11 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) ret = sysfs_create_link(&sys_dev->kobj, &managed_policy->kobj, "cpufreq"); - if (ret) { - unlock_policy_rwsem_write(cpu); + if (ret) goto err_out_driver_exit; - } cpufreq_debug_enable_ratelimit(); ret = 0; - unlock_policy_rwsem_write(cpu); goto err_out_driver_exit; /* call driver->exit() */ } } @@ -859,33 +875,26 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) /* prepare interface data */ ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq, &sys_dev->kobj, "cpufreq"); - if (ret) { - unlock_policy_rwsem_write(cpu); + if (ret) goto err_out_driver_exit; - } + /* set up files for this cpu device */ drv_attr = cpufreq_driver->attr; while ((drv_attr) && (*drv_attr)) { ret = sysfs_create_file(&policy->kobj, &((*drv_attr)->attr)); - if (ret) { - unlock_policy_rwsem_write(cpu); + if (ret) goto err_out_driver_exit; - } drv_attr++; } - if (cpufreq_driver->get){ + if (cpufreq_driver->get) { ret = sysfs_create_file(&policy->kobj, &cpuinfo_cur_freq.attr); - if (ret) { - unlock_policy_rwsem_write(cpu); + if (ret) goto err_out_driver_exit; - } } - if (cpufreq_driver->target){ + if (cpufreq_driver->target) { ret = sysfs_create_file(&policy->kobj, &scaling_cur_freq.attr); - if (ret) { - unlock_policy_rwsem_write(cpu); + if (ret) goto err_out_driver_exit; - } } spin_lock_irqsave(&cpufreq_driver_lock, flags); @@ -907,10 +916,8 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) cpu_sys_dev = get_cpu_sysdev(j); ret = sysfs_create_link(&cpu_sys_dev->kobj, &policy->kobj, "cpufreq"); - if (ret) { - unlock_policy_rwsem_write(cpu); + if (ret) goto err_out_unregister; - } } policy->governor = NULL; /* to assure that the starting sequence is @@ -950,6 +957,7 @@ err_out_driver_exit: cpufreq_driver->exit(policy); err_out: + unlock_policy_rwsem_write(cpu); kfree(policy); nomem_out: @@ -967,7 +975,7 @@ module_out: * Caller should already have policy_rwsem in write mode for this CPU. * This routine frees the rwsem before returning. */ -static int __cpufreq_remove_dev (struct sys_device * sys_dev) +static int __cpufreq_remove_dev(struct sys_device *sys_dev) { unsigned int cpu = sys_dev->id; unsigned long flags; @@ -1071,7 +1079,7 @@ static int __cpufreq_remove_dev (struct sys_device * sys_dev) } -static int cpufreq_remove_dev (struct sys_device * sys_dev) +static int cpufreq_remove_dev(struct sys_device *sys_dev) { unsigned int cpu = sys_dev->id; int retval; @@ -1138,7 +1146,7 @@ unsigned int cpufreq_quick_get(unsigned int cpu) cpufreq_cpu_put(policy); } - return (ret_freq); + return ret_freq; } EXPORT_SYMBOL(cpufreq_quick_get); @@ -1149,7 +1157,7 @@ static unsigned int __cpufreq_get(unsigned int cpu) unsigned int ret_freq = 0; if (!cpufreq_driver->get) - return (ret_freq); + return ret_freq; ret_freq = cpufreq_driver->get(cpu); @@ -1163,7 +1171,7 @@ static unsigned int __cpufreq_get(unsigned int cpu) } } - return (ret_freq); + return ret_freq; } /** @@ -1190,7 +1198,7 @@ unsigned int cpufreq_get(unsigned int cpu) out_policy: cpufreq_cpu_put(policy); out: - return (ret_freq); + return ret_freq; } EXPORT_SYMBOL(cpufreq_get); @@ -1199,7 +1207,7 @@ EXPORT_SYMBOL(cpufreq_get); * cpufreq_suspend - let the low level driver prepare for suspend */ -static int cpufreq_suspend(struct sys_device * sysdev, pm_message_t pmsg) +static int cpufreq_suspend(struct sys_device *sysdev, pm_message_t pmsg) { int cpu = sysdev->id; int ret = 0; @@ -1221,22 +1229,18 @@ static int cpufreq_suspend(struct sys_device * sysdev, pm_message_t pmsg) return -EINVAL; /* only handle each CPU group once */ - if (unlikely(cpu_policy->cpu != cpu)) { - cpufreq_cpu_put(cpu_policy); - return 0; - } + if (unlikely(cpu_policy->cpu != cpu)) + goto out; if (cpufreq_driver->suspend) { ret = cpufreq_driver->suspend(cpu_policy, pmsg); if (ret) { printk(KERN_ERR "cpufreq: suspend failed in ->suspend " "step on CPU %u\n", cpu_policy->cpu); - cpufreq_cpu_put(cpu_policy); - return ret; + goto out; } } - if (cpufreq_driver->flags & CPUFREQ_CONST_LOOPS) goto out; @@ -1270,7 +1274,7 @@ static int cpufreq_suspend(struct sys_device * sysdev, pm_message_t pmsg) out: cpufreq_cpu_put(cpu_policy); - return 0; + return ret; } /** @@ -1281,7 +1285,7 @@ out: * 3.) schedule call cpufreq_update_policy() ASAP as interrupts are * restored. */ -static int cpufreq_resume(struct sys_device * sysdev) +static int cpufreq_resume(struct sys_device *sysdev) { int cpu = sysdev->id; int ret = 0; @@ -1302,18 +1306,15 @@ static int cpufreq_resume(struct sys_device * sysdev) return -EINVAL; /* only handle each CPU group once */ - if (unlikely(cpu_policy->cpu != cpu)) { - cpufreq_cpu_put(cpu_policy); - return 0; - } + if (unlikely(cpu_policy->cpu != cpu)) + goto fail; if (cpufreq_driver->resume) { ret = cpufreq_driver->resume(cpu_policy); if (ret) { printk(KERN_ERR "cpufreq: resume failed in ->resume " "step on CPU %u\n", cpu_policy->cpu); - cpufreq_cpu_put(cpu_policy); - return ret; + goto fail; } } @@ -1353,6 +1354,7 @@ static int cpufreq_resume(struct sys_device * sysdev) out: schedule_work(&cpu_policy->update); +fail: cpufreq_cpu_put(cpu_policy); return ret; } @@ -1386,6 +1388,8 @@ int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list) { int ret; + WARN_ON(!init_cpufreq_transition_notifier_list_called); + switch (list) { case CPUFREQ_TRANSITION_NOTIFIER: ret = srcu_notifier_chain_register( @@ -1848,7 +1852,7 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data) cpufreq_debug_enable_ratelimit(); } - return (ret); + return ret; } EXPORT_SYMBOL_GPL(cpufreq_register_driver); diff --git a/drivers/cpufreq/cpufreq_powersave.c b/drivers/cpufreq/cpufreq_powersave.c index 13fe06b94b0..88d2f44fba4 100644 --- a/drivers/cpufreq/cpufreq_powersave.c +++ b/drivers/cpufreq/cpufreq_powersave.c @@ -35,12 +35,12 @@ static int cpufreq_governor_powersave(struct cpufreq_policy *policy, return 0; } -static struct cpufreq_governor cpufreq_gov_powersave = { +struct cpufreq_governor cpufreq_gov_powersave = { .name = "powersave", .governor = cpufreq_governor_powersave, .owner = THIS_MODULE, }; - +EXPORT_SYMBOL(cpufreq_gov_powersave); static int __init cpufreq_gov_powersave_init(void) { @@ -58,5 +58,9 @@ MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>"); MODULE_DESCRIPTION("CPUfreq policy governor 'powersave'"); MODULE_LICENSE("GPL"); +#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE +fs_initcall(cpufreq_gov_powersave_init); +#else module_init(cpufreq_gov_powersave_init); +#endif module_exit(cpufreq_gov_powersave_exit); diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 070421a5480..ae70d63a8b2 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -114,7 +114,7 @@ show_trans_table(struct cpufreq_policy *policy, char *buf) stat->freq_table[i]); } if (len >= PAGE_SIZE) - return len; + return PAGE_SIZE; len += snprintf(buf + len, PAGE_SIZE - len, "\n"); @@ -131,8 +131,12 @@ show_trans_table(struct cpufreq_policy *policy, char *buf) len += snprintf(buf + len, PAGE_SIZE - len, "%9u ", stat->trans_table[i*stat->max_state+j]); } + if (len >= PAGE_SIZE) + break; len += snprintf(buf + len, PAGE_SIZE - len, "\n"); } + if (len >= PAGE_SIZE) + return PAGE_SIZE; return len; } CPUFREQ_STATDEVICE_ATTR(trans_table,0444,show_trans_table); @@ -284,7 +288,7 @@ cpufreq_stat_notifier_trans (struct notifier_block *nb, unsigned long val, if (!stat) return 0; - old_index = freq_table_get_index(stat, freq->old); + old_index = stat->last_index; new_index = freq_table_get_index(stat, freq->new); cpufreq_stats_update(freq->cpu); diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index 2b382990fe5..6e6c3c4aea6 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -67,7 +67,7 @@ config EDAC_E7XXX E7205, E7500, E7501 and E7505 server chipsets. config EDAC_E752X - tristate "Intel e752x (e7520, e7525, e7320)" + tristate "Intel e752x (e7520, e7525, e7320) and 3100" depends on EDAC_MM_EDAC && PCI && X86 && HOTPLUG help Support for error detection and correction on the Intel diff --git a/drivers/edac/amd76x_edac.c b/drivers/edac/amd76x_edac.c index f2207541059..2b95f1a3edf 100644 --- a/drivers/edac/amd76x_edac.c +++ b/drivers/edac/amd76x_edac.c @@ -17,6 +17,7 @@ #include <linux/pci.h> #include <linux/pci_ids.h> #include <linux/slab.h> +#include <linux/edac.h> #include "edac_core.h" #define AMD76X_REVISION " Ver: 2.0.2 " __DATE__ @@ -344,6 +345,9 @@ static struct pci_driver amd76x_driver = { static int __init amd76x_init(void) { + /* Ensure that the OPSTATE is set correctly for POLL or NMI */ + opstate_init(); + return pci_register_driver(&amd76x_driver); } @@ -358,3 +362,6 @@ module_exit(amd76x_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh"); MODULE_DESCRIPTION("MC support for AMD 76x memory controllers"); + +module_param(edac_op_state, int, 0444); +MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI"); diff --git a/drivers/edac/e752x_edac.c b/drivers/edac/e752x_edac.c index 6eb434749cd..c94a0eb492c 100644 --- a/drivers/edac/e752x_edac.c +++ b/drivers/edac/e752x_edac.c @@ -29,6 +29,7 @@ #define EDAC_MOD_STR "e752x_edac" static int force_function_unhide; +static int sysbus_parity = -1; static struct edac_pci_ctl_info *e752x_pci; @@ -62,6 +63,14 @@ static struct edac_pci_ctl_info *e752x_pci; #define PCI_DEVICE_ID_INTEL_7320_1_ERR 0x3593 #endif /* PCI_DEVICE_ID_INTEL_7320_1_ERR */ +#ifndef PCI_DEVICE_ID_INTEL_3100_0 +#define PCI_DEVICE_ID_INTEL_3100_0 0x35B0 +#endif /* PCI_DEVICE_ID_INTEL_3100_0 */ + +#ifndef PCI_DEVICE_ID_INTEL_3100_1_ERR +#define PCI_DEVICE_ID_INTEL_3100_1_ERR 0x35B1 +#endif /* PCI_DEVICE_ID_INTEL_3100_1_ERR */ + #define E752X_NR_CSROWS 8 /* number of csrows */ /* E752X register addresses - device 0 function 0 */ @@ -152,6 +161,12 @@ static struct edac_pci_ctl_info *e752x_pci; /* error syndrome register (16b) */ #define E752X_DEVPRES1 0xF4 /* Device Present 1 register (8b) */ +/* 3100 IMCH specific register addresses - device 0 function 1 */ +#define I3100_NSI_FERR 0x48 /* NSI first error reg (32b) */ +#define I3100_NSI_NERR 0x4C /* NSI next error reg (32b) */ +#define I3100_NSI_SMICMD 0x54 /* NSI SMI command register (32b) */ +#define I3100_NSI_EMASK 0x90 /* NSI error mask register (32b) */ + /* ICH5R register addresses - device 30 function 0 */ #define ICH5R_PCI_STAT 0x06 /* PCI status register (16b) */ #define ICH5R_PCI_2ND_STAT 0x1E /* PCI status secondary reg (16b) */ @@ -160,7 +175,8 @@ static struct edac_pci_ctl_info *e752x_pci; enum e752x_chips { E7520 = 0, E7525 = 1, - E7320 = 2 + E7320 = 2, + I3100 = 3 }; struct e752x_pvt { @@ -185,8 +201,10 @@ struct e752x_dev_info { struct e752x_error_info { u32 ferr_global; u32 nerr_global; - u8 hi_ferr; - u8 hi_nerr; + u32 nsi_ferr; /* 3100 only */ + u32 nsi_nerr; /* 3100 only */ + u8 hi_ferr; /* all but 3100 */ + u8 hi_nerr; /* all but 3100 */ u16 sysbus_ferr; u16 sysbus_nerr; u8 buf_ferr; @@ -215,6 +233,10 @@ static const struct e752x_dev_info e752x_devs[] = { .err_dev = PCI_DEVICE_ID_INTEL_7320_1_ERR, .ctl_dev = PCI_DEVICE_ID_INTEL_7320_0, .ctl_name = "E7320"}, + [I3100] = { + .err_dev = PCI_DEVICE_ID_INTEL_3100_1_ERR, + .ctl_dev = PCI_DEVICE_ID_INTEL_3100_0, + .ctl_name = "3100"}, }; static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci, @@ -402,7 +424,7 @@ static inline void process_threshold_ce(struct mem_ctl_info *mci, u16 error, static char *global_message[11] = { "PCI Express C1", "PCI Express C", "PCI Express B1", "PCI Express B", "PCI Express A1", "PCI Express A", - "DMA Controler", "HUB Interface", "System Bus", + "DMA Controler", "HUB or NS Interface", "System Bus", "DRAM Controler", "Internal Buffer" }; @@ -455,6 +477,63 @@ static inline void hub_error(int fatal, u8 errors, int *error_found, do_hub_error(fatal, errors); } +#define NSI_FATAL_MASK 0x0c080081 +#define NSI_NON_FATAL_MASK 0x23a0ba64 +#define NSI_ERR_MASK (NSI_FATAL_MASK | NSI_NON_FATAL_MASK) + +static char *nsi_message[30] = { + "NSI Link Down", /* NSI_FERR/NSI_NERR bit 0, fatal error */ + "", /* reserved */ + "NSI Parity Error", /* bit 2, non-fatal */ + "", /* reserved */ + "", /* reserved */ + "Correctable Error Message", /* bit 5, non-fatal */ + "Non-Fatal Error Message", /* bit 6, non-fatal */ + "Fatal Error Message", /* bit 7, fatal */ + "", /* reserved */ + "Receiver Error", /* bit 9, non-fatal */ + "", /* reserved */ + "Bad TLP", /* bit 11, non-fatal */ + "Bad DLLP", /* bit 12, non-fatal */ + "REPLAY_NUM Rollover", /* bit 13, non-fatal */ + "", /* reserved */ + "Replay Timer Timeout", /* bit 15, non-fatal */ + "", /* reserved */ + "", /* reserved */ + "", /* reserved */ + "Data Link Protocol Error", /* bit 19, fatal */ + "", /* reserved */ + "Poisoned TLP", /* bit 21, non-fatal */ + "", /* reserved */ + "Completion Timeout", /* bit 23, non-fatal */ + "Completer Abort", /* bit 24, non-fatal */ + "Unexpected Completion", /* bit 25, non-fatal */ + "Receiver Overflow", /* bit 26, fatal */ + "Malformed TLP", /* bit 27, fatal */ + "", /* reserved */ + "Unsupported Request" /* bit 29, non-fatal */ +}; + +static void do_nsi_error(int fatal, u32 errors) +{ + int i; + + for (i = 0; i < 30; i++) { + if (errors & (1 << i)) + printk(KERN_WARNING "%sError %s\n", + fatal_message[fatal], nsi_message[i]); + } +} + +static inline void nsi_error(int fatal, u32 errors, int *error_found, + int handle_error) +{ + *error_found = 1; + + if (handle_error) + do_nsi_error(fatal, errors); +} + static char *membuf_message[4] = { "Internal PMWB to DRAM parity", "Internal PMWB to System Bus Parity", @@ -546,6 +625,31 @@ static void e752x_check_hub_interface(struct e752x_error_info *info, } } +static void e752x_check_ns_interface(struct e752x_error_info *info, + int *error_found, int handle_error) +{ + u32 stat32; + + stat32 = info->nsi_ferr; + if (stat32 & NSI_ERR_MASK) { /* Error, so process */ + if (stat32 & NSI_FATAL_MASK) /* check for fatal errors */ + nsi_error(1, stat32 & NSI_FATAL_MASK, error_found, + handle_error); + if (stat32 & NSI_NON_FATAL_MASK) /* check for non-fatal ones */ + nsi_error(0, stat32 & NSI_NON_FATAL_MASK, error_found, + handle_error); + } + stat32 = info->nsi_nerr; + if (stat32 & NSI_ERR_MASK) { + if (stat32 & NSI_FATAL_MASK) + nsi_error(1, stat32 & NSI_FATAL_MASK, error_found, + handle_error); + if (stat32 & NSI_NON_FATAL_MASK) + nsi_error(0, stat32 & NSI_NON_FATAL_MASK, error_found, + handle_error); + } +} + static void e752x_check_sysbus(struct e752x_error_info *info, int *error_found, int handle_error) { @@ -653,7 +757,15 @@ static void e752x_get_error_info(struct mem_ctl_info *mci, pci_read_config_dword(dev, E752X_FERR_GLOBAL, &info->ferr_global); if (info->ferr_global) { - pci_read_config_byte(dev, E752X_HI_FERR, &info->hi_ferr); + if (pvt->dev_info->err_dev == PCI_DEVICE_ID_INTEL_3100_1_ERR) { + pci_read_config_dword(dev, I3100_NSI_FERR, + &info->nsi_ferr); + info->hi_ferr = 0; + } else { + pci_read_config_byte(dev, E752X_HI_FERR, + &info->hi_ferr); + info->nsi_ferr = 0; + } pci_read_config_word(dev, E752X_SYSBUS_FERR, &info->sysbus_ferr); pci_read_config_byte(dev, E752X_BUF_FERR, &info->buf_ferr); @@ -669,10 +781,15 @@ static void e752x_get_error_info(struct mem_ctl_info *mci, pci_read_config_dword(dev, E752X_DRAM_RETR_ADD, &info->dram_retr_add); + /* ignore the reserved bits just in case */ if (info->hi_ferr & 0x7f) pci_write_config_byte(dev, E752X_HI_FERR, info->hi_ferr); + if (info->nsi_ferr & NSI_ERR_MASK) + pci_write_config_dword(dev, I3100_NSI_FERR, + info->nsi_ferr); + if (info->sysbus_ferr) pci_write_config_word(dev, E752X_SYSBUS_FERR, info->sysbus_ferr); @@ -692,7 +809,15 @@ static void e752x_get_error_info(struct mem_ctl_info *mci, pci_read_config_dword(dev, E752X_NERR_GLOBAL, &info->nerr_global); if (info->nerr_global) { - pci_read_config_byte(dev, E752X_HI_NERR, &info->hi_nerr); + if (pvt->dev_info->err_dev == PCI_DEVICE_ID_INTEL_3100_1_ERR) { + pci_read_config_dword(dev, I3100_NSI_NERR, + &info->nsi_nerr); + info->hi_nerr = 0; + } else { + pci_read_config_byte(dev, E752X_HI_NERR, + &info->hi_nerr); + info->nsi_nerr = 0; + } pci_read_config_word(dev, E752X_SYSBUS_NERR, &info->sysbus_nerr); pci_read_config_byte(dev, E752X_BUF_NERR, &info->buf_nerr); @@ -706,6 +831,10 @@ static void e752x_get_error_info(struct mem_ctl_info *mci, pci_write_config_byte(dev, E752X_HI_NERR, info->hi_nerr); + if (info->nsi_nerr & NSI_ERR_MASK) + pci_write_config_dword(dev, I3100_NSI_NERR, + info->nsi_nerr); + if (info->sysbus_nerr) pci_write_config_word(dev, E752X_SYSBUS_NERR, info->sysbus_nerr); @@ -750,6 +879,7 @@ static int e752x_process_error_info(struct mem_ctl_info *mci, global_error(0, stat32, &error_found, handle_errors); e752x_check_hub_interface(info, &error_found, handle_errors); + e752x_check_ns_interface(info, &error_found, handle_errors); e752x_check_sysbus(info, &error_found, handle_errors); e752x_check_membuf(info, &error_found, handle_errors); e752x_check_dram(mci, info, &error_found, handle_errors); @@ -920,15 +1050,53 @@ fail: return 1; } +/* Setup system bus parity mask register. + * Sysbus parity supported on: + * e7320/e7520/e7525 + Xeon + * i3100 + Xeon/Celeron + * Sysbus parity not supported on: + * i3100 + Pentium M/Celeron M/Core Duo/Core2 Duo + */ +static void e752x_init_sysbus_parity_mask(struct e752x_pvt *pvt) +{ + char *cpu_id = cpu_data(0).x86_model_id; + struct pci_dev *dev = pvt->dev_d0f1; + int enable = 1; + + /* Allow module paramter override, else see if CPU supports parity */ + if (sysbus_parity != -1) { + enable = sysbus_parity; + } else if (cpu_id[0] && + ((strstr(cpu_id, "Pentium") && strstr(cpu_id, " M ")) || + (strstr(cpu_id, "Celeron") && strstr(cpu_id, " M ")) || + (strstr(cpu_id, "Core") && strstr(cpu_id, "Duo")))) { + e752x_printk(KERN_INFO, "System Bus Parity not " + "supported by CPU, disabling\n"); + enable = 0; + } + + if (enable) + pci_write_config_word(dev, E752X_SYSBUS_ERRMASK, 0x0000); + else + pci_write_config_word(dev, E752X_SYSBUS_ERRMASK, 0x0309); +} + static void e752x_init_error_reporting_regs(struct e752x_pvt *pvt) { struct pci_dev *dev; dev = pvt->dev_d0f1; /* Turn off error disable & SMI in case the BIOS turned it on */ - pci_write_config_byte(dev, E752X_HI_ERRMASK, 0x00); - pci_write_config_byte(dev, E752X_HI_SMICMD, 0x00); - pci_write_config_word(dev, E752X_SYSBUS_ERRMASK, 0x00); + if (pvt->dev_info->err_dev == PCI_DEVICE_ID_INTEL_3100_1_ERR) { + pci_write_config_dword(dev, I3100_NSI_EMASK, 0); + pci_write_config_dword(dev, I3100_NSI_SMICMD, 0); + } else { + pci_write_config_byte(dev, E752X_HI_ERRMASK, 0x00); + pci_write_config_byte(dev, E752X_HI_SMICMD, 0x00); + } + + e752x_init_sysbus_parity_mask(pvt); + pci_write_config_word(dev, E752X_SYSBUS_SMICMD, 0x00); pci_write_config_byte(dev, E752X_BUF_ERRMASK, 0x00); pci_write_config_byte(dev, E752X_BUF_SMICMD, 0x00); @@ -949,16 +1117,6 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx) debugf0("%s(): mci\n", __func__); debugf0("Starting Probe1\n"); - /* make sure error reporting method is sane */ - switch (edac_op_state) { - case EDAC_OPSTATE_POLL: - case EDAC_OPSTATE_NMI: - break; - default: - edac_op_state = EDAC_OPSTATE_POLL; - break; - } - /* check to see if device 0 function 1 is enabled; if it isn't, we * assume the BIOS has reserved it for a reason and is expecting * exclusive access, we take care not to violate that assumption and @@ -985,8 +1143,9 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx) debugf3("%s(): init mci\n", __func__); mci->mtype_cap = MEM_FLAG_RDDR; - mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED | - EDAC_FLAG_S4ECD4ED; + /* 3100 IMCH supports SECDEC only */ + mci->edac_ctl_cap = (dev_idx == I3100) ? EDAC_FLAG_SECDED : + (EDAC_FLAG_NONE | EDAC_FLAG_SECDED | EDAC_FLAG_S4ECD4ED); /* FIXME - what if different memory types are in different csrows? */ mci->mod_name = EDAC_MOD_STR; mci->mod_ver = E752X_REVISION; @@ -1018,7 +1177,10 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx) e752x_init_csrows(mci, pdev, ddrcsr); e752x_init_mem_map_table(pdev, pvt); - mci->edac_cap |= EDAC_FLAG_NONE; + if (dev_idx == I3100) + mci->edac_cap = EDAC_FLAG_SECDED; /* the only mode supported */ + else + mci->edac_cap |= EDAC_FLAG_NONE; debugf3("%s(): tolm, remapbase, remaplimit\n", __func__); /* load the top of low memory, remap base, and remap limit vars */ @@ -1110,6 +1272,9 @@ static const struct pci_device_id e752x_pci_tbl[] __devinitdata = { PCI_VEND_DEV(INTEL, 7320_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, E7320}, { + PCI_VEND_DEV(INTEL, 3100_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, + I3100}, + { 0, } /* 0 terminated list. */ }; @@ -1128,6 +1293,10 @@ static int __init e752x_init(void) int pci_rc; debugf3("%s()\n", __func__); + + /* Ensure that the OPSTATE is set correctly for POLL or NMI */ + opstate_init(); + pci_rc = pci_register_driver(&e752x_driver); return (pci_rc < 0) ? pci_rc : 0; } @@ -1143,10 +1312,15 @@ module_exit(e752x_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Linux Networx (http://lnxi.com) Tom Zimmerman\n"); -MODULE_DESCRIPTION("MC support for Intel e752x memory controllers"); +MODULE_DESCRIPTION("MC support for Intel e752x/3100 memory controllers"); module_param(force_function_unhide, int, 0444); MODULE_PARM_DESC(force_function_unhide, "if BIOS sets Dev0:Fun1 up as hidden:" " 1=force unhide and hope BIOS doesn't fight driver for Dev0:Fun1 access"); + module_param(edac_op_state, int, 0444); MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI"); + +module_param(sysbus_parity, int, 0444); +MODULE_PARM_DESC(sysbus_parity, "0=disable system bus parity checking," + " 1=enable system bus parity checking, default=auto-detect"); diff --git a/drivers/edac/e7xxx_edac.c b/drivers/edac/e7xxx_edac.c index 96ecc492664..c7d11cc4e21 100644 --- a/drivers/edac/e7xxx_edac.c +++ b/drivers/edac/e7xxx_edac.c @@ -414,16 +414,6 @@ static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx) debugf0("%s(): mci\n", __func__); - /* make sure error reporting method is sane */ - switch (edac_op_state) { - case EDAC_OPSTATE_POLL: - case EDAC_OPSTATE_NMI: - break; - default: - edac_op_state = EDAC_OPSTATE_POLL; - break; - } - pci_read_config_dword(pdev, E7XXX_DRC, &drc); drc_chan = dual_channel_active(drc, dev_idx); @@ -565,6 +555,9 @@ static struct pci_driver e7xxx_driver = { static int __init e7xxx_init(void) { + /* Ensure that the OPSTATE is set correctly for POLL or NMI */ + opstate_init(); + return pci_register_driver(&e7xxx_driver); } diff --git a/drivers/edac/edac_device.c b/drivers/edac/edac_device.c index b9552bc03de..63372fa7ecf 100644 --- a/drivers/edac/edac_device.c +++ b/drivers/edac/edac_device.c @@ -36,7 +36,7 @@ * is protected by the 'device_ctls_mutex' lock */ static DEFINE_MUTEX(device_ctls_mutex); -static struct list_head edac_device_list = LIST_HEAD_INIT(edac_device_list); +static LIST_HEAD(edac_device_list); #ifdef CONFIG_EDAC_DEBUG static void edac_device_dump_device(struct edac_device_ctl_info *edac_dev) @@ -375,37 +375,6 @@ static void del_edac_device_from_global_list(struct edac_device_ctl_info wait_for_completion(&edac_device->removal_complete); } -/** - * edac_device_find - * Search for a edac_device_ctl_info structure whose index is 'idx'. - * - * If found, return a pointer to the structure. - * Else return NULL. - * - * Caller must hold device_ctls_mutex. - */ -struct edac_device_ctl_info *edac_device_find(int idx) -{ - struct list_head *item; - struct edac_device_ctl_info *edac_dev; - - /* Iterate over list, looking for exact match of ID */ - list_for_each(item, &edac_device_list) { - edac_dev = list_entry(item, struct edac_device_ctl_info, link); - - if (edac_dev->dev_idx >= idx) { - if (edac_dev->dev_idx == idx) - return edac_dev; - - /* not on list, so terminate early */ - break; - } - } - - return NULL; -} -EXPORT_SYMBOL_GPL(edac_device_find); - /* * edac_device_workq_function * performs the operation scheduled by a workq request diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index 063a1bffe38..a4cf1645f58 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c @@ -36,7 +36,7 @@ /* lock to memory controller's control array */ static DEFINE_MUTEX(mem_ctls_mutex); -static struct list_head mc_devices = LIST_HEAD_INIT(mc_devices); +static LIST_HEAD(mc_devices); #ifdef CONFIG_EDAC_DEBUG @@ -886,24 +886,3 @@ void edac_mc_handle_fbd_ce(struct mem_ctl_info *mci, mci->csrows[csrow].channels[channel].ce_count++; } EXPORT_SYMBOL(edac_mc_handle_fbd_ce); - -/* - * Iterate over all MC instances and check for ECC, et al, errors - */ -void edac_check_mc_devices(void) -{ - struct list_head *item; - struct mem_ctl_info *mci; - - debugf3("%s()\n", __func__); - mutex_lock(&mem_ctls_mutex); - - list_for_each(item, &mc_devices) { - mci = list_entry(item, struct mem_ctl_info, link); - - if (mci->edac_check != NULL) - mci->edac_check(mci); - } - - mutex_unlock(&mem_ctls_mutex); -} diff --git a/drivers/edac/edac_module.h b/drivers/edac/edac_module.h index cbc419c8ebc..233d4798c3a 100644 --- a/drivers/edac/edac_module.h +++ b/drivers/edac/edac_module.h @@ -27,7 +27,6 @@ extern int edac_mc_register_sysfs_main_kobj(struct mem_ctl_info *mci); extern void edac_mc_unregister_sysfs_main_kobj(struct mem_ctl_info *mci); extern int edac_create_sysfs_mci_device(struct mem_ctl_info *mci); extern void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci); -extern void edac_check_mc_devices(void); extern int edac_get_log_ue(void); extern int edac_get_log_ce(void); extern int edac_get_panic_on_ue(void); diff --git a/drivers/edac/edac_pci.c b/drivers/edac/edac_pci.c index 32be43576a8..9b24340b52e 100644 --- a/drivers/edac/edac_pci.c +++ b/drivers/edac/edac_pci.c @@ -29,7 +29,7 @@ #include "edac_module.h" static DEFINE_MUTEX(edac_pci_ctls_mutex); -static struct list_head edac_pci_list = LIST_HEAD_INIT(edac_pci_list); +static LIST_HEAD(edac_pci_list); /* * edac_pci_alloc_ctl_info @@ -189,6 +189,9 @@ static void del_edac_pci_from_global_list(struct edac_pci_ctl_info *pci) wait_for_completion(&pci->complete); } +#if 0 +/* Older code, but might use in the future */ + /* * edac_pci_find() * Search for an edac_pci_ctl_info structure whose index is 'idx' @@ -219,6 +222,7 @@ struct edac_pci_ctl_info *edac_pci_find(int idx) return NULL; } EXPORT_SYMBOL_GPL(edac_pci_find); +#endif /* * edac_pci_workq_function() @@ -422,7 +426,7 @@ EXPORT_SYMBOL_GPL(edac_pci_del_device); * * a Generic parity check API */ -void edac_pci_generic_check(struct edac_pci_ctl_info *pci) +static void edac_pci_generic_check(struct edac_pci_ctl_info *pci) { debugf4("%s()\n", __func__); edac_pci_do_parity_check(); diff --git a/drivers/edac/edac_pci_sysfs.c b/drivers/edac/edac_pci_sysfs.c index 71c3195d370..2c1fa1bb6df 100644 --- a/drivers/edac/edac_pci_sysfs.c +++ b/drivers/edac/edac_pci_sysfs.c @@ -37,17 +37,17 @@ int edac_pci_get_check_errors(void) return check_pci_errors; } -int edac_pci_get_log_pe(void) +static int edac_pci_get_log_pe(void) { return edac_pci_log_pe; } -int edac_pci_get_log_npe(void) +static int edac_pci_get_log_npe(void) { return edac_pci_log_npe; } -int edac_pci_get_panic_on_pe(void) +static int edac_pci_get_panic_on_pe(void) { return edac_pci_panic_on_pe; } @@ -197,7 +197,8 @@ error_out: * * unregister the kobj for the EDAC PCI instance */ -void edac_pci_unregister_sysfs_instance_kobj(struct edac_pci_ctl_info *pci) +static void edac_pci_unregister_sysfs_instance_kobj( + struct edac_pci_ctl_info *pci) { debugf0("%s()\n", __func__); @@ -337,7 +338,7 @@ static struct kobj_type ktype_edac_pci_main_kobj = { * setup the sysfs for EDAC PCI attributes * assumes edac_class has already been initialized */ -int edac_pci_main_kobj_setup(void) +static int edac_pci_main_kobj_setup(void) { int err; struct sysdev_class *edac_class; diff --git a/drivers/edac/i3000_edac.c b/drivers/edac/i3000_edac.c index 5d4292811c1..6c9a0f2a593 100644 --- a/drivers/edac/i3000_edac.c +++ b/drivers/edac/i3000_edac.c @@ -326,15 +326,6 @@ static int i3000_probe1(struct pci_dev *pdev, int dev_idx) return -ENODEV; } - switch (edac_op_state) { - case EDAC_OPSTATE_POLL: - case EDAC_OPSTATE_NMI: - break; - default: - edac_op_state = EDAC_OPSTATE_POLL; - break; - } - c0dra[0] = readb(window + I3000_C0DRA + 0); /* ranks 0,1 */ c0dra[1] = readb(window + I3000_C0DRA + 1); /* ranks 2,3 */ c1dra[0] = readb(window + I3000_C1DRA + 0); /* ranks 0,1 */ @@ -503,6 +494,10 @@ static int __init i3000_init(void) int pci_rc; debugf3("MC: %s()\n", __func__); + + /* Ensure that the OPSTATE is set correctly for POLL or NMI */ + opstate_init(); + pci_rc = pci_register_driver(&i3000_driver); if (pci_rc < 0) goto fail0; diff --git a/drivers/edac/i5000_edac.c b/drivers/edac/i5000_edac.c index 5a852017c17..4a16b5b61cf 100644 --- a/drivers/edac/i5000_edac.c +++ b/drivers/edac/i5000_edac.c @@ -1286,16 +1286,6 @@ static int i5000_probe1(struct pci_dev *pdev, int dev_idx) if (PCI_FUNC(pdev->devfn) != 0) return -ENODEV; - /* make sure error reporting method is sane */ - switch (edac_op_state) { - case EDAC_OPSTATE_POLL: - case EDAC_OPSTATE_NMI: - break; - default: - edac_op_state = EDAC_OPSTATE_POLL; - break; - } - /* Ask the devices for the number of CSROWS and CHANNELS so * that we can calculate the memory resources, etc * @@ -1478,6 +1468,9 @@ static int __init i5000_init(void) debugf2("MC: " __FILE__ ": %s()\n", __func__); + /* Ensure that the OPSTATE is set correctly for POLL or NMI */ + opstate_init(); + pci_rc = pci_register_driver(&i5000_driver); return (pci_rc < 0) ? pci_rc : 0; @@ -1501,5 +1494,6 @@ MODULE_AUTHOR ("Linux Networx (http://lnxi.com) Doug Thompson <norsk5@xmission.com>"); MODULE_DESCRIPTION("MC Driver for Intel I5000 memory controllers - " I5000_REVISION); + module_param(edac_op_state, int, 0444); MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI"); diff --git a/drivers/edac/i82443bxgx_edac.c b/drivers/edac/i82443bxgx_edac.c index 83bfe37c4bb..c5305e3ee43 100644 --- a/drivers/edac/i82443bxgx_edac.c +++ b/drivers/edac/i82443bxgx_edac.c @@ -29,6 +29,7 @@ #include <linux/slab.h> +#include <linux/edac.h> #include "edac_core.h" #define I82443_REVISION "0.1" @@ -386,6 +387,9 @@ static struct pci_driver i82443bxgx_edacmc_driver = { static int __init i82443bxgx_edacmc_init(void) { + /* Ensure that the OPSTATE is set correctly for POLL or NMI */ + opstate_init(); + return pci_register_driver(&i82443bxgx_edacmc_driver); } @@ -400,3 +404,6 @@ module_exit(i82443bxgx_edacmc_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Tim Small <tim@buttersideup.com> - WPAD"); MODULE_DESCRIPTION("EDAC MC support for Intel 82443BX/GX memory controllers"); + +module_param(edac_op_state, int, 0444); +MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI"); diff --git a/drivers/edac/i82860_edac.c b/drivers/edac/i82860_edac.c index f5ecd2c4d81..c0088ba9672 100644 --- a/drivers/edac/i82860_edac.c +++ b/drivers/edac/i82860_edac.c @@ -14,6 +14,7 @@ #include <linux/pci.h> #include <linux/pci_ids.h> #include <linux/slab.h> +#include <linux/edac.h> #include "edac_core.h" #define I82860_REVISION " Ver: 2.0.2 " __DATE__ @@ -294,6 +295,9 @@ static int __init i82860_init(void) debugf3("%s()\n", __func__); + /* Ensure that the OPSTATE is set correctly for POLL or NMI */ + opstate_init(); + if ((pci_rc = pci_register_driver(&i82860_driver)) < 0) goto fail0; @@ -345,3 +349,6 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com) " "Ben Woodard <woodard@redhat.com>"); MODULE_DESCRIPTION("ECC support for Intel 82860 memory hub controllers"); + +module_param(edac_op_state, int, 0444); +MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI"); diff --git a/drivers/edac/i82875p_edac.c b/drivers/edac/i82875p_edac.c index 031abadc439..e43bdc43a1b 100644 --- a/drivers/edac/i82875p_edac.c +++ b/drivers/edac/i82875p_edac.c @@ -18,6 +18,7 @@ #include <linux/pci.h> #include <linux/pci_ids.h> #include <linux/slab.h> +#include <linux/edac.h> #include "edac_core.h" #define I82875P_REVISION " Ver: 2.0.2 " __DATE__ @@ -393,6 +394,7 @@ static int i82875p_probe1(struct pci_dev *pdev, int dev_idx) struct i82875p_error_info discard; debugf0("%s()\n", __func__); + ovrfl_pdev = pci_get_device(PCI_VEND_DEV(INTEL, 82875_6), NULL); if (i82875p_setup_overfl_dev(pdev, &ovrfl_pdev, &ovrfl_window)) @@ -532,6 +534,10 @@ static int __init i82875p_init(void) int pci_rc; debugf3("%s()\n", __func__); + + /* Ensure that the OPSTATE is set correctly for POLL or NMI */ + opstate_init(); + pci_rc = pci_register_driver(&i82875p_driver); if (pci_rc < 0) @@ -586,3 +592,6 @@ module_exit(i82875p_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh"); MODULE_DESCRIPTION("MC support for Intel 82875 memory hub controllers"); + +module_param(edac_op_state, int, 0444); +MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI"); diff --git a/drivers/edac/i82975x_edac.c b/drivers/edac/i82975x_edac.c index 0ee88845693..2eed3ea2cf6 100644 --- a/drivers/edac/i82975x_edac.c +++ b/drivers/edac/i82975x_edac.c @@ -14,7 +14,7 @@ #include <linux/pci.h> #include <linux/pci_ids.h> #include <linux/slab.h> - +#include <linux/edac.h> #include "edac_core.h" #define I82975X_REVISION " Ver: 1.0.0 " __DATE__ @@ -611,6 +611,9 @@ static int __init i82975x_init(void) debugf3("%s()\n", __func__); + /* Ensure that the OPSTATE is set correctly for POLL or NMI */ + opstate_init(); + pci_rc = pci_register_driver(&i82975x_driver); if (pci_rc < 0) goto fail0; @@ -664,3 +667,6 @@ module_exit(i82975x_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Arvind R. <arvind@acarlab.com>"); MODULE_DESCRIPTION("MC support for Intel 82975 memory hub controllers"); + +module_param(edac_op_state, int, 0444); +MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI"); diff --git a/drivers/edac/pasemi_edac.c b/drivers/edac/pasemi_edac.c index 90320917be2..3fd65a56384 100644 --- a/drivers/edac/pasemi_edac.c +++ b/drivers/edac/pasemi_edac.c @@ -284,6 +284,9 @@ static struct pci_driver pasemi_edac_driver = { static int __init pasemi_edac_init(void) { + /* Ensure that the OPSTATE is set correctly for POLL or NMI */ + opstate_init(); + return pci_register_driver(&pasemi_edac_driver); } @@ -298,3 +301,6 @@ module_exit(pasemi_edac_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Egor Martovetsky <egor@pasemi.com>"); MODULE_DESCRIPTION("MC support for PA Semi PWRficient memory controller"); +module_param(edac_op_state, int, 0444); +MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI"); + diff --git a/drivers/edac/r82600_edac.c b/drivers/edac/r82600_edac.c index e25f712f2dc..9900675e959 100644 --- a/drivers/edac/r82600_edac.c +++ b/drivers/edac/r82600_edac.c @@ -20,6 +20,7 @@ #include <linux/pci.h> #include <linux/pci_ids.h> #include <linux/slab.h> +#include <linux/edac.h> #include "edac_core.h" #define R82600_REVISION " Ver: 2.0.2 " __DATE__ @@ -393,6 +394,9 @@ static struct pci_driver r82600_driver = { static int __init r82600_init(void) { + /* Ensure that the OPSTATE is set correctly for POLL or NMI */ + opstate_init(); + return pci_register_driver(&r82600_driver); } @@ -412,3 +416,6 @@ MODULE_DESCRIPTION("MC support for Radisys 82600 memory controllers"); module_param(disable_hardware_scrub, bool, 0644); MODULE_PARM_DESC(disable_hardware_scrub, "If set, disable the chipset's automatic scrub for CEs"); + +module_param(edac_op_state, int, 0444); +MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI"); diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index 40ffd767647..dc2cec6127d 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -17,6 +17,15 @@ config EDD obscure configurations. Most disk controller BIOS vendors do not yet implement this feature. +config EDD_OFF + bool "Sets default behavior for EDD detection to off" + depends on EDD + default n + help + Say Y if you want EDD disabled by default, even though it is compiled into the + kernel. Say N if you want EDD enabled by default. EDD can be dynamically set + using the kernel parameter 'edd={on|skipmbr|off}'. + config EFI_VARS tristate "EFI Variable Support via sysfs" depends on EFI diff --git a/drivers/firmware/dcdbas.c b/drivers/firmware/dcdbas.c index f235940719e..25918f7dfd0 100644 --- a/drivers/firmware/dcdbas.c +++ b/drivers/firmware/dcdbas.c @@ -63,7 +63,7 @@ static void smi_data_buf_free(void) return; dev_dbg(&dcdbas_pdev->dev, "%s: phys: %x size: %lu\n", - __FUNCTION__, smi_data_buf_phys_addr, smi_data_buf_size); + __func__, smi_data_buf_phys_addr, smi_data_buf_size); dma_free_coherent(&dcdbas_pdev->dev, smi_data_buf_size, smi_data_buf, smi_data_buf_handle); @@ -92,7 +92,7 @@ static int smi_data_buf_realloc(unsigned long size) if (!buf) { dev_dbg(&dcdbas_pdev->dev, "%s: failed to allocate memory size %lu\n", - __FUNCTION__, size); + __func__, size); return -ENOMEM; } /* memory zeroed by dma_alloc_coherent */ @@ -110,7 +110,7 @@ static int smi_data_buf_realloc(unsigned long size) smi_data_buf_size = size; dev_dbg(&dcdbas_pdev->dev, "%s: phys: %x size: %lu\n", - __FUNCTION__, smi_data_buf_phys_addr, smi_data_buf_size); + __func__, smi_data_buf_phys_addr, smi_data_buf_size); return 0; } @@ -258,7 +258,7 @@ static int smi_request(struct smi_cmd *smi_cmd) if (smi_cmd->magic != SMI_CMD_MAGIC) { dev_info(&dcdbas_pdev->dev, "%s: invalid magic value\n", - __FUNCTION__); + __func__); return -EBADR; } @@ -267,7 +267,7 @@ static int smi_request(struct smi_cmd *smi_cmd) set_cpus_allowed_ptr(current, &cpumask_of_cpu(0)); if (smp_processor_id() != 0) { dev_dbg(&dcdbas_pdev->dev, "%s: failed to get CPU 0\n", - __FUNCTION__); + __func__); ret = -EBUSY; goto out; } @@ -428,7 +428,7 @@ static int host_control_smi(void) default: dev_dbg(&dcdbas_pdev->dev, "%s: invalid SMI type %u\n", - __FUNCTION__, host_control_smi_type); + __func__, host_control_smi_type); return -ENOSYS; } @@ -456,13 +456,13 @@ static void dcdbas_host_control(void) host_control_action = HC_ACTION_NONE; if (!smi_data_buf) { - dev_dbg(&dcdbas_pdev->dev, "%s: no SMI buffer\n", __FUNCTION__); + dev_dbg(&dcdbas_pdev->dev, "%s: no SMI buffer\n", __func__); return; } if (smi_data_buf_size < sizeof(struct apm_cmd)) { dev_dbg(&dcdbas_pdev->dev, "%s: SMI buffer too small\n", - __FUNCTION__); + __func__); return; } diff --git a/drivers/firmware/dell_rbu.c b/drivers/firmware/dell_rbu.c index 477a3d0e3ca..6a8b1e037e0 100644 --- a/drivers/firmware/dell_rbu.c +++ b/drivers/firmware/dell_rbu.c @@ -123,7 +123,7 @@ static int create_packet(void *data, size_t length) if (!newpacket) { printk(KERN_WARNING "dell_rbu:%s: failed to allocate new " - "packet\n", __FUNCTION__); + "packet\n", __func__); retval = -ENOMEM; spin_lock(&rbu_data.lock); goto out_noalloc; @@ -152,7 +152,7 @@ static int create_packet(void *data, size_t length) printk(KERN_WARNING "dell_rbu:%s: failed to allocate " "invalid_addr_packet_array \n", - __FUNCTION__); + __func__); retval = -ENOMEM; spin_lock(&rbu_data.lock); goto out_alloc_packet; @@ -164,7 +164,7 @@ static int create_packet(void *data, size_t length) if (!packet_data_temp_buf) { printk(KERN_WARNING "dell_rbu:%s: failed to allocate new " - "packet\n", __FUNCTION__); + "packet\n", __func__); retval = -ENOMEM; spin_lock(&rbu_data.lock); goto out_alloc_packet_array; @@ -416,7 +416,7 @@ static int img_update_realloc(unsigned long size) */ if ((size != 0) && (rbu_data.image_update_buffer == NULL)) { printk(KERN_ERR "dell_rbu:%s: corruption " - "check failed\n", __FUNCTION__); + "check failed\n", __func__); return -EINVAL; } /* @@ -642,7 +642,7 @@ static ssize_t write_rbu_image_type(struct kobject *kobj, if (req_firm_rc) { printk(KERN_ERR "dell_rbu:%s request_firmware_nowait" - " failed %d\n", __FUNCTION__, rc); + " failed %d\n", __func__, rc); rc = -EIO; } else rbu_data.entry_created = 1; @@ -718,7 +718,7 @@ static int __init dcdrbu_init(void) if (IS_ERR(rbu_device)) { printk(KERN_ERR "dell_rbu:%s:platform_device_register_simple " - "failed\n", __FUNCTION__); + "failed\n", __func__); return PTR_ERR(rbu_device); } diff --git a/drivers/firmware/iscsi_ibft_find.c b/drivers/firmware/iscsi_ibft_find.c index d0e5fa4ea51..11f17440fea 100644 --- a/drivers/firmware/iscsi_ibft_find.c +++ b/drivers/firmware/iscsi_ibft_find.c @@ -58,7 +58,7 @@ void __init reserve_ibft_region(void) unsigned int len = 0; void *virt; - ibft_addr = 0; + ibft_addr = NULL; for (pos = IBFT_START; pos < IBFT_END; pos += 16) { /* The table can't be inside the VGA BIOS reserved space, diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index d8db2f8ee41..24c62b848bf 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -43,6 +43,7 @@ struct gpio_desc { /* flag symbols are bit numbers */ #define FLAG_REQUESTED 0 #define FLAG_IS_OUT 1 +#define FLAG_RESERVED 2 #ifdef CONFIG_DEBUG_FS const char *label; @@ -68,6 +69,9 @@ static void gpio_ensure_requested(struct gpio_desc *desc) if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) { pr_warning("GPIO-%d autorequested\n", (int)(desc - gpio_desc)); desc_set_label(desc, "[auto]"); + if (!try_module_get(desc->chip->owner)) + pr_err("GPIO-%d: module can't be gotten \n", + (int)(desc - gpio_desc)); } } @@ -77,6 +81,76 @@ static inline struct gpio_chip *gpio_to_chip(unsigned gpio) return gpio_desc[gpio].chip; } +/* dynamic allocation of GPIOs, e.g. on a hotplugged device */ +static int gpiochip_find_base(int ngpio) +{ + int i; + int spare = 0; + int base = -ENOSPC; + + for (i = ARCH_NR_GPIOS - 1; i >= 0 ; i--) { + struct gpio_desc *desc = &gpio_desc[i]; + struct gpio_chip *chip = desc->chip; + + if (!chip && !test_bit(FLAG_RESERVED, &desc->flags)) { + spare++; + if (spare == ngpio) { + base = i; + break; + } + } else { + spare = 0; + if (chip) + i -= chip->ngpio - 1; + } + } + + if (gpio_is_valid(base)) + pr_debug("%s: found new base at %d\n", __func__, base); + return base; +} + +/** + * gpiochip_reserve() - reserve range of gpios to use with platform code only + * @start: starting gpio number + * @ngpio: number of gpios to reserve + * Context: platform init, potentially before irqs or kmalloc will work + * + * Returns a negative errno if any gpio within the range is already reserved + * or registered, else returns zero as a success code. Use this function + * to mark a range of gpios as unavailable for dynamic gpio number allocation, + * for example because its driver support is not yet loaded. + */ +int __init gpiochip_reserve(int start, int ngpio) +{ + int ret = 0; + unsigned long flags; + int i; + + if (!gpio_is_valid(start) || !gpio_is_valid(start + ngpio)) + return -EINVAL; + + spin_lock_irqsave(&gpio_lock, flags); + + for (i = start; i < start + ngpio; i++) { + struct gpio_desc *desc = &gpio_desc[i]; + + if (desc->chip || test_bit(FLAG_RESERVED, &desc->flags)) { + ret = -EBUSY; + goto err; + } + + set_bit(FLAG_RESERVED, &desc->flags); + } + + pr_debug("%s: reserved gpios from %d to %d\n", + __func__, start, start + ngpio - 1); +err: + spin_unlock_irqrestore(&gpio_lock, flags); + + return ret; +} + /** * gpiochip_add() - register a gpio_chip * @chip: the chip to register, with chip->base initialized @@ -85,38 +159,49 @@ static inline struct gpio_chip *gpio_to_chip(unsigned gpio) * Returns a negative errno if the chip can't be registered, such as * because the chip->base is invalid or already associated with a * different chip. Otherwise it returns zero as a success code. + * + * If chip->base is negative, this requests dynamic assignment of + * a range of valid GPIOs. */ int gpiochip_add(struct gpio_chip *chip) { unsigned long flags; int status = 0; unsigned id; + int base = chip->base; - /* NOTE chip->base negative is reserved to mean a request for - * dynamic allocation. We don't currently support that. - */ - - if (chip->base < 0 || (chip->base + chip->ngpio) >= ARCH_NR_GPIOS) { + if ((!gpio_is_valid(base) || !gpio_is_valid(base + chip->ngpio)) + && base >= 0) { status = -EINVAL; goto fail; } spin_lock_irqsave(&gpio_lock, flags); + if (base < 0) { + base = gpiochip_find_base(chip->ngpio); + if (base < 0) { + status = base; + goto fail_unlock; + } + chip->base = base; + } + /* these GPIO numbers must not be managed by another gpio_chip */ - for (id = chip->base; id < chip->base + chip->ngpio; id++) { + for (id = base; id < base + chip->ngpio; id++) { if (gpio_desc[id].chip != NULL) { status = -EBUSY; break; } } if (status == 0) { - for (id = chip->base; id < chip->base + chip->ngpio; id++) { + for (id = base; id < base + chip->ngpio; id++) { gpio_desc[id].chip = chip; gpio_desc[id].flags = 0; } } +fail_unlock: spin_unlock_irqrestore(&gpio_lock, flags); fail: /* failures here can mean systems won't boot... */ @@ -171,12 +256,15 @@ int gpio_request(unsigned gpio, const char *label) spin_lock_irqsave(&gpio_lock, flags); - if (gpio >= ARCH_NR_GPIOS) + if (!gpio_is_valid(gpio)) goto done; desc = &gpio_desc[gpio]; if (desc->chip == NULL) goto done; + if (!try_module_get(desc->chip->owner)) + goto done; + /* NOTE: gpio_request() can be called in early boot, * before IRQs are enabled. */ @@ -184,8 +272,10 @@ int gpio_request(unsigned gpio, const char *label) if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) { desc_set_label(desc, label ? : "?"); status = 0; - } else + } else { status = -EBUSY; + module_put(desc->chip->owner); + } done: if (status) @@ -201,7 +291,7 @@ void gpio_free(unsigned gpio) unsigned long flags; struct gpio_desc *desc; - if (gpio >= ARCH_NR_GPIOS) { + if (!gpio_is_valid(gpio)) { WARN_ON(extra_checks); return; } @@ -209,9 +299,10 @@ void gpio_free(unsigned gpio) spin_lock_irqsave(&gpio_lock, flags); desc = &gpio_desc[gpio]; - if (desc->chip && test_and_clear_bit(FLAG_REQUESTED, &desc->flags)) + if (desc->chip && test_and_clear_bit(FLAG_REQUESTED, &desc->flags)) { desc_set_label(desc, NULL); - else + module_put(desc->chip->owner); + } else WARN_ON(extra_checks); spin_unlock_irqrestore(&gpio_lock, flags); @@ -236,7 +327,7 @@ const char *gpiochip_is_requested(struct gpio_chip *chip, unsigned offset) { unsigned gpio = chip->base + offset; - if (gpio >= ARCH_NR_GPIOS || gpio_desc[gpio].chip != chip) + if (!gpio_is_valid(gpio) || gpio_desc[gpio].chip != chip) return NULL; if (test_bit(FLAG_REQUESTED, &gpio_desc[gpio].flags) == 0) return NULL; @@ -267,7 +358,7 @@ int gpio_direction_input(unsigned gpio) spin_lock_irqsave(&gpio_lock, flags); - if (gpio >= ARCH_NR_GPIOS) + if (!gpio_is_valid(gpio)) goto fail; chip = desc->chip; if (!chip || !chip->get || !chip->direction_input) @@ -305,7 +396,7 @@ int gpio_direction_output(unsigned gpio, int value) spin_lock_irqsave(&gpio_lock, flags); - if (gpio >= ARCH_NR_GPIOS) + if (!gpio_is_valid(gpio)) goto fail; chip = desc->chip; if (!chip || !chip->set || !chip->direction_output) @@ -522,7 +613,7 @@ static int gpiolib_show(struct seq_file *s, void *unused) /* REVISIT this isn't locked against gpio_chip removal ... */ - for (gpio = 0; gpio < ARCH_NR_GPIOS; gpio++) { + for (gpio = 0; gpio_is_valid(gpio); gpio++) { if (chip == gpio_desc[gpio].chip) continue; chip = gpio_desc[gpio].chip; diff --git a/drivers/gpio/mcp23s08.c b/drivers/gpio/mcp23s08.c index bb60e8c1a1f..7fb5b9d009d 100644 --- a/drivers/gpio/mcp23s08.c +++ b/drivers/gpio/mcp23s08.c @@ -239,6 +239,7 @@ static int mcp23s08_probe(struct spi_device *spi) mcp->chip.base = pdata->base; mcp->chip.ngpio = 8; mcp->chip.can_sleep = 1; + mcp->chip.owner = THIS_MODULE; spi_set_drvdata(spi, mcp); diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c index 6e72fd31184..5a99e81d278 100644 --- a/drivers/gpio/pca953x.c +++ b/drivers/gpio/pca953x.c @@ -23,13 +23,7 @@ #define PCA953X_INVERT 2 #define PCA953X_DIRECTION 3 -/* This is temporary - in 2.6.26 i2c_driver_data should replace it. */ -struct pca953x_desc { - char name[I2C_NAME_SIZE]; - unsigned long driver_data; -}; - -static const struct pca953x_desc pca953x_descs[] = { +static const struct i2c_device_id pca953x_id[] = { { "pca9534", 8, }, { "pca9535", 16, }, { "pca9536", 4, }, @@ -37,7 +31,9 @@ static const struct pca953x_desc pca953x_descs[] = { { "pca9538", 8, }, { "pca9539", 16, }, /* REVISIT several pca955x parts should work here too */ + { } }; +MODULE_DEVICE_TABLE(i2c, pca953x_id); struct pca953x_chip { unsigned gpio_start; @@ -189,28 +185,20 @@ static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios) gc->base = chip->gpio_start; gc->ngpio = gpios; gc->label = chip->client->name; + gc->owner = THIS_MODULE; } -static int __devinit pca953x_probe(struct i2c_client *client) +static int __devinit pca953x_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct pca953x_platform_data *pdata; struct pca953x_chip *chip; int ret, i; - const struct pca953x_desc *id = NULL; pdata = client->dev.platform_data; if (pdata == NULL) return -ENODEV; - /* this loop vanishes when we get i2c_device_id */ - for (i = 0; i < ARRAY_SIZE(pca953x_descs); i++) - if (!strcmp(pca953x_descs[i].name, client->name)) { - id = pca953x_descs + i; - break; - } - if (!id) - return -ENODEV; - chip = kzalloc(sizeof(struct pca953x_chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; @@ -290,6 +278,7 @@ static struct i2c_driver pca953x_driver = { }, .probe = pca953x_probe, .remove = pca953x_remove, + .id_table = pca953x_id, }; static int __init pca953x_init(void) diff --git a/drivers/gpio/pcf857x.c b/drivers/gpio/pcf857x.c index c6b3b537838..aa6cc8b2a2b 100644 --- a/drivers/gpio/pcf857x.c +++ b/drivers/gpio/pcf857x.c @@ -26,6 +26,21 @@ #include <asm/gpio.h> +static const struct i2c_device_id pcf857x_id[] = { + { "pcf8574", 8 }, + { "pca8574", 8 }, + { "pca9670", 8 }, + { "pca9672", 8 }, + { "pca9674", 8 }, + { "pcf8575", 16 }, + { "pca8575", 16 }, + { "pca9671", 16 }, + { "pca9673", 16 }, + { "pca9675", 16 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, pcf857x_id); + /* * The pcf857x, pca857x, and pca967x chips only expose one read and one * write register. Writing a "one" bit (to match the reset state) lets @@ -142,7 +157,8 @@ static void pcf857x_set16(struct gpio_chip *chip, unsigned offset, int value) /*-------------------------------------------------------------------------*/ -static int pcf857x_probe(struct i2c_client *client) +static int pcf857x_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct pcf857x_platform_data *pdata; struct pcf857x *gpio; @@ -159,6 +175,7 @@ static int pcf857x_probe(struct i2c_client *client) gpio->chip.base = pdata->gpio_base; gpio->chip.can_sleep = 1; + gpio->chip.owner = THIS_MODULE; /* NOTE: the OnSemi jlc1562b is also largely compatible with * these parts, notably for output. It has a low-resolution @@ -171,13 +188,8 @@ static int pcf857x_probe(struct i2c_client *client) * * NOTE: we don't distinguish here between *4 and *4a parts. */ - if (strcmp(client->name, "pcf8574") == 0 - || strcmp(client->name, "pca8574") == 0 - || strcmp(client->name, "pca9670") == 0 - || strcmp(client->name, "pca9672") == 0 - || strcmp(client->name, "pca9674") == 0 - ) { - gpio->chip.ngpio = 8; + gpio->chip.ngpio = id->driver_data; + if (gpio->chip.ngpio == 8) { gpio->chip.direction_input = pcf857x_input8; gpio->chip.get = pcf857x_get8; gpio->chip.direction_output = pcf857x_output8; @@ -197,13 +209,7 @@ static int pcf857x_probe(struct i2c_client *client) * * NOTE: we don't distinguish here between '75 and '75c parts. */ - } else if (strcmp(client->name, "pcf8575") == 0 - || strcmp(client->name, "pca8575") == 0 - || strcmp(client->name, "pca9671") == 0 - || strcmp(client->name, "pca9673") == 0 - || strcmp(client->name, "pca9675") == 0 - ) { - gpio->chip.ngpio = 16; + } else if (gpio->chip.ngpio == 16) { gpio->chip.direction_input = pcf857x_input16; gpio->chip.get = pcf857x_get16; gpio->chip.direction_output = pcf857x_output16; @@ -312,6 +318,7 @@ static struct i2c_driver pcf857x_driver = { }, .probe = pcf857x_probe, .remove = pcf857x_remove, + .id_table = pcf857x_id, }; static int __init pcf857x_init(void) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index e03c67dd3e6..f43d6d3cf2f 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -606,7 +606,7 @@ static u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item) case 2: if ((end - start) < 2) return NULL; - item->data.u16 = le16_to_cpu(get_unaligned((__le16*)start)); + item->data.u16 = get_unaligned_le16(start); start = (__u8 *)((__le16 *)start + 1); return start; @@ -614,7 +614,7 @@ static u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item) item->size++; if ((end - start) < 4) return NULL; - item->data.u32 = le32_to_cpu(get_unaligned((__le32*)start)); + item->data.u32 = get_unaligned_le32(start); start = (__u8 *)((__le32 *)start + 1); return start; } @@ -765,7 +765,7 @@ static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n) report += offset >> 3; /* adjust byte index */ offset &= 7; /* now only need bit offset into one byte */ - x = le64_to_cpu(get_unaligned((__le64 *) report)); + x = get_unaligned_le64(report); x = (x >> offset) & ((1ULL << n) - 1); /* extract bit field */ return (u32) x; } diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index e0d805f1b2b..01427c51c7c 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -654,7 +654,7 @@ static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t co ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), HID_REQ_SET_REPORT, USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - cpu_to_le16(((HID_OUTPUT_REPORT + 1) << 8) | *buf), + ((HID_OUTPUT_REPORT + 1) << 8) | *buf, interface->desc.bInterfaceNumber, buf + 1, count - 1, USB_CTRL_SET_TIMEOUT); diff --git a/drivers/hwmon/f75375s.c b/drivers/hwmon/f75375s.c index 1464338e4e1..dc1f30e432e 100644 --- a/drivers/hwmon/f75375s.c +++ b/drivers/hwmon/f75375s.c @@ -117,7 +117,8 @@ struct f75375_data { static int f75375_attach_adapter(struct i2c_adapter *adapter); static int f75375_detect(struct i2c_adapter *adapter, int address, int kind); static int f75375_detach_client(struct i2c_client *client); -static int f75375_probe(struct i2c_client *client); +static int f75375_probe(struct i2c_client *client, + const struct i2c_device_id *id); static int f75375_remove(struct i2c_client *client); static struct i2c_driver f75375_legacy_driver = { @@ -128,12 +129,20 @@ static struct i2c_driver f75375_legacy_driver = { .detach_client = f75375_detach_client, }; +static const struct i2c_device_id f75375_id[] = { + { "f75373", f75373 }, + { "f75375", f75375 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, f75375_id); + static struct i2c_driver f75375_driver = { .driver = { .name = "f75375", }, .probe = f75375_probe, .remove = f75375_remove, + .id_table = f75375_id, }; static inline int f75375_read8(struct i2c_client *client, u8 reg) @@ -628,7 +637,8 @@ static void f75375_init(struct i2c_client *client, struct f75375_data *data, } -static int f75375_probe(struct i2c_client *client) +static int f75375_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct f75375_data *data = i2c_get_clientdata(client); struct f75375s_platform_data *f75375s_pdata = client->dev.platform_data; @@ -643,15 +653,7 @@ static int f75375_probe(struct i2c_client *client) i2c_set_clientdata(client, data); data->client = client; mutex_init(&data->update_lock); - - if (strcmp(client->name, "f75375") == 0) - data->kind = f75375; - else if (strcmp(client->name, "f75373") == 0) - data->kind = f75373; - else { - dev_err(&client->dev, "Unsupported device: %s\n", client->name); - return -ENODEV; - } + data->kind = id->driver_data; if ((err = sysfs_create_group(&client->dev.kobj, &f75375_group))) goto exit_free; @@ -712,6 +714,7 @@ static int f75375_detect(struct i2c_adapter *adapter, int address, int kind) u8 version = 0; int err = 0; const char *name = ""; + struct i2c_device_id id; if (!(client = kzalloc(sizeof(*client), GFP_KERNEL))) { err = -ENOMEM; @@ -748,7 +751,9 @@ static int f75375_detect(struct i2c_adapter *adapter, int address, int kind) if ((err = i2c_attach_client(client))) goto exit_free; - if ((err = f75375_probe(client)) < 0) + strlcpy(id.name, name, I2C_NAME_SIZE); + id.driver_data = kind; + if ((err = f75375_probe(client, &id)) < 0) goto exit_detach; return 0; diff --git a/drivers/i2c/busses/i2c-amd756-s4882.c b/drivers/i2c/busses/i2c-amd756-s4882.c index e5e96c81756..c38a0a11220 100644 --- a/drivers/i2c/busses/i2c-amd756-s4882.c +++ b/drivers/i2c/busses/i2c-amd756-s4882.c @@ -1,7 +1,7 @@ /* * i2c-amd756-s4882.c - i2c-amd756 extras for the Tyan S4882 motherboard * - * Copyright (C) 2004 Jean Delvare <khali@linux-fr.org> + * Copyright (C) 2004, 2008 Jean Delvare <khali@linux-fr.org> * * 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 @@ -231,7 +231,8 @@ ERROR2: kfree(s4882_adapter); s4882_adapter = NULL; ERROR1: - i2c_del_adapter(&amd756_smbus); + /* Restore physical bus */ + i2c_add_adapter(&amd756_smbus); ERROR0: return error; } diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index 9bbe96cef71..fdc9ad805e3 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -38,7 +38,6 @@ #include <linux/ioport.h> #include <linux/i2c.h> #include <linux/init.h> -#include <linux/apm_bios.h> #include <linux/dmi.h> #include <asm/io.h> @@ -223,7 +222,7 @@ static int piix4_transaction(void) dev_err(&piix4_adapter.dev, "Failed! (%02x)\n", temp); return -1; } else { - dev_dbg(&piix4_adapter.dev, "Successfull!\n"); + dev_dbg(&piix4_adapter.dev, "Successful!\n"); } } @@ -343,12 +342,7 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr, switch (size) { - case PIIX4_BYTE: /* Where is the result put? I assume here it is in - SMBHSTDAT0 but it might just as well be in the - SMBHSTCMD. No clue in the docs */ - - data->byte = inb_p(SMBHSTDAT0); - break; + case PIIX4_BYTE: case PIIX4_BYTE_DATA: data->byte = inb_p(SMBHSTDAT0); break; diff --git a/drivers/i2c/busses/i2c-sis5595.c b/drivers/i2c/busses/i2c-sis5595.c index 283769cecee..9ca8f9155f9 100644 --- a/drivers/i2c/busses/i2c-sis5595.c +++ b/drivers/i2c/busses/i2c-sis5595.c @@ -238,7 +238,7 @@ static int sis5595_transaction(struct i2c_adapter *adap) dev_dbg(&adap->dev, "Failed! (%02x)\n", temp); return -1; } else { - dev_dbg(&adap->dev, "Successfull!\n"); + dev_dbg(&adap->dev, "Successful!\n"); } } @@ -316,14 +316,8 @@ static s32 sis5595_access(struct i2c_adapter *adap, u16 addr, } size = (size == I2C_SMBUS_PROC_CALL) ? SIS5595_PROC_CALL : SIS5595_WORD_DATA; break; -/* - case I2C_SMBUS_BLOCK_DATA: - printk(KERN_WARNING "sis5595.o: Block data not yet implemented!\n"); - return -1; - break; -*/ default: - printk(KERN_WARNING "sis5595.o: Unsupported transaction %d\n", size); + dev_warn(&adap->dev, "Unsupported transaction %d\n", size); return -1; } @@ -338,9 +332,7 @@ static s32 sis5595_access(struct i2c_adapter *adap, u16 addr, switch (size) { - case SIS5595_BYTE: /* Where is the result put? I assume here it is in - SMB_DATA but it might just as well be in the - SMB_CMD. No clue in the docs */ + case SIS5595_BYTE: case SIS5595_BYTE_DATA: data->byte = sis5595_read(SMB_BYTE); break; diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c index 5fd734f99ee..3765dd7f450 100644 --- a/drivers/i2c/busses/i2c-sis630.c +++ b/drivers/i2c/busses/i2c-sis630.c @@ -136,7 +136,7 @@ static int sis630_transaction_start(struct i2c_adapter *adap, int size, u8 *oldc dev_dbg(&adap->dev, "Failed! (%02x)\n", temp); return -1; } else { - dev_dbg(&adap->dev, "Successfull!\n"); + dev_dbg(&adap->dev, "Successful!\n"); } } diff --git a/drivers/i2c/busses/i2c-stub.c b/drivers/i2c/busses/i2c-stub.c index c2a9f8c94f5..d08eeec5391 100644 --- a/drivers/i2c/busses/i2c-stub.c +++ b/drivers/i2c/busses/i2c-stub.c @@ -33,7 +33,7 @@ static unsigned short chip_addr[MAX_CHIPS]; module_param_array(chip_addr, ushort, NULL, S_IRUGO); MODULE_PARM_DESC(chip_addr, - "Chip addresses (up to 10, between 0x03 and 0x77)\n"); + "Chip addresses (up to 10, between 0x03 and 0x77)"); struct stub_chip { u8 pointer; diff --git a/drivers/i2c/busses/i2c-taos-evm.c b/drivers/i2c/busses/i2c-taos-evm.c index 1b0cfd5472f..de9db49e54d 100644 --- a/drivers/i2c/busses/i2c-taos-evm.c +++ b/drivers/i2c/busses/i2c-taos-evm.c @@ -51,7 +51,6 @@ struct taos_data { /* TAOS TSL2550 EVM */ static struct i2c_board_info tsl2550_info = { I2C_BOARD_INFO("tsl2550", 0x39), - .type = "tsl2550", }; /* Instantiate i2c devices based on the adapter name */ @@ -59,7 +58,7 @@ static struct i2c_client *taos_instantiate_device(struct i2c_adapter *adapter) { if (!strncmp(adapter->name, "TAOS TSL2550 EVM", 16)) { dev_info(&adapter->dev, "Instantiating device %s at 0x%02x\n", - tsl2550_info.driver_name, tsl2550_info.addr); + tsl2550_info.type, tsl2550_info.addr); return i2c_new_device(adapter, &tsl2550_info); } diff --git a/drivers/i2c/chips/ds1682.c b/drivers/i2c/chips/ds1682.c index 9e94542c18a..23be4d42cb0 100644 --- a/drivers/i2c/chips/ds1682.c +++ b/drivers/i2c/chips/ds1682.c @@ -200,7 +200,8 @@ static struct bin_attribute ds1682_eeprom_attr = { /* * Called when a ds1682 device is matched with this driver */ -static int ds1682_probe(struct i2c_client *client) +static int ds1682_probe(struct i2c_client *client, + const struct i2c_device_id *id) { int rc; @@ -234,12 +235,19 @@ static int ds1682_remove(struct i2c_client *client) return 0; } +static const struct i2c_device_id ds1682_id[] = { + { "ds1682", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ds1682_id); + static struct i2c_driver ds1682_driver = { .driver = { .name = "ds1682", }, .probe = ds1682_probe, .remove = ds1682_remove, + .id_table = ds1682_id, }; static int __init ds1682_init(void) diff --git a/drivers/i2c/chips/menelaus.c b/drivers/i2c/chips/menelaus.c index 2dea0123a95..b36db1797c1 100644 --- a/drivers/i2c/chips/menelaus.c +++ b/drivers/i2c/chips/menelaus.c @@ -1149,7 +1149,8 @@ static inline void menelaus_rtc_init(struct menelaus_chip *m) static struct i2c_driver menelaus_i2c_driver; -static int menelaus_probe(struct i2c_client *client) +static int menelaus_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct menelaus_chip *menelaus; int rev = 0, val; @@ -1242,12 +1243,19 @@ static int __exit menelaus_remove(struct i2c_client *client) return 0; } +static const struct i2c_device_id menelaus_id[] = { + { "menelaus", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, menelaus_id); + static struct i2c_driver menelaus_i2c_driver = { .driver = { .name = DRIVER_NAME, }, .probe = menelaus_probe, .remove = __exit_p(menelaus_remove), + .id_table = menelaus_id, }; static int __init menelaus_init(void) diff --git a/drivers/i2c/chips/tps65010.c b/drivers/i2c/chips/tps65010.c index b67f69c2e7f..85949685191 100644 --- a/drivers/i2c/chips/tps65010.c +++ b/drivers/i2c/chips/tps65010.c @@ -64,7 +64,6 @@ static struct i2c_driver tps65010_driver; * as part of board setup by a bootloader. */ enum tps_model { - TPS_UNKNOWN = 0, TPS65010, TPS65011, TPS65012, @@ -527,11 +526,13 @@ static int __exit tps65010_remove(struct i2c_client *client) flush_scheduled_work(); debugfs_remove(tps->file); kfree(tps); + i2c_set_clientdata(client, NULL); the_tps = NULL; return 0; } -static int tps65010_probe(struct i2c_client *client) +static int tps65010_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct tps65010 *tps; int status; @@ -552,20 +553,7 @@ static int tps65010_probe(struct i2c_client *client) mutex_init(&tps->lock); INIT_DELAYED_WORK(&tps->work, tps65010_work); tps->client = client; - - if (strcmp(client->name, "tps65010") == 0) - tps->model = TPS65010; - else if (strcmp(client->name, "tps65011") == 0) - tps->model = TPS65011; - else if (strcmp(client->name, "tps65012") == 0) - tps->model = TPS65012; - else if (strcmp(client->name, "tps65013") == 0) - tps->model = TPS65013; - else { - dev_warn(&client->dev, "unknown chip '%s'\n", client->name); - status = -ENODEV; - goto fail1; - } + tps->model = id->driver_data; /* the IRQ is active low, but many gpio lines can't support that * so this driver uses falling-edge triggers instead. @@ -594,9 +582,6 @@ static int tps65010_probe(struct i2c_client *client) case TPS65012: tps->por = 1; break; - case TPS_UNKNOWN: - printk(KERN_WARNING "%s: unknown TPS chip\n", DRIVER_NAME); - break; /* else CHGCONFIG.POR is replaced by AUA, enabling a WAIT mode */ } tps->chgconf = i2c_smbus_read_byte_data(client, TPS_CHGCONFIG); @@ -615,6 +600,7 @@ static int tps65010_probe(struct i2c_client *client) i2c_smbus_read_byte_data(client, TPS_DEFGPIO), i2c_smbus_read_byte_data(client, TPS_MASK3)); + i2c_set_clientdata(client, tps); the_tps = tps; #if defined(CONFIG_USB_GADGET) && !defined(CONFIG_USB_OTG) @@ -682,12 +668,22 @@ fail1: return status; } +static const struct i2c_device_id tps65010_id[] = { + { "tps65010", TPS65010 }, + { "tps65011", TPS65011 }, + { "tps65012", TPS65012 }, + { "tps65013", TPS65013 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tps65010_id); + static struct i2c_driver tps65010_driver = { .driver = { .name = "tps65010", }, .probe = tps65010_probe, .remove = __exit_p(tps65010_remove), + .id_table = tps65010_id, }; /*-------------------------------------------------------------------------*/ diff --git a/drivers/i2c/chips/tsl2550.c b/drivers/i2c/chips/tsl2550.c index a10fd2791a6..1a9cc135219 100644 --- a/drivers/i2c/chips/tsl2550.c +++ b/drivers/i2c/chips/tsl2550.c @@ -364,7 +364,8 @@ static int tsl2550_init_client(struct i2c_client *client) */ static struct i2c_driver tsl2550_driver; -static int __devinit tsl2550_probe(struct i2c_client *client) +static int __devinit tsl2550_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); struct tsl2550_data *data; @@ -451,6 +452,12 @@ static int tsl2550_resume(struct i2c_client *client) #endif /* CONFIG_PM */ +static const struct i2c_device_id tsl2550_id[] = { + { "tsl2550", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tsl2550_id); + static struct i2c_driver tsl2550_driver = { .driver = { .name = TSL2550_DRV_NAME, @@ -460,6 +467,7 @@ static struct i2c_driver tsl2550_driver = { .resume = tsl2550_resume, .probe = tsl2550_probe, .remove = __devexit_p(tsl2550_remove), + .id_table = tsl2550_id, }; static int __init tsl2550_init(void) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 6c7fa8d53c0..26384daccb9 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -48,6 +48,17 @@ static DEFINE_IDR(i2c_adapter_idr); /* ------------------------------------------------------------------------- */ +static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id, + const struct i2c_client *client) +{ + while (id->name[0]) { + if (strcmp(client->name, id->name) == 0) + return id; + id++; + } + return NULL; +} + static int i2c_device_match(struct device *dev, struct device_driver *drv) { struct i2c_client *client = to_i2c_client(dev); @@ -59,6 +70,10 @@ static int i2c_device_match(struct device *dev, struct device_driver *drv) if (!is_newstyle_driver(driver)) return 0; + /* match on an id table if there is one */ + if (driver->id_table) + return i2c_match_id(driver->id_table, client) != NULL; + /* new style drivers use the same kind of driver matching policy * as platform devices or SPI: compare device and driver IDs. */ @@ -73,11 +88,17 @@ static int i2c_device_uevent(struct device *dev, struct kobj_uevent_env *env) struct i2c_client *client = to_i2c_client(dev); /* by definition, legacy drivers can't hotplug */ - if (dev->driver || !client->driver_name) + if (dev->driver) return 0; - if (add_uevent_var(env, "MODALIAS=%s", client->driver_name)) - return -ENOMEM; + if (client->driver_name[0]) { + if (add_uevent_var(env, "MODALIAS=%s", client->driver_name)) + return -ENOMEM; + } else { + if (add_uevent_var(env, "MODALIAS=%s%s", + I2C_MODULE_PREFIX, client->name)) + return -ENOMEM; + } dev_dbg(dev, "uevent\n"); return 0; } @@ -90,13 +111,19 @@ static int i2c_device_probe(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct i2c_driver *driver = to_i2c_driver(dev->driver); + const struct i2c_device_id *id; int status; if (!driver->probe) return -ENODEV; client->driver = driver; dev_dbg(dev, "probe\n"); - status = driver->probe(client); + + if (driver->id_table) + id = i2c_match_id(driver->id_table, client); + else + id = NULL; + status = driver->probe(client, id); if (status) client->driver = NULL; return status; @@ -179,9 +206,9 @@ static ssize_t show_client_name(struct device *dev, struct device_attribute *att static ssize_t show_modalias(struct device *dev, struct device_attribute *attr, char *buf) { struct i2c_client *client = to_i2c_client(dev); - return client->driver_name + return client->driver_name[0] ? sprintf(buf, "%s\n", client->driver_name) - : 0; + : sprintf(buf, "%s%s\n", I2C_MODULE_PREFIX, client->name); } static struct device_attribute i2c_dev_attrs[] = { @@ -300,15 +327,21 @@ void i2c_unregister_device(struct i2c_client *client) EXPORT_SYMBOL_GPL(i2c_unregister_device); -static int dummy_nop(struct i2c_client *client) +static int dummy_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + return 0; +} + +static int dummy_remove(struct i2c_client *client) { return 0; } static struct i2c_driver dummy_driver = { .driver.name = "dummy", - .probe = dummy_nop, - .remove = dummy_nop, + .probe = dummy_probe, + .remove = dummy_remove, }; /** diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index 3f9e10001e1..f702f9152ce 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig @@ -862,40 +862,6 @@ config BLK_DEV_IDE_BAST Say Y here if you want to support the onboard IDE channels on the Simtec BAST or the Thorcom VR1000 -config ETRAX_IDE - tristate "ETRAX IDE support" - depends on CRIS && BROKEN - select BLK_DEV_IDEDMA - help - Enables the ETRAX IDE driver. - - You can't use parallel ports or SCSI ports at the same time. - -config ETRAX_IDE_DELAY - int "Delay for drives to regain consciousness" - depends on ETRAX_IDE && ETRAX_ARCH_V10 - default 15 - help - Number of seconds to wait for IDE drives to spin up after an IDE - reset. - -choice - prompt "IDE reset pin" - depends on ETRAX_IDE && ETRAX_ARCH_V10 - default ETRAX_IDE_PB7_RESET - -config ETRAX_IDE_PB7_RESET - bool "Port_PB_Bit_7" - help - IDE reset on pin 7 on port B - -config ETRAX_IDE_G27_RESET - bool "Port_G_Bit_27" - help - IDE reset on pin 27 on port G - -endchoice - config IDE_H8300 tristate "H8300 IDE support" depends on H8300 diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile index 571544c37bb..f94b679b611 100644 --- a/drivers/ide/Makefile +++ b/drivers/ide/Makefile @@ -35,7 +35,7 @@ ifeq ($(CONFIG_BLK_DEV_CMD640), y) obj-y += cmd640-core.o endif -obj-$(CONFIG_BLK_DEV_IDE) += cris/ ppc/ +obj-$(CONFIG_BLK_DEV_IDE) += ppc/ obj-$(CONFIG_IDE_H8300) += h8300/ obj-$(CONFIG_IDE_GENERIC) += ide-generic.o obj-$(CONFIG_BLK_DEV_IDEPNP) += ide-pnp.o diff --git a/drivers/ide/arm/icside.c b/drivers/ide/arm/icside.c index 124445c2092..061456914ca 100644 --- a/drivers/ide/arm/icside.c +++ b/drivers/ide/arm/icside.c @@ -419,17 +419,19 @@ icside_setup(void __iomem *base, struct cardinfo *info, struct expansion_card *e hwif = ide_find_port(); if (hwif) { - int i; - /* * Ensure we're using MMIO */ default_hwif_mmiops(hwif); - for (i = 0; i <= 7; i++) { - hwif->io_ports_array[i] = port; - port += 1 << info->stepping; - } + hwif->io_ports.data_addr = port; + hwif->io_ports.error_addr = port + (1 << info->stepping); + hwif->io_ports.nsect_addr = port + (2 << info->stepping); + hwif->io_ports.lbal_addr = port + (3 << info->stepping); + hwif->io_ports.lbam_addr = port + (4 << info->stepping); + hwif->io_ports.lbah_addr = port + (5 << info->stepping); + hwif->io_ports.device_addr = port + (6 << info->stepping); + hwif->io_ports.status_addr = port + (7 << info->stepping); hwif->io_ports.ctl_addr = (unsigned long)base + info->ctrloffset; hwif->irq = ec->irq; @@ -481,7 +483,7 @@ static const struct ide_port_info icside_v6_port_info __initdata = { .init_dma = icside_dma_off_init, .port_ops = &icside_v6_no_dma_port_ops, .dma_ops = &icside_v6_dma_ops, - .host_flags = IDE_HFLAG_SERIALIZE, + .host_flags = IDE_HFLAG_SERIALIZE | IDE_HFLAG_MMIO, .mwdma_mask = ATA_MWDMA2, .swdma_mask = ATA_SWDMA2, }; diff --git a/drivers/ide/arm/palm_bk3710.c b/drivers/ide/arm/palm_bk3710.c index aaf32541622..96378ebfb31 100644 --- a/drivers/ide/arm/palm_bk3710.c +++ b/drivers/ide/arm/palm_bk3710.c @@ -342,6 +342,7 @@ static const struct ide_port_ops palm_bk3710_ports_ops = { static const struct ide_port_info __devinitdata palm_bk3710_port_info = { .init_dma = palm_bk3710_init_dma, .port_ops = &palm_bk3710_ports_ops, + .host_flags = IDE_HFLAG_MMIO, .pio_mask = ATA_PIO4, .udma_mask = ATA_UDMA4, /* (input clk 99MHz) */ .mwdma_mask = ATA_MWDMA2, diff --git a/drivers/ide/arm/rapide.c b/drivers/ide/arm/rapide.c index babc1a5e128..1747b235877 100644 --- a/drivers/ide/arm/rapide.c +++ b/drivers/ide/arm/rapide.c @@ -53,6 +53,7 @@ rapide_probe(struct expansion_card *ec, const struct ecard_id *id) ide_init_port_hw(hwif, &hw); + hwif->host_flags = IDE_HFLAG_MMIO; default_hwif_mmiops(hwif); idx[0] = hwif->index; diff --git a/drivers/ide/cris/Makefile b/drivers/ide/cris/Makefile deleted file mode 100644 index 20b95960531..00000000000 --- a/drivers/ide/cris/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -EXTRA_CFLAGS += -Idrivers/ide - -obj-$(CONFIG_IDE_ETRAX) += ide-cris.o diff --git a/drivers/ide/cris/ide-cris.c b/drivers/ide/cris/ide-cris.c deleted file mode 100644 index 9df26855bc0..00000000000 --- a/drivers/ide/cris/ide-cris.c +++ /dev/null @@ -1,1086 +0,0 @@ -/* - * Etrax specific IDE functions, like init and PIO-mode setting etc. - * Almost the entire ide.c is used for the rest of the Etrax ATA driver. - * Copyright (c) 2000-2005 Axis Communications AB - * - * Authors: Bjorn Wesen (initial version) - * Mikael Starvik (crisv32 port) - */ - -/* Regarding DMA: - * - * There are two forms of DMA - "DMA handshaking" between the interface and the drive, - * and DMA between the memory and the interface. We can ALWAYS use the latter, since it's - * something built-in in the Etrax. However only some drives support the DMA-mode handshaking - * on the ATA-bus. The normal PC driver and Triton interface disables memory-if DMA when the - * device can't do DMA handshaking for some stupid reason. We don't need to do that. - */ - -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/timer.h> -#include <linux/mm.h> -#include <linux/interrupt.h> -#include <linux/delay.h> -#include <linux/blkdev.h> -#include <linux/hdreg.h> -#include <linux/ide.h> -#include <linux/init.h> - -#include <asm/io.h> -#include <asm/dma.h> - -/* number of DMA descriptors */ -#define MAX_DMA_DESCRS 64 - -/* number of times to retry busy-flags when reading/writing IDE-registers - * this can't be too high because a hung harddisk might cause the watchdog - * to trigger (sometimes INB and OUTB are called with irq's disabled) - */ - -#define IDE_REGISTER_TIMEOUT 300 - -#define LOWDB(x) -#define D(x) - -enum /* Transfer types */ -{ - TYPE_PIO, - TYPE_DMA, - TYPE_UDMA -}; - -/* CRISv32 specifics */ -#ifdef CONFIG_ETRAX_ARCH_V32 -#include <asm/arch/hwregs/ata_defs.h> -#include <asm/arch/hwregs/dma_defs.h> -#include <asm/arch/hwregs/dma.h> -#include <asm/arch/pinmux.h> - -#define ATA_UDMA2_CYC 2 -#define ATA_UDMA2_DVS 3 -#define ATA_UDMA1_CYC 2 -#define ATA_UDMA1_DVS 4 -#define ATA_UDMA0_CYC 4 -#define ATA_UDMA0_DVS 6 -#define ATA_DMA2_STROBE 7 -#define ATA_DMA2_HOLD 1 -#define ATA_DMA1_STROBE 8 -#define ATA_DMA1_HOLD 3 -#define ATA_DMA0_STROBE 25 -#define ATA_DMA0_HOLD 19 -#define ATA_PIO4_SETUP 3 -#define ATA_PIO4_STROBE 7 -#define ATA_PIO4_HOLD 1 -#define ATA_PIO3_SETUP 3 -#define ATA_PIO3_STROBE 9 -#define ATA_PIO3_HOLD 3 -#define ATA_PIO2_SETUP 3 -#define ATA_PIO2_STROBE 13 -#define ATA_PIO2_HOLD 5 -#define ATA_PIO1_SETUP 5 -#define ATA_PIO1_STROBE 23 -#define ATA_PIO1_HOLD 9 -#define ATA_PIO0_SETUP 9 -#define ATA_PIO0_STROBE 39 -#define ATA_PIO0_HOLD 9 - -int -cris_ide_ack_intr(ide_hwif_t* hwif) -{ - reg_ata_rw_ctrl2 ctrl2 = REG_TYPE_CONV(reg_ata_rw_ctrl2, int, - hwif->io_ports.data_addr); - REG_WR_INT(ata, regi_ata, rw_ack_intr, 1 << ctrl2.sel); - return 1; -} - -static inline int -cris_ide_busy(void) -{ - reg_ata_rs_stat_data stat_data; - stat_data = REG_RD(ata, regi_ata, rs_stat_data); - return stat_data.busy; -} - -static inline int -cris_ide_ready(void) -{ - return !cris_ide_busy(); -} - -static inline int -cris_ide_data_available(unsigned short* data) -{ - reg_ata_rs_stat_data stat_data; - stat_data = REG_RD(ata, regi_ata, rs_stat_data); - *data = stat_data.data; - return stat_data.dav; -} - -static void -cris_ide_write_command(unsigned long command) -{ - REG_WR_INT(ata, regi_ata, rw_ctrl2, command); /* write data to the drive's register */ -} - -static void -cris_ide_set_speed(int type, int setup, int strobe, int hold) -{ - reg_ata_rw_ctrl0 ctrl0 = REG_RD(ata, regi_ata, rw_ctrl0); - reg_ata_rw_ctrl1 ctrl1 = REG_RD(ata, regi_ata, rw_ctrl1); - - if (type == TYPE_PIO) { - ctrl0.pio_setup = setup; - ctrl0.pio_strb = strobe; - ctrl0.pio_hold = hold; - } else if (type == TYPE_DMA) { - ctrl0.dma_strb = strobe; - ctrl0.dma_hold = hold; - } else if (type == TYPE_UDMA) { - ctrl1.udma_tcyc = setup; - ctrl1.udma_tdvs = strobe; - } - REG_WR(ata, regi_ata, rw_ctrl0, ctrl0); - REG_WR(ata, regi_ata, rw_ctrl1, ctrl1); -} - -static unsigned long -cris_ide_base_address(int bus) -{ - reg_ata_rw_ctrl2 ctrl2 = {0}; - ctrl2.sel = bus; - return REG_TYPE_CONV(int, reg_ata_rw_ctrl2, ctrl2); -} - -static unsigned long -cris_ide_reg_addr(unsigned long addr, int cs0, int cs1) -{ - reg_ata_rw_ctrl2 ctrl2 = {0}; - ctrl2.addr = addr; - ctrl2.cs1 = cs1; - ctrl2.cs0 = cs0; - return REG_TYPE_CONV(int, reg_ata_rw_ctrl2, ctrl2); -} - -static __init void -cris_ide_reset(unsigned val) -{ - reg_ata_rw_ctrl0 ctrl0 = {0}; - ctrl0.rst = val ? regk_ata_active : regk_ata_inactive; - REG_WR(ata, regi_ata, rw_ctrl0, ctrl0); -} - -static __init void -cris_ide_init(void) -{ - reg_ata_rw_ctrl0 ctrl0 = {0}; - reg_ata_rw_intr_mask intr_mask = {0}; - - ctrl0.en = regk_ata_yes; - REG_WR(ata, regi_ata, rw_ctrl0, ctrl0); - - intr_mask.bus0 = regk_ata_yes; - intr_mask.bus1 = regk_ata_yes; - intr_mask.bus2 = regk_ata_yes; - intr_mask.bus3 = regk_ata_yes; - - REG_WR(ata, regi_ata, rw_intr_mask, intr_mask); - - crisv32_request_dma(2, "ETRAX FS built-in ATA", DMA_VERBOSE_ON_ERROR, 0, dma_ata); - crisv32_request_dma(3, "ETRAX FS built-in ATA", DMA_VERBOSE_ON_ERROR, 0, dma_ata); - - crisv32_pinmux_alloc_fixed(pinmux_ata); - crisv32_pinmux_alloc_fixed(pinmux_ata0); - crisv32_pinmux_alloc_fixed(pinmux_ata1); - crisv32_pinmux_alloc_fixed(pinmux_ata2); - crisv32_pinmux_alloc_fixed(pinmux_ata3); - - DMA_RESET(regi_dma2); - DMA_ENABLE(regi_dma2); - DMA_RESET(regi_dma3); - DMA_ENABLE(regi_dma3); - - DMA_WR_CMD (regi_dma2, regk_dma_set_w_size2); - DMA_WR_CMD (regi_dma3, regk_dma_set_w_size2); -} - -static dma_descr_context mycontext __attribute__ ((__aligned__(32))); - -#define cris_dma_descr_type dma_descr_data -#define cris_pio_read regk_ata_rd -#define cris_ultra_mask 0x7 -#define MAX_DESCR_SIZE 0xffffffffUL - -static unsigned long -cris_ide_get_reg(unsigned long reg) -{ - return (reg & 0x0e000000) >> 25; -} - -static void -cris_ide_fill_descriptor(cris_dma_descr_type *d, void* buf, unsigned int len, int last) -{ - d->buf = (char*)virt_to_phys(buf); - d->after = d->buf + len; - d->eol = last; -} - -static void -cris_ide_start_dma(ide_drive_t *drive, cris_dma_descr_type *d, int dir,int type,int len) -{ - ide_hwif_t *hwif = drive->hwif; - - reg_ata_rw_ctrl2 ctrl2 = REG_TYPE_CONV(reg_ata_rw_ctrl2, int, - hwif->io_ports.data_addr); - reg_ata_rw_trf_cnt trf_cnt = {0}; - - mycontext.saved_data = (dma_descr_data*)virt_to_phys(d); - mycontext.saved_data_buf = d->buf; - /* start the dma channel */ - DMA_START_CONTEXT(dir ? regi_dma3 : regi_dma2, virt_to_phys(&mycontext)); - - /* initiate a multi word dma read using PIO handshaking */ - trf_cnt.cnt = len >> 1; - /* Due to a "feature" the transfer count has to be one extra word for UDMA. */ - if (type == TYPE_UDMA) - trf_cnt.cnt++; - REG_WR(ata, regi_ata, rw_trf_cnt, trf_cnt); - - ctrl2.rw = dir ? regk_ata_rd : regk_ata_wr; - ctrl2.trf_mode = regk_ata_dma; - ctrl2.hsh = type == TYPE_PIO ? regk_ata_pio : - type == TYPE_DMA ? regk_ata_dma : regk_ata_udma; - ctrl2.multi = regk_ata_yes; - ctrl2.dma_size = regk_ata_word; - REG_WR(ata, regi_ata, rw_ctrl2, ctrl2); -} - -static void -cris_ide_wait_dma(int dir) -{ - reg_dma_rw_stat status; - do - { - status = REG_RD(dma, dir ? regi_dma3 : regi_dma2, rw_stat); - } while(status.list_state != regk_dma_data_at_eol); -} - -static int cris_dma_test_irq(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - int intr = REG_RD_INT(ata, regi_ata, r_intr); - - reg_ata_rw_ctrl2 ctrl2 = REG_TYPE_CONV(reg_ata_rw_ctrl2, int, - hwif->io_ports.data_addr); - - return intr & (1 << ctrl2.sel) ? 1 : 0; -} - -static void cris_ide_initialize_dma(int dir) -{ -} - -#else -/* CRISv10 specifics */ -#include <asm/arch/svinto.h> -#include <asm/arch/io_interface_mux.h> - -/* PIO timing (in R_ATA_CONFIG) - * - * _____________________________ - * ADDRESS : ________/ - * - * _______________ - * DIOR : ____________/ \__________ - * - * _______________ - * DATA : XXXXXXXXXXXXXXXX_______________XXXXXXXX - * - * - * DIOR is unbuffered while address and data is buffered. - * This creates two problems: - * 1. The DIOR pulse is to early (because it is unbuffered) - * 2. The rise time of DIOR is long - * - * There are at least three different plausible solutions - * 1. Use a pad capable of larger currents in Etrax - * 2. Use an external buffer - * 3. Make the strobe pulse longer - * - * Some of the strobe timings below are modified to compensate - * for this. This implies a slight performance decrease. - * - * THIS SHOULD NEVER BE CHANGED! - * - * TODO: Is this true for the latest LX boards still ? - */ - -#define ATA_UDMA2_CYC 0 /* No UDMA supported, just to make it compile. */ -#define ATA_UDMA2_DVS 0 -#define ATA_UDMA1_CYC 0 -#define ATA_UDMA1_DVS 0 -#define ATA_UDMA0_CYC 0 -#define ATA_UDMA0_DVS 0 -#define ATA_DMA2_STROBE 4 -#define ATA_DMA2_HOLD 0 -#define ATA_DMA1_STROBE 4 -#define ATA_DMA1_HOLD 1 -#define ATA_DMA0_STROBE 12 -#define ATA_DMA0_HOLD 9 -#define ATA_PIO4_SETUP 1 -#define ATA_PIO4_STROBE 5 -#define ATA_PIO4_HOLD 0 -#define ATA_PIO3_SETUP 1 -#define ATA_PIO3_STROBE 5 -#define ATA_PIO3_HOLD 1 -#define ATA_PIO2_SETUP 1 -#define ATA_PIO2_STROBE 6 -#define ATA_PIO2_HOLD 2 -#define ATA_PIO1_SETUP 2 -#define ATA_PIO1_STROBE 11 -#define ATA_PIO1_HOLD 4 -#define ATA_PIO0_SETUP 4 -#define ATA_PIO0_STROBE 19 -#define ATA_PIO0_HOLD 4 - -int -cris_ide_ack_intr(ide_hwif_t* hwif) -{ - return 1; -} - -static inline int -cris_ide_busy(void) -{ - return *R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy) ; -} - -static inline int -cris_ide_ready(void) -{ - return *R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, tr_rdy) ; -} - -static inline int -cris_ide_data_available(unsigned short* data) -{ - unsigned long status = *R_ATA_STATUS_DATA; - *data = (unsigned short)status; - return status & IO_MASK(R_ATA_STATUS_DATA, dav); -} - -static void -cris_ide_write_command(unsigned long command) -{ - *R_ATA_CTRL_DATA = command; -} - -static void -cris_ide_set_speed(int type, int setup, int strobe, int hold) -{ - static int pio_setup = ATA_PIO4_SETUP; - static int pio_strobe = ATA_PIO4_STROBE; - static int pio_hold = ATA_PIO4_HOLD; - static int dma_strobe = ATA_DMA2_STROBE; - static int dma_hold = ATA_DMA2_HOLD; - - if (type == TYPE_PIO) { - pio_setup = setup; - pio_strobe = strobe; - pio_hold = hold; - } else if (type == TYPE_DMA) { - dma_strobe = strobe; - dma_hold = hold; - } - *R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable, 1 ) | - IO_FIELD( R_ATA_CONFIG, dma_strobe, dma_strobe ) | - IO_FIELD( R_ATA_CONFIG, dma_hold, dma_hold ) | - IO_FIELD( R_ATA_CONFIG, pio_setup, pio_setup ) | - IO_FIELD( R_ATA_CONFIG, pio_strobe, pio_strobe ) | - IO_FIELD( R_ATA_CONFIG, pio_hold, pio_hold ) ); -} - -static unsigned long -cris_ide_base_address(int bus) -{ - return IO_FIELD(R_ATA_CTRL_DATA, sel, bus); -} - -static unsigned long -cris_ide_reg_addr(unsigned long addr, int cs0, int cs1) -{ - return IO_FIELD(R_ATA_CTRL_DATA, addr, addr) | - IO_FIELD(R_ATA_CTRL_DATA, cs0, cs0) | - IO_FIELD(R_ATA_CTRL_DATA, cs1, cs1); -} - -static __init void -cris_ide_reset(unsigned val) -{ -#ifdef CONFIG_ETRAX_IDE_G27_RESET - REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, 27, val); -#endif -#ifdef CONFIG_ETRAX_IDE_PB7_RESET - port_pb_dir_shadow = port_pb_dir_shadow | - IO_STATE(R_PORT_PB_DIR, dir7, output); - *R_PORT_PB_DIR = port_pb_dir_shadow; - REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, 7, val); -#endif -} - -static __init void -cris_ide_init(void) -{ - volatile unsigned int dummy; - - *R_ATA_CTRL_DATA = 0; - *R_ATA_TRANSFER_CNT = 0; - *R_ATA_CONFIG = 0; - - if (cris_request_io_interface(if_ata, "ETRAX100LX IDE")) { - printk(KERN_CRIT "ide: Failed to get IO interface\n"); - return; - } else if (cris_request_dma(ATA_TX_DMA_NBR, - "ETRAX100LX IDE TX", - DMA_VERBOSE_ON_ERROR, - dma_ata)) { - cris_free_io_interface(if_ata); - printk(KERN_CRIT "ide: Failed to get Tx DMA channel\n"); - return; - } else if (cris_request_dma(ATA_RX_DMA_NBR, - "ETRAX100LX IDE RX", - DMA_VERBOSE_ON_ERROR, - dma_ata)) { - cris_free_dma(ATA_TX_DMA_NBR, "ETRAX100LX IDE Tx"); - cris_free_io_interface(if_ata); - printk(KERN_CRIT "ide: Failed to get Rx DMA channel\n"); - return; - } - - /* make a dummy read to set the ata controller in a proper state */ - dummy = *R_ATA_STATUS_DATA; - - *R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable, 1 )); - *R_ATA_CTRL_DATA = ( IO_STATE( R_ATA_CTRL_DATA, rw, read) | - IO_FIELD( R_ATA_CTRL_DATA, addr, 1 ) ); - - while(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)); /* wait for busy flag*/ - - *R_IRQ_MASK0_SET = ( IO_STATE( R_IRQ_MASK0_SET, ata_irq0, set ) | - IO_STATE( R_IRQ_MASK0_SET, ata_irq1, set ) | - IO_STATE( R_IRQ_MASK0_SET, ata_irq2, set ) | - IO_STATE( R_IRQ_MASK0_SET, ata_irq3, set ) ); - - /* reset the dma channels we will use */ - - RESET_DMA(ATA_TX_DMA_NBR); - RESET_DMA(ATA_RX_DMA_NBR); - WAIT_DMA(ATA_TX_DMA_NBR); - WAIT_DMA(ATA_RX_DMA_NBR); -} - -#define cris_dma_descr_type etrax_dma_descr -#define cris_pio_read IO_STATE(R_ATA_CTRL_DATA, rw, read) -#define cris_ultra_mask 0x0 -#define MAX_DESCR_SIZE 0x10000UL - -static unsigned long -cris_ide_get_reg(unsigned long reg) -{ - return (reg & 0x0e000000) >> 25; -} - -static void -cris_ide_fill_descriptor(cris_dma_descr_type *d, void* buf, unsigned int len, int last) -{ - d->buf = virt_to_phys(buf); - d->sw_len = len == MAX_DESCR_SIZE ? 0 : len; - if (last) - d->ctrl |= d_eol; -} - -static void cris_ide_start_dma(ide_drive_t *drive, cris_dma_descr_type *d, int dir, int type, int len) -{ - unsigned long cmd; - - if (dir) { - /* need to do this before RX DMA due to a chip bug - * it is enough to just flush the part of the cache that - * corresponds to the buffers we start, but since HD transfers - * usually are more than 8 kB, it is easier to optimize for the - * normal case and just flush the entire cache. its the only - * way to be sure! (OB movie quote) - */ - flush_etrax_cache(); - *R_DMA_CH3_FIRST = virt_to_phys(d); - *R_DMA_CH3_CMD = IO_STATE(R_DMA_CH3_CMD, cmd, start); - - } else { - *R_DMA_CH2_FIRST = virt_to_phys(d); - *R_DMA_CH2_CMD = IO_STATE(R_DMA_CH2_CMD, cmd, start); - } - - /* initiate a multi word dma read using DMA handshaking */ - - *R_ATA_TRANSFER_CNT = - IO_FIELD(R_ATA_TRANSFER_CNT, count, len >> 1); - - cmd = dir ? IO_STATE(R_ATA_CTRL_DATA, rw, read) : IO_STATE(R_ATA_CTRL_DATA, rw, write); - cmd |= type == TYPE_PIO ? IO_STATE(R_ATA_CTRL_DATA, handsh, pio) : - IO_STATE(R_ATA_CTRL_DATA, handsh, dma); - *R_ATA_CTRL_DATA = - cmd | - IO_FIELD(R_ATA_CTRL_DATA, data, - drive->hwif->io_ports.data_addr) | - IO_STATE(R_ATA_CTRL_DATA, src_dst, dma) | - IO_STATE(R_ATA_CTRL_DATA, multi, on) | - IO_STATE(R_ATA_CTRL_DATA, dma_size, word); -} - -static void -cris_ide_wait_dma(int dir) -{ - if (dir) - WAIT_DMA(ATA_RX_DMA_NBR); - else - WAIT_DMA(ATA_TX_DMA_NBR); -} - -static int cris_dma_test_irq(ide_drive_t *drive) -{ - int intr = *R_IRQ_MASK0_RD; - int bus = IO_EXTRACT(R_ATA_CTRL_DATA, sel, - drive->hwif->io_ports.data_addr); - - return intr & (1 << (bus + IO_BITNR(R_IRQ_MASK0_RD, ata_irq0))) ? 1 : 0; -} - - -static void cris_ide_initialize_dma(int dir) -{ - if (dir) - { - RESET_DMA(ATA_RX_DMA_NBR); /* sometimes the DMA channel get stuck so we need to do this */ - WAIT_DMA(ATA_RX_DMA_NBR); - } - else - { - RESET_DMA(ATA_TX_DMA_NBR); /* sometimes the DMA channel get stuck so we need to do this */ - WAIT_DMA(ATA_TX_DMA_NBR); - } -} - -#endif - -void -cris_ide_outw(unsigned short data, unsigned long reg) { - int timeleft; - - LOWDB(printk("ow: data 0x%x, reg 0x%x\n", data, reg)); - - /* note the lack of handling any timeouts. we stop waiting, but we don't - * really notify anybody. - */ - - timeleft = IDE_REGISTER_TIMEOUT; - /* wait for busy flag */ - do { - timeleft--; - } while(timeleft && cris_ide_busy()); - - /* - * Fall through at a timeout, so the ongoing command will be - * aborted by the write below, which is expected to be a dummy - * command to the command register. This happens when a faulty - * drive times out on a command. See comment on timeout in - * INB. - */ - if(!timeleft) - printk("ATA timeout reg 0x%lx := 0x%x\n", reg, data); - - cris_ide_write_command(reg|data); /* write data to the drive's register */ - - timeleft = IDE_REGISTER_TIMEOUT; - /* wait for transmitter ready */ - do { - timeleft--; - } while(timeleft && !cris_ide_ready()); -} - -void -cris_ide_outb(unsigned char data, unsigned long reg) -{ - cris_ide_outw(data, reg); -} - -void -cris_ide_outbsync(ide_drive_t *drive, u8 addr, unsigned long port) -{ - cris_ide_outw(addr, port); -} - -unsigned short -cris_ide_inw(unsigned long reg) { - int timeleft; - unsigned short val; - - timeleft = IDE_REGISTER_TIMEOUT; - /* wait for busy flag */ - do { - timeleft--; - } while(timeleft && cris_ide_busy()); - - if(!timeleft) { - /* - * If we're asked to read the status register, like for - * example when a command does not complete for an - * extended time, but the ATA interface is stuck in a - * busy state at the *ETRAX* ATA interface level (as has - * happened repeatedly with at least one bad disk), then - * the best thing to do is to pretend that we read - * "busy" in the status register, so the IDE driver will - * time-out, abort the ongoing command and perform a - * reset sequence. Note that the subsequent OUT_BYTE - * call will also timeout on busy, but as long as the - * write is still performed, everything will be fine. - */ - if (cris_ide_get_reg(reg) == 7) - return BUSY_STAT; - else - /* For other rare cases we assume 0 is good enough. */ - return 0; - } - - cris_ide_write_command(reg | cris_pio_read); - - timeleft = IDE_REGISTER_TIMEOUT; - /* wait for available */ - do { - timeleft--; - } while(timeleft && !cris_ide_data_available(&val)); - - if(!timeleft) - return 0; - - LOWDB(printk("inb: 0x%x from reg 0x%x\n", val & 0xff, reg)); - - return val; -} - -unsigned char -cris_ide_inb(unsigned long reg) -{ - return (unsigned char)cris_ide_inw(reg); -} - -static void cris_ide_input_data (ide_drive_t *drive, void *, unsigned int); -static void cris_ide_output_data (ide_drive_t *drive, void *, unsigned int); -static void cris_atapi_input_bytes(ide_drive_t *drive, void *, unsigned int); -static void cris_atapi_output_bytes(ide_drive_t *drive, void *, unsigned int); - -static void cris_dma_host_set(ide_drive_t *drive, int on) -{ -} - -static void cris_set_pio_mode(ide_drive_t *drive, const u8 pio) -{ - int setup, strobe, hold; - - switch(pio) - { - case 0: - setup = ATA_PIO0_SETUP; - strobe = ATA_PIO0_STROBE; - hold = ATA_PIO0_HOLD; - break; - case 1: - setup = ATA_PIO1_SETUP; - strobe = ATA_PIO1_STROBE; - hold = ATA_PIO1_HOLD; - break; - case 2: - setup = ATA_PIO2_SETUP; - strobe = ATA_PIO2_STROBE; - hold = ATA_PIO2_HOLD; - break; - case 3: - setup = ATA_PIO3_SETUP; - strobe = ATA_PIO3_STROBE; - hold = ATA_PIO3_HOLD; - break; - case 4: - setup = ATA_PIO4_SETUP; - strobe = ATA_PIO4_STROBE; - hold = ATA_PIO4_HOLD; - break; - default: - return; - } - - cris_ide_set_speed(TYPE_PIO, setup, strobe, hold); -} - -static void cris_set_dma_mode(ide_drive_t *drive, const u8 speed) -{ - int cyc = 0, dvs = 0, strobe = 0, hold = 0; - - switch(speed) - { - case XFER_UDMA_0: - cyc = ATA_UDMA0_CYC; - dvs = ATA_UDMA0_DVS; - break; - case XFER_UDMA_1: - cyc = ATA_UDMA1_CYC; - dvs = ATA_UDMA1_DVS; - break; - case XFER_UDMA_2: - cyc = ATA_UDMA2_CYC; - dvs = ATA_UDMA2_DVS; - break; - case XFER_MW_DMA_0: - strobe = ATA_DMA0_STROBE; - hold = ATA_DMA0_HOLD; - break; - case XFER_MW_DMA_1: - strobe = ATA_DMA1_STROBE; - hold = ATA_DMA1_HOLD; - break; - case XFER_MW_DMA_2: - strobe = ATA_DMA2_STROBE; - hold = ATA_DMA2_HOLD; - break; - } - - if (speed >= XFER_UDMA_0) - cris_ide_set_speed(TYPE_UDMA, cyc, dvs, 0); - else - cris_ide_set_speed(TYPE_DMA, 0, strobe, hold); -} - -static void __init cris_setup_ports(hw_regs_t *hw, unsigned long base) -{ - int i; - - memset(hw, 0, sizeof(*hw)); - - for (i = 0; i <= 7; i++) - hw->io_ports_array[i] = base + cris_ide_reg_addr(i, 0, 1); - - /* - * the IDE control register is at ATA address 6, - * with CS1 active instead of CS0 - */ - hw->io_ports.ctl_addr = base + cris_ide_reg_addr(6, 1, 0); - - hw->irq = ide_default_irq(0); - hw->ack_intr = cris_ide_ack_intr; -} - -static const struct ide_port_ops cris_port_ops = { - .set_pio_mode = cris_set_pio_mode, - .set_dma_mode = cris_set_dma_mode, -}; - -static const struct ide_dma_ops cris_dma_ops; - -static const struct ide_port_info cris_port_info __initdata = { - .chipset = ide_etrax100, - .port_ops = &cris_port_ops, - .dma_ops = &cris_dma_ops, - .host_flags = IDE_HFLAG_NO_ATAPI_DMA | - IDE_HFLAG_NO_DMA, /* no SFF-style DMA */ - .pio_mask = ATA_PIO4, - .udma_mask = cris_ultra_mask, - .mwdma_mask = ATA_MWDMA2, -}; - -static int __init init_e100_ide(void) -{ - hw_regs_t hw; - int h; - u8 idx[4] = { 0xff, 0xff, 0xff, 0xff }; - - printk("ide: ETRAX FS built-in ATA DMA controller\n"); - - for (h = 0; h < 4; h++) { - ide_hwif_t *hwif = NULL; - - cris_setup_ports(&hw, cris_ide_base_address(h)); - - hwif = ide_find_port(); - if (hwif == NULL) - continue; - ide_init_port_data(hwif, hwif->index); - ide_init_port_hw(hwif, &hw); - - hwif->ata_input_data = &cris_ide_input_data; - hwif->ata_output_data = &cris_ide_output_data; - hwif->atapi_input_bytes = &cris_atapi_input_bytes; - hwif->atapi_output_bytes = &cris_atapi_output_bytes; - hwif->OUTB = &cris_ide_outb; - hwif->OUTW = &cris_ide_outw; - hwif->OUTBSYNC = &cris_ide_outbsync; - hwif->INB = &cris_ide_inb; - hwif->INW = &cris_ide_inw; - hwif->cbl = ATA_CBL_PATA40; - - idx[h] = hwif->index; - } - - /* Reset pulse */ - cris_ide_reset(0); - udelay(25); - cris_ide_reset(1); - - cris_ide_init(); - - cris_ide_set_speed(TYPE_PIO, ATA_PIO4_SETUP, ATA_PIO4_STROBE, ATA_PIO4_HOLD); - cris_ide_set_speed(TYPE_DMA, 0, ATA_DMA2_STROBE, ATA_DMA2_HOLD); - cris_ide_set_speed(TYPE_UDMA, ATA_UDMA2_CYC, ATA_UDMA2_DVS, 0); - - ide_device_add(idx, &cris_port_info); - - return 0; -} - -static cris_dma_descr_type mydescr __attribute__ ((__aligned__(16))); - -/* - * The following routines are mainly used by the ATAPI drivers. - * - * These routines will round up any request for an odd number of bytes, - * so if an odd bytecount is specified, be sure that there's at least one - * extra byte allocated for the buffer. - */ -static void -cris_atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount) -{ - D(printk("atapi_input_bytes, buffer 0x%x, count %d\n", - buffer, bytecount)); - - if(bytecount & 1) { - printk("warning, odd bytecount in cdrom_in_bytes = %d.\n", bytecount); - bytecount++; /* to round off */ - } - - /* setup DMA and start transfer */ - - cris_ide_fill_descriptor(&mydescr, buffer, bytecount, 1); - cris_ide_start_dma(drive, &mydescr, 1, TYPE_PIO, bytecount); - - /* wait for completion */ - LED_DISK_READ(1); - cris_ide_wait_dma(1); - LED_DISK_READ(0); -} - -static void -cris_atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount) -{ - D(printk("atapi_output_bytes, buffer 0x%x, count %d\n", - buffer, bytecount)); - - if(bytecount & 1) { - printk("odd bytecount %d in atapi_out_bytes!\n", bytecount); - bytecount++; - } - - cris_ide_fill_descriptor(&mydescr, buffer, bytecount, 1); - cris_ide_start_dma(drive, &mydescr, 0, TYPE_PIO, bytecount); - - /* wait for completion */ - - LED_DISK_WRITE(1); - LED_DISK_READ(1); - cris_ide_wait_dma(0); - LED_DISK_WRITE(0); -} - -/* - * This is used for most PIO data transfers *from* the IDE interface - */ -static void -cris_ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount) -{ - cris_atapi_input_bytes(drive, buffer, wcount << 2); -} - -/* - * This is used for most PIO data transfers *to* the IDE interface - */ -static void -cris_ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount) -{ - cris_atapi_output_bytes(drive, buffer, wcount << 2); -} - -/* we only have one DMA channel on the chip for ATA, so we can keep these statically */ -static cris_dma_descr_type ata_descrs[MAX_DMA_DESCRS] __attribute__ ((__aligned__(16))); -static unsigned int ata_tot_size; - -/* - * cris_ide_build_dmatable() prepares a dma request. - * Returns 0 if all went okay, returns 1 otherwise. - */ -static int cris_ide_build_dmatable (ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - struct scatterlist* sg; - struct request *rq = drive->hwif->hwgroup->rq; - unsigned long size, addr; - unsigned int count = 0; - int i = 0; - - sg = hwif->sg_table; - - ata_tot_size = 0; - - ide_map_sg(drive, rq); - i = hwif->sg_nents; - - while(i) { - /* - * Determine addr and size of next buffer area. We assume that - * individual virtual buffers are always composed linearly in - * physical memory. For example, we assume that any 8kB buffer - * is always composed of two adjacent physical 4kB pages rather - * than two possibly non-adjacent physical 4kB pages. - */ - /* group sequential buffers into one large buffer */ - addr = sg_phys(sg); - size = sg_dma_len(sg); - while (--i) { - sg = sg_next(sg); - if ((addr + size) != sg_phys(sg)) - break; - size += sg_dma_len(sg); - } - - /* did we run out of descriptors? */ - - if(count >= MAX_DMA_DESCRS) { - printk("%s: too few DMA descriptors\n", drive->name); - return 1; - } - - /* however, this case is more difficult - rw_trf_cnt cannot be more - than 65536 words per transfer, so in that case we need to either - 1) use a DMA interrupt to re-trigger rw_trf_cnt and continue with - the descriptors, or - 2) simply do the request here, and get dma_intr to only ide_end_request on - those blocks that were actually set-up for transfer. - */ - - if(ata_tot_size + size > 131072) { - printk("too large total ATA DMA request, %d + %d!\n", ata_tot_size, (int)size); - return 1; - } - - /* If size > MAX_DESCR_SIZE it has to be splitted into new descriptors. Since we - don't handle size > 131072 only one split is necessary */ - - if(size > MAX_DESCR_SIZE) { - cris_ide_fill_descriptor(&ata_descrs[count], (void*)addr, MAX_DESCR_SIZE, 0); - count++; - ata_tot_size += MAX_DESCR_SIZE; - size -= MAX_DESCR_SIZE; - addr += MAX_DESCR_SIZE; - } - - cris_ide_fill_descriptor(&ata_descrs[count], (void*)addr, size,i ? 0 : 1); - count++; - ata_tot_size += size; - } - - if (count) { - /* return and say all is ok */ - return 0; - } - - printk("%s: empty DMA table?\n", drive->name); - return 1; /* let the PIO routines handle this weirdness */ -} - -/* - * cris_dma_intr() is the handler for disk read/write DMA interrupts - */ -static ide_startstop_t cris_dma_intr (ide_drive_t *drive) -{ - LED_DISK_READ(0); - LED_DISK_WRITE(0); - - return ide_dma_intr(drive); -} - -/* - * Functions below initiates/aborts DMA read/write operations on a drive. - * - * The caller is assumed to have selected the drive and programmed the drive's - * sector address using CHS or LBA. All that remains is to prepare for DMA - * and then issue the actual read/write DMA/PIO command to the drive. - * - * For ATAPI devices, we just prepare for DMA and return. The caller should - * then issue the packet command to the drive and call us again with - * cris_dma_start afterwards. - * - * Returns 0 if all went well. - * Returns 1 if DMA read/write could not be started, in which case - * the caller should revert to PIO for the current request. - */ - -static int cris_dma_end(ide_drive_t *drive) -{ - drive->waiting_for_dma = 0; - return 0; -} - -static int cris_dma_setup(ide_drive_t *drive) -{ - struct request *rq = drive->hwif->hwgroup->rq; - - cris_ide_initialize_dma(!rq_data_dir(rq)); - if (cris_ide_build_dmatable (drive)) { - ide_map_sg(drive, rq); - return 1; - } - - drive->waiting_for_dma = 1; - return 0; -} - -static void cris_dma_exec_cmd(ide_drive_t *drive, u8 command) -{ - ide_execute_command(drive, command, &cris_dma_intr, WAIT_CMD, NULL); -} - -static void cris_dma_start(ide_drive_t *drive) -{ - struct request *rq = drive->hwif->hwgroup->rq; - int writing = rq_data_dir(rq); - int type = TYPE_DMA; - - if (drive->current_speed >= XFER_UDMA_0) - type = TYPE_UDMA; - - cris_ide_start_dma(drive, &ata_descrs[0], writing ? 0 : 1, type, ata_tot_size); - - if (writing) { - LED_DISK_WRITE(1); - } else { - LED_DISK_READ(1); - } -} - -static const struct ide_dma_ops cris_dma_ops = { - .dma_host_set = cris_dma_host_set, - .dma_setup = cris_dma_setup, - .dma_exec_cmd = cris_dma_exec_cmd, - .dma_start = cris_dma_start, - .dma_end = cris_dma_end, - .dma_test_irq = cris_dma_test_irq, -}; - -module_init(init_e100_ide); - -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/h8300/ide-h8300.c b/drivers/ide/h8300/ide-h8300.c index fd23f12e17a..ecf53bb0d2a 100644 --- a/drivers/ide/h8300/ide-h8300.c +++ b/drivers/ide/h8300/ide-h8300.c @@ -42,6 +42,91 @@ static u16 mm_inw(unsigned long a) return r; } +static void h8300_tf_load(ide_drive_t *drive, ide_task_t *task) +{ + ide_hwif_t *hwif = drive->hwif; + struct ide_io_ports *io_ports = &hwif->io_ports; + struct ide_taskfile *tf = &task->tf; + u8 HIHI = (task->tf_flags & IDE_TFLAG_LBA48) ? 0xE0 : 0xEF; + + if (task->tf_flags & IDE_TFLAG_FLAGGED) + HIHI = 0xFF; + + ide_set_irq(drive, 1); + + if (task->tf_flags & IDE_TFLAG_OUT_DATA) + mm_outw((tf->hob_data << 8) | tf->data, io_ports->data_addr); + + if (task->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE) + outb(tf->hob_feature, io_ports->feature_addr); + if (task->tf_flags & IDE_TFLAG_OUT_HOB_NSECT) + outb(tf->hob_nsect, io_ports->nsect_addr); + if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAL) + outb(tf->hob_lbal, io_ports->lbal_addr); + if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAM) + outb(tf->hob_lbam, io_ports->lbam_addr); + if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAH) + outb(tf->hob_lbah, io_ports->lbah_addr); + + if (task->tf_flags & IDE_TFLAG_OUT_FEATURE) + outb(tf->feature, io_ports->feature_addr); + if (task->tf_flags & IDE_TFLAG_OUT_NSECT) + outb(tf->nsect, io_ports->nsect_addr); + if (task->tf_flags & IDE_TFLAG_OUT_LBAL) + outb(tf->lbal, io_ports->lbal_addr); + if (task->tf_flags & IDE_TFLAG_OUT_LBAM) + outb(tf->lbam, io_ports->lbam_addr); + if (task->tf_flags & IDE_TFLAG_OUT_LBAH) + outb(tf->lbah, io_ports->lbah_addr); + + if (task->tf_flags & IDE_TFLAG_OUT_DEVICE) + outb((tf->device & HIHI) | drive->select.all, + io_ports->device_addr); +} + +static void h8300_tf_read(ide_drive_t *drive, ide_task_t *task) +{ + ide_hwif_t *hwif = drive->hwif; + struct ide_io_ports *io_ports = &hwif->io_ports; + struct ide_taskfile *tf = &task->tf; + + if (task->tf_flags & IDE_TFLAG_IN_DATA) { + u16 data = mm_inw(io_ports->data_addr); + + tf->data = data & 0xff; + tf->hob_data = (data >> 8) & 0xff; + } + + /* be sure we're looking at the low order bits */ + outb(drive->ctl & ~0x80, io_ports->ctl_addr); + + if (task->tf_flags & IDE_TFLAG_IN_NSECT) + tf->nsect = inb(io_ports->nsect_addr); + if (task->tf_flags & IDE_TFLAG_IN_LBAL) + tf->lbal = inb(io_ports->lbal_addr); + if (task->tf_flags & IDE_TFLAG_IN_LBAM) + tf->lbam = inb(io_ports->lbam_addr); + if (task->tf_flags & IDE_TFLAG_IN_LBAH) + tf->lbah = inb(io_ports->lbah_addr); + if (task->tf_flags & IDE_TFLAG_IN_DEVICE) + tf->device = inb(io_ports->device_addr); + + if (task->tf_flags & IDE_TFLAG_LBA48) { + outb(drive->ctl | 0x80, io_ports->ctl_addr); + + if (task->tf_flags & IDE_TFLAG_IN_HOB_FEATURE) + tf->hob_feature = inb(io_ports->feature_addr); + if (task->tf_flags & IDE_TFLAG_IN_HOB_NSECT) + tf->hob_nsect = inb(io_ports->nsect_addr); + if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAL) + tf->hob_lbal = inb(io_ports->lbal_addr); + if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAM) + tf->hob_lbam = inb(io_ports->lbam_addr); + if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAH) + tf->hob_lbah = inb(io_ports->lbah_addr); + } +} + static void mm_outsw(unsigned long addr, void *buf, u32 len) { unsigned short *bp = (unsigned short *)buf; @@ -56,6 +141,18 @@ static void mm_insw(unsigned long addr, void *buf, u32 len) *bp = bswap(*(volatile u16 *)addr); } +static void h8300_input_data(ide_drive_t *drive, struct request *rq, + void *buf, unsigned int len) +{ + mm_insw(drive->hwif->io_ports.data_addr, buf, (len + 1) / 2); +} + +static void h8300_output_data(ide_drive_t *drive, struct request *rq, + void *buf, unsigned int len) +{ + mm_outsw(drive->hwif->io_ports.data_addr, buf, (len + 1) / 2); +} + #define H8300_IDE_GAP (2) static inline void hw_setup(hw_regs_t *hw) @@ -74,12 +171,11 @@ static inline void hwif_setup(ide_hwif_t *hwif) { default_hwif_iops(hwif); - hwif->OUTW = mm_outw; - hwif->OUTSW = mm_outsw; - hwif->INW = mm_inw; - hwif->INSW = mm_insw; - hwif->OUTSL = NULL; - hwif->INSL = NULL; + hwif->tf_load = h8300_tf_load; + hwif->tf_read = h8300_tf_read; + + hwif->input_data = h8300_input_data; + hwif->output_data = h8300_output_data; } static int __init h8300_ide_init(void) diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index b34fd2bde96..68e7f19dc03 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -142,7 +142,6 @@ static void cdrom_analyze_sense_data(ide_drive_t *drive, { unsigned long sector; unsigned long bio_sectors; - unsigned long valid; struct cdrom_info *info = drive->driver_data; if (!cdrom_log_sense(drive, failed_command, sense)) @@ -173,17 +172,13 @@ static void cdrom_analyze_sense_data(ide_drive_t *drive, (sense->information[2] << 8) | (sense->information[3]); - bio_sectors = bio_sectors(failed_command->bio); - if (bio_sectors < 4) - bio_sectors = 4; if (drive->queue->hardsect_size == 2048) /* device sector size is 2K */ sector <<= 2; + + bio_sectors = max(bio_sectors(failed_command->bio), 4U); sector &= ~(bio_sectors - 1); - valid = (sector - failed_command->sector) << 9; - if (valid < 0) - valid = 0; if (sector < get_capacity(info->disk) && drive->probed_capacity - sector < 4 * 75) set_capacity(info->disk, sector); @@ -555,14 +550,7 @@ static ide_startstop_t cdrom_start_packet_command(ide_drive_t *drive, ATAPI_WAIT_PC, cdrom_timer_expiry); return ide_started; } else { - unsigned long flags; - - /* packet command */ - spin_lock_irqsave(&ide_lock, flags); - hwif->OUTBSYNC(drive, WIN_PACKETCMD, - hwif->io_ports.command_addr); - ndelay(400); - spin_unlock_irqrestore(&ide_lock, flags); + ide_execute_pkt_cmd(drive); return (*handler) (drive); } @@ -613,7 +601,7 @@ static ide_startstop_t cdrom_transfer_packet_command(ide_drive_t *drive, cmd_len = ATAPI_MIN_CDB_BYTES; /* send the command to the device */ - HWIF(drive)->atapi_output_bytes(drive, rq->cmd, cmd_len); + hwif->output_data(drive, NULL, rq->cmd, cmd_len); /* start the DMA if need be */ if (info->dma) @@ -629,7 +617,7 @@ static void ide_cd_pad_transfer(ide_drive_t *drive, xfer_func_t *xf, int len) { while (len > 0) { int dum = 0; - xf(drive, &dum, sizeof(dum)); + xf(drive, NULL, &dum, sizeof(dum)); len -= sizeof(dum); } } @@ -639,7 +627,7 @@ static void ide_cd_drain_data(ide_drive_t *drive, int nsects) while (nsects > 0) { static char dum[SECTOR_SIZE]; - drive->hwif->atapi_input_bytes(drive, dum, sizeof(dum)); + drive->hwif->input_data(drive, NULL, dum, sizeof(dum)); nsects--; } } @@ -666,7 +654,7 @@ static int ide_cd_check_ireason(ide_drive_t *drive, struct request *rq, printk(KERN_ERR "%s: %s: wrong transfer direction!\n", drive->name, __func__); - xf = rw ? hwif->atapi_output_bytes : hwif->atapi_input_bytes; + xf = rw ? hwif->output_data : hwif->input_data; ide_cd_pad_transfer(drive, xf, len); } else if (rw == 0 && ireason == 1) { /* @@ -794,7 +782,7 @@ static ide_startstop_t cdrom_start_seek_continuation(ide_drive_t *drive) sector_div(frame, queue_hardsect_size(drive->queue) >> SECTOR_BITS); - memset(rq->cmd, 0, sizeof(rq->cmd)); + memset(rq->cmd, 0, BLK_MAX_CDB); rq->cmd[0] = GPCMD_SEEK; put_unaligned(cpu_to_be32(frame), (unsigned int *) &rq->cmd[2]); @@ -1019,10 +1007,10 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) if (ireason == 0) { write = 1; - xferfunc = HWIF(drive)->atapi_output_bytes; + xferfunc = hwif->output_data; } else { write = 0; - xferfunc = HWIF(drive)->atapi_input_bytes; + xferfunc = hwif->input_data; } /* transfer data */ @@ -1061,7 +1049,7 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) if (blen > thislen) blen = thislen; - xferfunc(drive, ptr, blen); + xferfunc(drive, NULL, ptr, blen); thislen -= blen; len -= blen; @@ -1706,7 +1694,7 @@ static int ide_cdrom_prep_fs(struct request_queue *q, struct request *rq) long block = (long)rq->hard_sector / (hard_sect >> 9); unsigned long blocks = rq->hard_nr_sectors / (hard_sect >> 9); - memset(rq->cmd, 0, sizeof(rq->cmd)); + memset(rq->cmd, 0, BLK_MAX_CDB); if (rq_data_dir(rq) == READ) rq->cmd[0] = GPCMD_READ_10; diff --git a/drivers/ide/ide-cd_verbose.c b/drivers/ide/ide-cd_verbose.c index 6ed7ca07133..6490a2dea96 100644 --- a/drivers/ide/ide-cd_verbose.c +++ b/drivers/ide/ide-cd_verbose.c @@ -326,7 +326,7 @@ void ide_cd_log_error(const char *name, struct request *failed_command, printk(KERN_ERR " The failed \"%s\" packet command " "was: \n \"", s); - for (i = 0; i < sizeof(failed_command->cmd); i++) + for (i = 0; i < BLK_MAX_CDB; i++) printk(KERN_CONT "%02x ", failed_command->cmd[i]); printk(KERN_CONT "\"\n"); } diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c index c352cf27b6e..653b1ade13d 100644 --- a/drivers/ide/ide-dma.c +++ b/drivers/ide/ide-dma.c @@ -464,9 +464,10 @@ int ide_dma_setup(ide_drive_t *drive) /* PRD table */ if (hwif->mmio) - writel(hwif->dmatable_dma, (void __iomem *)hwif->dma_prdtable); + writel(hwif->dmatable_dma, + (void __iomem *)(hwif->dma_base + ATA_DMA_TABLE_OFS)); else - outl(hwif->dmatable_dma, hwif->dma_prdtable); + outl(hwif->dmatable_dma, hwif->dma_base + ATA_DMA_TABLE_OFS); /* specify r/w */ hwif->OUTB(reading, hwif->dma_command); @@ -858,14 +859,8 @@ void ide_setup_dma(ide_hwif_t *hwif, unsigned long base) if (!hwif->dma_command) hwif->dma_command = hwif->dma_base + 0; - if (!hwif->dma_vendor1) - hwif->dma_vendor1 = hwif->dma_base + 1; if (!hwif->dma_status) hwif->dma_status = hwif->dma_base + 2; - if (!hwif->dma_vendor3) - hwif->dma_vendor3 = hwif->dma_base + 3; - if (!hwif->dma_prdtable) - hwif->dma_prdtable = hwif->dma_base + 4; hwif->dma_ops = &sff_dma_ops; } diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c index 489079b8ed0..f05fbc2bd7a 100644 --- a/drivers/ide/ide-floppy.c +++ b/drivers/ide/ide-floppy.c @@ -231,6 +231,7 @@ static int idefloppy_end_request(ide_drive_t *drive, int uptodate, int nsecs) static void ide_floppy_io_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc, unsigned int bcount, int direction) { + ide_hwif_t *hwif = drive->hwif; struct request *rq = pc->rq; struct req_iterator iter; struct bio_vec *bvec; @@ -246,9 +247,9 @@ static void ide_floppy_io_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc, data = bvec_kmap_irq(bvec, &flags); if (direction) - drive->hwif->atapi_output_bytes(drive, data, count); + hwif->output_data(drive, NULL, data, count); else - drive->hwif->atapi_input_bytes(drive, data, count); + hwif->input_data(drive, NULL, data, count); bvec_kunmap_irq(data, &flags); bcount -= count; @@ -261,10 +262,7 @@ static void ide_floppy_io_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc, if (bcount) { printk(KERN_ERR "%s: leftover data in %s, bcount == %d\n", drive->name, __func__, bcount); - if (direction) - ide_atapi_write_zeros(drive, bcount); - else - ide_atapi_discard_data(drive, bcount); + ide_pad_transfer(drive, direction, bcount); } } @@ -490,7 +488,7 @@ static ide_startstop_t idefloppy_pc_intr(ide_drive_t *drive) printk(KERN_ERR "ide-floppy: The floppy wants " "to send us more data than expected " "- discarding data\n"); - ide_atapi_discard_data(drive, bcount); + ide_pad_transfer(drive, 0, bcount); ide_set_handler(drive, &idefloppy_pc_intr, @@ -503,12 +501,12 @@ static ide_startstop_t idefloppy_pc_intr(ide_drive_t *drive) } } if (pc->flags & PC_FLAG_WRITING) - xferfunc = hwif->atapi_output_bytes; + xferfunc = hwif->output_data; else - xferfunc = hwif->atapi_input_bytes; + xferfunc = hwif->input_data; if (pc->buf) - xferfunc(drive, pc->cur_pos, bcount); + xferfunc(drive, NULL, pc->cur_pos, bcount); else ide_floppy_io_buffers(drive, pc, bcount, !!(pc->flags & PC_FLAG_WRITING)); @@ -548,8 +546,10 @@ static ide_startstop_t idefloppy_transfer_pc(ide_drive_t *drive) /* Set the interrupt routine */ ide_set_handler(drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL); + /* Send the actual packet */ - HWIF(drive)->atapi_output_bytes(drive, floppy->pc->c, 12); + hwif->output_data(drive, NULL, floppy->pc->c, 12); + return ide_started; } @@ -569,7 +569,8 @@ static int idefloppy_transfer_pc2(ide_drive_t *drive) idefloppy_floppy_t *floppy = drive->driver_data; /* Send the actual packet */ - HWIF(drive)->atapi_output_bytes(drive, floppy->pc->c, 12); + drive->hwif->output_data(drive, NULL, floppy->pc->c, 12); + /* Timeout for the packet command */ return IDEFLOPPY_WAIT_CMD; } @@ -692,7 +693,7 @@ static ide_startstop_t idefloppy_issue_pc(ide_drive_t *drive, return ide_started; } else { /* Issue the packet command */ - hwif->OUTB(WIN_PACKETCMD, hwif->io_ports.command_addr); + ide_execute_pkt_cmd(drive); return (*pkt_xfer_routine) (drive); } } diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index 3a2d8930d17..696525342e9 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -295,49 +295,6 @@ static void ide_complete_pm_request (ide_drive_t *drive, struct request *rq) spin_unlock_irqrestore(&ide_lock, flags); } -void ide_tf_read(ide_drive_t *drive, ide_task_t *task) -{ - ide_hwif_t *hwif = drive->hwif; - struct ide_io_ports *io_ports = &hwif->io_ports; - struct ide_taskfile *tf = &task->tf; - - if (task->tf_flags & IDE_TFLAG_IN_DATA) { - u16 data = hwif->INW(io_ports->data_addr); - - tf->data = data & 0xff; - tf->hob_data = (data >> 8) & 0xff; - } - - /* be sure we're looking at the low order bits */ - hwif->OUTB(drive->ctl & ~0x80, io_ports->ctl_addr); - - if (task->tf_flags & IDE_TFLAG_IN_NSECT) - tf->nsect = hwif->INB(io_ports->nsect_addr); - if (task->tf_flags & IDE_TFLAG_IN_LBAL) - tf->lbal = hwif->INB(io_ports->lbal_addr); - if (task->tf_flags & IDE_TFLAG_IN_LBAM) - tf->lbam = hwif->INB(io_ports->lbam_addr); - if (task->tf_flags & IDE_TFLAG_IN_LBAH) - tf->lbah = hwif->INB(io_ports->lbah_addr); - if (task->tf_flags & IDE_TFLAG_IN_DEVICE) - tf->device = hwif->INB(io_ports->device_addr); - - if (task->tf_flags & IDE_TFLAG_LBA48) { - hwif->OUTB(drive->ctl | 0x80, io_ports->ctl_addr); - - if (task->tf_flags & IDE_TFLAG_IN_HOB_FEATURE) - tf->hob_feature = hwif->INB(io_ports->feature_addr); - if (task->tf_flags & IDE_TFLAG_IN_HOB_NSECT) - tf->hob_nsect = hwif->INB(io_ports->nsect_addr); - if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAL) - tf->hob_lbal = hwif->INB(io_ports->lbal_addr); - if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAM) - tf->hob_lbam = hwif->INB(io_ports->lbam_addr); - if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAH) - tf->hob_lbah = hwif->INB(io_ports->lbah_addr); - } -} - /** * ide_end_drive_cmd - end an explicit drive command * @drive: command @@ -373,7 +330,7 @@ void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err) tf->error = err; tf->status = stat; - ide_tf_read(drive, task); + drive->hwif->tf_read(drive, task); if (task->tf_flags & IDE_TFLAG_DYN) kfree(task); @@ -422,7 +379,7 @@ static void try_to_flush_leftover_data (ide_drive_t *drive) u32 wcount = (i > 16) ? 16 : i; i -= wcount; - HWIF(drive)->ata_input_data(drive, buffer, wcount); + drive->hwif->input_data(drive, NULL, buffer, wcount * 4); } } @@ -502,7 +459,8 @@ static ide_startstop_t ide_atapi_error(ide_drive_t *drive, struct request *rq, u if (ide_read_status(drive) & (BUSY_STAT | DRQ_STAT)) /* force an abort */ - hwif->OUTB(WIN_IDLEIMMEDIATE, hwif->io_ports.command_addr); + hwif->OUTBSYNC(drive, WIN_IDLEIMMEDIATE, + hwif->io_ports.command_addr); if (rq->errors >= ERROR_MAX) { ide_kill_rq(drive, rq); @@ -1592,8 +1550,7 @@ irqreturn_t ide_intr (int irq, void *dev_id) void ide_init_drive_cmd (struct request *rq) { - memset(rq, 0, sizeof(*rq)); - rq->ref_count = 1; + blk_rq_init(NULL, rq); } EXPORT_SYMBOL(ide_init_drive_cmd); @@ -1679,7 +1636,23 @@ void ide_pktcmd_tf_load(ide_drive_t *drive, u32 tf_flags, u16 bcount, u8 dma) task.tf.lbam = bcount & 0xff; task.tf.lbah = (bcount >> 8) & 0xff; - ide_tf_load(drive, &task); + ide_tf_dump(drive->name, &task.tf); + drive->hwif->tf_load(drive, &task); } EXPORT_SYMBOL_GPL(ide_pktcmd_tf_load); + +void ide_pad_transfer(ide_drive_t *drive, int write, int len) +{ + ide_hwif_t *hwif = drive->hwif; + u8 buf[4] = { 0 }; + + while (len > 0) { + if (write) + hwif->output_data(drive, NULL, buf, min(4, len)); + else + hwif->input_data(drive, NULL, buf, min(4, len)); + len -= 4; + } +} +EXPORT_SYMBOL_GPL(ide_pad_transfer); diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c index 5425d3038ec..57d9a9a79a6 100644 --- a/drivers/ide/ide-iops.c +++ b/drivers/ide/ide-iops.c @@ -37,21 +37,6 @@ static u8 ide_inb (unsigned long port) return (u8) inb(port); } -static u16 ide_inw (unsigned long port) -{ - return (u16) inw(port); -} - -static void ide_insw (unsigned long port, void *addr, u32 count) -{ - insw(port, addr, count); -} - -static void ide_insl (unsigned long port, void *addr, u32 count) -{ - insl(port, addr, count); -} - static void ide_outb (u8 val, unsigned long port) { outb(val, port); @@ -62,32 +47,11 @@ static void ide_outbsync (ide_drive_t *drive, u8 addr, unsigned long port) outb(addr, port); } -static void ide_outw (u16 val, unsigned long port) -{ - outw(val, port); -} - -static void ide_outsw (unsigned long port, void *addr, u32 count) -{ - outsw(port, addr, count); -} - -static void ide_outsl (unsigned long port, void *addr, u32 count) -{ - outsl(port, addr, count); -} - void default_hwif_iops (ide_hwif_t *hwif) { hwif->OUTB = ide_outb; hwif->OUTBSYNC = ide_outbsync; - hwif->OUTW = ide_outw; - hwif->OUTSW = ide_outsw; - hwif->OUTSL = ide_outsl; hwif->INB = ide_inb; - hwif->INW = ide_inw; - hwif->INSW = ide_insw; - hwif->INSL = ide_insl; } /* @@ -99,21 +63,6 @@ static u8 ide_mm_inb (unsigned long port) return (u8) readb((void __iomem *) port); } -static u16 ide_mm_inw (unsigned long port) -{ - return (u16) readw((void __iomem *) port); -} - -static void ide_mm_insw (unsigned long port, void *addr, u32 count) -{ - __ide_mm_insw((void __iomem *) port, addr, count); -} - -static void ide_mm_insl (unsigned long port, void *addr, u32 count) -{ - __ide_mm_insl((void __iomem *) port, addr, count); -} - static void ide_mm_outb (u8 value, unsigned long port) { writeb(value, (void __iomem *) port); @@ -124,34 +73,13 @@ static void ide_mm_outbsync (ide_drive_t *drive, u8 value, unsigned long port) writeb(value, (void __iomem *) port); } -static void ide_mm_outw (u16 value, unsigned long port) -{ - writew(value, (void __iomem *) port); -} - -static void ide_mm_outsw (unsigned long port, void *addr, u32 count) -{ - __ide_mm_outsw((void __iomem *) port, addr, count); -} - -static void ide_mm_outsl (unsigned long port, void *addr, u32 count) -{ - __ide_mm_outsl((void __iomem *) port, addr, count); -} - void default_hwif_mmiops (ide_hwif_t *hwif) { hwif->OUTB = ide_mm_outb; /* Most systems will need to override OUTBSYNC, alas however this one is controller specific! */ hwif->OUTBSYNC = ide_mm_outbsync; - hwif->OUTW = ide_mm_outw; - hwif->OUTSW = ide_mm_outsw; - hwif->OUTSL = ide_mm_outsl; hwif->INB = ide_mm_inb; - hwif->INW = ide_mm_inw; - hwif->INSW = ide_mm_insw; - hwif->INSL = ide_mm_insl; } EXPORT_SYMBOL(default_hwif_mmiops); @@ -175,6 +103,123 @@ void SELECT_MASK (ide_drive_t *drive, int mask) port_ops->maskproc(drive, mask); } +static void ide_tf_load(ide_drive_t *drive, ide_task_t *task) +{ + ide_hwif_t *hwif = drive->hwif; + struct ide_io_ports *io_ports = &hwif->io_ports; + struct ide_taskfile *tf = &task->tf; + void (*tf_outb)(u8 addr, unsigned long port); + u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0; + u8 HIHI = (task->tf_flags & IDE_TFLAG_LBA48) ? 0xE0 : 0xEF; + + if (mmio) + tf_outb = ide_mm_outb; + else + tf_outb = ide_outb; + + if (task->tf_flags & IDE_TFLAG_FLAGGED) + HIHI = 0xFF; + + ide_set_irq(drive, 1); + + if ((task->tf_flags & IDE_TFLAG_NO_SELECT_MASK) == 0) + SELECT_MASK(drive, 0); + + if (task->tf_flags & IDE_TFLAG_OUT_DATA) { + u16 data = (tf->hob_data << 8) | tf->data; + + if (mmio) + writew(data, (void __iomem *)io_ports->data_addr); + else + outw(data, io_ports->data_addr); + } + + if (task->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE) + tf_outb(tf->hob_feature, io_ports->feature_addr); + if (task->tf_flags & IDE_TFLAG_OUT_HOB_NSECT) + tf_outb(tf->hob_nsect, io_ports->nsect_addr); + if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAL) + tf_outb(tf->hob_lbal, io_ports->lbal_addr); + if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAM) + tf_outb(tf->hob_lbam, io_ports->lbam_addr); + if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAH) + tf_outb(tf->hob_lbah, io_ports->lbah_addr); + + if (task->tf_flags & IDE_TFLAG_OUT_FEATURE) + tf_outb(tf->feature, io_ports->feature_addr); + if (task->tf_flags & IDE_TFLAG_OUT_NSECT) + tf_outb(tf->nsect, io_ports->nsect_addr); + if (task->tf_flags & IDE_TFLAG_OUT_LBAL) + tf_outb(tf->lbal, io_ports->lbal_addr); + if (task->tf_flags & IDE_TFLAG_OUT_LBAM) + tf_outb(tf->lbam, io_ports->lbam_addr); + if (task->tf_flags & IDE_TFLAG_OUT_LBAH) + tf_outb(tf->lbah, io_ports->lbah_addr); + + if (task->tf_flags & IDE_TFLAG_OUT_DEVICE) + tf_outb((tf->device & HIHI) | drive->select.all, + io_ports->device_addr); +} + +static void ide_tf_read(ide_drive_t *drive, ide_task_t *task) +{ + ide_hwif_t *hwif = drive->hwif; + struct ide_io_ports *io_ports = &hwif->io_ports; + struct ide_taskfile *tf = &task->tf; + void (*tf_outb)(u8 addr, unsigned long port); + u8 (*tf_inb)(unsigned long port); + u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0; + + if (mmio) { + tf_outb = ide_mm_outb; + tf_inb = ide_mm_inb; + } else { + tf_outb = ide_outb; + tf_inb = ide_inb; + } + + if (task->tf_flags & IDE_TFLAG_IN_DATA) { + u16 data; + + if (mmio) + data = readw((void __iomem *)io_ports->data_addr); + else + data = inw(io_ports->data_addr); + + tf->data = data & 0xff; + tf->hob_data = (data >> 8) & 0xff; + } + + /* be sure we're looking at the low order bits */ + tf_outb(drive->ctl & ~0x80, io_ports->ctl_addr); + + if (task->tf_flags & IDE_TFLAG_IN_NSECT) + tf->nsect = tf_inb(io_ports->nsect_addr); + if (task->tf_flags & IDE_TFLAG_IN_LBAL) + tf->lbal = tf_inb(io_ports->lbal_addr); + if (task->tf_flags & IDE_TFLAG_IN_LBAM) + tf->lbam = tf_inb(io_ports->lbam_addr); + if (task->tf_flags & IDE_TFLAG_IN_LBAH) + tf->lbah = tf_inb(io_ports->lbah_addr); + if (task->tf_flags & IDE_TFLAG_IN_DEVICE) + tf->device = tf_inb(io_ports->device_addr); + + if (task->tf_flags & IDE_TFLAG_LBA48) { + tf_outb(drive->ctl | 0x80, io_ports->ctl_addr); + + if (task->tf_flags & IDE_TFLAG_IN_HOB_FEATURE) + tf->hob_feature = tf_inb(io_ports->feature_addr); + if (task->tf_flags & IDE_TFLAG_IN_HOB_NSECT) + tf->hob_nsect = tf_inb(io_ports->nsect_addr); + if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAL) + tf->hob_lbal = tf_inb(io_ports->lbal_addr); + if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAM) + tf->hob_lbam = tf_inb(io_ports->lbam_addr); + if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAH) + tf->hob_lbah = tf_inb(io_ports->lbah_addr); + } +} + /* * Some localbus EIDE interfaces require a special access sequence * when using 32-bit I/O instructions to transfer data. We call this @@ -182,109 +227,112 @@ void SELECT_MASK (ide_drive_t *drive, int mask) * of the sector count register location, with interrupts disabled * to ensure that the reads all happen together. */ -static void ata_vlb_sync(ide_drive_t *drive, unsigned long port) +static void ata_vlb_sync(unsigned long port) { - (void) HWIF(drive)->INB(port); - (void) HWIF(drive)->INB(port); - (void) HWIF(drive)->INB(port); + (void)inb(port); + (void)inb(port); + (void)inb(port); } /* * This is used for most PIO data transfers *from* the IDE interface + * + * These routines will round up any request for an odd number of bytes, + * so if an odd len is specified, be sure that there's at least one + * extra byte allocated for the buffer. */ -static void ata_input_data(ide_drive_t *drive, void *buffer, u32 wcount) +static void ata_input_data(ide_drive_t *drive, struct request *rq, + void *buf, unsigned int len) { ide_hwif_t *hwif = drive->hwif; struct ide_io_ports *io_ports = &hwif->io_ports; + unsigned long data_addr = io_ports->data_addr; u8 io_32bit = drive->io_32bit; + u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0; + + len++; if (io_32bit) { - if (io_32bit & 2) { - unsigned long flags; + unsigned long uninitialized_var(flags); + if ((io_32bit & 2) && !mmio) { local_irq_save(flags); - ata_vlb_sync(drive, io_ports->nsect_addr); - hwif->INSL(io_ports->data_addr, buffer, wcount); + ata_vlb_sync(io_ports->nsect_addr); + } + + if (mmio) + __ide_mm_insl((void __iomem *)data_addr, buf, len / 4); + else + insl(data_addr, buf, len / 4); + + if ((io_32bit & 2) && !mmio) local_irq_restore(flags); - } else - hwif->INSL(io_ports->data_addr, buffer, wcount); - } else - hwif->INSW(io_ports->data_addr, buffer, wcount << 1); + + if ((len & 3) >= 2) { + if (mmio) + __ide_mm_insw((void __iomem *)data_addr, + (u8 *)buf + (len & ~3), 1); + else + insw(data_addr, (u8 *)buf + (len & ~3), 1); + } + } else { + if (mmio) + __ide_mm_insw((void __iomem *)data_addr, buf, len / 2); + else + insw(data_addr, buf, len / 2); + } } /* * This is used for most PIO data transfers *to* the IDE interface */ -static void ata_output_data(ide_drive_t *drive, void *buffer, u32 wcount) +static void ata_output_data(ide_drive_t *drive, struct request *rq, + void *buf, unsigned int len) { ide_hwif_t *hwif = drive->hwif; struct ide_io_ports *io_ports = &hwif->io_ports; + unsigned long data_addr = io_ports->data_addr; u8 io_32bit = drive->io_32bit; + u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0; if (io_32bit) { - if (io_32bit & 2) { - unsigned long flags; + unsigned long uninitialized_var(flags); + if ((io_32bit & 2) && !mmio) { local_irq_save(flags); - ata_vlb_sync(drive, io_ports->nsect_addr); - hwif->OUTSL(io_ports->data_addr, buffer, wcount); - local_irq_restore(flags); - } else - hwif->OUTSL(io_ports->data_addr, buffer, wcount); - } else - hwif->OUTSW(io_ports->data_addr, buffer, wcount << 1); -} - -/* - * The following routines are mainly used by the ATAPI drivers. - * - * These routines will round up any request for an odd number of bytes, - * so if an odd bytecount is specified, be sure that there's at least one - * extra byte allocated for the buffer. - */ - -static void atapi_input_bytes(ide_drive_t *drive, void *buffer, u32 bytecount) -{ - ide_hwif_t *hwif = HWIF(drive); + ata_vlb_sync(io_ports->nsect_addr); + } - ++bytecount; -#if defined(CONFIG_ATARI) || defined(CONFIG_Q40) - if (MACH_IS_ATARI || MACH_IS_Q40) { - /* Atari has a byte-swapped IDE interface */ - insw_swapw(hwif->io_ports.data_addr, buffer, bytecount / 2); - return; - } -#endif /* CONFIG_ATARI || CONFIG_Q40 */ - hwif->ata_input_data(drive, buffer, bytecount / 4); - if ((bytecount & 0x03) >= 2) - hwif->INSW(hwif->io_ports.data_addr, - (u8 *)buffer + (bytecount & ~0x03), 1); -} + if (mmio) + __ide_mm_outsl((void __iomem *)data_addr, buf, len / 4); + else + outsl(data_addr, buf, len / 4); -static void atapi_output_bytes(ide_drive_t *drive, void *buffer, u32 bytecount) -{ - ide_hwif_t *hwif = HWIF(drive); + if ((io_32bit & 2) && !mmio) + local_irq_restore(flags); - ++bytecount; -#if defined(CONFIG_ATARI) || defined(CONFIG_Q40) - if (MACH_IS_ATARI || MACH_IS_Q40) { - /* Atari has a byte-swapped IDE interface */ - outsw_swapw(hwif->io_ports.data_addr, buffer, bytecount / 2); - return; + if ((len & 3) >= 2) { + if (mmio) + __ide_mm_outsw((void __iomem *)data_addr, + (u8 *)buf + (len & ~3), 1); + else + outsw(data_addr, (u8 *)buf + (len & ~3), 1); + } + } else { + if (mmio) + __ide_mm_outsw((void __iomem *)data_addr, buf, len / 2); + else + outsw(data_addr, buf, len / 2); } -#endif /* CONFIG_ATARI || CONFIG_Q40 */ - hwif->ata_output_data(drive, buffer, bytecount / 4); - if ((bytecount & 0x03) >= 2) - hwif->OUTSW(hwif->io_ports.data_addr, - (u8 *)buffer + (bytecount & ~0x03), 1); } void default_hwif_transport(ide_hwif_t *hwif) { - hwif->ata_input_data = ata_input_data; - hwif->ata_output_data = ata_output_data; - hwif->atapi_input_bytes = atapi_input_bytes; - hwif->atapi_output_bytes = atapi_output_bytes; + hwif->tf_load = ide_tf_load; + hwif->tf_read = ide_tf_read; + + hwif->input_data = ata_input_data; + hwif->output_data = ata_output_data; } void ide_fix_driveid (struct hd_driveid *id) @@ -577,6 +625,8 @@ static const struct drive_list_entry ivb_list[] = { { "TSSTcorp CDDVDW SH-S202J" , "SB01" }, { "TSSTcorp CDDVDW SH-S202N" , "SB00" }, { "TSSTcorp CDDVDW SH-S202N" , "SB01" }, + { "TSSTcorp CDDVDW SH-S202H" , "SB00" }, + { "TSSTcorp CDDVDW SH-S202H" , "SB01" }, { NULL , NULL } }; @@ -641,7 +691,7 @@ int ide_driveid_update(ide_drive_t *drive) SELECT_MASK(drive, 1); ide_set_irq(drive, 1); msleep(50); - hwif->OUTB(WIN_IDENTIFY, hwif->io_ports.command_addr); + hwif->OUTBSYNC(drive, WIN_IDENTIFY, hwif->io_ports.command_addr); timeout = jiffies + WAIT_WORSTCASE; do { if (time_after(jiffies, timeout)) { @@ -668,7 +718,7 @@ int ide_driveid_update(ide_drive_t *drive) local_irq_restore(flags); return 0; } - hwif->ata_input_data(drive, id, SECTOR_WORDS); + hwif->input_data(drive, NULL, id, SECTOR_SIZE); (void)ide_read_status(drive); /* clear drive IRQ */ local_irq_enable(); local_irq_restore(flags); @@ -849,9 +899,19 @@ void ide_execute_command(ide_drive_t *drive, u8 cmd, ide_handler_t *handler, ndelay(400); spin_unlock_irqrestore(&ide_lock, flags); } - EXPORT_SYMBOL(ide_execute_command); +void ide_execute_pkt_cmd(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + unsigned long flags; + + spin_lock_irqsave(&ide_lock, flags); + hwif->OUTBSYNC(drive, WIN_PACKETCMD, hwif->io_ports.command_addr); + ndelay(400); + spin_unlock_irqrestore(&ide_lock, flags); +} +EXPORT_SYMBOL_GPL(ide_execute_pkt_cmd); /* needed below */ static ide_startstop_t do_reset1 (ide_drive_t *, int); diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c index 6f04ea3e93a..47af80df687 100644 --- a/drivers/ide/ide-lib.c +++ b/drivers/ide/ide-lib.c @@ -487,7 +487,7 @@ static void ide_dump_sector(ide_drive_t *drive) else task.tf_flags = IDE_TFLAG_IN_LBA | IDE_TFLAG_IN_DEVICE; - ide_tf_read(drive, &task); + drive->hwif->tf_read(drive, &task); if (lba48 || (tf->device & ATA_LBA)) printk(", LBAsect=%llu", diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index 862f02603f9..099a0fe1745 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -124,7 +124,7 @@ static inline void do_identify (ide_drive_t *drive, u8 cmd) id = drive->id; /* read 512 bytes of id info */ - hwif->ata_input_data(drive, id, SECTOR_WORDS); + hwif->input_data(drive, NULL, id, SECTOR_SIZE); drive->id_read = 1; local_irq_enable(); @@ -293,7 +293,7 @@ static int actual_try_to_identify (ide_drive_t *drive, u8 cmd) hwif->OUTB(0, io_ports->feature_addr); /* ask drive for ID */ - hwif->OUTB(cmd, io_ports->command_addr); + hwif->OUTBSYNC(drive, cmd, io_ports->command_addr); timeout = ((cmd == WIN_IDENTIFY) ? WAIT_WORSTCASE : WAIT_PIDENTIFY) / 2; timeout += jiffies; @@ -480,7 +480,7 @@ static int do_probe (ide_drive_t *drive, u8 cmd) msleep(50); hwif->OUTB(drive->select.all, io_ports->device_addr); msleep(50); - hwif->OUTB(WIN_SRST, io_ports->command_addr); + hwif->OUTBSYNC(drive, WIN_SRST, io_ports->command_addr); (void)ide_busy_sleep(hwif); rc = try_to_identify(drive, cmd); } @@ -516,7 +516,7 @@ static void enable_nest (ide_drive_t *drive) printk("%s: enabling %s -- ", hwif->name, drive->id->model); SELECT_DRIVE(drive); msleep(50); - hwif->OUTB(EXABYTE_ENABLE_NEST, hwif->io_ports.command_addr); + hwif->OUTBSYNC(drive, EXABYTE_ENABLE_NEST, hwif->io_ports.command_addr); if (ide_busy_sleep(hwif)) { printk(KERN_CONT "failed (timeout)\n"); diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c index 7b2f3815a83..8d6ad812a01 100644 --- a/drivers/ide/ide-proc.c +++ b/drivers/ide/ide-proc.c @@ -822,6 +822,7 @@ static int ide_drivers_open(struct inode *inode, struct file *file) } static const struct file_operations ide_drivers_operations = { + .owner = THIS_MODULE, .open = ide_drivers_open, .read = seq_read, .llseek = seq_lseek, @@ -830,16 +831,12 @@ static const struct file_operations ide_drivers_operations = { void proc_ide_create(void) { - struct proc_dir_entry *entry; - proc_ide_root = proc_mkdir("ide", NULL); if (!proc_ide_root) return; - entry = create_proc_entry("drivers", 0, proc_ide_root); - if (entry) - entry->proc_fops = &ide_drivers_operations; + proc_create("drivers", 0, proc_ide_root, &ide_drivers_operations); } void proc_ide_destroy(void) diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index 29870c41511..1e1f26331a2 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -395,13 +395,13 @@ static void idetape_input_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc, if (bh == NULL) { printk(KERN_ERR "ide-tape: bh == NULL in " "idetape_input_buffers\n"); - ide_atapi_discard_data(drive, bcount); + ide_pad_transfer(drive, 0, bcount); return; } count = min( (unsigned int)(bh->b_size - atomic_read(&bh->b_count)), bcount); - HWIF(drive)->atapi_input_bytes(drive, bh->b_data + + drive->hwif->input_data(drive, NULL, bh->b_data + atomic_read(&bh->b_count), count); bcount -= count; atomic_add(count, &bh->b_count); @@ -427,7 +427,7 @@ static void idetape_output_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc, return; } count = min((unsigned int)pc->b_count, (unsigned int)bcount); - HWIF(drive)->atapi_output_bytes(drive, pc->b_data, count); + drive->hwif->output_data(drive, NULL, pc->b_data, count); bcount -= count; pc->b_data += count; pc->b_count -= count; @@ -662,7 +662,7 @@ static void idetape_create_request_sense_cmd(struct ide_atapi_pc *pc) static void idetape_init_rq(struct request *rq, u8 cmd) { - memset(rq, 0, sizeof(*rq)); + blk_rq_init(NULL, rq); rq->cmd_type = REQ_TYPE_SPECIAL; rq->cmd[0] = cmd; } @@ -871,7 +871,7 @@ static ide_startstop_t idetape_pc_intr(ide_drive_t *drive) printk(KERN_ERR "ide-tape: The tape wants to " "send us more data than expected " "- discarding data\n"); - ide_atapi_discard_data(drive, bcount); + ide_pad_transfer(drive, 0, bcount); ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL); return ide_started; @@ -880,16 +880,16 @@ static ide_startstop_t idetape_pc_intr(ide_drive_t *drive) "data than expected - allowing transfer\n"); } iobuf = &idetape_input_buffers; - xferfunc = hwif->atapi_input_bytes; + xferfunc = hwif->input_data; } else { iobuf = &idetape_output_buffers; - xferfunc = hwif->atapi_output_bytes; + xferfunc = hwif->output_data; } if (pc->bh) iobuf(drive, pc, bcount); else - xferfunc(drive, pc->cur_pos, bcount); + xferfunc(drive, NULL, pc->cur_pos, bcount); /* Update the current position */ pc->xferred += bcount; @@ -979,7 +979,8 @@ static ide_startstop_t idetape_transfer_pc(ide_drive_t *drive) hwif->dma_ops->dma_start(drive); #endif /* Send the actual packet */ - HWIF(drive)->atapi_output_bytes(drive, pc->c, 12); + hwif->output_data(drive, NULL, pc->c, 12); + return ide_started; } @@ -1055,7 +1056,7 @@ static ide_startstop_t idetape_issue_pc(ide_drive_t *drive, IDETAPE_WAIT_CMD, NULL); return ide_started; } else { - hwif->OUTB(WIN_PACKETCMD, hwif->io_ports.command_addr); + ide_execute_pkt_cmd(drive); return idetape_transfer_pc(drive); } } diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c index 9f9ad9fb6b8..0c908ca3ff7 100644 --- a/drivers/ide/ide-taskfile.c +++ b/drivers/ide/ide-taskfile.c @@ -33,60 +33,18 @@ #include <asm/uaccess.h> #include <asm/io.h> -void ide_tf_load(ide_drive_t *drive, ide_task_t *task) +void ide_tf_dump(const char *s, struct ide_taskfile *tf) { - ide_hwif_t *hwif = drive->hwif; - struct ide_io_ports *io_ports = &hwif->io_ports; - struct ide_taskfile *tf = &task->tf; - u8 HIHI = (task->tf_flags & IDE_TFLAG_LBA48) ? 0xE0 : 0xEF; - - if (task->tf_flags & IDE_TFLAG_FLAGGED) - HIHI = 0xFF; - #ifdef DEBUG printk("%s: tf: feat 0x%02x nsect 0x%02x lbal 0x%02x " "lbam 0x%02x lbah 0x%02x dev 0x%02x cmd 0x%02x\n", - drive->name, tf->feature, tf->nsect, tf->lbal, + s, tf->feature, tf->nsect, tf->lbal, tf->lbam, tf->lbah, tf->device, tf->command); printk("%s: hob: nsect 0x%02x lbal 0x%02x " "lbam 0x%02x lbah 0x%02x\n", - drive->name, tf->hob_nsect, tf->hob_lbal, + s, tf->hob_nsect, tf->hob_lbal, tf->hob_lbam, tf->hob_lbah); #endif - - ide_set_irq(drive, 1); - - if ((task->tf_flags & IDE_TFLAG_NO_SELECT_MASK) == 0) - SELECT_MASK(drive, 0); - - if (task->tf_flags & IDE_TFLAG_OUT_DATA) - hwif->OUTW((tf->hob_data << 8) | tf->data, io_ports->data_addr); - - if (task->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE) - hwif->OUTB(tf->hob_feature, io_ports->feature_addr); - if (task->tf_flags & IDE_TFLAG_OUT_HOB_NSECT) - hwif->OUTB(tf->hob_nsect, io_ports->nsect_addr); - if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAL) - hwif->OUTB(tf->hob_lbal, io_ports->lbal_addr); - if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAM) - hwif->OUTB(tf->hob_lbam, io_ports->lbam_addr); - if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAH) - hwif->OUTB(tf->hob_lbah, io_ports->lbah_addr); - - if (task->tf_flags & IDE_TFLAG_OUT_FEATURE) - hwif->OUTB(tf->feature, io_ports->feature_addr); - if (task->tf_flags & IDE_TFLAG_OUT_NSECT) - hwif->OUTB(tf->nsect, io_ports->nsect_addr); - if (task->tf_flags & IDE_TFLAG_OUT_LBAL) - hwif->OUTB(tf->lbal, io_ports->lbal_addr); - if (task->tf_flags & IDE_TFLAG_OUT_LBAM) - hwif->OUTB(tf->lbam, io_ports->lbam_addr); - if (task->tf_flags & IDE_TFLAG_OUT_LBAH) - hwif->OUTB(tf->lbah, io_ports->lbah_addr); - - if (task->tf_flags & IDE_TFLAG_OUT_DEVICE) - hwif->OUTB((tf->device & HIHI) | drive->select.all, - io_ports->device_addr); } int taskfile_lib_get_identify (ide_drive_t *drive, u8 *buf) @@ -149,8 +107,10 @@ ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task) if (task->tf_flags & IDE_TFLAG_FLAGGED) task->tf_flags |= IDE_TFLAG_FLAGGED_SET_IN_FLAGS; - if ((task->tf_flags & IDE_TFLAG_DMA_PIO_FALLBACK) == 0) - ide_tf_load(drive, task); + if ((task->tf_flags & IDE_TFLAG_DMA_PIO_FALLBACK) == 0) { + ide_tf_dump(drive->name, tf); + hwif->tf_load(drive, task); + } switch (task->data_phase) { case TASKFILE_MULTI_OUT: @@ -283,7 +243,8 @@ static u8 wait_drive_not_busy(ide_drive_t *drive) return stat; } -static void ide_pio_sector(ide_drive_t *drive, unsigned int write) +static void ide_pio_sector(ide_drive_t *drive, struct request *rq, + unsigned int write) { ide_hwif_t *hwif = drive->hwif; struct scatterlist *sg = hwif->sg_table; @@ -323,9 +284,9 @@ static void ide_pio_sector(ide_drive_t *drive, unsigned int write) /* do the actual data transfer */ if (write) - hwif->ata_output_data(drive, buf, SECTOR_WORDS); + hwif->output_data(drive, rq, buf, SECTOR_SIZE); else - hwif->ata_input_data(drive, buf, SECTOR_WORDS); + hwif->input_data(drive, rq, buf, SECTOR_SIZE); kunmap_atomic(buf, KM_BIO_SRC_IRQ); #ifdef CONFIG_HIGHMEM @@ -333,13 +294,14 @@ static void ide_pio_sector(ide_drive_t *drive, unsigned int write) #endif } -static void ide_pio_multi(ide_drive_t *drive, unsigned int write) +static void ide_pio_multi(ide_drive_t *drive, struct request *rq, + unsigned int write) { unsigned int nsect; nsect = min_t(unsigned int, drive->hwif->nleft, drive->mult_count); while (nsect--) - ide_pio_sector(drive, write); + ide_pio_sector(drive, rq, write); } static void ide_pio_datablock(ide_drive_t *drive, struct request *rq, @@ -362,10 +324,10 @@ static void ide_pio_datablock(ide_drive_t *drive, struct request *rq, switch (drive->hwif->data_phase) { case TASKFILE_MULTI_IN: case TASKFILE_MULTI_OUT: - ide_pio_multi(drive, write); + ide_pio_multi(drive, rq, write); break; default: - ide_pio_sector(drive, write); + ide_pio_sector(drive, rq, write); break; } @@ -532,8 +494,7 @@ int ide_raw_taskfile(ide_drive_t *drive, ide_task_t *task, u8 *buf, u16 nsect) { struct request rq; - memset(&rq, 0, sizeof(rq)); - rq.ref_count = 1; + blk_rq_init(NULL, &rq); rq.cmd_type = REQ_TYPE_ATA_TASKFILE; rq.buffer = buf; diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index 999584c03d9..c758dcb13b1 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -564,7 +564,7 @@ static int generic_ide_suspend(struct device *dev, pm_message_t mesg) if (!(drive->dn % 2)) ide_acpi_get_timing(hwif); - memset(&rq, 0, sizeof(rq)); + blk_rq_init(NULL, &rq); memset(&rqpm, 0, sizeof(rqpm)); memset(&args, 0, sizeof(args)); rq.cmd_type = REQ_TYPE_PM_SUSPEND; @@ -602,7 +602,7 @@ static int generic_ide_resume(struct device *dev) ide_acpi_exec_tfs(drive); - memset(&rq, 0, sizeof(rq)); + blk_rq_init(NULL, &rq); memset(&rqpm, 0, sizeof(rqpm)); memset(&args, 0, sizeof(args)); rq.cmd_type = REQ_TYPE_PM_RESUME; diff --git a/drivers/ide/legacy/falconide.c b/drivers/ide/legacy/falconide.c index 56cdaa0eeea..83555ca513b 100644 --- a/drivers/ide/legacy/falconide.c +++ b/drivers/ide/legacy/falconide.c @@ -44,6 +44,28 @@ int falconide_intr_lock; EXPORT_SYMBOL(falconide_intr_lock); +static void falconide_input_data(ide_drive_t *drive, struct request *rq, + void *buf, unsigned int len) +{ + unsigned long data_addr = drive->hwif->io_ports.data_addr; + + if (drive->media == ide_disk && rq && rq->cmd_type == REQ_TYPE_FS) + return insw(data_addr, buf, (len + 1) / 2); + + insw_swapw(data_addr, buf, (len + 1) / 2); +} + +static void falconide_output_data(ide_drive_t *drive, struct request *rq, + void *buf, unsigned int len) +{ + unsigned long data_addr = drive->hwif->io_ports.data_addr; + + if (drive->media == ide_disk && rq && rq->cmd_type == REQ_TYPE_FS) + return outsw(data_adr, buf, (len + 1) / 2); + + outsw_swapw(data_addr, buf, (len + 1) / 2); +} + static void __init falconide_setup_ports(hw_regs_t *hw) { int i; @@ -90,6 +112,10 @@ static int __init falconide_init(void) ide_init_port_data(hwif, index); ide_init_port_hw(hwif, &hw); + /* Atari has a byte-swapped IDE interface */ + hwif->input_data = falconide_input_data; + hwif->output_data = falconide_output_data; + ide_get_lock(NULL, NULL); ide_device_add(idx, NULL); ide_release_lock(); diff --git a/drivers/ide/legacy/ide_platform.c b/drivers/ide/legacy/ide_platform.c index 8279dc7ca4c..d3bc3f24e05 100644 --- a/drivers/ide/legacy/ide_platform.c +++ b/drivers/ide/legacy/ide_platform.c @@ -101,8 +101,10 @@ static int __devinit plat_ide_probe(struct platform_device *pdev) ide_init_port_hw(hwif, &hw); - if (mmio) + if (mmio) { + hwif->host_flags = IDE_HFLAG_MMIO; default_hwif_mmiops(hwif); + } idx[0] = hwif->index; diff --git a/drivers/ide/legacy/q40ide.c b/drivers/ide/legacy/q40ide.c index a3573d40b4b..6f535d00e63 100644 --- a/drivers/ide/legacy/q40ide.c +++ b/drivers/ide/legacy/q40ide.c @@ -36,23 +36,6 @@ static const unsigned long pcide_bases[Q40IDE_NUM_HWIFS] = { PCIDE_BASE6 */ }; - - /* - * Offsets from one of the above bases - */ - -/* used to do addr translation here but it is easier to do in setup ports */ -/*#define IDE_OFF_B(x) ((unsigned long)Q40_ISA_IO_B((IDE_##x##_OFFSET)))*/ - -#define IDE_OFF_B(x) ((unsigned long)((IDE_##x##_OFFSET))) -#define IDE_OFF_W(x) ((unsigned long)((IDE_##x##_OFFSET))) - -static const int pcide_offsets[IDE_NR_PORTS] = { - IDE_OFF_W(DATA), IDE_OFF_B(ERROR), IDE_OFF_B(NSECTOR), IDE_OFF_B(SECTOR), - IDE_OFF_B(LCYL), IDE_OFF_B(HCYL), 6 /*IDE_OFF_B(CURRENT)*/, IDE_OFF_B(STATUS), - 518/*IDE_OFF(CMD)*/ -}; - static int q40ide_default_irq(unsigned long base) { switch (base) { @@ -68,29 +51,48 @@ static int q40ide_default_irq(unsigned long base) /* * Addresses are pretranslated for Q40 ISA access. */ -void q40_ide_setup_ports ( hw_regs_t *hw, - unsigned long base, int *offsets, - unsigned long ctrl, unsigned long intr, +static void q40_ide_setup_ports(hw_regs_t *hw, unsigned long base, ide_ack_intr_t *ack_intr, int irq) { - int i; - memset(hw, 0, sizeof(hw_regs_t)); - for (i = 0; i < IDE_NR_PORTS; i++) { - /* BIG FAT WARNING: - assumption: only DATA port is ever used in 16 bit mode */ - if (i == 0) - hw->io_ports_array[i] = Q40_ISA_IO_W(base + offsets[i]); - else - hw->io_ports_array[i] = Q40_ISA_IO_B(base + offsets[i]); - } + /* BIG FAT WARNING: + assumption: only DATA port is ever used in 16 bit mode */ + hw->io_ports.data_addr = Q40_ISA_IO_W(base); + hw->io_ports.error_addr = Q40_ISA_IO_B(base + 1); + hw->io_ports.nsect_addr = Q40_ISA_IO_B(base + 2); + hw->io_ports.lbal_addr = Q40_ISA_IO_B(base + 3); + hw->io_ports.lbam_addr = Q40_ISA_IO_B(base + 4); + hw->io_ports.lbah_addr = Q40_ISA_IO_B(base + 5); + hw->io_ports.device_addr = Q40_ISA_IO_B(base + 6); + hw->io_ports.status_addr = Q40_ISA_IO_B(base + 7); + hw->io_ports.ctl_addr = Q40_ISA_IO_B(base + 0x206); hw->irq = irq; hw->ack_intr = ack_intr; } +static void q40ide_input_data(ide_drive_t *drive, struct request *rq, + void *buf, unsigned int len) +{ + unsigned long data_addr = drive->hwif->io_ports.data_addr; + + if (drive->media == ide_disk && rq && rq->cmd_type == REQ_TYPE_FS) + return insw(data_addr, buf, (len + 1) / 2); + insw_swapw(data_addr, buf, (len + 1) / 2); +} + +static void q40ide_output_data(ide_drive_t *drive, struct request *rq, + void *buf, unsigned int len) +{ + unsigned long data_addr = drive->hwif->io_ports.data_addr; + + if (drive->media == ide_disk && rq && rq->cmd_type == REQ_TYPE_FS) + return outsw(data_addr, buf, (len + 1) / 2); + + outsw_swapw(data_addr, buf, (len + 1) / 2); +} /* * the static array is needed to have the name reported in /proc/ioports, @@ -131,9 +133,8 @@ static int __init q40ide_init(void) release_region(pcide_bases[i], 8); continue; } - q40_ide_setup_ports(&hw,(unsigned long) pcide_bases[i], (int *)pcide_offsets, - pcide_bases[i]+0x206, - 0, NULL, + q40_ide_setup_ports(&hw, pcide_bases[i], + NULL, // m68kide_iops, q40ide_default_irq(pcide_bases[i])); @@ -142,6 +143,10 @@ static int __init q40ide_init(void) ide_init_port_data(hwif, hwif->index); ide_init_port_hw(hwif, &hw); + /* Q40 has a byte-swapped IDE interface */ + hwif->input_data = q40ide_input_data; + hwif->output_data = q40ide_output_data; + idx[i] = hwif->index; } } diff --git a/drivers/ide/mips/au1xxx-ide.c b/drivers/ide/mips/au1xxx-ide.c index 296b9c674ba..1a6c27b3249 100644 --- a/drivers/ide/mips/au1xxx-ide.c +++ b/drivers/ide/mips/au1xxx-ide.c @@ -48,8 +48,6 @@ static _auide_hwif auide_hwif; -static int auide_ddma_init(_auide_hwif *auide); - #if defined(CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA) void auide_insw(unsigned long port, void *addr, u32 count) @@ -88,6 +86,17 @@ void auide_outsw(unsigned long port, void *addr, u32 count) ctp->cur_ptr = au1xxx_ddma_get_nextptr_virt(dp); } +static void au1xxx_input_data(ide_drive_t *drive, struct request *rq, + void *buf, unsigned int len) +{ + auide_insw(drive->hwif->io_ports.data_addr, buf, (len + 1) / 2); +} + +static void au1xxx_output_data(ide_drive_t *drive, struct request *rq, + void *buf, unsigned int len) +{ + auide_outsw(drive->hwif->io_ports.data_addr, buf, (len + 1) / 2); +} #endif static void au1xxx_set_pio_mode(ide_drive_t *drive, const u8 pio) @@ -359,7 +368,7 @@ static void auide_ddma_rx_callback(int irq, void *param) static void auide_init_dbdma_dev(dbdev_tab_t *dev, u32 dev_id, u32 tsize, u32 devwidth, u32 flags) { dev->dev_id = dev_id; - dev->dev_physaddr = (u32)AU1XXX_ATA_PHYS_ADDR; + dev->dev_physaddr = (u32)IDE_PHYS_ADDR; dev->dev_intlevel = 0; dev->dev_intpolarity = 0; dev->dev_tsize = tsize; @@ -397,7 +406,7 @@ static int auide_ddma_init(ide_hwif_t *hwif, const struct ide_port_info *d) dbdev_tab_t source_dev_tab, target_dev_tab; u32 dev_id, tsize, devwidth, flags; - dev_id = AU1XXX_ATA_DDMA_REQ; + dev_id = IDE_DDMA_REQ; tsize = 8; /* 1 */ devwidth = 32; /* 16 */ @@ -506,10 +515,10 @@ static void auide_setup_ports(hw_regs_t *hw, _auide_hwif *ahwif) /* FIXME? */ for (i = 0; i < 8; i++) - *ata_regs++ = ahwif->regbase + (i << AU1XXX_ATA_REG_OFFSET); + *ata_regs++ = ahwif->regbase + (i << IDE_REG_SHIFT); /* set the Alternative Status register */ - *ata_regs = ahwif->regbase + (14 << AU1XXX_ATA_REG_OFFSET); + *ata_regs = ahwif->regbase + (14 << IDE_REG_SHIFT); } static const struct ide_port_ops au1xxx_port_ops = { @@ -598,8 +607,8 @@ static int au_ide_probe(struct device *dev) */ #ifdef CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA - hwif->INSW = auide_insw; - hwif->OUTSW = auide_outsw; + hwif->input_data = au1xxx_input_data; + hwif->output_data = au1xxx_output_data; #endif hwif->select_data = 0; /* no chipset-specific code */ hwif->config_data = 0; /* no chipset-specific code */ diff --git a/drivers/ide/mips/swarm.c b/drivers/ide/mips/swarm.c index 68947626e4a..712d17bdd47 100644 --- a/drivers/ide/mips/swarm.c +++ b/drivers/ide/mips/swarm.c @@ -109,6 +109,7 @@ static int __devinit swarm_ide_probe(struct device *dev) base = ioremap(offset, size); /* Setup MMIO ops. */ + hwif->host_flags = IDE_HFLAG_MMIO; default_hwif_mmiops(hwif); hwif->chipset = ide_generic; diff --git a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c index b36a22b8c21..c1922f9cfe8 100644 --- a/drivers/ide/pci/alim15x3.c +++ b/drivers/ide/pci/alim15x3.c @@ -412,14 +412,14 @@ static u8 __devinit ali_cable_detect(ide_hwif_t *hwif) return cbl; } -#ifndef CONFIG_SPARC64 +#if !defined(CONFIG_SPARC64) && !defined(CONFIG_PPC) /** * init_hwif_ali15x3 - Initialize the ALI IDE x86 stuff * @hwif: interface to configure * * Obtain the IRQ tables for an ALi based IDE solution on the PC * class platforms. This part of the code isn't applicable to the - * Sparc systems + * Sparc and PowerPC systems. */ static void __devinit init_hwif_ali15x3 (ide_hwif_t *hwif) @@ -463,7 +463,9 @@ static void __devinit init_hwif_ali15x3 (ide_hwif_t *hwif) hwif->irq = irq; } } -#endif +#else +#define init_hwif_ali15x3 NULL +#endif /* !defined(CONFIG_SPARC64) && !defined(CONFIG_PPC) */ /** * init_dma_ali15x3 - set up DMA on ALi15x3 @@ -517,9 +519,7 @@ static const struct ide_dma_ops ali_dma_ops = { static const struct ide_port_info ali15x3_chipset __devinitdata = { .name = "ALI15X3", .init_chipset = init_chipset_ali15x3, -#ifndef CONFIG_SPARC64 .init_hwif = init_hwif_ali15x3, -#endif .init_dma = init_dma_ali15x3, .port_ops = &ali_port_ops, .pio_mask = ATA_PIO5, diff --git a/drivers/ide/pci/ns87415.c b/drivers/ide/pci/ns87415.c index c13e299077e..fec4955f449 100644 --- a/drivers/ide/pci/ns87415.c +++ b/drivers/ide/pci/ns87415.c @@ -63,6 +63,48 @@ static u8 superio_ide_inb (unsigned long port) return inb(port); } +static void superio_tf_read(ide_drive_t *drive, ide_task_t *task) +{ + struct ide_io_ports *io_ports = &drive->hwif->io_ports; + struct ide_taskfile *tf = &task->tf; + + if (task->tf_flags & IDE_TFLAG_IN_DATA) { + u16 data = inw(io_ports->data_addr); + + tf->data = data & 0xff; + tf->hob_data = (data >> 8) & 0xff; + } + + /* be sure we're looking at the low order bits */ + outb(drive->ctl & ~0x80, io_ports->ctl_addr); + + if (task->tf_flags & IDE_TFLAG_IN_NSECT) + tf->nsect = inb(io_ports->nsect_addr); + if (task->tf_flags & IDE_TFLAG_IN_LBAL) + tf->lbal = inb(io_ports->lbal_addr); + if (task->tf_flags & IDE_TFLAG_IN_LBAM) + tf->lbam = inb(io_ports->lbam_addr); + if (task->tf_flags & IDE_TFLAG_IN_LBAH) + tf->lbah = inb(io_ports->lbah_addr); + if (task->tf_flags & IDE_TFLAG_IN_DEVICE) + tf->device = superio_ide_inb(io_ports->device_addr); + + if (task->tf_flags & IDE_TFLAG_LBA48) { + outb(drive->ctl | 0x80, io_ports->ctl_addr); + + if (task->tf_flags & IDE_TFLAG_IN_HOB_FEATURE) + tf->hob_feature = inb(io_ports->feature_addr); + if (task->tf_flags & IDE_TFLAG_IN_HOB_NSECT) + tf->hob_nsect = inb(io_ports->nsect_addr); + if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAL) + tf->hob_lbal = inb(io_ports->lbal_addr); + if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAM) + tf->hob_lbam = inb(io_ports->lbam_addr); + if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAH) + tf->hob_lbah = inb(io_ports->lbah_addr); + } +} + static void __devinit superio_ide_init_iops (struct hwif_s *hwif) { struct pci_dev *pdev = to_pci_dev(hwif->dev); @@ -80,6 +122,8 @@ static void __devinit superio_ide_init_iops (struct hwif_s *hwif) tmp = superio_ide_inb(superio_ide_dma_status[port]); outb(tmp | 0x66, superio_ide_dma_status[port]); + hwif->tf_read = superio_tf_read; + /* We need to override inb to workaround a SuperIO errata */ hwif->INB = superio_ide_inb; } diff --git a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c index ec9bd7b352f..070df8ab3b2 100644 --- a/drivers/ide/pci/pdc202xx_new.c +++ b/drivers/ide/pci/pdc202xx_new.c @@ -83,8 +83,8 @@ static u8 get_indexed_reg(ide_hwif_t *hwif, u8 index) { u8 value; - outb(index, hwif->dma_vendor1); - value = inb(hwif->dma_vendor3); + outb(index, hwif->dma_base + 1); + value = inb(hwif->dma_base + 3); DBG("index[%02X] value[%02X]\n", index, value); return value; @@ -97,8 +97,8 @@ static u8 get_indexed_reg(ide_hwif_t *hwif, u8 index) */ static void set_indexed_reg(ide_hwif_t *hwif, u8 index, u8 value) { - outb(index, hwif->dma_vendor1); - outb(value, hwif->dma_vendor3); + outb(index, hwif->dma_base + 1); + outb(value, hwif->dma_base + 3); DBG("index[%02X] value[%02X]\n", index, value); } diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c index 21c5dd23f92..f04738d14a6 100644 --- a/drivers/ide/pci/piix.c +++ b/drivers/ide/pci/piix.c @@ -250,6 +250,7 @@ static const struct ich_laptop ich_laptop[] = { { 0x27DF, 0x1043, 0x1267 }, /* ICH7 on Asus W5F */ { 0x27DF, 0x103C, 0x30A1 }, /* ICH7 on HP Compaq nc2400 */ { 0x24CA, 0x1025, 0x0061 }, /* ICH4 on Acer Aspire 2023WLMi */ + { 0x2653, 0x1043, 0x82D8 }, /* ICH6M on Asus Eee 701 */ /* end marker */ { 0, } }; diff --git a/drivers/ide/pci/scc_pata.c b/drivers/ide/pci/scc_pata.c index ad7cdf9060c..910fb00deb7 100644 --- a/drivers/ide/pci/scc_pata.c +++ b/drivers/ide/pci/scc_pata.c @@ -126,12 +126,6 @@ static u8 scc_ide_inb(unsigned long port) return (u8)data; } -static u16 scc_ide_inw(unsigned long port) -{ - u32 data = in_be32((void*)port); - return (u16)data; -} - static void scc_ide_insw(unsigned long port, void *addr, u32 count) { u16 *ptr = (u16 *)addr; @@ -154,11 +148,6 @@ static void scc_ide_outb(u8 addr, unsigned long port) out_be32((void*)port, addr); } -static void scc_ide_outw(u16 addr, unsigned long port) -{ - out_be32((void*)port, addr); -} - static void scc_ide_outbsync(ide_drive_t * drive, u8 addr, unsigned long port) { @@ -271,6 +260,20 @@ static void scc_set_dma_mode(ide_drive_t *drive, const u8 speed) out_be32((void __iomem *)udenvt_port, reg); } +static void scc_dma_host_set(ide_drive_t *drive, int on) +{ + ide_hwif_t *hwif = drive->hwif; + u8 unit = (drive->select.b.unit & 0x01); + u8 dma_stat = scc_ide_inb(hwif->dma_status); + + if (on) + dma_stat |= (1 << (5 + unit)); + else + dma_stat &= ~(1 << (5 + unit)); + + scc_ide_outb(dma_stat, hwif->dma_status); +} + /** * scc_ide_dma_setup - begin a DMA phase * @drive: target device @@ -301,7 +304,7 @@ static int scc_dma_setup(ide_drive_t *drive) } /* PRD table */ - out_be32((void __iomem *)hwif->dma_prdtable, hwif->dmatable_dma); + out_be32((void __iomem *)(hwif->dma_base + 8), hwif->dmatable_dma); /* specify r/w */ out_be32((void __iomem *)hwif->dma_command, reading); @@ -315,13 +318,45 @@ static int scc_dma_setup(ide_drive_t *drive) return 0; } +static void scc_dma_start(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + u8 dma_cmd = scc_ide_inb(hwif->dma_command); + + /* start DMA */ + scc_ide_outb(dma_cmd | 1, hwif->dma_command); + hwif->dma = 1; + wmb(); +} + +static int __scc_dma_end(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + u8 dma_stat, dma_cmd; + + drive->waiting_for_dma = 0; + /* get DMA command mode */ + dma_cmd = scc_ide_inb(hwif->dma_command); + /* stop DMA */ + scc_ide_outb(dma_cmd & ~1, hwif->dma_command); + /* get DMA status */ + dma_stat = scc_ide_inb(hwif->dma_status); + /* clear the INTR & ERROR bits */ + scc_ide_outb(dma_stat | 6, hwif->dma_status); + /* purge DMA mappings */ + ide_destroy_dmatable(drive); + /* verify good DMA status */ + hwif->dma = 0; + wmb(); + return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0; +} /** * scc_dma_end - Stop DMA * @drive: IDE drive * * Check and clear INT Status register. - * Then call __ide_dma_end(). + * Then call __scc_dma_end(). */ static int scc_dma_end(ide_drive_t *drive) @@ -425,7 +460,7 @@ static int scc_dma_end(ide_drive_t *drive) break; } - dma_stat = __ide_dma_end(drive); + dma_stat = __scc_dma_end(drive); if (data_loss) dma_stat |= 2; /* emulate DMA error (to retry command) */ return dma_stat; @@ -618,6 +653,122 @@ static int __devinit init_setup_scc(struct pci_dev *dev, return rc; } +static void scc_tf_load(ide_drive_t *drive, ide_task_t *task) +{ + struct ide_io_ports *io_ports = &drive->hwif->io_ports; + struct ide_taskfile *tf = &task->tf; + u8 HIHI = (task->tf_flags & IDE_TFLAG_LBA48) ? 0xE0 : 0xEF; + + if (task->tf_flags & IDE_TFLAG_FLAGGED) + HIHI = 0xFF; + + ide_set_irq(drive, 1); + + if (task->tf_flags & IDE_TFLAG_OUT_DATA) + out_be32((void *)io_ports->data_addr, + (tf->hob_data << 8) | tf->data); + + if (task->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE) + scc_ide_outb(tf->hob_feature, io_ports->feature_addr); + if (task->tf_flags & IDE_TFLAG_OUT_HOB_NSECT) + scc_ide_outb(tf->hob_nsect, io_ports->nsect_addr); + if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAL) + scc_ide_outb(tf->hob_lbal, io_ports->lbal_addr); + if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAM) + scc_ide_outb(tf->hob_lbam, io_ports->lbam_addr); + if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAH) + scc_ide_outb(tf->hob_lbah, io_ports->lbah_addr); + + if (task->tf_flags & IDE_TFLAG_OUT_FEATURE) + scc_ide_outb(tf->feature, io_ports->feature_addr); + if (task->tf_flags & IDE_TFLAG_OUT_NSECT) + scc_ide_outb(tf->nsect, io_ports->nsect_addr); + if (task->tf_flags & IDE_TFLAG_OUT_LBAL) + scc_ide_outb(tf->lbal, io_ports->lbal_addr); + if (task->tf_flags & IDE_TFLAG_OUT_LBAM) + scc_ide_outb(tf->lbam, io_ports->lbam_addr); + if (task->tf_flags & IDE_TFLAG_OUT_LBAH) + scc_ide_outb(tf->lbah, io_ports->lbah_addr); + + if (task->tf_flags & IDE_TFLAG_OUT_DEVICE) + scc_ide_outb((tf->device & HIHI) | drive->select.all, + io_ports->device_addr); +} + +static void scc_tf_read(ide_drive_t *drive, ide_task_t *task) +{ + struct ide_io_ports *io_ports = &drive->hwif->io_ports; + struct ide_taskfile *tf = &task->tf; + + if (task->tf_flags & IDE_TFLAG_IN_DATA) { + u16 data = (u16)in_be32((void *)io_ports->data_addr); + + tf->data = data & 0xff; + tf->hob_data = (data >> 8) & 0xff; + } + + /* be sure we're looking at the low order bits */ + scc_ide_outb(drive->ctl & ~0x80, io_ports->ctl_addr); + + if (task->tf_flags & IDE_TFLAG_IN_NSECT) + tf->nsect = scc_ide_inb(io_ports->nsect_addr); + if (task->tf_flags & IDE_TFLAG_IN_LBAL) + tf->lbal = scc_ide_inb(io_ports->lbal_addr); + if (task->tf_flags & IDE_TFLAG_IN_LBAM) + tf->lbam = scc_ide_inb(io_ports->lbam_addr); + if (task->tf_flags & IDE_TFLAG_IN_LBAH) + tf->lbah = scc_ide_inb(io_ports->lbah_addr); + if (task->tf_flags & IDE_TFLAG_IN_DEVICE) + tf->device = scc_ide_inb(io_ports->device_addr); + + if (task->tf_flags & IDE_TFLAG_LBA48) { + scc_ide_outb(drive->ctl | 0x80, io_ports->ctl_addr); + + if (task->tf_flags & IDE_TFLAG_IN_HOB_FEATURE) + tf->hob_feature = scc_ide_inb(io_ports->feature_addr); + if (task->tf_flags & IDE_TFLAG_IN_HOB_NSECT) + tf->hob_nsect = scc_ide_inb(io_ports->nsect_addr); + if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAL) + tf->hob_lbal = scc_ide_inb(io_ports->lbal_addr); + if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAM) + tf->hob_lbam = scc_ide_inb(io_ports->lbam_addr); + if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAH) + tf->hob_lbah = scc_ide_inb(io_ports->lbah_addr); + } +} + +static void scc_input_data(ide_drive_t *drive, struct request *rq, + void *buf, unsigned int len) +{ + unsigned long data_addr = drive->hwif->io_ports.data_addr; + + len++; + + if (drive->io_32bit) { + scc_ide_insl(data_addr, buf, len / 4); + + if ((len & 3) >= 2) + scc_ide_insw(data_addr, (u8 *)buf + (len & ~3), 1); + } else + scc_ide_insw(data_addr, buf, len / 2); +} + +static void scc_output_data(ide_drive_t *drive, struct request *rq, + void *buf, unsigned int len) +{ + unsigned long data_addr = drive->hwif->io_ports.data_addr; + + len++; + + if (drive->io_32bit) { + scc_ide_outsl(data_addr, buf, len / 4); + + if ((len & 3) >= 2) + scc_ide_outsw(data_addr, (u8 *)buf + (len & ~3), 1); + } else + scc_ide_outsw(data_addr, buf, len / 2); +} + /** * init_mmio_iops_scc - set up the iops for MMIO * @hwif: interface to set up @@ -632,15 +783,15 @@ static void __devinit init_mmio_iops_scc(ide_hwif_t *hwif) ide_set_hwifdata(hwif, ports); + hwif->tf_load = scc_tf_load; + hwif->tf_read = scc_tf_read; + + hwif->input_data = scc_input_data; + hwif->output_data = scc_output_data; + hwif->INB = scc_ide_inb; - hwif->INW = scc_ide_inw; - hwif->INSW = scc_ide_insw; - hwif->INSL = scc_ide_insl; hwif->OUTB = scc_ide_outb; hwif->OUTBSYNC = scc_ide_outbsync; - hwif->OUTW = scc_ide_outw; - hwif->OUTSW = scc_ide_outsw; - hwif->OUTSL = scc_ide_outsl; hwif->dma_base = dma_base; hwif->config_data = ports->ctl; @@ -687,7 +838,6 @@ static void __devinit init_hwif_scc(ide_hwif_t *hwif) hwif->dma_command = hwif->dma_base; hwif->dma_status = hwif->dma_base + 0x04; - hwif->dma_prdtable = hwif->dma_base + 0x08; /* PTERADD */ out_be32((void __iomem *)(hwif->dma_base + 0x018), hwif->dmatable_dma); @@ -706,10 +856,10 @@ static const struct ide_port_ops scc_port_ops = { }; static const struct ide_dma_ops scc_dma_ops = { - .dma_host_set = ide_dma_host_set, + .dma_host_set = scc_dma_host_set, .dma_setup = scc_dma_setup, .dma_exec_cmd = ide_dma_exec_cmd, - .dma_start = ide_dma_start, + .dma_start = scc_dma_start, .dma_end = scc_dma_end, .dma_test_irq = scc_dma_test_irq, .dma_lost_irq = ide_dma_lost_irq, diff --git a/drivers/ide/pci/sgiioc4.c b/drivers/ide/pci/sgiioc4.c index 63e28f4e6d3..16a0bce17d6 100644 --- a/drivers/ide/pci/sgiioc4.c +++ b/drivers/ide/pci/sgiioc4.c @@ -573,6 +573,7 @@ static const struct ide_port_info sgiioc4_port_info __devinitdata = { .init_dma = ide_dma_sgiioc4, .port_ops = &sgiioc4_port_ops, .dma_ops = &sgiioc4_dma_ops, + .host_flags = IDE_HFLAG_MMIO, .mwdma_mask = ATA_MWDMA2_ONLY, }; diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c index c2040a017f4..0006b9e5856 100644 --- a/drivers/ide/pci/siimage.c +++ b/drivers/ide/pci/siimage.c @@ -1,8 +1,8 @@ /* * Copyright (C) 2001-2002 Andre Hedrick <andre@linux-ide.org> * Copyright (C) 2003 Red Hat <alan@redhat.com> - * Copyright (C) 2007 MontaVista Software, Inc. - * Copyright (C) 2007 Bartlomiej Zolnierkiewicz + * Copyright (C) 2007-2008 MontaVista Software, Inc. + * Copyright (C) 2007-2008 Bartlomiej Zolnierkiewicz * * May be copied or modified under the terms of the GNU General Public License * @@ -17,10 +17,10 @@ * * FAQ Items: * If you are using Marvell SATA-IDE adapters with Maxtor drives - * ensure the system is set up for ATA100/UDMA5 not UDMA6. + * ensure the system is set up for ATA100/UDMA5, not UDMA6. * * If you are using WD drives with SATA bridges you must set the - * drive to "Single". "Master" will hang + * drive to "Single". "Master" will hang. * * If you have strange problems with nVidia chipset systems please * see the SI support documentation and update your system BIOS @@ -42,25 +42,24 @@ #include <linux/hdreg.h> #include <linux/ide.h> #include <linux/init.h> - -#include <asm/io.h> +#include <linux/io.h> /** * pdev_is_sata - check if device is SATA * @pdev: PCI device to check - * + * * Returns true if this is a SATA controller */ - + static int pdev_is_sata(struct pci_dev *pdev) { #ifdef CONFIG_BLK_DEV_IDE_SATA - switch(pdev->device) { - case PCI_DEVICE_ID_SII_3112: - case PCI_DEVICE_ID_SII_1210SA: - return 1; - case PCI_DEVICE_ID_SII_680: - return 0; + switch (pdev->device) { + case PCI_DEVICE_ID_SII_3112: + case PCI_DEVICE_ID_SII_1210SA: + return 1; + case PCI_DEVICE_ID_SII_680: + return 0; } BUG(); #endif @@ -70,10 +69,10 @@ static int pdev_is_sata(struct pci_dev *pdev) /** * is_sata - check if hwif is SATA * @hwif: interface to check - * + * * Returns true if this is a SATA controller */ - + static inline int is_sata(ide_hwif_t *hwif) { return pdev_is_sata(to_pci_dev(hwif->dev)); @@ -86,21 +85,22 @@ static inline int is_sata(ide_hwif_t *hwif) * * Turn a config register offset into the right address in either * PCI space or MMIO space to access the control register in question - * Thankfully this is a configuration operation so isnt performance - * criticial. + * Thankfully this is a configuration operation, so isn't performance + * critical. */ - + static unsigned long siimage_selreg(ide_hwif_t *hwif, int r) { unsigned long base = (unsigned long)hwif->hwif_data; + base += 0xA0 + r; - if(hwif->mmio) - base += (hwif->channel << 6); + if (hwif->mmio) + base += hwif->channel << 6; else - base += (hwif->channel << 4); + base += hwif->channel << 4; return base; } - + /** * siimage_seldev - return register base * @hwif: interface @@ -110,20 +110,69 @@ static unsigned long siimage_selreg(ide_hwif_t *hwif, int r) * PCI space or MMIO space to access the control register in question * including accounting for the unit shift. */ - + static inline unsigned long siimage_seldev(ide_drive_t *drive, int r) { ide_hwif_t *hwif = HWIF(drive); - unsigned long base = (unsigned long)hwif->hwif_data; + unsigned long base = (unsigned long)hwif->hwif_data; + base += 0xA0 + r; - if(hwif->mmio) - base += (hwif->channel << 6); + if (hwif->mmio) + base += hwif->channel << 6; else - base += (hwif->channel << 4); + base += hwif->channel << 4; base |= drive->select.b.unit << drive->select.b.unit; return base; } +static u8 sil_ioread8(struct pci_dev *dev, unsigned long addr) +{ + u8 tmp = 0; + + if (pci_get_drvdata(dev)) + tmp = readb((void __iomem *)addr); + else + pci_read_config_byte(dev, addr, &tmp); + + return tmp; +} + +static u16 sil_ioread16(struct pci_dev *dev, unsigned long addr) +{ + u16 tmp = 0; + + if (pci_get_drvdata(dev)) + tmp = readw((void __iomem *)addr); + else + pci_read_config_word(dev, addr, &tmp); + + return tmp; +} + +static void sil_iowrite8(struct pci_dev *dev, u8 val, unsigned long addr) +{ + if (pci_get_drvdata(dev)) + writeb(val, (void __iomem *)addr); + else + pci_write_config_byte(dev, addr, val); +} + +static void sil_iowrite16(struct pci_dev *dev, u16 val, unsigned long addr) +{ + if (pci_get_drvdata(dev)) + writew(val, (void __iomem *)addr); + else + pci_write_config_word(dev, addr, val); +} + +static void sil_iowrite32(struct pci_dev *dev, u32 val, unsigned long addr) +{ + if (pci_get_drvdata(dev)) + writel(val, (void __iomem *)addr); + else + pci_write_config_dword(dev, addr, val); +} + /** * sil_udma_filter - compute UDMA mask * @drive: IDE device @@ -136,24 +185,26 @@ static inline unsigned long siimage_seldev(ide_drive_t *drive, int r) static u8 sil_pata_udma_filter(ide_drive_t *drive) { - ide_hwif_t *hwif = drive->hwif; - struct pci_dev *dev = to_pci_dev(hwif->dev); - unsigned long base = (unsigned long) hwif->hwif_data; - u8 mask = 0, scsc = 0; + ide_hwif_t *hwif = drive->hwif; + struct pci_dev *dev = to_pci_dev(hwif->dev); + unsigned long base = (unsigned long)hwif->hwif_data; + u8 scsc, mask = 0; - if (hwif->mmio) - scsc = hwif->INB(base + 0x4A); - else - pci_read_config_byte(dev, 0x8A, &scsc); + scsc = sil_ioread8(dev, base + (hwif->mmio ? 0x4A : 0x8A)); - if ((scsc & 0x30) == 0x10) /* 133 */ + switch (scsc & 0x30) { + case 0x10: /* 133 */ mask = ATA_UDMA6; - else if ((scsc & 0x30) == 0x20) /* 2xPCI */ + break; + case 0x20: /* 2xPCI */ mask = ATA_UDMA6; - else if ((scsc & 0x30) == 0x00) /* 100 */ + break; + case 0x00: /* 100 */ mask = ATA_UDMA5; - else /* Disabled ? */ + break; + default: /* Disabled ? */ BUG(); + } return mask; } @@ -175,15 +226,16 @@ static u8 sil_sata_udma_filter(ide_drive_t *drive) static void sil_set_pio_mode(ide_drive_t *drive, u8 pio) { - const u16 tf_speed[] = { 0x328a, 0x2283, 0x1281, 0x10c3, 0x10c1 }; - const u16 data_speed[] = { 0x328a, 0x2283, 0x1104, 0x10c3, 0x10c1 }; + static const u16 tf_speed[] = { 0x328a, 0x2283, 0x1281, 0x10c3, 0x10c1 }; + static const u16 data_speed[] = { 0x328a, 0x2283, 0x1104, 0x10c3, 0x10c1 }; ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = to_pci_dev(hwif->dev); ide_drive_t *pair = ide_get_paired_drive(drive); u32 speedt = 0; u16 speedp = 0; unsigned long addr = siimage_seldev(drive, 0x04); - unsigned long tfaddr = siimage_selreg(hwif, 0x02); + unsigned long tfaddr = siimage_selreg(hwif, 0x02); unsigned long base = (unsigned long)hwif->hwif_data; u8 tf_pio = pio; u8 addr_mask = hwif->channel ? (hwif->mmio ? 0xF4 : 0x84) @@ -203,36 +255,20 @@ static void sil_set_pio_mode(ide_drive_t *drive, u8 pio) speedp = data_speed[pio]; speedt = tf_speed[tf_pio]; - if (hwif->mmio) { - hwif->OUTW(speedp, addr); - hwif->OUTW(speedt, tfaddr); - /* Now set up IORDY */ - if (pio > 2) - hwif->OUTW(hwif->INW(tfaddr-2)|0x200, tfaddr-2); - else - hwif->OUTW(hwif->INW(tfaddr-2)&~0x200, tfaddr-2); - - mode = hwif->INB(base + addr_mask); - mode &= ~(unit ? 0x30 : 0x03); - mode |= (unit ? 0x10 : 0x01); - hwif->OUTB(mode, base + addr_mask); - } else { - struct pci_dev *dev = to_pci_dev(hwif->dev); - - pci_write_config_word(dev, addr, speedp); - pci_write_config_word(dev, tfaddr, speedt); - pci_read_config_word(dev, tfaddr - 2, &speedp); - speedp &= ~0x200; - /* Set IORDY for mode 3 or 4 */ - if (pio > 2) - speedp |= 0x200; - pci_write_config_word(dev, tfaddr - 2, speedp); - - pci_read_config_byte(dev, addr_mask, &mode); - mode &= ~(unit ? 0x30 : 0x03); - mode |= (unit ? 0x10 : 0x01); - pci_write_config_byte(dev, addr_mask, mode); - } + sil_iowrite16(dev, speedp, addr); + sil_iowrite16(dev, speedt, tfaddr); + + /* now set up IORDY */ + speedp = sil_ioread16(dev, tfaddr - 2); + speedp &= ~0x200; + if (pio > 2) + speedp |= 0x200; + sil_iowrite16(dev, speedp, tfaddr - 2); + + mode = sil_ioread8(dev, base + addr_mask); + mode &= ~(unit ? 0x30 : 0x03); + mode |= unit ? 0x10 : 0x01; + sil_iowrite8(dev, mode, base + addr_mask); } /** @@ -245,59 +281,45 @@ static void sil_set_pio_mode(ide_drive_t *drive, u8 pio) static void sil_set_dma_mode(ide_drive_t *drive, const u8 speed) { - u8 ultra6[] = { 0x0F, 0x0B, 0x07, 0x05, 0x03, 0x02, 0x01 }; - u8 ultra5[] = { 0x0C, 0x07, 0x05, 0x04, 0x02, 0x01 }; - u16 dma[] = { 0x2208, 0x10C2, 0x10C1 }; + static const u8 ultra6[] = { 0x0F, 0x0B, 0x07, 0x05, 0x03, 0x02, 0x01 }; + static const u8 ultra5[] = { 0x0C, 0x07, 0x05, 0x04, 0x02, 0x01 }; + static const u16 dma[] = { 0x2208, 0x10C2, 0x10C1 }; ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = to_pci_dev(hwif->dev); u16 ultra = 0, multi = 0; u8 mode = 0, unit = drive->select.b.unit; unsigned long base = (unsigned long)hwif->hwif_data; - u8 scsc = 0, addr_mask = ((hwif->channel) ? - ((hwif->mmio) ? 0xF4 : 0x84) : - ((hwif->mmio) ? 0xB4 : 0x80)); - + u8 scsc = 0, addr_mask = hwif->channel ? + (hwif->mmio ? 0xF4 : 0x84) : + (hwif->mmio ? 0xB4 : 0x80); unsigned long ma = siimage_seldev(drive, 0x08); unsigned long ua = siimage_seldev(drive, 0x0C); - if (hwif->mmio) { - scsc = hwif->INB(base + 0x4A); - mode = hwif->INB(base + addr_mask); - multi = hwif->INW(ma); - ultra = hwif->INW(ua); - } else { - pci_read_config_byte(dev, 0x8A, &scsc); - pci_read_config_byte(dev, addr_mask, &mode); - pci_read_config_word(dev, ma, &multi); - pci_read_config_word(dev, ua, &ultra); - } + scsc = sil_ioread8 (dev, base + (hwif->mmio ? 0x4A : 0x8A)); + mode = sil_ioread8 (dev, base + addr_mask); + multi = sil_ioread16(dev, ma); + ultra = sil_ioread16(dev, ua); - mode &= ~((unit) ? 0x30 : 0x03); + mode &= ~(unit ? 0x30 : 0x03); ultra &= ~0x3F; scsc = ((scsc & 0x30) == 0x00) ? 0 : 1; scsc = is_sata(hwif) ? 1 : scsc; if (speed >= XFER_UDMA_0) { - multi = dma[2]; - ultra |= (scsc ? ultra6[speed - XFER_UDMA_0] : - ultra5[speed - XFER_UDMA_0]); - mode |= (unit ? 0x30 : 0x03); + multi = dma[2]; + ultra |= scsc ? ultra6[speed - XFER_UDMA_0] : + ultra5[speed - XFER_UDMA_0]; + mode |= unit ? 0x30 : 0x03; } else { multi = dma[speed - XFER_MW_DMA_0]; - mode |= (unit ? 0x20 : 0x02); + mode |= unit ? 0x20 : 0x02; } - if (hwif->mmio) { - hwif->OUTB(mode, base + addr_mask); - hwif->OUTW(multi, ma); - hwif->OUTW(ultra, ua); - } else { - pci_write_config_byte(dev, addr_mask, mode); - pci_write_config_word(dev, ma, multi); - pci_write_config_word(dev, ua, ultra); - } + sil_iowrite8 (dev, mode, base + addr_mask); + sil_iowrite16(dev, multi, ma); + sil_iowrite16(dev, ultra, ua); } /* returns 1 if dma irq issued, 0 otherwise */ @@ -309,13 +331,14 @@ static int siimage_io_dma_test_irq(ide_drive_t *drive) unsigned long addr = siimage_selreg(hwif, 1); /* return 1 if INTR asserted */ - if ((hwif->INB(hwif->dma_status) & 4) == 4) + if (hwif->INB(hwif->dma_status) & 4) return 1; /* return 1 if Device INTR asserted */ pci_read_config_byte(dev, addr, &dma_altstat); if (dma_altstat & 8) - return 0; //return 1; + return 0; /* return 1; */ + return 0; } @@ -335,9 +358,9 @@ static int siimage_mmio_dma_test_irq(ide_drive_t *drive) = (void __iomem *)hwif->sata_scr[SATA_ERROR_OFFSET]; if (sata_error_addr) { - unsigned long base = (unsigned long)hwif->hwif_data; - u32 ext_stat = readl((void __iomem *)(base + 0x10)); - u8 watchdog = 0; + unsigned long base = (unsigned long)hwif->hwif_data; + u32 ext_stat = readl((void __iomem *)(base + 0x10)); + u8 watchdog = 0; if (ext_stat & ((hwif->channel) ? 0x40 : 0x10)) { u32 sata_error = readl(sata_error_addr); @@ -346,25 +369,22 @@ static int siimage_mmio_dma_test_irq(ide_drive_t *drive) watchdog = (sata_error & 0x00680000) ? 1 : 0; printk(KERN_WARNING "%s: sata_error = 0x%08x, " "watchdog = %d, %s\n", - drive->name, sata_error, watchdog, - __func__); - - } else { + drive->name, sata_error, watchdog, __func__); + } else watchdog = (ext_stat & 0x8000) ? 1 : 0; - } - ext_stat >>= 16; + ext_stat >>= 16; if (!(ext_stat & 0x0404) && !watchdog) return 0; } /* return 1 if INTR asserted */ - if ((readb((void __iomem *)hwif->dma_status) & 0x04) == 0x04) + if (readb((void __iomem *)hwif->dma_status) & 0x04) return 1; /* return 1 if Device INTR asserted */ - if ((readb((void __iomem *)addr) & 8) == 8) - return 0; //return 1; + if (readb((void __iomem *)addr) & 8) + return 0; /* return 1; */ return 0; } @@ -423,63 +443,33 @@ static void sil_sata_pre_reset(ide_drive_t *drive) } /** - * proc_reports_siimage - add siimage controller to proc - * @dev: PCI device - * @clocking: SCSC value - * @name: controller name - * - * Report the clocking mode of the controller and add it to - * the /proc interface layer - */ - -static void proc_reports_siimage (struct pci_dev *dev, u8 clocking, const char *name) -{ - if (!pdev_is_sata(dev)) { - printk(KERN_INFO "%s: BASE CLOCK ", name); - clocking &= 0x03; - switch (clocking) { - case 0x03: printk("DISABLED!\n"); break; - case 0x02: printk("== 2X PCI\n"); break; - case 0x01: printk("== 133\n"); break; - case 0x00: printk("== 100\n"); break; - } - } -} - -/** - * setup_mmio_siimage - switch an SI controller into MMIO + * setup_mmio_siimage - switch controller into MMIO mode * @dev: PCI device we are configuring * @name: device name * - * Attempt to put the device into mmio mode. There are some slight - * complications here with certain systems where the mmio bar isnt - * mapped so we have to be sure we can fall back to I/O. + * Attempt to put the device into MMIO mode. There are some slight + * complications here with certain systems where the MMIO BAR isn't + * mapped, so we have to be sure that we can fall back to I/O. */ - -static unsigned int setup_mmio_siimage (struct pci_dev *dev, const char *name) + +static unsigned int setup_mmio_siimage(struct pci_dev *dev, const char *name) { resource_size_t bar5 = pci_resource_start(dev, 5); unsigned long barsize = pci_resource_len(dev, 5); - u8 tmpbyte = 0; void __iomem *ioaddr; - u32 tmp, irq_mask; /* - * Drop back to PIO if we can't map the mmio. Some - * systems seem to get terminally confused in the PCI - * spaces. + * Drop back to PIO if we can't map the MMIO. Some systems + * seem to get terminally confused in the PCI spaces. */ - - if(!request_mem_region(bar5, barsize, name)) - { - printk(KERN_WARNING "siimage: IDE controller MMIO ports not available.\n"); + if (!request_mem_region(bar5, barsize, name)) { + printk(KERN_WARNING "siimage: IDE controller MMIO ports not " + "available.\n"); return 0; } - - ioaddr = ioremap(bar5, barsize); - if (ioaddr == NULL) - { + ioaddr = ioremap(bar5, barsize); + if (ioaddr == NULL) { release_mem_region(bar5, barsize); return 0; } @@ -487,62 +477,6 @@ static unsigned int setup_mmio_siimage (struct pci_dev *dev, const char *name) pci_set_master(dev); pci_set_drvdata(dev, (void *) ioaddr); - if (pdev_is_sata(dev)) { - /* make sure IDE0/1 interrupts are not masked */ - irq_mask = (1 << 22) | (1 << 23); - tmp = readl(ioaddr + 0x48); - if (tmp & irq_mask) { - tmp &= ~irq_mask; - writel(tmp, ioaddr + 0x48); - readl(ioaddr + 0x48); /* flush */ - } - writel(0, ioaddr + 0x148); - writel(0, ioaddr + 0x1C8); - } - - writeb(0, ioaddr + 0xB4); - writeb(0, ioaddr + 0xF4); - tmpbyte = readb(ioaddr + 0x4A); - - switch(tmpbyte & 0x30) { - case 0x00: - /* In 100 MHz clocking, try and switch to 133 */ - writeb(tmpbyte|0x10, ioaddr + 0x4A); - break; - case 0x10: - /* On 133Mhz clocking */ - break; - case 0x20: - /* On PCIx2 clocking */ - break; - case 0x30: - /* Clocking is disabled */ - /* 133 clock attempt to force it on */ - writeb(tmpbyte & ~0x20, ioaddr + 0x4A); - break; - } - - writeb( 0x72, ioaddr + 0xA1); - writew( 0x328A, ioaddr + 0xA2); - writel(0x62DD62DD, ioaddr + 0xA4); - writel(0x43924392, ioaddr + 0xA8); - writel(0x40094009, ioaddr + 0xAC); - writeb( 0x72, ioaddr + 0xE1); - writew( 0x328A, ioaddr + 0xE2); - writel(0x62DD62DD, ioaddr + 0xE4); - writel(0x43924392, ioaddr + 0xE8); - writel(0x40094009, ioaddr + 0xEC); - - if (pdev_is_sata(dev)) { - writel(0xFFFF0000, ioaddr + 0x108); - writel(0xFFFF0000, ioaddr + 0x188); - writel(0x00680000, ioaddr + 0x148); - writel(0x00680000, ioaddr + 0x1C8); - } - - tmpbyte = readb(ioaddr + 0x4A); - - proc_reports_siimage(dev, (tmpbyte>>4), name); return 1; } @@ -552,55 +486,92 @@ static unsigned int setup_mmio_siimage (struct pci_dev *dev, const char *name) * @name: device name * * Perform the initial PCI set up for this device. Attempt to switch - * to 133MHz clocking if the system isn't already set up to do it. + * to 133 MHz clocking if the system isn't already set up to do it. */ -static unsigned int __devinit init_chipset_siimage(struct pci_dev *dev, const char *name) +static unsigned int __devinit init_chipset_siimage(struct pci_dev *dev, + const char *name) { - u8 rev = dev->revision, tmpbyte = 0, BA5_EN = 0; + unsigned long base, scsc_addr; + void __iomem *ioaddr = NULL; + u8 rev = dev->revision, tmp, BA5_EN; pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, rev ? 1 : 255); pci_read_config_byte(dev, 0x8A, &BA5_EN); - if ((BA5_EN & 0x01) || (pci_resource_start(dev, 5))) { - if (setup_mmio_siimage(dev, name)) { - return 0; + + if ((BA5_EN & 0x01) || pci_resource_start(dev, 5)) + if (setup_mmio_siimage(dev, name)) + ioaddr = pci_get_drvdata(dev); + + base = (unsigned long)ioaddr; + + if (ioaddr && pdev_is_sata(dev)) { + u32 tmp32, irq_mask; + + /* make sure IDE0/1 interrupts are not masked */ + irq_mask = (1 << 22) | (1 << 23); + tmp32 = readl(ioaddr + 0x48); + if (tmp32 & irq_mask) { + tmp32 &= ~irq_mask; + writel(tmp32, ioaddr + 0x48); + readl(ioaddr + 0x48); /* flush */ } + writel(0, ioaddr + 0x148); + writel(0, ioaddr + 0x1C8); + } + + sil_iowrite8(dev, 0, base ? (base + 0xB4) : 0x80); + sil_iowrite8(dev, 0, base ? (base + 0xF4) : 0x84); + + scsc_addr = base ? (base + 0x4A) : 0x8A; + tmp = sil_ioread8(dev, scsc_addr); + + switch (tmp & 0x30) { + case 0x00: + /* On 100 MHz clocking, try and switch to 133 MHz */ + sil_iowrite8(dev, tmp | 0x10, scsc_addr); + break; + case 0x30: + /* Clocking is disabled, attempt to force 133MHz clocking. */ + sil_iowrite8(dev, tmp & ~0x20, scsc_addr); + case 0x10: + /* On 133Mhz clocking. */ + break; + case 0x20: + /* On PCIx2 clocking. */ + break; } - pci_write_config_byte(dev, 0x80, 0x00); - pci_write_config_byte(dev, 0x84, 0x00); - pci_read_config_byte(dev, 0x8A, &tmpbyte); - switch(tmpbyte & 0x30) { - case 0x00: - /* 133 clock attempt to force it on */ - pci_write_config_byte(dev, 0x8A, tmpbyte|0x10); - case 0x30: - /* if clocking is disabled */ - /* 133 clock attempt to force it on */ - pci_write_config_byte(dev, 0x8A, tmpbyte & ~0x20); - case 0x10: - /* 133 already */ - break; - case 0x20: - /* BIOS set PCI x2 clocking */ - break; + tmp = sil_ioread8(dev, scsc_addr); + + sil_iowrite8 (dev, 0x72, base + 0xA1); + sil_iowrite16(dev, 0x328A, base + 0xA2); + sil_iowrite32(dev, 0x62DD62DD, base + 0xA4); + sil_iowrite32(dev, 0x43924392, base + 0xA8); + sil_iowrite32(dev, 0x40094009, base + 0xAC); + sil_iowrite8 (dev, 0x72, base ? (base + 0xE1) : 0xB1); + sil_iowrite16(dev, 0x328A, base ? (base + 0xE2) : 0xB2); + sil_iowrite32(dev, 0x62DD62DD, base ? (base + 0xE4) : 0xB4); + sil_iowrite32(dev, 0x43924392, base ? (base + 0xE8) : 0xB8); + sil_iowrite32(dev, 0x40094009, base ? (base + 0xEC) : 0xBC); + + if (base && pdev_is_sata(dev)) { + writel(0xFFFF0000, ioaddr + 0x108); + writel(0xFFFF0000, ioaddr + 0x188); + writel(0x00680000, ioaddr + 0x148); + writel(0x00680000, ioaddr + 0x1C8); } - pci_read_config_byte(dev, 0x8A, &tmpbyte); + /* report the clocking mode of the controller */ + if (!pdev_is_sata(dev)) { + static const char *clk_str[] = + { "== 100", "== 133", "== 2X PCI", "DISABLED!" }; - pci_write_config_byte(dev, 0xA1, 0x72); - pci_write_config_word(dev, 0xA2, 0x328A); - pci_write_config_dword(dev, 0xA4, 0x62DD62DD); - pci_write_config_dword(dev, 0xA8, 0x43924392); - pci_write_config_dword(dev, 0xAC, 0x40094009); - pci_write_config_byte(dev, 0xB1, 0x72); - pci_write_config_word(dev, 0xB2, 0x328A); - pci_write_config_dword(dev, 0xB4, 0x62DD62DD); - pci_write_config_dword(dev, 0xB8, 0x43924392); - pci_write_config_dword(dev, 0xBC, 0x40094009); + tmp >>= 4; + printk(KERN_INFO "%s: BASE CLOCK %s\n", name, clk_str[tmp & 3]); + } - proc_reports_siimage(dev, (tmpbyte>>4), name); return 0; } @@ -610,8 +581,7 @@ static unsigned int __devinit init_chipset_siimage(struct pci_dev *dev, const ch * * The basic setup here is fairly simple, we can use standard MMIO * operations. However we do have to set the taskfile register offsets - * by hand as there isnt a standard defined layout for them this - * time. + * by hand as there isn't a standard defined layout for them this time. * * The hardware supports buffered taskfiles and also some rather nice * extended PRD tables. For better SI3112 support use the libata driver @@ -622,23 +592,20 @@ static void __devinit init_mmio_iops_siimage(ide_hwif_t *hwif) struct pci_dev *dev = to_pci_dev(hwif->dev); void *addr = pci_get_drvdata(dev); u8 ch = hwif->channel; - unsigned long base; - struct ide_io_ports *io_ports = &hwif->io_ports; + unsigned long base; /* - * Fill in the basic HWIF bits + * Fill in the basic hwif bits */ - + hwif->host_flags |= IDE_HFLAG_MMIO; default_hwif_mmiops(hwif); - hwif->hwif_data = addr; + hwif->hwif_data = addr; /* - * Now set up the hw. We have to do this ourselves as - * the MMIO layout isnt the same as the standard port - * based I/O + * Now set up the hw. We have to do this ourselves as the + * MMIO layout isn't the same as the standard port based I/O. */ - memset(io_ports, 0, sizeof(*io_ports)); base = (unsigned long)addr; @@ -648,10 +615,9 @@ static void __devinit init_mmio_iops_siimage(ide_hwif_t *hwif) base += 0x80; /* - * The buffered task file doesn't have status/control - * so we can't currently use it sanely since we want to - * use LBA48 mode. - */ + * The buffered task file doesn't have status/control, so we + * can't currently use it sanely since we want to use LBA48 mode. + */ io_ports->data_addr = base; io_ports->error_addr = base + 1; io_ports->nsect_addr = base + 2; @@ -680,19 +646,17 @@ static void __devinit init_mmio_iops_siimage(ide_hwif_t *hwif) static int is_dev_seagate_sata(ide_drive_t *drive) { - const char *s = &drive->id->model[0]; - unsigned len; - - len = strnlen(s, sizeof(drive->id->model)); + const char *s = &drive->id->model[0]; + unsigned len = strnlen(s, sizeof(drive->id->model)); - if ((len > 4) && (!memcmp(s, "ST", 2))) { + if ((len > 4) && (!memcmp(s, "ST", 2))) if ((!memcmp(s + len - 2, "AS", 2)) || (!memcmp(s + len - 3, "ASL", 3))) { printk(KERN_INFO "%s: applying pessimistic Seagate " "errata fix\n", drive->name); return 1; } - } + return 0; } @@ -709,7 +673,7 @@ static void __devinit sil_quirkproc(ide_drive_t *drive) { ide_hwif_t *hwif = drive->hwif; - /* Try and raise the rqsize */ + /* Try and rise the rqsize */ if (!is_sata(hwif) || !is_dev_seagate_sata(drive)) hwif->rqsize = 128; } @@ -743,20 +707,14 @@ static void __devinit init_iops_siimage(ide_hwif_t *hwif) * sil_cable_detect - cable detection * @hwif: interface to check * - * Check for the presence of an ATA66 capable cable on the - * interface. + * Check for the presence of an ATA66 capable cable on the interface. */ static u8 __devinit sil_cable_detect(ide_hwif_t *hwif) { - struct pci_dev *dev = to_pci_dev(hwif->dev); - unsigned long addr = siimage_selreg(hwif, 0); - u8 ata66 = 0; - - if (pci_get_drvdata(dev) == NULL) - pci_read_config_byte(dev, addr, &ata66); - else - ata66 = hwif->INB(addr); + struct pci_dev *dev = to_pci_dev(hwif->dev); + unsigned long addr = siimage_selreg(hwif, 0); + u8 ata66 = sil_ioread8(dev, addr); return (ata66 & 0x01) ? ATA_CBL_PATA80 : ATA_CBL_PATA40; } @@ -779,8 +737,15 @@ static const struct ide_port_ops sil_sata_port_ops = { .cable_detect = sil_cable_detect, }; -static struct ide_dma_ops sil_dma_ops = { +static const struct ide_dma_ops sil_dma_ops = { + .dma_host_set = ide_dma_host_set, + .dma_setup = ide_dma_setup, + .dma_exec_cmd = ide_dma_exec_cmd, + .dma_start = ide_dma_start, + .dma_end = __ide_dma_end, .dma_test_irq = siimage_dma_test_irq, + .dma_timeout = ide_dma_timeout, + .dma_lost_irq = ide_dma_lost_irq, }; #define DECLARE_SII_DEV(name_str, p_ops) \ @@ -802,15 +767,16 @@ static const struct ide_port_info siimage_chipsets[] __devinitdata = { }; /** - * siimage_init_one - pci layer discovery entry + * siimage_init_one - PCI layer discovery entry * @dev: PCI device * @id: ident table entry * - * Called by the PCI code when it finds an SI680 or SI3112 controller. + * Called by the PCI code when it finds an SiI680 or SiI3112 controller. * We then use the IDE PCI generic helper to do most of the work. */ - -static int __devinit siimage_init_one(struct pci_dev *dev, const struct pci_device_id *id) + +static int __devinit siimage_init_one(struct pci_dev *dev, + const struct pci_device_id *id) { struct ide_port_info d; u8 idx = id->driver_data; diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c index 3cac6b2790d..48aa019127b 100644 --- a/drivers/ide/ppc/pmac.c +++ b/drivers/ide/ppc/pmac.c @@ -941,6 +941,7 @@ static const struct ide_port_info pmac_port_info = { .port_ops = &pmac_ide_port_ops, .host_flags = IDE_HFLAG_SET_PIO_MODE_KEEP_DMA | IDE_HFLAG_POST_SET_MODE | + IDE_HFLAG_MMIO | IDE_HFLAG_UNMASK_IRQS, .pio_mask = ATA_PIO4, .mwdma_mask = ATA_MWDMA2, diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c index 4e3128ff73c..fe78f7d2509 100644 --- a/drivers/infiniband/core/umem.c +++ b/drivers/infiniband/core/umem.c @@ -38,6 +38,7 @@ #include <linux/dma-mapping.h> #include <linux/sched.h> #include <linux/hugetlb.h> +#include <linux/dma-attrs.h> #include "uverbs.h" @@ -72,9 +73,10 @@ static void __ib_umem_release(struct ib_device *dev, struct ib_umem *umem, int d * @addr: userspace virtual address to start at * @size: length of region to pin * @access: IB_ACCESS_xxx flags for memory being pinned + * @dmasync: flush in-flight DMA when the memory region is written */ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, - size_t size, int access) + size_t size, int access, int dmasync) { struct ib_umem *umem; struct page **page_list; @@ -87,6 +89,10 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, int ret; int off; int i; + DEFINE_DMA_ATTRS(attrs); + + if (dmasync) + dma_set_attr(DMA_ATTR_WRITE_BARRIER, &attrs); if (!can_do_mlock()) return ERR_PTR(-EPERM); @@ -174,10 +180,11 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, sg_set_page(&chunk->page_list[i], page_list[i + off], PAGE_SIZE, 0); } - chunk->nmap = ib_dma_map_sg(context->device, - &chunk->page_list[0], - chunk->nents, - DMA_BIDIRECTIONAL); + chunk->nmap = ib_dma_map_sg_attrs(context->device, + &chunk->page_list[0], + chunk->nents, + DMA_BIDIRECTIONAL, + &attrs); if (chunk->nmap <= 0) { for (i = 0; i < chunk->nents; ++i) put_page(sg_page(&chunk->page_list[i])); diff --git a/drivers/infiniband/hw/amso1100/c2_provider.c b/drivers/infiniband/hw/amso1100/c2_provider.c index 6af2c0f79a6..2acf9b62cf9 100644 --- a/drivers/infiniband/hw/amso1100/c2_provider.c +++ b/drivers/infiniband/hw/amso1100/c2_provider.c @@ -452,7 +452,7 @@ static struct ib_mr *c2_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, return ERR_PTR(-ENOMEM); c2mr->pd = c2pd; - c2mr->umem = ib_umem_get(pd->uobject->context, start, length, acc); + c2mr->umem = ib_umem_get(pd->uobject->context, start, length, acc, 0); if (IS_ERR(c2mr->umem)) { err = PTR_ERR(c2mr->umem); kfree(c2mr); diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.c b/drivers/infiniband/hw/cxgb3/cxio_hal.c index 66eb7030aea..ed2ee4ba4b7 100644 --- a/drivers/infiniband/hw/cxgb3/cxio_hal.c +++ b/drivers/infiniband/hw/cxgb3/cxio_hal.c @@ -456,7 +456,8 @@ void cxio_count_scqes(struct t3_cq *cq, struct t3_wq *wq, int *count) ptr = cq->sw_rptr; while (!Q_EMPTY(ptr, cq->sw_wptr)) { cqe = cq->sw_queue + (Q_PTR2IDX(ptr, cq->size_log2)); - if ((SQ_TYPE(*cqe) || (CQE_OPCODE(*cqe) == T3_READ_RESP)) && + if ((SQ_TYPE(*cqe) || + ((CQE_OPCODE(*cqe) == T3_READ_RESP) && wq->oldest_read)) && (CQE_QPID(*cqe) == wq->qpid)) (*count)++; ptr++; @@ -829,7 +830,8 @@ int cxio_rdma_init(struct cxio_rdev *rdev_p, struct t3_rdma_init_attr *attr) wqe->mpaattrs = attr->mpaattrs; wqe->qpcaps = attr->qpcaps; wqe->ulpdu_size = cpu_to_be16(attr->tcp_emss); - wqe->flags = cpu_to_be32(attr->flags); + wqe->rqe_count = cpu_to_be16(attr->rqe_count); + wqe->flags_rtr_type = cpu_to_be16(attr->flags|V_RTR_TYPE(attr->rtr_type)); wqe->ord = cpu_to_be32(attr->ord); wqe->ird = cpu_to_be32(attr->ird); wqe->qp_dma_addr = cpu_to_be64(attr->qp_dma_addr); @@ -1135,6 +1137,18 @@ int cxio_poll_cq(struct t3_wq *wq, struct t3_cq *cq, struct t3_cqe *cqe, if (RQ_TYPE(*hw_cqe) && (CQE_OPCODE(*hw_cqe) == T3_READ_RESP)) { /* + * If this is an unsolicited read response, then the read + * was generated by the kernel driver as part of peer-2-peer + * connection setup. So ignore the completion. + */ + if (!wq->oldest_read) { + if (CQE_STATUS(*hw_cqe)) + wq->error = 1; + ret = -1; + goto skip_cqe; + } + + /* * Don't write to the HWCQ, so create a new read req CQE * in local memory. */ diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.h b/drivers/infiniband/hw/cxgb3/cxio_hal.h index 99543d63470..2bcff7f5046 100644 --- a/drivers/infiniband/hw/cxgb3/cxio_hal.h +++ b/drivers/infiniband/hw/cxgb3/cxio_hal.h @@ -53,6 +53,7 @@ #define T3_MAX_PBL_SIZE 256 #define T3_MAX_RQ_SIZE 1024 #define T3_MAX_NUM_STAG (1<<15) +#define T3_MAX_MR_SIZE 0x100000000ULL #define T3_STAG_UNSET 0xffffffff diff --git a/drivers/infiniband/hw/cxgb3/cxio_wr.h b/drivers/infiniband/hw/cxgb3/cxio_wr.h index 969d4d92845..f1a25a821a4 100644 --- a/drivers/infiniband/hw/cxgb3/cxio_wr.h +++ b/drivers/infiniband/hw/cxgb3/cxio_wr.h @@ -278,6 +278,17 @@ enum t3_qp_caps { uP_RI_QP_STAG0_ENABLE = 0x10 } __attribute__ ((packed)); +enum rdma_init_rtr_types { + RTR_READ = 1, + RTR_WRITE = 2, + RTR_SEND = 3, +}; + +#define S_RTR_TYPE 2 +#define M_RTR_TYPE 0x3 +#define V_RTR_TYPE(x) ((x) << S_RTR_TYPE) +#define G_RTR_TYPE(x) ((((x) >> S_RTR_TYPE)) & M_RTR_TYPE) + struct t3_rdma_init_attr { u32 tid; u32 qpid; @@ -293,7 +304,9 @@ struct t3_rdma_init_attr { u32 ird; u64 qp_dma_addr; u32 qp_dma_size; - u32 flags; + enum rdma_init_rtr_types rtr_type; + u16 flags; + u16 rqe_count; u32 irs; }; @@ -309,8 +322,8 @@ struct t3_rdma_init_wr { u8 mpaattrs; /* 5 */ u8 qpcaps; __be16 ulpdu_size; - __be32 flags; /* bits 31-1 - reservered */ - /* bit 0 - set if RECV posted */ + __be16 flags_rtr_type; + __be16 rqe_count; __be32 ord; /* 6 */ __be32 ird; __be64 qp_dma_addr; /* 7 */ @@ -324,7 +337,7 @@ struct t3_genbit { }; enum rdma_init_wr_flags { - RECVS_POSTED = (1<<0), + MPA_INITIATOR = (1<<0), PRIV_QP = (1<<1), }; diff --git a/drivers/infiniband/hw/cxgb3/iwch.c b/drivers/infiniband/hw/cxgb3/iwch.c index 6ba4138c8ec..71554eacb13 100644 --- a/drivers/infiniband/hw/cxgb3/iwch.c +++ b/drivers/infiniband/hw/cxgb3/iwch.c @@ -83,6 +83,7 @@ static void rnic_init(struct iwch_dev *rnicp) rnicp->attr.max_phys_buf_entries = T3_MAX_PBL_SIZE; rnicp->attr.max_pds = T3_MAX_NUM_PD - 1; rnicp->attr.mem_pgsizes_bitmask = 0x7FFF; /* 4KB-128MB */ + rnicp->attr.max_mr_size = T3_MAX_MR_SIZE; rnicp->attr.can_resize_wq = 0; rnicp->attr.max_rdma_reads_per_qp = 8; rnicp->attr.max_rdma_read_resources = diff --git a/drivers/infiniband/hw/cxgb3/iwch.h b/drivers/infiniband/hw/cxgb3/iwch.h index 9ad9b1e7c8c..d2409a505e8 100644 --- a/drivers/infiniband/hw/cxgb3/iwch.h +++ b/drivers/infiniband/hw/cxgb3/iwch.h @@ -66,6 +66,7 @@ struct iwch_rnic_attributes { * size (4k)^i. Phys block list mode unsupported. */ u32 mem_pgsizes_bitmask; + u64 max_mr_size; u8 can_resize_wq; /* diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c index 72ca360c3db..d44a6df9ad8 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_cm.c +++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c @@ -63,6 +63,10 @@ static char *states[] = { NULL, }; +int peer2peer = 0; +module_param(peer2peer, int, 0644); +MODULE_PARM_DESC(peer2peer, "Support peer2peer ULPs (default=0)"); + static int ep_timeout_secs = 10; module_param(ep_timeout_secs, int, 0644); MODULE_PARM_DESC(ep_timeout_secs, "CM Endpoint operation timeout " @@ -125,6 +129,12 @@ static void start_ep_timer(struct iwch_ep *ep) static void stop_ep_timer(struct iwch_ep *ep) { PDBG("%s ep %p\n", __func__, ep); + if (!timer_pending(&ep->timer)) { + printk(KERN_ERR "%s timer stopped when its not running! ep %p state %u\n", + __func__, ep, ep->com.state); + WARN_ON(1); + return; + } del_timer_sync(&ep->timer); put_ep(&ep->com); } @@ -508,7 +518,7 @@ static void send_mpa_req(struct iwch_ep *ep, struct sk_buff *skb) skb_reset_transport_header(skb); len = skb->len; req = (struct tx_data_wr *) skb_push(skb, sizeof(*req)); - req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA)); + req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA)|F_WR_COMPL); req->wr_lo = htonl(V_WR_TID(ep->hwtid)); req->len = htonl(len); req->param = htonl(V_TX_PORT(ep->l2t->smt_idx) | @@ -559,7 +569,7 @@ static int send_mpa_reject(struct iwch_ep *ep, const void *pdata, u8 plen) set_arp_failure_handler(skb, arp_failure_discard); skb_reset_transport_header(skb); req = (struct tx_data_wr *) skb_push(skb, sizeof(*req)); - req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA)); + req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA)|F_WR_COMPL); req->wr_lo = htonl(V_WR_TID(ep->hwtid)); req->len = htonl(mpalen); req->param = htonl(V_TX_PORT(ep->l2t->smt_idx) | @@ -611,7 +621,7 @@ static int send_mpa_reply(struct iwch_ep *ep, const void *pdata, u8 plen) skb_reset_transport_header(skb); len = skb->len; req = (struct tx_data_wr *) skb_push(skb, sizeof(*req)); - req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA)); + req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA)|F_WR_COMPL); req->wr_lo = htonl(V_WR_TID(ep->hwtid)); req->len = htonl(len); req->param = htonl(V_TX_PORT(ep->l2t->smt_idx) | @@ -879,6 +889,7 @@ static void process_mpa_reply(struct iwch_ep *ep, struct sk_buff *skb) * the MPA header is valid. */ state_set(&ep->com, FPDU_MODE); + ep->mpa_attr.initiator = 1; ep->mpa_attr.crc_enabled = (mpa->flags & MPA_CRC) | crc_enabled ? 1 : 0; ep->mpa_attr.recv_marker_enabled = markers_enabled; ep->mpa_attr.xmit_marker_enabled = mpa->flags & MPA_MARKERS ? 1 : 0; @@ -901,8 +912,14 @@ static void process_mpa_reply(struct iwch_ep *ep, struct sk_buff *skb) /* bind QP and TID with INIT_WR */ err = iwch_modify_qp(ep->com.qp->rhp, ep->com.qp, mask, &attrs, 1); - if (!err) - goto out; + if (err) + goto err; + + if (peer2peer && iwch_rqes_posted(ep->com.qp) == 0) { + iwch_post_zb_read(ep->com.qp); + } + + goto out; err: abort_connection(ep, skb, GFP_KERNEL); out: @@ -995,6 +1012,7 @@ static void process_mpa_request(struct iwch_ep *ep, struct sk_buff *skb) * If we get here we have accumulated the entire mpa * start reply message including private data. */ + ep->mpa_attr.initiator = 0; ep->mpa_attr.crc_enabled = (mpa->flags & MPA_CRC) | crc_enabled ? 1 : 0; ep->mpa_attr.recv_marker_enabled = markers_enabled; ep->mpa_attr.xmit_marker_enabled = mpa->flags & MPA_MARKERS ? 1 : 0; @@ -1065,17 +1083,33 @@ static int tx_ack(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) PDBG("%s ep %p credits %u\n", __func__, ep, credits); - if (credits == 0) + if (credits == 0) { + PDBG(KERN_ERR "%s 0 credit ack ep %p state %u\n", + __func__, ep, state_read(&ep->com)); return CPL_RET_BUF_DONE; + } + BUG_ON(credits != 1); - BUG_ON(ep->mpa_skb == NULL); - kfree_skb(ep->mpa_skb); - ep->mpa_skb = NULL; dst_confirm(ep->dst); - if (state_read(&ep->com) == MPA_REP_SENT) { - ep->com.rpl_done = 1; - PDBG("waking up ep %p\n", ep); - wake_up(&ep->com.waitq); + if (!ep->mpa_skb) { + PDBG("%s rdma_init wr_ack ep %p state %u\n", + __func__, ep, state_read(&ep->com)); + if (ep->mpa_attr.initiator) { + PDBG("%s initiator ep %p state %u\n", + __func__, ep, state_read(&ep->com)); + if (peer2peer) + iwch_post_zb_read(ep->com.qp); + } else { + PDBG("%s responder ep %p state %u\n", + __func__, ep, state_read(&ep->com)); + ep->com.rpl_done = 1; + wake_up(&ep->com.waitq); + } + } else { + PDBG("%s lsm ack ep %p state %u freeing skb\n", + __func__, ep, state_read(&ep->com)); + kfree_skb(ep->mpa_skb); + ep->mpa_skb = NULL; } return CPL_RET_BUF_DONE; } @@ -1083,8 +1117,11 @@ static int tx_ack(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) static int abort_rpl(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) { struct iwch_ep *ep = ctx; + unsigned long flags; + int release = 0; PDBG("%s ep %p\n", __func__, ep); + BUG_ON(!ep); /* * We get 2 abort replies from the HW. The first one must @@ -1095,9 +1132,22 @@ static int abort_rpl(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) return CPL_RET_BUF_DONE; } - close_complete_upcall(ep); - state_set(&ep->com, DEAD); - release_ep_resources(ep); + spin_lock_irqsave(&ep->com.lock, flags); + switch (ep->com.state) { + case ABORTING: + close_complete_upcall(ep); + __state_set(&ep->com, DEAD); + release = 1; + break; + default: + printk(KERN_ERR "%s ep %p state %d\n", + __func__, ep, ep->com.state); + break; + } + spin_unlock_irqrestore(&ep->com.lock, flags); + + if (release) + release_ep_resources(ep); return CPL_RET_BUF_DONE; } @@ -1470,7 +1520,8 @@ static int peer_abort(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) struct sk_buff *rpl_skb; struct iwch_qp_attributes attrs; int ret; - int state; + int release = 0; + unsigned long flags; if (is_neg_adv_abort(req->status)) { PDBG("%s neg_adv_abort ep %p tid %d\n", __func__, ep, @@ -1488,9 +1539,9 @@ static int peer_abort(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) return CPL_RET_BUF_DONE; } - state = state_read(&ep->com); - PDBG("%s ep %p state %u\n", __func__, ep, state); - switch (state) { + spin_lock_irqsave(&ep->com.lock, flags); + PDBG("%s ep %p state %u\n", __func__, ep, ep->com.state); + switch (ep->com.state) { case CONNECTING: break; case MPA_REQ_WAIT: @@ -1536,21 +1587,25 @@ static int peer_abort(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) break; case DEAD: PDBG("%s PEER_ABORT IN DEAD STATE!!!!\n", __func__); + spin_unlock_irqrestore(&ep->com.lock, flags); return CPL_RET_BUF_DONE; default: BUG_ON(1); break; } dst_confirm(ep->dst); + if (ep->com.state != ABORTING) { + __state_set(&ep->com, DEAD); + release = 1; + } + spin_unlock_irqrestore(&ep->com.lock, flags); rpl_skb = get_skb(skb, sizeof(*rpl), GFP_KERNEL); if (!rpl_skb) { printk(KERN_ERR MOD "%s - cannot allocate skb!\n", __func__); - dst_release(ep->dst); - l2t_release(L2DATA(ep->com.tdev), ep->l2t); - put_ep(&ep->com); - return CPL_RET_BUF_DONE; + release = 1; + goto out; } rpl_skb->priority = CPL_PRIORITY_DATA; rpl = (struct cpl_abort_rpl *) skb_put(rpl_skb, sizeof(*rpl)); @@ -1559,10 +1614,9 @@ static int peer_abort(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) OPCODE_TID(rpl) = htonl(MK_OPCODE_TID(CPL_ABORT_RPL, ep->hwtid)); rpl->cmd = CPL_ABORT_NO_RST; cxgb3_ofld_send(ep->com.tdev, rpl_skb); - if (state != ABORTING) { - state_set(&ep->com, DEAD); +out: + if (release) release_ep_resources(ep); - } return CPL_RET_BUF_DONE; } @@ -1661,15 +1715,18 @@ static void ep_timeout(unsigned long arg) struct iwch_ep *ep = (struct iwch_ep *)arg; struct iwch_qp_attributes attrs; unsigned long flags; + int abort = 1; spin_lock_irqsave(&ep->com.lock, flags); PDBG("%s ep %p tid %u state %d\n", __func__, ep, ep->hwtid, ep->com.state); switch (ep->com.state) { case MPA_REQ_SENT: + __state_set(&ep->com, ABORTING); connect_reply_upcall(ep, -ETIMEDOUT); break; case MPA_REQ_WAIT: + __state_set(&ep->com, ABORTING); break; case CLOSING: case MORIBUND: @@ -1679,13 +1736,17 @@ static void ep_timeout(unsigned long arg) ep->com.qp, IWCH_QP_ATTR_NEXT_STATE, &attrs, 1); } + __state_set(&ep->com, ABORTING); break; default: - BUG(); + printk(KERN_ERR "%s unexpected state ep %p state %u\n", + __func__, ep, ep->com.state); + WARN_ON(1); + abort = 0; } - __state_set(&ep->com, CLOSING); spin_unlock_irqrestore(&ep->com.lock, flags); - abort_connection(ep, NULL, GFP_ATOMIC); + if (abort) + abort_connection(ep, NULL, GFP_ATOMIC); put_ep(&ep->com); } @@ -1762,16 +1823,19 @@ int iwch_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) if (err) goto err; + /* if needed, wait for wr_ack */ + if (iwch_rqes_posted(qp)) { + wait_event(ep->com.waitq, ep->com.rpl_done); + err = ep->com.rpl_err; + if (err) + goto err; + } + err = send_mpa_reply(ep, conn_param->private_data, conn_param->private_data_len); if (err) goto err; - /* wait for wr_ack */ - wait_event(ep->com.waitq, ep->com.rpl_done); - err = ep->com.rpl_err; - if (err) - goto err; state_set(&ep->com, FPDU_MODE); established_upcall(ep); @@ -1968,40 +2032,39 @@ int iwch_ep_disconnect(struct iwch_ep *ep, int abrupt, gfp_t gfp) PDBG("%s ep %p state %s, abrupt %d\n", __func__, ep, states[ep->com.state], abrupt); - if (ep->com.state == DEAD) { - PDBG("%s already dead ep %p\n", __func__, ep); - goto out; - } - - if (abrupt) { - if (ep->com.state != ABORTING) { - ep->com.state = ABORTING; - close = 1; - } - goto out; - } - switch (ep->com.state) { case MPA_REQ_WAIT: case MPA_REQ_SENT: case MPA_REQ_RCVD: case MPA_REP_SENT: case FPDU_MODE: - start_ep_timer(ep); - ep->com.state = CLOSING; close = 1; + if (abrupt) + ep->com.state = ABORTING; + else { + ep->com.state = CLOSING; + start_ep_timer(ep); + } break; case CLOSING: - ep->com.state = MORIBUND; close = 1; + if (abrupt) { + stop_ep_timer(ep); + ep->com.state = ABORTING; + } else + ep->com.state = MORIBUND; break; case MORIBUND: + case ABORTING: + case DEAD: + PDBG("%s ignoring disconnect ep %p state %u\n", + __func__, ep, ep->com.state); break; default: BUG(); break; } -out: + spin_unlock_irqrestore(&ep->com.lock, flags); if (close) { if (abrupt) diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.h b/drivers/infiniband/hw/cxgb3/iwch_cm.h index 2bb7fbdb3ff..d7c7e09f099 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_cm.h +++ b/drivers/infiniband/hw/cxgb3/iwch_cm.h @@ -56,6 +56,7 @@ #define put_ep(ep) { \ PDBG("put_ep (via %s:%u) ep %p refcnt %d\n", __func__, __LINE__, \ ep, atomic_read(&((ep)->kref.refcount))); \ + WARN_ON(atomic_read(&((ep)->kref.refcount)) < 1); \ kref_put(&((ep)->kref), __free_ep); \ } @@ -225,5 +226,6 @@ int iwch_ep_redirect(void *ctx, struct dst_entry *old, struct dst_entry *new, st int __init iwch_cm_init(void); void __exit iwch_cm_term(void); +extern int peer2peer; #endif /* _IWCH_CM_H_ */ diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c index ab4695c1dd5..d07d3a377b5 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_provider.c +++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c @@ -602,7 +602,7 @@ static struct ib_mr *iwch_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, if (!mhp) return ERR_PTR(-ENOMEM); - mhp->umem = ib_umem_get(pd->uobject->context, start, length, acc); + mhp->umem = ib_umem_get(pd->uobject->context, start, length, acc, 0); if (IS_ERR(mhp->umem)) { err = PTR_ERR(mhp->umem); kfree(mhp); @@ -998,7 +998,7 @@ static int iwch_query_device(struct ib_device *ibdev, props->device_cap_flags = dev->device_cap_flags; props->vendor_id = (u32)dev->rdev.rnic_info.pdev->vendor; props->vendor_part_id = (u32)dev->rdev.rnic_info.pdev->device; - props->max_mr_size = ~0ull; + props->max_mr_size = dev->attr.max_mr_size; props->max_qp = dev->attr.max_qps; props->max_qp_wr = dev->attr.max_wrs; props->max_sge = dev->attr.max_sge_per_wr; diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.h b/drivers/infiniband/hw/cxgb3/iwch_provider.h index 61356f91109..db5100d27ca 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_provider.h +++ b/drivers/infiniband/hw/cxgb3/iwch_provider.h @@ -118,6 +118,7 @@ enum IWCH_QP_FLAGS { }; struct iwch_mpa_attributes { + u8 initiator; u8 recv_marker_enabled; u8 xmit_marker_enabled; /* iWARP: enable inbound Read Resp. */ u8 crc_enabled; @@ -322,6 +323,7 @@ enum iwch_qp_query_flags { IWCH_QP_QUERY_TEST_USERWRITE = 0x32 /* Test special */ }; +u16 iwch_rqes_posted(struct iwch_qp *qhp); int iwch_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, struct ib_send_wr **bad_wr); int iwch_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr, @@ -331,6 +333,7 @@ int iwch_bind_mw(struct ib_qp *qp, struct ib_mw_bind *mw_bind); int iwch_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc); int iwch_post_terminate(struct iwch_qp *qhp, struct respQ_msg_t *rsp_msg); +int iwch_post_zb_read(struct iwch_qp *qhp); int iwch_register_device(struct iwch_dev *dev); void iwch_unregister_device(struct iwch_dev *dev); int iwch_quiesce_qps(struct iwch_cq *chp); diff --git a/drivers/infiniband/hw/cxgb3/iwch_qp.c b/drivers/infiniband/hw/cxgb3/iwch_qp.c index 8891c3b0a3d..9b4be889c58 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_qp.c +++ b/drivers/infiniband/hw/cxgb3/iwch_qp.c @@ -586,6 +586,36 @@ static inline void build_term_codes(struct respQ_msg_t *rsp_msg, } } +int iwch_post_zb_read(struct iwch_qp *qhp) +{ + union t3_wr *wqe; + struct sk_buff *skb; + u8 flit_cnt = sizeof(struct t3_rdma_read_wr) >> 3; + + PDBG("%s enter\n", __func__); + skb = alloc_skb(40, GFP_KERNEL); + if (!skb) { + printk(KERN_ERR "%s cannot send zb_read!!\n", __func__); + return -ENOMEM; + } + wqe = (union t3_wr *)skb_put(skb, sizeof(struct t3_rdma_read_wr)); + memset(wqe, 0, sizeof(struct t3_rdma_read_wr)); + wqe->read.rdmaop = T3_READ_REQ; + wqe->read.reserved[0] = 0; + wqe->read.reserved[1] = 0; + wqe->read.reserved[2] = 0; + wqe->read.rem_stag = cpu_to_be32(1); + wqe->read.rem_to = cpu_to_be64(1); + wqe->read.local_stag = cpu_to_be32(1); + wqe->read.local_len = cpu_to_be32(0); + wqe->read.local_to = cpu_to_be64(1); + wqe->send.wrh.op_seop_flags = cpu_to_be32(V_FW_RIWR_OP(T3_WR_READ)); + wqe->send.wrh.gen_tid_len = cpu_to_be32(V_FW_RIWR_TID(qhp->ep->hwtid)| + V_FW_RIWR_LEN(flit_cnt)); + skb->priority = CPL_PRIORITY_DATA; + return cxgb3_ofld_send(qhp->rhp->rdev.t3cdev_p, skb); +} + /* * This posts a TERMINATE with layer=RDMA, type=catastrophic. */ @@ -671,11 +701,18 @@ static void flush_qp(struct iwch_qp *qhp, unsigned long *flag) /* - * Return non zero if at least one RECV was pre-posted. + * Return count of RECV WRs posted */ -static int rqes_posted(struct iwch_qp *qhp) +u16 iwch_rqes_posted(struct iwch_qp *qhp) { - return fw_riwrh_opcode((struct fw_riwrh *)qhp->wq.queue) == T3_WR_RCV; + union t3_wr *wqe = qhp->wq.queue; + u16 count = 0; + while ((count+1) != 0 && fw_riwrh_opcode((struct fw_riwrh *)wqe) == T3_WR_RCV) { + count++; + wqe++; + } + PDBG("%s qhp %p count %u\n", __func__, qhp, count); + return count; } static int rdma_init(struct iwch_dev *rhp, struct iwch_qp *qhp, @@ -716,8 +753,17 @@ static int rdma_init(struct iwch_dev *rhp, struct iwch_qp *qhp, init_attr.ird = qhp->attr.max_ird; init_attr.qp_dma_addr = qhp->wq.dma_addr; init_attr.qp_dma_size = (1UL << qhp->wq.size_log2); - init_attr.flags = rqes_posted(qhp) ? RECVS_POSTED : 0; + init_attr.rqe_count = iwch_rqes_posted(qhp); + init_attr.flags = qhp->attr.mpa_attr.initiator ? MPA_INITIATOR : 0; init_attr.flags |= capable(CAP_NET_BIND_SERVICE) ? PRIV_QP : 0; + if (peer2peer) { + init_attr.rtr_type = RTR_READ; + if (init_attr.ord == 0 && qhp->attr.mpa_attr.initiator) + init_attr.ord = 1; + if (init_attr.ird == 0 && !qhp->attr.mpa_attr.initiator) + init_attr.ird = 1; + } else + init_attr.rtr_type = 0; init_attr.irs = qhp->ep->rcv_seq; PDBG("%s init_attr.rq_addr 0x%x init_attr.rq_size = %d " "flags 0x%x qpcaps 0x%x\n", __func__, @@ -832,6 +878,7 @@ int iwch_modify_qp(struct iwch_dev *rhp, struct iwch_qp *qhp, abort=0; disconnect = 1; ep = qhp->ep; + get_ep(&ep->com); } flush_qp(qhp, &flag); break; @@ -848,6 +895,7 @@ int iwch_modify_qp(struct iwch_dev *rhp, struct iwch_qp *qhp, abort=1; disconnect = 1; ep = qhp->ep; + get_ep(&ep->com); } goto err; break; @@ -929,8 +977,10 @@ out: * on the EP. This can be a normal close (RTS->CLOSING) or * an abnormal close (RTS/CLOSING->ERROR). */ - if (disconnect) + if (disconnect) { iwch_ep_disconnect(ep, abort, GFP_KERNEL); + put_ep(&ep->com); + } /* * If free is 1, then we've disassociated the EP from the QP diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h index 3d6d9461c31..00bab60f6de 100644 --- a/drivers/infiniband/hw/ehca/ehca_classes.h +++ b/drivers/infiniband/hw/ehca/ehca_classes.h @@ -66,6 +66,7 @@ struct ehca_av; #include "ehca_irq.h" #define EHCA_EQE_CACHE_SIZE 20 +#define EHCA_MAX_NUM_QUEUES 0xffff struct ehca_eqe_cache_entry { struct ehca_eqe *eqe; @@ -127,6 +128,8 @@ struct ehca_shca { /* MR pgsize: bit 0-3 means 4K, 64K, 1M, 16M respectively */ u32 hca_cap_mr_pgsize; int max_mtu; + atomic_t num_cqs; + atomic_t num_qps; }; struct ehca_pd { @@ -344,6 +347,8 @@ extern int ehca_use_hp_mr; extern int ehca_scaling_code; extern int ehca_lock_hcalls; extern int ehca_nr_ports; +extern int ehca_max_cq; +extern int ehca_max_qp; struct ipzu_queue_resp { u32 qe_size; /* queue entry size */ diff --git a/drivers/infiniband/hw/ehca/ehca_cq.c b/drivers/infiniband/hw/ehca/ehca_cq.c index ec0cfcf3073..5540b276a33 100644 --- a/drivers/infiniband/hw/ehca/ehca_cq.c +++ b/drivers/infiniband/hw/ehca/ehca_cq.c @@ -132,10 +132,19 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector, if (cqe >= 0xFFFFFFFF - 64 - additional_cqe) return ERR_PTR(-EINVAL); + if (!atomic_add_unless(&shca->num_cqs, 1, ehca_max_cq)) { + ehca_err(device, "Unable to create CQ, max number of %i " + "CQs reached.", ehca_max_cq); + ehca_err(device, "To increase the maximum number of CQs " + "use the number_of_cqs module parameter.\n"); + return ERR_PTR(-ENOSPC); + } + my_cq = kmem_cache_zalloc(cq_cache, GFP_KERNEL); if (!my_cq) { ehca_err(device, "Out of memory for ehca_cq struct device=%p", device); + atomic_dec(&shca->num_cqs); return ERR_PTR(-ENOMEM); } @@ -305,6 +314,7 @@ create_cq_exit2: create_cq_exit1: kmem_cache_free(cq_cache, my_cq); + atomic_dec(&shca->num_cqs); return cq; } @@ -359,6 +369,7 @@ int ehca_destroy_cq(struct ib_cq *cq) ipz_queue_dtor(NULL, &my_cq->ipz_queue); kmem_cache_free(cq_cache, my_cq); + atomic_dec(&shca->num_cqs); return 0; } diff --git a/drivers/infiniband/hw/ehca/ehca_eq.c b/drivers/infiniband/hw/ehca/ehca_eq.c index b4ac617a70e..49660dfa186 100644 --- a/drivers/infiniband/hw/ehca/ehca_eq.c +++ b/drivers/infiniband/hw/ehca/ehca_eq.c @@ -54,7 +54,8 @@ int ehca_create_eq(struct ehca_shca *shca, struct ehca_eq *eq, const enum ehca_eq_type type, const u32 length) { - u64 ret; + int ret; + u64 h_ret; u32 nr_pages; u32 i; void *vpage; @@ -73,15 +74,15 @@ int ehca_create_eq(struct ehca_shca *shca, return -EINVAL; } - ret = hipz_h_alloc_resource_eq(shca->ipz_hca_handle, - &eq->pf, - type, - length, - &eq->ipz_eq_handle, - &eq->length, - &nr_pages, &eq->ist); + h_ret = hipz_h_alloc_resource_eq(shca->ipz_hca_handle, + &eq->pf, + type, + length, + &eq->ipz_eq_handle, + &eq->length, + &nr_pages, &eq->ist); - if (ret != H_SUCCESS) { + if (h_ret != H_SUCCESS) { ehca_err(ib_dev, "Can't allocate EQ/NEQ. eq=%p", eq); return -EINVAL; } @@ -97,24 +98,22 @@ int ehca_create_eq(struct ehca_shca *shca, u64 rpage; vpage = ipz_qpageit_get_inc(&eq->ipz_queue); - if (!vpage) { - ret = H_RESOURCE; + if (!vpage) goto create_eq_exit2; - } rpage = virt_to_abs(vpage); - ret = hipz_h_register_rpage_eq(shca->ipz_hca_handle, - eq->ipz_eq_handle, - &eq->pf, - 0, 0, rpage, 1); + h_ret = hipz_h_register_rpage_eq(shca->ipz_hca_handle, + eq->ipz_eq_handle, + &eq->pf, + 0, 0, rpage, 1); if (i == (nr_pages - 1)) { /* last page */ vpage = ipz_qpageit_get_inc(&eq->ipz_queue); - if (ret != H_SUCCESS || vpage) + if (h_ret != H_SUCCESS || vpage) goto create_eq_exit2; } else { - if (ret != H_PAGE_REGISTERED || !vpage) + if (h_ret != H_PAGE_REGISTERED || !vpage) goto create_eq_exit2; } } diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c index 65048976198..482103eb6ea 100644 --- a/drivers/infiniband/hw/ehca/ehca_main.c +++ b/drivers/infiniband/hw/ehca/ehca_main.c @@ -68,6 +68,8 @@ int ehca_port_act_time = 30; int ehca_static_rate = -1; int ehca_scaling_code = 0; int ehca_lock_hcalls = -1; +int ehca_max_cq = -1; +int ehca_max_qp = -1; module_param_named(open_aqp1, ehca_open_aqp1, bool, S_IRUGO); module_param_named(debug_level, ehca_debug_level, int, S_IRUGO); @@ -79,6 +81,8 @@ module_param_named(poll_all_eqs, ehca_poll_all_eqs, bool, S_IRUGO); module_param_named(static_rate, ehca_static_rate, int, S_IRUGO); module_param_named(scaling_code, ehca_scaling_code, bool, S_IRUGO); module_param_named(lock_hcalls, ehca_lock_hcalls, bool, S_IRUGO); +module_param_named(number_of_cqs, ehca_max_cq, int, S_IRUGO); +module_param_named(number_of_qps, ehca_max_qp, int, S_IRUGO); MODULE_PARM_DESC(open_aqp1, "Open AQP1 on startup (default: no)"); @@ -104,6 +108,12 @@ MODULE_PARM_DESC(scaling_code, MODULE_PARM_DESC(lock_hcalls, "Serialize all hCalls made by the driver " "(default: autodetect)"); +MODULE_PARM_DESC(number_of_cqs, + "Max number of CQs which can be allocated " + "(default: autodetect)"); +MODULE_PARM_DESC(number_of_qps, + "Max number of QPs which can be allocated " + "(default: autodetect)"); DEFINE_RWLOCK(ehca_qp_idr_lock); DEFINE_RWLOCK(ehca_cq_idr_lock); @@ -355,6 +365,25 @@ static int ehca_sense_attributes(struct ehca_shca *shca) if (rblock->memory_page_size_supported & pgsize_map[i]) shca->hca_cap_mr_pgsize |= pgsize_map[i + 1]; + /* Set maximum number of CQs and QPs to calculate EQ size */ + if (ehca_max_qp == -1) + ehca_max_qp = min_t(int, rblock->max_qp, EHCA_MAX_NUM_QUEUES); + else if (ehca_max_qp < 1 || ehca_max_qp > rblock->max_qp) { + ehca_gen_err("Requested number of QPs is out of range (1 - %i) " + "specified by HW", rblock->max_qp); + ret = -EINVAL; + goto sense_attributes1; + } + + if (ehca_max_cq == -1) + ehca_max_cq = min_t(int, rblock->max_cq, EHCA_MAX_NUM_QUEUES); + else if (ehca_max_cq < 1 || ehca_max_cq > rblock->max_cq) { + ehca_gen_err("Requested number of CQs is out of range (1 - %i) " + "specified by HW", rblock->max_cq); + ret = -EINVAL; + goto sense_attributes1; + } + /* query max MTU from first port -- it's the same for all ports */ port = (struct hipz_query_port *)rblock; h_ret = hipz_h_query_port(shca->ipz_hca_handle, 1, port); @@ -684,7 +713,7 @@ static int __devinit ehca_probe(struct of_device *dev, struct ehca_shca *shca; const u64 *handle; struct ib_pd *ibpd; - int ret, i; + int ret, i, eq_size; handle = of_get_property(dev->node, "ibm,hca-handle", NULL); if (!handle) { @@ -705,6 +734,8 @@ static int __devinit ehca_probe(struct of_device *dev, return -ENOMEM; } mutex_init(&shca->modify_mutex); + atomic_set(&shca->num_cqs, 0); + atomic_set(&shca->num_qps, 0); for (i = 0; i < ARRAY_SIZE(shca->sport); i++) spin_lock_init(&shca->sport[i].mod_sqp_lock); @@ -724,8 +755,9 @@ static int __devinit ehca_probe(struct of_device *dev, goto probe1; } + eq_size = 2 * ehca_max_cq + 4 * ehca_max_qp; /* create event queues */ - ret = ehca_create_eq(shca, &shca->eq, EHCA_EQ, 2048); + ret = ehca_create_eq(shca, &shca->eq, EHCA_EQ, eq_size); if (ret) { ehca_err(&shca->ib_device, "Cannot create EQ."); goto probe1; diff --git a/drivers/infiniband/hw/ehca/ehca_mrmw.c b/drivers/infiniband/hw/ehca/ehca_mrmw.c index 46ae4eb2c4e..f974367cad4 100644 --- a/drivers/infiniband/hw/ehca/ehca_mrmw.c +++ b/drivers/infiniband/hw/ehca/ehca_mrmw.c @@ -323,7 +323,7 @@ struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, } e_mr->umem = ib_umem_get(pd->uobject->context, start, length, - mr_access_flags); + mr_access_flags, 0); if (IS_ERR(e_mr->umem)) { ib_mr = (void *)e_mr->umem; goto reg_user_mr_exit1; diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c index 57bef1152cc..18fba92fa7a 100644 --- a/drivers/infiniband/hw/ehca/ehca_qp.c +++ b/drivers/infiniband/hw/ehca/ehca_qp.c @@ -421,8 +421,18 @@ static struct ehca_qp *internal_create_qp( u32 swqe_size = 0, rwqe_size = 0, ib_qp_num; unsigned long flags; - if (init_attr->create_flags) + if (!atomic_add_unless(&shca->num_qps, 1, ehca_max_qp)) { + ehca_err(pd->device, "Unable to create QP, max number of %i " + "QPs reached.", ehca_max_qp); + ehca_err(pd->device, "To increase the maximum number of QPs " + "use the number_of_qps module parameter.\n"); + return ERR_PTR(-ENOSPC); + } + + if (init_attr->create_flags) { + atomic_dec(&shca->num_qps); return ERR_PTR(-EINVAL); + } memset(&parms, 0, sizeof(parms)); qp_type = init_attr->qp_type; @@ -431,6 +441,7 @@ static struct ehca_qp *internal_create_qp( init_attr->sq_sig_type != IB_SIGNAL_ALL_WR) { ehca_err(pd->device, "init_attr->sg_sig_type=%x not allowed", init_attr->sq_sig_type); + atomic_dec(&shca->num_qps); return ERR_PTR(-EINVAL); } @@ -455,6 +466,7 @@ static struct ehca_qp *internal_create_qp( if (is_llqp && has_srq) { ehca_err(pd->device, "LLQPs can't have an SRQ"); + atomic_dec(&shca->num_qps); return ERR_PTR(-EINVAL); } @@ -466,6 +478,7 @@ static struct ehca_qp *internal_create_qp( ehca_err(pd->device, "no more than three SGEs " "supported for SRQ pd=%p max_sge=%x", pd, init_attr->cap.max_recv_sge); + atomic_dec(&shca->num_qps); return ERR_PTR(-EINVAL); } } @@ -477,6 +490,7 @@ static struct ehca_qp *internal_create_qp( qp_type != IB_QPT_SMI && qp_type != IB_QPT_GSI) { ehca_err(pd->device, "wrong QP Type=%x", qp_type); + atomic_dec(&shca->num_qps); return ERR_PTR(-EINVAL); } @@ -490,6 +504,7 @@ static struct ehca_qp *internal_create_qp( "or max_rq_wr=%x for RC LLQP", init_attr->cap.max_send_wr, init_attr->cap.max_recv_wr); + atomic_dec(&shca->num_qps); return ERR_PTR(-EINVAL); } break; @@ -497,6 +512,7 @@ static struct ehca_qp *internal_create_qp( if (!EHCA_BMASK_GET(HCA_CAP_UD_LL_QP, shca->hca_cap)) { ehca_err(pd->device, "UD LLQP not supported " "by this adapter"); + atomic_dec(&shca->num_qps); return ERR_PTR(-ENOSYS); } if (!(init_attr->cap.max_send_sge <= 5 @@ -508,20 +524,22 @@ static struct ehca_qp *internal_create_qp( "or max_recv_sge=%x for UD LLQP", init_attr->cap.max_send_sge, init_attr->cap.max_recv_sge); + atomic_dec(&shca->num_qps); return ERR_PTR(-EINVAL); } else if (init_attr->cap.max_send_wr > 255) { ehca_err(pd->device, "Invalid Number of " "max_send_wr=%x for UD QP_TYPE=%x", init_attr->cap.max_send_wr, qp_type); + atomic_dec(&shca->num_qps); return ERR_PTR(-EINVAL); } break; default: ehca_err(pd->device, "unsupported LL QP Type=%x", qp_type); + atomic_dec(&shca->num_qps); return ERR_PTR(-EINVAL); - break; } } else { int max_sge = (qp_type == IB_QPT_UD || qp_type == IB_QPT_SMI @@ -533,6 +551,7 @@ static struct ehca_qp *internal_create_qp( "send_sge=%x recv_sge=%x max_sge=%x", init_attr->cap.max_send_sge, init_attr->cap.max_recv_sge, max_sge); + atomic_dec(&shca->num_qps); return ERR_PTR(-EINVAL); } } @@ -543,6 +562,7 @@ static struct ehca_qp *internal_create_qp( my_qp = kmem_cache_zalloc(qp_cache, GFP_KERNEL); if (!my_qp) { ehca_err(pd->device, "pd=%p not enough memory to alloc qp", pd); + atomic_dec(&shca->num_qps); return ERR_PTR(-ENOMEM); } @@ -823,6 +843,7 @@ create_qp_exit1: create_qp_exit0: kmem_cache_free(qp_cache, my_qp); + atomic_dec(&shca->num_qps); return ERR_PTR(ret); } @@ -1948,6 +1969,7 @@ static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp, if (HAS_SQ(my_qp)) ipz_queue_dtor(my_pd, &my_qp->ipz_squeue); kmem_cache_free(qp_cache, my_qp); + atomic_dec(&shca->num_qps); return 0; } diff --git a/drivers/infiniband/hw/ipath/ipath_mr.c b/drivers/infiniband/hw/ipath/ipath_mr.c index db4ba92f79f..9d343b7c2f3 100644 --- a/drivers/infiniband/hw/ipath/ipath_mr.c +++ b/drivers/infiniband/hw/ipath/ipath_mr.c @@ -195,7 +195,8 @@ struct ib_mr *ipath_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, goto bail; } - umem = ib_umem_get(pd->uobject->context, start, length, mr_access_flags); + umem = ib_umem_get(pd->uobject->context, start, length, + mr_access_flags, 0); if (IS_ERR(umem)) return (void *) umem; diff --git a/drivers/infiniband/hw/mlx4/cq.c b/drivers/infiniband/hw/mlx4/cq.c index 5e570bb0bb6..2f199c5c4a7 100644 --- a/drivers/infiniband/hw/mlx4/cq.c +++ b/drivers/infiniband/hw/mlx4/cq.c @@ -137,7 +137,7 @@ static int mlx4_ib_get_cq_umem(struct mlx4_ib_dev *dev, struct ib_ucontext *cont int err; *umem = ib_umem_get(context, buf_addr, cqe * sizeof (struct mlx4_cqe), - IB_ACCESS_LOCAL_WRITE); + IB_ACCESS_LOCAL_WRITE, 1); if (IS_ERR(*umem)) return PTR_ERR(*umem); @@ -221,7 +221,7 @@ struct ib_cq *mlx4_ib_create_cq(struct ib_device *ibdev, int entries, int vector } err = mlx4_cq_alloc(dev->dev, entries, &cq->buf.mtt, uar, - cq->db.dma, &cq->mcq); + cq->db.dma, &cq->mcq, 0); if (err) goto err_dbmap; diff --git a/drivers/infiniband/hw/mlx4/doorbell.c b/drivers/infiniband/hw/mlx4/doorbell.c index 8e342cc9bae..8aee4233b38 100644 --- a/drivers/infiniband/hw/mlx4/doorbell.c +++ b/drivers/infiniband/hw/mlx4/doorbell.c @@ -63,7 +63,7 @@ int mlx4_ib_db_map_user(struct mlx4_ib_ucontext *context, unsigned long virt, page->user_virt = (virt & PAGE_MASK); page->refcnt = 0; page->umem = ib_umem_get(&context->ibucontext, virt & PAGE_MASK, - PAGE_SIZE, 0); + PAGE_SIZE, 0, 0); if (IS_ERR(page->umem)) { err = PTR_ERR(page->umem); kfree(page); diff --git a/drivers/infiniband/hw/mlx4/mr.c b/drivers/infiniband/hw/mlx4/mr.c index fe2c2e94a5f..68e92485fc7 100644 --- a/drivers/infiniband/hw/mlx4/mr.c +++ b/drivers/infiniband/hw/mlx4/mr.c @@ -132,7 +132,8 @@ struct ib_mr *mlx4_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, if (!mr) return ERR_PTR(-ENOMEM); - mr->umem = ib_umem_get(pd->uobject->context, start, length, access_flags); + mr->umem = ib_umem_get(pd->uobject->context, start, length, + access_flags, 0); if (IS_ERR(mr->umem)) { err = PTR_ERR(mr->umem); goto err_free; diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c index 80ea8b9e776..8e02ecfec18 100644 --- a/drivers/infiniband/hw/mlx4/qp.c +++ b/drivers/infiniband/hw/mlx4/qp.c @@ -482,7 +482,7 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd, goto err; qp->umem = ib_umem_get(pd->uobject->context, ucmd.buf_addr, - qp->buf_size, 0); + qp->buf_size, 0, 0); if (IS_ERR(qp->umem)) { err = PTR_ERR(qp->umem); goto err; diff --git a/drivers/infiniband/hw/mlx4/srq.c b/drivers/infiniband/hw/mlx4/srq.c index 204619702f9..12d6bc6f800 100644 --- a/drivers/infiniband/hw/mlx4/srq.c +++ b/drivers/infiniband/hw/mlx4/srq.c @@ -109,7 +109,7 @@ struct ib_srq *mlx4_ib_create_srq(struct ib_pd *pd, } srq->umem = ib_umem_get(pd->uobject->context, ucmd.buf_addr, - buf_size, 0); + buf_size, 0, 0); if (IS_ERR(srq->umem)) { err = PTR_ERR(srq->umem); goto err_srq; diff --git a/drivers/infiniband/hw/mthca/mthca_mr.c b/drivers/infiniband/hw/mthca/mthca_mr.c index 3538da16e3f..820205dec56 100644 --- a/drivers/infiniband/hw/mthca/mthca_mr.c +++ b/drivers/infiniband/hw/mthca/mthca_mr.c @@ -818,15 +818,9 @@ int mthca_arbel_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list, void mthca_tavor_fmr_unmap(struct mthca_dev *dev, struct mthca_fmr *fmr) { - u32 key; - if (!fmr->maps) return; - key = tavor_key_to_hw_index(fmr->ibmr.lkey); - key &= dev->limits.num_mpts - 1; - fmr->ibmr.lkey = fmr->ibmr.rkey = tavor_hw_index_to_key(key); - fmr->maps = 0; writeb(MTHCA_MPT_STATUS_SW, fmr->mem.tavor.mpt); @@ -834,16 +828,9 @@ void mthca_tavor_fmr_unmap(struct mthca_dev *dev, struct mthca_fmr *fmr) void mthca_arbel_fmr_unmap(struct mthca_dev *dev, struct mthca_fmr *fmr) { - u32 key; - if (!fmr->maps) return; - key = arbel_key_to_hw_index(fmr->ibmr.lkey); - key &= dev->limits.num_mpts - 1; - key = adjust_key(dev, key); - fmr->ibmr.lkey = fmr->ibmr.rkey = arbel_hw_index_to_key(key); - fmr->maps = 0; *(u8 *) fmr->mem.arbel.mpt = MTHCA_MPT_STATUS_SW; diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c index 696e1f30233..be34f99ca62 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.c +++ b/drivers/infiniband/hw/mthca/mthca_provider.c @@ -39,6 +39,8 @@ #include <rdma/ib_smi.h> #include <rdma/ib_umem.h> #include <rdma/ib_user_verbs.h> + +#include <linux/sched.h> #include <linux/mm.h> #include "mthca_dev.h" @@ -367,6 +369,8 @@ static struct ib_ucontext *mthca_alloc_ucontext(struct ib_device *ibdev, return ERR_PTR(-EFAULT); } + context->reg_mr_warned = 0; + return &context->ibucontext; } @@ -1006,17 +1010,31 @@ static struct ib_mr *mthca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, struct mthca_dev *dev = to_mdev(pd->device); struct ib_umem_chunk *chunk; struct mthca_mr *mr; + struct mthca_reg_mr ucmd; u64 *pages; int shift, n, len; int i, j, k; int err = 0; int write_mtt_size; + if (udata->inlen - sizeof (struct ib_uverbs_cmd_hdr) < sizeof ucmd) { + if (!to_mucontext(pd->uobject->context)->reg_mr_warned) { + mthca_warn(dev, "Process '%s' did not pass in MR attrs.\n", + current->comm); + mthca_warn(dev, " Update libmthca to fix this.\n"); + } + ++to_mucontext(pd->uobject->context)->reg_mr_warned; + ucmd.mr_attrs = 0; + } else if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd)) + return ERR_PTR(-EFAULT); + mr = kmalloc(sizeof *mr, GFP_KERNEL); if (!mr) return ERR_PTR(-ENOMEM); - mr->umem = ib_umem_get(pd->uobject->context, start, length, acc); + mr->umem = ib_umem_get(pd->uobject->context, start, length, acc, + ucmd.mr_attrs & MTHCA_MR_DMASYNC); + if (IS_ERR(mr->umem)) { err = PTR_ERR(mr->umem); goto err; diff --git a/drivers/infiniband/hw/mthca/mthca_provider.h b/drivers/infiniband/hw/mthca/mthca_provider.h index 262616c8ebb..934bf954403 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.h +++ b/drivers/infiniband/hw/mthca/mthca_provider.h @@ -67,6 +67,7 @@ struct mthca_ucontext { struct ib_ucontext ibucontext; struct mthca_uar uar; struct mthca_user_db_table *db_tab; + int reg_mr_warned; }; struct mthca_mtt; diff --git a/drivers/infiniband/hw/mthca/mthca_user.h b/drivers/infiniband/hw/mthca/mthca_user.h index 02cc0a766f3..e1262c942db 100644 --- a/drivers/infiniband/hw/mthca/mthca_user.h +++ b/drivers/infiniband/hw/mthca/mthca_user.h @@ -61,6 +61,16 @@ struct mthca_alloc_pd_resp { __u32 reserved; }; +struct mthca_reg_mr { +/* + * Mark the memory region with a DMA attribute that causes + * in-flight DMA to be flushed when the region is written to: + */ +#define MTHCA_MR_DMASYNC 0x1 + __u32 mr_attrs; + __u32 reserved; +}; + struct mthca_create_cq { __u32 lkey; __u32 pdn; diff --git a/drivers/infiniband/hw/nes/Kconfig b/drivers/infiniband/hw/nes/Kconfig index 2aeb7ac972a..d449eb6ec78 100644 --- a/drivers/infiniband/hw/nes/Kconfig +++ b/drivers/infiniband/hw/nes/Kconfig @@ -2,6 +2,7 @@ config INFINIBAND_NES tristate "NetEffect RNIC Driver" depends on PCI && INET && INFINIBAND select LIBCRC32C + select INET_LRO ---help--- This is a low-level driver for NetEffect RDMA enabled Network Interface Cards (RNIC). diff --git a/drivers/infiniband/hw/nes/nes.c b/drivers/infiniband/hw/nes/nes.c index a4e9269a29b..9f7364a9096 100644 --- a/drivers/infiniband/hw/nes/nes.c +++ b/drivers/infiniband/hw/nes/nes.c @@ -91,6 +91,10 @@ unsigned int nes_debug_level = 0; module_param_named(debug_level, nes_debug_level, uint, 0644); MODULE_PARM_DESC(debug_level, "Enable debug output level"); +unsigned int nes_lro_max_aggr = NES_LRO_MAX_AGGR; +module_param(nes_lro_max_aggr, int, NES_LRO_MAX_AGGR); +MODULE_PARM_DESC(nes_mro_max_aggr, " nic LRO MAX packet aggregation"); + LIST_HEAD(nes_adapter_list); static LIST_HEAD(nes_dev_list); diff --git a/drivers/infiniband/hw/nes/nes.h b/drivers/infiniband/hw/nes/nes.h index cdf2e9ad62f..1f9f7bf7386 100644 --- a/drivers/infiniband/hw/nes/nes.h +++ b/drivers/infiniband/hw/nes/nes.h @@ -173,6 +173,7 @@ extern int disable_mpa_crc; extern unsigned int send_first; extern unsigned int nes_drv_opt; extern unsigned int nes_debug_level; +extern unsigned int nes_lro_max_aggr; extern struct list_head nes_adapter_list; @@ -535,8 +536,8 @@ int nes_register_ofa_device(struct nes_ib_device *); int nes_read_eeprom_values(struct nes_device *, struct nes_adapter *); void nes_write_1G_phy_reg(struct nes_device *, u8, u8, u16); void nes_read_1G_phy_reg(struct nes_device *, u8, u8, u16 *); -void nes_write_10G_phy_reg(struct nes_device *, u16, u8, u16); -void nes_read_10G_phy_reg(struct nes_device *, u16, u8); +void nes_write_10G_phy_reg(struct nes_device *, u16, u8, u16, u16); +void nes_read_10G_phy_reg(struct nes_device *, u8, u8, u16); struct nes_cqp_request *nes_get_cqp_request(struct nes_device *); void nes_post_cqp_request(struct nes_device *, struct nes_cqp_request *, int); int nes_arp_table(struct nes_device *, u32, u8 *, u32); diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c index d940fc27129..9a4b40fae40 100644 --- a/drivers/infiniband/hw/nes/nes_cm.c +++ b/drivers/infiniband/hw/nes/nes_cm.c @@ -594,7 +594,7 @@ static void nes_cm_timer_tick(unsigned long pass) continue; } /* this seems like the correct place, but leave send entry unprotected */ - // spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags); + /* spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags); */ atomic_inc(&send_entry->skb->users); cm_packets_retrans++; nes_debug(NES_DBG_CM, "Retransmitting send_entry %p for node %p," @@ -1335,7 +1335,7 @@ static int process_packet(struct nes_cm_node *cm_node, struct sk_buff *skb, cm_node->loc_addr, cm_node->loc_port, cm_node->rem_addr, cm_node->rem_port, cm_node->state, atomic_read(&cm_node->ref_count)); - // create event + /* create event */ cm_node->state = NES_CM_STATE_CLOSED; create_event(cm_node, NES_CM_EVENT_ABORTED); @@ -1669,7 +1669,7 @@ static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *cm_core, if (!cm_node) return NULL; - // set our node side to client (active) side + /* set our node side to client (active) side */ cm_node->tcp_cntxt.client = 1; cm_node->tcp_cntxt.rcv_wscale = NES_CM_DEFAULT_RCV_WND_SCALE; @@ -1694,7 +1694,7 @@ static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *cm_core, loopbackremotenode->mpa_frame_size = mpa_frame_size - sizeof(struct ietf_mpa_frame); - // we are done handling this state, set node to a TSA state + /* we are done handling this state, set node to a TSA state */ cm_node->state = NES_CM_STATE_TSA; cm_node->tcp_cntxt.rcv_nxt = loopbackremotenode->tcp_cntxt.loc_seq_num; loopbackremotenode->tcp_cntxt.rcv_nxt = cm_node->tcp_cntxt.loc_seq_num; diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c index 08964cc7e98..8dc70f9bad2 100644 --- a/drivers/infiniband/hw/nes/nes_hw.c +++ b/drivers/infiniband/hw/nes/nes_hw.c @@ -38,6 +38,7 @@ #include <linux/ip.h> #include <linux/tcp.h> #include <linux/if_vlan.h> +#include <linux/inet_lro.h> #include "nes.h" @@ -832,7 +833,7 @@ static void nes_init_csr_ne020(struct nes_device *nesdev, u8 hw_rev, u8 port_cou nes_write_indexed(nesdev, 0x00000900, 0x20000001); nes_write_indexed(nesdev, 0x000060C0, 0x0000028e); nes_write_indexed(nesdev, 0x000060C8, 0x00000020); - // + nes_write_indexed(nesdev, 0x000001EC, 0x7b2625a0); /* nes_write_indexed(nesdev, 0x000001EC, 0x5f2625a0); */ @@ -1207,11 +1208,16 @@ int nes_init_phy(struct nes_device *nesdev) { struct nes_adapter *nesadapter = nesdev->nesadapter; u32 counter = 0; + u32 sds_common_control0; u32 mac_index = nesdev->mac_index; - u32 tx_config; + u32 tx_config = 0; u16 phy_data; + u32 temp_phy_data = 0; + u32 temp_phy_data2 = 0; + u32 i = 0; - if (nesadapter->OneG_Mode) { + if ((nesadapter->OneG_Mode) && + (nesadapter->phy_type[mac_index] != NES_PHY_TYPE_PUMA_1G)) { nes_debug(NES_DBG_PHY, "1G PHY, mac_index = %d.\n", mac_index); if (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_1G) { printk(PFX "%s: Programming mdc config for 1G\n", __func__); @@ -1223,7 +1229,7 @@ int nes_init_phy(struct nes_device *nesdev) nes_read_1G_phy_reg(nesdev, 1, nesadapter->phy_index[mac_index], &phy_data); nes_debug(NES_DBG_PHY, "Phy data from register 1 phy address %u = 0x%X.\n", nesadapter->phy_index[mac_index], phy_data); - nes_write_1G_phy_reg(nesdev, 23, nesadapter->phy_index[mac_index], 0xb000); + nes_write_1G_phy_reg(nesdev, 23, nesadapter->phy_index[mac_index], 0xb000); /* Reset the PHY */ nes_write_1G_phy_reg(nesdev, 0, nesadapter->phy_index[mac_index], 0x8000); @@ -1277,12 +1283,126 @@ int nes_init_phy(struct nes_device *nesdev) nes_read_1G_phy_reg(nesdev, 0, nesadapter->phy_index[mac_index], &phy_data); nes_write_1G_phy_reg(nesdev, 0, nesadapter->phy_index[mac_index], phy_data | 0x0300); } else { - if (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_IRIS) { + if ((nesadapter->phy_type[mac_index] == NES_PHY_TYPE_IRIS) || + (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_ARGUS)) { /* setup 10G MDIO operation */ tx_config = nes_read_indexed(nesdev, NES_IDX_MAC_TX_CONFIG); tx_config |= 0x14; nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONFIG, tx_config); } + if ((nesadapter->phy_type[mac_index] == NES_PHY_TYPE_ARGUS)) { + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0xd7ee); + + temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); + mdelay(10); + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0xd7ee); + temp_phy_data2 = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); + + /* + * if firmware is already running (like from a + * driver un-load/load, don't do anything. + */ + if (temp_phy_data == temp_phy_data2) { + /* configure QT2505 AMCC PHY */ + nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0x0000, 0x8000); + nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xc300, 0x0000); + nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xc302, 0x0044); + nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xc318, 0x0052); + nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xc319, 0x0008); + nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xc31a, 0x0098); + nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0x0026, 0x0E00); + nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0x0027, 0x0000); + nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0x0028, 0xA528); + + /* + * remove micro from reset; chip boots from ROM, + * uploads EEPROM f/w image, uC executes f/w + */ + nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xc300, 0x0002); + + /* + * wait for heart beat to start to + * know loading is done + */ + counter = 0; + do { + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0xd7ee); + temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); + if (counter++ > 1000) { + nes_debug(NES_DBG_PHY, "AMCC PHY- breaking from heartbeat check <this is bad!!!> \n"); + break; + } + mdelay(100); + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0xd7ee); + temp_phy_data2 = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); + } while ((temp_phy_data2 == temp_phy_data)); + + /* + * wait for tracking to start to know + * f/w is good to go + */ + counter = 0; + do { + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0xd7fd); + temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); + if (counter++ > 1000) { + nes_debug(NES_DBG_PHY, "AMCC PHY- breaking from status check <this is bad!!!> \n"); + break; + } + mdelay(1000); + /* + * nes_debug(NES_DBG_PHY, "AMCC PHY- phy_status not ready yet = 0x%02X\n", + * temp_phy_data); + */ + } while (((temp_phy_data & 0xff) != 0x50) && ((temp_phy_data & 0xff) != 0x70)); + + /* set LOS Control invert RXLOSB_I_PADINV */ + nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xd003, 0x0000); + /* set LOS Control to mask of RXLOSB_I */ + nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xc314, 0x0042); + /* set LED1 to input mode (LED1 and LED2 share same LED) */ + nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xd006, 0x0007); + /* set LED2 to RX link_status and activity */ + nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xd007, 0x000A); + /* set LED3 to RX link_status */ + nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xd008, 0x0009); + + /* + * reset the res-calibration on t2 + * serdes; ensures it is stable after + * the amcc phy is stable + */ + + sds_common_control0 = nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0); + sds_common_control0 |= 0x1; + nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0, sds_common_control0); + + /* release the res-calibration reset */ + sds_common_control0 &= 0xfffffffe; + nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0, sds_common_control0); + + i = 0; + while (((nes_read32(nesdev->regs + NES_SOFTWARE_RESET) & 0x00000040) != 0x00000040) + && (i++ < 5000)) { + /* mdelay(1); */ + } + + /* + * wait for link train done before moving on, + * or will get an interupt storm + */ + counter = 0; + do { + temp_phy_data = nes_read_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 + + (0x200 * (nesdev->mac_index & 1))); + if (counter++ > 1000) { + nes_debug(NES_DBG_PHY, "AMCC PHY- breaking from link train wait <this is bad, link didnt train!!!>\n"); + break; + } + mdelay(1); + } while (((temp_phy_data & 0x0f1f0000) != 0x0f0f0000)); + } + } } return 0; } @@ -1375,6 +1495,25 @@ static void nes_rq_wqes_timeout(unsigned long parm) } +static int nes_lro_get_skb_hdr(struct sk_buff *skb, void **iphdr, + void **tcph, u64 *hdr_flags, void *priv) +{ + unsigned int ip_len; + struct iphdr *iph; + skb_reset_network_header(skb); + iph = ip_hdr(skb); + if (iph->protocol != IPPROTO_TCP) + return -1; + ip_len = ip_hdrlen(skb); + skb_set_transport_header(skb, ip_len); + *tcph = tcp_hdr(skb); + + *hdr_flags = LRO_IPV4 | LRO_TCP; + *iphdr = iph; + return 0; +} + + /** * nes_init_nic_qp */ @@ -1520,10 +1659,10 @@ int nes_init_nic_qp(struct nes_device *nesdev, struct net_device *netdev) } u64temp = (u64)nesvnic->nic.sq_pbase; - nic_context->context_words[NES_NIC_CTX_SQ_LOW_IDX] = cpu_to_le32((u32)u64temp); + nic_context->context_words[NES_NIC_CTX_SQ_LOW_IDX] = cpu_to_le32((u32)u64temp); nic_context->context_words[NES_NIC_CTX_SQ_HIGH_IDX] = cpu_to_le32((u32)(u64temp >> 32)); u64temp = (u64)nesvnic->nic.rq_pbase; - nic_context->context_words[NES_NIC_CTX_RQ_LOW_IDX] = cpu_to_le32((u32)u64temp); + nic_context->context_words[NES_NIC_CTX_RQ_LOW_IDX] = cpu_to_le32((u32)u64temp); nic_context->context_words[NES_NIC_CTX_RQ_HIGH_IDX] = cpu_to_le32((u32)(u64temp >> 32)); cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_CREATE_QP | @@ -1575,7 +1714,7 @@ int nes_init_nic_qp(struct nes_device *nesdev, struct net_device *netdev) nic_rqe = &nesvnic->nic.rq_vbase[counter]; nic_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_1_0_IDX] = cpu_to_le32(nesvnic->max_frame_size); nic_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_3_2_IDX] = 0; - nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX] = cpu_to_le32((u32)pmem); + nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX] = cpu_to_le32((u32)pmem); nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_HIGH_IDX] = cpu_to_le32((u32)((u64)pmem >> 32)); nesvnic->nic.rx_skb[counter] = skb; } @@ -1592,15 +1731,21 @@ int nes_init_nic_qp(struct nes_device *nesdev, struct net_device *netdev) nesvnic->rq_wqes_timer.function = nes_rq_wqes_timeout; nesvnic->rq_wqes_timer.data = (unsigned long)nesvnic; nes_debug(NES_DBG_INIT, "NAPI support Enabled\n"); - if (nesdev->nesadapter->et_use_adaptive_rx_coalesce) { nes_nic_init_timer(nesdev); if (netdev->mtu > 1500) jumbomode = 1; - nes_nic_init_timer_defaults(nesdev, jumbomode); - } - + nes_nic_init_timer_defaults(nesdev, jumbomode); + } + nesvnic->lro_mgr.max_aggr = NES_LRO_MAX_AGGR; + nesvnic->lro_mgr.max_desc = NES_MAX_LRO_DESCRIPTORS; + nesvnic->lro_mgr.lro_arr = nesvnic->lro_desc; + nesvnic->lro_mgr.get_skb_header = nes_lro_get_skb_hdr; + nesvnic->lro_mgr.features = LRO_F_NAPI | LRO_F_EXTRACT_VLAN_ID; + nesvnic->lro_mgr.dev = netdev; + nesvnic->lro_mgr.ip_summed = CHECKSUM_UNNECESSARY; + nesvnic->lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY; return 0; } @@ -1620,8 +1765,8 @@ void nes_destroy_nic_qp(struct nes_vnic *nesvnic) /* Free remaining NIC receive buffers */ while (nesvnic->nic.rq_head != nesvnic->nic.rq_tail) { - nic_rqe = &nesvnic->nic.rq_vbase[nesvnic->nic.rq_tail]; - wqe_frag = (u64)le32_to_cpu(nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX]); + nic_rqe = &nesvnic->nic.rq_vbase[nesvnic->nic.rq_tail]; + wqe_frag = (u64)le32_to_cpu(nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX]); wqe_frag |= ((u64)le32_to_cpu(nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_HIGH_IDX])) << 32; pci_unmap_single(nesdev->pcidev, (dma_addr_t)wqe_frag, nesvnic->max_frame_size, PCI_DMA_FROMDEVICE); @@ -1704,17 +1849,17 @@ int nes_napi_isr(struct nes_device *nesdev) /* iff NIC, process here, else wait for DPC */ if ((int_stat) && ((int_stat & 0x0000ff00) == int_stat)) { nesdev->napi_isr_ran = 0; - nes_write32(nesdev->regs+NES_INT_STAT, - (int_stat & - ~(NES_INT_INTF|NES_INT_TIMER|NES_INT_MAC0|NES_INT_MAC1|NES_INT_MAC2|NES_INT_MAC3))); + nes_write32(nesdev->regs + NES_INT_STAT, + (int_stat & + ~(NES_INT_INTF | NES_INT_TIMER | NES_INT_MAC0 | NES_INT_MAC1 | NES_INT_MAC2 | NES_INT_MAC3))); /* Process the CEQs */ nes_process_ceq(nesdev, &nesdev->nesadapter->ceq[nesdev->nic_ceq_index]); if (unlikely((((nesadapter->et_rx_coalesce_usecs_irq) && - (!nesadapter->et_use_adaptive_rx_coalesce)) || - ((nesadapter->et_use_adaptive_rx_coalesce) && - (nesdev->deepcq_count > nesadapter->et_pkt_rate_low)))) ) { + (!nesadapter->et_use_adaptive_rx_coalesce)) || + ((nesadapter->et_use_adaptive_rx_coalesce) && + (nesdev->deepcq_count > nesadapter->et_pkt_rate_low))))) { if ((nesdev->int_req & NES_INT_TIMER) == 0) { /* Enable Periodic timer interrupts */ nesdev->int_req |= NES_INT_TIMER; @@ -1792,12 +1937,12 @@ void nes_dpc(unsigned long param) } if (int_stat) { - if (int_stat & ~(NES_INT_INTF|NES_INT_TIMER|NES_INT_MAC0| - NES_INT_MAC1|NES_INT_MAC2|NES_INT_MAC3)) { + if (int_stat & ~(NES_INT_INTF | NES_INT_TIMER | NES_INT_MAC0| + NES_INT_MAC1|NES_INT_MAC2 | NES_INT_MAC3)) { /* Ack the interrupts */ nes_write32(nesdev->regs+NES_INT_STAT, - (int_stat & ~(NES_INT_INTF|NES_INT_TIMER|NES_INT_MAC0| - NES_INT_MAC1|NES_INT_MAC2|NES_INT_MAC3))); + (int_stat & ~(NES_INT_INTF | NES_INT_TIMER | NES_INT_MAC0| + NES_INT_MAC1 | NES_INT_MAC2 | NES_INT_MAC3))); } temp_int_stat = int_stat; @@ -1862,8 +2007,8 @@ void nes_dpc(unsigned long param) } } /* Don't use the interface interrupt bit stay in loop */ - int_stat &= ~NES_INT_INTF|NES_INT_TIMER|NES_INT_MAC0| - NES_INT_MAC1|NES_INT_MAC2|NES_INT_MAC3; + int_stat &= ~NES_INT_INTF | NES_INT_TIMER | NES_INT_MAC0 | + NES_INT_MAC1 | NES_INT_MAC2 | NES_INT_MAC3; } while ((int_stat != 0) && (loop_counter++ < MAX_DPC_ITERATIONS)); if (timer_ints == 1) { @@ -1874,9 +2019,9 @@ void nes_dpc(unsigned long param) nesdev->timer_only_int_count = 0; nesdev->int_req &= ~NES_INT_TIMER; nes_write32(nesdev->regs + NES_INTF_INT_MASK, ~(nesdev->intf_int_req)); - nes_write32(nesdev->regs+NES_INT_MASK, ~nesdev->int_req); + nes_write32(nesdev->regs + NES_INT_MASK, ~nesdev->int_req); } else { - nes_write32(nesdev->regs+NES_INT_MASK, 0x0000ffff|(~nesdev->int_req)); + nes_write32(nesdev->regs+NES_INT_MASK, 0x0000ffff | (~nesdev->int_req)); } } else { if (unlikely(nesadapter->et_use_adaptive_rx_coalesce)) @@ -1884,7 +2029,7 @@ void nes_dpc(unsigned long param) nes_nic_init_timer(nesdev); } nesdev->timer_only_int_count = 0; - nes_write32(nesdev->regs+NES_INT_MASK, 0x0000ffff|(~nesdev->int_req)); + nes_write32(nesdev->regs+NES_INT_MASK, 0x0000ffff | (~nesdev->int_req)); } } else { nesdev->timer_only_int_count = 0; @@ -1933,7 +2078,7 @@ static void nes_process_ceq(struct nes_device *nesdev, struct nes_hw_ceq *ceq) do { if (le32_to_cpu(ceq->ceq_vbase[head].ceqe_words[NES_CEQE_CQ_CTX_HIGH_IDX]) & NES_CEQE_VALID) { - u64temp = (((u64)(le32_to_cpu(ceq->ceq_vbase[head].ceqe_words[NES_CEQE_CQ_CTX_HIGH_IDX])))<<32) | + u64temp = (((u64)(le32_to_cpu(ceq->ceq_vbase[head].ceqe_words[NES_CEQE_CQ_CTX_HIGH_IDX]))) << 32) | ((u64)(le32_to_cpu(ceq->ceq_vbase[head].ceqe_words[NES_CEQE_CQ_CTX_LOW_IDX]))); u64temp <<= 1; cq = *((struct nes_hw_cq **)&u64temp); @@ -1961,7 +2106,7 @@ static void nes_process_ceq(struct nes_device *nesdev, struct nes_hw_ceq *ceq) */ static void nes_process_aeq(struct nes_device *nesdev, struct nes_hw_aeq *aeq) { -// u64 u64temp; + /* u64 u64temp; */ u32 head; u32 aeq_size; u32 aeqe_misc; @@ -1980,8 +2125,10 @@ static void nes_process_aeq(struct nes_device *nesdev, struct nes_hw_aeq *aeq) if (aeqe_misc & (NES_AEQE_QP|NES_AEQE_CQ)) { if (aeqe_cq_id >= NES_FIRST_QPN) { /* dealing with an accelerated QP related AE */ -// u64temp = (((u64)(le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_HIGH_IDX])))<<32) | -// ((u64)(le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_LOW_IDX]))); + /* + * u64temp = (((u64)(le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_HIGH_IDX]))) << 32) | + * ((u64)(le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_LOW_IDX]))); + */ nes_process_iwarp_aeqe(nesdev, (struct nes_hw_aeqe *)aeqe); } else { /* TODO: dealing with a CQP related AE */ @@ -2081,6 +2228,8 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number) u32 u32temp; u16 phy_data; u16 temp_phy_data; + u32 pcs_val = 0x0f0f0000; + u32 pcs_mask = 0x0f1f0000; spin_lock_irqsave(&nesadapter->phy_lock, flags); if (nesadapter->mac_sw_state[mac_number] != NES_MAC_SW_IDLE) { @@ -2144,13 +2293,30 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number) nes_debug(NES_DBG_PHY, "Eth SERDES Common Status: 0=0x%08X, 1=0x%08X\n", nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS0), nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS0+0x200)); - pcs_control_status = nes_read_indexed(nesdev, - NES_IDX_PHY_PCS_CONTROL_STATUS0 + ((mac_index&1)*0x200)); - pcs_control_status = nes_read_indexed(nesdev, - NES_IDX_PHY_PCS_CONTROL_STATUS0 + ((mac_index&1)*0x200)); + + if (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_PUMA_1G) { + switch (mac_index) { + case 1: + case 3: + pcs_control_status = nes_read_indexed(nesdev, + NES_IDX_PHY_PCS_CONTROL_STATUS0 + 0x200); + break; + default: + pcs_control_status = nes_read_indexed(nesdev, + NES_IDX_PHY_PCS_CONTROL_STATUS0); + break; + } + } else { + pcs_control_status = nes_read_indexed(nesdev, + NES_IDX_PHY_PCS_CONTROL_STATUS0 + ((mac_index & 1) * 0x200)); + pcs_control_status = nes_read_indexed(nesdev, + NES_IDX_PHY_PCS_CONTROL_STATUS0 + ((mac_index & 1) * 0x200)); + } + nes_debug(NES_DBG_PHY, "PCS PHY Control/Status%u: 0x%08X\n", mac_index, pcs_control_status); - if (nesadapter->OneG_Mode) { + if ((nesadapter->OneG_Mode) && + (nesadapter->phy_type[mac_index] != NES_PHY_TYPE_PUMA_1G)) { u32temp = 0x01010000; if (nesadapter->port_count > 2) { u32temp |= 0x02020000; @@ -2159,24 +2325,59 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number) phy_data = 0; nes_debug(NES_DBG_PHY, "PCS says the link is down\n"); } - } else if (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_IRIS) { - nes_read_10G_phy_reg(nesdev, 1, nesadapter->phy_index[mac_index]); - temp_phy_data = (u16)nes_read_indexed(nesdev, - NES_IDX_MAC_MDIO_CONTROL); - u32temp = 20; - do { - nes_read_10G_phy_reg(nesdev, 1, nesadapter->phy_index[mac_index]); - phy_data = (u16)nes_read_indexed(nesdev, - NES_IDX_MAC_MDIO_CONTROL); - if ((phy_data == temp_phy_data) || (!(--u32temp))) - break; - temp_phy_data = phy_data; - } while (1); - nes_debug(NES_DBG_PHY, "%s: Phy data = 0x%04X, link was %s.\n", - __func__, phy_data, nesadapter->mac_link_down ? "DOWN" : "UP"); - } else { - phy_data = (0x0f0f0000 == (pcs_control_status & 0x0f1f0000)) ? 4 : 0; + switch (nesadapter->phy_type[mac_index]) { + case NES_PHY_TYPE_IRIS: + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 1); + temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); + u32temp = 20; + do { + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 1); + phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); + if ((phy_data == temp_phy_data) || (!(--u32temp))) + break; + temp_phy_data = phy_data; + } while (1); + nes_debug(NES_DBG_PHY, "%s: Phy data = 0x%04X, link was %s.\n", + __func__, phy_data, nesadapter->mac_link_down[mac_index] ? "DOWN" : "UP"); + break; + + case NES_PHY_TYPE_ARGUS: + /* clear the alarms */ + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 4, 0x0008); + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 4, 0xc001); + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 4, 0xc002); + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 4, 0xc005); + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 4, 0xc006); + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 0x9003); + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 0x9004); + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 0x9005); + /* check link status */ + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 1); + temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); + u32temp = 100; + do { + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 1); + + phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); + if ((phy_data == temp_phy_data) || (!(--u32temp))) + break; + temp_phy_data = phy_data; + } while (1); + nes_debug(NES_DBG_PHY, "%s: Phy data = 0x%04X, link was %s.\n", + __func__, phy_data, nesadapter->mac_link_down ? "DOWN" : "UP"); + break; + + case NES_PHY_TYPE_PUMA_1G: + if (mac_index < 2) + pcs_val = pcs_mask = 0x01010000; + else + pcs_val = pcs_mask = 0x02020000; + /* fall through */ + default: + phy_data = (pcs_val == (pcs_control_status & pcs_mask)) ? 0x4 : 0x0; + break; + } } if (phy_data & 0x0004) { @@ -2185,8 +2386,8 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number) nes_debug(NES_DBG_PHY, "The Link is UP!!. linkup was %d\n", nesvnic->linkup); if (nesvnic->linkup == 0) { - printk(PFX "The Link is now up for port %u, netdev %p.\n", - mac_index, nesvnic->netdev); + printk(PFX "The Link is now up for port %s, netdev %p.\n", + nesvnic->netdev->name, nesvnic->netdev); if (netif_queue_stopped(nesvnic->netdev)) netif_start_queue(nesvnic->netdev); nesvnic->linkup = 1; @@ -2199,8 +2400,8 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number) nes_debug(NES_DBG_PHY, "The Link is Down!!. linkup was %d\n", nesvnic->linkup); if (nesvnic->linkup == 1) { - printk(PFX "The Link is now down for port %u, netdev %p.\n", - mac_index, nesvnic->netdev); + printk(PFX "The Link is now down for port %s, netdev %p.\n", + nesvnic->netdev->name, nesvnic->netdev); if (!(netif_queue_stopped(nesvnic->netdev))) netif_stop_queue(nesvnic->netdev); nesvnic->linkup = 0; @@ -2254,10 +2455,13 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq) u16 pkt_type; u16 rqes_processed = 0; u8 sq_cqes = 0; + u8 nes_use_lro = 0; head = cq->cq_head; cq_size = cq->cq_size; cq->cqes_pending = 1; + if (nesvnic->netdev->features & NETIF_F_LRO) + nes_use_lro = 1; do { if (le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_NIC_CQE_MISC_IDX]) & NES_NIC_CQE_VALID) { @@ -2272,8 +2476,10 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq) /* bump past the vlan tag */ wqe_fragment_length++; if (le16_to_cpu(wqe_fragment_length[wqe_fragment_index]) != 0) { - u64temp = (u64) le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_LOW_IDX+wqe_fragment_index*2]); - u64temp += ((u64)le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_HIGH_IDX+wqe_fragment_index*2]))<<32; + u64temp = (u64) le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_LOW_IDX + + wqe_fragment_index * 2]); + u64temp += ((u64)le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_HIGH_IDX + + wqe_fragment_index * 2])) << 32; bus_address = (dma_addr_t)u64temp; if (test_and_clear_bit(nesnic->sq_tail, nesnic->first_frag_overflow)) { pci_unmap_single(nesdev->pcidev, @@ -2283,8 +2489,10 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq) } for (; wqe_fragment_index < 5; wqe_fragment_index++) { if (wqe_fragment_length[wqe_fragment_index]) { - u64temp = le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_LOW_IDX+wqe_fragment_index*2]); - u64temp += ((u64)le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_HIGH_IDX+wqe_fragment_index*2]))<<32; + u64temp = le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_LOW_IDX + + wqe_fragment_index * 2]); + u64temp += ((u64)le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_HIGH_IDX + + wqe_fragment_index * 2])) <<32; bus_address = (dma_addr_t)u64temp; pci_unmap_page(nesdev->pcidev, bus_address, @@ -2331,7 +2539,7 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq) if (atomic_read(&nesvnic->rx_skbs_needed) > (nesvnic->nic.rq_size>>1)) { nes_write32(nesdev->regs+NES_CQE_ALLOC, cq->cq_number | (cqe_count << 16)); -// nesadapter->tune_timer.cq_count += cqe_count; + /* nesadapter->tune_timer.cq_count += cqe_count; */ nesdev->currcq_count += cqe_count; cqe_count = 0; nes_replenish_nic_rq(nesvnic); @@ -2379,9 +2587,16 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq) >> 16); nes_debug(NES_DBG_CQ, "%s: Reporting stripped VLAN packet. Tag = 0x%04X\n", nesvnic->netdev->name, vlan_tag); - nes_vlan_rx(rx_skb, nesvnic->vlan_grp, vlan_tag); + if (nes_use_lro) + lro_vlan_hwaccel_receive_skb(&nesvnic->lro_mgr, rx_skb, + nesvnic->vlan_grp, vlan_tag, NULL); + else + nes_vlan_rx(rx_skb, nesvnic->vlan_grp, vlan_tag); } else { - nes_netif_rx(rx_skb); + if (nes_use_lro) + lro_receive_skb(&nesvnic->lro_mgr, rx_skb, NULL); + else + nes_netif_rx(rx_skb); } } @@ -2399,7 +2614,7 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq) /* Replenish Nic CQ */ nes_write32(nesdev->regs+NES_CQE_ALLOC, cq->cq_number | (cqe_count << 16)); -// nesdev->nesadapter->tune_timer.cq_count += cqe_count; + /* nesdev->nesadapter->tune_timer.cq_count += cqe_count; */ nesdev->currcq_count += cqe_count; cqe_count = 0; } @@ -2413,26 +2628,27 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq) } while (1); + if (nes_use_lro) + lro_flush_all(&nesvnic->lro_mgr); if (sq_cqes) { barrier(); /* restart the queue if it had been stopped */ if (netif_queue_stopped(nesvnic->netdev)) netif_wake_queue(nesvnic->netdev); } - cq->cq_head = head; /* nes_debug(NES_DBG_CQ, "CQ%u Processed = %u cqes, new head = %u.\n", cq->cq_number, cqe_count, cq->cq_head); */ cq->cqe_allocs_pending = cqe_count; if (unlikely(nesadapter->et_use_adaptive_rx_coalesce)) { -// nesdev->nesadapter->tune_timer.cq_count += cqe_count; + /* nesdev->nesadapter->tune_timer.cq_count += cqe_count; */ nesdev->currcq_count += cqe_count; nes_nic_tune_timer(nesdev); } if (atomic_read(&nesvnic->rx_skbs_needed)) nes_replenish_nic_rq(nesvnic); - } +} /** @@ -2461,7 +2677,7 @@ static void nes_cqp_ce_handler(struct nes_device *nesdev, struct nes_hw_cq *cq) if (le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX]) & NES_CQE_VALID) { u64temp = (((u64)(le32_to_cpu(cq->cq_vbase[head]. - cqe_words[NES_CQE_COMP_COMP_CTX_HIGH_IDX])))<<32) | + cqe_words[NES_CQE_COMP_COMP_CTX_HIGH_IDX]))) << 32) | ((u64)(le32_to_cpu(cq->cq_vbase[head]. cqe_words[NES_CQE_COMP_COMP_CTX_LOW_IDX]))); cqp = *((struct nes_hw_cqp **)&u64temp); @@ -2478,7 +2694,7 @@ static void nes_cqp_ce_handler(struct nes_device *nesdev, struct nes_hw_cq *cq) } u64temp = (((u64)(le32_to_cpu(nesdev->cqp.sq_vbase[cqp->sq_tail]. - wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX])))<<32) | + wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX]))) << 32) | ((u64)(le32_to_cpu(nesdev->cqp.sq_vbase[cqp->sq_tail]. wqe_words[NES_CQP_WQE_COMP_SCRATCH_LOW_IDX]))); cqp_request = *((struct nes_cqp_request **)&u64temp); @@ -2515,7 +2731,7 @@ static void nes_cqp_ce_handler(struct nes_device *nesdev, struct nes_hw_cq *cq) } else { nes_debug(NES_DBG_CQP, "CQP request %p (opcode 0x%02X) freed.\n", cqp_request, - le32_to_cpu(cqp_request->cqp_wqe.wqe_words[NES_CQP_WQE_OPCODE_IDX])&0x3f); + le32_to_cpu(cqp_request->cqp_wqe.wqe_words[NES_CQP_WQE_OPCODE_IDX]) & 0x3f); if (cqp_request->dynamic) { kfree(cqp_request); } else { @@ -2529,7 +2745,7 @@ static void nes_cqp_ce_handler(struct nes_device *nesdev, struct nes_hw_cq *cq) } cq->cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX] = 0; - nes_write32(nesdev->regs+NES_CQE_ALLOC, cq->cq_number | (1 << 16)); + nes_write32(nesdev->regs + NES_CQE_ALLOC, cq->cq_number | (1 << 16)); if (++cqp->sq_tail >= cqp->sq_size) cqp->sq_tail = 0; @@ -2598,13 +2814,13 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, nes_debug(NES_DBG_AEQ, "\n"); aeq_info = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_MISC_IDX]); if ((NES_AEQE_INBOUND_RDMA&aeq_info) || (!(NES_AEQE_QP&aeq_info))) { - context = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_LOW_IDX]); + context = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_LOW_IDX]); context += ((u64)le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_HIGH_IDX])) << 32; } else { aeqe_context = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_LOW_IDX]); aeqe_context += ((u64)le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_HIGH_IDX])) << 32; context = (unsigned long)nesadapter->qp_table[le32_to_cpu( - aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX])-NES_FIRST_QPN]; + aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]) - NES_FIRST_QPN]; BUG_ON(!context); } @@ -2617,7 +2833,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]), aeqe, nes_tcp_state_str[tcp_state], nes_iwarp_state_str[iwarp_state]); - switch (async_event_id) { case NES_AEQE_AEID_LLP_FIN_RECEIVED: nesqp = *((struct nes_qp **)&context); @@ -3021,7 +3236,7 @@ void nes_manage_arp_cache(struct net_device *netdev, unsigned char *mac_addr, cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] |= cpu_to_le32(NES_CQP_ARP_VALID); cqp_wqe->wqe_words[NES_CQP_ARP_WQE_MAC_ADDR_LOW_IDX] = cpu_to_le32( (((u32)mac_addr[2]) << 24) | (((u32)mac_addr[3]) << 16) | - (((u32)mac_addr[4]) << 8) | (u32)mac_addr[5]); + (((u32)mac_addr[4]) << 8) | (u32)mac_addr[5]); cqp_wqe->wqe_words[NES_CQP_ARP_WQE_MAC_HIGH_IDX] = cpu_to_le32( (((u32)mac_addr[0]) << 16) | (u32)mac_addr[1]); } else { diff --git a/drivers/infiniband/hw/nes/nes_hw.h b/drivers/infiniband/hw/nes/nes_hw.h index 8f36e231bdf..745bf94f3f0 100644 --- a/drivers/infiniband/hw/nes/nes_hw.h +++ b/drivers/infiniband/hw/nes/nes_hw.h @@ -33,8 +33,12 @@ #ifndef __NES_HW_H #define __NES_HW_H -#define NES_PHY_TYPE_1G 2 -#define NES_PHY_TYPE_IRIS 3 +#include <linux/inet_lro.h> + +#define NES_PHY_TYPE_1G 2 +#define NES_PHY_TYPE_IRIS 3 +#define NES_PHY_TYPE_ARGUS 4 +#define NES_PHY_TYPE_PUMA_1G 5 #define NES_PHY_TYPE_PUMA_10G 6 #define NES_MULTICAST_PF_MAX 8 @@ -965,7 +969,7 @@ struct nes_arp_entry { #define NES_NIC_CQ_DOWNWARD_TREND 16 struct nes_hw_tune_timer { - //u16 cq_count; + /* u16 cq_count; */ u16 threshold_low; u16 threshold_target; u16 threshold_high; @@ -982,8 +986,10 @@ struct nes_hw_tune_timer { #define NES_TIMER_INT_LIMIT 2 #define NES_TIMER_INT_LIMIT_DYNAMIC 10 #define NES_TIMER_ENABLE_LIMIT 4 -#define NES_MAX_LINK_INTERRUPTS 128 -#define NES_MAX_LINK_CHECK 200 +#define NES_MAX_LINK_INTERRUPTS 128 +#define NES_MAX_LINK_CHECK 200 +#define NES_MAX_LRO_DESCRIPTORS 32 +#define NES_LRO_MAX_AGGR 64 struct nes_adapter { u64 fw_ver; @@ -1183,6 +1189,9 @@ struct nes_vnic { u8 of_device_registered; u8 rdma_enabled; u8 rx_checksum_disabled; + u32 lro_max_aggr; + struct net_lro_mgr lro_mgr; + struct net_lro_desc lro_desc[NES_MAX_LRO_DESCRIPTORS]; }; struct nes_ib_device { diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c index e5366b013c1..1b0938c8777 100644 --- a/drivers/infiniband/hw/nes/nes_nic.c +++ b/drivers/infiniband/hw/nes/nes_nic.c @@ -185,12 +185,13 @@ static int nes_netdev_open(struct net_device *netdev) nic_active |= nic_active_bit; nes_write_indexed(nesdev, NES_IDX_NIC_BROADCAST_ON, nic_active); - macaddr_high = ((u16)netdev->dev_addr[0]) << 8; + macaddr_high = ((u16)netdev->dev_addr[0]) << 8; macaddr_high += (u16)netdev->dev_addr[1]; - macaddr_low = ((u32)netdev->dev_addr[2]) << 24; - macaddr_low += ((u32)netdev->dev_addr[3]) << 16; - macaddr_low += ((u32)netdev->dev_addr[4]) << 8; - macaddr_low += (u32)netdev->dev_addr[5]; + + macaddr_low = ((u32)netdev->dev_addr[2]) << 24; + macaddr_low += ((u32)netdev->dev_addr[3]) << 16; + macaddr_low += ((u32)netdev->dev_addr[4]) << 8; + macaddr_low += (u32)netdev->dev_addr[5]; /* Program the various MAC regs */ for (i = 0; i < NES_MAX_PORT_COUNT; i++) { @@ -451,7 +452,7 @@ static int nes_netdev_start_xmit(struct sk_buff *skb, struct net_device *netdev) __le16 *wqe_fragment_length; u32 nr_frags; u32 original_first_length; -// u64 *wqe_fragment_address; + /* u64 *wqe_fragment_address; */ /* first fragment (0) is used by copy buffer */ u16 wqe_fragment_index=1; u16 hoffset; @@ -461,11 +462,12 @@ static int nes_netdev_start_xmit(struct sk_buff *skb, struct net_device *netdev) u32 old_head; u32 wqe_misc; - /* nes_debug(NES_DBG_NIC_TX, "%s Request to tx NIC packet length %u, headlen %u," - " (%u frags), tso_size=%u\n", - netdev->name, skb->len, skb_headlen(skb), - skb_shinfo(skb)->nr_frags, skb_is_gso(skb)); - */ + /* + * nes_debug(NES_DBG_NIC_TX, "%s Request to tx NIC packet length %u, headlen %u," + * " (%u frags), tso_size=%u\n", + * netdev->name, skb->len, skb_headlen(skb), + * skb_shinfo(skb)->nr_frags, skb_is_gso(skb)); + */ if (!netif_carrier_ok(netdev)) return NETDEV_TX_OK; @@ -795,12 +797,12 @@ static int nes_netdev_set_mac_address(struct net_device *netdev, void *p) memcpy(netdev->dev_addr, mac_addr->sa_data, netdev->addr_len); printk(PFX "%s: Address length = %d, Address = %s\n", __func__, netdev->addr_len, print_mac(mac, mac_addr->sa_data)); - macaddr_high = ((u16)netdev->dev_addr[0]) << 8; + macaddr_high = ((u16)netdev->dev_addr[0]) << 8; macaddr_high += (u16)netdev->dev_addr[1]; - macaddr_low = ((u32)netdev->dev_addr[2]) << 24; - macaddr_low += ((u32)netdev->dev_addr[3]) << 16; - macaddr_low += ((u32)netdev->dev_addr[4]) << 8; - macaddr_low += (u32)netdev->dev_addr[5]; + macaddr_low = ((u32)netdev->dev_addr[2]) << 24; + macaddr_low += ((u32)netdev->dev_addr[3]) << 16; + macaddr_low += ((u32)netdev->dev_addr[4]) << 8; + macaddr_low += (u32)netdev->dev_addr[5]; for (i = 0; i < NES_MAX_PORT_COUNT; i++) { if (nesvnic->qp_nic_index[i] == 0xf) { @@ -881,12 +883,12 @@ static void nes_netdev_set_multicast_list(struct net_device *netdev) print_mac(mac, multicast_addr->dmi_addr), perfect_filter_register_address+(mc_index * 8), mc_nic_index); - macaddr_high = ((u16)multicast_addr->dmi_addr[0]) << 8; + macaddr_high = ((u16)multicast_addr->dmi_addr[0]) << 8; macaddr_high += (u16)multicast_addr->dmi_addr[1]; - macaddr_low = ((u32)multicast_addr->dmi_addr[2]) << 24; - macaddr_low += ((u32)multicast_addr->dmi_addr[3]) << 16; - macaddr_low += ((u32)multicast_addr->dmi_addr[4]) << 8; - macaddr_low += (u32)multicast_addr->dmi_addr[5]; + macaddr_low = ((u32)multicast_addr->dmi_addr[2]) << 24; + macaddr_low += ((u32)multicast_addr->dmi_addr[3]) << 16; + macaddr_low += ((u32)multicast_addr->dmi_addr[4]) << 8; + macaddr_low += (u32)multicast_addr->dmi_addr[5]; nes_write_indexed(nesdev, perfect_filter_register_address+(mc_index * 8), macaddr_low); @@ -910,23 +912,23 @@ static void nes_netdev_set_multicast_list(struct net_device *netdev) /** * nes_netdev_change_mtu */ -static int nes_netdev_change_mtu(struct net_device *netdev, int new_mtu) +static int nes_netdev_change_mtu(struct net_device *netdev, int new_mtu) { struct nes_vnic *nesvnic = netdev_priv(netdev); - struct nes_device *nesdev = nesvnic->nesdev; - int ret = 0; - u8 jumbomode=0; + struct nes_device *nesdev = nesvnic->nesdev; + int ret = 0; + u8 jumbomode = 0; - if ((new_mtu < ETH_ZLEN) || (new_mtu > max_mtu)) + if ((new_mtu < ETH_ZLEN) || (new_mtu > max_mtu)) return -EINVAL; - netdev->mtu = new_mtu; + netdev->mtu = new_mtu; nesvnic->max_frame_size = new_mtu + VLAN_ETH_HLEN; if (netdev->mtu > 1500) { jumbomode=1; } - nes_nic_init_timer_defaults(nesdev, jumbomode); + nes_nic_init_timer_defaults(nesdev, jumbomode); if (netif_running(netdev)) { nes_netdev_stop(netdev); @@ -936,8 +938,7 @@ static int nes_netdev_change_mtu(struct net_device *netdev, int new_mtu) return ret; } -#define NES_ETHTOOL_STAT_COUNT 55 -static const char nes_ethtool_stringset[NES_ETHTOOL_STAT_COUNT][ETH_GSTRING_LEN] = { +static const char nes_ethtool_stringset[][ETH_GSTRING_LEN] = { "Link Change Interrupts", "Linearized SKBs", "T/GSO Requests", @@ -993,8 +994,12 @@ static const char nes_ethtool_stringset[NES_ETHTOOL_STAT_COUNT][ETH_GSTRING_LEN] "CQ Depth 32", "CQ Depth 128", "CQ Depth 256", + "LRO aggregated", + "LRO flushed", + "LRO no_desc", }; +#define NES_ETHTOOL_STAT_COUNT ARRAY_SIZE(nes_ethtool_stringset) /** * nes_netdev_get_rx_csum @@ -1189,6 +1194,9 @@ static void nes_netdev_get_ethtool_stats(struct net_device *netdev, target_stat_values[52] = int_mod_cq_depth_32; target_stat_values[53] = int_mod_cq_depth_128; target_stat_values[54] = int_mod_cq_depth_256; + target_stat_values[55] = nesvnic->lro_mgr.stats.aggregated; + target_stat_values[56] = nesvnic->lro_mgr.stats.flushed; + target_stat_values[57] = nesvnic->lro_mgr.stats.no_desc; } @@ -1219,14 +1227,14 @@ static int nes_netdev_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *et_coalesce) { struct nes_vnic *nesvnic = netdev_priv(netdev); - struct nes_device *nesdev = nesvnic->nesdev; + struct nes_device *nesdev = nesvnic->nesdev; struct nes_adapter *nesadapter = nesdev->nesadapter; struct nes_hw_tune_timer *shared_timer = &nesadapter->tune_timer; unsigned long flags; - spin_lock_irqsave(&nesadapter->periodic_timer_lock, flags); + spin_lock_irqsave(&nesadapter->periodic_timer_lock, flags); if (et_coalesce->rx_max_coalesced_frames_low) { - shared_timer->threshold_low = et_coalesce->rx_max_coalesced_frames_low; + shared_timer->threshold_low = et_coalesce->rx_max_coalesced_frames_low; } if (et_coalesce->rx_max_coalesced_frames_irq) { shared_timer->threshold_target = et_coalesce->rx_max_coalesced_frames_irq; @@ -1246,14 +1254,14 @@ static int nes_netdev_set_coalesce(struct net_device *netdev, nesadapter->et_rx_coalesce_usecs_irq = et_coalesce->rx_coalesce_usecs_irq; if (et_coalesce->use_adaptive_rx_coalesce) { nesadapter->et_use_adaptive_rx_coalesce = 1; - nesadapter->timer_int_limit = NES_TIMER_INT_LIMIT_DYNAMIC; + nesadapter->timer_int_limit = NES_TIMER_INT_LIMIT_DYNAMIC; nesadapter->et_rx_coalesce_usecs_irq = 0; if (et_coalesce->pkt_rate_low) { - nesadapter->et_pkt_rate_low = et_coalesce->pkt_rate_low; + nesadapter->et_pkt_rate_low = et_coalesce->pkt_rate_low; } } else { nesadapter->et_use_adaptive_rx_coalesce = 0; - nesadapter->timer_int_limit = NES_TIMER_INT_LIMIT; + nesadapter->timer_int_limit = NES_TIMER_INT_LIMIT; if (nesadapter->et_rx_coalesce_usecs_irq) { nes_write32(nesdev->regs+NES_PERIODIC_CONTROL, 0x80000000 | ((u32)(nesadapter->et_rx_coalesce_usecs_irq*8))); @@ -1270,28 +1278,28 @@ static int nes_netdev_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *et_coalesce) { struct nes_vnic *nesvnic = netdev_priv(netdev); - struct nes_device *nesdev = nesvnic->nesdev; + struct nes_device *nesdev = nesvnic->nesdev; struct nes_adapter *nesadapter = nesdev->nesadapter; struct ethtool_coalesce temp_et_coalesce; struct nes_hw_tune_timer *shared_timer = &nesadapter->tune_timer; unsigned long flags; memset(&temp_et_coalesce, 0, sizeof(temp_et_coalesce)); - temp_et_coalesce.rx_coalesce_usecs_irq = nesadapter->et_rx_coalesce_usecs_irq; - temp_et_coalesce.use_adaptive_rx_coalesce = nesadapter->et_use_adaptive_rx_coalesce; - temp_et_coalesce.rate_sample_interval = nesadapter->et_rate_sample_interval; + temp_et_coalesce.rx_coalesce_usecs_irq = nesadapter->et_rx_coalesce_usecs_irq; + temp_et_coalesce.use_adaptive_rx_coalesce = nesadapter->et_use_adaptive_rx_coalesce; + temp_et_coalesce.rate_sample_interval = nesadapter->et_rate_sample_interval; temp_et_coalesce.pkt_rate_low = nesadapter->et_pkt_rate_low; spin_lock_irqsave(&nesadapter->periodic_timer_lock, flags); - temp_et_coalesce.rx_max_coalesced_frames_low = shared_timer->threshold_low; - temp_et_coalesce.rx_max_coalesced_frames_irq = shared_timer->threshold_target; + temp_et_coalesce.rx_max_coalesced_frames_low = shared_timer->threshold_low; + temp_et_coalesce.rx_max_coalesced_frames_irq = shared_timer->threshold_target; temp_et_coalesce.rx_max_coalesced_frames_high = shared_timer->threshold_high; - temp_et_coalesce.rx_coalesce_usecs_low = shared_timer->timer_in_use_min; + temp_et_coalesce.rx_coalesce_usecs_low = shared_timer->timer_in_use_min; temp_et_coalesce.rx_coalesce_usecs_high = shared_timer->timer_in_use_max; if (nesadapter->et_use_adaptive_rx_coalesce) { temp_et_coalesce.rx_coalesce_usecs_irq = shared_timer->timer_in_use; } spin_unlock_irqrestore(&nesadapter->periodic_timer_lock, flags); - memcpy(et_coalesce, &temp_et_coalesce, sizeof(*et_coalesce)); + memcpy(et_coalesce, &temp_et_coalesce, sizeof(*et_coalesce)); return 0; } @@ -1370,30 +1378,38 @@ static int nes_netdev_get_settings(struct net_device *netdev, struct ethtool_cmd u16 phy_data; et_cmd->duplex = DUPLEX_FULL; - et_cmd->port = PORT_MII; + et_cmd->port = PORT_MII; + if (nesadapter->OneG_Mode) { - et_cmd->supported = SUPPORTED_1000baseT_Full|SUPPORTED_Autoneg; - et_cmd->advertising = ADVERTISED_1000baseT_Full|ADVERTISED_Autoneg; et_cmd->speed = SPEED_1000; - nes_read_1G_phy_reg(nesdev, 0, nesadapter->phy_index[nesdev->mac_index], - &phy_data); - if (phy_data&0x1000) { - et_cmd->autoneg = AUTONEG_ENABLE; + if (nesadapter->phy_type[nesdev->mac_index] == NES_PHY_TYPE_PUMA_1G) { + et_cmd->supported = SUPPORTED_1000baseT_Full; + et_cmd->advertising = ADVERTISED_1000baseT_Full; + et_cmd->autoneg = AUTONEG_DISABLE; + et_cmd->transceiver = XCVR_INTERNAL; + et_cmd->phy_address = nesdev->mac_index; } else { - et_cmd->autoneg = AUTONEG_DISABLE; + et_cmd->supported = SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg; + et_cmd->advertising = ADVERTISED_1000baseT_Full | ADVERTISED_Autoneg; + nes_read_1G_phy_reg(nesdev, 0, nesadapter->phy_index[nesdev->mac_index], &phy_data); + if (phy_data & 0x1000) + et_cmd->autoneg = AUTONEG_ENABLE; + else + et_cmd->autoneg = AUTONEG_DISABLE; + et_cmd->transceiver = XCVR_EXTERNAL; + et_cmd->phy_address = nesadapter->phy_index[nesdev->mac_index]; } - et_cmd->transceiver = XCVR_EXTERNAL; - et_cmd->phy_address = nesadapter->phy_index[nesdev->mac_index]; } else { - if (nesadapter->phy_type[nesvnic->logical_port] == NES_PHY_TYPE_IRIS) { + if ((nesadapter->phy_type[nesdev->mac_index] == NES_PHY_TYPE_IRIS) || + (nesadapter->phy_type[nesdev->mac_index] == NES_PHY_TYPE_ARGUS)) { et_cmd->transceiver = XCVR_EXTERNAL; - et_cmd->port = PORT_FIBRE; - et_cmd->supported = SUPPORTED_FIBRE; + et_cmd->port = PORT_FIBRE; + et_cmd->supported = SUPPORTED_FIBRE; et_cmd->advertising = ADVERTISED_FIBRE; et_cmd->phy_address = nesadapter->phy_index[nesdev->mac_index]; } else { et_cmd->transceiver = XCVR_INTERNAL; - et_cmd->supported = SUPPORTED_10000baseT_Full; + et_cmd->supported = SUPPORTED_10000baseT_Full; et_cmd->advertising = ADVERTISED_10000baseT_Full; et_cmd->phy_address = nesdev->mac_index; } @@ -1416,14 +1432,15 @@ static int nes_netdev_set_settings(struct net_device *netdev, struct ethtool_cmd struct nes_adapter *nesadapter = nesdev->nesadapter; u16 phy_data; - if (nesadapter->OneG_Mode) { + if ((nesadapter->OneG_Mode) && + (nesadapter->phy_type[nesdev->mac_index] != NES_PHY_TYPE_PUMA_1G)) { nes_read_1G_phy_reg(nesdev, 0, nesadapter->phy_index[nesdev->mac_index], &phy_data); if (et_cmd->autoneg) { /* Turn on Full duplex, Autoneg, and restart autonegotiation */ phy_data |= 0x1300; } else { - // Turn off autoneg + /* Turn off autoneg */ phy_data &= ~0x1000; } nes_write_1G_phy_reg(nesdev, 0, nesadapter->phy_index[nesdev->mac_index], @@ -1454,6 +1471,8 @@ static struct ethtool_ops nes_ethtool_ops = { .set_sg = ethtool_op_set_sg, .get_tso = ethtool_op_get_tso, .set_tso = ethtool_op_set_tso, + .get_flags = ethtool_op_get_flags, + .set_flags = ethtool_op_set_flags, }; @@ -1607,27 +1626,34 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev, list_add_tail(&nesvnic->list, &nesdev->nesadapter->nesvnic_list[nesdev->mac_index]); if ((nesdev->netdev_count == 0) && - (PCI_FUNC(nesdev->pcidev->devfn) == nesdev->mac_index)) { - nes_debug(NES_DBG_INIT, "Setting up PHY interrupt mask. Using register index 0x%04X\n", - NES_IDX_PHY_PCS_CONTROL_STATUS0+(0x200*(nesvnic->logical_port&1))); + ((PCI_FUNC(nesdev->pcidev->devfn) == nesdev->mac_index) || + ((nesdev->nesadapter->phy_type[nesdev->mac_index] == NES_PHY_TYPE_PUMA_1G) && + (((PCI_FUNC(nesdev->pcidev->devfn) == 1) && (nesdev->mac_index == 2)) || + ((PCI_FUNC(nesdev->pcidev->devfn) == 2) && (nesdev->mac_index == 1)))))) { + /* + * nes_debug(NES_DBG_INIT, "Setting up PHY interrupt mask. Using register index 0x%04X\n", + * NES_IDX_PHY_PCS_CONTROL_STATUS0 + (0x200 * (nesvnic->logical_port & 1))); + */ u32temp = nes_read_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 + - (0x200*(nesvnic->logical_port&1))); - u32temp |= 0x00200000; - nes_write_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 + - (0x200*(nesvnic->logical_port&1)), u32temp); + (0x200 * (nesdev->mac_index & 1))); + if (nesdev->nesadapter->phy_type[nesdev->mac_index] != NES_PHY_TYPE_PUMA_1G) { + u32temp |= 0x00200000; + nes_write_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 + + (0x200 * (nesdev->mac_index & 1)), u32temp); + } + u32temp = nes_read_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 + - (0x200*(nesvnic->logical_port&1)) ); + (0x200 * (nesdev->mac_index & 1))); + if ((u32temp&0x0f1f0000) == 0x0f0f0000) { - if (nesdev->nesadapter->phy_type[nesvnic->logical_port] == NES_PHY_TYPE_IRIS) { + if (nesdev->nesadapter->phy_type[nesdev->mac_index] == NES_PHY_TYPE_IRIS) { nes_init_phy(nesdev); - nes_read_10G_phy_reg(nesdev, 1, - nesdev->nesadapter->phy_index[nesvnic->logical_port]); + nes_read_10G_phy_reg(nesdev, nesdev->nesadapter->phy_index[nesdev->mac_index], 1, 1); temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); u32temp = 20; do { - nes_read_10G_phy_reg(nesdev, 1, - nesdev->nesadapter->phy_index[nesvnic->logical_port]); + nes_read_10G_phy_reg(nesdev, nesdev->nesadapter->phy_index[nesdev->mac_index], 1, 1); phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); if ((phy_data == temp_phy_data) || (!(--u32temp))) @@ -1644,6 +1670,14 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev, nes_debug(NES_DBG_INIT, "The Link is UP!!.\n"); nesvnic->linkup = 1; } + } else if (nesdev->nesadapter->phy_type[nesdev->mac_index] == NES_PHY_TYPE_PUMA_1G) { + nes_debug(NES_DBG_INIT, "mac_index=%d, logical_port=%d, u32temp=0x%04X, PCI_FUNC=%d\n", + nesdev->mac_index, nesvnic->logical_port, u32temp, PCI_FUNC(nesdev->pcidev->devfn)); + if (((nesdev->mac_index < 2) && ((u32temp&0x01010000) == 0x01010000)) || + ((nesdev->mac_index > 1) && ((u32temp&0x02020000) == 0x02020000))) { + nes_debug(NES_DBG_INIT, "The Link is UP!!.\n"); + nesvnic->linkup = 1; + } } /* clear the MAC interrupt status, assumes direct logical to physical mapping */ u32temp = nes_read_indexed(nesdev, NES_IDX_MAC_INT_STATUS + (0x200 * nesdev->mac_index)); diff --git a/drivers/infiniband/hw/nes/nes_utils.c b/drivers/infiniband/hw/nes/nes_utils.c index c6d5631a699..fe83d1b2b17 100644 --- a/drivers/infiniband/hw/nes/nes_utils.c +++ b/drivers/infiniband/hw/nes/nes_utils.c @@ -444,15 +444,13 @@ void nes_read_1G_phy_reg(struct nes_device *nesdev, u8 phy_reg, u8 phy_addr, u16 /** * nes_write_10G_phy_reg */ -void nes_write_10G_phy_reg(struct nes_device *nesdev, u16 phy_reg, - u8 phy_addr, u16 data) +void nes_write_10G_phy_reg(struct nes_device *nesdev, u16 phy_addr, u8 dev_addr, u16 phy_reg, + u16 data) { - u32 dev_addr; u32 port_addr; u32 u32temp; u32 counter; - dev_addr = 1; port_addr = phy_addr; /* set address */ @@ -492,14 +490,12 @@ void nes_write_10G_phy_reg(struct nes_device *nesdev, u16 phy_reg, * This routine only issues the read, the data must be read * separately. */ -void nes_read_10G_phy_reg(struct nes_device *nesdev, u16 phy_reg, u8 phy_addr) +void nes_read_10G_phy_reg(struct nes_device *nesdev, u8 phy_addr, u8 dev_addr, u16 phy_reg) { - u32 dev_addr; u32 port_addr; u32 u32temp; u32 counter; - dev_addr = 1; port_addr = phy_addr; /* set address */ diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c index ee74f7c7a6d..99b3c4ae86e 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.c +++ b/drivers/infiniband/hw/nes/nes_verbs.c @@ -1266,7 +1266,7 @@ static struct ib_qp *nes_create_qp(struct ib_pd *ibpd, sq_size = init_attr->cap.max_send_wr; rq_size = init_attr->cap.max_recv_wr; - // check if the encoded sizes are OK or not... + /* check if the encoded sizes are OK or not... */ sq_encoded_size = nes_get_encoded_size(&sq_size); rq_encoded_size = nes_get_encoded_size(&rq_size); @@ -2377,7 +2377,7 @@ static struct ib_mr *nes_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, u8 single_page = 1; u8 stag_key; - region = ib_umem_get(pd->uobject->context, start, length, acc); + region = ib_umem_get(pd->uobject->context, start, length, acc, 0); if (IS_ERR(region)) { return (struct ib_mr *)region; } diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h index f1f142dc64b..9044f880353 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/drivers/infiniband/ulp/ipoib/ipoib.h @@ -95,6 +95,8 @@ enum { IPOIB_MCAST_FLAG_SENDONLY = 1, IPOIB_MCAST_FLAG_BUSY = 2, /* joining or already joined */ IPOIB_MCAST_FLAG_ATTACHED = 3, + + MAX_SEND_CQE = 16, }; #define IPOIB_OP_RECV (1ul << 31) @@ -285,7 +287,8 @@ struct ipoib_dev_priv { u16 pkey_index; struct ib_pd *pd; struct ib_mr *mr; - struct ib_cq *cq; + struct ib_cq *recv_cq; + struct ib_cq *send_cq; struct ib_qp *qp; u32 qkey; @@ -305,6 +308,7 @@ struct ipoib_dev_priv { struct ib_sge tx_sge[MAX_SKB_FRAGS + 1]; struct ib_send_wr tx_wr; unsigned tx_outstanding; + struct ib_wc send_wc[MAX_SEND_CQE]; struct ib_recv_wr rx_wr; struct ib_sge rx_sge[IPOIB_UD_RX_SG]; @@ -662,7 +666,6 @@ static inline int ipoib_register_debugfs(void) { return 0; } static inline void ipoib_unregister_debugfs(void) { } #endif - #define ipoib_printk(level, priv, format, arg...) \ printk(level "%s: " format, ((struct ipoib_dev_priv *) priv)->dev->name , ## arg) #define ipoib_warn(priv, format, arg...) \ diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index 9db7b0bd913..97e67d36378 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -249,8 +249,8 @@ static struct ib_qp *ipoib_cm_create_rx_qp(struct net_device *dev, struct ipoib_dev_priv *priv = netdev_priv(dev); struct ib_qp_init_attr attr = { .event_handler = ipoib_cm_rx_event_handler, - .send_cq = priv->cq, /* For drain WR */ - .recv_cq = priv->cq, + .send_cq = priv->recv_cq, /* For drain WR */ + .recv_cq = priv->recv_cq, .srq = priv->cm.srq, .cap.max_send_wr = 1, /* For drain WR */ .cap.max_send_sge = 1, /* FIXME: 0 Seems not to work */ @@ -951,8 +951,8 @@ static struct ib_qp *ipoib_cm_create_tx_qp(struct net_device *dev, struct ipoib_ { struct ipoib_dev_priv *priv = netdev_priv(dev); struct ib_qp_init_attr attr = { - .send_cq = priv->cq, - .recv_cq = priv->cq, + .send_cq = priv->recv_cq, + .recv_cq = priv->recv_cq, .srq = priv->cm.srq, .cap.max_send_wr = ipoib_sendq_size, .cap.max_send_sge = 1, diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c b/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c index 9a47428366c..10279b79c44 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c @@ -71,7 +71,7 @@ static int ipoib_set_coalesce(struct net_device *dev, coal->rx_max_coalesced_frames > 0xffff) return -EINVAL; - ret = ib_modify_cq(priv->cq, coal->rx_max_coalesced_frames, + ret = ib_modify_cq(priv->recv_cq, coal->rx_max_coalesced_frames, coal->rx_coalesce_usecs); if (ret && ret != -ENOSYS) { ipoib_warn(priv, "failed modifying CQ (%d)\n", ret); diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index 7cf1fa7074a..97b815c1a3f 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -364,7 +364,6 @@ static void ipoib_ib_handle_tx_wc(struct net_device *dev, struct ib_wc *wc) struct ipoib_dev_priv *priv = netdev_priv(dev); unsigned int wr_id = wc->wr_id; struct ipoib_tx_buf *tx_req; - unsigned long flags; ipoib_dbg_data(priv, "send completion: id %d, status: %d\n", wr_id, wc->status); @@ -384,13 +383,11 @@ static void ipoib_ib_handle_tx_wc(struct net_device *dev, struct ib_wc *wc) dev_kfree_skb_any(tx_req->skb); - spin_lock_irqsave(&priv->tx_lock, flags); ++priv->tx_tail; if (unlikely(--priv->tx_outstanding == ipoib_sendq_size >> 1) && netif_queue_stopped(dev) && test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags)) netif_wake_queue(dev); - spin_unlock_irqrestore(&priv->tx_lock, flags); if (wc->status != IB_WC_SUCCESS && wc->status != IB_WC_WR_FLUSH_ERR) @@ -399,6 +396,17 @@ static void ipoib_ib_handle_tx_wc(struct net_device *dev, struct ib_wc *wc) wc->status, wr_id, wc->vendor_err); } +static int poll_tx(struct ipoib_dev_priv *priv) +{ + int n, i; + + n = ib_poll_cq(priv->send_cq, MAX_SEND_CQE, priv->send_wc); + for (i = 0; i < n; ++i) + ipoib_ib_handle_tx_wc(priv->dev, priv->send_wc + i); + + return n == MAX_SEND_CQE; +} + int ipoib_poll(struct napi_struct *napi, int budget) { struct ipoib_dev_priv *priv = container_of(napi, struct ipoib_dev_priv, napi); @@ -414,7 +422,7 @@ poll_more: int max = (budget - done); t = min(IPOIB_NUM_WC, max); - n = ib_poll_cq(priv->cq, t, priv->ibwc); + n = ib_poll_cq(priv->recv_cq, t, priv->ibwc); for (i = 0; i < n; i++) { struct ib_wc *wc = priv->ibwc + i; @@ -425,12 +433,8 @@ poll_more: ipoib_cm_handle_rx_wc(dev, wc); else ipoib_ib_handle_rx_wc(dev, wc); - } else { - if (wc->wr_id & IPOIB_OP_CM) - ipoib_cm_handle_tx_wc(dev, wc); - else - ipoib_ib_handle_tx_wc(dev, wc); - } + } else + ipoib_cm_handle_tx_wc(priv->dev, wc); } if (n != t) @@ -439,7 +443,7 @@ poll_more: if (done < budget) { netif_rx_complete(dev, napi); - if (unlikely(ib_req_notify_cq(priv->cq, + if (unlikely(ib_req_notify_cq(priv->recv_cq, IB_CQ_NEXT_COMP | IB_CQ_REPORT_MISSED_EVENTS)) && netif_rx_reschedule(dev, napi)) @@ -562,12 +566,16 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb, address->last_send = priv->tx_head; ++priv->tx_head; + skb_orphan(skb); if (++priv->tx_outstanding == ipoib_sendq_size) { ipoib_dbg(priv, "TX ring full, stopping kernel net queue\n"); netif_stop_queue(dev); } } + + if (unlikely(priv->tx_outstanding > MAX_SEND_CQE)) + poll_tx(priv); } static void __ipoib_reap_ah(struct net_device *dev) @@ -714,7 +722,7 @@ void ipoib_drain_cq(struct net_device *dev) struct ipoib_dev_priv *priv = netdev_priv(dev); int i, n; do { - n = ib_poll_cq(priv->cq, IPOIB_NUM_WC, priv->ibwc); + n = ib_poll_cq(priv->recv_cq, IPOIB_NUM_WC, priv->ibwc); for (i = 0; i < n; ++i) { /* * Convert any successful completions to flush @@ -729,14 +737,13 @@ void ipoib_drain_cq(struct net_device *dev) ipoib_cm_handle_rx_wc(dev, priv->ibwc + i); else ipoib_ib_handle_rx_wc(dev, priv->ibwc + i); - } else { - if (priv->ibwc[i].wr_id & IPOIB_OP_CM) - ipoib_cm_handle_tx_wc(dev, priv->ibwc + i); - else - ipoib_ib_handle_tx_wc(dev, priv->ibwc + i); - } + } else + ipoib_cm_handle_tx_wc(dev, priv->ibwc + i); } } while (n == IPOIB_NUM_WC); + + while (poll_tx(priv)) + ; /* nothing */ } int ipoib_ib_dev_stop(struct net_device *dev, int flush) @@ -826,7 +833,7 @@ timeout: msleep(1); } - ib_req_notify_cq(priv->cq, IB_CQ_NEXT_COMP); + ib_req_notify_cq(priv->recv_cq, IB_CQ_NEXT_COMP); return 0; } diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 7a4ed9d3d84..2442090ac8d 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -1298,7 +1298,8 @@ static int __init ipoib_init_module(void) ipoib_sendq_size = roundup_pow_of_two(ipoib_sendq_size); ipoib_sendq_size = min(ipoib_sendq_size, IPOIB_MAX_QUEUE_SIZE); - ipoib_sendq_size = max(ipoib_sendq_size, IPOIB_MIN_QUEUE_SIZE); + ipoib_sendq_size = max(ipoib_sendq_size, max(2 * MAX_SEND_CQE, + IPOIB_MIN_QUEUE_SIZE)); #ifdef CONFIG_INFINIBAND_IPOIB_CM ipoib_max_conn_qp = min(ipoib_max_conn_qp, IPOIB_CM_MAX_CONN_QP); #endif diff --git a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c index 07c03f178a4..c1e7ece1fd4 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c @@ -171,26 +171,33 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca) goto out_free_pd; } - size = ipoib_sendq_size + ipoib_recvq_size + 1; + size = ipoib_recvq_size + 1; ret = ipoib_cm_dev_init(dev); if (!ret) { + size += ipoib_sendq_size; if (ipoib_cm_has_srq(dev)) size += ipoib_recvq_size + 1; /* 1 extra for rx_drain_qp */ else size += ipoib_recvq_size * ipoib_max_conn_qp; } - priv->cq = ib_create_cq(priv->ca, ipoib_ib_completion, NULL, dev, size, 0); - if (IS_ERR(priv->cq)) { - printk(KERN_WARNING "%s: failed to create CQ\n", ca->name); + priv->recv_cq = ib_create_cq(priv->ca, ipoib_ib_completion, NULL, dev, size, 0); + if (IS_ERR(priv->recv_cq)) { + printk(KERN_WARNING "%s: failed to create receive CQ\n", ca->name); goto out_free_mr; } - if (ib_req_notify_cq(priv->cq, IB_CQ_NEXT_COMP)) - goto out_free_cq; + priv->send_cq = ib_create_cq(priv->ca, NULL, NULL, dev, ipoib_sendq_size, 0); + if (IS_ERR(priv->send_cq)) { + printk(KERN_WARNING "%s: failed to create send CQ\n", ca->name); + goto out_free_recv_cq; + } + + if (ib_req_notify_cq(priv->recv_cq, IB_CQ_NEXT_COMP)) + goto out_free_send_cq; - init_attr.send_cq = priv->cq; - init_attr.recv_cq = priv->cq; + init_attr.send_cq = priv->send_cq; + init_attr.recv_cq = priv->recv_cq; if (priv->hca_caps & IB_DEVICE_UD_TSO) init_attr.create_flags = IB_QP_CREATE_IPOIB_UD_LSO; @@ -201,7 +208,7 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca) priv->qp = ib_create_qp(priv->pd, &init_attr); if (IS_ERR(priv->qp)) { printk(KERN_WARNING "%s: failed to create QP\n", ca->name); - goto out_free_cq; + goto out_free_send_cq; } priv->dev->dev_addr[1] = (priv->qp->qp_num >> 16) & 0xff; @@ -230,8 +237,11 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca) return 0; -out_free_cq: - ib_destroy_cq(priv->cq); +out_free_send_cq: + ib_destroy_cq(priv->send_cq); + +out_free_recv_cq: + ib_destroy_cq(priv->recv_cq); out_free_mr: ib_dereg_mr(priv->mr); @@ -254,8 +264,11 @@ void ipoib_transport_dev_cleanup(struct net_device *dev) clear_bit(IPOIB_PKEY_ASSIGNED, &priv->flags); } - if (ib_destroy_cq(priv->cq)) - ipoib_warn(priv, "ib_cq_destroy failed\n"); + if (ib_destroy_cq(priv->send_cq)) + ipoib_warn(priv, "ib_cq_destroy (send) failed\n"); + + if (ib_destroy_cq(priv->recv_cq)) + ipoib_warn(priv, "ib_cq_destroy (recv) failed\n"); ipoib_cm_dev_cleanup(dev); diff --git a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c index 431fdeaa2dc..1cdb5cfb0ff 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c @@ -90,6 +90,9 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey) } priv->max_ib_mtu = ppriv->max_ib_mtu; + /* MTU will be reset when mcast join happens */ + priv->dev->mtu = IPOIB_UD_MTU(priv->max_ib_mtu); + priv->mcast_mtu = priv->admin_mtu = priv->dev->mtu; set_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags); priv->pkey = pkey; diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index be1b9fbd416..aeb58cae9a3 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -473,13 +473,15 @@ iscsi_iser_conn_get_stats(struct iscsi_cls_conn *cls_conn, struct iscsi_stats *s stats->r2t_pdus = conn->r2t_pdus_cnt; /* always 0 */ stats->tmfcmd_pdus = conn->tmfcmd_pdus_cnt; stats->tmfrsp_pdus = conn->tmfrsp_pdus_cnt; - stats->custom_length = 3; + stats->custom_length = 4; strcpy(stats->custom[0].desc, "qp_tx_queue_full"); stats->custom[0].value = 0; /* TB iser_conn->qp_tx_queue_full; */ strcpy(stats->custom[1].desc, "fmr_map_not_avail"); stats->custom[1].value = 0; /* TB iser_conn->fmr_map_not_avail */; strcpy(stats->custom[2].desc, "eh_abort_cnt"); stats->custom[2].value = conn->eh_abort_cnt; + strcpy(stats->custom[3].desc, "fmr_unalign_cnt"); + stats->custom[3].value = conn->fmr_unalign_cnt; } static int diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h index 1ee867b1b34..a8c1b300e34 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.h +++ b/drivers/infiniband/ulp/iser/iscsi_iser.h @@ -71,6 +71,13 @@ #define iser_dbg(fmt, arg...) \ do { \ + if (iser_debug_level > 1) \ + printk(KERN_DEBUG PFX "%s:" fmt,\ + __func__ , ## arg); \ + } while (0) + +#define iser_warn(fmt, arg...) \ + do { \ if (iser_debug_level > 0) \ printk(KERN_DEBUG PFX "%s:" fmt,\ __func__ , ## arg); \ diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c index 4a17743a639..cac50c4dc15 100644 --- a/drivers/infiniband/ulp/iser/iser_memory.c +++ b/drivers/infiniband/ulp/iser/iser_memory.c @@ -334,8 +334,11 @@ static void iser_data_buf_dump(struct iser_data_buf *data, struct scatterlist *sg; int i; + if (iser_debug_level == 0) + return; + for_each_sg(sgl, sg, data->dma_nents, i) - iser_err("sg[%d] dma_addr:0x%lX page:0x%p " + iser_warn("sg[%d] dma_addr:0x%lX page:0x%p " "off:0x%x sz:0x%x dma_len:0x%x\n", i, (unsigned long)ib_sg_dma_address(ibdev, sg), sg_page(sg), sg->offset, @@ -420,6 +423,7 @@ void iser_dma_unmap_task_data(struct iscsi_iser_cmd_task *iser_ctask) int iser_reg_rdma_mem(struct iscsi_iser_cmd_task *iser_ctask, enum iser_data_dir cmd_dir) { + struct iscsi_conn *iscsi_conn = iser_ctask->iser_conn->iscsi_conn; struct iser_conn *ib_conn = iser_ctask->iser_conn->ib_conn; struct iser_device *device = ib_conn->device; struct ib_device *ibdev = device->ib_device; @@ -434,7 +438,8 @@ int iser_reg_rdma_mem(struct iscsi_iser_cmd_task *iser_ctask, aligned_len = iser_data_buf_aligned_len(mem, ibdev); if (aligned_len != mem->dma_nents) { - iser_err("rdma alignment violation %d/%d aligned\n", + iscsi_conn->fmr_unalign_cnt++; + iser_warn("rdma alignment violation %d/%d aligned\n", aligned_len, mem->size); iser_data_buf_dump(mem, ibdev); diff --git a/drivers/input/input.c b/drivers/input/input.c index f02c242c311..27006fc1830 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -898,30 +898,26 @@ static int __init input_proc_init(void) { struct proc_dir_entry *entry; - proc_bus_input_dir = proc_mkdir("input", proc_bus); + proc_bus_input_dir = proc_mkdir("bus/input", NULL); if (!proc_bus_input_dir) return -ENOMEM; proc_bus_input_dir->owner = THIS_MODULE; - entry = create_proc_entry("devices", 0, proc_bus_input_dir); + entry = proc_create("devices", 0, proc_bus_input_dir, + &input_devices_fileops); if (!entry) goto fail1; - entry->owner = THIS_MODULE; - entry->proc_fops = &input_devices_fileops; - - entry = create_proc_entry("handlers", 0, proc_bus_input_dir); + entry = proc_create("handlers", 0, proc_bus_input_dir, + &input_handlers_fileops); if (!entry) goto fail2; - entry->owner = THIS_MODULE; - entry->proc_fops = &input_handlers_fileops; - return 0; fail2: remove_proc_entry("devices", proc_bus_input_dir); - fail1: remove_proc_entry("input", proc_bus); + fail1: remove_proc_entry("bus/input", NULL); return -ENOMEM; } @@ -929,7 +925,7 @@ static void input_proc_exit(void) { remove_proc_entry("devices", proc_bus_input_dir); remove_proc_entry("handlers", proc_bus_input_dir); - remove_proc_entry("input", proc_bus); + remove_proc_entry("bus/input", NULL); } #else /* !CONFIG_PROC_FS */ diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c index 1457b73850e..7fb3cf81cfb 100644 --- a/drivers/input/joystick/iforce/iforce-usb.c +++ b/drivers/input/joystick/iforce/iforce-usb.c @@ -159,7 +159,7 @@ static int iforce_usb_probe(struct usb_interface *intf, iforce->cr.bRequestType = USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_INTERFACE; iforce->cr.wIndex = 0; - iforce->cr.wLength = 16; + iforce->cr.wLength = cpu_to_le16(16); usb_fill_int_urb(iforce->irq, dev, usb_rcvintpipe(dev, epirq->bEndpointAddress), iforce->data, 16, iforce_usb_irq, iforce, epirq->bInterval); diff --git a/drivers/input/misc/sparcspkr.c b/drivers/input/misc/sparcspkr.c index fed3c375ccf..d8765cc93d2 100644 --- a/drivers/input/misc/sparcspkr.c +++ b/drivers/input/misc/sparcspkr.c @@ -2,33 +2,69 @@ * Driver for PC-speaker like devices found on various Sparc systems. * * Copyright (c) 2002 Vojtech Pavlik - * Copyright (c) 2002, 2006 David S. Miller (davem@davemloft.net) + * Copyright (c) 2002, 2006, 2008 David S. Miller (davem@davemloft.net) */ #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> #include <linux/input.h> -#include <linux/platform_device.h> +#include <linux/of_device.h> #include <asm/io.h> -#include <asm/ebus.h> -#include <asm/isa.h> MODULE_AUTHOR("David S. Miller <davem@davemloft.net>"); MODULE_DESCRIPTION("Sparc Speaker beeper driver"); MODULE_LICENSE("GPL"); +struct grover_beep_info { + void __iomem *freq_regs; + void __iomem *enable_reg; +}; + +struct bbc_beep_info { + u32 clock_freq; + void __iomem *regs; +}; + struct sparcspkr_state { const char *name; - unsigned long iobase; int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value); spinlock_t lock; struct input_dev *input_dev; + union { + struct grover_beep_info grover; + struct bbc_beep_info bbc; + } u; }; -static int ebus_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) +static u32 bbc_count_to_reg(struct bbc_beep_info *info, unsigned int count) +{ + u32 val, clock_freq = info->clock_freq; + int i; + + if (!count) + return 0; + + if (count <= clock_freq >> 20) + return 1 << 18; + + if (count >= clock_freq >> 12) + return 1 << 10; + + val = 1 << 18; + for (i = 19; i >= 11; i--) { + val >>= 1; + if (count <= clock_freq >> i) + break; + } + + return val; +} + +static int bbc_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { struct sparcspkr_state *state = dev_get_drvdata(dev->dev.parent); + struct bbc_beep_info *info = &state->u.bbc; unsigned int count = 0; unsigned long flags; @@ -44,24 +80,29 @@ static int ebus_spkr_event(struct input_dev *dev, unsigned int type, unsigned in if (value > 20 && value < 32767) count = 1193182 / value; + count = bbc_count_to_reg(info, count); + spin_lock_irqsave(&state->lock, flags); - /* EBUS speaker only has on/off state, the frequency does not - * appear to be programmable. - */ - if (state->iobase & 0x2UL) - outb(!!count, state->iobase); - else - outl(!!count, state->iobase); + if (count) { + outb(0x01, info->regs + 0); + outb(0x00, info->regs + 2); + outb((count >> 16) & 0xff, info->regs + 3); + outb((count >> 8) & 0xff, info->regs + 4); + outb(0x00, info->regs + 5); + } else { + outb(0x00, info->regs + 0); + } spin_unlock_irqrestore(&state->lock, flags); return 0; } -static int isa_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) +static int grover_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { struct sparcspkr_state *state = dev_get_drvdata(dev->dev.parent); + struct grover_beep_info *info = &state->u.grover; unsigned int count = 0; unsigned long flags; @@ -81,15 +122,15 @@ static int isa_spkr_event(struct input_dev *dev, unsigned int type, unsigned int if (count) { /* enable counter 2 */ - outb(inb(state->iobase + 0x61) | 3, state->iobase + 0x61); + outb(inb(info->enable_reg) | 3, info->enable_reg); /* set command for counter 2, 2 byte write */ - outb(0xB6, state->iobase + 0x43); + outb(0xB6, info->freq_regs + 1); /* select desired HZ */ - outb(count & 0xff, state->iobase + 0x42); - outb((count >> 8) & 0xff, state->iobase + 0x42); + outb(count & 0xff, info->freq_regs + 0); + outb((count >> 8) & 0xff, info->freq_regs + 0); } else { /* disable counter 2 */ - outb(inb_p(state->iobase + 0x61) & 0xFC, state->iobase + 0x61); + outb(inb_p(info->enable_reg) & 0xFC, info->enable_reg); } spin_unlock_irqrestore(&state->lock, flags); @@ -131,7 +172,7 @@ static int __devinit sparcspkr_probe(struct device *dev) return 0; } -static int __devexit sparcspkr_remove(struct of_device *dev) +static int sparcspkr_shutdown(struct of_device *dev) { struct sparcspkr_state *state = dev_get_drvdata(&dev->dev); struct input_dev *input_dev = state->input_dev; @@ -139,115 +180,180 @@ static int __devexit sparcspkr_remove(struct of_device *dev) /* turn off the speaker */ state->event(input_dev, EV_SND, SND_BELL, 0); - input_unregister_device(input_dev); - - dev_set_drvdata(&dev->dev, NULL); - kfree(state); - return 0; } -static int sparcspkr_shutdown(struct of_device *dev) +static int __devinit bbc_beep_probe(struct of_device *op, const struct of_device_id *match) { - struct sparcspkr_state *state = dev_get_drvdata(&dev->dev); - struct input_dev *input_dev = state->input_dev; + struct sparcspkr_state *state; + struct bbc_beep_info *info; + struct device_node *dp; + int err = -ENOMEM; - /* turn off the speaker */ - state->event(input_dev, EV_SND, SND_BELL, 0); + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (!state) + goto out_err; + + state->name = "Sparc BBC Speaker"; + state->event = bbc_spkr_event; + spin_lock_init(&state->lock); + + dp = of_find_node_by_path("/"); + err = -ENODEV; + if (!dp) + goto out_free; + + info = &state->u.bbc; + info->clock_freq = of_getintprop_default(dp, "clock-frequency", 0); + if (!info->clock_freq) + goto out_free; + + info->regs = of_ioremap(&op->resource[0], 0, 6, "bbc beep"); + if (!info->regs) + goto out_free; + + dev_set_drvdata(&op->dev, state); + + err = sparcspkr_probe(&op->dev); + if (err) + goto out_clear_drvdata; return 0; + +out_clear_drvdata: + dev_set_drvdata(&op->dev, NULL); + of_iounmap(&op->resource[0], info->regs, 6); + +out_free: + kfree(state); +out_err: + return err; } -static int __devinit ebus_beep_probe(struct of_device *dev, const struct of_device_id *match) +static int bbc_remove(struct of_device *op) { - struct linux_ebus_device *edev = to_ebus_device(&dev->dev); - struct sparcspkr_state *state; - int err; + struct sparcspkr_state *state = dev_get_drvdata(&op->dev); + struct input_dev *input_dev = state->input_dev; + struct bbc_beep_info *info = &state->u.bbc; - state = kzalloc(sizeof(*state), GFP_KERNEL); - if (!state) - return -ENOMEM; + /* turn off the speaker */ + state->event(input_dev, EV_SND, SND_BELL, 0); - state->name = "Sparc EBUS Speaker"; - state->iobase = edev->resource[0].start; - state->event = ebus_spkr_event; - spin_lock_init(&state->lock); + input_unregister_device(input_dev); - dev_set_drvdata(&dev->dev, state); + of_iounmap(&op->resource[0], info->regs, 6); - err = sparcspkr_probe(&dev->dev); - if (err) { - dev_set_drvdata(&dev->dev, NULL); - kfree(state); - } + dev_set_drvdata(&op->dev, NULL); + kfree(state); return 0; } -static struct of_device_id ebus_beep_match[] = { +static struct of_device_id bbc_beep_match[] = { { .name = "beep", + .compatible = "SUNW,bbc-beep", }, {}, }; -static struct of_platform_driver ebus_beep_driver = { - .name = "beep", - .match_table = ebus_beep_match, - .probe = ebus_beep_probe, - .remove = __devexit_p(sparcspkr_remove), +static struct of_platform_driver bbc_beep_driver = { + .name = "bbcbeep", + .match_table = bbc_beep_match, + .probe = bbc_beep_probe, + .remove = __devexit_p(bbc_remove), .shutdown = sparcspkr_shutdown, }; -static int __devinit isa_beep_probe(struct of_device *dev, const struct of_device_id *match) +static int __devinit grover_beep_probe(struct of_device *op, const struct of_device_id *match) { - struct sparc_isa_device *idev = to_isa_device(&dev->dev); struct sparcspkr_state *state; - int err; + struct grover_beep_info *info; + int err = -ENOMEM; state = kzalloc(sizeof(*state), GFP_KERNEL); if (!state) - return -ENOMEM; + goto out_err; - state->name = "Sparc ISA Speaker"; - state->iobase = idev->resource.start; - state->event = isa_spkr_event; + state->name = "Sparc Grover Speaker"; + state->event = grover_spkr_event; spin_lock_init(&state->lock); - dev_set_drvdata(&dev->dev, state); + info = &state->u.grover; + info->freq_regs = of_ioremap(&op->resource[2], 0, 2, "grover beep freq"); + if (!info->freq_regs) + goto out_free; - err = sparcspkr_probe(&dev->dev); - if (err) { - dev_set_drvdata(&dev->dev, NULL); - kfree(state); - } + info->enable_reg = of_ioremap(&op->resource[3], 0, 1, "grover beep enable"); + if (!info->enable_reg) + goto out_unmap_freq_regs; + + dev_set_drvdata(&op->dev, state); + + err = sparcspkr_probe(&op->dev); + if (err) + goto out_clear_drvdata; + + return 0; + +out_clear_drvdata: + dev_set_drvdata(&op->dev, NULL); + of_iounmap(&op->resource[3], info->enable_reg, 1); + +out_unmap_freq_regs: + of_iounmap(&op->resource[2], info->freq_regs, 2); +out_free: + kfree(state); +out_err: + return err; +} + +static int grover_remove(struct of_device *op) +{ + struct sparcspkr_state *state = dev_get_drvdata(&op->dev); + struct grover_beep_info *info = &state->u.grover; + struct input_dev *input_dev = state->input_dev; + + /* turn off the speaker */ + state->event(input_dev, EV_SND, SND_BELL, 0); + + input_unregister_device(input_dev); + + of_iounmap(&op->resource[3], info->enable_reg, 1); + of_iounmap(&op->resource[2], info->freq_regs, 2); + + dev_set_drvdata(&op->dev, NULL); + kfree(state); return 0; } -static struct of_device_id isa_beep_match[] = { +static struct of_device_id grover_beep_match[] = { { - .name = "dma", + .name = "beep", + .compatible = "SUNW,smbus-beep", }, {}, }; -static struct of_platform_driver isa_beep_driver = { - .name = "beep", - .match_table = isa_beep_match, - .probe = isa_beep_probe, - .remove = __devexit_p(sparcspkr_remove), +static struct of_platform_driver grover_beep_driver = { + .name = "groverbeep", + .match_table = grover_beep_match, + .probe = grover_beep_probe, + .remove = __devexit_p(grover_remove), .shutdown = sparcspkr_shutdown, }; static int __init sparcspkr_init(void) { - int err = of_register_driver(&ebus_beep_driver, &ebus_bus_type); + int err = of_register_driver(&bbc_beep_driver, + &of_platform_bus_type); if (!err) { - err = of_register_driver(&isa_beep_driver, &isa_bus_type); + err = of_register_driver(&grover_beep_driver, + &of_platform_bus_type); if (err) - of_unregister_driver(&ebus_beep_driver); + of_unregister_driver(&bbc_beep_driver); } return err; @@ -255,8 +361,8 @@ static int __init sparcspkr_init(void) static void __exit sparcspkr_exit(void) { - of_unregister_driver(&ebus_beep_driver); - of_unregister_driver(&isa_beep_driver); + of_unregister_driver(&bbc_beep_driver); + of_unregister_driver(&grover_beep_driver); } module_init(sparcspkr_init); diff --git a/drivers/input/tablet/aiptek.c b/drivers/input/tablet/aiptek.c index 1d759f6f807..55c1134d613 100644 --- a/drivers/input/tablet/aiptek.c +++ b/drivers/input/tablet/aiptek.c @@ -528,9 +528,9 @@ static void aiptek_irq(struct urb *urb) (aiptek->curSetting.pointerMode)) { aiptek->diagnostic = AIPTEK_DIAGNOSTIC_TOOL_DISALLOWED; } else { - x = le16_to_cpu(get_unaligned((__le16 *) (data + 1))); - y = le16_to_cpu(get_unaligned((__le16 *) (data + 3))); - z = le16_to_cpu(get_unaligned((__le16 *) (data + 6))); + x = get_unaligned_le16(data + 1); + y = get_unaligned_le16(data + 3); + z = get_unaligned_le16(data + 6); dv = (data[5] & 0x01) != 0 ? 1 : 0; p = (data[5] & 0x02) != 0 ? 1 : 0; @@ -613,8 +613,8 @@ static void aiptek_irq(struct urb *urb) (aiptek->curSetting.pointerMode)) { aiptek->diagnostic = AIPTEK_DIAGNOSTIC_TOOL_DISALLOWED; } else { - x = le16_to_cpu(get_unaligned((__le16 *) (data + 1))); - y = le16_to_cpu(get_unaligned((__le16 *) (data + 3))); + x = get_unaligned_le16(data + 1); + y = get_unaligned_le16(data + 3); jitterable = data[5] & 0x1c; @@ -679,7 +679,7 @@ static void aiptek_irq(struct urb *urb) pck = (data[1] & aiptek->curSetting.stylusButtonUpper) != 0 ? 1 : 0; macro = dv && p && tip && !(data[3] & 1) ? (data[3] >> 1) : -1; - z = le16_to_cpu(get_unaligned((__le16 *) (data + 4))); + z = get_unaligned_le16(data + 4); if (dv) { /* If the selected tool changed, reset the old @@ -757,7 +757,7 @@ static void aiptek_irq(struct urb *urb) * hat switches (which just so happen to be the macroKeys.) */ else if (data[0] == 6) { - macro = le16_to_cpu(get_unaligned((__le16 *) (data + 1))); + macro = get_unaligned_le16(data + 1); if (macro > 0) { input_report_key(inputdev, macroKeyEvents[macro - 1], 0); @@ -952,7 +952,7 @@ aiptek_query(struct aiptek *aiptek, unsigned char command, unsigned char data) buf[0], buf[1], buf[2]); ret = -EIO; } else { - ret = le16_to_cpu(get_unaligned((__le16 *) (buf + 1))); + ret = get_unaligned_le16(buf + 1); } kfree(buf); return ret; diff --git a/drivers/input/tablet/gtco.c b/drivers/input/tablet/gtco.c index d2c6da26472..c5a8661a1ba 100644 --- a/drivers/input/tablet/gtco.c +++ b/drivers/input/tablet/gtco.c @@ -245,11 +245,11 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report, data = report[i]; break; case 2: - data16 = le16_to_cpu(get_unaligned((__le16 *)&report[i])); + data16 = get_unaligned_le16(&report[i]); break; case 3: size = 4; - data32 = le32_to_cpu(get_unaligned((__le32 *)&report[i])); + data32 = get_unaligned_le32(&report[i]); break; } @@ -695,10 +695,10 @@ static void gtco_urb_callback(struct urb *urbinfo) /* Fall thru */ case 1: /* All reports have X and Y coords in the same place */ - val = le16_to_cpu(get_unaligned((__le16 *)&device->buffer[1])); + val = get_unaligned_le16(&device->buffer[1]); input_report_abs(inputdev, ABS_X, val); - val = le16_to_cpu(get_unaligned((__le16 *)&device->buffer[3])); + val = get_unaligned_le16(&device->buffer[3]); input_report_abs(inputdev, ABS_Y, val); /* Ditto for proximity bit */ @@ -762,7 +762,7 @@ static void gtco_urb_callback(struct urb *urbinfo) le_buffer[1] = (u8)(device->buffer[4] >> 1); le_buffer[1] |= (u8)((device->buffer[5] & 0x1) << 7); - val = le16_to_cpu(get_unaligned((__le16 *)le_buffer)); + val = get_unaligned_le16(le_buffer); input_report_abs(inputdev, ABS_Y, val); /* @@ -772,10 +772,10 @@ static void gtco_urb_callback(struct urb *urbinfo) buttonbyte = device->buffer[5] >> 1; } else { - val = le16_to_cpu(get_unaligned((__le16 *)&device->buffer[1])); + val = get_unaligned_le16(&device->buffer[1]); input_report_abs(inputdev, ABS_X, val); - val = le16_to_cpu(get_unaligned((__le16 *)&device->buffer[3])); + val = get_unaligned_le16(&device->buffer[3]); input_report_abs(inputdev, ABS_Y, val); buttonbyte = device->buffer[5]; @@ -897,7 +897,7 @@ static int gtco_probe(struct usb_interface *usbinterface, dbg("Extra descriptor success: type:%d len:%d", hid_desc->bDescriptorType, hid_desc->wDescriptorLength); - report = kzalloc(hid_desc->wDescriptorLength, GFP_KERNEL); + report = kzalloc(le16_to_cpu(hid_desc->wDescriptorLength), GFP_KERNEL); if (!report) { err("No more memory for report"); error = -ENOMEM; @@ -913,16 +913,16 @@ static int gtco_probe(struct usb_interface *usbinterface, REPORT_DEVICE_TYPE << 8, 0, /* interface */ report, - hid_desc->wDescriptorLength, + le16_to_cpu(hid_desc->wDescriptorLength), 5000); /* 5 secs */ - if (result == hid_desc->wDescriptorLength) + if (result == le16_to_cpu(hid_desc->wDescriptorLength)) break; } /* If we didn't get the report, fail */ dbg("usb_control_msg result: :%d", result); - if (result != hid_desc->wDescriptorLength) { + if (result != le16_to_cpu(hid_desc->wDescriptorLength)) { err("Failed to get HID Report Descriptor of size: %d", hid_desc->wDescriptorLength); error = -EIO; diff --git a/drivers/input/tablet/kbtab.c b/drivers/input/tablet/kbtab.c index 1182fc13316..f23f5a97fb3 100644 --- a/drivers/input/tablet/kbtab.c +++ b/drivers/input/tablet/kbtab.c @@ -63,8 +63,8 @@ static void kbtab_irq(struct urb *urb) goto exit; } - kbtab->x = le16_to_cpu(get_unaligned((__le16 *) &data[1])); - kbtab->y = le16_to_cpu(get_unaligned((__le16 *) &data[3])); + kbtab->x = get_unaligned_le16(&data[1]); + kbtab->y = get_unaligned_le16(&data[3]); kbtab->pressure = (data[5]); diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c index 23ae66c76d4..24c6b7ca62b 100644 --- a/drivers/isdn/capi/capi.c +++ b/drivers/isdn/capi/capi.c @@ -350,7 +350,7 @@ static void capincci_free(struct capidev *cdev, u32 ncci) if (ncci == 0xffffffff || np->ncci == ncci) { *pp = (*pp)->next; #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE - if ((mp = np->minorp) != 0) { + if ((mp = np->minorp) != NULL) { #if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE) capifs_free_ncci(mp->minor); #endif @@ -366,7 +366,7 @@ static void capincci_free(struct capidev *cdev, u32 ncci) } #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ kfree(np); - if (*pp == 0) return; + if (*pp == NULL) return; } else { pp = &(*pp)->next; } @@ -483,7 +483,7 @@ static int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb) #endif goto bad; } - if ((nskb = gen_data_b3_resp_for(mp, skb)) == 0) { + if ((nskb = gen_data_b3_resp_for(mp, skb)) == NULL) { printk(KERN_ERR "capi: gen_data_b3_resp failed\n"); goto bad; } @@ -512,7 +512,7 @@ bad: static void handle_minor_recv(struct capiminor *mp) { struct sk_buff *skb; - while ((skb = skb_dequeue(&mp->inqueue)) != 0) { + while ((skb = skb_dequeue(&mp->inqueue)) != NULL) { unsigned int len = skb->len; mp->inbytes -= len; if (handle_recv_skb(mp, skb) < 0) { @@ -538,7 +538,7 @@ static int handle_minor_send(struct capiminor *mp) return 0; } - while ((skb = skb_dequeue(&mp->outqueue)) != 0) { + while ((skb = skb_dequeue(&mp->outqueue)) != NULL) { datahandle = mp->datahandle; len = (u16)skb->len; skb_push(skb, CAPI_DATA_B3_REQ_LEN); @@ -689,19 +689,19 @@ capi_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) if (!cdev->ap.applid) return -ENODEV; - if ((skb = skb_dequeue(&cdev->recvqueue)) == 0) { + if ((skb = skb_dequeue(&cdev->recvqueue)) == NULL) { if (file->f_flags & O_NONBLOCK) return -EAGAIN; for (;;) { interruptible_sleep_on(&cdev->recvwait); - if ((skb = skb_dequeue(&cdev->recvqueue)) != 0) + if ((skb = skb_dequeue(&cdev->recvqueue)) != NULL) break; if (signal_pending(current)) break; } - if (skb == 0) + if (skb == NULL) return -ERESTARTNOHAND; } if (skb->len > count) { @@ -940,12 +940,12 @@ capi_ioctl(struct inode *inode, struct file *file, return -EFAULT; mutex_lock(&cdev->ncci_list_mtx); - if ((nccip = capincci_find(cdev, (u32) ncci)) == 0) { + if ((nccip = capincci_find(cdev, (u32) ncci)) == NULL) { mutex_unlock(&cdev->ncci_list_mtx); return 0; } #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE - if ((mp = nccip->minorp) != 0) { + if ((mp = nccip->minorp) != NULL) { count += atomic_read(&mp->ttyopencount); } #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ @@ -966,7 +966,7 @@ capi_ioctl(struct inode *inode, struct file *file, return -EFAULT; mutex_lock(&cdev->ncci_list_mtx); nccip = capincci_find(cdev, (u32) ncci); - if (!nccip || (mp = nccip->minorp) == 0) { + if (!nccip || (mp = nccip->minorp) == NULL) { mutex_unlock(&cdev->ncci_list_mtx); return -ESRCH; } @@ -986,7 +986,7 @@ capi_open(struct inode *inode, struct file *file) if (file->private_data) return -EEXIST; - if ((file->private_data = capidev_alloc()) == 0) + if ((file->private_data = capidev_alloc()) == NULL) return -ENOMEM; return nonseekable_open(inode, file); @@ -1023,9 +1023,9 @@ static int capinc_tty_open(struct tty_struct * tty, struct file * file) struct capiminor *mp; unsigned long flags; - if ((mp = capiminor_find(iminor(file->f_path.dentry->d_inode))) == 0) + if ((mp = capiminor_find(iminor(file->f_path.dentry->d_inode))) == NULL) return -ENXIO; - if (mp->nccip == 0) + if (mp->nccip == NULL) return -ENXIO; tty->driver_data = (void *)mp; @@ -1058,7 +1058,7 @@ static void capinc_tty_close(struct tty_struct * tty, struct file * file) #ifdef _DEBUG_REFCOUNT printk(KERN_DEBUG "capinc_tty_close ocount=%d\n", atomic_read(&mp->ttyopencount)); #endif - if (mp->nccip == 0) + if (mp->nccip == NULL) capiminor_free(mp); } @@ -1526,9 +1526,9 @@ static int __init capi_init(void) char *compileinfo; int major_ret; - if ((p = strchr(revision, ':')) != 0 && p[1]) { + if ((p = strchr(revision, ':')) != NULL && p[1]) { strlcpy(rev, p + 2, sizeof(rev)); - if ((p = strchr(rev, '$')) != 0 && p > rev) + if ((p = strchr(rev, '$')) != NULL && p > rev) *(p-1) = 0; } else strcpy(rev, "1.0"); diff --git a/drivers/isdn/capi/capidrv.c b/drivers/isdn/capi/capidrv.c index cb42b690b45..d5b4cc357a3 100644 --- a/drivers/isdn/capi/capidrv.c +++ b/drivers/isdn/capi/capidrv.c @@ -335,7 +335,7 @@ static capidrv_plci *new_plci(capidrv_contr * card, int chan) plcip = kzalloc(sizeof(capidrv_plci), GFP_ATOMIC); - if (plcip == 0) + if (plcip == NULL) return NULL; plcip->state = ST_PLCI_NONE; @@ -404,7 +404,7 @@ static inline capidrv_ncci *new_ncci(capidrv_contr * card, nccip = kzalloc(sizeof(capidrv_ncci), GFP_ATOMIC); - if (nccip == 0) + if (nccip == NULL) return NULL; nccip->ncci = ncci; @@ -426,7 +426,7 @@ static inline capidrv_ncci *find_ncci(capidrv_contr * card, u32 ncci) capidrv_plci *plcip; capidrv_ncci *p; - if ((plcip = find_plci_by_ncci(card, ncci)) == 0) + if ((plcip = find_plci_by_ncci(card, ncci)) == NULL) return NULL; for (p = plcip->ncci_list; p; p = p->next) @@ -441,7 +441,7 @@ static inline capidrv_ncci *find_ncci_by_msgid(capidrv_contr * card, capidrv_plci *plcip; capidrv_ncci *p; - if ((plcip = find_plci_by_ncci(card, ncci)) == 0) + if ((plcip = find_plci_by_ncci(card, ncci)) == NULL) return NULL; for (p = plcip->ncci_list; p; p = p->next) @@ -755,7 +755,7 @@ static inline int new_bchan(capidrv_contr * card) { int i; for (i = 0; i < card->nbchan; i++) { - if (card->bchans[i].plcip == 0) { + if (card->bchans[i].plcip == NULL) { card->bchans[i].disconnecting = 0; return i; } @@ -877,7 +877,7 @@ static void handle_incoming_call(capidrv_contr * card, _cmsg * cmsg) return; } bchan = &card->bchans[chan]; - if ((plcip = new_plci(card, chan)) == 0) { + if ((plcip = new_plci(card, chan)) == NULL) { printk(KERN_ERR "capidrv-%d: incoming call: no memory, sorry.\n", card->contrnr); return; } @@ -1388,12 +1388,12 @@ static void capidrv_recv_message(struct capi20_appl *ap, struct sk_buff *skb) _cdebbuf *cdb = capi_cmsg2str(&s_cmsg); if (cdb) { - printk(KERN_DEBUG "%s: applid=%d %s\n", __FUNCTION__, + printk(KERN_DEBUG "%s: applid=%d %s\n", __func__, ap->applid, cdb->buf); cdebbuf_free(cdb); } else printk(KERN_DEBUG "%s: applid=%d %s not traced\n", - __FUNCTION__, ap->applid, + __func__, ap->applid, capi_cmd2str(s_cmsg.Command, s_cmsg.Subcommand)); } if (s_cmsg.Command == CAPI_DATA_B3 @@ -1661,7 +1661,7 @@ static int capidrv_command(isdn_ctrl * c, capidrv_contr * card) NULL, /* Useruserdata */ NULL /* Facilitydataarray */ ); - if ((plcip = new_plci(card, (c->arg % card->nbchan))) == 0) { + if ((plcip = new_plci(card, (c->arg % card->nbchan))) == NULL) { cmd.command = ISDN_STAT_DHUP; cmd.driver = card->myid; cmd.arg = (c->arg % card->nbchan); @@ -1966,7 +1966,7 @@ static void enable_dchannel_trace(capidrv_contr *card) card->name, errcode); return; } - if (strstr(manufacturer, "AVM") == 0) { + if (strstr(manufacturer, "AVM") == NULL) { printk(KERN_ERR "%s: not from AVM, no d-channel trace possible (%s)\n", card->name, manufacturer); return; @@ -2291,10 +2291,10 @@ static int __init capidrv_init(void) u32 ncontr, contr; u16 errcode; - if ((p = strchr(revision, ':')) != 0 && p[1]) { + if ((p = strchr(revision, ':')) != NULL && p[1]) { strncpy(rev, p + 2, sizeof(rev)); rev[sizeof(rev)-1] = 0; - if ((p = strchr(rev, '$')) != 0 && p > rev) + if ((p = strchr(rev, '$')) != NULL && p > rev) *(p-1) = 0; } else strcpy(rev, "1.0"); @@ -2335,10 +2335,10 @@ static void __exit capidrv_exit(void) char rev[32]; char *p; - if ((p = strchr(revision, ':')) != 0) { + if ((p = strchr(revision, ':')) != NULL) { strncpy(rev, p + 1, sizeof(rev)); rev[sizeof(rev)-1] = 0; - if ((p = strchr(rev, '$')) != 0) + if ((p = strchr(rev, '$')) != NULL) *p = 0; } else { strcpy(rev, " ??? "); diff --git a/drivers/isdn/capi/capifs.c b/drivers/isdn/capi/capifs.c index 6d7c47ec036..550e80f390a 100644 --- a/drivers/isdn/capi/capifs.c +++ b/drivers/isdn/capi/capifs.c @@ -69,6 +69,7 @@ static int capifs_remount(struct super_block *s, int *flags, char *data) } else if (sscanf(this_char, "mode=%o%c", &n, &dummy) == 1) mode = n & ~S_IFMT; else { + kfree(new_opt); printk("capifs: called with bogus options\n"); return -EINVAL; } @@ -189,9 +190,9 @@ static int __init capifs_init(void) char *p; int err; - if ((p = strchr(revision, ':')) != 0 && p[1]) { + if ((p = strchr(revision, ':')) != NULL && p[1]) { strlcpy(rev, p + 2, sizeof(rev)); - if ((p = strchr(rev, '$')) != 0 && p > rev) + if ((p = strchr(rev, '$')) != NULL && p > rev) *(p-1) = 0; } else strcpy(rev, "1.0"); diff --git a/drivers/isdn/capi/capilib.c b/drivers/isdn/capi/capilib.c index 68409d971e7..fcaa1241ee7 100644 --- a/drivers/isdn/capi/capilib.c +++ b/drivers/isdn/capi/capilib.c @@ -4,7 +4,7 @@ #include <linux/isdn/capilli.h> #define DBG(format, arg...) do { \ -printk(KERN_DEBUG "%s: " format "\n" , __FUNCTION__ , ## arg); \ +printk(KERN_DEBUG "%s: " format "\n" , __func__ , ## arg); \ } while (0) struct capilib_msgidqueue { @@ -44,7 +44,7 @@ static inline void mq_init(struct capilib_ncci * np) static inline int mq_enqueue(struct capilib_ncci * np, u16 msgid) { struct capilib_msgidqueue *mq; - if ((mq = np->msgidfree) == 0) + if ((mq = np->msgidfree) == NULL) return 0; np->msgidfree = mq->next; mq->msgid = msgid; diff --git a/drivers/isdn/capi/capiutil.c b/drivers/isdn/capi/capiutil.c index 22379b94e88..ebef4ce1b00 100644 --- a/drivers/isdn/capi/capiutil.c +++ b/drivers/isdn/capi/capiutil.c @@ -450,7 +450,7 @@ static void pars_2_message(_cmsg * cmsg) cmsg->l += 4; break; case _CSTRUCT: - if (*(u8 **) OFF == 0) { + if (*(u8 **) OFF == NULL) { *(cmsg->m + cmsg->l) = '\0'; cmsg->l++; } else if (**(_cstruct *) OFF != 0xff) { diff --git a/drivers/isdn/capi/kcapi.c b/drivers/isdn/capi/kcapi.c index f5553186931..75726ea0fbb 100644 --- a/drivers/isdn/capi/kcapi.c +++ b/drivers/isdn/capi/kcapi.c @@ -10,7 +10,7 @@ * */ -#define CONFIG_AVMB1_COMPAT +#define AVMB1_COMPAT #include "kcapi.h" #include <linux/module.h> @@ -29,7 +29,7 @@ #include <asm/uaccess.h> #include <linux/isdn/capicmd.h> #include <linux/isdn/capiutil.h> -#ifdef CONFIG_AVMB1_COMPAT +#ifdef AVMB1_COMPAT #include <linux/b1lli.h> #endif #include <linux/mutex.h> @@ -154,7 +154,7 @@ static void register_appl(struct capi_ctr *card, u16 applid, capi_register_param if (card) card->register_appl(card, applid, rparam); else - printk(KERN_WARNING "%s: cannot get card resources\n", __FUNCTION__); + printk(KERN_WARNING "%s: cannot get card resources\n", __func__); } @@ -178,7 +178,7 @@ static void notify_up(u32 contr) printk(KERN_DEBUG "kcapi: notify up contr %d\n", contr); } if (!card) { - printk(KERN_WARNING "%s: invalid contr %d\n", __FUNCTION__, contr); + printk(KERN_WARNING "%s: invalid contr %d\n", __func__, contr); return; } for (applid = 1; applid <= CAPI_MAXAPPL; applid++) { @@ -740,7 +740,7 @@ u16 capi20_get_profile(u32 contr, struct capi_profile *profp) EXPORT_SYMBOL(capi20_get_profile); -#ifdef CONFIG_AVMB1_COMPAT +#ifdef AVMB1_COMPAT static int old_capi_manufacturer(unsigned int cmd, void __user *data) { avmb1_loadandconfigdef ldef; @@ -826,7 +826,7 @@ static int old_capi_manufacturer(unsigned int cmd, void __user *data) card = capi_ctr_get(card); if (!card) return -ESRCH; - if (card->load_firmware == 0) { + if (card->load_firmware == NULL) { printk(KERN_DEBUG "kcapi: load: no load function\n"); return -ESRCH; } @@ -835,7 +835,7 @@ static int old_capi_manufacturer(unsigned int cmd, void __user *data) printk(KERN_DEBUG "kcapi: load: invalid parameter: length of t4file is %d ?\n", ldef.t4file.len); return -EINVAL; } - if (ldef.t4file.data == 0) { + if (ldef.t4file.data == NULL) { printk(KERN_DEBUG "kcapi: load: invalid parameter: dataptr is 0\n"); return -EINVAL; } @@ -904,7 +904,7 @@ int capi20_manufacturer(unsigned int cmd, void __user *data) struct capi_ctr *card; switch (cmd) { -#ifdef CONFIG_AVMB1_COMPAT +#ifdef AVMB1_COMPAT case AVMB1_LOAD: case AVMB1_LOAD_AND_CONFIG: case AVMB1_RESETCARD: @@ -951,7 +951,7 @@ int capi20_manufacturer(unsigned int cmd, void __user *data) if (strcmp(driver->name, cdef.driver) == 0) break; } - if (driver == 0) { + if (driver == NULL) { printk(KERN_ERR "kcapi: driver \"%s\" not loaded.\n", cdef.driver); return -ESRCH; @@ -1004,9 +1004,9 @@ static int __init kcapi_init(void) return ret; kcapi_proc_init(); - if ((p = strchr(revision, ':')) != 0 && p[1]) { + if ((p = strchr(revision, ':')) != NULL && p[1]) { strlcpy(rev, p + 2, sizeof(rev)); - if ((p = strchr(rev, '$')) != 0 && p > rev) + if ((p = strchr(rev, '$')) != NULL && p > rev) *(p-1) = 0; } else strcpy(rev, "1.0"); diff --git a/drivers/isdn/capi/kcapi.h b/drivers/isdn/capi/kcapi.h index 1cb2c40f992..244711f7f83 100644 --- a/drivers/isdn/capi/kcapi.h +++ b/drivers/isdn/capi/kcapi.h @@ -17,7 +17,7 @@ #ifdef KCAPI_DEBUG #define DBG(format, arg...) do { \ -printk(KERN_DEBUG "%s: " format "\n" , __FUNCTION__ , ## arg); \ +printk(KERN_DEBUG "%s: " format "\n" , __func__ , ## arg); \ } while (0) #else #define DBG(format, arg...) /* */ diff --git a/drivers/isdn/capi/kcapi_proc.c b/drivers/isdn/capi/kcapi_proc.c index 845a797b003..c29208bd752 100644 --- a/drivers/isdn/capi/kcapi_proc.c +++ b/drivers/isdn/capi/kcapi_proc.c @@ -114,6 +114,7 @@ static int seq_contrstats_open(struct inode *inode, struct file *file) } static const struct file_operations proc_controller_ops = { + .owner = THIS_MODULE, .open = seq_controller_open, .read = seq_read, .llseek = seq_lseek, @@ -121,6 +122,7 @@ static const struct file_operations proc_controller_ops = { }; static const struct file_operations proc_contrstats_ops = { + .owner = THIS_MODULE, .open = seq_contrstats_open, .read = seq_read, .llseek = seq_lseek, @@ -219,6 +221,7 @@ seq_applstats_open(struct inode *inode, struct file *file) } static const struct file_operations proc_applications_ops = { + .owner = THIS_MODULE, .open = seq_applications_open, .read = seq_read, .llseek = seq_lseek, @@ -226,21 +229,13 @@ static const struct file_operations proc_applications_ops = { }; static const struct file_operations proc_applstats_ops = { + .owner = THIS_MODULE, .open = seq_applstats_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release, }; -static void -create_seq_entry(char *name, mode_t mode, const struct file_operations *f) -{ - struct proc_dir_entry *entry; - entry = create_proc_entry(name, mode, NULL); - if (entry) - entry->proc_fops = f; -} - // --------------------------------------------------------------------------- static void *capi_driver_start(struct seq_file *seq, loff_t *pos) @@ -283,6 +278,7 @@ seq_capi_driver_open(struct inode *inode, struct file *file) } static const struct file_operations proc_driver_ops = { + .owner = THIS_MODULE, .open = seq_capi_driver_open, .read = seq_read, .llseek = seq_lseek, @@ -296,11 +292,11 @@ kcapi_proc_init(void) { proc_mkdir("capi", NULL); proc_mkdir("capi/controllers", NULL); - create_seq_entry("capi/controller", 0, &proc_controller_ops); - create_seq_entry("capi/contrstats", 0, &proc_contrstats_ops); - create_seq_entry("capi/applications", 0, &proc_applications_ops); - create_seq_entry("capi/applstats", 0, &proc_applstats_ops); - create_seq_entry("capi/driver", 0, &proc_driver_ops); + proc_create("capi/controller", 0, NULL, &proc_controller_ops); + proc_create("capi/contrstats", 0, NULL, &proc_contrstats_ops); + proc_create("capi/applications", 0, NULL, &proc_applications_ops); + proc_create("capi/applstats", 0, NULL, &proc_applstats_ops); + proc_create("capi/driver", 0, NULL, &proc_driver_ops); } void __exit diff --git a/drivers/isdn/divert/divert_procfs.c b/drivers/isdn/divert/divert_procfs.c index 4fd4c46892e..8b256a617c8 100644 --- a/drivers/isdn/divert/divert_procfs.c +++ b/drivers/isdn/divert/divert_procfs.c @@ -288,13 +288,12 @@ divert_dev_init(void) isdn_proc_entry = proc_mkdir("isdn", init_net.proc_net); if (!isdn_proc_entry) return (-1); - isdn_divert_entry = create_proc_entry("divert", S_IFREG | S_IRUGO, isdn_proc_entry); + isdn_divert_entry = proc_create("divert", S_IFREG | S_IRUGO, + isdn_proc_entry, &isdn_fops); if (!isdn_divert_entry) { remove_proc_entry("isdn", init_net.proc_net); return (-1); } - isdn_divert_entry->proc_fops = &isdn_fops; - isdn_divert_entry->owner = THIS_MODULE; #endif /* CONFIG_PROC_FS */ return (0); diff --git a/drivers/isdn/hardware/avm/b1.c b/drivers/isdn/hardware/avm/b1.c index 4484a641723..abf05ec3176 100644 --- a/drivers/isdn/hardware/avm/b1.c +++ b/drivers/isdn/hardware/avm/b1.c @@ -661,11 +661,11 @@ int b1ctl_read_proc(char *page, char **start, off_t off, len += sprintf(page+len, "%-16s %s\n", "type", s); if (card->cardtype == avm_t1isa) len += sprintf(page+len, "%-16s %d\n", "cardnr", card->cardnr); - if ((s = cinfo->version[VER_DRIVER]) != 0) + if ((s = cinfo->version[VER_DRIVER]) != NULL) len += sprintf(page+len, "%-16s %s\n", "ver_driver", s); - if ((s = cinfo->version[VER_CARDTYPE]) != 0) + if ((s = cinfo->version[VER_CARDTYPE]) != NULL) len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s); - if ((s = cinfo->version[VER_SERIAL]) != 0) + if ((s = cinfo->version[VER_SERIAL]) != NULL) len += sprintf(page+len, "%-16s %s\n", "ver_serial", s); if (card->cardtype != avm_m1) { @@ -788,9 +788,9 @@ static int __init b1_init(void) char *p; char rev[32]; - if ((p = strchr(revision, ':')) != 0 && p[1]) { + if ((p = strchr(revision, ':')) != NULL && p[1]) { strlcpy(rev, p + 2, 32); - if ((p = strchr(rev, '$')) != 0 && p > rev) + if ((p = strchr(rev, '$')) != NULL && p > rev) *(p-1) = 0; } else strcpy(rev, "1.0"); diff --git a/drivers/isdn/hardware/avm/b1dma.c b/drivers/isdn/hardware/avm/b1dma.c index 669f6f67449..da34b98e3de 100644 --- a/drivers/isdn/hardware/avm/b1dma.c +++ b/drivers/isdn/hardware/avm/b1dma.c @@ -883,11 +883,11 @@ int b1dmactl_read_proc(char *page, char **start, off_t off, default: s = "???"; break; } len += sprintf(page+len, "%-16s %s\n", "type", s); - if ((s = cinfo->version[VER_DRIVER]) != 0) + if ((s = cinfo->version[VER_DRIVER]) != NULL) len += sprintf(page+len, "%-16s %s\n", "ver_driver", s); - if ((s = cinfo->version[VER_CARDTYPE]) != 0) + if ((s = cinfo->version[VER_CARDTYPE]) != NULL) len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s); - if ((s = cinfo->version[VER_SERIAL]) != 0) + if ((s = cinfo->version[VER_SERIAL]) != NULL) len += sprintf(page+len, "%-16s %s\n", "ver_serial", s); if (card->cardtype != avm_m1) { @@ -970,9 +970,9 @@ static int __init b1dma_init(void) char *p; char rev[32]; - if ((p = strchr(revision, ':')) != 0 && p[1]) { + if ((p = strchr(revision, ':')) != NULL && p[1]) { strlcpy(rev, p + 2, sizeof(rev)); - if ((p = strchr(rev, '$')) != 0 && p > rev) + if ((p = strchr(rev, '$')) != NULL && p > rev) *(p-1) = 0; } else strcpy(rev, "1.0"); diff --git a/drivers/isdn/hardware/avm/b1isa.c b/drivers/isdn/hardware/avm/b1isa.c index 80fb488848b..1e288eeb5e2 100644 --- a/drivers/isdn/hardware/avm/b1isa.c +++ b/drivers/isdn/hardware/avm/b1isa.c @@ -203,9 +203,9 @@ static int __init b1isa_init(void) char rev[32]; int i; - if ((p = strchr(revision, ':')) != 0 && p[1]) { + if ((p = strchr(revision, ':')) != NULL && p[1]) { strlcpy(rev, p + 2, 32); - if ((p = strchr(rev, '$')) != 0 && p > rev) + if ((p = strchr(rev, '$')) != NULL && p > rev) *(p-1) = 0; } else strcpy(rev, "1.0"); diff --git a/drivers/isdn/hardware/avm/b1pci.c b/drivers/isdn/hardware/avm/b1pci.c index 90e2e6643d1..5b314a2c404 100644 --- a/drivers/isdn/hardware/avm/b1pci.c +++ b/drivers/isdn/hardware/avm/b1pci.c @@ -382,9 +382,9 @@ static int __init b1pci_init(void) char rev[32]; int err; - if ((p = strchr(revision, ':')) != 0 && p[1]) { + if ((p = strchr(revision, ':')) != NULL && p[1]) { strlcpy(rev, p + 2, 32); - if ((p = strchr(rev, '$')) != 0 && p > rev) + if ((p = strchr(rev, '$')) != NULL && p > rev) *(p-1) = 0; } else strcpy(rev, "1.0"); diff --git a/drivers/isdn/hardware/avm/b1pcmcia.c b/drivers/isdn/hardware/avm/b1pcmcia.c index e479c0aef38..7740403b40e 100644 --- a/drivers/isdn/hardware/avm/b1pcmcia.c +++ b/drivers/isdn/hardware/avm/b1pcmcia.c @@ -201,9 +201,9 @@ static int __init b1pcmcia_init(void) char *p; char rev[32]; - if ((p = strchr(revision, ':')) != 0 && p[1]) { + if ((p = strchr(revision, ':')) != NULL && p[1]) { strlcpy(rev, p + 2, 32); - if ((p = strchr(rev, '$')) != 0 && p > rev) + if ((p = strchr(rev, '$')) != NULL && p > rev) *(p-1) = 0; } else strcpy(rev, "1.0"); diff --git a/drivers/isdn/hardware/avm/c4.c b/drivers/isdn/hardware/avm/c4.c index 4bbbbe68807..9df1d3f66c8 100644 --- a/drivers/isdn/hardware/avm/c4.c +++ b/drivers/isdn/hardware/avm/c4.c @@ -1088,11 +1088,11 @@ static int c4_read_proc(char *page, char **start, off_t off, default: s = "???"; break; } len += sprintf(page+len, "%-16s %s\n", "type", s); - if ((s = cinfo->version[VER_DRIVER]) != 0) + if ((s = cinfo->version[VER_DRIVER]) != NULL) len += sprintf(page+len, "%-16s %s\n", "ver_driver", s); - if ((s = cinfo->version[VER_CARDTYPE]) != 0) + if ((s = cinfo->version[VER_CARDTYPE]) != NULL) len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s); - if ((s = cinfo->version[VER_SERIAL]) != 0) + if ((s = cinfo->version[VER_SERIAL]) != NULL) len += sprintf(page+len, "%-16s %s\n", "ver_serial", s); if (card->cardtype != avm_m1) { @@ -1167,7 +1167,7 @@ static int c4_add_card(struct capicardparams *p, struct pci_dev *dev, } card->mbase = ioremap(card->membase, 128); - if (card->mbase == 0) { + if (card->mbase == NULL) { printk(KERN_NOTICE "c4: can't remap memory at 0x%lx\n", card->membase); retval = -EIO; @@ -1291,9 +1291,9 @@ static int __init c4_init(void) char rev[32]; int err; - if ((p = strchr(revision, ':')) != 0 && p[1]) { + if ((p = strchr(revision, ':')) != NULL && p[1]) { strlcpy(rev, p + 2, 32); - if ((p = strchr(rev, '$')) != 0 && p > rev) + if ((p = strchr(rev, '$')) != NULL && p > rev) *(p-1) = 0; } else strcpy(rev, "1.0"); diff --git a/drivers/isdn/hardware/avm/t1isa.c b/drivers/isdn/hardware/avm/t1isa.c index 6130724e46e..e7724493738 100644 --- a/drivers/isdn/hardware/avm/t1isa.c +++ b/drivers/isdn/hardware/avm/t1isa.c @@ -551,9 +551,9 @@ static int __init t1isa_init(void) char *p; int i; - if ((p = strchr(revision, ':')) != 0 && p[1]) { + if ((p = strchr(revision, ':')) != NULL && p[1]) { strlcpy(rev, p + 2, 32); - if ((p = strchr(rev, '$')) != 0 && p > rev) + if ((p = strchr(rev, '$')) != NULL && p > rev) *(p-1) = 0; } else strcpy(rev, "1.0"); diff --git a/drivers/isdn/hardware/avm/t1pci.c b/drivers/isdn/hardware/avm/t1pci.c index d1e253c94db..e6d298d7514 100644 --- a/drivers/isdn/hardware/avm/t1pci.c +++ b/drivers/isdn/hardware/avm/t1pci.c @@ -233,9 +233,9 @@ static int __init t1pci_init(void) char rev[32]; int err; - if ((p = strchr(revision, ':')) != 0 && p[1]) { + if ((p = strchr(revision, ':')) != NULL && p[1]) { strlcpy(rev, p + 2, 32); - if ((p = strchr(rev, '$')) != 0 && p > rev) + if ((p = strchr(rev, '$')) != NULL && p > rev) *(p-1) = 0; } else strcpy(rev, "1.0"); diff --git a/drivers/isdn/hardware/eicon/divasmain.c b/drivers/isdn/hardware/eicon/divasmain.c index 6d39f936076..5fcbdccd7a5 100644 --- a/drivers/isdn/hardware/eicon/divasmain.c +++ b/drivers/isdn/hardware/eicon/divasmain.c @@ -393,7 +393,7 @@ void diva_free_dma_map(void *hdev, struct _diva_dma_map_entry *pmap) dma_addr_t dma_handle; void *addr_handle; - for (i = 0; (pmap != 0); i++) { + for (i = 0; (pmap != NULL); i++) { diva_get_dma_map_entry(pmap, i, &cpu_addr, &phys_addr); if (!cpu_addr) { break; diff --git a/drivers/isdn/hardware/eicon/divasproc.c b/drivers/isdn/hardware/eicon/divasproc.c index 0632a260699..fae895828a1 100644 --- a/drivers/isdn/hardware/eicon/divasproc.c +++ b/drivers/isdn/hardware/eicon/divasproc.c @@ -125,15 +125,11 @@ static const struct file_operations divas_fops = { int create_divas_proc(void) { - divas_proc_entry = create_proc_entry(divas_proc_name, - S_IFREG | S_IRUGO, - proc_net_eicon); + proc_create(divas_proc_name, S_IFREG | S_IRUGO, proc_net_eicon, + &divas_fops); if (!divas_proc_entry) return (0); - divas_proc_entry->proc_fops = &divas_fops; - divas_proc_entry->owner = THIS_MODULE; - return (1); } diff --git a/drivers/isdn/hardware/eicon/message.c b/drivers/isdn/hardware/eicon/message.c index 1ff98e7eb79..599fed88222 100644 --- a/drivers/isdn/hardware/eicon/message.c +++ b/drivers/isdn/hardware/eicon/message.c @@ -742,7 +742,7 @@ static void start_internal_command (dword Id, PLCI *plci, t_std_internal_comma else { i = 1; - while (plci->internal_command_queue[i] != 0) + while (plci->internal_command_queue[i] != NULL) i++; plci->internal_command_queue[i] = command_function; } @@ -758,7 +758,7 @@ static void next_internal_command (dword Id, PLCI *plci) plci->internal_command = 0; plci->internal_command_queue[0] = NULL; - while (plci->internal_command_queue[1] != 0) + while (plci->internal_command_queue[1] != NULL) { for (i = 0; i < MAX_INTERNAL_COMMAND_LEVELS - 1; i++) plci->internal_command_queue[i] = plci->internal_command_queue[i+1]; @@ -9119,7 +9119,7 @@ word AdvCodecSupport(DIVA_CAPI_ADAPTER *a, PLCI *plci, APPL *appl, byte ho dbug(1,dprintf("AdvSigPlci=0x%x",a->AdvSignalPLCI)); return 0x2001; /* codec in use by another application */ } - if(plci!=0) + if(plci!=NULL) { a->AdvSignalPLCI = plci; plci->tel=ADV_VOICE; @@ -9144,7 +9144,7 @@ word AdvCodecSupport(DIVA_CAPI_ADAPTER *a, PLCI *plci, APPL *appl, byte ho } /* indicate D-ch connect if */ } /* codec is connected OK */ - if(plci!=0) + if(plci!=NULL) { a->AdvSignalPLCI = plci; plci->tel=ADV_VOICE; @@ -9170,7 +9170,7 @@ word AdvCodecSupport(DIVA_CAPI_ADAPTER *a, PLCI *plci, APPL *appl, byte ho { if(hook_listen) return 0x300B; /* Facility not supported */ /* no hook with SCOM */ - if(plci!=0) plci->tel = CODEC; + if(plci!=NULL) plci->tel = CODEC; dbug(1,dprintf("S/SCOM codec")); /* first time we use the scom-s codec we must shut down the internal */ /* handset application of the card. This can be done by an assign with */ @@ -14604,7 +14604,7 @@ static void channel_xmit_extended_xon (PLCI * plci) { int max_ch = ARRAY_SIZE(a->ch_flow_control); int i, one_requested = 0; - if ((!plci) || (!plci->Id) || ((a = plci->adapter) == 0)) { + if ((!plci) || (!plci->Id) || ((a = plci->adapter) == NULL)) { return; } diff --git a/drivers/isdn/hisax/asuscom.c b/drivers/isdn/hisax/asuscom.c index b96f3184c2e..1f879b500d8 100644 --- a/drivers/isdn/hisax/asuscom.c +++ b/drivers/isdn/hisax/asuscom.c @@ -344,7 +344,7 @@ setup_asuscom(struct IsdnCard *card) err = pnp_activate_dev(pnp_d); if (err<0) { printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __FUNCTION__, err); + __func__, err); return(0); } card->para[1] = pnp_port_start(pnp_d, 0); diff --git a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c index 0f1db1f669b..7cabc5a1949 100644 --- a/drivers/isdn/hisax/avm_pci.c +++ b/drivers/isdn/hisax/avm_pci.c @@ -797,7 +797,7 @@ static int __devinit avm_pnp_setup(struct IsdnCardState *cs) err = pnp_activate_dev(pnp_avm_d); if (err<0) { printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __FUNCTION__, err); + __func__, err); return(0); } cs->hw.avm.cfg_reg = diff --git a/drivers/isdn/hisax/diva.c b/drivers/isdn/hisax/diva.c index 2d670856d14..018bd293e58 100644 --- a/drivers/isdn/hisax/diva.c +++ b/drivers/isdn/hisax/diva.c @@ -1088,7 +1088,7 @@ static int __devinit setup_diva_isapnp(struct IsdnCard *card) err = pnp_activate_dev(pnp_d); if (err<0) { printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __FUNCTION__, err); + __func__, err); return(0); } card->para[1] = pnp_port_start(pnp_d, 0); diff --git a/drivers/isdn/hisax/elsa.c b/drivers/isdn/hisax/elsa.c index 2c3691fda30..aa29d1cf16a 100644 --- a/drivers/isdn/hisax/elsa.c +++ b/drivers/isdn/hisax/elsa.c @@ -937,7 +937,7 @@ setup_elsa_isapnp(struct IsdnCard *card) err = pnp_activate_dev(pnp_d); if (err<0) { printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __FUNCTION__, err); + __func__, err); return(0); } card->para[1] = pnp_port_start(pnp_d, 0); diff --git a/drivers/isdn/hisax/hfc_sx.c b/drivers/isdn/hisax/hfc_sx.c index f4a213877e3..d92e8d6c2ae 100644 --- a/drivers/isdn/hisax/hfc_sx.c +++ b/drivers/isdn/hisax/hfc_sx.c @@ -1417,7 +1417,7 @@ setup_hfcsx(struct IsdnCard *card) err = pnp_activate_dev(pnp_d); if (err<0) { printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __FUNCTION__, err); + __func__, err); return(0); } card->para[1] = pnp_port_start(pnp_d, 0); diff --git a/drivers/isdn/hisax/hfc_usb.c b/drivers/isdn/hisax/hfc_usb.c index 98b0149bca6..8df889b0c1a 100644 --- a/drivers/isdn/hisax/hfc_usb.c +++ b/drivers/isdn/hisax/hfc_usb.c @@ -905,7 +905,7 @@ rx_int_complete(struct urb *urb) if (status) { printk(KERN_INFO "HFC-S USB: %s error resubmitting URB fifo(%d)\n", - __FUNCTION__, fifon); + __func__, fifon); } } @@ -1543,14 +1543,14 @@ hfc_usb_disconnect(struct usb_interface *intf) stop_isoc_chain(&context->fifos[i]); DBG(HFCUSB_DBG_INIT, "HFC-S USB: %s stopping ISOC chain Fifo(%i)", - __FUNCTION__, i); + __func__, i); } } else { if (context->fifos[i].active > 0) { context->fifos[i].active = 0; DBG(HFCUSB_DBG_INIT, "HFC-S USB: %s unlinking URB for Fifo(%i)", - __FUNCTION__, i); + __func__, i); } usb_kill_urb(context->fifos[i].urb); usb_free_urb(context->fifos[i].urb); diff --git a/drivers/isdn/hisax/hfcscard.c b/drivers/isdn/hisax/hfcscard.c index 909d6709ec1..cf082665cc8 100644 --- a/drivers/isdn/hisax/hfcscard.c +++ b/drivers/isdn/hisax/hfcscard.c @@ -193,7 +193,7 @@ setup_hfcs(struct IsdnCard *card) err = pnp_activate_dev(pnp_d); if (err<0) { printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __FUNCTION__, err); + __func__, err); return(0); } card->para[1] = pnp_port_start(pnp_d, 0); diff --git a/drivers/isdn/hisax/hisax_debug.h b/drivers/isdn/hisax/hisax_debug.h index ceafecdb103..5ed3b1c4418 100644 --- a/drivers/isdn/hisax/hisax_debug.h +++ b/drivers/isdn/hisax/hisax_debug.h @@ -27,14 +27,14 @@ #define DBG(level, format, arg...) do { \ if (level & __debug_variable) \ -printk(KERN_DEBUG "%s: " format "\n" , __FUNCTION__ , ## arg); \ +printk(KERN_DEBUG "%s: " format "\n" , __func__ , ## arg); \ } while (0) #define DBG_PACKET(level,data,count) \ - if (level & __debug_variable) dump_packet(__FUNCTION__,data,count) + if (level & __debug_variable) dump_packet(__func__,data,count) #define DBG_SKB(level,skb) \ - if ((level & __debug_variable) && skb) dump_packet(__FUNCTION__,skb->data,skb->len) + if ((level & __debug_variable) && skb) dump_packet(__func__,skb->data,skb->len) static void __attribute__((unused)) diff --git a/drivers/isdn/hisax/hisax_fcpcipnp.c b/drivers/isdn/hisax/hisax_fcpcipnp.c index 76043dedba5..c0b4db2f836 100644 --- a/drivers/isdn/hisax/hisax_fcpcipnp.c +++ b/drivers/isdn/hisax/hisax_fcpcipnp.c @@ -68,7 +68,7 @@ static struct pci_device_id fcpci_ids[] = { MODULE_DEVICE_TABLE(pci, fcpci_ids); -#ifdef __ISAPNP__ +#ifdef CONFIG_PNP static struct pnp_device_id fcpnp_ids[] __devinitdata = { { .id = "AVM0900", @@ -914,7 +914,7 @@ static int __devinit fcpci_probe(struct pci_dev *pdev, return retval; } -#ifdef __ISAPNP__ +#ifdef CONFIG_PNP static int __devinit fcpnp_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) { struct fritz_adapter *adapter; @@ -935,7 +935,7 @@ static int __devinit fcpnp_probe(struct pnp_dev *pdev, const struct pnp_device_i pnp_disable_dev(pdev); retval = pnp_activate_dev(pdev); if (retval < 0) { - printk(KERN_WARNING "%s: pnp_activate_dev(%s) ret(%d)\n", __FUNCTION__, + printk(KERN_WARNING "%s: pnp_activate_dev(%s) ret(%d)\n", __func__, (char *)dev_id->driver_data, retval); goto err_free; } @@ -974,6 +974,8 @@ static struct pnp_driver fcpnp_driver = { .remove = __devexit_p(fcpnp_remove), .id_table = fcpnp_ids, }; +#else +static struct pnp_driver fcpnp_driver; #endif static void __devexit fcpci_remove(struct pci_dev *pdev) @@ -1001,7 +1003,7 @@ static int __init hisax_fcpcipnp_init(void) retval = pci_register_driver(&fcpci_driver); if (retval) return retval; -#ifdef __ISAPNP__ +#ifdef CONFIG_PNP retval = pnp_register_driver(&fcpnp_driver); if (retval < 0) { pci_unregister_driver(&fcpci_driver); @@ -1013,7 +1015,7 @@ static int __init hisax_fcpcipnp_init(void) static void __exit hisax_fcpcipnp_exit(void) { -#ifdef __ISAPNP__ +#ifdef CONFIG_PNP pnp_unregister_driver(&fcpnp_driver); #endif pci_unregister_driver(&fcpci_driver); diff --git a/drivers/isdn/hisax/ix1_micro.c b/drivers/isdn/hisax/ix1_micro.c index 2d18d4f1e57..a92bf0d2cab 100644 --- a/drivers/isdn/hisax/ix1_micro.c +++ b/drivers/isdn/hisax/ix1_micro.c @@ -252,7 +252,7 @@ setup_ix1micro(struct IsdnCard *card) err = pnp_activate_dev(pnp_d); if (err<0) { printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __FUNCTION__, err); + __func__, err); return(0); } card->para[1] = pnp_port_start(pnp_d, 0); diff --git a/drivers/isdn/hisax/niccy.c b/drivers/isdn/hisax/niccy.c index 421b8e6763d..ef00633e1d2 100644 --- a/drivers/isdn/hisax/niccy.c +++ b/drivers/isdn/hisax/niccy.c @@ -255,7 +255,7 @@ int __devinit setup_niccy(struct IsdnCard *card) err = pnp_activate_dev(pnp_d); if (err < 0) { printk(KERN_WARNING "%s: pnp_activate_dev " - "ret(%d)\n", __FUNCTION__, err); + "ret(%d)\n", __func__, err); return 0; } card->para[1] = pnp_port_start(pnp_d, 0); diff --git a/drivers/isdn/hisax/sedlbauer.c b/drivers/isdn/hisax/sedlbauer.c index 95425f3d222..a10dfa82c73 100644 --- a/drivers/isdn/hisax/sedlbauer.c +++ b/drivers/isdn/hisax/sedlbauer.c @@ -555,7 +555,7 @@ setup_sedlbauer_isapnp(struct IsdnCard *card, int *bytecnt) err = pnp_activate_dev(pnp_d); if (err<0) { printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __FUNCTION__, err); + __func__, err); return(0); } card->para[1] = pnp_port_start(pnp_d, 0); diff --git a/drivers/isdn/hisax/st5481.h b/drivers/isdn/hisax/st5481.h index 04416bad611..2044e7173ab 100644 --- a/drivers/isdn/hisax/st5481.h +++ b/drivers/isdn/hisax/st5481.h @@ -218,13 +218,13 @@ enum { #define L1_EVENT_COUNT (EV_TIMER3 + 1) #define ERR(format, arg...) \ -printk(KERN_ERR "%s:%s: " format "\n" , __FILE__, __FUNCTION__ , ## arg) +printk(KERN_ERR "%s:%s: " format "\n" , __FILE__, __func__ , ## arg) #define WARN(format, arg...) \ -printk(KERN_WARNING "%s:%s: " format "\n" , __FILE__, __FUNCTION__ , ## arg) +printk(KERN_WARNING "%s:%s: " format "\n" , __FILE__, __func__ , ## arg) #define INFO(format, arg...) \ -printk(KERN_INFO "%s:%s: " format "\n" , __FILE__, __FUNCTION__ , ## arg) +printk(KERN_INFO "%s:%s: " format "\n" , __FILE__, __func__ , ## arg) #include "isdnhdlc.h" #include "fsm.h" @@ -406,7 +406,7 @@ struct st5481_adapter { /* * Submit an URB with error reporting. This is a macro so - * the __FUNCTION__ returns the caller function name. + * the __func__ returns the caller function name. */ #define SUBMIT_URB(urb, mem_flags) \ ({ \ @@ -470,7 +470,7 @@ extern int st5481_debug; #ifdef CONFIG_HISAX_DEBUG #define DBG_ISO_PACKET(level,urb) \ - if (level & __debug_variable) dump_iso_packet(__FUNCTION__,urb) + if (level & __debug_variable) dump_iso_packet(__func__,urb) static void __attribute__((unused)) dump_iso_packet(const char *name, struct urb *urb) diff --git a/drivers/isdn/hisax/st5481_usb.c b/drivers/isdn/hisax/st5481_usb.c index 4ada66b8b67..427a8b0520f 100644 --- a/drivers/isdn/hisax/st5481_usb.c +++ b/drivers/isdn/hisax/st5481_usb.c @@ -342,7 +342,7 @@ void st5481_release_usb(struct st5481_adapter *adapter) usb_kill_urb(intr->urb); kfree(intr->urb->transfer_buffer); usb_free_urb(intr->urb); - ctrl->urb = NULL; + intr->urb = NULL; } /* diff --git a/drivers/isdn/hisax/teles3.c b/drivers/isdn/hisax/teles3.c index 6a5e379e077..5dc9f1a4362 100644 --- a/drivers/isdn/hisax/teles3.c +++ b/drivers/isdn/hisax/teles3.c @@ -301,7 +301,7 @@ setup_teles3(struct IsdnCard *card) err = pnp_activate_dev(pnp_d); if (err<0) { printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __FUNCTION__, err); + __func__, err); return(0); } card->para[3] = pnp_port_start(pnp_d, 2); diff --git a/drivers/isdn/hysdn/hysdn_procconf.c b/drivers/isdn/hysdn/hysdn_procconf.c index 27d890b48f8..877be9922c3 100644 --- a/drivers/isdn/hysdn/hysdn_procconf.c +++ b/drivers/isdn/hysdn/hysdn_procconf.c @@ -370,6 +370,7 @@ hysdn_conf_close(struct inode *ino, struct file *filep) /******************************************************/ static const struct file_operations conf_fops = { + .owner = THIS_MODULE, .llseek = no_llseek, .read = hysdn_conf_read, .write = hysdn_conf_write, @@ -402,11 +403,9 @@ hysdn_procconf_init(void) while (card) { sprintf(conf_name, "%s%d", PROC_CONF_BASENAME, card->myid); - if ((card->procconf = (void *) create_proc_entry(conf_name, - S_IFREG | S_IRUGO | S_IWUSR, - hysdn_proc_entry)) != NULL) { - ((struct proc_dir_entry *) card->procconf)->proc_fops = &conf_fops; - ((struct proc_dir_entry *) card->procconf)->owner = THIS_MODULE; + if ((card->procconf = (void *) proc_create(conf_name, + S_IFREG | S_IRUGO | S_IWUSR, + hysdn_proc_entry)) != NULL) { hysdn_proclog_init(card); /* init the log file entry */ } card = card->next; /* next entry */ diff --git a/drivers/isdn/hysdn/hysdn_proclog.c b/drivers/isdn/hysdn/hysdn_proclog.c index 27b3991fb0e..8991d2c8ee4 100644 --- a/drivers/isdn/hysdn/hysdn_proclog.c +++ b/drivers/isdn/hysdn/hysdn_proclog.c @@ -380,6 +380,7 @@ hysdn_log_poll(struct file *file, poll_table * wait) /**************************************************/ static const struct file_operations log_fops = { + .owner = THIS_MODULE, .llseek = no_llseek, .read = hysdn_log_read, .write = hysdn_log_write, @@ -402,10 +403,9 @@ hysdn_proclog_init(hysdn_card * card) if ((pd = kzalloc(sizeof(struct procdata), GFP_KERNEL)) != NULL) { sprintf(pd->log_name, "%s%d", PROC_LOG_BASENAME, card->myid); - if ((pd->log = create_proc_entry(pd->log_name, S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry)) != NULL) { - pd->log->proc_fops = &log_fops; - pd->log->owner = THIS_MODULE; - } + pd->log = proc_create(pd->log_name, + S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry, + &log_fops); init_waitqueue_head(&(pd->rd_queue)); diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c index d4ad6992f77..0f3c66de69b 100644 --- a/drivers/isdn/i4l/isdn_common.c +++ b/drivers/isdn/i4l/isdn_common.c @@ -1924,7 +1924,7 @@ isdn_free_channel(int di, int ch, int usage) if ((di < 0) || (ch < 0)) { printk(KERN_WARNING "%s: called with invalid drv(%d) or channel(%d)\n", - __FUNCTION__, di, ch); + __func__, di, ch); return; } for (i = 0; i < ISDN_MAX_CHANNELS; i++) diff --git a/drivers/isdn/i4l/isdn_net.h b/drivers/isdn/i4l/isdn_net.h index bc2f0dd962e..be4949715d5 100644 --- a/drivers/isdn/i4l/isdn_net.h +++ b/drivers/isdn/i4l/isdn_net.h @@ -108,7 +108,7 @@ static __inline__ void isdn_net_add_to_bundle(isdn_net_dev *nd, isdn_net_local * lp = nd->queue; // printk(KERN_DEBUG "%s: lp:%s(%p) nlp:%s(%p) last(%p)\n", -// __FUNCTION__, lp->name, lp, nlp->name, nlp, lp->last); +// __func__, lp->name, lp, nlp->name, nlp, lp->last); nlp->last = lp->last; lp->last->next = nlp; lp->last = nlp; @@ -129,7 +129,7 @@ static __inline__ void isdn_net_rm_from_bundle(isdn_net_local *lp) master_lp = (isdn_net_local *) lp->master->priv; // printk(KERN_DEBUG "%s: lp:%s(%p) mlp:%s(%p) last(%p) next(%p) mndq(%p)\n", -// __FUNCTION__, lp->name, lp, master_lp->name, master_lp, lp->last, lp->next, master_lp->netdev->queue); +// __func__, lp->name, lp, master_lp->name, master_lp, lp->last, lp->next, master_lp->netdev->queue); spin_lock_irqsave(&master_lp->netdev->queue_lock, flags); lp->last->next = lp->next; lp->next->last = lp->last; @@ -141,7 +141,7 @@ static __inline__ void isdn_net_rm_from_bundle(isdn_net_local *lp) } lp->next = lp->last = lp; /* (re)set own pointers */ // printk(KERN_DEBUG "%s: mndq(%p)\n", -// __FUNCTION__, master_lp->netdev->queue); +// __func__, master_lp->netdev->queue); spin_unlock_irqrestore(&master_lp->netdev->queue_lock, flags); } diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c index 9f5fe372f83..127cfdad68e 100644 --- a/drivers/isdn/i4l/isdn_ppp.c +++ b/drivers/isdn/i4l/isdn_ppp.c @@ -110,7 +110,7 @@ isdn_ppp_free(isdn_net_local * lp) if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) { printk(KERN_ERR "%s: ppp_slot(%d) out of range\n", - __FUNCTION__, lp->ppp_slot); + __func__, lp->ppp_slot); return 0; } @@ -127,7 +127,7 @@ isdn_ppp_free(isdn_net_local * lp) #endif /* CONFIG_ISDN_MPP */ if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) { printk(KERN_ERR "%s: ppp_slot(%d) now invalid\n", - __FUNCTION__, lp->ppp_slot); + __func__, lp->ppp_slot); return 0; } is = ippp_table[lp->ppp_slot]; @@ -226,7 +226,7 @@ isdn_ppp_wakeup_daemon(isdn_net_local * lp) { if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) { printk(KERN_ERR "%s: ppp_slot(%d) out of range\n", - __FUNCTION__, lp->ppp_slot); + __func__, lp->ppp_slot); return; } ippp_table[lp->ppp_slot]->state = IPPP_OPEN | IPPP_CONNECT | IPPP_NOBLOCK; @@ -245,7 +245,7 @@ isdn_ppp_closewait(int slot) if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { printk(KERN_ERR "%s: slot(%d) out of range\n", - __FUNCTION__, slot); + __func__, slot); return 0; } is = ippp_table[slot]; @@ -343,7 +343,7 @@ isdn_ppp_release(int min, struct file *file) is = file->private_data; if (!is) { - printk(KERN_ERR "%s: no file->private_data\n", __FUNCTION__); + printk(KERN_ERR "%s: no file->private_data\n", __func__); return; } if (is->debug & 0x1) @@ -353,7 +353,7 @@ isdn_ppp_release(int min, struct file *file) isdn_net_dev *p = is->lp->netdev; if (!p) { - printk(KERN_ERR "%s: no lp->netdev\n", __FUNCTION__); + printk(KERN_ERR "%s: no lp->netdev\n", __func__); return; } is->state &= ~IPPP_CONNECT; /* -> effect: no call of wakeup */ @@ -1080,7 +1080,7 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff printk(KERN_DEBUG "isdn_ppp: VJC_UNCOMP\n"); if (net_dev->local->ppp_slot < 0) { printk(KERN_ERR "%s: net_dev->local->ppp_slot(%d) out of range\n", - __FUNCTION__, net_dev->local->ppp_slot); + __func__, net_dev->local->ppp_slot); goto drop_packet; } if (slhc_remember(ippp_table[net_dev->local->ppp_slot]->slcomp, skb->data, skb->len) <= 0) { @@ -1107,7 +1107,7 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff skb_old->len); if (net_dev->local->ppp_slot < 0) { printk(KERN_ERR "%s: net_dev->local->ppp_slot(%d) out of range\n", - __FUNCTION__, net_dev->local->ppp_slot); + __func__, net_dev->local->ppp_slot); goto drop_packet; } pkt_len = slhc_uncompress(ippp_table[net_dev->local->ppp_slot]->slcomp, @@ -1553,7 +1553,7 @@ static int isdn_ppp_mp_init( isdn_net_local * lp, ippp_bundle * add_to ) if (lp->ppp_slot < 0) { printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n", - __FUNCTION__, lp->ppp_slot); + __func__, lp->ppp_slot); return(-EINVAL); } @@ -1604,7 +1604,7 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, slot = lp->ppp_slot; if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { printk(KERN_ERR "%s: lp->ppp_slot(%d)\n", - __FUNCTION__, lp->ppp_slot); + __func__, lp->ppp_slot); stats->frame_drops++; dev_kfree_skb(skb); spin_unlock_irqrestore(&mp->lock, flags); @@ -1641,7 +1641,7 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, slot = lpq->ppp_slot; if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { printk(KERN_ERR "%s: lpq->ppp_slot(%d)\n", - __FUNCTION__, lpq->ppp_slot); + __func__, lpq->ppp_slot); } else { u32 lls = ippp_table[slot]->last_link_seqno; if (MP_LT(lls, minseq)) @@ -1875,7 +1875,7 @@ void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp, if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) { printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n", - __FUNCTION__, lp->ppp_slot); + __func__, lp->ppp_slot); return; } if( MP_FLAGS(from) == (MP_BEGIN_FRAG | MP_END_FRAG) ) { @@ -2655,7 +2655,7 @@ static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, lp->ppp_slot); if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) { printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n", - __FUNCTION__, lp->ppp_slot); + __func__, lp->ppp_slot); return; } is = ippp_table[lp->ppp_slot]; @@ -2665,7 +2665,7 @@ static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, int slot = ((isdn_net_local *) (lp->master->priv))->ppp_slot; if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { printk(KERN_ERR "%s: slot(%d) out of range\n", - __FUNCTION__, slot); + __func__, slot); return; } mis = ippp_table[slot]; @@ -2829,7 +2829,7 @@ static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, struct return; if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n", - __FUNCTION__, slot); + __func__, slot); return; } is = ippp_table[slot]; @@ -2852,7 +2852,7 @@ static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, struct slot = ((isdn_net_local *) (lp->master->priv))->ppp_slot; if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { printk(KERN_ERR "%s: slot(%d) out of range\n", - __FUNCTION__, slot); + __func__, slot); return; } mis = ippp_table[slot]; diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c index 133eb18e65c..8af0df1d5b8 100644 --- a/drivers/isdn/i4l/isdn_tty.c +++ b/drivers/isdn/i4l/isdn_tty.c @@ -1347,7 +1347,7 @@ isdn_tty_tiocmget(struct tty_struct *tty, struct file *file) modem_info *info = (modem_info *) tty->driver_data; u_char control, status; - if (isdn_tty_paranoia_check(info, tty->name, __FUNCTION__)) + if (isdn_tty_paranoia_check(info, tty->name, __func__)) return -ENODEV; if (tty->flags & (1 << TTY_IO_ERROR)) return -EIO; @@ -1372,7 +1372,7 @@ isdn_tty_tiocmset(struct tty_struct *tty, struct file *file, { modem_info *info = (modem_info *) tty->driver_data; - if (isdn_tty_paranoia_check(info, tty->name, __FUNCTION__)) + if (isdn_tty_paranoia_check(info, tty->name, __func__)) return -ENODEV; if (tty->flags & (1 << TTY_IO_ERROR)) return -EIO; @@ -1608,7 +1608,7 @@ isdn_tty_open(struct tty_struct *tty, struct file *filp) if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_open")) return -ENODEV; if (!try_module_get(info->owner)) { - printk(KERN_WARNING "%s: cannot reserve module\n", __FUNCTION__); + printk(KERN_WARNING "%s: cannot reserve module\n", __func__); return -ENODEV; } #ifdef ISDN_DEBUG_MODEM_OPEN diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index ac05a928f76..b3c54be7455 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -105,7 +105,7 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev) led_cdev->dev = device_create(leds_class, parent, 0, "%s", led_cdev->name); - if (unlikely(IS_ERR(led_cdev->dev))) + if (IS_ERR(led_cdev->dev)) return PTR_ERR(led_cdev->dev); dev_set_drvdata(led_cdev->dev, led_cdev); diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig index 77f50b63a97..b52659620d5 100644 --- a/drivers/macintosh/Kconfig +++ b/drivers/macintosh/Kconfig @@ -234,6 +234,14 @@ config WINDFARM_PM112 which are the recent dual and quad G5 machines using the 970MP dual-core processor. +config WINDFARM_PM121 + tristate "Support for thermal management on PowerMac12,1" + depends on WINDFARM && I2C && PMAC_SMU + select I2C_POWERMAC + help + This driver provides thermal control for the PowerMac12,1 + which is the iMac G5 (iSight). + config ANSLCD tristate "Support for ANS LCD display" depends on ADB_CUDA && PPC_PMAC diff --git a/drivers/macintosh/Makefile b/drivers/macintosh/Makefile index 2dfc3f4eaf4..e3132efa17c 100644 --- a/drivers/macintosh/Makefile +++ b/drivers/macintosh/Makefile @@ -42,4 +42,9 @@ obj-$(CONFIG_WINDFARM_PM112) += windfarm_pm112.o windfarm_smu_sat.o \ windfarm_smu_sensors.o \ windfarm_max6690_sensor.o \ windfarm_lm75_sensor.o windfarm_pid.o +obj-$(CONFIG_WINDFARM_PM121) += windfarm_pm121.o windfarm_smu_sat.o \ + windfarm_smu_controls.o \ + windfarm_smu_sensors.o \ + windfarm_max6690_sensor.o \ + windfarm_lm75_sensor.o windfarm_pid.o obj-$(CONFIG_PMAC_RACKMETER) += rack-meter.o diff --git a/drivers/macintosh/windfarm_lm75_sensor.c b/drivers/macintosh/windfarm_lm75_sensor.c index 7e10c3ab4d5..b92b959fe16 100644 --- a/drivers/macintosh/windfarm_lm75_sensor.c +++ b/drivers/macintosh/windfarm_lm75_sensor.c @@ -127,6 +127,12 @@ static struct wf_lm75_sensor *wf_lm75_create(struct i2c_adapter *adapter, */ if (!strcmp(loc, "Hard drive") || !strcmp(loc, "DRIVE BAY")) lm->sens.name = "hd-temp"; + else if (!strcmp(loc, "Incoming Air Temp")) + lm->sens.name = "incoming-air-temp"; + else if (!strcmp(loc, "ODD Temp")) + lm->sens.name = "optical-drive-temp"; + else if (!strcmp(loc, "HD Temp")) + lm->sens.name = "hard-drive-temp"; else goto fail; diff --git a/drivers/macintosh/windfarm_max6690_sensor.c b/drivers/macintosh/windfarm_max6690_sensor.c index 5f03aab9fb5..e207a90d6b2 100644 --- a/drivers/macintosh/windfarm_max6690_sensor.c +++ b/drivers/macintosh/windfarm_max6690_sensor.c @@ -77,18 +77,28 @@ static struct wf_sensor_ops wf_max6690_ops = { .owner = THIS_MODULE, }; -static void wf_max6690_create(struct i2c_adapter *adapter, u8 addr) +static void wf_max6690_create(struct i2c_adapter *adapter, u8 addr, + const char *loc) { struct wf_6690_sensor *max; - char *name = "backside-temp"; + char *name; max = kzalloc(sizeof(struct wf_6690_sensor), GFP_KERNEL); if (max == NULL) { printk(KERN_ERR "windfarm: Couldn't create MAX6690 sensor %s: " - "no memory\n", name); + "no memory\n", loc); return; } + if (!strcmp(loc, "BACKSIDE")) + name = "backside-temp"; + else if (!strcmp(loc, "NB Ambient")) + name = "north-bridge-temp"; + else if (!strcmp(loc, "GPU Ambient")) + name = "gpu-temp"; + else + goto fail; + max->sens.ops = &wf_max6690_ops; max->sens.name = name; max->i2c.addr = addr >> 1; @@ -138,9 +148,7 @@ static int wf_max6690_attach(struct i2c_adapter *adapter) if (loc == NULL || addr == 0) continue; printk("found max6690, loc=%s addr=0x%02x\n", loc, addr); - if (strcmp(loc, "BACKSIDE")) - continue; - wf_max6690_create(adapter, addr); + wf_max6690_create(adapter, addr, loc); } return 0; diff --git a/drivers/macintosh/windfarm_pm121.c b/drivers/macintosh/windfarm_pm121.c new file mode 100644 index 00000000000..66ec4fb115b --- /dev/null +++ b/drivers/macintosh/windfarm_pm121.c @@ -0,0 +1,1040 @@ +/* + * Windfarm PowerMac thermal control. iMac G5 iSight + * + * (c) Copyright 2007 Étienne Bersac <bersace@gmail.com> + * + * Bits & pieces from windfarm_pm81.c by (c) Copyright 2005 Benjamin + * Herrenschmidt, IBM Corp. <benh@kernel.crashing.org> + * + * Released under the term of the GNU GPL v2. + * + * + * + * PowerMac12,1 + * ============ + * + * + * The algorithm used is the PID control algorithm, used the same way + * the published Darwin code does, using the same values that are + * present in the Darwin 8.10 snapshot property lists (note however + * that none of the code has been re-used, it's a complete + * re-implementation + * + * There is two models using PowerMac12,1. Model 2 is iMac G5 iSight + * 17" while Model 3 is iMac G5 20". They do have both the same + * controls with a tiny difference. The control-ids of hard-drive-fan + * and cpu-fan is swapped. + * + * + * Target Correction : + * + * controls have a target correction calculated as : + * + * new_min = ((((average_power * slope) >> 16) + offset) >> 16) + min_value + * new_value = max(new_value, max(new_min, 0)) + * + * OD Fan control correction. + * + * # model_id: 2 + * offset : -19563152 + * slope : 1956315 + * + * # model_id: 3 + * offset : -15650652 + * slope : 1565065 + * + * HD Fan control correction. + * + * # model_id: 2 + * offset : -15650652 + * slope : 1565065 + * + * # model_id: 3 + * offset : -19563152 + * slope : 1956315 + * + * CPU Fan control correction. + * + * # model_id: 2 + * offset : -25431900 + * slope : 2543190 + * + * # model_id: 3 + * offset : -15650652 + * slope : 1565065 + * + * + * Target rubber-banding : + * + * Some controls have a target correction which depends on another + * control value. The correction is computed in the following way : + * + * new_min = ref_value * slope + offset + * + * ref_value is the value of the reference control. If new_min is + * greater than 0, then we correct the target value using : + * + * new_target = max (new_target, new_min >> 16) + * + * + * # model_id : 2 + * control : cpu-fan + * ref : optical-drive-fan + * offset : -15650652 + * slope : 1565065 + * + * # model_id : 3 + * control : optical-drive-fan + * ref : hard-drive-fan + * offset : -32768000 + * slope : 65536 + * + * + * In order to have the moste efficient correction with those + * dependencies, we must trigger HD loop before OD loop before CPU + * loop. + * + * + * The various control loops found in Darwin config file are: + * + * HD Fan control loop. + * + * # model_id: 2 + * control : hard-drive-fan + * sensor : hard-drive-temp + * PID params : G_d = 0x00000000 + * G_p = 0x002D70A3 + * G_r = 0x00019999 + * History = 2 entries + * Input target = 0x370000 + * Interval = 5s + * + * # model_id: 3 + * control : hard-drive-fan + * sensor : hard-drive-temp + * PID params : G_d = 0x00000000 + * G_p = 0x002170A3 + * G_r = 0x00019999 + * History = 2 entries + * Input target = 0x370000 + * Interval = 5s + * + * OD Fan control loop. + * + * # model_id: 2 + * control : optical-drive-fan + * sensor : optical-drive-temp + * PID params : G_d = 0x00000000 + * G_p = 0x001FAE14 + * G_r = 0x00019999 + * History = 2 entries + * Input target = 0x320000 + * Interval = 5s + * + * # model_id: 3 + * control : optical-drive-fan + * sensor : optical-drive-temp + * PID params : G_d = 0x00000000 + * G_p = 0x001FAE14 + * G_r = 0x00019999 + * History = 2 entries + * Input target = 0x320000 + * Interval = 5s + * + * GPU Fan control loop. + * + * # model_id: 2 + * control : hard-drive-fan + * sensor : gpu-temp + * PID params : G_d = 0x00000000 + * G_p = 0x002A6666 + * G_r = 0x00019999 + * History = 2 entries + * Input target = 0x5A0000 + * Interval = 5s + * + * # model_id: 3 + * control : cpu-fan + * sensor : gpu-temp + * PID params : G_d = 0x00000000 + * G_p = 0x0010CCCC + * G_r = 0x00019999 + * History = 2 entries + * Input target = 0x500000 + * Interval = 5s + * + * KODIAK (aka northbridge) Fan control loop. + * + * # model_id: 2 + * control : optical-drive-fan + * sensor : north-bridge-temp + * PID params : G_d = 0x00000000 + * G_p = 0x003BD70A + * G_r = 0x00019999 + * History = 2 entries + * Input target = 0x550000 + * Interval = 5s + * + * # model_id: 3 + * control : hard-drive-fan + * sensor : north-bridge-temp + * PID params : G_d = 0x00000000 + * G_p = 0x0030F5C2 + * G_r = 0x00019999 + * History = 2 entries + * Input target = 0x550000 + * Interval = 5s + * + * CPU Fan control loop. + * + * control : cpu-fan + * sensors : cpu-temp, cpu-power + * PID params : from SDB partition + * + * + * CPU Slew control loop. + * + * control : cpufreq-clamp + * sensor : cpu-temp + * + */ + +#undef DEBUG + +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/spinlock.h> +#include <linux/wait.h> +#include <linux/kmod.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <asm/prom.h> +#include <asm/machdep.h> +#include <asm/io.h> +#include <asm/system.h> +#include <asm/sections.h> +#include <asm/smu.h> + +#include "windfarm.h" +#include "windfarm_pid.h" + +#define VERSION "0.3" + +static int pm121_mach_model; /* machine model id */ + +/* Controls & sensors */ +static struct wf_sensor *sensor_cpu_power; +static struct wf_sensor *sensor_cpu_temp; +static struct wf_sensor *sensor_cpu_voltage; +static struct wf_sensor *sensor_cpu_current; +static struct wf_sensor *sensor_gpu_temp; +static struct wf_sensor *sensor_north_bridge_temp; +static struct wf_sensor *sensor_hard_drive_temp; +static struct wf_sensor *sensor_optical_drive_temp; +static struct wf_sensor *sensor_incoming_air_temp; /* unused ! */ + +enum { + FAN_CPU, + FAN_HD, + FAN_OD, + CPUFREQ, + N_CONTROLS +}; +static struct wf_control *controls[N_CONTROLS] = {}; + +/* Set to kick the control loop into life */ +static int pm121_all_controls_ok, pm121_all_sensors_ok, pm121_started; + +enum { + FAILURE_FAN = 1 << 0, + FAILURE_SENSOR = 1 << 1, + FAILURE_OVERTEMP = 1 << 2 +}; + +/* All sys loops. Note the HD before the OD loop in order to have it + run before. */ +enum { + LOOP_GPU, /* control = hd or cpu, but luckily, + it doesn't matter */ + LOOP_HD, /* control = hd */ + LOOP_KODIAK, /* control = hd or od */ + LOOP_OD, /* control = od */ + N_LOOPS +}; + +static const char *loop_names[N_LOOPS] = { + "GPU", + "HD", + "KODIAK", + "OD", +}; + +#define PM121_NUM_CONFIGS 2 + +static unsigned int pm121_failure_state; +static int pm121_readjust, pm121_skipping; +static s32 average_power; + +struct pm121_correction { + int offset; + int slope; +}; + +static struct pm121_correction corrections[N_CONTROLS][PM121_NUM_CONFIGS] = { + /* FAN_OD */ + { + /* MODEL 2 */ + { .offset = -19563152, + .slope = 1956315 + }, + /* MODEL 3 */ + { .offset = -15650652, + .slope = 1565065 + }, + }, + /* FAN_HD */ + { + /* MODEL 2 */ + { .offset = -15650652, + .slope = 1565065 + }, + /* MODEL 3 */ + { .offset = -19563152, + .slope = 1956315 + }, + }, + /* FAN_CPU */ + { + /* MODEL 2 */ + { .offset = -25431900, + .slope = 2543190 + }, + /* MODEL 3 */ + { .offset = -15650652, + .slope = 1565065 + }, + }, + /* CPUFREQ has no correction (and is not implemented at all) */ +}; + +struct pm121_connection { + unsigned int control_id; + unsigned int ref_id; + struct pm121_correction correction; +}; + +static struct pm121_connection pm121_connections[] = { + /* MODEL 2 */ + { .control_id = FAN_CPU, + .ref_id = FAN_OD, + { .offset = -32768000, + .slope = 65536 + } + }, + /* MODEL 3 */ + { .control_id = FAN_OD, + .ref_id = FAN_HD, + { .offset = -32768000, + .slope = 65536 + } + }, +}; + +/* pointer to the current model connection */ +static struct pm121_connection *pm121_connection; + +/* + * ****** System Fans Control Loop ****** + * + */ + +/* Since each loop handles only one control and we want to avoid + * writing virtual control, we store the control correction with the + * loop params. Some data are not set, there are common to all loop + * and thus, hardcoded. + */ +struct pm121_sys_param { + /* purely informative since we use mach_model-2 as index */ + int model_id; + struct wf_sensor **sensor; /* use sensor_id instead ? */ + s32 gp, itarget; + unsigned int control_id; +}; + +static struct pm121_sys_param +pm121_sys_all_params[N_LOOPS][PM121_NUM_CONFIGS] = { + /* GPU Fan control loop */ + { + { .model_id = 2, + .sensor = &sensor_gpu_temp, + .gp = 0x002A6666, + .itarget = 0x5A0000, + .control_id = FAN_HD, + }, + { .model_id = 3, + .sensor = &sensor_gpu_temp, + .gp = 0x0010CCCC, + .itarget = 0x500000, + .control_id = FAN_CPU, + }, + }, + /* HD Fan control loop */ + { + { .model_id = 2, + .sensor = &sensor_hard_drive_temp, + .gp = 0x002D70A3, + .itarget = 0x370000, + .control_id = FAN_HD, + }, + { .model_id = 3, + .sensor = &sensor_hard_drive_temp, + .gp = 0x002170A3, + .itarget = 0x370000, + .control_id = FAN_HD, + }, + }, + /* KODIAK Fan control loop */ + { + { .model_id = 2, + .sensor = &sensor_north_bridge_temp, + .gp = 0x003BD70A, + .itarget = 0x550000, + .control_id = FAN_OD, + }, + { .model_id = 3, + .sensor = &sensor_north_bridge_temp, + .gp = 0x0030F5C2, + .itarget = 0x550000, + .control_id = FAN_HD, + }, + }, + /* OD Fan control loop */ + { + { .model_id = 2, + .sensor = &sensor_optical_drive_temp, + .gp = 0x001FAE14, + .itarget = 0x320000, + .control_id = FAN_OD, + }, + { .model_id = 3, + .sensor = &sensor_optical_drive_temp, + .gp = 0x001FAE14, + .itarget = 0x320000, + .control_id = FAN_OD, + }, + }, +}; + +/* the hardcoded values */ +#define PM121_SYS_GD 0x00000000 +#define PM121_SYS_GR 0x00019999 +#define PM121_SYS_HISTORY_SIZE 2 +#define PM121_SYS_INTERVAL 5 + +/* State data used by the system fans control loop + */ +struct pm121_sys_state { + int ticks; + s32 setpoint; + struct wf_pid_state pid; +}; + +struct pm121_sys_state *pm121_sys_state[N_LOOPS] = {}; + +/* + * ****** CPU Fans Control Loop ****** + * + */ + +#define PM121_CPU_INTERVAL 1 + +/* State data used by the cpu fans control loop + */ +struct pm121_cpu_state { + int ticks; + s32 setpoint; + struct wf_cpu_pid_state pid; +}; + +static struct pm121_cpu_state *pm121_cpu_state; + + + +/* + * ***** Implementation ***** + * + */ + +/* correction the value using the output-low-bound correction algo */ +static s32 pm121_correct(s32 new_setpoint, + unsigned int control_id, + s32 min) +{ + s32 new_min; + struct pm121_correction *correction; + correction = &corrections[control_id][pm121_mach_model - 2]; + + new_min = (average_power * correction->slope) >> 16; + new_min += correction->offset; + new_min = (new_min >> 16) + min; + + return max(new_setpoint, max(new_min, 0)); +} + +static s32 pm121_connect(unsigned int control_id, s32 setpoint) +{ + s32 new_min, value, new_setpoint; + + if (pm121_connection->control_id == control_id) { + controls[control_id]->ops->get_value(controls[control_id], + &value); + new_min = value * pm121_connection->correction.slope; + new_min += pm121_connection->correction.offset; + if (new_min > 0) { + new_setpoint = max(setpoint, (new_min >> 16)); + if (new_setpoint != setpoint) { + pr_debug("pm121: %s depending on %s, " + "corrected from %d to %d RPM\n", + controls[control_id]->name, + controls[pm121_connection->ref_id]->name, + (int) setpoint, (int) new_setpoint); + } + } else + new_setpoint = setpoint; + } + /* no connection */ + else + new_setpoint = setpoint; + + return new_setpoint; +} + +/* FAN LOOPS */ +static void pm121_create_sys_fans(int loop_id) +{ + struct pm121_sys_param *param = NULL; + struct wf_pid_param pid_param; + struct wf_control *control = NULL; + int i; + + /* First, locate the params for this model */ + for (i = 0; i < PM121_NUM_CONFIGS; i++) { + if (pm121_sys_all_params[loop_id][i].model_id == pm121_mach_model) { + param = &(pm121_sys_all_params[loop_id][i]); + break; + } + } + + /* No params found, put fans to max */ + if (param == NULL) { + printk(KERN_WARNING "pm121: %s fan config not found " + " for this machine model\n", + loop_names[loop_id]); + goto fail; + } + + control = controls[param->control_id]; + + /* Alloc & initialize state */ + pm121_sys_state[loop_id] = kmalloc(sizeof(struct pm121_sys_state), + GFP_KERNEL); + if (pm121_sys_state[loop_id] == NULL) { + printk(KERN_WARNING "pm121: Memory allocation error\n"); + goto fail; + } + pm121_sys_state[loop_id]->ticks = 1; + + /* Fill PID params */ + pid_param.gd = PM121_SYS_GD; + pid_param.gp = param->gp; + pid_param.gr = PM121_SYS_GR; + pid_param.interval = PM121_SYS_INTERVAL; + pid_param.history_len = PM121_SYS_HISTORY_SIZE; + pid_param.itarget = param->itarget; + pid_param.min = control->ops->get_min(control); + pid_param.max = control->ops->get_max(control); + + wf_pid_init(&pm121_sys_state[loop_id]->pid, &pid_param); + + pr_debug("pm121: %s Fan control loop initialized.\n" + " itarged=%d.%03d, min=%d RPM, max=%d RPM\n", + loop_names[loop_id], FIX32TOPRINT(pid_param.itarget), + pid_param.min, pid_param.max); + return; + + fail: + /* note that this is not optimal since another loop may still + control the same control */ + printk(KERN_WARNING "pm121: failed to set up %s loop " + "setting \"%s\" to max speed.\n", + loop_names[loop_id], control->name); + + if (control) + wf_control_set_max(control); +} + +static void pm121_sys_fans_tick(int loop_id) +{ + struct pm121_sys_param *param; + struct pm121_sys_state *st; + struct wf_sensor *sensor; + struct wf_control *control; + s32 temp, new_setpoint; + int rc; + + param = &(pm121_sys_all_params[loop_id][pm121_mach_model-2]); + st = pm121_sys_state[loop_id]; + sensor = *(param->sensor); + control = controls[param->control_id]; + + if (--st->ticks != 0) { + if (pm121_readjust) + goto readjust; + return; + } + st->ticks = PM121_SYS_INTERVAL; + + rc = sensor->ops->get_value(sensor, &temp); + if (rc) { + printk(KERN_WARNING "windfarm: %s sensor error %d\n", + sensor->name, rc); + pm121_failure_state |= FAILURE_SENSOR; + return; + } + + pr_debug("pm121: %s Fan tick ! %s: %d.%03d\n", + loop_names[loop_id], sensor->name, + FIX32TOPRINT(temp)); + + new_setpoint = wf_pid_run(&st->pid, temp); + + /* correction */ + new_setpoint = pm121_correct(new_setpoint, + param->control_id, + st->pid.param.min); + /* linked corretion */ + new_setpoint = pm121_connect(param->control_id, new_setpoint); + + if (new_setpoint == st->setpoint) + return; + st->setpoint = new_setpoint; + pr_debug("pm121: %s corrected setpoint: %d RPM\n", + control->name, (int)new_setpoint); + readjust: + if (control && pm121_failure_state == 0) { + rc = control->ops->set_value(control, st->setpoint); + if (rc) { + printk(KERN_WARNING "windfarm: %s fan error %d\n", + control->name, rc); + pm121_failure_state |= FAILURE_FAN; + } + } +} + + +/* CPU LOOP */ +static void pm121_create_cpu_fans(void) +{ + struct wf_cpu_pid_param pid_param; + const struct smu_sdbp_header *hdr; + struct smu_sdbp_cpupiddata *piddata; + struct smu_sdbp_fvt *fvt; + struct wf_control *fan_cpu; + s32 tmax, tdelta, maxpow, powadj; + + fan_cpu = controls[FAN_CPU]; + + /* First, locate the PID params in SMU SBD */ + hdr = smu_get_sdb_partition(SMU_SDB_CPUPIDDATA_ID, NULL); + if (hdr == 0) { + printk(KERN_WARNING "pm121: CPU PID fan config not found.\n"); + goto fail; + } + piddata = (struct smu_sdbp_cpupiddata *)&hdr[1]; + + /* Get the FVT params for operating point 0 (the only supported one + * for now) in order to get tmax + */ + hdr = smu_get_sdb_partition(SMU_SDB_FVT_ID, NULL); + if (hdr) { + fvt = (struct smu_sdbp_fvt *)&hdr[1]; + tmax = ((s32)fvt->maxtemp) << 16; + } else + tmax = 0x5e0000; /* 94 degree default */ + + /* Alloc & initialize state */ + pm121_cpu_state = kmalloc(sizeof(struct pm121_cpu_state), + GFP_KERNEL); + if (pm121_cpu_state == NULL) + goto fail; + pm121_cpu_state->ticks = 1; + + /* Fill PID params */ + pid_param.interval = PM121_CPU_INTERVAL; + pid_param.history_len = piddata->history_len; + if (pid_param.history_len > WF_CPU_PID_MAX_HISTORY) { + printk(KERN_WARNING "pm121: History size overflow on " + "CPU control loop (%d)\n", piddata->history_len); + pid_param.history_len = WF_CPU_PID_MAX_HISTORY; + } + pid_param.gd = piddata->gd; + pid_param.gp = piddata->gp; + pid_param.gr = piddata->gr / pid_param.history_len; + + tdelta = ((s32)piddata->target_temp_delta) << 16; + maxpow = ((s32)piddata->max_power) << 16; + powadj = ((s32)piddata->power_adj) << 16; + + pid_param.tmax = tmax; + pid_param.ttarget = tmax - tdelta; + pid_param.pmaxadj = maxpow - powadj; + + pid_param.min = fan_cpu->ops->get_min(fan_cpu); + pid_param.max = fan_cpu->ops->get_max(fan_cpu); + + wf_cpu_pid_init(&pm121_cpu_state->pid, &pid_param); + + pr_debug("pm121: CPU Fan control initialized.\n"); + pr_debug(" ttarged=%d.%03d, tmax=%d.%03d, min=%d RPM, max=%d RPM,\n", + FIX32TOPRINT(pid_param.ttarget), FIX32TOPRINT(pid_param.tmax), + pid_param.min, pid_param.max); + + return; + + fail: + printk(KERN_WARNING "pm121: CPU fan config not found, max fan speed\n"); + + if (controls[CPUFREQ]) + wf_control_set_max(controls[CPUFREQ]); + if (fan_cpu) + wf_control_set_max(fan_cpu); +} + + +static void pm121_cpu_fans_tick(struct pm121_cpu_state *st) +{ + s32 new_setpoint, temp, power; + struct wf_control *fan_cpu = NULL; + int rc; + + if (--st->ticks != 0) { + if (pm121_readjust) + goto readjust; + return; + } + st->ticks = PM121_CPU_INTERVAL; + + fan_cpu = controls[FAN_CPU]; + + rc = sensor_cpu_temp->ops->get_value(sensor_cpu_temp, &temp); + if (rc) { + printk(KERN_WARNING "pm121: CPU temp sensor error %d\n", + rc); + pm121_failure_state |= FAILURE_SENSOR; + return; + } + + rc = sensor_cpu_power->ops->get_value(sensor_cpu_power, &power); + if (rc) { + printk(KERN_WARNING "pm121: CPU power sensor error %d\n", + rc); + pm121_failure_state |= FAILURE_SENSOR; + return; + } + + pr_debug("pm121: CPU Fans tick ! CPU temp: %d.%03d°C, power: %d.%03d\n", + FIX32TOPRINT(temp), FIX32TOPRINT(power)); + + if (temp > st->pid.param.tmax) + pm121_failure_state |= FAILURE_OVERTEMP; + + new_setpoint = wf_cpu_pid_run(&st->pid, power, temp); + + /* correction */ + new_setpoint = pm121_correct(new_setpoint, + FAN_CPU, + st->pid.param.min); + + /* connected correction */ + new_setpoint = pm121_connect(FAN_CPU, new_setpoint); + + if (st->setpoint == new_setpoint) + return; + st->setpoint = new_setpoint; + pr_debug("pm121: CPU corrected setpoint: %d RPM\n", (int)new_setpoint); + + readjust: + if (fan_cpu && pm121_failure_state == 0) { + rc = fan_cpu->ops->set_value(fan_cpu, st->setpoint); + if (rc) { + printk(KERN_WARNING "pm121: %s fan error %d\n", + fan_cpu->name, rc); + pm121_failure_state |= FAILURE_FAN; + } + } +} + +/* + * ****** Common ****** + * + */ + +static void pm121_tick(void) +{ + unsigned int last_failure = pm121_failure_state; + unsigned int new_failure; + s32 total_power; + int i; + + if (!pm121_started) { + pr_debug("pm121: creating control loops !\n"); + for (i = 0; i < N_LOOPS; i++) + pm121_create_sys_fans(i); + + pm121_create_cpu_fans(); + pm121_started = 1; + } + + /* skipping ticks */ + if (pm121_skipping && --pm121_skipping) + return; + + /* compute average power */ + total_power = 0; + for (i = 0; i < pm121_cpu_state->pid.param.history_len; i++) + total_power += pm121_cpu_state->pid.powers[i]; + + average_power = total_power / pm121_cpu_state->pid.param.history_len; + + + pm121_failure_state = 0; + for (i = 0 ; i < N_LOOPS; i++) { + if (pm121_sys_state[i]) + pm121_sys_fans_tick(i); + } + + if (pm121_cpu_state) + pm121_cpu_fans_tick(pm121_cpu_state); + + pm121_readjust = 0; + new_failure = pm121_failure_state & ~last_failure; + + /* If entering failure mode, clamp cpufreq and ramp all + * fans to full speed. + */ + if (pm121_failure_state && !last_failure) { + for (i = 0; i < N_CONTROLS; i++) { + if (controls[i]) + wf_control_set_max(controls[i]); + } + } + + /* If leaving failure mode, unclamp cpufreq and readjust + * all fans on next iteration + */ + if (!pm121_failure_state && last_failure) { + if (controls[CPUFREQ]) + wf_control_set_min(controls[CPUFREQ]); + pm121_readjust = 1; + } + + /* Overtemp condition detected, notify and start skipping a couple + * ticks to let the temperature go down + */ + if (new_failure & FAILURE_OVERTEMP) { + wf_set_overtemp(); + pm121_skipping = 2; + } + + /* We only clear the overtemp condition if overtemp is cleared + * _and_ no other failure is present. Since a sensor error will + * clear the overtemp condition (can't measure temperature) at + * the control loop levels, but we don't want to keep it clear + * here in this case + */ + if (new_failure == 0 && last_failure & FAILURE_OVERTEMP) + wf_clear_overtemp(); +} + + +static struct wf_control* pm121_register_control(struct wf_control *ct, + const char *match, + unsigned int id) +{ + if (controls[id] == NULL && !strcmp(ct->name, match)) { + if (wf_get_control(ct) == 0) + controls[id] = ct; + } + return controls[id]; +} + +static void pm121_new_control(struct wf_control *ct) +{ + int all = 1; + + if (pm121_all_controls_ok) + return; + + all = pm121_register_control(ct, "optical-drive-fan", FAN_OD) && all; + all = pm121_register_control(ct, "hard-drive-fan", FAN_HD) && all; + all = pm121_register_control(ct, "cpu-fan", FAN_CPU) && all; + all = pm121_register_control(ct, "cpufreq-clamp", CPUFREQ) && all; + + if (all) + pm121_all_controls_ok = 1; +} + + + + +static struct wf_sensor* pm121_register_sensor(struct wf_sensor *sensor, + const char *match, + struct wf_sensor **var) +{ + if (*var == NULL && !strcmp(sensor->name, match)) { + if (wf_get_sensor(sensor) == 0) + *var = sensor; + } + return *var; +} + +static void pm121_new_sensor(struct wf_sensor *sr) +{ + int all = 1; + + if (pm121_all_sensors_ok) + return; + + all = pm121_register_sensor(sr, "cpu-temp", + &sensor_cpu_temp) && all; + all = pm121_register_sensor(sr, "cpu-current", + &sensor_cpu_current) && all; + all = pm121_register_sensor(sr, "cpu-voltage", + &sensor_cpu_voltage) && all; + all = pm121_register_sensor(sr, "cpu-power", + &sensor_cpu_power) && all; + all = pm121_register_sensor(sr, "hard-drive-temp", + &sensor_hard_drive_temp) && all; + all = pm121_register_sensor(sr, "optical-drive-temp", + &sensor_optical_drive_temp) && all; + all = pm121_register_sensor(sr, "incoming-air-temp", + &sensor_incoming_air_temp) && all; + all = pm121_register_sensor(sr, "north-bridge-temp", + &sensor_north_bridge_temp) && all; + all = pm121_register_sensor(sr, "gpu-temp", + &sensor_gpu_temp) && all; + + if (all) + pm121_all_sensors_ok = 1; +} + + + +static int pm121_notify(struct notifier_block *self, + unsigned long event, void *data) +{ + switch (event) { + case WF_EVENT_NEW_CONTROL: + pr_debug("pm121: new control %s detected\n", + ((struct wf_control *)data)->name); + pm121_new_control(data); + break; + case WF_EVENT_NEW_SENSOR: + pr_debug("pm121: new sensor %s detected\n", + ((struct wf_sensor *)data)->name); + pm121_new_sensor(data); + break; + case WF_EVENT_TICK: + if (pm121_all_controls_ok && pm121_all_sensors_ok) + pm121_tick(); + break; + } + + return 0; +} + +static struct notifier_block pm121_events = { + .notifier_call = pm121_notify, +}; + +static int pm121_init_pm(void) +{ + const struct smu_sdbp_header *hdr; + + hdr = smu_get_sdb_partition(SMU_SDB_SENSORTREE_ID, NULL); + if (hdr != 0) { + struct smu_sdbp_sensortree *st = + (struct smu_sdbp_sensortree *)&hdr[1]; + pm121_mach_model = st->model_id; + } + + pm121_connection = &pm121_connections[pm121_mach_model - 2]; + + printk(KERN_INFO "pm121: Initializing for iMac G5 iSight model ID %d\n", + pm121_mach_model); + + return 0; +} + + +static int pm121_probe(struct platform_device *ddev) +{ + wf_register_client(&pm121_events); + + return 0; +} + +static int __devexit pm121_remove(struct platform_device *ddev) +{ + wf_unregister_client(&pm121_events); + return 0; +} + +static struct platform_driver pm121_driver = { + .probe = pm121_probe, + .remove = __devexit_p(pm121_remove), + .driver = { + .name = "windfarm", + .bus = &platform_bus_type, + }, +}; + + +static int __init pm121_init(void) +{ + int rc = -ENODEV; + + if (machine_is_compatible("PowerMac12,1")) + rc = pm121_init_pm(); + + if (rc == 0) { + request_module("windfarm_smu_controls"); + request_module("windfarm_smu_sensors"); + request_module("windfarm_smu_sat"); + request_module("windfarm_lm75_sensor"); + request_module("windfarm_max6690_sensor"); + request_module("windfarm_cpufreq_clamp"); + platform_driver_register(&pm121_driver); + } + + return rc; +} + +static void __exit pm121_exit(void) +{ + + platform_driver_unregister(&pm121_driver); +} + + +module_init(pm121_init); +module_exit(pm121_exit); + +MODULE_AUTHOR("Étienne Bersac <bersace@gmail.com>"); +MODULE_DESCRIPTION("Thermal control logic for iMac G5 (iSight)"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/macintosh/windfarm_smu_controls.c b/drivers/macintosh/windfarm_smu_controls.c index 58c2590f05e..961fa0e7c2c 100644 --- a/drivers/macintosh/windfarm_smu_controls.c +++ b/drivers/macintosh/windfarm_smu_controls.c @@ -218,6 +218,10 @@ static struct smu_fan_control *smu_fan_create(struct device_node *node, fct->ctrl.name = "cpu-fan"; else if (!strcmp(l, "Hard Drive") || !strcmp(l, "Hard drive")) fct->ctrl.name = "drive-bay-fan"; + else if (!strcmp(l, "HDD Fan")) /* seen on iMac G5 iSight */ + fct->ctrl.name = "hard-drive-fan"; + else if (!strcmp(l, "ODD Fan")) /* same */ + fct->ctrl.name = "optical-drive-fan"; /* Unrecognized fan, bail out */ if (fct->ctrl.name == NULL) diff --git a/drivers/mca/mca-legacy.c b/drivers/mca/mca-legacy.c index 0c7bfa74c8e..494f0c2001f 100644 --- a/drivers/mca/mca-legacy.c +++ b/drivers/mca/mca-legacy.c @@ -282,24 +282,6 @@ void mca_set_adapter_name(int slot, char* name) EXPORT_SYMBOL(mca_set_adapter_name); /** - * mca_is_adapter_used - check if claimed by driver - * @slot: slot to check - * - * Returns 1 if the slot has been claimed by a driver - */ - -int mca_is_adapter_used(int slot) -{ - struct mca_device *mca_dev = mca_find_device_by_slot(slot); - - if(!mca_dev) - return 0; - - return mca_device_claimed(mca_dev); -} -EXPORT_SYMBOL(mca_is_adapter_used); - -/** * mca_mark_as_used - claim an MCA device * @slot: slot to claim * FIXME: should we make this threadsafe diff --git a/drivers/mca/mca-proc.c b/drivers/mca/mca-proc.c index 33d5e0820cc..81ea0d377bf 100644 --- a/drivers/mca/mca-proc.c +++ b/drivers/mca/mca-proc.c @@ -183,7 +183,7 @@ void __init mca_do_proc_init(void) struct proc_dir_entry* node = NULL; struct mca_device *mca_dev; - proc_mca = proc_mkdir("mca", &proc_root); + proc_mca = proc_mkdir("mca", NULL); create_proc_read_entry("pos",0,proc_mca,get_mca_info,NULL); create_proc_read_entry("machine",0,proc_mca,get_mca_machine_info,NULL); diff --git a/drivers/md/dm-emc.c b/drivers/md/dm-emc.c index 6b91b9ab1d4..3ea5ad4b780 100644 --- a/drivers/md/dm-emc.c +++ b/drivers/md/dm-emc.c @@ -110,8 +110,6 @@ static struct request *get_failover_req(struct emc_handler *h, memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); rq->sense_len = 0; - memset(&rq->cmd, 0, BLK_MAX_CDB); - rq->timeout = EMC_FAILOVER_TIMEOUT; rq->cmd_type = REQ_TYPE_BLOCK_PC; rq->cmd_flags |= REQ_FAILFAST | REQ_NOMERGE; diff --git a/drivers/md/dm-mpath-hp-sw.c b/drivers/md/dm-mpath-hp-sw.c index 204bf42c944..b63a0ab37c5 100644 --- a/drivers/md/dm-mpath-hp-sw.c +++ b/drivers/md/dm-mpath-hp-sw.c @@ -137,7 +137,6 @@ static struct request *hp_sw_get_request(struct dm_path *path) req->sense = h->sense; memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE); - memset(&req->cmd, 0, BLK_MAX_CDB); req->cmd[0] = START_STOP; req->cmd[4] = 1; req->cmd_len = COMMAND_SIZE(req->cmd[0]); diff --git a/drivers/md/dm-mpath-rdac.c b/drivers/md/dm-mpath-rdac.c index e04eb5c697f..95e77734880 100644 --- a/drivers/md/dm-mpath-rdac.c +++ b/drivers/md/dm-mpath-rdac.c @@ -284,7 +284,6 @@ static struct request *get_rdac_req(struct rdac_handler *h, return NULL; } - memset(&rq->cmd, 0, BLK_MAX_CDB); rq->sense = h->sense; memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); rq->sense_len = 0; diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 51be5334421..94116eaf470 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -873,10 +873,11 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q) q->max_hw_sectors = t->limits.max_hw_sectors; q->seg_boundary_mask = t->limits.seg_boundary_mask; q->bounce_pfn = t->limits.bounce_pfn; + if (t->limits.no_cluster) - q->queue_flags &= ~(1 << QUEUE_FLAG_CLUSTER); + queue_flag_clear_unlocked(QUEUE_FLAG_CLUSTER, q); else - q->queue_flags |= (1 << QUEUE_FLAG_CLUSTER); + queue_flag_set_unlocked(QUEUE_FLAG_CLUSTER, q); } diff --git a/drivers/md/dm-uevent.c b/drivers/md/dm-uevent.c index 50377e5dc2a..6f65883aef1 100644 --- a/drivers/md/dm-uevent.c +++ b/drivers/md/dm-uevent.c @@ -78,7 +78,7 @@ static struct dm_uevent *dm_build_path_uevent(struct mapped_device *md, event = dm_uevent_alloc(md); if (!event) { - DMERR("%s: dm_uevent_alloc() failed", __FUNCTION__); + DMERR("%s: dm_uevent_alloc() failed", __func__); goto err_nomem; } @@ -86,32 +86,32 @@ static struct dm_uevent *dm_build_path_uevent(struct mapped_device *md, if (add_uevent_var(&event->ku_env, "DM_TARGET=%s", ti->type->name)) { DMERR("%s: add_uevent_var() for DM_TARGET failed", - __FUNCTION__); + __func__); goto err_add; } if (add_uevent_var(&event->ku_env, "DM_ACTION=%s", dm_action)) { DMERR("%s: add_uevent_var() for DM_ACTION failed", - __FUNCTION__); + __func__); goto err_add; } if (add_uevent_var(&event->ku_env, "DM_SEQNUM=%u", dm_next_uevent_seq(md))) { DMERR("%s: add_uevent_var() for DM_SEQNUM failed", - __FUNCTION__); + __func__); goto err_add; } if (add_uevent_var(&event->ku_env, "DM_PATH=%s", path)) { - DMERR("%s: add_uevent_var() for DM_PATH failed", __FUNCTION__); + DMERR("%s: add_uevent_var() for DM_PATH failed", __func__); goto err_add; } if (add_uevent_var(&event->ku_env, "DM_NR_VALID_PATHS=%d", nr_valid_paths)) { DMERR("%s: add_uevent_var() for DM_NR_VALID_PATHS failed", - __FUNCTION__); + __func__); goto err_add; } @@ -146,25 +146,25 @@ void dm_send_uevents(struct list_head *events, struct kobject *kobj) if (dm_copy_name_and_uuid(event->md, event->name, event->uuid)) { DMERR("%s: dm_copy_name_and_uuid() failed", - __FUNCTION__); + __func__); goto uevent_free; } if (add_uevent_var(&event->ku_env, "DM_NAME=%s", event->name)) { DMERR("%s: add_uevent_var() for DM_NAME failed", - __FUNCTION__); + __func__); goto uevent_free; } if (add_uevent_var(&event->ku_env, "DM_UUID=%s", event->uuid)) { DMERR("%s: add_uevent_var() for DM_UUID failed", - __FUNCTION__); + __func__); goto uevent_free; } r = kobject_uevent_env(kobj, event->action, event->ku_env.envp); if (r) - DMERR("%s: kobject_uevent_env failed", __FUNCTION__); + DMERR("%s: kobject_uevent_env failed", __func__); uevent_free: dm_uevent_free(event); } @@ -187,7 +187,7 @@ void dm_path_uevent(enum dm_uevent_type event_type, struct dm_target *ti, struct dm_uevent *event; if (event_type >= ARRAY_SIZE(_dm_uevent_type_names)) { - DMERR("%s: Invalid event_type %d", __FUNCTION__, event_type); + DMERR("%s: Invalid event_type %d", __func__, event_type); goto out; } diff --git a/drivers/md/md.c b/drivers/md/md.c index 5ebfb4d7990..bb3e4b1cb77 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -282,7 +282,8 @@ static mddev_t * mddev_find(dev_t unit) kfree(new); return NULL; } - set_bit(QUEUE_FLAG_CLUSTER, &new->queue->queue_flags); + /* Can be unlocked because the queue is new: no concurrency */ + queue_flag_set_unlocked(QUEUE_FLAG_CLUSTER, new->queue); blk_queue_make_request(new->queue, md_fail_request); @@ -731,9 +732,9 @@ static int super_90_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version else rdev->desc_nr = sb->this_disk.number; - if (refdev == 0) + if (!refdev) { ret = 1; - else { + } else { __u64 ev1, ev2; mdp_super_t *refsb = (mdp_super_t*)page_address(refdev->sb_page); if (!uuid_equal(refsb, sb)) { @@ -1116,9 +1117,9 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version) else rdev->desc_nr = le32_to_cpu(sb->dev_number); - if (refdev == 0) + if (!refdev) { ret = 1; - else { + } else { __u64 ev1, ev2; struct mdp_superblock_1 *refsb = (struct mdp_superblock_1*)page_address(refdev->sb_page); @@ -5947,13 +5948,9 @@ static struct notifier_block md_notifier = { static void md_geninit(void) { - struct proc_dir_entry *p; - dprintk("md: sizeof(mdp_super_t) = %d\n", (int)sizeof(mdp_super_t)); - p = create_proc_entry("mdstat", S_IRUGO, NULL); - if (p) - p->proc_fops = &md_seq_fops; + proc_create("mdstat", S_IRUGO, NULL, &md_seq_fops); } static int __init md_init(void) diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index 3f299d835a2..42ee1a2dc14 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -244,7 +244,8 @@ static void multipath_error (mddev_t *mddev, mdk_rdev_t *rdev) conf->working_disks--; mddev->degraded++; printk(KERN_ALERT "multipath: IO failure on %s," - " disabling IO path. \n Operation continuing" + " disabling IO path.\n" + "multipath: Operation continuing" " on %d IO paths.\n", bdevname (rdev->bdev,b), conf->working_disks); diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index ff61b309129..9fd473a6dbf 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1008,8 +1008,8 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev) } else set_bit(Faulty, &rdev->flags); set_bit(MD_CHANGE_DEVS, &mddev->flags); - printk(KERN_ALERT "raid1: Disk failure on %s, disabling device. \n" - " Operation continuing on %d devices\n", + printk(KERN_ALERT "raid1: Disk failure on %s, disabling device.\n" + "raid1: Operation continuing on %d devices.\n", bdevname(rdev->bdev,b), conf->raid_disks - mddev->degraded); } diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 32389d2f18f..1e96aa3ff51 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -1001,8 +1001,8 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev) } set_bit(Faulty, &rdev->flags); set_bit(MD_CHANGE_DEVS, &mddev->flags); - printk(KERN_ALERT "raid10: Disk failure on %s, disabling device. \n" - " Operation continuing on %d devices\n", + printk(KERN_ALERT "raid10: Disk failure on %s, disabling device.\n" + "raid10: Operation continuing on %d devices.\n", bdevname(rdev->bdev,b), conf->raid_disks - mddev->degraded); } diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index b162b839a66..968dacaced6 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -63,6 +63,7 @@ #define STRIPE_SHIFT (PAGE_SHIFT - 9) #define STRIPE_SECTORS (STRIPE_SIZE>>9) #define IO_THRESHOLD 1 +#define BYPASS_THRESHOLD 1 #define NR_HASH (PAGE_SIZE / sizeof(struct hlist_head)) #define HASH_MASK (NR_HASH - 1) @@ -398,6 +399,7 @@ static void ops_run_io(struct stripe_head *sh) might_sleep(); + set_bit(STRIPE_IO_STARTED, &sh->state); for (i = disks; i--; ) { int rw; struct bio *bi; @@ -433,7 +435,7 @@ static void ops_run_io(struct stripe_head *sh) bi->bi_bdev = rdev->bdev; pr_debug("%s: for %llu schedule op %ld on disc %d\n", - __FUNCTION__, (unsigned long long)sh->sector, + __func__, (unsigned long long)sh->sector, bi->bi_rw, i); atomic_inc(&sh->count); bi->bi_sector = sh->sector + rdev->data_offset; @@ -520,7 +522,7 @@ static void ops_complete_biofill(void *stripe_head_ref) raid5_conf_t *conf = sh->raid_conf; int i; - pr_debug("%s: stripe %llu\n", __FUNCTION__, + pr_debug("%s: stripe %llu\n", __func__, (unsigned long long)sh->sector); /* clear completed biofills */ @@ -569,7 +571,7 @@ static void ops_run_biofill(struct stripe_head *sh) raid5_conf_t *conf = sh->raid_conf; int i; - pr_debug("%s: stripe %llu\n", __FUNCTION__, + pr_debug("%s: stripe %llu\n", __func__, (unsigned long long)sh->sector); for (i = sh->disks; i--; ) { @@ -600,7 +602,7 @@ static void ops_complete_compute5(void *stripe_head_ref) int target = sh->ops.target; struct r5dev *tgt = &sh->dev[target]; - pr_debug("%s: stripe %llu\n", __FUNCTION__, + pr_debug("%s: stripe %llu\n", __func__, (unsigned long long)sh->sector); set_bit(R5_UPTODATE, &tgt->flags); @@ -625,7 +627,7 @@ ops_run_compute5(struct stripe_head *sh, unsigned long pending) int i; pr_debug("%s: stripe %llu block: %d\n", - __FUNCTION__, (unsigned long long)sh->sector, target); + __func__, (unsigned long long)sh->sector, target); BUG_ON(!test_bit(R5_Wantcompute, &tgt->flags)); for (i = disks; i--; ) @@ -653,7 +655,7 @@ static void ops_complete_prexor(void *stripe_head_ref) { struct stripe_head *sh = stripe_head_ref; - pr_debug("%s: stripe %llu\n", __FUNCTION__, + pr_debug("%s: stripe %llu\n", __func__, (unsigned long long)sh->sector); set_bit(STRIPE_OP_PREXOR, &sh->ops.complete); @@ -670,7 +672,7 @@ ops_run_prexor(struct stripe_head *sh, struct dma_async_tx_descriptor *tx) /* existing parity data subtracted */ struct page *xor_dest = xor_srcs[count++] = sh->dev[pd_idx].page; - pr_debug("%s: stripe %llu\n", __FUNCTION__, + pr_debug("%s: stripe %llu\n", __func__, (unsigned long long)sh->sector); for (i = disks; i--; ) { @@ -699,7 +701,7 @@ ops_run_biodrain(struct stripe_head *sh, struct dma_async_tx_descriptor *tx, */ int prexor = test_bit(STRIPE_OP_PREXOR, &pending); - pr_debug("%s: stripe %llu\n", __FUNCTION__, + pr_debug("%s: stripe %llu\n", __func__, (unsigned long long)sh->sector); for (i = disks; i--; ) { @@ -744,7 +746,7 @@ static void ops_complete_postxor(void *stripe_head_ref) { struct stripe_head *sh = stripe_head_ref; - pr_debug("%s: stripe %llu\n", __FUNCTION__, + pr_debug("%s: stripe %llu\n", __func__, (unsigned long long)sh->sector); set_bit(STRIPE_OP_POSTXOR, &sh->ops.complete); @@ -757,7 +759,7 @@ static void ops_complete_write(void *stripe_head_ref) struct stripe_head *sh = stripe_head_ref; int disks = sh->disks, i, pd_idx = sh->pd_idx; - pr_debug("%s: stripe %llu\n", __FUNCTION__, + pr_debug("%s: stripe %llu\n", __func__, (unsigned long long)sh->sector); for (i = disks; i--; ) { @@ -787,7 +789,7 @@ ops_run_postxor(struct stripe_head *sh, struct dma_async_tx_descriptor *tx, unsigned long flags; dma_async_tx_callback callback; - pr_debug("%s: stripe %llu\n", __FUNCTION__, + pr_debug("%s: stripe %llu\n", __func__, (unsigned long long)sh->sector); /* check if prexor is active which means only process blocks @@ -837,7 +839,7 @@ static void ops_complete_check(void *stripe_head_ref) struct stripe_head *sh = stripe_head_ref; int pd_idx = sh->pd_idx; - pr_debug("%s: stripe %llu\n", __FUNCTION__, + pr_debug("%s: stripe %llu\n", __func__, (unsigned long long)sh->sector); if (test_and_clear_bit(STRIPE_OP_MOD_DMA_CHECK, &sh->ops.pending) && @@ -859,7 +861,7 @@ static void ops_run_check(struct stripe_head *sh) int count = 0, pd_idx = sh->pd_idx, i; struct page *xor_dest = xor_srcs[count++] = sh->dev[pd_idx].page; - pr_debug("%s: stripe %llu\n", __FUNCTION__, + pr_debug("%s: stripe %llu\n", __func__, (unsigned long long)sh->sector); for (i = disks; i--; ) { @@ -1260,8 +1262,8 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev) } set_bit(Faulty, &rdev->flags); printk (KERN_ALERT - "raid5: Disk failure on %s, disabling device." - " Operation continuing on %d devices\n", + "raid5: Disk failure on %s, disabling device.\n" + "raid5: Operation continuing on %d devices.\n", bdevname(rdev->bdev,b), conf->raid_disks - mddev->degraded); } } @@ -1720,6 +1722,9 @@ handle_write_operations5(struct stripe_head *sh, int rcw, int expand) locked++; } } + if (locked + 1 == disks) + if (!test_and_set_bit(STRIPE_FULL_WRITE, &sh->state)) + atomic_inc(&sh->raid_conf->pending_full_writes); } else { BUG_ON(!(test_bit(R5_UPTODATE, &sh->dev[pd_idx].flags) || test_bit(R5_Wantcompute, &sh->dev[pd_idx].flags))); @@ -1759,7 +1764,7 @@ handle_write_operations5(struct stripe_head *sh, int rcw, int expand) locked++; pr_debug("%s: stripe %llu locked: %d pending: %lx\n", - __FUNCTION__, (unsigned long long)sh->sector, + __func__, (unsigned long long)sh->sector, locked, sh->ops.pending); return locked; @@ -1947,6 +1952,9 @@ handle_requests_to_failed_array(raid5_conf_t *conf, struct stripe_head *sh, STRIPE_SECTORS, 0, 0); } + if (test_and_clear_bit(STRIPE_FULL_WRITE, &sh->state)) + if (atomic_dec_and_test(&conf->pending_full_writes)) + md_wakeup_thread(conf->mddev->thread); } /* __handle_issuing_new_read_requests5 - returns 0 if there are no more disks @@ -2149,6 +2157,10 @@ static void handle_completed_write_requests(raid5_conf_t *conf, 0); } } + + if (test_and_clear_bit(STRIPE_FULL_WRITE, &sh->state)) + if (atomic_dec_and_test(&conf->pending_full_writes)) + md_wakeup_thread(conf->mddev->thread); } static void handle_issuing_new_write_requests5(raid5_conf_t *conf, @@ -2333,6 +2345,9 @@ static void handle_issuing_new_write_requests6(raid5_conf_t *conf, s->locked++; set_bit(R5_Wantwrite, &sh->dev[i].flags); } + if (s->locked == disks) + if (!test_and_set_bit(STRIPE_FULL_WRITE, &sh->state)) + atomic_inc(&conf->pending_full_writes); /* after a RECONSTRUCT_WRITE, the stripe MUST be in-sync */ set_bit(STRIPE_INSYNC, &sh->state); @@ -3094,6 +3109,8 @@ static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page) else continue; + set_bit(STRIPE_IO_STARTED, &sh->state); + bi = &sh->dev[i].req; bi->bi_rw = rw; @@ -3164,7 +3181,7 @@ static void raid5_activate_delayed(raid5_conf_t *conf) clear_bit(STRIPE_DELAYED, &sh->state); if (!test_and_set_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) atomic_inc(&conf->preread_active_stripes); - list_add_tail(&sh->lru, &conf->handle_list); + list_add_tail(&sh->lru, &conf->hold_list); } } else blk_plug_device(conf->mddev->queue); @@ -3442,6 +3459,58 @@ static int chunk_aligned_read(struct request_queue *q, struct bio * raid_bio) } } +/* __get_priority_stripe - get the next stripe to process + * + * Full stripe writes are allowed to pass preread active stripes up until + * the bypass_threshold is exceeded. In general the bypass_count + * increments when the handle_list is handled before the hold_list; however, it + * will not be incremented when STRIPE_IO_STARTED is sampled set signifying a + * stripe with in flight i/o. The bypass_count will be reset when the + * head of the hold_list has changed, i.e. the head was promoted to the + * handle_list. + */ +static struct stripe_head *__get_priority_stripe(raid5_conf_t *conf) +{ + struct stripe_head *sh; + + pr_debug("%s: handle: %s hold: %s full_writes: %d bypass_count: %d\n", + __func__, + list_empty(&conf->handle_list) ? "empty" : "busy", + list_empty(&conf->hold_list) ? "empty" : "busy", + atomic_read(&conf->pending_full_writes), conf->bypass_count); + + if (!list_empty(&conf->handle_list)) { + sh = list_entry(conf->handle_list.next, typeof(*sh), lru); + + if (list_empty(&conf->hold_list)) + conf->bypass_count = 0; + else if (!test_bit(STRIPE_IO_STARTED, &sh->state)) { + if (conf->hold_list.next == conf->last_hold) + conf->bypass_count++; + else { + conf->last_hold = conf->hold_list.next; + conf->bypass_count -= conf->bypass_threshold; + if (conf->bypass_count < 0) + conf->bypass_count = 0; + } + } + } else if (!list_empty(&conf->hold_list) && + ((conf->bypass_threshold && + conf->bypass_count > conf->bypass_threshold) || + atomic_read(&conf->pending_full_writes) == 0)) { + sh = list_entry(conf->hold_list.next, + typeof(*sh), lru); + conf->bypass_count -= conf->bypass_threshold; + if (conf->bypass_count < 0) + conf->bypass_count = 0; + } else + return NULL; + + list_del_init(&sh->lru); + atomic_inc(&sh->count); + BUG_ON(atomic_read(&sh->count) != 1); + return sh; +} static int make_request(struct request_queue *q, struct bio * bi) { @@ -3914,7 +3983,6 @@ static void raid5d(mddev_t *mddev) handled = 0; spin_lock_irq(&conf->device_lock); while (1) { - struct list_head *first; struct bio *bio; if (conf->seq_flush != conf->seq_write) { @@ -3936,17 +4004,12 @@ static void raid5d(mddev_t *mddev) handled++; } - if (list_empty(&conf->handle_list)) { + sh = __get_priority_stripe(conf); + + if (!sh) { async_tx_issue_pending_all(); break; } - - first = conf->handle_list.next; - sh = list_entry(first, struct stripe_head, lru); - - list_del_init(first); - atomic_inc(&sh->count); - BUG_ON(atomic_read(&sh->count)!= 1); spin_unlock_irq(&conf->device_lock); handled++; @@ -3978,15 +4041,13 @@ static ssize_t raid5_store_stripe_cache_size(mddev_t *mddev, const char *page, size_t len) { raid5_conf_t *conf = mddev_to_conf(mddev); - char *end; - int new; + unsigned long new; if (len >= PAGE_SIZE) return -EINVAL; if (!conf) return -ENODEV; - new = simple_strtoul(page, &end, 10); - if (!*page || (*end && *end != '\n') ) + if (strict_strtoul(page, 10, &new)) return -EINVAL; if (new <= 16 || new > 32768) return -EINVAL; @@ -4011,6 +4072,40 @@ raid5_stripecache_size = __ATTR(stripe_cache_size, S_IRUGO | S_IWUSR, raid5_store_stripe_cache_size); static ssize_t +raid5_show_preread_threshold(mddev_t *mddev, char *page) +{ + raid5_conf_t *conf = mddev_to_conf(mddev); + if (conf) + return sprintf(page, "%d\n", conf->bypass_threshold); + else + return 0; +} + +static ssize_t +raid5_store_preread_threshold(mddev_t *mddev, const char *page, size_t len) +{ + raid5_conf_t *conf = mddev_to_conf(mddev); + unsigned long new; + if (len >= PAGE_SIZE) + return -EINVAL; + if (!conf) + return -ENODEV; + + if (strict_strtoul(page, 10, &new)) + return -EINVAL; + if (new > conf->max_nr_stripes) + return -EINVAL; + conf->bypass_threshold = new; + return len; +} + +static struct md_sysfs_entry +raid5_preread_bypass_threshold = __ATTR(preread_bypass_threshold, + S_IRUGO | S_IWUSR, + raid5_show_preread_threshold, + raid5_store_preread_threshold); + +static ssize_t stripe_cache_active_show(mddev_t *mddev, char *page) { raid5_conf_t *conf = mddev_to_conf(mddev); @@ -4026,6 +4121,7 @@ raid5_stripecache_active = __ATTR_RO(stripe_cache_active); static struct attribute *raid5_attrs[] = { &raid5_stripecache_size.attr, &raid5_stripecache_active.attr, + &raid5_preread_bypass_threshold.attr, NULL, }; static struct attribute_group raid5_attrs_group = { @@ -4130,12 +4226,14 @@ static int run(mddev_t *mddev) init_waitqueue_head(&conf->wait_for_stripe); init_waitqueue_head(&conf->wait_for_overlap); INIT_LIST_HEAD(&conf->handle_list); + INIT_LIST_HEAD(&conf->hold_list); INIT_LIST_HEAD(&conf->delayed_list); INIT_LIST_HEAD(&conf->bitmap_list); INIT_LIST_HEAD(&conf->inactive_list); atomic_set(&conf->active_stripes, 0); atomic_set(&conf->preread_active_stripes, 0); atomic_set(&conf->active_aligned_reads, 0); + conf->bypass_threshold = BYPASS_THRESHOLD; pr_debug("raid5: run(%s) called.\n", mdname(mddev)); diff --git a/drivers/md/raid6algos.c b/drivers/md/raid6algos.c index 77a6e4bf503..21987e3dbe6 100644 --- a/drivers/md/raid6algos.c +++ b/drivers/md/raid6algos.c @@ -121,7 +121,8 @@ int __init raid6_select_algo(void) j0 = jiffies; while ( (j1 = jiffies) == j0 ) cpu_relax(); - while ( (jiffies-j1) < (1 << RAID6_TIME_JIFFIES_LG2) ) { + while (time_before(jiffies, + j1 + (1<<RAID6_TIME_JIFFIES_LG2))) { (*algo)->gen_syndrome(disks, PAGE_SIZE, dptrs); perf++; } diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 128bb9cd575..ddf57e135c6 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -5,16 +5,20 @@ menu "Multimedia devices" depends on HAS_IOMEM +comment "Multimedia core support" + +# +# V4L core and enabled API's +# + config VIDEO_DEV tristate "Video For Linux" ---help--- - Support for audio/video capture and overlay devices and FM radio - cards. The exact capabilities of each device vary. + V4L core support for video capture and overlay devices, webcams and + AM/FM radio cards. This kernel includes support for the new Video for Linux Two API, - (V4L2) as well as the original system. Drivers and applications - need to be rewritten to use V4L2, but drivers for popular cards - and applications for most video capture functions already exist. + (V4L2). Additional info and docs are available on the web at <http://linuxtv.org> @@ -36,8 +40,11 @@ config VIDEO_ALLOW_V4L1 default VIDEO_DEV && VIDEO_V4L2_COMMON select VIDEO_V4L1_COMPAT ---help--- - Enables a compatibility API used by most V4L2 devices to allow - its usage with legacy applications that supports only V4L1 api. + Enables drivers based on the legacy V4L1 API. + + This api were developed to be used at Kernel 2.2 and 2.4, but + lacks support for several video standards. There are several + drivers at kernel that still depends on it. If you are unsure as to whether this is required, answer Y. @@ -46,9 +53,8 @@ config VIDEO_V4L1_COMPAT depends on VIDEO_DEV default VIDEO_DEV ---help--- - This api were developed to be used at Kernel 2.2 and 2.4, but - lacks support for several video standards. There are several - drivers at kernel that still depends on it. + Enables a compatibility API used by most V4L2 devices to allow + its usage with legacy applications that supports only V4L1 api. Documentation for the original API is included in the file <Documentation/video4linux/API.html>. @@ -58,135 +64,57 @@ config VIDEO_V4L1_COMPAT If you are unsure as to whether this is required, answer Y. -config VIDEO_V4L2 - tristate - depends on VIDEO_DEV && VIDEO_V4L2_COMMON - default VIDEO_DEV && VIDEO_V4L2_COMMON - -config VIDEO_V4L1 - tristate - depends on VIDEO_DEV && VIDEO_V4L2_COMMON && VIDEO_ALLOW_V4L1 - default VIDEO_DEV && VIDEO_V4L2_COMMON && VIDEO_ALLOW_V4L1 - -source "drivers/media/video/Kconfig" - -source "drivers/media/radio/Kconfig" - -source "drivers/media/dvb/Kconfig" - -source "drivers/media/common/Kconfig" +# +# DVB Core +# -config VIDEO_TUNER - tristate - depends on I2C - select TUNER_XC2028 if !VIDEO_TUNER_CUSTOMIZE - select TUNER_MT20XX if !VIDEO_TUNER_CUSTOMIZE - select TUNER_TDA8290 if !VIDEO_TUNER_CUSTOMIZE - select TUNER_TEA5761 if !VIDEO_TUNER_CUSTOMIZE - select TUNER_TEA5767 if !VIDEO_TUNER_CUSTOMIZE - select TUNER_SIMPLE if !VIDEO_TUNER_CUSTOMIZE - select TUNER_TDA9887 if !VIDEO_TUNER_CUSTOMIZE - -menuconfig VIDEO_TUNER_CUSTOMIZE - bool "Customize analog tuner modules to build" - depends on VIDEO_TUNER +config DVB_CORE + tristate "DVB for Linux" + depends on NET && INET + select CRC32 help - This allows the user to deselect tuner drivers unnecessary - for their hardware from the build. Use this option with care - as deselecting tuner drivers which are in fact necessary will - result in V4L devices which cannot be tuned due to lack of - driver support + DVB core utility functions for device handling, software fallbacks etc. - If unsure say N. - -if VIDEO_TUNER_CUSTOMIZE - -config TUNER_XC2028 - tristate "XCeive xc2028/xc3028 tuners" - depends on I2C && FW_LOADER - default m if VIDEO_TUNER_CUSTOMIZE - help - Say Y here to include support for the xc2028/xc3028 tuners. + Enable this if you own a DVB/ATSC adapter and want to use it or if + you compile Linux for a digital SetTopBox. -config TUNER_MT20XX - tristate "Microtune 2032 / 2050 tuners" - depends on I2C - default m if VIDEO_TUNER_CUSTOMIZE - help - Say Y here to include support for the MT2032 / MT2050 tuner. - -config TUNER_TDA8290 - tristate "TDA 8290/8295 + 8275(a)/18271 tuner combo" - depends on I2C - select DVB_TDA827X - select DVB_TDA18271 - default m if VIDEO_TUNER_CUSTOMIZE - help - Say Y here to include support for Philips TDA8290+8275(a) tuner. + Say Y when you have a DVB or an ATSC card and want to use it. -config TUNER_TEA5761 - tristate "TEA 5761 radio tuner (EXPERIMENTAL)" - depends on I2C && EXPERIMENTAL - default m if VIDEO_TUNER_CUSTOMIZE - help - Say Y here to include support for the Philips TEA5761 radio tuner. + API specs and user tools are available from <http://www.linuxtv.org/>. -config TUNER_TEA5767 - tristate "TEA 5767 radio tuner" - depends on I2C - default m if VIDEO_TUNER_CUSTOMIZE - help - Say Y here to include support for the Philips TEA5767 radio tuner. + Please report problems regarding this support to the LinuxDVB + mailing list. -config TUNER_SIMPLE - tristate "Simple tuner support" - depends on I2C - select TUNER_TDA9887 - default m if VIDEO_TUNER_CUSTOMIZE - help - Say Y here to include support for various simple tuners. + If unsure say N. -config TUNER_TDA9887 - tristate "TDA 9885/6/7 analog IF demodulator" - depends on I2C - default m if VIDEO_TUNER_CUSTOMIZE - help - Say Y here to include support for Philips TDA9885/6/7 - analog IF demodulator. +config VIDEO_MEDIA + tristate + default DVB_CORE || VIDEO_DEV + depends on DVB_CORE || VIDEO_DEV -endif # VIDEO_TUNER_CUSTOMIZE +comment "Multimedia drivers" -config VIDEOBUF_GEN - tristate +source "drivers/media/common/Kconfig" -config VIDEOBUF_DMA_SG - depends on HAS_DMA - select VIDEOBUF_GEN - tristate +# +# Tuner drivers for DVB and V4L +# -config VIDEOBUF_VMALLOC - select VIDEOBUF_GEN - tristate +source "drivers/media/common/tuners/Kconfig" -config VIDEOBUF_DVB - tristate - select VIDEOBUF_GEN - select VIDEOBUF_DMA_SG +# +# Video/Radio/Hybrid adapters +# -config VIDEO_BTCX - tristate +source "drivers/media/video/Kconfig" -config VIDEO_IR_I2C - tristate +source "drivers/media/radio/Kconfig" -config VIDEO_IR - tristate - depends on INPUT - select VIDEO_IR_I2C if I2C +# +# DVB adapters +# -config VIDEO_TVEEPROM - tristate - depends on I2C +source "drivers/media/dvb/Kconfig" config DAB boolean "DAB adapters" diff --git a/drivers/media/Makefile b/drivers/media/Makefile index 7b8bb6949f5..73f742c7e81 100644 --- a/drivers/media/Makefile +++ b/drivers/media/Makefile @@ -2,10 +2,10 @@ # Makefile for the kernel multimedia device drivers. # -obj-y := common/ -obj-y += video/ +obj-$(CONFIG_VIDEO_MEDIA) += common/ + +# Since hybrid devices are here, should be compiled if DVB and/or V4L +obj-$(CONFIG_VIDEO_MEDIA) += video/ + obj-$(CONFIG_VIDEO_DEV) += radio/ obj-$(CONFIG_DVB_CORE) += dvb/ -ifeq ($(CONFIG_DVB_CORE),) - obj-$(CONFIG_VIDEO_TUNER) += dvb/frontends/ -endif diff --git a/drivers/media/common/tuners/Kconfig b/drivers/media/common/tuners/Kconfig new file mode 100644 index 00000000000..7b379e1ce01 --- /dev/null +++ b/drivers/media/common/tuners/Kconfig @@ -0,0 +1,146 @@ +config MEDIA_ATTACH + bool "Load and attach frontend driver modules as needed" + depends on DVB_CORE + depends on MODULES + help + Remove the static dependency of DVB card drivers on all + frontend modules for all possible card variants. Instead, + allow the card drivers to only load the frontend modules + they require. This saves several KBytes of memory. + + Note: You will need module-init-tools v3.2 or later for this feature. + + If unsure say Y. + +config MEDIA_TUNER + tristate + default DVB_CORE || VIDEO_DEV + depends on DVB_CORE || VIDEO_DEV + select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMIZE + select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMIZE + select MEDIA_TUNER_MT20XX if !MEDIA_TUNER_CUSTOMIZE + select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMIZE + select MEDIA_TUNER_TEA5761 if !MEDIA_TUNER_CUSTOMIZE + select MEDIA_TUNER_TEA5767 if !MEDIA_TUNER_CUSTOMIZE + select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE + select MEDIA_TUNER_TDA9887 if !MEDIA_TUNER_CUSTOMIZE + +menuconfig MEDIA_TUNER_CUSTOMIZE + bool "Customize analog and hybrid tuner modules to build" + depends on MEDIA_TUNER + help + This allows the user to deselect tuner drivers unnecessary + for their hardware from the build. Use this option with care + as deselecting tuner drivers which are in fact necessary will + result in V4L/DVB devices which cannot be tuned due to lack of + driver support + + If unsure say N. + +if MEDIA_TUNER_CUSTOMIZE + +config MEDIA_TUNER_SIMPLE + tristate "Simple tuner support" + depends on I2C + select MEDIA_TUNER_TDA9887 + default m if MEDIA_TUNER_CUSTOMIZE + help + Say Y here to include support for various simple tuners. + +config MEDIA_TUNER_TDA8290 + tristate "TDA 8290/8295 + 8275(a)/18271 tuner combo" + depends on I2C + select MEDIA_TUNER_TDA827X + select MEDIA_TUNER_TDA18271 + default m if MEDIA_TUNER_CUSTOMIZE + help + Say Y here to include support for Philips TDA8290+8275(a) tuner. + +config MEDIA_TUNER_TDA827X + tristate "Philips TDA827X silicon tuner" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-T silicon tuner module. Say Y when you want to support this tuner. + +config MEDIA_TUNER_TDA18271 + tristate "NXP TDA18271 silicon tuner" + depends on I2C + default m if DVB_FE_CUSTOMISE + help + A silicon tuner module. Say Y when you want to support this tuner. + +config MEDIA_TUNER_TDA9887 + tristate "TDA 9885/6/7 analog IF demodulator" + depends on I2C + default m if MEDIA_TUNER_CUSTOMIZE + help + Say Y here to include support for Philips TDA9885/6/7 + analog IF demodulator. + +config MEDIA_TUNER_TEA5761 + tristate "TEA 5761 radio tuner (EXPERIMENTAL)" + depends on I2C && EXPERIMENTAL + default m if MEDIA_TUNER_CUSTOMIZE + help + Say Y here to include support for the Philips TEA5761 radio tuner. + +config MEDIA_TUNER_TEA5767 + tristate "TEA 5767 radio tuner" + depends on I2C + default m if MEDIA_TUNER_CUSTOMIZE + help + Say Y here to include support for the Philips TEA5767 radio tuner. + +config MEDIA_TUNER_MT20XX + tristate "Microtune 2032 / 2050 tuners" + depends on I2C + default m if MEDIA_TUNER_CUSTOMIZE + help + Say Y here to include support for the MT2032 / MT2050 tuner. + +config MEDIA_TUNER_MT2060 + tristate "Microtune MT2060 silicon IF tuner" + depends on I2C + default m if DVB_FE_CUSTOMISE + help + A driver for the silicon IF tuner MT2060 from Microtune. + +config MEDIA_TUNER_MT2266 + tristate "Microtune MT2266 silicon tuner" + depends on I2C + default m if DVB_FE_CUSTOMISE + help + A driver for the silicon baseband tuner MT2266 from Microtune. + +config MEDIA_TUNER_MT2131 + tristate "Microtune MT2131 silicon tuner" + depends on I2C + default m if DVB_FE_CUSTOMISE + help + A driver for the silicon baseband tuner MT2131 from Microtune. + +config MEDIA_TUNER_QT1010 + tristate "Quantek QT1010 silicon tuner" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A driver for the silicon tuner QT1010 from Quantek. + +config MEDIA_TUNER_XC2028 + tristate "XCeive xc2028/xc3028 tuners" + depends on I2C && FW_LOADER + default m if MEDIA_TUNER_CUSTOMIZE + help + Say Y here to include support for the xc2028/xc3028 tuners. + +config MEDIA_TUNER_XC5000 + tristate "Xceive XC5000 silicon tuner" + depends on I2C + default m if DVB_FE_CUSTOMISE + help + A driver for the silicon tuner XC5000 from Xceive. + This device is only used inside a SiP called togther with a + demodulator for now. + +endif # MEDIA_TUNER_CUSTOMIZE diff --git a/drivers/media/common/tuners/Makefile b/drivers/media/common/tuners/Makefile new file mode 100644 index 00000000000..236d9932fd9 --- /dev/null +++ b/drivers/media/common/tuners/Makefile @@ -0,0 +1,25 @@ +# +# Makefile for common V4L/DVB tuners +# + +tda18271-objs := tda18271-maps.o tda18271-common.o tda18271-fe.o + +obj-$(CONFIG_MEDIA_TUNER_XC2028) += tuner-xc2028.o +obj-$(CONFIG_MEDIA_TUNER_SIMPLE) += tuner-simple.o +# tuner-types will be merged into tuner-simple, in the future +obj-$(CONFIG_MEDIA_TUNER_SIMPLE) += tuner-types.o +obj-$(CONFIG_MEDIA_TUNER_MT20XX) += mt20xx.o +obj-$(CONFIG_MEDIA_TUNER_TDA8290) += tda8290.o +obj-$(CONFIG_MEDIA_TUNER_TEA5767) += tea5767.o +obj-$(CONFIG_MEDIA_TUNER_TEA5761) += tea5761.o +obj-$(CONFIG_MEDIA_TUNER_TDA9887) += tda9887.o +obj-$(CONFIG_MEDIA_TUNER_TDA827X) += tda827x.o +obj-$(CONFIG_MEDIA_TUNER_TDA18271) += tda18271.o +obj-$(CONFIG_MEDIA_TUNER_XC5000) += xc5000.o +obj-$(CONFIG_MEDIA_TUNER_MT2060) += mt2060.o +obj-$(CONFIG_MEDIA_TUNER_MT2266) += mt2266.o +obj-$(CONFIG_MEDIA_TUNER_QT1010) += qt1010.o +obj-$(CONFIG_MEDIA_TUNER_MT2131) += mt2131.o + +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core +EXTRA_CFLAGS += -Idrivers/media/dvb/frontends diff --git a/drivers/media/dvb/frontends/mt2060.c b/drivers/media/common/tuners/mt2060.c index 1305b0e63ce..1305b0e63ce 100644 --- a/drivers/media/dvb/frontends/mt2060.c +++ b/drivers/media/common/tuners/mt2060.c diff --git a/drivers/media/dvb/frontends/mt2060.h b/drivers/media/common/tuners/mt2060.h index acba0058f51..cb60caffb6b 100644 --- a/drivers/media/dvb/frontends/mt2060.h +++ b/drivers/media/common/tuners/mt2060.h @@ -30,7 +30,7 @@ struct mt2060_config { u8 clock_out; /* 0 = off, 1 = CLK/4, 2 = CLK/2, 3 = CLK/1 */ }; -#if defined(CONFIG_DVB_TUNER_MT2060) || (defined(CONFIG_DVB_TUNER_MT2060_MODULE) && defined(MODULE)) +#if defined(CONFIG_MEDIA_TUNER_MT2060) || (defined(CONFIG_MEDIA_TUNER_MT2060_MODULE) && defined(MODULE)) extern struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1); #else static inline struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1) @@ -38,6 +38,6 @@ static inline struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struc printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return NULL; } -#endif // CONFIG_DVB_TUNER_MT2060 +#endif // CONFIG_MEDIA_TUNER_MT2060 #endif diff --git a/drivers/media/dvb/frontends/mt2060_priv.h b/drivers/media/common/tuners/mt2060_priv.h index 5eaccdefd0b..5eaccdefd0b 100644 --- a/drivers/media/dvb/frontends/mt2060_priv.h +++ b/drivers/media/common/tuners/mt2060_priv.h diff --git a/drivers/media/video/mt20xx.c b/drivers/media/common/tuners/mt20xx.c index fbcb2823373..fbcb2823373 100644 --- a/drivers/media/video/mt20xx.c +++ b/drivers/media/common/tuners/mt20xx.c diff --git a/drivers/media/video/mt20xx.h b/drivers/media/common/tuners/mt20xx.h index aa848e14ce5..259553a2490 100644 --- a/drivers/media/video/mt20xx.h +++ b/drivers/media/common/tuners/mt20xx.h @@ -20,7 +20,7 @@ #include <linux/i2c.h> #include "dvb_frontend.h" -#if defined(CONFIG_TUNER_MT20XX) || (defined(CONFIG_TUNER_MT20XX_MODULE) && defined(MODULE)) +#if defined(CONFIG_MEDIA_TUNER_MT20XX) || (defined(CONFIG_MEDIA_TUNER_MT20XX_MODULE) && defined(MODULE)) extern struct dvb_frontend *microtune_attach(struct dvb_frontend *fe, struct i2c_adapter* i2c_adap, u8 i2c_addr); diff --git a/drivers/media/dvb/frontends/mt2131.c b/drivers/media/common/tuners/mt2131.c index e254bcfc2ef..e254bcfc2ef 100644 --- a/drivers/media/dvb/frontends/mt2131.c +++ b/drivers/media/common/tuners/mt2131.c diff --git a/drivers/media/dvb/frontends/mt2131.h b/drivers/media/common/tuners/mt2131.h index 606d8576bc9..cd8376f6f7b 100644 --- a/drivers/media/dvb/frontends/mt2131.h +++ b/drivers/media/common/tuners/mt2131.h @@ -30,7 +30,7 @@ struct mt2131_config { u8 clock_out; /* 0 = off, 1 = CLK/4, 2 = CLK/2, 3 = CLK/1 */ }; -#if defined(CONFIG_DVB_TUNER_MT2131) || (defined(CONFIG_DVB_TUNER_MT2131_MODULE) && defined(MODULE)) +#if defined(CONFIG_MEDIA_TUNER_MT2131) || (defined(CONFIG_MEDIA_TUNER_MT2131_MODULE) && defined(MODULE)) extern struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2131_config *cfg, @@ -44,7 +44,7 @@ static inline struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe, printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return NULL; } -#endif /* CONFIG_DVB_TUNER_MT2131 */ +#endif /* CONFIG_MEDIA_TUNER_MT2131 */ #endif /* __MT2131_H__ */ diff --git a/drivers/media/dvb/frontends/mt2131_priv.h b/drivers/media/common/tuners/mt2131_priv.h index e930759c2c0..e930759c2c0 100644 --- a/drivers/media/dvb/frontends/mt2131_priv.h +++ b/drivers/media/common/tuners/mt2131_priv.h diff --git a/drivers/media/dvb/frontends/mt2266.c b/drivers/media/common/tuners/mt2266.c index 54b18f94b14..54b18f94b14 100644 --- a/drivers/media/dvb/frontends/mt2266.c +++ b/drivers/media/common/tuners/mt2266.c diff --git a/drivers/media/dvb/frontends/mt2266.h b/drivers/media/common/tuners/mt2266.h index c5113efe333..4d083882d04 100644 --- a/drivers/media/dvb/frontends/mt2266.h +++ b/drivers/media/common/tuners/mt2266.h @@ -24,7 +24,7 @@ struct mt2266_config { u8 i2c_address; }; -#if defined(CONFIG_DVB_TUNER_MT2266) || (defined(CONFIG_DVB_TUNER_MT2266_MODULE) && defined(MODULE)) +#if defined(CONFIG_MEDIA_TUNER_MT2266) || (defined(CONFIG_MEDIA_TUNER_MT2266_MODULE) && defined(MODULE)) extern struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg); #else static inline struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg) @@ -32,6 +32,6 @@ static inline struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struc printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return NULL; } -#endif // CONFIG_DVB_TUNER_MT2266 +#endif // CONFIG_MEDIA_TUNER_MT2266 #endif diff --git a/drivers/media/dvb/frontends/qt1010.c b/drivers/media/common/tuners/qt1010.c index 825aa1412e6..825aa1412e6 100644 --- a/drivers/media/dvb/frontends/qt1010.c +++ b/drivers/media/common/tuners/qt1010.c diff --git a/drivers/media/dvb/frontends/qt1010.h b/drivers/media/common/tuners/qt1010.h index cff6a7ca538..807fb7b6146 100644 --- a/drivers/media/dvb/frontends/qt1010.h +++ b/drivers/media/common/tuners/qt1010.h @@ -36,7 +36,7 @@ struct qt1010_config { * @param cfg tuner hw based configuration * @return fe pointer on success, NULL on failure */ -#if defined(CONFIG_DVB_TUNER_QT1010) || (defined(CONFIG_DVB_TUNER_QT1010_MODULE) && defined(MODULE)) +#if defined(CONFIG_MEDIA_TUNER_QT1010) || (defined(CONFIG_MEDIA_TUNER_QT1010_MODULE) && defined(MODULE)) extern struct dvb_frontend *qt1010_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct qt1010_config *cfg); @@ -48,6 +48,6 @@ static inline struct dvb_frontend *qt1010_attach(struct dvb_frontend *fe, printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return NULL; } -#endif // CONFIG_DVB_TUNER_QT1010 +#endif // CONFIG_MEDIA_TUNER_QT1010 #endif diff --git a/drivers/media/dvb/frontends/qt1010_priv.h b/drivers/media/common/tuners/qt1010_priv.h index 090cf475f09..090cf475f09 100644 --- a/drivers/media/dvb/frontends/qt1010_priv.h +++ b/drivers/media/common/tuners/qt1010_priv.h diff --git a/drivers/media/dvb/frontends/tda18271-common.c b/drivers/media/common/tuners/tda18271-common.c index e27a7620a32..e27a7620a32 100644 --- a/drivers/media/dvb/frontends/tda18271-common.c +++ b/drivers/media/common/tuners/tda18271-common.c diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/common/tuners/tda18271-fe.c index b262100ae89..b262100ae89 100644 --- a/drivers/media/dvb/frontends/tda18271-fe.c +++ b/drivers/media/common/tuners/tda18271-fe.c diff --git a/drivers/media/dvb/frontends/tda18271-tables.c b/drivers/media/common/tuners/tda18271-maps.c index 83e7561960c..83e7561960c 100644 --- a/drivers/media/dvb/frontends/tda18271-tables.c +++ b/drivers/media/common/tuners/tda18271-maps.c diff --git a/drivers/media/dvb/frontends/tda18271-priv.h b/drivers/media/common/tuners/tda18271-priv.h index 2bc5eb368ea..2bc5eb368ea 100644 --- a/drivers/media/dvb/frontends/tda18271-priv.h +++ b/drivers/media/common/tuners/tda18271-priv.h diff --git a/drivers/media/dvb/frontends/tda18271.h b/drivers/media/common/tuners/tda18271.h index 0e7af8d05a3..7db9831c0cb 100644 --- a/drivers/media/dvb/frontends/tda18271.h +++ b/drivers/media/common/tuners/tda18271.h @@ -81,7 +81,7 @@ struct tda18271_config { unsigned int small_i2c:1; }; -#if defined(CONFIG_DVB_TDA18271) || (defined(CONFIG_DVB_TDA18271_MODULE) && defined(MODULE)) +#if defined(CONFIG_MEDIA_TUNER_TDA18271) || (defined(CONFIG_MEDIA_TUNER_TDA18271_MODULE) && defined(MODULE)) extern struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, struct i2c_adapter *i2c, struct tda18271_config *cfg); diff --git a/drivers/media/dvb/frontends/tda827x.c b/drivers/media/common/tuners/tda827x.c index d30d2c9094d..d30d2c9094d 100644 --- a/drivers/media/dvb/frontends/tda827x.c +++ b/drivers/media/common/tuners/tda827x.c diff --git a/drivers/media/dvb/frontends/tda827x.h b/drivers/media/common/tuners/tda827x.h index b73c23570da..7850a9a1dc8 100644 --- a/drivers/media/dvb/frontends/tda827x.h +++ b/drivers/media/common/tuners/tda827x.h @@ -51,7 +51,7 @@ struct tda827x_config * @param cfg optional callback function pointers. * @return FE pointer on success, NULL on failure. */ -#if defined(CONFIG_DVB_TDA827X) || (defined(CONFIG_DVB_TDA827X_MODULE) && defined(MODULE)) +#if defined(CONFIG_MEDIA_TUNER_TDA827X) || (defined(CONFIG_MEDIA_TUNER_TDA827X_MODULE) && defined(MODULE)) extern struct dvb_frontend* tda827x_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c, struct tda827x_config *cfg); @@ -64,6 +64,6 @@ static inline struct dvb_frontend* tda827x_attach(struct dvb_frontend *fe, printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return NULL; } -#endif // CONFIG_DVB_TDA827X +#endif // CONFIG_MEDIA_TUNER_TDA827X #endif // __DVB_TDA827X_H__ diff --git a/drivers/media/video/tda8290.c b/drivers/media/common/tuners/tda8290.c index 0ebb5b525e5..91204d3f282 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/common/tuners/tda8290.c @@ -578,16 +578,16 @@ static int tda829x_find_tuner(struct dvb_frontend *fe) if ((data == 0x83) || (data == 0x84)) { priv->ver |= TDA18271; - tda18271_attach(fe, priv->tda827x_addr, - priv->i2c_props.adap, - &tda829x_tda18271_config); + dvb_attach(tda18271_attach, fe, priv->tda827x_addr, + priv->i2c_props.adap, &tda829x_tda18271_config); } else { if ((data & 0x3c) == 0) priv->ver |= TDA8275; else priv->ver |= TDA8275A; - tda827x_attach(fe, priv->tda827x_addr, priv->i2c_props.adap, &priv->cfg); + dvb_attach(tda827x_attach, fe, priv->tda827x_addr, + priv->i2c_props.adap, &priv->cfg); priv->cfg.switch_addr = priv->i2c_props.addr; } if (fe->ops.tuner_ops.init) diff --git a/drivers/media/video/tda8290.h b/drivers/media/common/tuners/tda8290.h index d3bbf276a46..aa074f3f0c0 100644 --- a/drivers/media/video/tda8290.h +++ b/drivers/media/common/tuners/tda8290.h @@ -29,7 +29,7 @@ struct tda829x_config { #define TDA829X_DONT_PROBE 1 }; -#if defined(CONFIG_TUNER_TDA8290) || (defined(CONFIG_TUNER_TDA8290_MODULE) && defined(MODULE)) +#if defined(CONFIG_MEDIA_TUNER_TDA8290) || (defined(CONFIG_MEDIA_TUNER_TDA8290_MODULE) && defined(MODULE)) extern int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr); extern struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe, diff --git a/drivers/media/video/tda9887.c b/drivers/media/common/tuners/tda9887.c index a0545ba957b..a0545ba957b 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/common/tuners/tda9887.c diff --git a/drivers/media/video/tda9887.h b/drivers/media/common/tuners/tda9887.h index be49dcbfc70..acc419e8c4f 100644 --- a/drivers/media/video/tda9887.h +++ b/drivers/media/common/tuners/tda9887.h @@ -21,7 +21,7 @@ #include "dvb_frontend.h" /* ------------------------------------------------------------------------ */ -#if defined(CONFIG_TUNER_TDA9887) || (defined(CONFIG_TUNER_TDA9887_MODULE) && defined(MODULE)) +#if defined(CONFIG_MEDIA_TUNER_TDA9887) || (defined(CONFIG_MEDIA_TUNER_TDA9887_MODULE) && defined(MODULE)) extern struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c_adap, u8 i2c_addr); diff --git a/drivers/media/video/tea5761.c b/drivers/media/common/tuners/tea5761.c index b93cdef9ac7..b93cdef9ac7 100644 --- a/drivers/media/video/tea5761.c +++ b/drivers/media/common/tuners/tea5761.c diff --git a/drivers/media/video/tea5761.h b/drivers/media/common/tuners/tea5761.h index 8eb62722b98..2e2ff82c95a 100644 --- a/drivers/media/video/tea5761.h +++ b/drivers/media/common/tuners/tea5761.h @@ -20,7 +20,7 @@ #include <linux/i2c.h> #include "dvb_frontend.h" -#if defined(CONFIG_TUNER_TEA5761) || (defined(CONFIG_TUNER_TEA5761_MODULE) && defined(MODULE)) +#if defined(CONFIG_MEDIA_TUNER_TEA5761) || (defined(CONFIG_MEDIA_TUNER_TEA5761_MODULE) && defined(MODULE)) extern int tea5761_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr); extern struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe, diff --git a/drivers/media/video/tea5767.c b/drivers/media/common/tuners/tea5767.c index f6e7d7ad842..f6e7d7ad842 100644 --- a/drivers/media/video/tea5767.c +++ b/drivers/media/common/tuners/tea5767.c diff --git a/drivers/media/video/tea5767.h b/drivers/media/common/tuners/tea5767.h index 7b547c092e2..d30ab1b483d 100644 --- a/drivers/media/video/tea5767.h +++ b/drivers/media/common/tuners/tea5767.h @@ -39,7 +39,7 @@ struct tea5767_ctrl { enum tea5767_xtal xtal_freq; }; -#if defined(CONFIG_TUNER_TEA5767) || (defined(CONFIG_TUNER_TEA5767_MODULE) && defined(MODULE)) +#if defined(CONFIG_MEDIA_TUNER_TEA5767) || (defined(CONFIG_MEDIA_TUNER_TEA5767_MODULE) && defined(MODULE)) extern int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr); extern struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe, diff --git a/drivers/media/video/tuner-i2c.h b/drivers/media/common/tuners/tuner-i2c.h index 3ad6c8e0b04..3ad6c8e0b04 100644 --- a/drivers/media/video/tuner-i2c.h +++ b/drivers/media/common/tuners/tuner-i2c.h diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/common/tuners/tuner-simple.c index be8d903171b..be8d903171b 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/common/tuners/tuner-simple.c diff --git a/drivers/media/video/tuner-simple.h b/drivers/media/common/tuners/tuner-simple.h index e46cf0121e0..381fa5d35a9 100644 --- a/drivers/media/video/tuner-simple.h +++ b/drivers/media/common/tuners/tuner-simple.h @@ -20,7 +20,7 @@ #include <linux/i2c.h> #include "dvb_frontend.h" -#if defined(CONFIG_TUNER_SIMPLE) || (defined(CONFIG_TUNER_SIMPLE_MODULE) && defined(MODULE)) +#if defined(CONFIG_MEDIA_TUNER_SIMPLE) || (defined(CONFIG_MEDIA_TUNER_SIMPLE_MODULE) && defined(MODULE)) extern struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c_adap, u8 i2c_addr, diff --git a/drivers/media/video/tuner-types.c b/drivers/media/common/tuners/tuner-types.c index 10dddca8b5d..10dddca8b5d 100644 --- a/drivers/media/video/tuner-types.c +++ b/drivers/media/common/tuners/tuner-types.c diff --git a/drivers/media/video/tuner-xc2028-types.h b/drivers/media/common/tuners/tuner-xc2028-types.h index 74dc46a71f6..74dc46a71f6 100644 --- a/drivers/media/video/tuner-xc2028-types.h +++ b/drivers/media/common/tuners/tuner-xc2028-types.h diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/common/tuners/tuner-xc2028.c index 9e9003cffc7..9e9003cffc7 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/common/tuners/tuner-xc2028.c diff --git a/drivers/media/video/tuner-xc2028.h b/drivers/media/common/tuners/tuner-xc2028.h index fc2f132a554..216025cf5d4 100644 --- a/drivers/media/video/tuner-xc2028.h +++ b/drivers/media/common/tuners/tuner-xc2028.h @@ -47,7 +47,7 @@ struct xc2028_config { #define XC2028_TUNER_RESET 0 #define XC2028_RESET_CLK 1 -#if defined(CONFIG_TUNER_XC2028) || (defined(CONFIG_TUNER_XC2028_MODULE) && defined(MODULE)) +#if defined(CONFIG_MEDIA_TUNER_XC2028) || (defined(CONFIG_MEDIA_TUNER_XC2028_MODULE) && defined(MODULE)) extern struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe, struct xc2028_config *cfg); #else diff --git a/drivers/media/dvb/frontends/xc5000.c b/drivers/media/common/tuners/xc5000.c index 43d35bdb221..43d35bdb221 100644 --- a/drivers/media/dvb/frontends/xc5000.c +++ b/drivers/media/common/tuners/xc5000.c diff --git a/drivers/media/dvb/frontends/xc5000.h b/drivers/media/common/tuners/xc5000.h index b890883a0cd..0ee80f9d19b 100644 --- a/drivers/media/dvb/frontends/xc5000.h +++ b/drivers/media/common/tuners/xc5000.h @@ -45,8 +45,8 @@ struct xc5000_config { /* xc5000 callback command */ #define XC5000_TUNER_RESET 0 -#if defined(CONFIG_DVB_TUNER_XC5000) || \ - (defined(CONFIG_DVB_TUNER_XC5000_MODULE) && defined(MODULE)) +#if defined(CONFIG_MEDIA_TUNER_XC5000) || \ + (defined(CONFIG_MEDIA_TUNER_XC5000_MODULE) && defined(MODULE)) extern struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct xc5000_config *cfg); @@ -58,6 +58,6 @@ static inline struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe, printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return NULL; } -#endif // CONFIG_DVB_TUNER_XC5000 +#endif // CONFIG_MEDIA_TUNER_XC5000 #endif // __XC5000_H__ diff --git a/drivers/media/dvb/frontends/xc5000_priv.h b/drivers/media/common/tuners/xc5000_priv.h index 13b2d19341d..13b2d19341d 100644 --- a/drivers/media/dvb/frontends/xc5000_priv.h +++ b/drivers/media/common/tuners/xc5000_priv.h diff --git a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig index 03ef88acd9b..7b21b49f194 100644 --- a/drivers/media/dvb/Kconfig +++ b/drivers/media/dvb/Kconfig @@ -1,9 +1,7 @@ # -# Multimedia device configuration +# DVB device configuration # -source "drivers/media/dvb/dvb-core/Kconfig" - menuconfig DVB_CAPTURE_DRIVERS bool "DVB/ATSC adapters" depends on DVB_CORE diff --git a/drivers/media/dvb/b2c2/Kconfig b/drivers/media/dvb/b2c2/Kconfig index 6ec5afba1ca..73dc2ee9b01 100644 --- a/drivers/media/dvb/b2c2/Kconfig +++ b/drivers/media/dvb/b2c2/Kconfig @@ -9,7 +9,7 @@ config DVB_B2C2_FLEXCOP select DVB_STV0297 if !DVB_FE_CUSTOMISE select DVB_BCM3510 if !DVB_FE_CUSTOMISE select DVB_LGDT330X if !DVB_FE_CUSTOMISE - select TUNER_SIMPLE if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE select DVB_S5H1420 if !DVB_FE_CUSTOMISE select DVB_TUNER_ITD1000 if !DVB_FE_CUSTOMISE select DVB_ISL6421 if !DVB_FE_CUSTOMISE diff --git a/drivers/media/dvb/b2c2/Makefile b/drivers/media/dvb/b2c2/Makefile index 870e2848c29..d9db066f985 100644 --- a/drivers/media/dvb/b2c2/Makefile +++ b/drivers/media/dvb/b2c2/Makefile @@ -14,4 +14,4 @@ b2c2-flexcop-usb-objs = flexcop-usb.o obj-$(CONFIG_DVB_B2C2_FLEXCOP_USB) += b2c2-flexcop-usb.o EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ -EXTRA_CFLAGS += -Idrivers/media/video/ +EXTRA_CFLAGS += -Idrivers/media/common/tuners/ diff --git a/drivers/media/dvb/bt8xx/Kconfig b/drivers/media/dvb/bt8xx/Kconfig index 902c762e0b7..d1239b8342f 100644 --- a/drivers/media/dvb/bt8xx/Kconfig +++ b/drivers/media/dvb/bt8xx/Kconfig @@ -8,7 +8,7 @@ config DVB_BT8XX select DVB_OR51211 if !DVB_FE_CUSTOMISE select DVB_LGDT330X if !DVB_FE_CUSTOMISE select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select TUNER_SIMPLE if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE select FW_LOADER help Support for PCI cards based on the Bt8xx PCI bridge. Examples are diff --git a/drivers/media/dvb/bt8xx/Makefile b/drivers/media/dvb/bt8xx/Makefile index 9d3e68b5d6e..d98f1d49ffa 100644 --- a/drivers/media/dvb/bt8xx/Makefile +++ b/drivers/media/dvb/bt8xx/Makefile @@ -3,4 +3,4 @@ obj-$(CONFIG_DVB_BT8XX) += bt878.o dvb-bt8xx.o dst.o dst_ca.o EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core EXTRA_CFLAGS += -Idrivers/media/dvb/frontends EXTRA_CFLAGS += -Idrivers/media/video/bt8xx -EXTRA_CFLAGS += -Idrivers/media/video +EXTRA_CFLAGS += -Idrivers/media/common/tuners diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c index 75711bde23a..a7637562e74 100644 --- a/drivers/media/dvb/bt8xx/dst.c +++ b/drivers/media/dvb/bt8xx/dst.c @@ -1714,7 +1714,7 @@ static void dst_release(struct dvb_frontend *fe) struct dst_state *state = fe->demodulator_priv; if (state->dst_ca) { dvb_unregister_device(state->dst_ca); -#ifdef CONFIG_DVB_CORE_ATTACH +#ifdef CONFIG_MEDIA_ATTACH symbol_put(dst_ca_attach); #endif } diff --git a/drivers/media/dvb/dvb-core/Kconfig b/drivers/media/dvb/dvb-core/Kconfig deleted file mode 100644 index e3e6839f807..00000000000 --- a/drivers/media/dvb/dvb-core/Kconfig +++ /dev/null @@ -1,34 +0,0 @@ -config DVB_CORE - tristate "DVB for Linux" - depends on NET && INET - select CRC32 - help - Support Digital Video Broadcasting hardware. Enable this if you - own a DVB adapter and want to use it or if you compile Linux for - a digital SetTopBox. - - DVB core utility functions for device handling, software fallbacks etc. - Say Y when you have a DVB card and want to use it. Say Y if your want - to build your drivers outside the kernel, but need the DVB core. All - in-kernel drivers will select this automatically if needed. - - API specs and user tools are available from <http://www.linuxtv.org/>. - - Please report problems regarding this driver to the LinuxDVB - mailing list. - - If unsure say N. - -config DVB_CORE_ATTACH - bool "Load and attach frontend modules as needed" - depends on DVB_CORE - depends on MODULES - help - Remove the static dependency of DVB card drivers on all - frontend modules for all possible card variants. Instead, - allow the card drivers to only load the frontend modules - they require. This saves several KBytes of memory. - - Note: You will need module-init-tools v3.2 or later for this feature. - - If unsure say Y. diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 2dddd08c544..8cbdb218952 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -1189,7 +1189,7 @@ int dvb_unregister_frontend(struct dvb_frontend* fe) } EXPORT_SYMBOL(dvb_unregister_frontend); -#ifdef CONFIG_DVB_CORE_ATTACH +#ifdef CONFIG_MEDIA_ATTACH void dvb_frontend_detach(struct dvb_frontend* fe) { void *ptr; diff --git a/drivers/media/dvb/dvb-core/dvbdev.h b/drivers/media/dvb/dvb-core/dvbdev.h index 5f9a737c6de..89d12dc477a 100644 --- a/drivers/media/dvb/dvb-core/dvbdev.h +++ b/drivers/media/dvb/dvb-core/dvbdev.h @@ -115,7 +115,7 @@ extern int dvb_usercopy(struct inode *inode, struct file *file, unsigned int cmd, void *arg)); /** generic DVB attach function. */ -#ifdef CONFIG_DVB_CORE_ATTACH +#ifdef CONFIG_MEDIA_ATTACH #define dvb_attach(FUNCTION, ARGS...) ({ \ void *__r = NULL; \ typeof(&FUNCTION) __a = symbol_request(FUNCTION); \ diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index 3c8493d2026..4c1cff9feb2 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -25,7 +25,7 @@ config DVB_USB_A800 tristate "AVerMedia AverTV DVB-T USB 2.0 (A800)" depends on DVB_USB select DVB_DIB3000MC - select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE select DVB_PLL if !DVB_FE_CUSTOMISE help Say Y here to support the AVerMedia AverTV DVB-T USB 2.0 (A800) receiver. @@ -35,7 +35,7 @@ config DVB_USB_DIBUSB_MB depends on DVB_USB select DVB_PLL if !DVB_FE_CUSTOMISE select DVB_DIB3000MB - select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE help Support for USB 1.1 and 2.0 DVB-T receivers based on reference designs made by DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-B demodulator. @@ -56,7 +56,7 @@ config DVB_USB_DIBUSB_MC tristate "DiBcom USB DVB-T devices (based on the DiB3000M-C/P) (see help for device list)" depends on DVB_USB select DVB_DIB3000MC - select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE help Support for USB2.0 DVB-T receivers based on reference designs made by DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-C/P demodulator. @@ -73,8 +73,8 @@ config DVB_USB_DIB0700 select DVB_DIB7000P select DVB_DIB7000M select DVB_DIB3000MC - select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE - select DVB_TUNER_MT2266 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2266 if !DVB_FE_CUSTOMISE select DVB_TUNER_DIB0070 help Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The @@ -93,7 +93,7 @@ config DVB_USB_UMT_010 depends on DVB_USB select DVB_PLL if !DVB_FE_CUSTOMISE select DVB_DIB3000MC - select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE help Say Y here to support the HanfTek UMT-010 USB2.0 stick-sized DVB-T receiver. @@ -105,7 +105,7 @@ config DVB_USB_CXUSB select DVB_LGDT330X if !DVB_FE_CUSTOMISE select DVB_MT352 if !DVB_FE_CUSTOMISE select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select TUNER_SIMPLE if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE help Say Y here to support the Conexant USB2.0 hybrid reference design. Currently, only DVB and ATSC modes are supported, analog mode @@ -118,7 +118,7 @@ config DVB_USB_M920X tristate "Uli m920x DVB-T USB2.0 support" depends on DVB_USB select DVB_MT352 if !DVB_FE_CUSTOMISE - select DVB_TUNER_QT1010 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE help Say Y here to support the MSI Mega Sky 580 USB2.0 DVB-T receiver. Currently, only devices with a product id of @@ -129,7 +129,7 @@ config DVB_USB_GL861 tristate "Genesys Logic GL861 USB2.0 support" depends on DVB_USB select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select DVB_TUNER_QT1010 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE help Say Y here to support the MSI Megasky 580 (55801) DVB-T USB2.0 receiver with USB ID 0db0:5581. @@ -138,7 +138,7 @@ config DVB_USB_AU6610 tristate "Alcor Micro AU6610 USB2.0 support" depends on DVB_USB select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select DVB_TUNER_QT1010 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE help Say Y here to support the Sigmatek DVB-110 DVB-T USB2.0 receiver. @@ -190,7 +190,7 @@ config DVB_USB_NOVA_T_USB2 tristate "Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 support" depends on DVB_USB select DVB_DIB3000MC - select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE select DVB_PLL if !DVB_FE_CUSTOMISE help Say Y here to support the Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 receiver. @@ -227,8 +227,8 @@ config DVB_USB_OPERA1 config DVB_USB_AF9005 tristate "Afatech AF9005 DVB-T USB1.1 support" depends on DVB_USB && EXPERIMENTAL - select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE - select DVB_TUNER_QT1010 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE help Say Y here to support the Afatech AF9005 based DVB-T USB1.1 receiver and the TerraTec Cinergy T USB XE (Rev.1) diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile index 60a910052c1..c6511a6c0ab 100644 --- a/drivers/media/dvb/dvb-usb/Makefile +++ b/drivers/media/dvb/dvb-usb/Makefile @@ -63,5 +63,5 @@ obj-$(CONFIG_DVB_USB_AF9005_REMOTE) += dvb-usb-af9005-remote.o EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ # due to tuner-xc3028 -EXTRA_CFLAGS += -Idrivers/media/video +EXTRA_CFLAGS += -Idrivers/media/common/tuners diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index f5fceb3cdb3..6d238460592 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -15,22 +15,36 @@ config DVB_FE_CUSTOMISE comment "DVB-S (satellite) frontends" depends on DVB_CORE -config DVB_STV0299 - tristate "ST STV0299 based" +config DVB_CX24110 + tristate "Conexant CX24110 based" depends on DVB_CORE && I2C default m if DVB_FE_CUSTOMISE help A DVB-S tuner module. Say Y when you want to support this frontend. -config DVB_CX24110 - tristate "Conexant CX24110 based" +config DVB_CX24123 + tristate "Conexant CX24123 based" depends on DVB_CORE && I2C default m if DVB_FE_CUSTOMISE help A DVB-S tuner module. Say Y when you want to support this frontend. -config DVB_CX24123 - tristate "Conexant CX24123 based" +config DVB_MT312 + tristate "Zarlink VP310/MT312 based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-S tuner module. Say Y when you want to support this frontend. + +config DVB_S5H1420 + tristate "Samsung S5H1420 based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-S tuner module. Say Y when you want to support this frontend. + +config DVB_STV0299 + tristate "ST STV0299 based" depends on DVB_CORE && I2C default m if DVB_FE_CUSTOMISE help @@ -43,8 +57,8 @@ config DVB_TDA8083 help A DVB-S tuner module. Say Y when you want to support this frontend. -config DVB_MT312 - tristate "Zarlink VP310/MT312 based" +config DVB_TDA10086 + tristate "Philips TDA10086 based" depends on DVB_CORE && I2C default m if DVB_FE_CUSTOMISE help @@ -57,19 +71,26 @@ config DVB_VES1X93 help A DVB-S tuner module. Say Y when you want to support this frontend. -config DVB_S5H1420 - tristate "Samsung S5H1420 based" +config DVB_TUNER_ITD1000 + tristate "Integrant ITD1000 Zero IF tuner for DVB-S/DSS" depends on DVB_CORE && I2C default m if DVB_FE_CUSTOMISE help A DVB-S tuner module. Say Y when you want to support this frontend. -config DVB_TDA10086 - tristate "Philips TDA10086 based" +config DVB_TDA826X + tristate "Philips TDA826X silicon tuner" depends on DVB_CORE && I2C default m if DVB_FE_CUSTOMISE help - A DVB-S tuner module. Say Y when you want to support this frontend. + A DVB-S silicon tuner module. Say Y when you want to support this tuner. + +config DVB_TUA6100 + tristate "Infineon TUA6100 PLL" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-S PLL chip. comment "DVB-T (terrestrial) frontends" depends on DVB_CORE @@ -315,7 +336,7 @@ config DVB_S5H1411 An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want to support this frontend. -comment "Tuners/PLL support" +comment "Digital terrestrial only tuners/PLL" depends on DVB_CORE config DVB_PLL @@ -326,55 +347,6 @@ config DVB_PLL This module drives a number of tuners based on PLL chips with a common I2C interface. Say Y when you want to support these tuners. -config DVB_TDA826X - tristate "Philips TDA826X silicon tuner" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-S silicon tuner module. Say Y when you want to support this tuner. - -config DVB_TDA827X - tristate "Philips TDA827X silicon tuner" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-T silicon tuner module. Say Y when you want to support this tuner. - -config DVB_TDA18271 - tristate "NXP TDA18271 silicon tuner" - depends on I2C - default m if DVB_FE_CUSTOMISE - help - A silicon tuner module. Say Y when you want to support this tuner. - -config DVB_TUNER_QT1010 - tristate "Quantek QT1010 silicon tuner" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A driver for the silicon tuner QT1010 from Quantek. - -config DVB_TUNER_MT2060 - tristate "Microtune MT2060 silicon IF tuner" - depends on I2C - default m if DVB_FE_CUSTOMISE - help - A driver for the silicon IF tuner MT2060 from Microtune. - -config DVB_TUNER_MT2266 - tristate "Microtune MT2266 silicon tuner" - depends on I2C - default m if DVB_FE_CUSTOMISE - help - A driver for the silicon baseband tuner MT2266 from Microtune. - -config DVB_TUNER_MT2131 - tristate "Microtune MT2131 silicon tuner" - depends on I2C - default m if DVB_FE_CUSTOMISE - help - A driver for the silicon baseband tuner MT2131 from Microtune. - config DVB_TUNER_DIB0070 tristate "DiBcom DiB0070 silicon base-band tuner" depends on I2C @@ -384,21 +356,7 @@ config DVB_TUNER_DIB0070 This device is only used inside a SiP called togther with a demodulator for now. -config DVB_TUNER_XC5000 - tristate "Xceive XC5000 silicon tuner" - depends on I2C - default m if DVB_FE_CUSTOMISE - help - A driver for the silicon tuner XC5000 from Xceive. - This device is only used inside a SiP called togther with a - demodulator for now. - -config DVB_TUNER_ITD1000 - tristate "Integrant ITD1000 Zero IF tuner for DVB-S/DSS" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - -comment "Miscellaneous devices" +comment "SEC control devices for DVB-S" depends on DVB_CORE config DVB_LNBP21 @@ -422,11 +380,4 @@ config DVB_ISL6421 help An SEC control chip. -config DVB_TUA6100 - tristate "TUA6100 PLL" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVBS PLL chip. - endmenu diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index 9747c73dc82..a89dc0fc4c6 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -3,9 +3,7 @@ # EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -EXTRA_CFLAGS += -Idrivers/media/video/ - -tda18271-objs := tda18271-tables.o tda18271-common.o tda18271-fe.o +EXTRA_CFLAGS += -Idrivers/media/common/tuners/ obj-$(CONFIG_DVB_PLL) += dvb-pll.o obj-$(CONFIG_DVB_STV0299) += stv0299.o @@ -42,16 +40,9 @@ obj-$(CONFIG_DVB_ISL6405) += isl6405.o obj-$(CONFIG_DVB_ISL6421) += isl6421.o obj-$(CONFIG_DVB_TDA10086) += tda10086.o obj-$(CONFIG_DVB_TDA826X) += tda826x.o -obj-$(CONFIG_DVB_TDA827X) += tda827x.o -obj-$(CONFIG_DVB_TDA18271) += tda18271.o -obj-$(CONFIG_DVB_TUNER_MT2060) += mt2060.o -obj-$(CONFIG_DVB_TUNER_MT2266) += mt2266.o obj-$(CONFIG_DVB_TUNER_DIB0070) += dib0070.o -obj-$(CONFIG_DVB_TUNER_QT1010) += qt1010.o obj-$(CONFIG_DVB_TUA6100) += tua6100.o -obj-$(CONFIG_DVB_TUNER_MT2131) += mt2131.o obj-$(CONFIG_DVB_S5H1409) += s5h1409.o -obj-$(CONFIG_DVB_TUNER_XC5000) += xc5000.o obj-$(CONFIG_DVB_TUNER_ITD1000) += itd1000.o obj-$(CONFIG_DVB_AU8522) += au8522.o obj-$(CONFIG_DVB_TDA10048) += tda10048.o diff --git a/drivers/media/dvb/frontends/s5h1420.c b/drivers/media/dvb/frontends/s5h1420.c index 281e1cb2edc..720ed9ff7c5 100644 --- a/drivers/media/dvb/frontends/s5h1420.c +++ b/drivers/media/dvb/frontends/s5h1420.c @@ -481,7 +481,7 @@ static void s5h1420_setsymbolrate(struct s5h1420_state* state, val *= 2; do_div(val, (state->fclk / 1000)); - dprintk("symbol rate register: %06llx\n", val); + dprintk("symbol rate register: %06llx\n", (unsigned long long)val); v = s5h1420_readreg(state, Loop01); s5h1420_writereg(state, Loop01, v & 0x7f); diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index fe9a4cc1414..fe743aa7f64 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -1,4 +1,50 @@ # +# Generic video config states +# + +config VIDEO_V4L2 + tristate + depends on VIDEO_DEV && VIDEO_V4L2_COMMON + default VIDEO_DEV && VIDEO_V4L2_COMMON + +config VIDEO_V4L1 + tristate + depends on VIDEO_DEV && VIDEO_V4L2_COMMON && VIDEO_ALLOW_V4L1 + default VIDEO_DEV && VIDEO_V4L2_COMMON && VIDEO_ALLOW_V4L1 + +config VIDEOBUF_GEN + tristate + +config VIDEOBUF_DMA_SG + depends on HAS_DMA + select VIDEOBUF_GEN + tristate + +config VIDEOBUF_VMALLOC + select VIDEOBUF_GEN + tristate + +config VIDEOBUF_DVB + tristate + select VIDEOBUF_GEN + select VIDEOBUF_DMA_SG + +config VIDEO_BTCX + tristate + +config VIDEO_IR_I2C + tristate + +config VIDEO_IR + tristate + depends on INPUT + select VIDEO_IR_I2C if I2C + +config VIDEO_TVEEPROM + tristate + depends on I2C + +# # Multimedia Video device configuration # @@ -644,7 +690,7 @@ config VIDEO_MXB tristate "Siemens-Nixdorf 'Multimedia eXtension Board'" depends on PCI && VIDEO_V4L1 && I2C select VIDEO_SAA7146_VV - select VIDEO_TUNER + select MEDIA_TUNER select VIDEO_SAA7111 if VIDEO_HELPER_CHIPS_AUTO select VIDEO_TDA9840 if VIDEO_HELPER_CHIPS_AUTO select VIDEO_TEA6415C if VIDEO_HELPER_CHIPS_AUTO @@ -702,6 +748,8 @@ source "drivers/media/video/au0828/Kconfig" source "drivers/media/video/ivtv/Kconfig" +source "drivers/media/video/cx18/Kconfig" + config VIDEO_M32R_AR tristate "AR devices" depends on M32R && VIDEO_V4L1 diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index be14227f372..a352c6e31f0 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -84,17 +84,7 @@ obj-$(CONFIG_VIDEO_HEXIUM_GEMINI) += hexium_gemini.o obj-$(CONFIG_VIDEO_DPC) += dpc7146.o obj-$(CONFIG_TUNER_3036) += tuner-3036.o -obj-$(CONFIG_VIDEO_TUNER) += tuner.o - -obj-$(CONFIG_TUNER_XC2028) += tuner-xc2028.o -obj-$(CONFIG_TUNER_SIMPLE) += tuner-simple.o -# tuner-types will be merged into tuner-simple, in the future -obj-$(CONFIG_TUNER_SIMPLE) += tuner-types.o -obj-$(CONFIG_TUNER_MT20XX) += mt20xx.o -obj-$(CONFIG_TUNER_TDA8290) += tda8290.o -obj-$(CONFIG_TUNER_TEA5767) += tea5767.o -obj-$(CONFIG_TUNER_TEA5761) += tea5761.o -obj-$(CONFIG_TUNER_TDA9887) += tda9887.o +obj-$(CONFIG_MEDIA_TUNER) += tuner.o obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o @@ -134,6 +124,7 @@ obj-$(CONFIG_USB_VICAM) += usbvideo/ obj-$(CONFIG_USB_QUICKCAM_MESSENGER) += usbvideo/ obj-$(CONFIG_VIDEO_IVTV) += ivtv/ +obj-$(CONFIG_VIDEO_CX18) += cx18/ obj-$(CONFIG_VIDEO_VIVI) += vivi.o obj-$(CONFIG_VIDEO_CX23885) += cx23885/ @@ -147,3 +138,4 @@ obj-$(CONFIG_VIDEO_AU0828) += au0828/ EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core EXTRA_CFLAGS += -Idrivers/media/dvb/frontends +EXTRA_CFLAGS += -Idrivers/media/common/tuners diff --git a/drivers/media/video/au0828/Kconfig b/drivers/media/video/au0828/Kconfig index 41708267e7a..cab277fafa6 100644 --- a/drivers/media/video/au0828/Kconfig +++ b/drivers/media/video/au0828/Kconfig @@ -4,7 +4,7 @@ config VIDEO_AU0828 depends on VIDEO_DEV && I2C && INPUT && DVB_CORE select I2C_ALGOBIT select DVB_AU8522 if !DVB_FE_CUSTOMIZE - select DVB_TUNER_XC5000 if !DVB_FE_CUSTOMIZE + select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMIZE ---help--- This is a video4linux driver for Auvitek's USB device. diff --git a/drivers/media/video/au0828/Makefile b/drivers/media/video/au0828/Makefile index 9f4f572c89c..cd2c58281b4 100644 --- a/drivers/media/video/au0828/Makefile +++ b/drivers/media/video/au0828/Makefile @@ -2,7 +2,7 @@ au0828-objs := au0828-core.o au0828-i2c.o au0828-cards.o au0828-dvb.o obj-$(CONFIG_VIDEO_AU0828) += au0828.o -EXTRA_CFLAGS += -Idrivers/media/video +EXTRA_CFLAGS += -Idrivers/media/common/tuners EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core EXTRA_CFLAGS += -Idrivers/media/dvb/frontends diff --git a/drivers/media/video/au0828/au0828-dvb.c b/drivers/media/video/au0828/au0828-dvb.c index 5040d7fc4af..1371b4e4b5f 100644 --- a/drivers/media/video/au0828/au0828-dvb.c +++ b/drivers/media/video/au0828/au0828-dvb.c @@ -119,7 +119,7 @@ static int start_urb_transfer(struct au0828_dev *dev) purb->transfer_buffer = kzalloc(URB_BUFSIZE, GFP_KERNEL); if (!purb->transfer_buffer) { usb_free_urb(purb); - dev->urbs[i] = 0; + dev->urbs[i] = NULL; goto err; } diff --git a/drivers/media/video/bt8xx/Kconfig b/drivers/media/video/bt8xx/Kconfig index cfc822bb502..7431ef6de9f 100644 --- a/drivers/media/video/bt8xx/Kconfig +++ b/drivers/media/video/bt8xx/Kconfig @@ -6,7 +6,7 @@ config VIDEO_BT848 select VIDEO_BTCX select VIDEOBUF_DMA_SG select VIDEO_IR - select VIDEO_TUNER + select MEDIA_TUNER select VIDEO_TVEEPROM select VIDEO_MSP3400 if VIDEO_HELPER_CHIPS_AUTO select VIDEO_TVAUDIO if VIDEO_HELPER_CHIPS_AUTO diff --git a/drivers/media/video/bt8xx/Makefile b/drivers/media/video/bt8xx/Makefile index 924d216d957..e415f6fc447 100644 --- a/drivers/media/video/bt8xx/Makefile +++ b/drivers/media/video/bt8xx/Makefile @@ -9,4 +9,5 @@ bttv-objs := bttv-driver.o bttv-cards.o bttv-if.o \ obj-$(CONFIG_VIDEO_BT848) += bttv.o EXTRA_CFLAGS += -Idrivers/media/video +EXTRA_CFLAGS += -Idrivers/media/common/tuners EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core diff --git a/drivers/media/video/cs5345.c b/drivers/media/video/cs5345.c index fae469ce16f..2a429f9e32c 100644 --- a/drivers/media/video/cs5345.c +++ b/drivers/media/video/cs5345.c @@ -142,7 +142,8 @@ static int cs5345_command(struct i2c_client *client, unsigned cmd, void *arg) /* ----------------------------------------------------------------------- */ -static int cs5345_probe(struct i2c_client *client) +static int cs5345_probe(struct i2c_client *client, + const struct i2c_device_id *id) { /* Check if the adapter supports the needed features */ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) diff --git a/drivers/media/video/cs53l32a.c b/drivers/media/video/cs53l32a.c index f41bfde045f..2dfd0afc62d 100644 --- a/drivers/media/video/cs53l32a.c +++ b/drivers/media/video/cs53l32a.c @@ -135,7 +135,8 @@ static int cs53l32a_command(struct i2c_client *client, unsigned cmd, void *arg) * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' */ -static int cs53l32a_probe(struct i2c_client *client) +static int cs53l32a_probe(struct i2c_client *client, + const struct i2c_device_id *id) { int i; diff --git a/drivers/media/video/cx18/Kconfig b/drivers/media/video/cx18/Kconfig new file mode 100644 index 00000000000..be654a27bd3 --- /dev/null +++ b/drivers/media/video/cx18/Kconfig @@ -0,0 +1,20 @@ +config VIDEO_CX18 + tristate "Conexant cx23418 MPEG encoder support" + depends on VIDEO_V4L2 && DVB_CORE && PCI && I2C && EXPERIMENTAL + select I2C_ALGOBIT + select FW_LOADER + select VIDEO_IR + select VIDEO_TUNER + select VIDEO_TVEEPROM + select VIDEO_CX2341X + select VIDEO_CS5345 + select DVB_S5H1409 + ---help--- + This is a video4linux driver for Conexant cx23418 based + PCI combo video recorder devices. + + This is used in devices such as the Hauppauge HVR-1600 + cards. + + To compile this driver as a module, choose M here: the + module will be called cx18. diff --git a/drivers/media/video/cx18/Makefile b/drivers/media/video/cx18/Makefile new file mode 100644 index 00000000000..b23d2e26120 --- /dev/null +++ b/drivers/media/video/cx18/Makefile @@ -0,0 +1,11 @@ +cx18-objs := cx18-driver.o cx18-cards.o cx18-i2c.o cx18-firmware.o cx18-gpio.o \ + cx18-queue.o cx18-streams.o cx18-fileops.o cx18-ioctl.o cx18-controls.o \ + cx18-mailbox.o cx18-vbi.o cx18-audio.o cx18-video.o cx18-irq.o \ + cx18-av-core.o cx18-av-audio.o cx18-av-firmware.o cx18-av-vbi.o cx18-scb.o \ + cx18-dvb.o + +obj-$(CONFIG_VIDEO_CX18) += cx18.o + +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core +EXTRA_CFLAGS += -Idrivers/media/dvb/frontends +EXTRA_CFLAGS += -Idrivers/media/common/tuners diff --git a/drivers/media/video/cx18/cx18-audio.c b/drivers/media/video/cx18/cx18-audio.c new file mode 100644 index 00000000000..1adc404d955 --- /dev/null +++ b/drivers/media/video/cx18/cx18-audio.c @@ -0,0 +1,73 @@ +/* + * cx18 audio-related functions + * + * Derived from ivtv-audio.c + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 "cx18-driver.h" +#include "cx18-i2c.h" +#include "cx18-cards.h" +#include "cx18-audio.h" + +/* Selects the audio input and output according to the current + settings. */ +int cx18_audio_set_io(struct cx18 *cx) +{ + struct v4l2_routing route; + u32 audio_input; + int mux_input; + + /* Determine which input to use */ + if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) { + audio_input = cx->card->radio_input.audio_input; + mux_input = cx->card->radio_input.muxer_input; + } else { + audio_input = + cx->card->audio_inputs[cx->audio_input].audio_input; + mux_input = + cx->card->audio_inputs[cx->audio_input].muxer_input; + } + + /* handle muxer chips */ + route.input = mux_input; + route.output = 0; + cx18_i2c_hw(cx, cx->card->hw_muxer, VIDIOC_INT_S_AUDIO_ROUTING, &route); + + route.input = audio_input; + return cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, + VIDIOC_INT_S_AUDIO_ROUTING, &route); +} + +void cx18_audio_set_route(struct cx18 *cx, struct v4l2_routing *route) +{ + cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, + VIDIOC_INT_S_AUDIO_ROUTING, route); +} + +void cx18_audio_set_audio_clock_freq(struct cx18 *cx, u8 freq) +{ + static u32 freqs[3] = { 44100, 48000, 32000 }; + + /* The audio clock of the digitizer must match the codec sample + rate otherwise you get some very strange effects. */ + if (freq > 2) + return; + cx18_call_i2c_clients(cx, VIDIOC_INT_AUDIO_CLOCK_FREQ, &freqs[freq]); +} diff --git a/drivers/media/video/cx18/cx18-audio.h b/drivers/media/video/cx18/cx18-audio.h new file mode 100644 index 00000000000..cb569a69379 --- /dev/null +++ b/drivers/media/video/cx18/cx18-audio.h @@ -0,0 +1,26 @@ +/* + * cx18 audio-related functions + * + * Derived from ivtv-audio.c + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 + */ + +int cx18_audio_set_io(struct cx18 *cx); +void cx18_audio_set_route(struct cx18 *cx, struct v4l2_routing *route); +void cx18_audio_set_audio_clock_freq(struct cx18 *cx, u8 freq); diff --git a/drivers/media/video/cx18/cx18-av-audio.c b/drivers/media/video/cx18/cx18-av-audio.c new file mode 100644 index 00000000000..2dc3a5dd170 --- /dev/null +++ b/drivers/media/video/cx18/cx18-av-audio.c @@ -0,0 +1,361 @@ +/* + * cx18 ADEC audio functions + * + * Derived from cx25840-audio.c + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "cx18-driver.h" + +static int set_audclk_freq(struct cx18 *cx, u32 freq) +{ + struct cx18_av_state *state = &cx->av_state; + + if (freq != 32000 && freq != 44100 && freq != 48000) + return -EINVAL; + + /* common for all inputs and rates */ + /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */ + cx18_av_write(cx, 0x127, 0x50); + + if (state->aud_input != CX18_AV_AUDIO_SERIAL) { + switch (freq) { + case 32000: + /* VID_PLL and AUX_PLL */ + cx18_av_write4(cx, 0x108, 0x1006040f); + + /* AUX_PLL_FRAC */ + cx18_av_write4(cx, 0x110, 0x01bb39ee); + + /* src3/4/6_ctl = 0x0801f77f */ + cx18_av_write4(cx, 0x900, 0x0801f77f); + cx18_av_write4(cx, 0x904, 0x0801f77f); + cx18_av_write4(cx, 0x90c, 0x0801f77f); + break; + + case 44100: + /* VID_PLL and AUX_PLL */ + cx18_av_write4(cx, 0x108, 0x1009040f); + + /* AUX_PLL_FRAC */ + cx18_av_write4(cx, 0x110, 0x00ec6bd6); + + /* src3/4/6_ctl = 0x08016d59 */ + cx18_av_write4(cx, 0x900, 0x08016d59); + cx18_av_write4(cx, 0x904, 0x08016d59); + cx18_av_write4(cx, 0x90c, 0x08016d59); + break; + + case 48000: + /* VID_PLL and AUX_PLL */ + cx18_av_write4(cx, 0x108, 0x100a040f); + + /* AUX_PLL_FRAC */ + cx18_av_write4(cx, 0x110, 0x0098d6e5); + + /* src3/4/6_ctl = 0x08014faa */ + cx18_av_write4(cx, 0x900, 0x08014faa); + cx18_av_write4(cx, 0x904, 0x08014faa); + cx18_av_write4(cx, 0x90c, 0x08014faa); + break; + } + } else { + switch (freq) { + case 32000: + /* VID_PLL and AUX_PLL */ + cx18_av_write4(cx, 0x108, 0x1e08040f); + + /* AUX_PLL_FRAC */ + cx18_av_write4(cx, 0x110, 0x012a0869); + + /* src1_ctl = 0x08010000 */ + cx18_av_write4(cx, 0x8f8, 0x08010000); + + /* src3/4/6_ctl = 0x08020000 */ + cx18_av_write4(cx, 0x900, 0x08020000); + cx18_av_write4(cx, 0x904, 0x08020000); + cx18_av_write4(cx, 0x90c, 0x08020000); + + /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x14 */ + cx18_av_write(cx, 0x127, 0x54); + break; + + case 44100: + /* VID_PLL and AUX_PLL */ + cx18_av_write4(cx, 0x108, 0x1809040f); + + /* AUX_PLL_FRAC */ + cx18_av_write4(cx, 0x110, 0x00ec6bd6); + + /* src1_ctl = 0x08010000 */ + cx18_av_write4(cx, 0x8f8, 0x080160cd); + + /* src3/4/6_ctl = 0x08020000 */ + cx18_av_write4(cx, 0x900, 0x08017385); + cx18_av_write4(cx, 0x904, 0x08017385); + cx18_av_write4(cx, 0x90c, 0x08017385); + break; + + case 48000: + /* VID_PLL and AUX_PLL */ + cx18_av_write4(cx, 0x108, 0x180a040f); + + /* AUX_PLL_FRAC */ + cx18_av_write4(cx, 0x110, 0x0098d6e5); + + /* src1_ctl = 0x08010000 */ + cx18_av_write4(cx, 0x8f8, 0x08018000); + + /* src3/4/6_ctl = 0x08020000 */ + cx18_av_write4(cx, 0x900, 0x08015555); + cx18_av_write4(cx, 0x904, 0x08015555); + cx18_av_write4(cx, 0x90c, 0x08015555); + break; + } + } + + state->audclk_freq = freq; + + return 0; +} + +void cx18_av_audio_set_path(struct cx18 *cx) +{ + struct cx18_av_state *state = &cx->av_state; + + /* stop microcontroller */ + cx18_av_and_or(cx, 0x803, ~0x10, 0); + + /* assert soft reset */ + cx18_av_and_or(cx, 0x810, ~0x1, 0x01); + + /* Mute everything to prevent the PFFT! */ + cx18_av_write(cx, 0x8d3, 0x1f); + + if (state->aud_input == CX18_AV_AUDIO_SERIAL) { + /* Set Path1 to Serial Audio Input */ + cx18_av_write4(cx, 0x8d0, 0x01011012); + + /* The microcontroller should not be started for the + * non-tuner inputs: autodetection is specific for + * TV audio. */ + } else { + /* Set Path1 to Analog Demod Main Channel */ + cx18_av_write4(cx, 0x8d0, 0x1f063870); + } + + set_audclk_freq(cx, state->audclk_freq); + + /* deassert soft reset */ + cx18_av_and_or(cx, 0x810, ~0x1, 0x00); + + if (state->aud_input != CX18_AV_AUDIO_SERIAL) { + /* When the microcontroller detects the + * audio format, it will unmute the lines */ + cx18_av_and_or(cx, 0x803, ~0x10, 0x10); + } +} + +static int get_volume(struct cx18 *cx) +{ + /* Volume runs +18dB to -96dB in 1/2dB steps + * change to fit the msp3400 -114dB to +12dB range */ + + /* check PATH1_VOLUME */ + int vol = 228 - cx18_av_read(cx, 0x8d4); + vol = (vol / 2) + 23; + return vol << 9; +} + +static void set_volume(struct cx18 *cx, int volume) +{ + /* First convert the volume to msp3400 values (0-127) */ + int vol = volume >> 9; + /* now scale it up to cx18_av values + * -114dB to -96dB maps to 0 + * this should be 19, but in my testing that was 4dB too loud */ + if (vol <= 23) + vol = 0; + else + vol -= 23; + + /* PATH1_VOLUME */ + cx18_av_write(cx, 0x8d4, 228 - (vol * 2)); +} + +static int get_bass(struct cx18 *cx) +{ + /* bass is 49 steps +12dB to -12dB */ + + /* check PATH1_EQ_BASS_VOL */ + int bass = cx18_av_read(cx, 0x8d9) & 0x3f; + bass = (((48 - bass) * 0xffff) + 47) / 48; + return bass; +} + +static void set_bass(struct cx18 *cx, int bass) +{ + /* PATH1_EQ_BASS_VOL */ + cx18_av_and_or(cx, 0x8d9, ~0x3f, 48 - (bass * 48 / 0xffff)); +} + +static int get_treble(struct cx18 *cx) +{ + /* treble is 49 steps +12dB to -12dB */ + + /* check PATH1_EQ_TREBLE_VOL */ + int treble = cx18_av_read(cx, 0x8db) & 0x3f; + treble = (((48 - treble) * 0xffff) + 47) / 48; + return treble; +} + +static void set_treble(struct cx18 *cx, int treble) +{ + /* PATH1_EQ_TREBLE_VOL */ + cx18_av_and_or(cx, 0x8db, ~0x3f, 48 - (treble * 48 / 0xffff)); +} + +static int get_balance(struct cx18 *cx) +{ + /* balance is 7 bit, 0 to -96dB */ + + /* check PATH1_BAL_LEVEL */ + int balance = cx18_av_read(cx, 0x8d5) & 0x7f; + /* check PATH1_BAL_LEFT */ + if ((cx18_av_read(cx, 0x8d5) & 0x80) == 0) + balance = 0x80 - balance; + else + balance = 0x80 + balance; + return balance << 8; +} + +static void set_balance(struct cx18 *cx, int balance) +{ + int bal = balance >> 8; + if (bal > 0x80) { + /* PATH1_BAL_LEFT */ + cx18_av_and_or(cx, 0x8d5, 0x7f, 0x80); + /* PATH1_BAL_LEVEL */ + cx18_av_and_or(cx, 0x8d5, ~0x7f, bal & 0x7f); + } else { + /* PATH1_BAL_LEFT */ + cx18_av_and_or(cx, 0x8d5, 0x7f, 0x00); + /* PATH1_BAL_LEVEL */ + cx18_av_and_or(cx, 0x8d5, ~0x7f, 0x80 - bal); + } +} + +static int get_mute(struct cx18 *cx) +{ + /* check SRC1_MUTE_EN */ + return cx18_av_read(cx, 0x8d3) & 0x2 ? 1 : 0; +} + +static void set_mute(struct cx18 *cx, int mute) +{ + struct cx18_av_state *state = &cx->av_state; + + if (state->aud_input != CX18_AV_AUDIO_SERIAL) { + /* Must turn off microcontroller in order to mute sound. + * Not sure if this is the best method, but it does work. + * If the microcontroller is running, then it will undo any + * changes to the mute register. */ + if (mute) { + /* disable microcontroller */ + cx18_av_and_or(cx, 0x803, ~0x10, 0x00); + cx18_av_write(cx, 0x8d3, 0x1f); + } else { + /* enable microcontroller */ + cx18_av_and_or(cx, 0x803, ~0x10, 0x10); + } + } else { + /* SRC1_MUTE_EN */ + cx18_av_and_or(cx, 0x8d3, ~0x2, mute ? 0x02 : 0x00); + } +} + +int cx18_av_audio(struct cx18 *cx, unsigned int cmd, void *arg) +{ + struct cx18_av_state *state = &cx->av_state; + struct v4l2_control *ctrl = arg; + int retval; + + switch (cmd) { + case VIDIOC_INT_AUDIO_CLOCK_FREQ: + if (state->aud_input != CX18_AV_AUDIO_SERIAL) { + cx18_av_and_or(cx, 0x803, ~0x10, 0); + cx18_av_write(cx, 0x8d3, 0x1f); + } + cx18_av_and_or(cx, 0x810, ~0x1, 1); + retval = set_audclk_freq(cx, *(u32 *)arg); + cx18_av_and_or(cx, 0x810, ~0x1, 0); + if (state->aud_input != CX18_AV_AUDIO_SERIAL) + cx18_av_and_or(cx, 0x803, ~0x10, 0x10); + return retval; + + case VIDIOC_G_CTRL: + switch (ctrl->id) { + case V4L2_CID_AUDIO_VOLUME: + ctrl->value = get_volume(cx); + break; + case V4L2_CID_AUDIO_BASS: + ctrl->value = get_bass(cx); + break; + case V4L2_CID_AUDIO_TREBLE: + ctrl->value = get_treble(cx); + break; + case V4L2_CID_AUDIO_BALANCE: + ctrl->value = get_balance(cx); + break; + case V4L2_CID_AUDIO_MUTE: + ctrl->value = get_mute(cx); + break; + default: + return -EINVAL; + } + break; + + case VIDIOC_S_CTRL: + switch (ctrl->id) { + case V4L2_CID_AUDIO_VOLUME: + set_volume(cx, ctrl->value); + break; + case V4L2_CID_AUDIO_BASS: + set_bass(cx, ctrl->value); + break; + case V4L2_CID_AUDIO_TREBLE: + set_treble(cx, ctrl->value); + break; + case V4L2_CID_AUDIO_BALANCE: + set_balance(cx, ctrl->value); + break; + case V4L2_CID_AUDIO_MUTE: + set_mute(cx, ctrl->value); + break; + default: + return -EINVAL; + } + break; + + default: + return -EINVAL; + } + + return 0; +} diff --git a/drivers/media/video/cx18/cx18-av-core.c b/drivers/media/video/cx18/cx18-av-core.c new file mode 100644 index 00000000000..66864904c99 --- /dev/null +++ b/drivers/media/video/cx18/cx18-av-core.c @@ -0,0 +1,879 @@ +/* + * cx18 ADEC audio functions + * + * Derived from cx25840-core.c + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "cx18-driver.h" + +int cx18_av_write(struct cx18 *cx, u16 addr, u8 value) +{ + u32 x = readl(cx->reg_mem + 0xc40000 + (addr & ~3)); + u32 mask = 0xff; + int shift = (addr & 3) * 8; + + x = (x & ~(mask << shift)) | ((u32)value << shift); + writel(x, cx->reg_mem + 0xc40000 + (addr & ~3)); + return 0; +} + +int cx18_av_write4(struct cx18 *cx, u16 addr, u32 value) +{ + writel(value, cx->reg_mem + 0xc40000 + addr); + return 0; +} + +u8 cx18_av_read(struct cx18 *cx, u16 addr) +{ + u32 x = readl(cx->reg_mem + 0xc40000 + (addr & ~3)); + int shift = (addr & 3) * 8; + + return (x >> shift) & 0xff; +} + +u32 cx18_av_read4(struct cx18 *cx, u16 addr) +{ + return readl(cx->reg_mem + 0xc40000 + addr); +} + +int cx18_av_and_or(struct cx18 *cx, u16 addr, unsigned and_mask, + u8 or_value) +{ + return cx18_av_write(cx, addr, + (cx18_av_read(cx, addr) & and_mask) | + or_value); +} + +int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 and_mask, + u32 or_value) +{ + return cx18_av_write4(cx, addr, + (cx18_av_read4(cx, addr) & and_mask) | + or_value); +} + +/* ----------------------------------------------------------------------- */ + +static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input, + enum cx18_av_audio_input aud_input); +static void log_audio_status(struct cx18 *cx); +static void log_video_status(struct cx18 *cx); + +/* ----------------------------------------------------------------------- */ + +static void cx18_av_initialize(struct cx18 *cx) +{ + u32 v; + + cx18_av_loadfw(cx); + /* Stop 8051 code execution */ + cx18_av_write4(cx, CXADEC_DL_CTL, 0x03000000); + + /* initallize the PLL by toggling sleep bit */ + v = cx18_av_read4(cx, CXADEC_HOST_REG1); + /* enable sleep mode */ + cx18_av_write4(cx, CXADEC_HOST_REG1, v | 1); + /* disable sleep mode */ + cx18_av_write4(cx, CXADEC_HOST_REG1, v & 0xfffe); + + /* initialize DLLs */ + v = cx18_av_read4(cx, CXADEC_DLL1_DIAG_CTRL) & 0xE1FFFEFF; + /* disable FLD */ + cx18_av_write4(cx, CXADEC_DLL1_DIAG_CTRL, v); + /* enable FLD */ + cx18_av_write4(cx, CXADEC_DLL1_DIAG_CTRL, v | 0x10000100); + + v = cx18_av_read4(cx, CXADEC_DLL2_DIAG_CTRL) & 0xE1FFFEFF; + /* disable FLD */ + cx18_av_write4(cx, CXADEC_DLL2_DIAG_CTRL, v); + /* enable FLD */ + cx18_av_write4(cx, CXADEC_DLL2_DIAG_CTRL, v | 0x06000100); + + /* set analog bias currents. Set Vreg to 1.20V. */ + cx18_av_write4(cx, CXADEC_AFE_DIAG_CTRL1, 0x000A1802); + + v = cx18_av_read4(cx, CXADEC_AFE_DIAG_CTRL3) | 1; + /* enable TUNE_FIL_RST */ + cx18_av_write4(cx, CXADEC_AFE_DIAG_CTRL3, v); + /* disable TUNE_FIL_RST */ + cx18_av_write4(cx, CXADEC_AFE_DIAG_CTRL3, v & 0xFFFFFFFE); + + /* enable 656 output */ + cx18_av_and_or4(cx, CXADEC_PIN_CTRL1, ~0, 0x040C00); + + /* video output drive strength */ + cx18_av_and_or4(cx, CXADEC_PIN_CTRL2, ~0, 0x2); + + /* reset video */ + cx18_av_write4(cx, CXADEC_SOFT_RST_CTRL, 0x8000); + cx18_av_write4(cx, CXADEC_SOFT_RST_CTRL, 0); + + /* set video to auto-detect */ + /* Clear bits 11-12 to enable slow locking mode. Set autodetect mode */ + /* set the comb notch = 1 */ + cx18_av_and_or4(cx, CXADEC_MODE_CTRL, 0xFFF7E7F0, 0x02040800); + + /* Enable wtw_en in CRUSH_CTRL (Set bit 22) */ + /* Enable maj_sel in CRUSH_CTRL (Set bit 20) */ + cx18_av_and_or4(cx, CXADEC_CRUSH_CTRL, ~0, 0x00500000); + + /* Set VGA_TRACK_RANGE to 0x20 */ + cx18_av_and_or4(cx, CXADEC_DFE_CTRL2, 0xFFFF00FF, 0x00002000); + + /* Enable VBI capture */ + cx18_av_write4(cx, CXADEC_OUT_CTRL1, 0x4010253F); + /* cx18_av_write4(cx, CXADEC_OUT_CTRL1, 0x4010253E); */ + + /* Set the video input. + The setting in MODE_CTRL gets lost when we do the above setup */ + /* EncSetSignalStd(dwDevNum, pEnc->dwSigStd); */ + /* EncSetVideoInput(dwDevNum, pEnc->VidIndSelection); */ + + v = cx18_av_read4(cx, CXADEC_AFE_CTRL); + v &= 0xFFFBFFFF; /* turn OFF bit 18 for droop_comp_ch1 */ + v &= 0xFFFF7FFF; /* turn OFF bit 9 for clamp_sel_ch1 */ + v &= 0xFFFFFFFE; /* turn OFF bit 0 for 12db_ch1 */ + /* v |= 0x00000001;*/ /* turn ON bit 0 for 12db_ch1 */ + cx18_av_write4(cx, CXADEC_AFE_CTRL, v); + +/* if(dwEnable && dw3DCombAvailable) { */ +/* CxDevWrReg(CXADEC_SRC_COMB_CFG, 0x7728021F); */ +/* } else { */ +/* CxDevWrReg(CXADEC_SRC_COMB_CFG, 0x6628021F); */ +/* } */ + cx18_av_write4(cx, CXADEC_SRC_COMB_CFG, 0x6628021F); +} + +/* ----------------------------------------------------------------------- */ + +static void input_change(struct cx18 *cx) +{ + struct cx18_av_state *state = &cx->av_state; + v4l2_std_id std = state->std; + + /* Follow step 8c and 8d of section 3.16 in the cx18_av datasheet */ + if (std & V4L2_STD_SECAM) + cx18_av_write(cx, 0x402, 0); + else { + cx18_av_write(cx, 0x402, 0x04); + cx18_av_write(cx, 0x49f, (std & V4L2_STD_NTSC) ? 0x14 : 0x11); + } + cx18_av_and_or(cx, 0x401, ~0x60, 0); + cx18_av_and_or(cx, 0x401, ~0x60, 0x60); + + if (std & V4L2_STD_525_60) { + if (std == V4L2_STD_NTSC_M_JP) { + /* Japan uses EIAJ audio standard */ + cx18_av_write(cx, 0x808, 0xf7); + } else if (std == V4L2_STD_NTSC_M_KR) { + /* South Korea uses A2 audio standard */ + cx18_av_write(cx, 0x808, 0xf8); + } else { + /* Others use the BTSC audio standard */ + cx18_av_write(cx, 0x808, 0xf6); + } + cx18_av_write(cx, 0x80b, 0x00); + } else if (std & V4L2_STD_PAL) { + /* Follow tuner change procedure for PAL */ + cx18_av_write(cx, 0x808, 0xff); + cx18_av_write(cx, 0x80b, 0x03); + } else if (std & V4L2_STD_SECAM) { + /* Select autodetect for SECAM */ + cx18_av_write(cx, 0x808, 0xff); + cx18_av_write(cx, 0x80b, 0x03); + } + + if (cx18_av_read(cx, 0x803) & 0x10) { + /* restart audio decoder microcontroller */ + cx18_av_and_or(cx, 0x803, ~0x10, 0x00); + cx18_av_and_or(cx, 0x803, ~0x10, 0x10); + } +} + +static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input, + enum cx18_av_audio_input aud_input) +{ + struct cx18_av_state *state = &cx->av_state; + u8 is_composite = (vid_input >= CX18_AV_COMPOSITE1 && + vid_input <= CX18_AV_COMPOSITE8); + u8 reg; + + CX18_DEBUG_INFO("decoder set video input %d, audio input %d\n", + vid_input, aud_input); + + if (is_composite) { + reg = 0xf0 + (vid_input - CX18_AV_COMPOSITE1); + } else { + int luma = vid_input & 0xf0; + int chroma = vid_input & 0xf00; + + if ((vid_input & ~0xff0) || + luma < CX18_AV_SVIDEO_LUMA1 || + luma > CX18_AV_SVIDEO_LUMA4 || + chroma < CX18_AV_SVIDEO_CHROMA4 || + chroma > CX18_AV_SVIDEO_CHROMA8) { + CX18_ERR("0x%04x is not a valid video input!\n", + vid_input); + return -EINVAL; + } + reg = 0xf0 + ((luma - CX18_AV_SVIDEO_LUMA1) >> 4); + if (chroma >= CX18_AV_SVIDEO_CHROMA7) { + reg &= 0x3f; + reg |= (chroma - CX18_AV_SVIDEO_CHROMA7) >> 2; + } else { + reg &= 0xcf; + reg |= (chroma - CX18_AV_SVIDEO_CHROMA4) >> 4; + } + } + + switch (aud_input) { + case CX18_AV_AUDIO_SERIAL: + /* do nothing, use serial audio input */ + break; + case CX18_AV_AUDIO4: reg &= ~0x30; break; + case CX18_AV_AUDIO5: reg &= ~0x30; reg |= 0x10; break; + case CX18_AV_AUDIO6: reg &= ~0x30; reg |= 0x20; break; + case CX18_AV_AUDIO7: reg &= ~0xc0; break; + case CX18_AV_AUDIO8: reg &= ~0xc0; reg |= 0x40; break; + + default: + CX18_ERR("0x%04x is not a valid audio input!\n", aud_input); + return -EINVAL; + } + + cx18_av_write(cx, 0x103, reg); + /* Set INPUT_MODE to Composite (0) or S-Video (1) */ + cx18_av_and_or(cx, 0x401, ~0x6, is_composite ? 0 : 0x02); + /* Set CH_SEL_ADC2 to 1 if input comes from CH3 */ + cx18_av_and_or(cx, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0); + /* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2 and CH3 */ + if ((reg & 0xc0) != 0xc0 && (reg & 0x30) != 0x30) + cx18_av_and_or(cx, 0x102, ~0x4, 4); + else + cx18_av_and_or(cx, 0x102, ~0x4, 0); + /*cx18_av_and_or4(cx, 0x104, ~0x001b4180, 0x00004180);*/ + + state->vid_input = vid_input; + state->aud_input = aud_input; + cx18_av_audio_set_path(cx); + input_change(cx); + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static int set_v4lstd(struct cx18 *cx) +{ + struct cx18_av_state *state = &cx->av_state; + u8 fmt = 0; /* zero is autodetect */ + u8 pal_m = 0; + + /* First tests should be against specific std */ + if (state->std == V4L2_STD_NTSC_M_JP) { + fmt = 0x2; + } else if (state->std == V4L2_STD_NTSC_443) { + fmt = 0x3; + } else if (state->std == V4L2_STD_PAL_M) { + pal_m = 1; + fmt = 0x5; + } else if (state->std == V4L2_STD_PAL_N) { + fmt = 0x6; + } else if (state->std == V4L2_STD_PAL_Nc) { + fmt = 0x7; + } else if (state->std == V4L2_STD_PAL_60) { + fmt = 0x8; + } else { + /* Then, test against generic ones */ + if (state->std & V4L2_STD_NTSC) + fmt = 0x1; + else if (state->std & V4L2_STD_PAL) + fmt = 0x4; + else if (state->std & V4L2_STD_SECAM) + fmt = 0xc; + } + + CX18_DEBUG_INFO("changing video std to fmt %i\n", fmt); + + /* Follow step 9 of section 3.16 in the cx18_av datasheet. + Without this PAL may display a vertical ghosting effect. + This happens for example with the Yuan MPC622. */ + if (fmt >= 4 && fmt < 8) { + /* Set format to NTSC-M */ + cx18_av_and_or(cx, 0x400, ~0xf, 1); + /* Turn off LCOMB */ + cx18_av_and_or(cx, 0x47b, ~6, 0); + } + cx18_av_and_or(cx, 0x400, ~0xf, fmt); + cx18_av_and_or(cx, 0x403, ~0x3, pal_m); + cx18_av_vbi_setup(cx); + input_change(cx); + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static int set_v4lctrl(struct cx18 *cx, struct v4l2_control *ctrl) +{ + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + if (ctrl->value < 0 || ctrl->value > 255) { + CX18_ERR("invalid brightness setting %d\n", + ctrl->value); + return -ERANGE; + } + + cx18_av_write(cx, 0x414, ctrl->value - 128); + break; + + case V4L2_CID_CONTRAST: + if (ctrl->value < 0 || ctrl->value > 127) { + CX18_ERR("invalid contrast setting %d\n", + ctrl->value); + return -ERANGE; + } + + cx18_av_write(cx, 0x415, ctrl->value << 1); + break; + + case V4L2_CID_SATURATION: + if (ctrl->value < 0 || ctrl->value > 127) { + CX18_ERR("invalid saturation setting %d\n", + ctrl->value); + return -ERANGE; + } + + cx18_av_write(cx, 0x420, ctrl->value << 1); + cx18_av_write(cx, 0x421, ctrl->value << 1); + break; + + case V4L2_CID_HUE: + if (ctrl->value < -127 || ctrl->value > 127) { + CX18_ERR("invalid hue setting %d\n", ctrl->value); + return -ERANGE; + } + + cx18_av_write(cx, 0x422, ctrl->value); + break; + + case V4L2_CID_AUDIO_VOLUME: + case V4L2_CID_AUDIO_BASS: + case V4L2_CID_AUDIO_TREBLE: + case V4L2_CID_AUDIO_BALANCE: + case V4L2_CID_AUDIO_MUTE: + return cx18_av_audio(cx, VIDIOC_S_CTRL, ctrl); + + default: + return -EINVAL; + } + + return 0; +} + +static int get_v4lctrl(struct cx18 *cx, struct v4l2_control *ctrl) +{ + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + ctrl->value = (s8)cx18_av_read(cx, 0x414) + 128; + break; + case V4L2_CID_CONTRAST: + ctrl->value = cx18_av_read(cx, 0x415) >> 1; + break; + case V4L2_CID_SATURATION: + ctrl->value = cx18_av_read(cx, 0x420) >> 1; + break; + case V4L2_CID_HUE: + ctrl->value = (s8)cx18_av_read(cx, 0x422); + break; + case V4L2_CID_AUDIO_VOLUME: + case V4L2_CID_AUDIO_BASS: + case V4L2_CID_AUDIO_TREBLE: + case V4L2_CID_AUDIO_BALANCE: + case V4L2_CID_AUDIO_MUTE: + return cx18_av_audio(cx, VIDIOC_G_CTRL, ctrl); + default: + return -EINVAL; + } + + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static int get_v4lfmt(struct cx18 *cx, struct v4l2_format *fmt) +{ + switch (fmt->type) { + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + return cx18_av_vbi(cx, VIDIOC_G_FMT, fmt); + default: + return -EINVAL; + } + + return 0; +} + +static int set_v4lfmt(struct cx18 *cx, struct v4l2_format *fmt) +{ + struct cx18_av_state *state = &cx->av_state; + struct v4l2_pix_format *pix; + int HSC, VSC, Vsrc, Hsrc, filter, Vlines; + int is_50Hz = !(state->std & V4L2_STD_525_60); + + switch (fmt->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + pix = &(fmt->fmt.pix); + + Vsrc = (cx18_av_read(cx, 0x476) & 0x3f) << 4; + Vsrc |= (cx18_av_read(cx, 0x475) & 0xf0) >> 4; + + Hsrc = (cx18_av_read(cx, 0x472) & 0x3f) << 4; + Hsrc |= (cx18_av_read(cx, 0x471) & 0xf0) >> 4; + + Vlines = pix->height + (is_50Hz ? 4 : 7); + + if ((pix->width * 16 < Hsrc) || (Hsrc < pix->width) || + (Vlines * 8 < Vsrc) || (Vsrc < Vlines)) { + CX18_ERR("%dx%d is not a valid size!\n", + pix->width, pix->height); + return -ERANGE; + } + + HSC = (Hsrc * (1 << 20)) / pix->width - (1 << 20); + VSC = (1 << 16) - (Vsrc * (1 << 9) / Vlines - (1 << 9)); + VSC &= 0x1fff; + + if (pix->width >= 385) + filter = 0; + else if (pix->width > 192) + filter = 1; + else if (pix->width > 96) + filter = 2; + else + filter = 3; + + CX18_DEBUG_INFO("decoder set size %dx%d -> scale %ux%u\n", + pix->width, pix->height, HSC, VSC); + + /* HSCALE=HSC */ + cx18_av_write(cx, 0x418, HSC & 0xff); + cx18_av_write(cx, 0x419, (HSC >> 8) & 0xff); + cx18_av_write(cx, 0x41a, HSC >> 16); + /* VSCALE=VSC */ + cx18_av_write(cx, 0x41c, VSC & 0xff); + cx18_av_write(cx, 0x41d, VSC >> 8); + /* VS_INTRLACE=1 VFILT=filter */ + cx18_av_write(cx, 0x41e, 0x8 | filter); + break; + + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + return cx18_av_vbi(cx, VIDIOC_S_FMT, fmt); + + case V4L2_BUF_TYPE_VBI_CAPTURE: + return cx18_av_vbi(cx, VIDIOC_S_FMT, fmt); + + default: + return -EINVAL; + } + + return 0; +} + +/* ----------------------------------------------------------------------- */ + +int cx18_av_cmd(struct cx18 *cx, unsigned int cmd, void *arg) +{ + struct cx18_av_state *state = &cx->av_state; + struct v4l2_tuner *vt = arg; + struct v4l2_routing *route = arg; + + /* ignore these commands */ + switch (cmd) { + case TUNER_SET_TYPE_ADDR: + return 0; + } + + if (!state->is_initialized) { + CX18_DEBUG_INFO("cmd %08x triggered fw load\n", cmd); + /* initialize on first use */ + state->is_initialized = 1; + cx18_av_initialize(cx); + } + + switch (cmd) { + case VIDIOC_INT_DECODE_VBI_LINE: + return cx18_av_vbi(cx, cmd, arg); + + case VIDIOC_INT_AUDIO_CLOCK_FREQ: + return cx18_av_audio(cx, cmd, arg); + + case VIDIOC_STREAMON: + CX18_DEBUG_INFO("enable output\n"); + cx18_av_write(cx, 0x115, 0x8c); + cx18_av_write(cx, 0x116, 0x07); + break; + + case VIDIOC_STREAMOFF: + CX18_DEBUG_INFO("disable output\n"); + cx18_av_write(cx, 0x115, 0x00); + cx18_av_write(cx, 0x116, 0x00); + break; + + case VIDIOC_LOG_STATUS: + log_video_status(cx); + log_audio_status(cx); + break; + + case VIDIOC_G_CTRL: + return get_v4lctrl(cx, (struct v4l2_control *)arg); + + case VIDIOC_S_CTRL: + return set_v4lctrl(cx, (struct v4l2_control *)arg); + + case VIDIOC_QUERYCTRL: + { + struct v4l2_queryctrl *qc = arg; + + switch (qc->id) { + case V4L2_CID_BRIGHTNESS: + case V4L2_CID_CONTRAST: + case V4L2_CID_SATURATION: + case V4L2_CID_HUE: + return v4l2_ctrl_query_fill_std(qc); + default: + break; + } + + switch (qc->id) { + case V4L2_CID_AUDIO_VOLUME: + case V4L2_CID_AUDIO_MUTE: + case V4L2_CID_AUDIO_BALANCE: + case V4L2_CID_AUDIO_BASS: + case V4L2_CID_AUDIO_TREBLE: + return v4l2_ctrl_query_fill_std(qc); + default: + return -EINVAL; + } + return -EINVAL; + } + + case VIDIOC_G_STD: + *(v4l2_std_id *)arg = state->std; + break; + + case VIDIOC_S_STD: + if (state->radio == 0 && state->std == *(v4l2_std_id *)arg) + return 0; + state->radio = 0; + state->std = *(v4l2_std_id *)arg; + return set_v4lstd(cx); + + case AUDC_SET_RADIO: + state->radio = 1; + break; + + case VIDIOC_INT_G_VIDEO_ROUTING: + route->input = state->vid_input; + route->output = 0; + break; + + case VIDIOC_INT_S_VIDEO_ROUTING: + return set_input(cx, route->input, state->aud_input); + + case VIDIOC_INT_G_AUDIO_ROUTING: + route->input = state->aud_input; + route->output = 0; + break; + + case VIDIOC_INT_S_AUDIO_ROUTING: + return set_input(cx, state->vid_input, route->input); + + case VIDIOC_S_FREQUENCY: + input_change(cx); + break; + + case VIDIOC_G_TUNER: + { + u8 vpres = cx18_av_read(cx, 0x40e) & 0x20; + u8 mode; + int val = 0; + + if (state->radio) + break; + + vt->signal = vpres ? 0xffff : 0x0; + + vt->capability |= + V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | + V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP; + + mode = cx18_av_read(cx, 0x804); + + /* get rxsubchans and audmode */ + if ((mode & 0xf) == 1) + val |= V4L2_TUNER_SUB_STEREO; + else + val |= V4L2_TUNER_SUB_MONO; + + if (mode == 2 || mode == 4) + val = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; + + if (mode & 0x10) + val |= V4L2_TUNER_SUB_SAP; + + vt->rxsubchans = val; + vt->audmode = state->audmode; + break; + } + + case VIDIOC_S_TUNER: + if (state->radio) + break; + + switch (vt->audmode) { + case V4L2_TUNER_MODE_MONO: + /* mono -> mono + stereo -> mono + bilingual -> lang1 */ + cx18_av_and_or(cx, 0x809, ~0xf, 0x00); + break; + case V4L2_TUNER_MODE_STEREO: + case V4L2_TUNER_MODE_LANG1: + /* mono -> mono + stereo -> stereo + bilingual -> lang1 */ + cx18_av_and_or(cx, 0x809, ~0xf, 0x04); + break; + case V4L2_TUNER_MODE_LANG1_LANG2: + /* mono -> mono + stereo -> stereo + bilingual -> lang1/lang2 */ + cx18_av_and_or(cx, 0x809, ~0xf, 0x07); + break; + case V4L2_TUNER_MODE_LANG2: + /* mono -> mono + stereo -> stereo + bilingual -> lang2 */ + cx18_av_and_or(cx, 0x809, ~0xf, 0x01); + break; + default: + return -EINVAL; + } + state->audmode = vt->audmode; + break; + + case VIDIOC_G_FMT: + return get_v4lfmt(cx, (struct v4l2_format *)arg); + + case VIDIOC_S_FMT: + return set_v4lfmt(cx, (struct v4l2_format *)arg); + + case VIDIOC_INT_RESET: + cx18_av_initialize(cx); + break; + + default: + return -EINVAL; + } + + return 0; +} + +/* ----------------------------------------------------------------------- */ + +/* ----------------------------------------------------------------------- */ + +static void log_video_status(struct cx18 *cx) +{ + static const char *const fmt_strs[] = { + "0x0", + "NTSC-M", "NTSC-J", "NTSC-4.43", + "PAL-BDGHI", "PAL-M", "PAL-N", "PAL-Nc", "PAL-60", + "0x9", "0xA", "0xB", + "SECAM", + "0xD", "0xE", "0xF" + }; + + struct cx18_av_state *state = &cx->av_state; + u8 vidfmt_sel = cx18_av_read(cx, 0x400) & 0xf; + u8 gen_stat1 = cx18_av_read(cx, 0x40d); + u8 gen_stat2 = cx18_av_read(cx, 0x40e); + int vid_input = state->vid_input; + + CX18_INFO("Video signal: %spresent\n", + (gen_stat2 & 0x20) ? "" : "not "); + CX18_INFO("Detected format: %s\n", + fmt_strs[gen_stat1 & 0xf]); + + CX18_INFO("Specified standard: %s\n", + vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection"); + + if (vid_input >= CX18_AV_COMPOSITE1 && + vid_input <= CX18_AV_COMPOSITE8) { + CX18_INFO("Specified video input: Composite %d\n", + vid_input - CX18_AV_COMPOSITE1 + 1); + } else { + CX18_INFO("Specified video input: S-Video (Luma In%d, Chroma In%d)\n", + (vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8); + } + + CX18_INFO("Specified audioclock freq: %d Hz\n", state->audclk_freq); +} + +/* ----------------------------------------------------------------------- */ + +static void log_audio_status(struct cx18 *cx) +{ + struct cx18_av_state *state = &cx->av_state; + u8 download_ctl = cx18_av_read(cx, 0x803); + u8 mod_det_stat0 = cx18_av_read(cx, 0x805); + u8 mod_det_stat1 = cx18_av_read(cx, 0x804); + u8 audio_config = cx18_av_read(cx, 0x808); + u8 pref_mode = cx18_av_read(cx, 0x809); + u8 afc0 = cx18_av_read(cx, 0x80b); + u8 mute_ctl = cx18_av_read(cx, 0x8d3); + int aud_input = state->aud_input; + char *p; + + switch (mod_det_stat0) { + case 0x00: p = "mono"; break; + case 0x01: p = "stereo"; break; + case 0x02: p = "dual"; break; + case 0x04: p = "tri"; break; + case 0x10: p = "mono with SAP"; break; + case 0x11: p = "stereo with SAP"; break; + case 0x12: p = "dual with SAP"; break; + case 0x14: p = "tri with SAP"; break; + case 0xfe: p = "forced mode"; break; + default: p = "not defined"; + } + CX18_INFO("Detected audio mode: %s\n", p); + + switch (mod_det_stat1) { + case 0x00: p = "BTSC"; break; + case 0x01: p = "EIAJ"; break; + case 0x02: p = "A2-M"; break; + case 0x03: p = "A2-BG"; break; + case 0x04: p = "A2-DK1"; break; + case 0x05: p = "A2-DK2"; break; + case 0x06: p = "A2-DK3"; break; + case 0x07: p = "A1 (6.0 MHz FM Mono)"; break; + case 0x08: p = "AM-L"; break; + case 0x09: p = "NICAM-BG"; break; + case 0x0a: p = "NICAM-DK"; break; + case 0x0b: p = "NICAM-I"; break; + case 0x0c: p = "NICAM-L"; break; + case 0x0d: p = "BTSC/EIAJ/A2-M Mono (4.5 MHz FMMono)"; break; + case 0xff: p = "no detected audio standard"; break; + default: p = "not defined"; + } + CX18_INFO("Detected audio standard: %s\n", p); + CX18_INFO("Audio muted: %s\n", + (mute_ctl & 0x2) ? "yes" : "no"); + CX18_INFO("Audio microcontroller: %s\n", + (download_ctl & 0x10) ? "running" : "stopped"); + + switch (audio_config >> 4) { + case 0x00: p = "BTSC"; break; + case 0x01: p = "EIAJ"; break; + case 0x02: p = "A2-M"; break; + case 0x03: p = "A2-BG"; break; + case 0x04: p = "A2-DK1"; break; + case 0x05: p = "A2-DK2"; break; + case 0x06: p = "A2-DK3"; break; + case 0x07: p = "A1 (6.0 MHz FM Mono)"; break; + case 0x08: p = "AM-L"; break; + case 0x09: p = "NICAM-BG"; break; + case 0x0a: p = "NICAM-DK"; break; + case 0x0b: p = "NICAM-I"; break; + case 0x0c: p = "NICAM-L"; break; + case 0x0d: p = "FM radio"; break; + case 0x0f: p = "automatic detection"; break; + default: p = "undefined"; + } + CX18_INFO("Configured audio standard: %s\n", p); + + if ((audio_config >> 4) < 0xF) { + switch (audio_config & 0xF) { + case 0x00: p = "MONO1 (LANGUAGE A/Mono L+R channel for BTSC, EIAJ, A2)"; break; + case 0x01: p = "MONO2 (LANGUAGE B)"; break; + case 0x02: p = "MONO3 (STEREO forced MONO)"; break; + case 0x03: p = "MONO4 (NICAM ANALOG-Language C/Analog Fallback)"; break; + case 0x04: p = "STEREO"; break; + case 0x05: p = "DUAL1 (AB)"; break; + case 0x06: p = "DUAL2 (AC) (FM)"; break; + case 0x07: p = "DUAL3 (BC) (FM)"; break; + case 0x08: p = "DUAL4 (AC) (AM)"; break; + case 0x09: p = "DUAL5 (BC) (AM)"; break; + case 0x0a: p = "SAP"; break; + default: p = "undefined"; + } + CX18_INFO("Configured audio mode: %s\n", p); + } else { + switch (audio_config & 0xF) { + case 0x00: p = "BG"; break; + case 0x01: p = "DK1"; break; + case 0x02: p = "DK2"; break; + case 0x03: p = "DK3"; break; + case 0x04: p = "I"; break; + case 0x05: p = "L"; break; + case 0x06: p = "BTSC"; break; + case 0x07: p = "EIAJ"; break; + case 0x08: p = "A2-M"; break; + case 0x09: p = "FM Radio"; break; + case 0x0f: p = "automatic standard and mode detection"; break; + default: p = "undefined"; + } + CX18_INFO("Configured audio system: %s\n", p); + } + + if (aud_input) + CX18_INFO("Specified audio input: Tuner (In%d)\n", + aud_input); + else + CX18_INFO("Specified audio input: External\n"); + + switch (pref_mode & 0xf) { + case 0: p = "mono/language A"; break; + case 1: p = "language B"; break; + case 2: p = "language C"; break; + case 3: p = "analog fallback"; break; + case 4: p = "stereo"; break; + case 5: p = "language AC"; break; + case 6: p = "language BC"; break; + case 7: p = "language AB"; break; + default: p = "undefined"; + } + CX18_INFO("Preferred audio mode: %s\n", p); + + if ((audio_config & 0xf) == 0xf) { + switch ((afc0 >> 2) & 0x1) { + case 0: p = "system DK"; break; + case 1: p = "system L"; break; + } + CX18_INFO("Selected 65 MHz format: %s\n", p); + + switch (afc0 & 0x3) { + case 0: p = "BTSC"; break; + case 1: p = "EIAJ"; break; + case 2: p = "A2-M"; break; + default: p = "undefined"; + } + CX18_INFO("Selected 45 MHz format: %s\n", p); + } +} diff --git a/drivers/media/video/cx18/cx18-av-core.h b/drivers/media/video/cx18/cx18-av-core.h new file mode 100644 index 00000000000..786901d72e9 --- /dev/null +++ b/drivers/media/video/cx18/cx18-av-core.h @@ -0,0 +1,318 @@ +/* + * cx18 ADEC header + * + * Derived from cx25840-core.h + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifndef _CX18_AV_CORE_H_ +#define _CX18_AV_CORE_H_ + +struct cx18; + +enum cx18_av_video_input { + /* Composite video inputs In1-In8 */ + CX18_AV_COMPOSITE1 = 1, + CX18_AV_COMPOSITE2, + CX18_AV_COMPOSITE3, + CX18_AV_COMPOSITE4, + CX18_AV_COMPOSITE5, + CX18_AV_COMPOSITE6, + CX18_AV_COMPOSITE7, + CX18_AV_COMPOSITE8, + + /* S-Video inputs consist of one luma input (In1-In4) ORed with one + chroma input (In5-In8) */ + CX18_AV_SVIDEO_LUMA1 = 0x10, + CX18_AV_SVIDEO_LUMA2 = 0x20, + CX18_AV_SVIDEO_LUMA3 = 0x30, + CX18_AV_SVIDEO_LUMA4 = 0x40, + CX18_AV_SVIDEO_CHROMA4 = 0x400, + CX18_AV_SVIDEO_CHROMA5 = 0x500, + CX18_AV_SVIDEO_CHROMA6 = 0x600, + CX18_AV_SVIDEO_CHROMA7 = 0x700, + CX18_AV_SVIDEO_CHROMA8 = 0x800, + + /* S-Video aliases for common luma/chroma combinations */ + CX18_AV_SVIDEO1 = 0x510, + CX18_AV_SVIDEO2 = 0x620, + CX18_AV_SVIDEO3 = 0x730, + CX18_AV_SVIDEO4 = 0x840, +}; + +enum cx18_av_audio_input { + /* Audio inputs: serial or In4-In8 */ + CX18_AV_AUDIO_SERIAL, + CX18_AV_AUDIO4 = 4, + CX18_AV_AUDIO5, + CX18_AV_AUDIO6, + CX18_AV_AUDIO7, + CX18_AV_AUDIO8, +}; + +struct cx18_av_state { + int radio; + v4l2_std_id std; + enum cx18_av_video_input vid_input; + enum cx18_av_audio_input aud_input; + u32 audclk_freq; + int audmode; + int vbi_line_offset; + u32 id; + u32 rev; + int is_initialized; +}; + + +/* Registers */ +#define CXADEC_CHIP_TYPE_TIGER 0x837 +#define CXADEC_CHIP_TYPE_MAKO 0x843 + +#define CXADEC_HOST_REG1 0x000 +#define CXADEC_HOST_REG2 0x001 + +#define CXADEC_CHIP_CTRL 0x100 +#define CXADEC_AFE_CTRL 0x104 +#define CXADEC_PLL_CTRL1 0x108 +#define CXADEC_VID_PLL_FRAC 0x10C +#define CXADEC_AUX_PLL_FRAC 0x110 +#define CXADEC_PIN_CTRL1 0x114 +#define CXADEC_PIN_CTRL2 0x118 +#define CXADEC_PIN_CFG1 0x11C +#define CXADEC_PIN_CFG2 0x120 + +#define CXADEC_PIN_CFG3 0x124 +#define CXADEC_I2S_MCLK 0x127 + +#define CXADEC_AUD_LOCK1 0x128 +#define CXADEC_AUD_LOCK2 0x12C +#define CXADEC_POWER_CTRL 0x130 +#define CXADEC_AFE_DIAG_CTRL1 0x134 +#define CXADEC_AFE_DIAG_CTRL2 0x138 +#define CXADEC_AFE_DIAG_CTRL3 0x13C +#define CXADEC_PLL_DIAG_CTRL 0x140 +#define CXADEC_TEST_CTRL1 0x144 +#define CXADEC_TEST_CTRL2 0x148 +#define CXADEC_BIST_STAT 0x14C +#define CXADEC_DLL1_DIAG_CTRL 0x158 +#define CXADEC_DLL2_DIAG_CTRL 0x15C + +/* IR registers */ +#define CXADEC_IR_CTRL_REG 0x200 +#define CXADEC_IR_TXCLK_REG 0x204 +#define CXADEC_IR_RXCLK_REG 0x208 +#define CXADEC_IR_CDUTY_REG 0x20C +#define CXADEC_IR_STAT_REG 0x210 +#define CXADEC_IR_IRQEN_REG 0x214 +#define CXADEC_IR_FILTER_REG 0x218 +#define CXADEC_IR_FIFO_REG 0x21C + +/* Video Registers */ +#define CXADEC_MODE_CTRL 0x400 +#define CXADEC_OUT_CTRL1 0x404 +#define CXADEC_OUT_CTRL2 0x408 +#define CXADEC_GEN_STAT 0x40C +#define CXADEC_INT_STAT_MASK 0x410 +#define CXADEC_LUMA_CTRL 0x414 + +#define CXADEC_BRIGHTNESS_CTRL_BYTE 0x414 +#define CXADEC_CONTRAST_CTRL_BYTE 0x415 +#define CXADEC_LUMA_CTRL_BYTE_3 0x416 + +#define CXADEC_HSCALE_CTRL 0x418 +#define CXADEC_VSCALE_CTRL 0x41C + +#define CXADEC_CHROMA_CTRL 0x420 + +#define CXADEC_USAT_CTRL_BYTE 0x420 +#define CXADEC_VSAT_CTRL_BYTE 0x421 +#define CXADEC_HUE_CTRL_BYTE 0x422 + +#define CXADEC_VBI_LINE_CTRL1 0x424 +#define CXADEC_VBI_LINE_CTRL2 0x428 +#define CXADEC_VBI_LINE_CTRL3 0x42C +#define CXADEC_VBI_LINE_CTRL4 0x430 +#define CXADEC_VBI_LINE_CTRL5 0x434 +#define CXADEC_VBI_FC_CFG 0x438 +#define CXADEC_VBI_MISC_CFG1 0x43C +#define CXADEC_VBI_MISC_CFG2 0x440 +#define CXADEC_VBI_PAY1 0x444 +#define CXADEC_VBI_PAY2 0x448 +#define CXADEC_VBI_CUST1_CFG1 0x44C +#define CXADEC_VBI_CUST1_CFG2 0x450 +#define CXADEC_VBI_CUST1_CFG3 0x454 +#define CXADEC_VBI_CUST2_CFG1 0x458 +#define CXADEC_VBI_CUST2_CFG2 0x45C +#define CXADEC_VBI_CUST2_CFG3 0x460 +#define CXADEC_VBI_CUST3_CFG1 0x464 +#define CXADEC_VBI_CUST3_CFG2 0x468 +#define CXADEC_VBI_CUST3_CFG3 0x46C +#define CXADEC_HORIZ_TIM_CTRL 0x470 +#define CXADEC_VERT_TIM_CTRL 0x474 +#define CXADEC_SRC_COMB_CFG 0x478 +#define CXADEC_CHROMA_VBIOFF_CFG 0x47C +#define CXADEC_FIELD_COUNT 0x480 +#define CXADEC_MISC_TIM_CTRL 0x484 +#define CXADEC_DFE_CTRL1 0x488 +#define CXADEC_DFE_CTRL2 0x48C +#define CXADEC_DFE_CTRL3 0x490 +#define CXADEC_PLL_CTRL2 0x494 +#define CXADEC_HTL_CTRL 0x498 +#define CXADEC_COMB_CTRL 0x49C +#define CXADEC_CRUSH_CTRL 0x4A0 +#define CXADEC_SOFT_RST_CTRL 0x4A4 +#define CXADEC_MV_DT_CTRL2 0x4A8 +#define CXADEC_MV_DT_CTRL3 0x4AC +#define CXADEC_MISC_DIAG_CTRL 0x4B8 + +#define CXADEC_DL_CTL 0x800 +#define CXADEC_DL_CTL_ADDRESS_LOW 0x800 /* Byte 1 in DL_CTL */ +#define CXADEC_DL_CTL_ADDRESS_HIGH 0x801 /* Byte 2 in DL_CTL */ +#define CXADEC_DL_CTL_DATA 0x802 /* Byte 3 in DL_CTL */ +#define CXADEC_DL_CTL_CONTROL 0x803 /* Byte 4 in DL_CTL */ + +#define CXADEC_STD_DET_STATUS 0x804 + +#define CXADEC_STD_DET_CTL 0x808 +#define CXADEC_STD_DET_CTL_AUD_CTL 0x808 /* Byte 1 in STD_DET_CTL */ +#define CXADEC_STD_DET_CTL_PREF_MODE 0x809 /* Byte 2 in STD_DET_CTL */ + +#define CXADEC_DW8051_INT 0x80C +#define CXADEC_GENERAL_CTL 0x810 +#define CXADEC_AAGC_CTL 0x814 +#define CXADEC_IF_SRC_CTL 0x818 +#define CXADEC_ANLOG_DEMOD_CTL 0x81C +#define CXADEC_ROT_FREQ_CTL 0x820 +#define CXADEC_FM1_CTL 0x824 +#define CXADEC_PDF_CTL 0x828 +#define CXADEC_DFT1_CTL1 0x82C +#define CXADEC_DFT1_CTL2 0x830 +#define CXADEC_DFT_STATUS 0x834 +#define CXADEC_DFT2_CTL1 0x838 +#define CXADEC_DFT2_CTL2 0x83C +#define CXADEC_DFT2_STATUS 0x840 +#define CXADEC_DFT3_CTL1 0x844 +#define CXADEC_DFT3_CTL2 0x848 +#define CXADEC_DFT3_STATUS 0x84C +#define CXADEC_DFT4_CTL1 0x850 +#define CXADEC_DFT4_CTL2 0x854 +#define CXADEC_DFT4_STATUS 0x858 +#define CXADEC_AM_MTS_DET 0x85C +#define CXADEC_ANALOG_MUX_CTL 0x860 +#define CXADEC_DIG_PLL_CTL1 0x864 +#define CXADEC_DIG_PLL_CTL2 0x868 +#define CXADEC_DIG_PLL_CTL3 0x86C +#define CXADEC_DIG_PLL_CTL4 0x870 +#define CXADEC_DIG_PLL_CTL5 0x874 +#define CXADEC_DEEMPH_GAIN_CTL 0x878 +#define CXADEC_DEEMPH_COEF1 0x87C +#define CXADEC_DEEMPH_COEF2 0x880 +#define CXADEC_DBX1_CTL1 0x884 +#define CXADEC_DBX1_CTL2 0x888 +#define CXADEC_DBX1_STATUS 0x88C +#define CXADEC_DBX2_CTL1 0x890 +#define CXADEC_DBX2_CTL2 0x894 +#define CXADEC_DBX2_STATUS 0x898 +#define CXADEC_AM_FM_DIFF 0x89C + +/* NICAM registers go here */ +#define CXADEC_NICAM_STATUS 0x8C8 +#define CXADEC_DEMATRIX_CTL 0x8CC + +#define CXADEC_PATH1_CTL1 0x8D0 +#define CXADEC_PATH1_VOL_CTL 0x8D4 +#define CXADEC_PATH1_EQ_CTL 0x8D8 +#define CXADEC_PATH1_SC_CTL 0x8DC + +#define CXADEC_PATH2_CTL1 0x8E0 +#define CXADEC_PATH2_VOL_CTL 0x8E4 +#define CXADEC_PATH2_EQ_CTL 0x8E8 +#define CXADEC_PATH2_SC_CTL 0x8EC + +#define CXADEC_SRC_CTL 0x8F0 +#define CXADEC_SRC_LF_COEF 0x8F4 +#define CXADEC_SRC1_CTL 0x8F8 +#define CXADEC_SRC2_CTL 0x8FC +#define CXADEC_SRC3_CTL 0x900 +#define CXADEC_SRC4_CTL 0x904 +#define CXADEC_SRC5_CTL 0x908 +#define CXADEC_SRC6_CTL 0x90C + +#define CXADEC_BASEBAND_OUT_SEL 0x910 +#define CXADEC_I2S_IN_CTL 0x914 +#define CXADEC_I2S_OUT_CTL 0x918 +#define CXADEC_AC97_CTL 0x91C +#define CXADEC_QAM_PDF 0x920 +#define CXADEC_QAM_CONST_DEC 0x924 +#define CXADEC_QAM_ROTATOR_FREQ 0x948 + +/* Bit defintions / settings used in Mako Audio */ +#define CXADEC_PREF_MODE_MONO_LANGA 0 +#define CXADEC_PREF_MODE_MONO_LANGB 1 +#define CXADEC_PREF_MODE_MONO_LANGC 2 +#define CXADEC_PREF_MODE_FALLBACK 3 +#define CXADEC_PREF_MODE_STEREO 4 +#define CXADEC_PREF_MODE_DUAL_LANG_AC 5 +#define CXADEC_PREF_MODE_DUAL_LANG_BC 6 +#define CXADEC_PREF_MODE_DUAL_LANG_AB 7 + + +#define CXADEC_DETECT_STEREO 1 +#define CXADEC_DETECT_DUAL 2 +#define CXADEC_DETECT_TRI 4 +#define CXADEC_DETECT_SAP 0x10 +#define CXADEC_DETECT_NO_SIGNAL 0xFF + +#define CXADEC_SELECT_AUDIO_STANDARD_BG 0xF0 /* NICAM BG and A2 BG */ +#define CXADEC_SELECT_AUDIO_STANDARD_DK1 0xF1 /* NICAM DK and A2 DK */ +#define CXADEC_SELECT_AUDIO_STANDARD_DK2 0xF2 +#define CXADEC_SELECT_AUDIO_STANDARD_DK3 0xF3 +#define CXADEC_SELECT_AUDIO_STANDARD_I 0xF4 /* NICAM I and A1 */ +#define CXADEC_SELECT_AUDIO_STANDARD_L 0xF5 /* NICAM L and System L AM */ +#define CXADEC_SELECT_AUDIO_STANDARD_BTSC 0xF6 +#define CXADEC_SELECT_AUDIO_STANDARD_EIAJ 0xF7 +#define CXADEC_SELECT_AUDIO_STANDARD_A2_M 0xF8 /* A2 M */ +#define CXADEC_SELECT_AUDIO_STANDARD_FM 0xF9 /* FM radio */ +#define CXADEC_SELECT_AUDIO_STANDARD_AUTO 0xFF /* Auto detect */ + +/* ----------------------------------------------------------------------- */ +/* cx18_av-core.c */ +int cx18_av_write(struct cx18 *cx, u16 addr, u8 value); +int cx18_av_write4(struct cx18 *cx, u16 addr, u32 value); +u8 cx18_av_read(struct cx18 *cx, u16 addr); +u32 cx18_av_read4(struct cx18 *cx, u16 addr); +int cx18_av_and_or(struct cx18 *cx, u16 addr, unsigned mask, u8 value); +int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 mask, u32 value); +int cx18_av_cmd(struct cx18 *cx, unsigned int cmd, void *arg); + +/* ----------------------------------------------------------------------- */ +/* cx18_av-firmware.c */ +int cx18_av_loadfw(struct cx18 *cx); + +/* ----------------------------------------------------------------------- */ +/* cx18_av-audio.c */ +int cx18_av_audio(struct cx18 *cx, unsigned int cmd, void *arg); +void cx18_av_audio_set_path(struct cx18 *cx); + +/* ----------------------------------------------------------------------- */ +/* cx18_av-vbi.c */ +void cx18_av_vbi_setup(struct cx18 *cx); +int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg); + +#endif diff --git a/drivers/media/video/cx18/cx18-av-firmware.c b/drivers/media/video/cx18/cx18-av-firmware.c new file mode 100644 index 00000000000..526e142156c --- /dev/null +++ b/drivers/media/video/cx18/cx18-av-firmware.c @@ -0,0 +1,120 @@ +/* + * cx18 ADEC firmware functions + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "cx18-driver.h" +#include <linux/firmware.h> + +#define FWFILE "v4l-cx23418-dig.fw" + +int cx18_av_loadfw(struct cx18 *cx) +{ + const struct firmware *fw = NULL; + u32 size; + u32 v; + u8 *ptr; + int i; + + if (request_firmware(&fw, FWFILE, &cx->dev->dev) != 0) { + CX18_ERR("unable to open firmware %s\n", FWFILE); + return -EINVAL; + } + + cx18_av_write4(cx, CXADEC_CHIP_CTRL, 0x00010000); + cx18_av_write(cx, CXADEC_STD_DET_CTL, 0xf6); /* Byte 0 */ + + /* Reset the Mako core (Register is undocumented.) */ + cx18_av_write4(cx, 0x8100, 0x00010000); + + /* Put the 8051 in reset and enable firmware upload */ + cx18_av_write4(cx, CXADEC_DL_CTL, 0x0F000000); + + ptr = fw->data; + size = fw->size; + + for (i = 0; i < size; i++) { + u32 dl_control = 0x0F000000 | ((u32)ptr[i] << 16); + u32 value = 0; + int retries; + + for (retries = 0; retries < 5; retries++) { + cx18_av_write4(cx, CXADEC_DL_CTL, dl_control); + value = cx18_av_read4(cx, CXADEC_DL_CTL); + if ((value & 0x3F00) == (dl_control & 0x3F00)) + break; + } + if (retries >= 5) { + CX18_ERR("unable to load firmware %s\n", FWFILE); + release_firmware(fw); + return -EIO; + } + } + + cx18_av_write4(cx, CXADEC_DL_CTL, 0x13000000 | fw->size); + + /* Output to the 416 */ + cx18_av_and_or4(cx, CXADEC_PIN_CTRL1, ~0, 0x78000); + + /* Audio input control 1 set to Sony mode */ + /* Audio output input 2 is 0 for slave operation input */ + /* 0xC4000914[5]: 0 = left sample on WS=0, 1 = left sample on WS=1 */ + /* 0xC4000914[7]: 0 = Philips mode, 1 = Sony mode (1st SCK rising edge + after WS transition for first bit of audio word. */ + cx18_av_write4(cx, CXADEC_I2S_IN_CTL, 0x000000A0); + + /* Audio output control 1 is set to Sony mode */ + /* Audio output control 2 is set to 1 for master mode */ + /* 0xC4000918[5]: 0 = left sample on WS=0, 1 = left sample on WS=1 */ + /* 0xC4000918[7]: 0 = Philips mode, 1 = Sony mode (1st SCK rising edge + after WS transition for first bit of audio word. */ + /* 0xC4000918[8]: 0 = slave operation, 1 = master (SCK_OUT and WS_OUT + are generated) */ + cx18_av_write4(cx, CXADEC_I2S_OUT_CTL, 0x000001A0); + + /* set alt I2s master clock to /16 and enable alt divider i2s + passthrough */ + cx18_av_write4(cx, CXADEC_PIN_CFG3, 0x5000B687); + + cx18_av_write4(cx, CXADEC_STD_DET_CTL, 0x000000F6); + /* CxDevWrReg(CXADEC_STD_DET_CTL, 0x000000FF); */ + + /* Set bit 0 in register 0x9CC to signify that this is MiniMe. */ + /* Register 0x09CC is defined by the Merlin firmware, and doesn't + have a name in the spec. */ + cx18_av_write4(cx, 0x09CC, 1); + +#define CX18_AUDIO_ENABLE 0xc72014 + v = read_reg(CX18_AUDIO_ENABLE); + /* If bit 11 is 1 */ + if (v & 0x800) + write_reg(v & 0xFFFFFBFF, CX18_AUDIO_ENABLE); /* Clear bit 10 */ + + /* Enable WW auto audio standard detection */ + v = cx18_av_read4(cx, CXADEC_STD_DET_CTL); + v |= 0xFF; /* Auto by default */ + v |= 0x400; /* Stereo by default */ + v |= 0x14000000; + cx18_av_write4(cx, CXADEC_STD_DET_CTL, v); + + release_firmware(fw); + + CX18_INFO("loaded %s firmware (%d bytes)\n", FWFILE, size); + return 0; +} diff --git a/drivers/media/video/cx18/cx18-av-vbi.c b/drivers/media/video/cx18/cx18-av-vbi.c new file mode 100644 index 00000000000..d09f1daf4eb --- /dev/null +++ b/drivers/media/video/cx18/cx18-av-vbi.c @@ -0,0 +1,413 @@ +/* + * cx18 ADEC VBI functions + * + * Derived from cx25840-vbi.c + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + + +#include "cx18-driver.h" + +static int odd_parity(u8 c) +{ + c ^= (c >> 4); + c ^= (c >> 2); + c ^= (c >> 1); + + return c & 1; +} + +static int decode_vps(u8 *dst, u8 *p) +{ + static const u8 biphase_tbl[] = { + 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4, + 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0, + 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96, + 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2, + 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94, + 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0, + 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4, + 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0, + 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5, + 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1, + 0xc3, 0x4b, 0x43, 0xc3, 0x87, 0x0f, 0x07, 0x87, + 0x83, 0x0b, 0x03, 0x83, 0xc3, 0x4b, 0x43, 0xc3, + 0xc1, 0x49, 0x41, 0xc1, 0x85, 0x0d, 0x05, 0x85, + 0x81, 0x09, 0x01, 0x81, 0xc1, 0x49, 0x41, 0xc1, + 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5, + 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1, + 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4, + 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0, + 0xc2, 0x4a, 0x42, 0xc2, 0x86, 0x0e, 0x06, 0x86, + 0x82, 0x0a, 0x02, 0x82, 0xc2, 0x4a, 0x42, 0xc2, + 0xc0, 0x48, 0x40, 0xc0, 0x84, 0x0c, 0x04, 0x84, + 0x80, 0x08, 0x00, 0x80, 0xc0, 0x48, 0x40, 0xc0, + 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4, + 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0, + 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4, + 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0, + 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96, + 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2, + 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94, + 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0, + 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4, + 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0, + }; + + u8 c, err = 0; + int i; + + for (i = 0; i < 2 * 13; i += 2) { + err |= biphase_tbl[p[i]] | biphase_tbl[p[i + 1]]; + c = (biphase_tbl[p[i + 1]] & 0xf) | + ((biphase_tbl[p[i]] & 0xf) << 4); + dst[i / 2] = c; + } + + return err & 0xf0; +} + +void cx18_av_vbi_setup(struct cx18 *cx) +{ + struct cx18_av_state *state = &cx->av_state; + v4l2_std_id std = state->std; + int hblank, hactive, burst, vblank, vactive, sc; + int vblank656, src_decimation; + int luma_lpf, uv_lpf, comb; + u32 pll_int, pll_frac, pll_post; + + /* datasheet startup, step 8d */ + if (std & ~V4L2_STD_NTSC) + cx18_av_write(cx, 0x49f, 0x11); + else + cx18_av_write(cx, 0x49f, 0x14); + + if (std & V4L2_STD_625_50) { + hblank = 0x084; + hactive = 0x2d0; + burst = 0x5d; + vblank = 0x024; + vactive = 0x244; + vblank656 = 0x28; + src_decimation = 0x21f; + + luma_lpf = 2; + if (std & V4L2_STD_SECAM) { + uv_lpf = 0; + comb = 0; + sc = 0x0a425f; + } else if (std == V4L2_STD_PAL_Nc) { + uv_lpf = 1; + comb = 0x20; + sc = 556453; + } else { + uv_lpf = 1; + comb = 0x20; + sc = 0x0a8263; + } + } else { + hactive = 720; + hblank = 122; + vactive = 487; + luma_lpf = 1; + uv_lpf = 1; + + src_decimation = 0x21f; + if (std == V4L2_STD_PAL_60) { + vblank = 26; + vblank656 = 26; + burst = 0x5b; + luma_lpf = 2; + comb = 0x20; + sc = 0x0a8263; + } else if (std == V4L2_STD_PAL_M) { + vblank = 20; + vblank656 = 24; + burst = 0x61; + comb = 0x20; + + sc = 555452; + } else { + vblank = 26; + vblank656 = 26; + burst = 0x5b; + comb = 0x66; + sc = 556063; + } + } + + /* DEBUG: Displays configured PLL frequency */ + pll_int = cx18_av_read(cx, 0x108); + pll_frac = cx18_av_read4(cx, 0x10c) & 0x1ffffff; + pll_post = cx18_av_read(cx, 0x109); + CX18_DEBUG_INFO("PLL regs = int: %u, frac: %u, post: %u\n", + pll_int, pll_frac, pll_post); + + if (pll_post) { + int fin, fsc; + int pll = 28636363L * ((((u64)pll_int) << 25) + pll_frac); + + pll >>= 25; + pll /= pll_post; + CX18_DEBUG_INFO("PLL = %d.%06d MHz\n", + pll / 1000000, pll % 1000000); + CX18_DEBUG_INFO("PLL/8 = %d.%06d MHz\n", + pll / 8000000, (pll / 8) % 1000000); + + fin = ((u64)src_decimation * pll) >> 12; + CX18_DEBUG_INFO("ADC Sampling freq = %d.%06d MHz\n", + fin / 1000000, fin % 1000000); + + fsc = (((u64)sc) * pll) >> 24L; + CX18_DEBUG_INFO("Chroma sub-carrier freq = %d.%06d MHz\n", + fsc / 1000000, fsc % 1000000); + + CX18_DEBUG_INFO("hblank %i, hactive %i, " + "vblank %i , vactive %i, vblank656 %i, src_dec %i," + "burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x," + " sc 0x%06x\n", + hblank, hactive, vblank, vactive, vblank656, + src_decimation, burst, luma_lpf, uv_lpf, comb, sc); + } + + /* Sets horizontal blanking delay and active lines */ + cx18_av_write(cx, 0x470, hblank); + cx18_av_write(cx, 0x471, 0xff & (((hblank >> 8) & 0x3) | + (hactive << 4))); + cx18_av_write(cx, 0x472, hactive >> 4); + + /* Sets burst gate delay */ + cx18_av_write(cx, 0x473, burst); + + /* Sets vertical blanking delay and active duration */ + cx18_av_write(cx, 0x474, vblank); + cx18_av_write(cx, 0x475, 0xff & (((vblank >> 8) & 0x3) | + (vactive << 4))); + cx18_av_write(cx, 0x476, vactive >> 4); + cx18_av_write(cx, 0x477, vblank656); + + /* Sets src decimation rate */ + cx18_av_write(cx, 0x478, 0xff & src_decimation); + cx18_av_write(cx, 0x479, 0xff & (src_decimation >> 8)); + + /* Sets Luma and UV Low pass filters */ + cx18_av_write(cx, 0x47a, luma_lpf << 6 | ((uv_lpf << 4) & 0x30)); + + /* Enables comb filters */ + cx18_av_write(cx, 0x47b, comb); + + /* Sets SC Step*/ + cx18_av_write(cx, 0x47c, sc); + cx18_av_write(cx, 0x47d, 0xff & sc >> 8); + cx18_av_write(cx, 0x47e, 0xff & sc >> 16); + + /* Sets VBI parameters */ + if (std & V4L2_STD_625_50) { + cx18_av_write(cx, 0x47f, 0x01); + state->vbi_line_offset = 5; + } else { + cx18_av_write(cx, 0x47f, 0x00); + state->vbi_line_offset = 8; + } +} + +int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg) +{ + struct cx18_av_state *state = &cx->av_state; + struct v4l2_format *fmt; + struct v4l2_sliced_vbi_format *svbi; + + switch (cmd) { + case VIDIOC_G_FMT: + { + static u16 lcr2vbi[] = { + 0, V4L2_SLICED_TELETEXT_B, 0, /* 1 */ + 0, V4L2_SLICED_WSS_625, 0, /* 4 */ + V4L2_SLICED_CAPTION_525, /* 6 */ + 0, 0, V4L2_SLICED_VPS, 0, 0, /* 9 */ + 0, 0, 0, 0 + }; + int is_pal = !(state->std & V4L2_STD_525_60); + int i; + + fmt = arg; + if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) + return -EINVAL; + svbi = &fmt->fmt.sliced; + memset(svbi, 0, sizeof(*svbi)); + /* we're done if raw VBI is active */ + if ((cx18_av_read(cx, 0x404) & 0x10) == 0) + break; + + if (is_pal) { + for (i = 7; i <= 23; i++) { + u8 v = cx18_av_read(cx, 0x424 + i - 7); + + svbi->service_lines[0][i] = lcr2vbi[v >> 4]; + svbi->service_lines[1][i] = lcr2vbi[v & 0xf]; + svbi->service_set |= svbi->service_lines[0][i] | + svbi->service_lines[1][i]; + } + } else { + for (i = 10; i <= 21; i++) { + u8 v = cx18_av_read(cx, 0x424 + i - 10); + + svbi->service_lines[0][i] = lcr2vbi[v >> 4]; + svbi->service_lines[1][i] = lcr2vbi[v & 0xf]; + svbi->service_set |= svbi->service_lines[0][i] | + svbi->service_lines[1][i]; + } + } + break; + } + + case VIDIOC_S_FMT: + { + int is_pal = !(state->std & V4L2_STD_525_60); + int vbi_offset = is_pal ? 1 : 0; + int i, x; + u8 lcr[24]; + + fmt = arg; + if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) + return -EINVAL; + svbi = &fmt->fmt.sliced; + if (svbi->service_set == 0) { + /* raw VBI */ + memset(svbi, 0, sizeof(*svbi)); + + /* Setup VBI */ + cx18_av_vbi_setup(cx); + + /* VBI Offset */ + cx18_av_write(cx, 0x47f, vbi_offset); + cx18_av_write(cx, 0x404, 0x2e); + break; + } + + for (x = 0; x <= 23; x++) + lcr[x] = 0x00; + + /* Setup VBI */ + cx18_av_vbi_setup(cx); + + /* Sliced VBI */ + cx18_av_write(cx, 0x404, 0x32); /* Ancillary data */ + cx18_av_write(cx, 0x406, 0x13); + cx18_av_write(cx, 0x47f, vbi_offset); + + if (is_pal) { + for (i = 0; i <= 6; i++) + svbi->service_lines[0][i] = + svbi->service_lines[1][i] = 0; + } else { + for (i = 0; i <= 9; i++) + svbi->service_lines[0][i] = + svbi->service_lines[1][i] = 0; + + for (i = 22; i <= 23; i++) + svbi->service_lines[0][i] = + svbi->service_lines[1][i] = 0; + } + + for (i = 7; i <= 23; i++) { + for (x = 0; x <= 1; x++) { + switch (svbi->service_lines[1-x][i]) { + case V4L2_SLICED_TELETEXT_B: + lcr[i] |= 1 << (4 * x); + break; + case V4L2_SLICED_WSS_625: + lcr[i] |= 4 << (4 * x); + break; + case V4L2_SLICED_CAPTION_525: + lcr[i] |= 6 << (4 * x); + break; + case V4L2_SLICED_VPS: + lcr[i] |= 9 << (4 * x); + break; + } + } + } + + if (is_pal) { + for (x = 1, i = 0x424; i <= 0x434; i++, x++) + cx18_av_write(cx, i, lcr[6 + x]); + } else { + for (x = 1, i = 0x424; i <= 0x430; i++, x++) + cx18_av_write(cx, i, lcr[9 + x]); + for (i = 0x431; i <= 0x434; i++) + cx18_av_write(cx, i, 0); + } + + cx18_av_write(cx, 0x43c, 0x16); + cx18_av_write(cx, 0x474, is_pal ? 0x2a : 0x22); + break; + } + + case VIDIOC_INT_DECODE_VBI_LINE: + { + struct v4l2_decode_vbi_line *vbi = arg; + u8 *p = vbi->p; + int id1, id2, l, err = 0; + + if (p[0] || p[1] != 0xff || p[2] != 0xff || + (p[3] != 0x55 && p[3] != 0x91)) { + vbi->line = vbi->type = 0; + break; + } + + p += 4; + id1 = p[-1]; + id2 = p[0] & 0xf; + l = p[2] & 0x3f; + l += state->vbi_line_offset; + p += 4; + + switch (id2) { + case 1: + id2 = V4L2_SLICED_TELETEXT_B; + break; + case 4: + id2 = V4L2_SLICED_WSS_625; + break; + case 6: + id2 = V4L2_SLICED_CAPTION_525; + err = !odd_parity(p[0]) || !odd_parity(p[1]); + break; + case 9: + id2 = V4L2_SLICED_VPS; + if (decode_vps(p, p) != 0) + err = 1; + break; + default: + id2 = 0; + err = 1; + break; + } + + vbi->type = err ? 0 : id2; + vbi->line = err ? 0 : l; + vbi->is_second_field = err ? 0 : (id1 == 0x55); + vbi->p = p; + break; + } + } + + return 0; +} diff --git a/drivers/media/video/cx18/cx18-cards.c b/drivers/media/video/cx18/cx18-cards.c new file mode 100644 index 00000000000..f5e3ba1f535 --- /dev/null +++ b/drivers/media/video/cx18/cx18-cards.c @@ -0,0 +1,277 @@ +/* + * cx18 functions to query card hardware + * + * Derived from ivtv-cards.c + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 "cx18-driver.h" +#include "cx18-cards.h" +#include "cx18-i2c.h" +#include <media/cs5345.h> + +/********************** card configuration *******************************/ + +/* usual i2c tuner addresses to probe */ +static struct cx18_card_tuner_i2c cx18_i2c_std = { + .radio = { I2C_CLIENT_END }, + .demod = { 0x43, I2C_CLIENT_END }, + .tv = { 0x61, 0x60, I2C_CLIENT_END }, +}; + +/* Please add new PCI IDs to: http://pci-ids.ucw.cz/iii + This keeps the PCI ID database up to date. Note that the entries + must be added under vendor 0x4444 (Conexant) as subsystem IDs. + New vendor IDs should still be added to the vendor ID list. */ + +/* Hauppauge HVR-1600 cards */ + +/* Note: for Hauppauge cards the tveeprom information is used instead + of PCI IDs */ +static const struct cx18_card cx18_card_hvr1600_esmt = { + .type = CX18_CARD_HVR_1600_ESMT, + .name = "Hauppauge HVR-1600", + .comment = "DVB & VBI are not yet supported\n", + .v4l2_capabilities = CX18_CAP_ENCODER, + .hw_audio_ctrl = CX18_HW_CX23418, + .hw_muxer = CX18_HW_CS5345, + .hw_all = CX18_HW_TVEEPROM | CX18_HW_TUNER | CX18_HW_CS5345, + .video_inputs = { + { CX18_CARD_INPUT_VID_TUNER, 0, CX23418_COMPOSITE7 }, + { CX18_CARD_INPUT_SVIDEO1, 1, CX23418_SVIDEO1 }, + { CX18_CARD_INPUT_COMPOSITE1, 1, CX23418_COMPOSITE3 }, + { CX18_CARD_INPUT_SVIDEO2, 2, CX23418_SVIDEO2 }, + { CX18_CARD_INPUT_COMPOSITE2, 2, CX23418_COMPOSITE4 }, + }, + .audio_inputs = { + { CX18_CARD_INPUT_AUD_TUNER, + CX23418_AUDIO8, CS5345_IN_1 | CS5345_MCLK_1_5 }, + { CX18_CARD_INPUT_LINE_IN1, + CX23418_AUDIO_SERIAL, CS5345_IN_2 }, + { CX18_CARD_INPUT_LINE_IN2, + CX23418_AUDIO_SERIAL, CS5345_IN_2 }, + }, + .radio_input = { CX18_CARD_INPUT_AUD_TUNER, + CX23418_AUDIO_SERIAL, 0 }, + .ddr = { + /* ESMT M13S128324A-5B memory */ + .chip_config = 0x003, + .refresh = 0x30c, + .timing1 = 0x44220e82, + .timing2 = 0x08, + .tune_lane = 0, + .initial_emrs = 0, + }, + .gpio_init.initial_value = 0x3001, + .gpio_init.direction = 0x3001, + .i2c = &cx18_i2c_std, +}; + +static const struct cx18_card cx18_card_hvr1600_samsung = { + .type = CX18_CARD_HVR_1600_SAMSUNG, + .name = "Hauppauge HVR-1600 (Preproduction)", + .comment = "DVB & VBI are not yet supported\n", + .v4l2_capabilities = CX18_CAP_ENCODER, + .hw_audio_ctrl = CX18_HW_CX23418, + .hw_muxer = CX18_HW_CS5345, + .hw_all = CX18_HW_TVEEPROM | CX18_HW_TUNER | CX18_HW_CS5345, + .video_inputs = { + { CX18_CARD_INPUT_VID_TUNER, 0, CX23418_COMPOSITE7 }, + { CX18_CARD_INPUT_SVIDEO1, 1, CX23418_SVIDEO1 }, + { CX18_CARD_INPUT_COMPOSITE1, 1, CX23418_COMPOSITE3 }, + { CX18_CARD_INPUT_SVIDEO2, 2, CX23418_SVIDEO2 }, + { CX18_CARD_INPUT_COMPOSITE2, 2, CX23418_COMPOSITE4 }, + }, + .audio_inputs = { + { CX18_CARD_INPUT_AUD_TUNER, + CX23418_AUDIO8, CS5345_IN_1 | CS5345_MCLK_1_5 }, + { CX18_CARD_INPUT_LINE_IN1, + CX23418_AUDIO_SERIAL, CS5345_IN_2 }, + { CX18_CARD_INPUT_LINE_IN2, + CX23418_AUDIO_SERIAL, CS5345_IN_2 }, + }, + .radio_input = { CX18_CARD_INPUT_AUD_TUNER, + CX23418_AUDIO_SERIAL, 0 }, + .ddr = { + /* Samsung K4D263238G-VC33 memory */ + .chip_config = 0x003, + .refresh = 0x30c, + .timing1 = 0x23230b73, + .timing2 = 0x08, + .tune_lane = 0, + .initial_emrs = 2, + }, + .gpio_init.initial_value = 0x3001, + .gpio_init.direction = 0x3001, + .i2c = &cx18_i2c_std, +}; + +/* ------------------------------------------------------------------------- */ + +/* Compro VideoMate H900: not working at the moment! */ + +static const struct cx18_card_pci_info cx18_pci_h900[] = { + { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_COMPRO, 0xe100 }, + { 0, 0, 0 } +}; + +static const struct cx18_card cx18_card_h900 = { + .type = CX18_CARD_COMPRO_H900, + .name = "Compro VideoMate H900", + .comment = "Not yet supported!\n", + .v4l2_capabilities = 0, + .hw_audio_ctrl = CX18_HW_CX23418, + .hw_all = CX18_HW_TUNER, + .video_inputs = { + { CX18_CARD_INPUT_VID_TUNER, 0, CX23418_COMPOSITE7 }, + { CX18_CARD_INPUT_SVIDEO1, 1, CX23418_SVIDEO1 }, + { CX18_CARD_INPUT_COMPOSITE1, 1, CX23418_COMPOSITE3 }, + }, + .audio_inputs = { + { CX18_CARD_INPUT_AUD_TUNER, + CX23418_AUDIO8, 0 }, + { CX18_CARD_INPUT_LINE_IN1, + CX23418_AUDIO_SERIAL, 0 }, + }, + .radio_input = { CX18_CARD_INPUT_AUD_TUNER, + CX23418_AUDIO_SERIAL, 0 }, + .tuners = { + { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, + }, + .ddr = { + /* EtronTech EM6A9160TS-5G memory */ + .chip_config = 0x50003, + .refresh = 0x753, + .timing1 = 0x24330e84, + .timing2 = 0x1f, + .tune_lane = 0, + .initial_emrs = 0, + }, + .pci_list = cx18_pci_h900, + .i2c = &cx18_i2c_std, +}; + +/* ------------------------------------------------------------------------- */ + +/* Yuan MPC718: not working at the moment! */ + +static const struct cx18_card_pci_info cx18_pci_mpc718[] = { + { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_YUAN, 0x0718 }, + { 0, 0, 0 } +}; + +static const struct cx18_card cx18_card_mpc718 = { + .type = CX18_CARD_YUAN_MPC718, + .name = "Yuan MPC718", + .comment = "Not yet supported!\n", + .v4l2_capabilities = 0, + .hw_audio_ctrl = CX18_HW_CX23418, + .hw_all = CX18_HW_TUNER, + .video_inputs = { + { CX18_CARD_INPUT_VID_TUNER, 0, CX23418_COMPOSITE7 }, + { CX18_CARD_INPUT_SVIDEO1, 1, CX23418_SVIDEO1 }, + { CX18_CARD_INPUT_COMPOSITE1, 1, CX23418_COMPOSITE3 }, + }, + .audio_inputs = { + { CX18_CARD_INPUT_AUD_TUNER, + CX23418_AUDIO8, 0 }, + { CX18_CARD_INPUT_LINE_IN1, + CX23418_AUDIO_SERIAL, 0 }, + }, + .radio_input = { CX18_CARD_INPUT_AUD_TUNER, + CX23418_AUDIO_SERIAL, 0 }, + .tuners = { + /* XC3028 tuner */ + { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, + }, + /* tuner reset */ + .gpio_init = { .direction = 0x1000, .initial_value = 0x1000 }, + .ddr = { + /* Probably Samsung K4D263238G-VC33 memory */ + .chip_config = 0x003, + .refresh = 0x30c, + .timing1 = 0x23230b73, + .timing2 = 0x08, + .tune_lane = 0, + .initial_emrs = 2, + }, + .pci_list = cx18_pci_mpc718, + .i2c = &cx18_i2c_std, +}; + +static const struct cx18_card *cx18_card_list[] = { + &cx18_card_hvr1600_esmt, + &cx18_card_hvr1600_samsung, + &cx18_card_h900, + &cx18_card_mpc718, +}; + +const struct cx18_card *cx18_get_card(u16 index) +{ + if (index >= ARRAY_SIZE(cx18_card_list)) + return NULL; + return cx18_card_list[index]; +} + +int cx18_get_input(struct cx18 *cx, u16 index, struct v4l2_input *input) +{ + const struct cx18_card_video_input *card_input = + cx->card->video_inputs + index; + static const char * const input_strs[] = { + "Tuner 1", + "S-Video 1", + "S-Video 2", + "Composite 1", + "Composite 2", + "Composite 3" + }; + + memset(input, 0, sizeof(*input)); + if (index >= cx->nof_inputs) + return -EINVAL; + input->index = index; + strlcpy(input->name, input_strs[card_input->video_type - 1], + sizeof(input->name)); + input->type = (card_input->video_type == CX18_CARD_INPUT_VID_TUNER ? + V4L2_INPUT_TYPE_TUNER : V4L2_INPUT_TYPE_CAMERA); + input->audioset = (1 << cx->nof_audio_inputs) - 1; + input->std = (input->type == V4L2_INPUT_TYPE_TUNER) ? + cx->tuner_std : V4L2_STD_ALL; + return 0; +} + +int cx18_get_audio_input(struct cx18 *cx, u16 index, struct v4l2_audio *audio) +{ + const struct cx18_card_audio_input *aud_input = + cx->card->audio_inputs + index; + static const char * const input_strs[] = { + "Tuner 1", + "Line In 1", + "Line In 2" + }; + + memset(audio, 0, sizeof(*audio)); + if (index >= cx->nof_audio_inputs) + return -EINVAL; + strlcpy(audio->name, input_strs[aud_input->audio_type - 1], + sizeof(audio->name)); + audio->index = index; + audio->capability = V4L2_AUDCAP_STEREO; + return 0; +} diff --git a/drivers/media/video/cx18/cx18-cards.h b/drivers/media/video/cx18/cx18-cards.h new file mode 100644 index 00000000000..bca249bdd33 --- /dev/null +++ b/drivers/media/video/cx18/cx18-cards.h @@ -0,0 +1,170 @@ +/* + * cx18 functions to query card hardware + * + * Derived from ivtv-cards.c + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 + */ + +/* hardware flags */ +#define CX18_HW_TUNER (1 << 0) +#define CX18_HW_TVEEPROM (1 << 1) +#define CX18_HW_CS5345 (1 << 2) +#define CX18_HW_GPIO (1 << 3) +#define CX18_HW_CX23418 (1 << 4) +#define CX18_HW_DVB (1 << 5) + +/* video inputs */ +#define CX18_CARD_INPUT_VID_TUNER 1 +#define CX18_CARD_INPUT_SVIDEO1 2 +#define CX18_CARD_INPUT_SVIDEO2 3 +#define CX18_CARD_INPUT_COMPOSITE1 4 +#define CX18_CARD_INPUT_COMPOSITE2 5 +#define CX18_CARD_INPUT_COMPOSITE3 6 + +enum cx34180_video_input { + /* Composite video inputs In1-In8 */ + CX23418_COMPOSITE1 = 1, + CX23418_COMPOSITE2, + CX23418_COMPOSITE3, + CX23418_COMPOSITE4, + CX23418_COMPOSITE5, + CX23418_COMPOSITE6, + CX23418_COMPOSITE7, + CX23418_COMPOSITE8, + + /* S-Video inputs consist of one luma input (In1-In4) ORed with one + chroma input (In5-In8) */ + CX23418_SVIDEO_LUMA1 = 0x10, + CX23418_SVIDEO_LUMA2 = 0x20, + CX23418_SVIDEO_LUMA3 = 0x30, + CX23418_SVIDEO_LUMA4 = 0x40, + CX23418_SVIDEO_CHROMA4 = 0x400, + CX23418_SVIDEO_CHROMA5 = 0x500, + CX23418_SVIDEO_CHROMA6 = 0x600, + CX23418_SVIDEO_CHROMA7 = 0x700, + CX23418_SVIDEO_CHROMA8 = 0x800, + + /* S-Video aliases for common luma/chroma combinations */ + CX23418_SVIDEO1 = 0x510, + CX23418_SVIDEO2 = 0x620, + CX23418_SVIDEO3 = 0x730, + CX23418_SVIDEO4 = 0x840, +}; + +/* audio inputs */ +#define CX18_CARD_INPUT_AUD_TUNER 1 +#define CX18_CARD_INPUT_LINE_IN1 2 +#define CX18_CARD_INPUT_LINE_IN2 3 + +#define CX18_CARD_MAX_VIDEO_INPUTS 6 +#define CX18_CARD_MAX_AUDIO_INPUTS 3 +#define CX18_CARD_MAX_TUNERS 2 + +enum cx23418_audio_input { + /* Audio inputs: serial or In4-In8 */ + CX23418_AUDIO_SERIAL, + CX23418_AUDIO4 = 4, + CX23418_AUDIO5, + CX23418_AUDIO6, + CX23418_AUDIO7, + CX23418_AUDIO8, +}; + +/* V4L2 capability aliases */ +#define CX18_CAP_ENCODER (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | \ + V4L2_CAP_AUDIO | V4L2_CAP_READWRITE) +/* | V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE) not yet */ + +struct cx18_card_video_input { + u8 video_type; /* video input type */ + u8 audio_index; /* index in cx18_card_audio_input array */ + u16 video_input; /* hardware video input */ +}; + +struct cx18_card_audio_input { + u8 audio_type; /* audio input type */ + u32 audio_input; /* hardware audio input */ + u16 muxer_input; /* hardware muxer input for boards with a + multiplexer chip */ +}; + +struct cx18_card_pci_info { + u16 device; + u16 subsystem_vendor; + u16 subsystem_device; +}; + +/* GPIO definitions */ + +/* The mask is the set of bits used by the operation */ + +struct cx18_gpio_init { /* set initial GPIO DIR and OUT values */ + u16 direction; /* DIR setting. Leave to 0 if no init is needed */ + u16 initial_value; +}; + +struct cx18_card_tuner { + v4l2_std_id std; /* standard for which the tuner is suitable */ + int tuner; /* tuner ID (from tuner.h) */ +}; + +struct cx18_card_tuner_i2c { + unsigned short radio[2];/* radio tuner i2c address to probe */ + unsigned short demod[2];/* demodulator i2c address to probe */ + unsigned short tv[4]; /* tv tuner i2c addresses to probe */ +}; + +struct cx18_ddr { /* DDR config data */ + u32 chip_config; + u32 refresh; + u32 timing1; + u32 timing2; + u32 tune_lane; + u32 initial_emrs; +}; + +/* for card information/parameters */ +struct cx18_card { + int type; + char *name; + char *comment; + u32 v4l2_capabilities; + u32 hw_audio_ctrl; /* hardware used for the V4L2 controls (only + 1 dev allowed) */ + u32 hw_muxer; /* hardware used to multiplex audio input */ + u32 hw_all; /* all hardware used by the board */ + struct cx18_card_video_input video_inputs[CX18_CARD_MAX_VIDEO_INPUTS]; + struct cx18_card_audio_input audio_inputs[CX18_CARD_MAX_AUDIO_INPUTS]; + struct cx18_card_audio_input radio_input; + + /* GPIO card-specific settings */ + struct cx18_gpio_init gpio_init; + + struct cx18_card_tuner tuners[CX18_CARD_MAX_TUNERS]; + struct cx18_card_tuner_i2c *i2c; + + struct cx18_ddr ddr; + + /* list of device and subsystem vendor/devices that + correspond to this card type. */ + const struct cx18_card_pci_info *pci_list; +}; + +int cx18_get_input(struct cx18 *cx, u16 index, struct v4l2_input *input); +int cx18_get_audio_input(struct cx18 *cx, u16 index, struct v4l2_audio *input); +const struct cx18_card *cx18_get_card(u16 index); diff --git a/drivers/media/video/cx18/cx18-controls.c b/drivers/media/video/cx18/cx18-controls.c new file mode 100644 index 00000000000..2bdac5ebbb0 --- /dev/null +++ b/drivers/media/video/cx18/cx18-controls.c @@ -0,0 +1,306 @@ +/* + * cx18 ioctl control functions + * + * Derived from ivtv-controls.c + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 "cx18-driver.h" +#include "cx18-av-core.h" +#include "cx18-cards.h" +#include "cx18-ioctl.h" +#include "cx18-audio.h" +#include "cx18-i2c.h" +#include "cx18-mailbox.h" +#include "cx18-controls.h" + +static const u32 user_ctrls[] = { + V4L2_CID_USER_CLASS, + V4L2_CID_BRIGHTNESS, + V4L2_CID_CONTRAST, + V4L2_CID_SATURATION, + V4L2_CID_HUE, + V4L2_CID_AUDIO_VOLUME, + V4L2_CID_AUDIO_BALANCE, + V4L2_CID_AUDIO_BASS, + V4L2_CID_AUDIO_TREBLE, + V4L2_CID_AUDIO_MUTE, + V4L2_CID_AUDIO_LOUDNESS, + 0 +}; + +static const u32 *ctrl_classes[] = { + user_ctrls, + cx2341x_mpeg_ctrls, + NULL +}; + +static int cx18_queryctrl(struct cx18 *cx, struct v4l2_queryctrl *qctrl) +{ + const char *name; + + CX18_DEBUG_IOCTL("VIDIOC_QUERYCTRL(%08x)\n", qctrl->id); + + qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); + if (qctrl->id == 0) + return -EINVAL; + + switch (qctrl->id) { + /* Standard V4L2 controls */ + case V4L2_CID_BRIGHTNESS: + case V4L2_CID_HUE: + case V4L2_CID_SATURATION: + case V4L2_CID_CONTRAST: + if (cx18_av_cmd(cx, VIDIOC_QUERYCTRL, qctrl)) + qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; + return 0; + + case V4L2_CID_AUDIO_VOLUME: + case V4L2_CID_AUDIO_MUTE: + case V4L2_CID_AUDIO_BALANCE: + case V4L2_CID_AUDIO_BASS: + case V4L2_CID_AUDIO_TREBLE: + case V4L2_CID_AUDIO_LOUDNESS: + if (cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, VIDIOC_QUERYCTRL, qctrl)) + qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; + return 0; + + default: + if (cx2341x_ctrl_query(&cx->params, qctrl)) + qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; + return 0; + } + strncpy(qctrl->name, name, sizeof(qctrl->name) - 1); + qctrl->name[sizeof(qctrl->name) - 1] = 0; + return 0; +} + +static int cx18_querymenu(struct cx18 *cx, struct v4l2_querymenu *qmenu) +{ + struct v4l2_queryctrl qctrl; + + qctrl.id = qmenu->id; + cx18_queryctrl(cx, &qctrl); + return v4l2_ctrl_query_menu(qmenu, &qctrl, cx2341x_ctrl_get_menu(qmenu->id)); +} + +static int cx18_s_ctrl(struct cx18 *cx, struct v4l2_control *vctrl) +{ + s32 v = vctrl->value; + + CX18_DEBUG_IOCTL("VIDIOC_S_CTRL(%08x, %x)\n", vctrl->id, v); + + switch (vctrl->id) { + /* Standard V4L2 controls */ + case V4L2_CID_BRIGHTNESS: + case V4L2_CID_HUE: + case V4L2_CID_SATURATION: + case V4L2_CID_CONTRAST: + return cx18_av_cmd(cx, VIDIOC_S_CTRL, vctrl); + + case V4L2_CID_AUDIO_VOLUME: + case V4L2_CID_AUDIO_MUTE: + case V4L2_CID_AUDIO_BALANCE: + case V4L2_CID_AUDIO_BASS: + case V4L2_CID_AUDIO_TREBLE: + case V4L2_CID_AUDIO_LOUDNESS: + return cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, VIDIOC_S_CTRL, vctrl); + + default: + CX18_DEBUG_IOCTL("invalid control %x\n", vctrl->id); + return -EINVAL; + } + return 0; +} + +static int cx18_g_ctrl(struct cx18 *cx, struct v4l2_control *vctrl) +{ + CX18_DEBUG_IOCTL("VIDIOC_G_CTRL(%08x)\n", vctrl->id); + + switch (vctrl->id) { + /* Standard V4L2 controls */ + case V4L2_CID_BRIGHTNESS: + case V4L2_CID_HUE: + case V4L2_CID_SATURATION: + case V4L2_CID_CONTRAST: + return cx18_av_cmd(cx, VIDIOC_G_CTRL, vctrl); + + case V4L2_CID_AUDIO_VOLUME: + case V4L2_CID_AUDIO_MUTE: + case V4L2_CID_AUDIO_BALANCE: + case V4L2_CID_AUDIO_BASS: + case V4L2_CID_AUDIO_TREBLE: + case V4L2_CID_AUDIO_LOUDNESS: + return cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, VIDIOC_G_CTRL, vctrl); + default: + CX18_DEBUG_IOCTL("invalid control %x\n", vctrl->id); + return -EINVAL; + } + return 0; +} + +static int cx18_setup_vbi_fmt(struct cx18 *cx, enum v4l2_mpeg_stream_vbi_fmt fmt) +{ + if (!(cx->v4l2_cap & V4L2_CAP_SLICED_VBI_CAPTURE)) + return -EINVAL; + if (atomic_read(&cx->capturing) > 0) + return -EBUSY; + + /* First try to allocate sliced VBI buffers if needed. */ + if (fmt && cx->vbi.sliced_mpeg_data[0] == NULL) { + int i; + + for (i = 0; i < CX18_VBI_FRAMES; i++) { + /* Yuck, hardcoded. Needs to be a define */ + cx->vbi.sliced_mpeg_data[i] = kmalloc(2049, GFP_KERNEL); + if (cx->vbi.sliced_mpeg_data[i] == NULL) { + while (--i >= 0) { + kfree(cx->vbi.sliced_mpeg_data[i]); + cx->vbi.sliced_mpeg_data[i] = NULL; + } + return -ENOMEM; + } + } + } + + cx->vbi.insert_mpeg = fmt; + + if (cx->vbi.insert_mpeg == 0) + return 0; + /* Need sliced data for mpeg insertion */ + if (cx18_get_service_set(cx->vbi.sliced_in) == 0) { + if (cx->is_60hz) + cx->vbi.sliced_in->service_set = V4L2_SLICED_CAPTION_525; + else + cx->vbi.sliced_in->service_set = V4L2_SLICED_WSS_625; + cx18_expand_service_set(cx->vbi.sliced_in, cx->is_50hz); + } + return 0; +} + +int cx18_control_ioctls(struct cx18 *cx, unsigned int cmd, void *arg) +{ + struct v4l2_control ctrl; + + switch (cmd) { + case VIDIOC_QUERYMENU: + CX18_DEBUG_IOCTL("VIDIOC_QUERYMENU\n"); + return cx18_querymenu(cx, arg); + + case VIDIOC_QUERYCTRL: + return cx18_queryctrl(cx, arg); + + case VIDIOC_S_CTRL: + return cx18_s_ctrl(cx, arg); + + case VIDIOC_G_CTRL: + return cx18_g_ctrl(cx, arg); + + case VIDIOC_S_EXT_CTRLS: + { + struct v4l2_ext_controls *c = arg; + + if (c->ctrl_class == V4L2_CTRL_CLASS_USER) { + int i; + int err = 0; + + for (i = 0; i < c->count; i++) { + ctrl.id = c->controls[i].id; + ctrl.value = c->controls[i].value; + err = cx18_s_ctrl(cx, &ctrl); + c->controls[i].value = ctrl.value; + if (err) { + c->error_idx = i; + break; + } + } + return err; + } + CX18_DEBUG_IOCTL("VIDIOC_S_EXT_CTRLS\n"); + if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) { + struct cx2341x_mpeg_params p = cx->params; + int err = cx2341x_ext_ctrls(&p, atomic_read(&cx->capturing), arg, cmd); + + if (err) + return err; + + if (p.video_encoding != cx->params.video_encoding) { + int is_mpeg1 = p.video_encoding == + V4L2_MPEG_VIDEO_ENCODING_MPEG_1; + struct v4l2_format fmt; + + /* fix videodecoder resolution */ + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + fmt.fmt.pix.width = cx->params.width / (is_mpeg1 ? 2 : 1); + fmt.fmt.pix.height = cx->params.height; + cx18_av_cmd(cx, VIDIOC_S_FMT, &fmt); + } + err = cx2341x_update(cx, cx18_api_func, &cx->params, &p); + if (!err && cx->params.stream_vbi_fmt != p.stream_vbi_fmt) + err = cx18_setup_vbi_fmt(cx, p.stream_vbi_fmt); + cx->params = p; + cx->dualwatch_stereo_mode = p.audio_properties & 0x0300; + cx18_audio_set_audio_clock_freq(cx, p.audio_properties & 0x03); + return err; + } + return -EINVAL; + } + + case VIDIOC_G_EXT_CTRLS: + { + struct v4l2_ext_controls *c = arg; + + if (c->ctrl_class == V4L2_CTRL_CLASS_USER) { + int i; + int err = 0; + + for (i = 0; i < c->count; i++) { + ctrl.id = c->controls[i].id; + ctrl.value = c->controls[i].value; + err = cx18_g_ctrl(cx, &ctrl); + c->controls[i].value = ctrl.value; + if (err) { + c->error_idx = i; + break; + } + } + return err; + } + CX18_DEBUG_IOCTL("VIDIOC_G_EXT_CTRLS\n"); + if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) + return cx2341x_ext_ctrls(&cx->params, 0, arg, cmd); + return -EINVAL; + } + + case VIDIOC_TRY_EXT_CTRLS: + { + struct v4l2_ext_controls *c = arg; + + CX18_DEBUG_IOCTL("VIDIOC_TRY_EXT_CTRLS\n"); + if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) + return cx2341x_ext_ctrls(&cx->params, + atomic_read(&cx->capturing), arg, cmd); + return -EINVAL; + } + + default: + return -EINVAL; + } + return 0; +} diff --git a/drivers/media/video/cx18/cx18-controls.h b/drivers/media/video/cx18/cx18-controls.h new file mode 100644 index 00000000000..6e985cf422a --- /dev/null +++ b/drivers/media/video/cx18/cx18-controls.h @@ -0,0 +1,24 @@ +/* + * cx18 ioctl control functions + * + * Derived from ivtv-controls.h + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + + * 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 + */ + +int cx18_control_ioctls(struct cx18 *cx, unsigned int cmd, void *arg); diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c new file mode 100644 index 00000000000..9f31befc313 --- /dev/null +++ b/drivers/media/video/cx18/cx18-driver.c @@ -0,0 +1,971 @@ +/* + * cx18 driver initialization and card probing + * + * Derived from ivtv-driver.c + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 "cx18-driver.h" +#include "cx18-version.h" +#include "cx18-cards.h" +#include "cx18-i2c.h" +#include "cx18-irq.h" +#include "cx18-gpio.h" +#include "cx18-firmware.h" +#include "cx18-streams.h" +#include "cx18-av-core.h" +#include "cx18-scb.h" +#include "cx18-mailbox.h" +#include "cx18-ioctl.h" +#include "tuner-xc2028.h" + +#include <media/tveeprom.h> + + +/* var to keep track of the number of array elements in use */ +int cx18_cards_active; + +/* If you have already X v4l cards, then set this to X. This way + the device numbers stay matched. Example: you have a WinTV card + without radio and a Compro H900 with. Normally this would give a + video1 device together with a radio0 device for the Compro. By + setting this to 1 you ensure that radio0 is now also radio1. */ +int cx18_first_minor; + +/* Master variable for all cx18 info */ +struct cx18 *cx18_cards[CX18_MAX_CARDS]; + +/* Protects cx18_cards_active */ +DEFINE_SPINLOCK(cx18_cards_lock); + +/* add your revision and whatnot here */ +static struct pci_device_id cx18_pci_tbl[] __devinitdata = { + {PCI_VENDOR_ID_CX, PCI_DEVICE_ID_CX23418, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0,} +}; + +MODULE_DEVICE_TABLE(pci, cx18_pci_tbl); + +/* Parameter declarations */ +static int cardtype[CX18_MAX_CARDS]; +static int tuner[CX18_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1 }; +static int radio[CX18_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1 }; + +static int cardtype_c = 1; +static int tuner_c = 1; +static int radio_c = 1; +static char pal[] = "--"; +static char secam[] = "--"; +static char ntsc[] = "-"; + +/* Buffers */ +static int enc_mpg_buffers = CX18_DEFAULT_ENC_MPG_BUFFERS; +static int enc_ts_buffers = CX18_DEFAULT_ENC_TS_BUFFERS; +static int enc_yuv_buffers = CX18_DEFAULT_ENC_YUV_BUFFERS; +static int enc_vbi_buffers = CX18_DEFAULT_ENC_VBI_BUFFERS; +static int enc_pcm_buffers = CX18_DEFAULT_ENC_PCM_BUFFERS; + +static int cx18_pci_latency = 1; + +int cx18_debug; + +module_param_array(tuner, int, &tuner_c, 0644); +module_param_array(radio, bool, &radio_c, 0644); +module_param_array(cardtype, int, &cardtype_c, 0644); +module_param_string(pal, pal, sizeof(pal), 0644); +module_param_string(secam, secam, sizeof(secam), 0644); +module_param_string(ntsc, ntsc, sizeof(ntsc), 0644); +module_param_named(debug, cx18_debug, int, 0644); +module_param(cx18_pci_latency, int, 0644); +module_param(cx18_first_minor, int, 0644); + +module_param(enc_mpg_buffers, int, 0644); +module_param(enc_ts_buffers, int, 0644); +module_param(enc_yuv_buffers, int, 0644); +module_param(enc_vbi_buffers, int, 0644); +module_param(enc_pcm_buffers, int, 0644); + +MODULE_PARM_DESC(tuner, "Tuner type selection,\n" + "\t\t\tsee tuner.h for values"); +MODULE_PARM_DESC(radio, + "Enable or disable the radio. Use only if autodetection\n" + "\t\t\tfails. 0 = disable, 1 = enable"); +MODULE_PARM_DESC(cardtype, + "Only use this option if your card is not detected properly.\n" + "\t\tSpecify card type:\n" + "\t\t\t 1 = Hauppauge HVR 1600 (ESMT memory)\n" + "\t\t\t 2 = Hauppauge HVR 1600 (Samsung memory)\n" + "\t\t\t 3 = Compro VideoMate H900\n" + "\t\t\t 4 = Yuan MPC718\n" + "\t\t\t 0 = Autodetect (default)\n" + "\t\t\t-1 = Ignore this card\n\t\t"); +MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60"); +MODULE_PARM_DESC(secam, "Set SECAM standard: B, G, H, D, K, L, LC"); +MODULE_PARM_DESC(ntsc, "Set NTSC standard: M, J, K"); +MODULE_PARM_DESC(debug, + "Debug level (bitmask). Default: 0\n" + "\t\t\t 1/0x0001: warning\n" + "\t\t\t 2/0x0002: info\n" + "\t\t\t 4/0x0004: mailbox\n" + "\t\t\t 8/0x0008: dma\n" + "\t\t\t 16/0x0010: ioctl\n" + "\t\t\t 32/0x0020: file\n" + "\t\t\t 64/0x0040: i2c\n" + "\t\t\t128/0x0080: irq\n" + "\t\t\t256/0x0100: high volume\n"); +MODULE_PARM_DESC(cx18_pci_latency, + "Change the PCI latency to 64 if lower: 0 = No, 1 = Yes,\n" + "\t\t\tDefault: Yes"); +MODULE_PARM_DESC(enc_mpg_buffers, + "Encoder MPG Buffers (in MB)\n" + "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_MPG_BUFFERS)); +MODULE_PARM_DESC(enc_ts_buffers, + "Encoder TS Buffers (in MB)\n" + "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_TS_BUFFERS)); +MODULE_PARM_DESC(enc_yuv_buffers, + "Encoder YUV Buffers (in MB)\n" + "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_YUV_BUFFERS)); +MODULE_PARM_DESC(enc_vbi_buffers, + "Encoder VBI Buffers (in MB)\n" + "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_VBI_BUFFERS)); +MODULE_PARM_DESC(enc_pcm_buffers, + "Encoder PCM buffers (in MB)\n" + "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_PCM_BUFFERS)); + +MODULE_PARM_DESC(cx18_first_minor, "Set minor assigned to first card"); + +MODULE_AUTHOR("Hans Verkuil"); +MODULE_DESCRIPTION("CX23418 driver"); +MODULE_SUPPORTED_DEVICE("CX23418 MPEG2 encoder"); +MODULE_LICENSE("GPL"); + +MODULE_VERSION(CX18_VERSION); + +int cx18_waitq(wait_queue_head_t *waitq) +{ + DEFINE_WAIT(wait); + + prepare_to_wait(waitq, &wait, TASK_INTERRUPTIBLE); + schedule(); + finish_wait(waitq, &wait); + return signal_pending(current) ? -EINTR : 0; +} + +/* Generic utility functions */ +int cx18_msleep_timeout(unsigned int msecs, int intr) +{ + int timeout = msecs_to_jiffies(msecs); + int sig; + + do { + set_current_state(intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); + timeout = schedule_timeout(timeout); + sig = intr ? signal_pending(current) : 0; + } while (!sig && timeout); + return sig; +} + +/* Release ioremapped memory */ +static void cx18_iounmap(struct cx18 *cx) +{ + if (cx == NULL) + return; + + /* Release io memory */ + if (cx->enc_mem != NULL) { + CX18_DEBUG_INFO("releasing enc_mem\n"); + iounmap(cx->enc_mem); + cx->enc_mem = NULL; + } +} + +/* Hauppauge card? get values from tveeprom */ +void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv) +{ + u8 eedata[256]; + + cx->i2c_client[0].addr = 0xA0 >> 1; + tveeprom_read(&cx->i2c_client[0], eedata, sizeof(eedata)); + tveeprom_hauppauge_analog(&cx->i2c_client[0], tv, eedata); +} + +static void cx18_process_eeprom(struct cx18 *cx) +{ + struct tveeprom tv; + + cx18_read_eeprom(cx, &tv); + + /* Many thanks to Steven Toth from Hauppauge for providing the + model numbers */ + switch (tv.model) { + case 74000 ... 74099: + cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT); + break; + case 74700 ... 74799: + cx->card = cx18_get_card(CX18_CARD_HVR_1600_SAMSUNG); + break; + case 0: + CX18_ERR("Invalid EEPROM\n"); + return; + default: + CX18_ERR("Unknown model %d, defaulting to HVR-1600\n", tv.model); + cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT); + break; + } + + cx->v4l2_cap = cx->card->v4l2_capabilities; + cx->card_name = cx->card->name; + cx->card_i2c = cx->card->i2c; + + CX18_INFO("Autodetected %s\n", cx->card_name); + + if (tv.tuner_type == TUNER_ABSENT) + CX18_ERR("tveeprom cannot autodetect tuner!"); + + if (cx->options.tuner == -1) + cx->options.tuner = tv.tuner_type; + if (cx->options.radio == -1) + cx->options.radio = (tv.has_radio != 0); + + if (cx->std != 0) + /* user specified tuner standard */ + return; + + /* autodetect tuner standard */ + if (tv.tuner_formats & V4L2_STD_PAL) { + CX18_DEBUG_INFO("PAL tuner detected\n"); + cx->std |= V4L2_STD_PAL_BG | V4L2_STD_PAL_H; + } else if (tv.tuner_formats & V4L2_STD_NTSC) { + CX18_DEBUG_INFO("NTSC tuner detected\n"); + cx->std |= V4L2_STD_NTSC_M; + } else if (tv.tuner_formats & V4L2_STD_SECAM) { + CX18_DEBUG_INFO("SECAM tuner detected\n"); + cx->std |= V4L2_STD_SECAM_L; + } else { + CX18_INFO("No tuner detected, default to NTSC-M\n"); + cx->std |= V4L2_STD_NTSC_M; + } +} + +static v4l2_std_id cx18_parse_std(struct cx18 *cx) +{ + switch (pal[0]) { + case '6': + return V4L2_STD_PAL_60; + case 'b': + case 'B': + case 'g': + case 'G': + return V4L2_STD_PAL_BG; + case 'h': + case 'H': + return V4L2_STD_PAL_H; + case 'n': + case 'N': + if (pal[1] == 'c' || pal[1] == 'C') + return V4L2_STD_PAL_Nc; + return V4L2_STD_PAL_N; + case 'i': + case 'I': + return V4L2_STD_PAL_I; + case 'd': + case 'D': + case 'k': + case 'K': + return V4L2_STD_PAL_DK; + case 'M': + case 'm': + return V4L2_STD_PAL_M; + case '-': + break; + default: + CX18_WARN("pal= argument not recognised\n"); + return 0; + } + + switch (secam[0]) { + case 'b': + case 'B': + case 'g': + case 'G': + case 'h': + case 'H': + return V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H; + case 'd': + case 'D': + case 'k': + case 'K': + return V4L2_STD_SECAM_DK; + case 'l': + case 'L': + if (secam[1] == 'C' || secam[1] == 'c') + return V4L2_STD_SECAM_LC; + return V4L2_STD_SECAM_L; + case '-': + break; + default: + CX18_WARN("secam= argument not recognised\n"); + return 0; + } + + switch (ntsc[0]) { + case 'm': + case 'M': + return V4L2_STD_NTSC_M; + case 'j': + case 'J': + return V4L2_STD_NTSC_M_JP; + case 'k': + case 'K': + return V4L2_STD_NTSC_M_KR; + case '-': + break; + default: + CX18_WARN("ntsc= argument not recognised\n"); + return 0; + } + + /* no match found */ + return 0; +} + +static void cx18_process_options(struct cx18 *cx) +{ + int i, j; + + cx->options.megabytes[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_buffers; + cx->options.megabytes[CX18_ENC_STREAM_TYPE_TS] = enc_ts_buffers; + cx->options.megabytes[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_buffers; + cx->options.megabytes[CX18_ENC_STREAM_TYPE_VBI] = enc_vbi_buffers; + cx->options.megabytes[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_buffers; + cx->options.cardtype = cardtype[cx->num]; + cx->options.tuner = tuner[cx->num]; + cx->options.radio = radio[cx->num]; + + cx->std = cx18_parse_std(cx); + if (cx->options.cardtype == -1) { + CX18_INFO("Ignore card\n"); + return; + } + cx->card = cx18_get_card(cx->options.cardtype - 1); + if (cx->card) + CX18_INFO("User specified %s card\n", cx->card->name); + else if (cx->options.cardtype != 0) + CX18_ERR("Unknown user specified type, trying to autodetect card\n"); + if (cx->card == NULL) { + if (cx->dev->subsystem_vendor == CX18_PCI_ID_HAUPPAUGE) { + cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT); + CX18_INFO("Autodetected Hauppauge card\n"); + } + } + if (cx->card == NULL) { + for (i = 0; (cx->card = cx18_get_card(i)); i++) { + if (cx->card->pci_list == NULL) + continue; + for (j = 0; cx->card->pci_list[j].device; j++) { + if (cx->dev->device != + cx->card->pci_list[j].device) + continue; + if (cx->dev->subsystem_vendor != + cx->card->pci_list[j].subsystem_vendor) + continue; + if (cx->dev->subsystem_device != + cx->card->pci_list[j].subsystem_device) + continue; + CX18_INFO("Autodetected %s card\n", cx->card->name); + goto done; + } + } + } +done: + + if (cx->card == NULL) { + cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT); + CX18_ERR("Unknown card: vendor/device: %04x/%04x\n", + cx->dev->vendor, cx->dev->device); + CX18_ERR(" subsystem vendor/device: %04x/%04x\n", + cx->dev->subsystem_vendor, cx->dev->subsystem_device); + CX18_ERR("Defaulting to %s card\n", cx->card->name); + CX18_ERR("Please mail the vendor/device and subsystem vendor/device IDs and what kind of\n"); + CX18_ERR("card you have to the ivtv-devel mailinglist (www.ivtvdriver.org)\n"); + CX18_ERR("Prefix your subject line with [UNKNOWN CX18 CARD].\n"); + } + cx->v4l2_cap = cx->card->v4l2_capabilities; + cx->card_name = cx->card->name; + cx->card_i2c = cx->card->i2c; +} + +/* Precondition: the cx18 structure has been memset to 0. Only + the dev and num fields have been filled in. + No assumptions on the card type may be made here (see cx18_init_struct2 + for that). + */ +static int __devinit cx18_init_struct1(struct cx18 *cx) +{ + cx->base_addr = pci_resource_start(cx->dev, 0); + + mutex_init(&cx->serialize_lock); + mutex_init(&cx->i2c_bus_lock[0]); + mutex_init(&cx->i2c_bus_lock[1]); + + spin_lock_init(&cx->lock); + spin_lock_init(&cx->dma_reg_lock); + + /* start counting open_id at 1 */ + cx->open_id = 1; + + /* Initial settings */ + cx2341x_fill_defaults(&cx->params); + cx->temporal_strength = cx->params.video_temporal_filter; + cx->spatial_strength = cx->params.video_spatial_filter; + cx->filter_mode = cx->params.video_spatial_filter_mode | + (cx->params.video_temporal_filter_mode << 1) | + (cx->params.video_median_filter_type << 2); + cx->params.port = CX2341X_PORT_MEMORY; + cx->params.capabilities = CX2341X_CAP_HAS_SLICED_VBI; + init_waitqueue_head(&cx->cap_w); + init_waitqueue_head(&cx->mb_apu_waitq); + init_waitqueue_head(&cx->mb_cpu_waitq); + init_waitqueue_head(&cx->mb_epu_waitq); + init_waitqueue_head(&cx->mb_hpu_waitq); + init_waitqueue_head(&cx->dma_waitq); + + /* VBI */ + cx->vbi.in.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE; + cx->vbi.sliced_in = &cx->vbi.in.fmt.sliced; + cx->vbi.raw_size = 1456; + cx->vbi.raw_decoder_line_size = 1456; + cx->vbi.raw_decoder_sav_odd_field = 0x20; + cx->vbi.raw_decoder_sav_even_field = 0x60; + cx->vbi.sliced_decoder_line_size = 272; + cx->vbi.sliced_decoder_sav_odd_field = 0xB0; + cx->vbi.sliced_decoder_sav_even_field = 0xF0; + return 0; +} + +/* Second initialization part. Here the card type has been + autodetected. */ +static void __devinit cx18_init_struct2(struct cx18 *cx) +{ + int i; + + for (i = 0; i < CX18_CARD_MAX_VIDEO_INPUTS; i++) + if (cx->card->video_inputs[i].video_type == 0) + break; + cx->nof_inputs = i; + for (i = 0; i < CX18_CARD_MAX_AUDIO_INPUTS; i++) + if (cx->card->audio_inputs[i].audio_type == 0) + break; + cx->nof_audio_inputs = i; + + /* Find tuner input */ + for (i = 0; i < cx->nof_inputs; i++) { + if (cx->card->video_inputs[i].video_type == + CX18_CARD_INPUT_VID_TUNER) + break; + } + if (i == cx->nof_inputs) + i = 0; + cx->active_input = i; + cx->audio_input = cx->card->video_inputs[i].audio_index; + cx->av_state.vid_input = CX18_AV_COMPOSITE7; + cx->av_state.aud_input = CX18_AV_AUDIO8; + cx->av_state.audclk_freq = 48000; + cx->av_state.audmode = V4L2_TUNER_MODE_LANG1; + cx->av_state.vbi_line_offset = 8; +} + +static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *dev, + const struct pci_device_id *pci_id) +{ + u16 cmd; + unsigned char pci_latency; + + CX18_DEBUG_INFO("Enabling pci device\n"); + + if (pci_enable_device(dev)) { + CX18_ERR("Can't enable device %d!\n", cx->num); + return -EIO; + } + if (pci_set_dma_mask(dev, 0xffffffff)) { + CX18_ERR("No suitable DMA available on card %d.\n", cx->num); + return -EIO; + } + if (!request_mem_region(cx->base_addr, CX18_MEM_SIZE, "cx18 encoder")) { + CX18_ERR("Cannot request encoder memory region on card %d.\n", cx->num); + return -EIO; + } + + /* Check for bus mastering */ + pci_read_config_word(dev, PCI_COMMAND, &cmd); + cmd |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; + pci_write_config_word(dev, PCI_COMMAND, cmd); + + pci_read_config_byte(dev, PCI_CLASS_REVISION, &cx->card_rev); + pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency); + + if (pci_latency < 64 && cx18_pci_latency) { + CX18_INFO("Unreasonably low latency timer, " + "setting to 64 (was %d)\n", pci_latency); + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64); + pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency); + } + /* This config space value relates to DMA latencies. The + default value 0x8080 is too low however and will lead + to DMA errors. 0xffff is the max value which solves + these problems. */ + pci_write_config_dword(dev, 0x40, 0xffff); + + CX18_DEBUG_INFO("cx%d (rev %d) at %02x:%02x.%x, " + "irq: %d, latency: %d, memory: 0x%lx\n", + cx->dev->device, cx->card_rev, dev->bus->number, + PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), + cx->dev->irq, pci_latency, (unsigned long)cx->base_addr); + + return 0; +} + +static u32 cx18_request_module(struct cx18 *cx, u32 hw, + const char *name, u32 id) +{ + if ((hw & id) == 0) + return hw; + if (request_module(name) != 0) { + CX18_ERR("Failed to load module %s\n", name); + return hw & ~id; + } + CX18_DEBUG_INFO("Loaded module %s\n", name); + return hw; +} + +static void cx18_load_and_init_modules(struct cx18 *cx) +{ + u32 hw = cx->card->hw_all; + int i; + + /* load modules */ +#ifndef CONFIG_VIDEO_TUNER + hw = cx18_request_module(cx, hw, "tuner", CX18_HW_TUNER); +#endif +#ifndef CONFIG_VIDEO_CS5345 + hw = cx18_request_module(cx, hw, "cs5345", CX18_HW_CS5345); +#endif + + /* check which i2c devices are actually found */ + for (i = 0; i < 32; i++) { + u32 device = 1 << i; + + if (!(device & hw)) + continue; + if (device == CX18_HW_GPIO || device == CX18_HW_TVEEPROM || + device == CX18_HW_CX23418 || device == CX18_HW_DVB) { + /* These 'devices' do not use i2c probing */ + cx->hw_flags |= device; + continue; + } + cx18_i2c_register(cx, i); + if (cx18_i2c_hw_addr(cx, device) > 0) + cx->hw_flags |= device; + } + + hw = cx->hw_flags; +} + +static int __devinit cx18_probe(struct pci_dev *dev, + const struct pci_device_id *pci_id) +{ + int retval = 0; + int vbi_buf_size; + u32 devtype; + struct cx18 *cx; + + spin_lock(&cx18_cards_lock); + + /* Make sure we've got a place for this card */ + if (cx18_cards_active == CX18_MAX_CARDS) { + printk(KERN_ERR "cx18: Maximum number of cards detected (%d).\n", + cx18_cards_active); + spin_unlock(&cx18_cards_lock); + return -ENOMEM; + } + + cx = kzalloc(sizeof(struct cx18), GFP_ATOMIC); + if (cx == 0) { + spin_unlock(&cx18_cards_lock); + return -ENOMEM; + } + cx18_cards[cx18_cards_active] = cx; + cx->dev = dev; + cx->num = cx18_cards_active++; + snprintf(cx->name, sizeof(cx->name) - 1, "cx18-%d", cx->num); + CX18_INFO("Initializing card #%d\n", cx->num); + + spin_unlock(&cx18_cards_lock); + + cx18_process_options(cx); + if (cx->options.cardtype == -1) { + retval = -ENODEV; + goto err; + } + if (cx18_init_struct1(cx)) { + retval = -ENOMEM; + goto err; + } + + CX18_DEBUG_INFO("base addr: 0x%08x\n", cx->base_addr); + + /* PCI Device Setup */ + retval = cx18_setup_pci(cx, dev, pci_id); + if (retval != 0) { + if (retval == -EIO) + goto free_workqueue; + else if (retval == -ENXIO) + goto free_mem; + } + /* save cx in the pci struct for later use */ + pci_set_drvdata(dev, cx); + + /* map io memory */ + CX18_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n", + cx->base_addr + CX18_MEM_OFFSET, CX18_MEM_SIZE); + cx->enc_mem = ioremap_nocache(cx->base_addr + CX18_MEM_OFFSET, + CX18_MEM_SIZE); + if (!cx->enc_mem) { + CX18_ERR("ioremap failed, perhaps increasing __VMALLOC_RESERVE in page.h\n"); + CX18_ERR("or disabling CONFIG_HIGHMEM4G into the kernel would help\n"); + retval = -ENOMEM; + goto free_mem; + } + cx->reg_mem = cx->enc_mem + CX18_REG_OFFSET; + devtype = read_reg(0xC72028); + switch (devtype & 0xff000000) { + case 0xff000000: + CX18_INFO("cx23418 revision %08x (A)\n", devtype); + break; + case 0x01000000: + CX18_INFO("cx23418 revision %08x (B)\n", devtype); + break; + default: + CX18_INFO("cx23418 revision %08x (Unknown)\n", devtype); + break; + } + + cx18_init_power(cx, 1); + cx18_init_memory(cx); + + cx->scb = (struct cx18_scb *)(cx->enc_mem + SCB_OFFSET); + cx18_init_scb(cx); + + cx18_gpio_init(cx); + + /* active i2c */ + CX18_DEBUG_INFO("activating i2c...\n"); + if (init_cx18_i2c(cx)) { + CX18_ERR("Could not initialize i2c\n"); + goto free_map; + } + + CX18_DEBUG_INFO("Active card count: %d.\n", cx18_cards_active); + + if (cx->card->hw_all & CX18_HW_TVEEPROM) { + /* Based on the model number the cardtype may be changed. + The PCI IDs are not always reliable. */ + cx18_process_eeprom(cx); + } + if (cx->card->comment) + CX18_INFO("%s", cx->card->comment); + if (cx->card->v4l2_capabilities == 0) { + retval = -ENODEV; + goto free_i2c; + } + cx18_init_memory(cx); + + /* Register IRQ */ + retval = request_irq(cx->dev->irq, cx18_irq_handler, + IRQF_SHARED | IRQF_DISABLED, cx->name, (void *)cx); + if (retval) { + CX18_ERR("Failed to register irq %d\n", retval); + goto free_i2c; + } + + if (cx->std == 0) + cx->std = V4L2_STD_NTSC_M; + + if (cx->options.tuner == -1) { + int i; + + for (i = 0; i < CX18_CARD_MAX_TUNERS; i++) { + if ((cx->std & cx->card->tuners[i].std) == 0) + continue; + cx->options.tuner = cx->card->tuners[i].tuner; + break; + } + } + /* if no tuner was found, then pick the first tuner in the card list */ + if (cx->options.tuner == -1 && cx->card->tuners[0].std) { + cx->std = cx->card->tuners[0].std; + cx->options.tuner = cx->card->tuners[0].tuner; + } + if (cx->options.radio == -1) + cx->options.radio = (cx->card->radio_input.audio_type != 0); + + /* The card is now fully identified, continue with card-specific + initialization. */ + cx18_init_struct2(cx); + + cx18_load_and_init_modules(cx); + + if (cx->std & V4L2_STD_525_60) { + cx->is_60hz = 1; + cx->is_out_60hz = 1; + } else { + cx->is_50hz = 1; + cx->is_out_50hz = 1; + } + cx->params.video_gop_size = cx->is_60hz ? 15 : 12; + + cx->stream_buf_size[CX18_ENC_STREAM_TYPE_MPG] = 0x08000; + cx->stream_buf_size[CX18_ENC_STREAM_TYPE_TS] = 0x08000; + cx->stream_buf_size[CX18_ENC_STREAM_TYPE_PCM] = 0x01200; + cx->stream_buf_size[CX18_ENC_STREAM_TYPE_YUV] = 0x20000; + vbi_buf_size = cx->vbi.raw_size * (cx->is_60hz ? 24 : 36) / 2; + cx->stream_buf_size[CX18_ENC_STREAM_TYPE_VBI] = vbi_buf_size; + + if (cx->options.radio > 0) + cx->v4l2_cap |= V4L2_CAP_RADIO; + + retval = cx18_streams_setup(cx); + if (retval) { + CX18_ERR("Error %d setting up streams\n", retval); + goto free_irq; + } + retval = cx18_streams_register(cx); + if (retval) { + CX18_ERR("Error %d registering devices\n", retval); + goto free_streams; + } + + if (cx->options.tuner > -1) { + struct tuner_setup setup; + + setup.addr = ADDR_UNSET; + setup.type = cx->options.tuner; + setup.mode_mask = T_ANALOG_TV; /* matches TV tuners */ + setup.tuner_callback = (setup.type == TUNER_XC2028) ? + cx18_reset_tuner_gpio : NULL; + cx18_call_i2c_clients(cx, TUNER_SET_TYPE_ADDR, &setup); + if (setup.type == TUNER_XC2028) { + static struct xc2028_ctrl ctrl = { + .fname = XC2028_DEFAULT_FIRMWARE, + .max_len = 64, + }; + struct v4l2_priv_tun_config cfg = { + .tuner = cx->options.tuner, + .priv = &ctrl, + }; + cx18_call_i2c_clients(cx, TUNER_SET_CONFIG, &cfg); + } + } + + /* The tuner is fixed to the standard. The other inputs (e.g. S-Video) + are not. */ + cx->tuner_std = cx->std; + + cx18_init_on_first_open(cx); + + CX18_INFO("Initialized card #%d: %s\n", cx->num, cx->card_name); + + return 0; + +free_streams: + cx18_streams_cleanup(cx); +free_irq: + free_irq(cx->dev->irq, (void *)cx); +free_i2c: + exit_cx18_i2c(cx); +free_map: + cx18_iounmap(cx); +free_mem: + release_mem_region(cx->base_addr, CX18_MEM_SIZE); +free_workqueue: +err: + if (retval == 0) + retval = -ENODEV; + CX18_ERR("Error %d on initialization\n", retval); + + kfree(cx18_cards[cx18_cards_active]); + cx18_cards[cx18_cards_active] = NULL; + return retval; +} + +int cx18_init_on_first_open(struct cx18 *cx) +{ + int video_input; + int fw_retry_count = 3; + struct v4l2_frequency vf; + + if (test_bit(CX18_F_I_FAILED, &cx->i_flags)) + return -ENXIO; + + if (test_and_set_bit(CX18_F_I_INITED, &cx->i_flags)) + return 0; + + while (--fw_retry_count > 0) { + /* load firmware */ + if (cx18_firmware_init(cx) == 0) + break; + if (fw_retry_count > 1) + CX18_WARN("Retry loading firmware\n"); + } + + if (fw_retry_count == 0) { + set_bit(CX18_F_I_FAILED, &cx->i_flags); + return -ENXIO; + } + set_bit(CX18_F_I_LOADED_FW, &cx->i_flags); + + /* Init the firmware twice to work around a silicon bug + * transport related. */ + + fw_retry_count = 3; + while (--fw_retry_count > 0) { + /* load firmware */ + if (cx18_firmware_init(cx) == 0) + break; + if (fw_retry_count > 1) + CX18_WARN("Retry loading firmware\n"); + } + + if (fw_retry_count == 0) { + set_bit(CX18_F_I_FAILED, &cx->i_flags); + return -ENXIO; + } + + vf.tuner = 0; + vf.type = V4L2_TUNER_ANALOG_TV; + vf.frequency = 6400; /* the tuner 'baseline' frequency */ + + /* Set initial frequency. For PAL/SECAM broadcasts no + 'default' channel exists AFAIK. */ + if (cx->std == V4L2_STD_NTSC_M_JP) + vf.frequency = 1460; /* ch. 1 91250*16/1000 */ + else if (cx->std & V4L2_STD_NTSC_M) + vf.frequency = 1076; /* ch. 4 67250*16/1000 */ + + video_input = cx->active_input; + cx->active_input++; /* Force update of input */ + cx18_v4l2_ioctls(cx, NULL, VIDIOC_S_INPUT, &video_input); + + /* Let the VIDIOC_S_STD ioctl do all the work, keeps the code + in one place. */ + cx->std++; /* Force full standard initialization */ + cx18_v4l2_ioctls(cx, NULL, VIDIOC_S_STD, &cx->tuner_std); + cx18_v4l2_ioctls(cx, NULL, VIDIOC_S_FREQUENCY, &vf); + return 0; +} + +static void cx18_remove(struct pci_dev *pci_dev) +{ + struct cx18 *cx = pci_get_drvdata(pci_dev); + + CX18_DEBUG_INFO("Removing Card #%d\n", cx->num); + + /* Stop all captures */ + CX18_DEBUG_INFO("Stopping all streams\n"); + if (atomic_read(&cx->capturing) > 0) + cx18_stop_all_captures(cx); + + /* Interrupts */ + sw1_irq_disable(IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU); + sw2_irq_disable(IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK); + + cx18_halt_firmware(cx); + + cx18_streams_cleanup(cx); + + exit_cx18_i2c(cx); + + free_irq(cx->dev->irq, (void *)cx); + + if (cx->dev) + cx18_iounmap(cx); + + release_mem_region(cx->base_addr, CX18_MEM_SIZE); + + pci_disable_device(cx->dev); + + CX18_INFO("Removed %s, card #%d\n", cx->card_name, cx->num); +} + +/* define a pci_driver for card detection */ +static struct pci_driver cx18_pci_driver = { + .name = "cx18", + .id_table = cx18_pci_tbl, + .probe = cx18_probe, + .remove = cx18_remove, +}; + +static int module_start(void) +{ + printk(KERN_INFO "cx18: Start initialization, version %s\n", CX18_VERSION); + + memset(cx18_cards, 0, sizeof(cx18_cards)); + + /* Validate parameters */ + if (cx18_first_minor < 0 || cx18_first_minor >= CX18_MAX_CARDS) { + printk(KERN_ERR "cx18: Exiting, ivtv_first_minor must be between 0 and %d\n", + CX18_MAX_CARDS - 1); + return -1; + } + + if (cx18_debug < 0 || cx18_debug > 511) { + cx18_debug = 0; + printk(KERN_INFO "cx18: Debug value must be >= 0 and <= 511!\n"); + } + + if (pci_register_driver(&cx18_pci_driver)) { + printk(KERN_ERR "cx18: Error detecting PCI card\n"); + return -ENODEV; + } + printk(KERN_INFO "cx18: End initialization\n"); + return 0; +} + +static void module_cleanup(void) +{ + int i; + + pci_unregister_driver(&cx18_pci_driver); + + for (i = 0; i < cx18_cards_active; i++) { + if (cx18_cards[i] == NULL) + continue; + kfree(cx18_cards[i]); + } +} + +module_init(module_start); +module_exit(module_cleanup); diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h new file mode 100644 index 00000000000..2ee939193bb --- /dev/null +++ b/drivers/media/video/cx18/cx18-driver.h @@ -0,0 +1,500 @@ +/* + * cx18 driver internal defines and structures + * + * Derived from ivtv-driver.h + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 CX18_DRIVER_H +#define CX18_DRIVER_H + +#include <linux/version.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/sched.h> +#include <linux/fs.h> +#include <linux/pci.h> +#include <linux/interrupt.h> +#include <linux/spinlock.h> +#include <linux/i2c.h> +#include <linux/i2c-algo-bit.h> +#include <linux/list.h> +#include <linux/unistd.h> +#include <linux/byteorder/swab.h> +#include <linux/pagemap.h> +#include <linux/workqueue.h> +#include <linux/mutex.h> + +#include <linux/dvb/video.h> +#include <linux/dvb/audio.h> +#include <media/v4l2-common.h> +#include <media/tuner.h> +#include "cx18-mailbox.h" +#include "cx18-av-core.h" +#include "cx23418.h" + +/* DVB */ +#include "demux.h" +#include "dmxdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" +#include "dvbdev.h" + +#ifndef CONFIG_PCI +# error "This driver requires kernel PCI support." +#endif + +#define CX18_MEM_OFFSET 0x00000000 +#define CX18_MEM_SIZE 0x04000000 +#define CX18_REG_OFFSET 0x02000000 + +/* Maximum cx18 driver instances. */ +#define CX18_MAX_CARDS 32 + +/* Supported cards */ +#define CX18_CARD_HVR_1600_ESMT 0 /* Hauppauge HVR 1600 (ESMT memory) */ +#define CX18_CARD_HVR_1600_SAMSUNG 1 /* Hauppauge HVR 1600 (Samsung memory) */ +#define CX18_CARD_COMPRO_H900 2 /* Compro VideoMate H900 */ +#define CX18_CARD_YUAN_MPC718 3 /* Yuan MPC718 */ +#define CX18_CARD_LAST 3 + +#define CX18_ENC_STREAM_TYPE_MPG 0 +#define CX18_ENC_STREAM_TYPE_TS 1 +#define CX18_ENC_STREAM_TYPE_YUV 2 +#define CX18_ENC_STREAM_TYPE_VBI 3 +#define CX18_ENC_STREAM_TYPE_PCM 4 +#define CX18_ENC_STREAM_TYPE_IDX 5 +#define CX18_ENC_STREAM_TYPE_RAD 6 +#define CX18_MAX_STREAMS 7 + +/* system vendor and device IDs */ +#define PCI_VENDOR_ID_CX 0x14f1 +#define PCI_DEVICE_ID_CX23418 0x5b7a + +/* subsystem vendor ID */ +#define CX18_PCI_ID_HAUPPAUGE 0x0070 +#define CX18_PCI_ID_COMPRO 0x185b +#define CX18_PCI_ID_YUAN 0x12ab + +/* ======================================================================== */ +/* ========================== START USER SETTABLE DMA VARIABLES =========== */ +/* ======================================================================== */ + +/* DMA Buffers, Default size in MB allocated */ +#define CX18_DEFAULT_ENC_TS_BUFFERS 1 +#define CX18_DEFAULT_ENC_MPG_BUFFERS 2 +#define CX18_DEFAULT_ENC_IDX_BUFFERS 1 +#define CX18_DEFAULT_ENC_YUV_BUFFERS 2 +#define CX18_DEFAULT_ENC_VBI_BUFFERS 1 +#define CX18_DEFAULT_ENC_PCM_BUFFERS 1 + +/* i2c stuff */ +#define I2C_CLIENTS_MAX 16 + +/* debugging */ + +/* Flag to turn on high volume debugging */ +#define CX18_DBGFLG_WARN (1 << 0) +#define CX18_DBGFLG_INFO (1 << 1) +#define CX18_DBGFLG_API (1 << 2) +#define CX18_DBGFLG_DMA (1 << 3) +#define CX18_DBGFLG_IOCTL (1 << 4) +#define CX18_DBGFLG_FILE (1 << 5) +#define CX18_DBGFLG_I2C (1 << 6) +#define CX18_DBGFLG_IRQ (1 << 7) +/* Flag to turn on high volume debugging */ +#define CX18_DBGFLG_HIGHVOL (1 << 8) + +/* NOTE: extra space before comma in 'cx->num , ## args' is required for + gcc-2.95, otherwise it won't compile. */ +#define CX18_DEBUG(x, type, fmt, args...) \ + do { \ + if ((x) & cx18_debug) \ + printk(KERN_INFO "cx18-%d " type ": " fmt, cx->num , ## args); \ + } while (0) +#define CX18_DEBUG_WARN(fmt, args...) CX18_DEBUG(CX18_DBGFLG_WARN, "warning", fmt , ## args) +#define CX18_DEBUG_INFO(fmt, args...) CX18_DEBUG(CX18_DBGFLG_INFO, "info", fmt , ## args) +#define CX18_DEBUG_API(fmt, args...) CX18_DEBUG(CX18_DBGFLG_API, "api", fmt , ## args) +#define CX18_DEBUG_DMA(fmt, args...) CX18_DEBUG(CX18_DBGFLG_DMA, "dma", fmt , ## args) +#define CX18_DEBUG_IOCTL(fmt, args...) CX18_DEBUG(CX18_DBGFLG_IOCTL, "ioctl", fmt , ## args) +#define CX18_DEBUG_FILE(fmt, args...) CX18_DEBUG(CX18_DBGFLG_FILE, "file", fmt , ## args) +#define CX18_DEBUG_I2C(fmt, args...) CX18_DEBUG(CX18_DBGFLG_I2C, "i2c", fmt , ## args) +#define CX18_DEBUG_IRQ(fmt, args...) CX18_DEBUG(CX18_DBGFLG_IRQ, "irq", fmt , ## args) + +#define CX18_DEBUG_HIGH_VOL(x, type, fmt, args...) \ + do { \ + if (((x) & cx18_debug) && (cx18_debug & CX18_DBGFLG_HIGHVOL)) \ + printk(KERN_INFO "cx18%d " type ": " fmt, cx->num , ## args); \ + } while (0) +#define CX18_DEBUG_HI_WARN(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_WARN, "warning", fmt , ## args) +#define CX18_DEBUG_HI_INFO(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_INFO, "info", fmt , ## args) +#define CX18_DEBUG_HI_API(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_API, "api", fmt , ## args) +#define CX18_DEBUG_HI_DMA(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_DMA, "dma", fmt , ## args) +#define CX18_DEBUG_HI_IOCTL(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_IOCTL, "ioctl", fmt , ## args) +#define CX18_DEBUG_HI_FILE(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_FILE, "file", fmt , ## args) +#define CX18_DEBUG_HI_I2C(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_I2C, "i2c", fmt , ## args) +#define CX18_DEBUG_HI_IRQ(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_IRQ, "irq", fmt , ## args) + +/* Standard kernel messages */ +#define CX18_ERR(fmt, args...) printk(KERN_ERR "cx18-%d: " fmt, cx->num , ## args) +#define CX18_WARN(fmt, args...) printk(KERN_WARNING "cx18-%d: " fmt, cx->num , ## args) +#define CX18_INFO(fmt, args...) printk(KERN_INFO "cx18-%d: " fmt, cx->num , ## args) + +/* Values for CX18_API_DEC_PLAYBACK_SPEED mpeg_frame_type_mask parameter: */ +#define MPEG_FRAME_TYPE_IFRAME 1 +#define MPEG_FRAME_TYPE_IFRAME_PFRAME 3 +#define MPEG_FRAME_TYPE_ALL 7 + +#define CX18_MAX_PGM_INDEX (400) + +extern int cx18_debug; + + +struct cx18_options { + int megabytes[CX18_MAX_STREAMS]; /* Size in megabytes of each stream */ + int cardtype; /* force card type on load */ + int tuner; /* set tuner on load */ + int radio; /* enable/disable radio */ +}; + +/* per-buffer bit flags */ +#define CX18_F_B_NEED_BUF_SWAP 0 /* this buffer should be byte swapped */ + +/* per-stream, s_flags */ +#define CX18_F_S_CLAIMED 3 /* this stream is claimed */ +#define CX18_F_S_STREAMING 4 /* the fw is decoding/encoding this stream */ +#define CX18_F_S_INTERNAL_USE 5 /* this stream is used internally (sliced VBI processing) */ +#define CX18_F_S_STREAMOFF 7 /* signal end of stream EOS */ +#define CX18_F_S_APPL_IO 8 /* this stream is used read/written by an application */ + +/* per-cx18, i_flags */ +#define CX18_F_I_LOADED_FW 0 /* Loaded the firmware the first time */ +#define CX18_F_I_EOS 4 /* End of encoder stream reached */ +#define CX18_F_I_RADIO_USER 5 /* The radio tuner is selected */ +#define CX18_F_I_ENC_PAUSED 13 /* the encoder is paused */ +#define CX18_F_I_INITED 21 /* set after first open */ +#define CX18_F_I_FAILED 22 /* set if first open failed */ + +/* These are the VBI types as they appear in the embedded VBI private packets. */ +#define CX18_SLICED_TYPE_TELETEXT_B (1) +#define CX18_SLICED_TYPE_CAPTION_525 (4) +#define CX18_SLICED_TYPE_WSS_625 (5) +#define CX18_SLICED_TYPE_VPS (7) + +struct cx18_buffer { + struct list_head list; + dma_addr_t dma_handle; + u32 id; + unsigned long b_flags; + char *buf; + + u32 bytesused; + u32 readpos; +}; + +struct cx18_queue { + struct list_head list; + u32 buffers; + u32 length; + u32 bytesused; +}; + +struct cx18_dvb { + struct dmx_frontend hw_frontend; + struct dmx_frontend mem_frontend; + struct dmxdev dmxdev; + struct dvb_adapter dvb_adapter; + struct dvb_demux demux; + struct dvb_frontend *fe; + struct dvb_net dvbnet; + int enabled; + int feeding; + + struct mutex feedlock; + +}; + +struct cx18; /* forward reference */ +struct cx18_scb; /* forward reference */ + +struct cx18_stream { + /* These first four fields are always set, even if the stream + is not actually created. */ + struct video_device *v4l2dev; /* NULL when stream not created */ + struct cx18 *cx; /* for ease of use */ + const char *name; /* name of the stream */ + int type; /* stream type */ + u32 handle; /* task handle */ + unsigned mdl_offset; + + u32 id; + spinlock_t qlock; /* locks access to the queues */ + unsigned long s_flags; /* status flags, see above */ + int dma; /* can be PCI_DMA_TODEVICE, + PCI_DMA_FROMDEVICE or + PCI_DMA_NONE */ + u64 dma_pts; + wait_queue_head_t waitq; + + /* Buffer Stats */ + u32 buffers; + u32 buf_size; + u32 buffers_stolen; + + /* Buffer Queues */ + struct cx18_queue q_free; /* free buffers */ + struct cx18_queue q_full; /* full buffers */ + struct cx18_queue q_io; /* waiting for I/O */ + + /* DVB / Digital Transport */ + struct cx18_dvb dvb; +}; + +struct cx18_open_id { + u32 open_id; + int type; + enum v4l2_priority prio; + struct cx18 *cx; +}; + +/* forward declaration of struct defined in cx18-cards.h */ +struct cx18_card; + + +#define CX18_VBI_FRAMES 32 + +/* VBI data */ +struct vbi_info { + u32 enc_size; + u32 frame; + u8 cc_data_odd[256]; + u8 cc_data_even[256]; + int cc_pos; + u8 cc_no_update; + u8 vps[5]; + u8 vps_found; + int wss; + u8 wss_found; + u8 wss_no_update; + u32 raw_decoder_line_size; + u8 raw_decoder_sav_odd_field; + u8 raw_decoder_sav_even_field; + u32 sliced_decoder_line_size; + u8 sliced_decoder_sav_odd_field; + u8 sliced_decoder_sav_even_field; + struct v4l2_format in; + /* convenience pointer to sliced struct in vbi_in union */ + struct v4l2_sliced_vbi_format *sliced_in; + u32 service_set_in; + int insert_mpeg; + + /* Buffer for the maximum of 2 * 18 * packet_size sliced VBI lines. + One for /dev/vbi0 and one for /dev/vbi8 */ + struct v4l2_sliced_vbi_data sliced_data[36]; + + /* Buffer for VBI data inserted into MPEG stream. + The first byte is a dummy byte that's never used. + The next 16 bytes contain the MPEG header for the VBI data, + the remainder is the actual VBI data. + The max size accepted by the MPEG VBI reinsertion turns out + to be 1552 bytes, which happens to be 4 + (1 + 42) * (2 * 18) bytes, + where 4 is a four byte header, 42 is the max sliced VBI payload, 1 is + a single line header byte and 2 * 18 is the number of VBI lines per frame. + + However, it seems that the data must be 1K aligned, so we have to + pad the data until the 1 or 2 K boundary. + + This pointer array will allocate 2049 bytes to store each VBI frame. */ + u8 *sliced_mpeg_data[CX18_VBI_FRAMES]; + u32 sliced_mpeg_size[CX18_VBI_FRAMES]; + struct cx18_buffer sliced_mpeg_buf; + u32 inserted_frame; + + u32 start[2], count; + u32 raw_size; + u32 sliced_size; +}; + +/* Per cx23418, per I2C bus private algo callback data */ +struct cx18_i2c_algo_callback_data { + struct cx18 *cx; + int bus_index; /* 0 or 1 for the cx23418's 1st or 2nd I2C bus */ +}; + +/* Struct to hold info about cx18 cards */ +struct cx18 { + int num; /* board number, -1 during init! */ + char name[8]; /* board name for printk and interrupts (e.g. 'cx180') */ + struct pci_dev *dev; /* PCI device */ + const struct cx18_card *card; /* card information */ + const char *card_name; /* full name of the card */ + const struct cx18_card_tuner_i2c *card_i2c; /* i2c addresses to probe for tuner */ + u8 is_50hz; + u8 is_60hz; + u8 is_out_50hz; + u8 is_out_60hz; + u8 nof_inputs; /* number of video inputs */ + u8 nof_audio_inputs; /* number of audio inputs */ + u16 buffer_id; /* buffer ID counter */ + u32 v4l2_cap; /* V4L2 capabilities of card */ + u32 hw_flags; /* Hardware description of the board */ + unsigned mdl_offset; + struct cx18_scb *scb; /* pointer to SCB */ + + struct cx18_av_state av_state; + + /* codec settings */ + struct cx2341x_mpeg_params params; + u32 filter_mode; + u32 temporal_strength; + u32 spatial_strength; + + /* dualwatch */ + unsigned long dualwatch_jiffies; + u16 dualwatch_stereo_mode; + + /* Digitizer type */ + int digitizer; /* 0x00EF = saa7114 0x00FO = saa7115 0x0106 = mic */ + + struct mutex serialize_lock; /* mutex used to serialize open/close/start/stop/ioctl operations */ + struct cx18_options options; /* User options */ + int stream_buf_size[CX18_MAX_STREAMS]; /* Stream buffer size */ + struct cx18_stream streams[CX18_MAX_STREAMS]; /* Stream data */ + unsigned long i_flags; /* global cx18 flags */ + atomic_t capturing; /* count number of active capture streams */ + spinlock_t lock; /* lock access to this struct */ + int search_pack_header; + + spinlock_t dma_reg_lock; /* lock access to DMA engine registers */ + + int open_id; /* incremented each time an open occurs, used as + unique ID. Starts at 1, so 0 can be used as + uninitialized value in the stream->id. */ + + u32 base_addr; + struct v4l2_prio_state prio; + + u8 card_rev; + void __iomem *enc_mem, *reg_mem; + + struct vbi_info vbi; + + u32 pgm_info_offset; + u32 pgm_info_num; + u32 pgm_info_write_idx; + u32 pgm_info_read_idx; + struct v4l2_enc_idx_entry pgm_info[CX18_MAX_PGM_INDEX]; + + u64 mpg_data_received; + u64 vbi_data_inserted; + + wait_queue_head_t mb_apu_waitq; + wait_queue_head_t mb_cpu_waitq; + wait_queue_head_t mb_epu_waitq; + wait_queue_head_t mb_hpu_waitq; + wait_queue_head_t cap_w; + /* when the current DMA is finished this queue is woken up */ + wait_queue_head_t dma_waitq; + + /* i2c */ + struct i2c_adapter i2c_adap[2]; + struct i2c_algo_bit_data i2c_algo[2]; + struct cx18_i2c_algo_callback_data i2c_algo_cb_data[2]; + struct i2c_client i2c_client[2]; + struct mutex i2c_bus_lock[2]; + struct i2c_client *i2c_clients[I2C_CLIENTS_MAX]; + + /* v4l2 and User settings */ + + /* codec settings */ + u32 audio_input; + u32 active_input; + u32 active_output; + v4l2_std_id std; + v4l2_std_id tuner_std; /* The norm of the tuner (fixed) */ +}; + +/* Globals */ +extern struct cx18 *cx18_cards[]; +extern int cx18_cards_active; +extern int cx18_first_minor; +extern spinlock_t cx18_cards_lock; + +/*==============Prototypes==================*/ + +/* Return non-zero if a signal is pending */ +int cx18_msleep_timeout(unsigned int msecs, int intr); + +/* Wait on queue, returns -EINTR if interrupted */ +int cx18_waitq(wait_queue_head_t *waitq); + +/* Read Hauppauge eeprom */ +struct tveeprom; /* forward reference */ +void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv); + +/* First-open initialization: load firmware, etc. */ +int cx18_init_on_first_open(struct cx18 *cx); + +/* This is a PCI post thing, where if the pci register is not read, then + the write doesn't always take effect right away. By reading back the + register any pending PCI writes will be performed (in order), and so + you can be sure that the writes are guaranteed to be done. + + Rarely needed, only in some timing sensitive cases. + Apparently if this is not done some motherboards seem + to kill the firmware and get into the broken state until computer is + rebooted. */ +#define write_sync(val, reg) \ + do { writel(val, reg); readl(reg); } while (0) + +#define read_reg(reg) readl(cx->reg_mem + (reg)) +#define write_reg(val, reg) writel(val, cx->reg_mem + (reg)) +#define write_reg_sync(val, reg) \ + do { write_reg(val, reg); read_reg(reg); } while (0) + +#define read_enc(addr) readl(cx->enc_mem + (u32)(addr)) +#define write_enc(val, addr) writel(val, cx->enc_mem + (u32)(addr)) +#define write_enc_sync(val, addr) \ + do { write_enc(val, addr); read_enc(addr); } while (0) + +#define sw1_irq_enable(val) do { \ + write_reg(val, SW1_INT_STATUS); \ + write_reg(read_reg(SW1_INT_ENABLE_PCI) | (val), SW1_INT_ENABLE_PCI); \ +} while (0) + +#define sw1_irq_disable(val) \ + write_reg(read_reg(SW1_INT_ENABLE_PCI) & ~(val), SW1_INT_ENABLE_PCI); + +#define sw2_irq_enable(val) do { \ + write_reg(val, SW2_INT_STATUS); \ + write_reg(read_reg(SW2_INT_ENABLE_PCI) | (val), SW2_INT_ENABLE_PCI); \ +} while (0) + +#define sw2_irq_disable(val) \ + write_reg(read_reg(SW2_INT_ENABLE_PCI) & ~(val), SW2_INT_ENABLE_PCI); + +#define setup_page(addr) do { \ + u32 val = read_reg(0xD000F8) & ~0x1f00; \ + write_reg(val | (((addr) >> 17) & 0x1f00), 0xD000F8); \ +} while (0) + +#endif /* CX18_DRIVER_H */ diff --git a/drivers/media/video/cx18/cx18-dvb.c b/drivers/media/video/cx18/cx18-dvb.c new file mode 100644 index 00000000000..65efe69d939 --- /dev/null +++ b/drivers/media/video/cx18/cx18-dvb.c @@ -0,0 +1,288 @@ +/* + * cx18 functions for DVB support + * + * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "cx18-version.h" +#include "cx18-dvb.h" +#include "cx18-streams.h" +#include "cx18-cards.h" +#include "s5h1409.h" + +/* Wait until the MXL500X driver is merged */ +#ifdef HAVE_MXL500X +#include "mxl500x.h" +#endif + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +#define CX18_REG_DMUX_NUM_PORT_0_CONTROL 0xd5a000 + +#ifdef HAVE_MXL500X +static struct mxl500x_config hauppauge_hvr1600_tuner = { + .delsys = MXL500x_MODE_ATSC, + .octf = MXL500x_OCTF_CH, + .xtal_freq = 16000000, + .iflo_freq = 5380000, + .ref_freq = 322800000, + .rssi_ena = MXL_RSSI_ENABLE, + .addr = 0xC6 >> 1, +}; + +static struct s5h1409_config hauppauge_hvr1600_config = { + .demod_address = 0x32 >> 1, + .output_mode = S5H1409_SERIAL_OUTPUT, + .gpio = S5H1409_GPIO_ON, + .qam_if = 44000, + .inversion = S5H1409_INVERSION_OFF, + .status_mode = S5H1409_DEMODLOCKING, + .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK + +}; +#endif + +static int dvb_register(struct cx18_stream *stream); + +/* Kernel DVB framework calls this when the feed needs to start. + * The CX18 framework should enable the transport DMA handling + * and queue processing. + */ +static int cx18_dvb_start_feed(struct dvb_demux_feed *feed) +{ + struct dvb_demux *demux = feed->demux; + struct cx18_stream *stream = (struct cx18_stream *) demux->priv; + struct cx18 *cx = stream->cx; + int ret = -EINVAL; + u32 v; + + CX18_DEBUG_INFO("Start feed: pid = 0x%x index = %d\n", + feed->pid, feed->index); + switch (cx->card->type) { + case CX18_CARD_HVR_1600_ESMT: + case CX18_CARD_HVR_1600_SAMSUNG: + v = read_reg(CX18_REG_DMUX_NUM_PORT_0_CONTROL); + v |= 0x00400000; /* Serial Mode */ + v |= 0x00002000; /* Data Length - Byte */ + v |= 0x00010000; /* Error - Polarity */ + v |= 0x00020000; /* Error - Passthru */ + v |= 0x000c0000; /* Error - Ignore */ + write_reg(v, CX18_REG_DMUX_NUM_PORT_0_CONTROL); + break; + + default: + /* Assumption - Parallel transport - Signalling + * undefined or default. + */ + break; + } + + if (!demux->dmx.frontend) + return -EINVAL; + + if (stream) { + mutex_lock(&stream->dvb.feedlock); + if (stream->dvb.feeding++ == 0) { + CX18_DEBUG_INFO("Starting Transport DMA\n"); + ret = cx18_start_v4l2_encode_stream(stream); + } else + ret = 0; + mutex_unlock(&stream->dvb.feedlock); + } + + return ret; +} + +/* Kernel DVB framework calls this when the feed needs to stop. */ +static int cx18_dvb_stop_feed(struct dvb_demux_feed *feed) +{ + struct dvb_demux *demux = feed->demux; + struct cx18_stream *stream = (struct cx18_stream *)demux->priv; + struct cx18 *cx = stream->cx; + int ret = -EINVAL; + + CX18_DEBUG_INFO("Stop feed: pid = 0x%x index = %d\n", + feed->pid, feed->index); + + if (stream) { + mutex_lock(&stream->dvb.feedlock); + if (--stream->dvb.feeding == 0) { + CX18_DEBUG_INFO("Stopping Transport DMA\n"); + ret = cx18_stop_v4l2_encode_stream(stream, 0); + } else + ret = 0; + mutex_unlock(&stream->dvb.feedlock); + } + + return ret; +} + +int cx18_dvb_register(struct cx18_stream *stream) +{ + struct cx18 *cx = stream->cx; + struct cx18_dvb *dvb = &stream->dvb; + struct dvb_adapter *dvb_adapter; + struct dvb_demux *dvbdemux; + struct dmx_demux *dmx; + int ret; + + if (!dvb) + return -EINVAL; + + ret = dvb_register_adapter(&dvb->dvb_adapter, + CX18_DRIVER_NAME, + THIS_MODULE, &cx->dev->dev, adapter_nr); + if (ret < 0) + goto err_out; + + dvb_adapter = &dvb->dvb_adapter; + + dvbdemux = &dvb->demux; + + dvbdemux->priv = (void *)stream; + + dvbdemux->filternum = 256; + dvbdemux->feednum = 256; + dvbdemux->start_feed = cx18_dvb_start_feed; + dvbdemux->stop_feed = cx18_dvb_stop_feed; + dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | + DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING); + ret = dvb_dmx_init(dvbdemux); + if (ret < 0) + goto err_dvb_unregister_adapter; + + dmx = &dvbdemux->dmx; + + dvb->hw_frontend.source = DMX_FRONTEND_0; + dvb->mem_frontend.source = DMX_MEMORY_FE; + dvb->dmxdev.filternum = 256; + dvb->dmxdev.demux = dmx; + + ret = dvb_dmxdev_init(&dvb->dmxdev, dvb_adapter); + if (ret < 0) + goto err_dvb_dmx_release; + + ret = dmx->add_frontend(dmx, &dvb->hw_frontend); + if (ret < 0) + goto err_dvb_dmxdev_release; + + ret = dmx->add_frontend(dmx, &dvb->mem_frontend); + if (ret < 0) + goto err_remove_hw_frontend; + + ret = dmx->connect_frontend(dmx, &dvb->hw_frontend); + if (ret < 0) + goto err_remove_mem_frontend; + + ret = dvb_register(stream); + if (ret < 0) + goto err_disconnect_frontend; + + dvb_net_init(dvb_adapter, &dvb->dvbnet, dmx); + + CX18_INFO("DVB Frontend registered\n"); + mutex_init(&dvb->feedlock); + dvb->enabled = 1; + return ret; + +err_disconnect_frontend: + dmx->disconnect_frontend(dmx); +err_remove_mem_frontend: + dmx->remove_frontend(dmx, &dvb->mem_frontend); +err_remove_hw_frontend: + dmx->remove_frontend(dmx, &dvb->hw_frontend); +err_dvb_dmxdev_release: + dvb_dmxdev_release(&dvb->dmxdev); +err_dvb_dmx_release: + dvb_dmx_release(dvbdemux); +err_dvb_unregister_adapter: + dvb_unregister_adapter(dvb_adapter); +err_out: + return ret; +} + +void cx18_dvb_unregister(struct cx18_stream *stream) +{ + struct cx18 *cx = stream->cx; + struct cx18_dvb *dvb = &stream->dvb; + struct dvb_adapter *dvb_adapter; + struct dvb_demux *dvbdemux; + struct dmx_demux *dmx; + + CX18_INFO("unregister DVB\n"); + + dvb_adapter = &dvb->dvb_adapter; + dvbdemux = &dvb->demux; + dmx = &dvbdemux->dmx; + + dmx->close(dmx); + dvb_net_release(&dvb->dvbnet); + dmx->remove_frontend(dmx, &dvb->mem_frontend); + dmx->remove_frontend(dmx, &dvb->hw_frontend); + dvb_dmxdev_release(&dvb->dmxdev); + dvb_dmx_release(dvbdemux); + dvb_unregister_frontend(dvb->fe); + dvb_frontend_detach(dvb->fe); + dvb_unregister_adapter(dvb_adapter); +} + +/* All the DVB attach calls go here, this function get's modified + * for each new card. No other function in this file needs + * to change. + */ +static int dvb_register(struct cx18_stream *stream) +{ + struct cx18_dvb *dvb = &stream->dvb; + struct cx18 *cx = stream->cx; + int ret = 0; + + switch (cx->card->type) { +/* Wait until the MXL500X driver is merged */ +#ifdef HAVE_MXL500X + case CX18_CARD_HVR_1600_ESMT: + case CX18_CARD_HVR_1600_SAMSUNG: + dvb->fe = dvb_attach(s5h1409_attach, + &hauppauge_hvr1600_config, + &cx->i2c_adap[0]); + if (dvb->fe != NULL) { + dvb_attach(mxl500x_attach, dvb->fe, + &hauppauge_hvr1600_tuner, + &cx->i2c_adap[0]); + ret = 0; + } + break; +#endif + default: + /* No Digital Tv Support */ + break; + } + + if (dvb->fe == NULL) { + CX18_ERR("frontend initialization failed\n"); + return -1; + } + + ret = dvb_register_frontend(&dvb->dvb_adapter, dvb->fe); + if (ret < 0) { + if (dvb->fe->ops.release) + dvb->fe->ops.release(dvb->fe); + return ret; + } + + return ret; +} diff --git a/drivers/media/video/cx18/cx18-dvb.h b/drivers/media/video/cx18/cx18-dvb.h new file mode 100644 index 00000000000..d6a6ccda79a --- /dev/null +++ b/drivers/media/video/cx18/cx18-dvb.h @@ -0,0 +1,25 @@ +/* + * cx18 functions for DVB support + * + * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "cx18-driver.h" + +int cx18_dvb_register(struct cx18_stream *stream); +void cx18_dvb_unregister(struct cx18_stream *stream); diff --git a/drivers/media/video/cx18/cx18-fileops.c b/drivers/media/video/cx18/cx18-fileops.c new file mode 100644 index 00000000000..69303065a29 --- /dev/null +++ b/drivers/media/video/cx18/cx18-fileops.c @@ -0,0 +1,711 @@ +/* + * cx18 file operation functions + * + * Derived from ivtv-fileops.c + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 "cx18-driver.h" +#include "cx18-fileops.h" +#include "cx18-i2c.h" +#include "cx18-queue.h" +#include "cx18-vbi.h" +#include "cx18-audio.h" +#include "cx18-mailbox.h" +#include "cx18-scb.h" +#include "cx18-streams.h" +#include "cx18-controls.h" +#include "cx18-ioctl.h" +#include "cx18-cards.h" + +/* This function tries to claim the stream for a specific file descriptor. + If no one else is using this stream then the stream is claimed and + associated VBI streams are also automatically claimed. + Possible error returns: -EBUSY if someone else has claimed + the stream or 0 on success. */ +int cx18_claim_stream(struct cx18_open_id *id, int type) +{ + struct cx18 *cx = id->cx; + struct cx18_stream *s = &cx->streams[type]; + struct cx18_stream *s_vbi; + int vbi_type; + + if (test_and_set_bit(CX18_F_S_CLAIMED, &s->s_flags)) { + /* someone already claimed this stream */ + if (s->id == id->open_id) { + /* yes, this file descriptor did. So that's OK. */ + return 0; + } + if (s->id == -1 && type == CX18_ENC_STREAM_TYPE_VBI) { + /* VBI is handled already internally, now also assign + the file descriptor to this stream for external + reading of the stream. */ + s->id = id->open_id; + CX18_DEBUG_INFO("Start Read VBI\n"); + return 0; + } + /* someone else is using this stream already */ + CX18_DEBUG_INFO("Stream %d is busy\n", type); + return -EBUSY; + } + s->id = id->open_id; + + /* CX18_DEC_STREAM_TYPE_MPG needs to claim CX18_DEC_STREAM_TYPE_VBI, + CX18_ENC_STREAM_TYPE_MPG needs to claim CX18_ENC_STREAM_TYPE_VBI + (provided VBI insertion is on and sliced VBI is selected), for all + other streams we're done */ + if (type == CX18_ENC_STREAM_TYPE_MPG && + cx->vbi.insert_mpeg && cx->vbi.sliced_in->service_set) { + vbi_type = CX18_ENC_STREAM_TYPE_VBI; + } else { + return 0; + } + s_vbi = &cx->streams[vbi_type]; + + set_bit(CX18_F_S_CLAIMED, &s_vbi->s_flags); + + /* mark that it is used internally */ + set_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags); + return 0; +} + +/* This function releases a previously claimed stream. It will take into + account associated VBI streams. */ +void cx18_release_stream(struct cx18_stream *s) +{ + struct cx18 *cx = s->cx; + struct cx18_stream *s_vbi; + + s->id = -1; + if (s->type == CX18_ENC_STREAM_TYPE_VBI && + test_bit(CX18_F_S_INTERNAL_USE, &s->s_flags)) { + /* this stream is still in use internally */ + return; + } + if (!test_and_clear_bit(CX18_F_S_CLAIMED, &s->s_flags)) { + CX18_DEBUG_WARN("Release stream %s not in use!\n", s->name); + return; + } + + cx18_flush_queues(s); + + /* CX18_ENC_STREAM_TYPE_MPG needs to release CX18_ENC_STREAM_TYPE_VBI, + for all other streams we're done */ + if (s->type == CX18_ENC_STREAM_TYPE_MPG) + s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI]; + else + return; + + /* clear internal use flag */ + if (!test_and_clear_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags)) { + /* was already cleared */ + return; + } + if (s_vbi->id != -1) { + /* VBI stream still claimed by a file descriptor */ + return; + } + clear_bit(CX18_F_S_CLAIMED, &s_vbi->s_flags); + cx18_flush_queues(s_vbi); +} + +static void cx18_dualwatch(struct cx18 *cx) +{ + struct v4l2_tuner vt; + u16 new_bitmap; + u16 new_stereo_mode; + const u16 stereo_mask = 0x0300; + const u16 dual = 0x0200; + + new_stereo_mode = cx->params.audio_properties & stereo_mask; + memset(&vt, 0, sizeof(vt)); + cx18_call_i2c_clients(cx, VIDIOC_G_TUNER, &vt); + if (vt.audmode == V4L2_TUNER_MODE_LANG1_LANG2 && + (vt.rxsubchans & V4L2_TUNER_SUB_LANG2)) + new_stereo_mode = dual; + + if (new_stereo_mode == cx->dualwatch_stereo_mode) + return; + + new_bitmap = new_stereo_mode | (cx->params.audio_properties & ~stereo_mask); + + CX18_DEBUG_INFO("dualwatch: change stereo flag from 0x%x to 0x%x. new audio_bitmask=0x%ux\n", + cx->dualwatch_stereo_mode, new_stereo_mode, new_bitmap); + + if (cx18_vapi(cx, CX18_CPU_SET_AUDIO_PARAMETERS, 2, + cx18_find_handle(cx), new_bitmap) == 0) { + cx->dualwatch_stereo_mode = new_stereo_mode; + return; + } + CX18_DEBUG_INFO("dualwatch: changing stereo flag failed\n"); +} + + +static struct cx18_buffer *cx18_get_buffer(struct cx18_stream *s, int non_block, int *err) +{ + struct cx18 *cx = s->cx; + struct cx18_stream *s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI]; + struct cx18_buffer *buf; + DEFINE_WAIT(wait); + + *err = 0; + while (1) { + if (s->type == CX18_ENC_STREAM_TYPE_MPG) { + + if (time_after(jiffies, cx->dualwatch_jiffies + msecs_to_jiffies(1000))) { + cx->dualwatch_jiffies = jiffies; + cx18_dualwatch(cx); + } + if (test_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags) && + !test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) { + while ((buf = cx18_dequeue(s_vbi, &s_vbi->q_full))) { + /* byteswap and process VBI data */ +/* cx18_process_vbi_data(cx, buf, s_vbi->dma_pts, s_vbi->type); */ + cx18_enqueue(s_vbi, buf, &s_vbi->q_free); + } + } + buf = &cx->vbi.sliced_mpeg_buf; + if (buf->readpos != buf->bytesused) + return buf; + } + + /* do we have leftover data? */ + buf = cx18_dequeue(s, &s->q_io); + if (buf) + return buf; + + /* do we have new data? */ + buf = cx18_dequeue(s, &s->q_full); + if (buf) { + if (!test_and_clear_bit(CX18_F_B_NEED_BUF_SWAP, + &buf->b_flags)) + return buf; + if (s->type == CX18_ENC_STREAM_TYPE_MPG) + /* byteswap MPG data */ + cx18_buf_swap(buf); + else { + /* byteswap and process VBI data */ + cx18_process_vbi_data(cx, buf, + s->dma_pts, s->type); + } + return buf; + } + + /* return if end of stream */ + if (!test_bit(CX18_F_S_STREAMING, &s->s_flags)) { + CX18_DEBUG_INFO("EOS %s\n", s->name); + return NULL; + } + + /* return if file was opened with O_NONBLOCK */ + if (non_block) { + *err = -EAGAIN; + return NULL; + } + + /* wait for more data to arrive */ + prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE); + /* New buffers might have become available before we were added + to the waitqueue */ + if (!s->q_full.buffers) + schedule(); + finish_wait(&s->waitq, &wait); + if (signal_pending(current)) { + /* return if a signal was received */ + CX18_DEBUG_INFO("User stopped %s\n", s->name); + *err = -EINTR; + return NULL; + } + } +} + +static void cx18_setup_sliced_vbi_buf(struct cx18 *cx) +{ + int idx = cx->vbi.inserted_frame % CX18_VBI_FRAMES; + + cx->vbi.sliced_mpeg_buf.buf = cx->vbi.sliced_mpeg_data[idx]; + cx->vbi.sliced_mpeg_buf.bytesused = cx->vbi.sliced_mpeg_size[idx]; + cx->vbi.sliced_mpeg_buf.readpos = 0; +} + +static size_t cx18_copy_buf_to_user(struct cx18_stream *s, + struct cx18_buffer *buf, char __user *ubuf, size_t ucount) +{ + struct cx18 *cx = s->cx; + size_t len = buf->bytesused - buf->readpos; + + if (len > ucount) + len = ucount; + if (cx->vbi.insert_mpeg && s->type == CX18_ENC_STREAM_TYPE_MPG && + cx->vbi.sliced_in->service_set && buf != &cx->vbi.sliced_mpeg_buf) { + const char *start = buf->buf + buf->readpos; + const char *p = start + 1; + const u8 *q; + u8 ch = cx->search_pack_header ? 0xba : 0xe0; + int stuffing, i; + + while (start + len > p) { + q = memchr(p, 0, start + len - p); + if (q == NULL) + break; + p = q + 1; + if ((char *)q + 15 >= buf->buf + buf->bytesused || + q[1] != 0 || q[2] != 1 || q[3] != ch) + continue; + if (!cx->search_pack_header) { + if ((q[6] & 0xc0) != 0x80) + continue; + if (((q[7] & 0xc0) == 0x80 && + (q[9] & 0xf0) == 0x20) || + ((q[7] & 0xc0) == 0xc0 && + (q[9] & 0xf0) == 0x30)) { + ch = 0xba; + cx->search_pack_header = 1; + p = q + 9; + } + continue; + } + stuffing = q[13] & 7; + /* all stuffing bytes must be 0xff */ + for (i = 0; i < stuffing; i++) + if (q[14 + i] != 0xff) + break; + if (i == stuffing && + (q[4] & 0xc4) == 0x44 && + (q[12] & 3) == 3 && + q[14 + stuffing] == 0 && + q[15 + stuffing] == 0 && + q[16 + stuffing] == 1) { + cx->search_pack_header = 0; + len = (char *)q - start; + cx18_setup_sliced_vbi_buf(cx); + break; + } + } + } + if (copy_to_user(ubuf, (u8 *)buf->buf + buf->readpos, len)) { + CX18_DEBUG_WARN("copy %zd bytes to user failed for %s\n", + len, s->name); + return -EFAULT; + } + buf->readpos += len; + if (s->type == CX18_ENC_STREAM_TYPE_MPG && + buf != &cx->vbi.sliced_mpeg_buf) + cx->mpg_data_received += len; + return len; +} + +static ssize_t cx18_read(struct cx18_stream *s, char __user *ubuf, + size_t tot_count, int non_block) +{ + struct cx18 *cx = s->cx; + size_t tot_written = 0; + int single_frame = 0; + + if (atomic_read(&cx->capturing) == 0 && s->id == -1) { + /* shouldn't happen */ + CX18_DEBUG_WARN("Stream %s not initialized before read\n", + s->name); + return -EIO; + } + + /* Each VBI buffer is one frame, the v4l2 API says that for VBI the + frames should arrive one-by-one, so make sure we never output more + than one VBI frame at a time */ + if (s->type == CX18_ENC_STREAM_TYPE_VBI && + cx->vbi.sliced_in->service_set) + single_frame = 1; + + for (;;) { + struct cx18_buffer *buf; + int rc; + + buf = cx18_get_buffer(s, non_block, &rc); + /* if there is no data available... */ + if (buf == NULL) { + /* if we got data, then return that regardless */ + if (tot_written) + break; + /* EOS condition */ + if (rc == 0) { + clear_bit(CX18_F_S_STREAMOFF, &s->s_flags); + clear_bit(CX18_F_S_APPL_IO, &s->s_flags); + cx18_release_stream(s); + } + /* set errno */ + return rc; + } + + rc = cx18_copy_buf_to_user(s, buf, ubuf + tot_written, + tot_count - tot_written); + + if (buf != &cx->vbi.sliced_mpeg_buf) { + if (buf->readpos == buf->bytesused) { + cx18_buf_sync_for_device(s, buf); + cx18_enqueue(s, buf, &s->q_free); + cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, + s->handle, + (void *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem, + 1, buf->id, s->buf_size); + } else + cx18_enqueue(s, buf, &s->q_io); + } else if (buf->readpos == buf->bytesused) { + int idx = cx->vbi.inserted_frame % CX18_VBI_FRAMES; + + cx->vbi.sliced_mpeg_size[idx] = 0; + cx->vbi.inserted_frame++; + cx->vbi_data_inserted += buf->bytesused; + } + if (rc < 0) + return rc; + tot_written += rc; + + if (tot_written == tot_count || single_frame) + break; + } + return tot_written; +} + +static ssize_t cx18_read_pos(struct cx18_stream *s, char __user *ubuf, + size_t count, loff_t *pos, int non_block) +{ + ssize_t rc = count ? cx18_read(s, ubuf, count, non_block) : 0; + struct cx18 *cx = s->cx; + + CX18_DEBUG_HI_FILE("read %zd from %s, got %zd\n", count, s->name, rc); + if (rc > 0) + pos += rc; + return rc; +} + +int cx18_start_capture(struct cx18_open_id *id) +{ + struct cx18 *cx = id->cx; + struct cx18_stream *s = &cx->streams[id->type]; + struct cx18_stream *s_vbi; + + if (s->type == CX18_ENC_STREAM_TYPE_RAD) { + /* you cannot read from these stream types. */ + return -EPERM; + } + + /* Try to claim this stream. */ + if (cx18_claim_stream(id, s->type)) + return -EBUSY; + + /* If capture is already in progress, then we also have to + do nothing extra. */ + if (test_bit(CX18_F_S_STREAMOFF, &s->s_flags) || + test_and_set_bit(CX18_F_S_STREAMING, &s->s_flags)) { + set_bit(CX18_F_S_APPL_IO, &s->s_flags); + return 0; + } + + /* Start VBI capture if required */ + s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI]; + if (s->type == CX18_ENC_STREAM_TYPE_MPG && + test_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags) && + !test_and_set_bit(CX18_F_S_STREAMING, &s_vbi->s_flags)) { + /* Note: the CX18_ENC_STREAM_TYPE_VBI is claimed + automatically when the MPG stream is claimed. + We only need to start the VBI capturing. */ + if (cx18_start_v4l2_encode_stream(s_vbi)) { + CX18_DEBUG_WARN("VBI capture start failed\n"); + + /* Failure, clean up and return an error */ + clear_bit(CX18_F_S_STREAMING, &s_vbi->s_flags); + clear_bit(CX18_F_S_STREAMING, &s->s_flags); + /* also releases the associated VBI stream */ + cx18_release_stream(s); + return -EIO; + } + CX18_DEBUG_INFO("VBI insertion started\n"); + } + + /* Tell the card to start capturing */ + if (!cx18_start_v4l2_encode_stream(s)) { + /* We're done */ + set_bit(CX18_F_S_APPL_IO, &s->s_flags); + /* Resume a possibly paused encoder */ + if (test_and_clear_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags)) + cx18_vapi(cx, CX18_CPU_CAPTURE_PAUSE, 1, s->handle); + return 0; + } + + /* failure, clean up */ + CX18_DEBUG_WARN("Failed to start capturing for stream %s\n", s->name); + + /* Note: the CX18_ENC_STREAM_TYPE_VBI is released + automatically when the MPG stream is released. + We only need to stop the VBI capturing. */ + if (s->type == CX18_ENC_STREAM_TYPE_MPG && + test_bit(CX18_F_S_STREAMING, &s_vbi->s_flags)) { + cx18_stop_v4l2_encode_stream(s_vbi, 0); + clear_bit(CX18_F_S_STREAMING, &s_vbi->s_flags); + } + clear_bit(CX18_F_S_STREAMING, &s->s_flags); + cx18_release_stream(s); + return -EIO; +} + +ssize_t cx18_v4l2_read(struct file *filp, char __user *buf, size_t count, + loff_t *pos) +{ + struct cx18_open_id *id = filp->private_data; + struct cx18 *cx = id->cx; + struct cx18_stream *s = &cx->streams[id->type]; + int rc; + + CX18_DEBUG_HI_FILE("read %zd bytes from %s\n", count, s->name); + + mutex_lock(&cx->serialize_lock); + rc = cx18_start_capture(id); + mutex_unlock(&cx->serialize_lock); + if (rc) + return rc; + return cx18_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK); +} + +unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait) +{ + struct cx18_open_id *id = filp->private_data; + struct cx18 *cx = id->cx; + struct cx18_stream *s = &cx->streams[id->type]; + int eof = test_bit(CX18_F_S_STREAMOFF, &s->s_flags); + + /* Start a capture if there is none */ + if (!eof && !test_bit(CX18_F_S_STREAMING, &s->s_flags)) { + int rc; + + mutex_lock(&cx->serialize_lock); + rc = cx18_start_capture(id); + mutex_unlock(&cx->serialize_lock); + if (rc) { + CX18_DEBUG_INFO("Could not start capture for %s (%d)\n", + s->name, rc); + return POLLERR; + } + CX18_DEBUG_FILE("Encoder poll started capture\n"); + } + + /* add stream's waitq to the poll list */ + CX18_DEBUG_HI_FILE("Encoder poll\n"); + poll_wait(filp, &s->waitq, wait); + + if (s->q_full.length || s->q_io.length) + return POLLIN | POLLRDNORM; + if (eof) + return POLLHUP; + return 0; +} + +void cx18_stop_capture(struct cx18_open_id *id, int gop_end) +{ + struct cx18 *cx = id->cx; + struct cx18_stream *s = &cx->streams[id->type]; + + CX18_DEBUG_IOCTL("close() of %s\n", s->name); + + /* 'Unclaim' this stream */ + + /* Stop capturing */ + if (test_bit(CX18_F_S_STREAMING, &s->s_flags)) { + struct cx18_stream *s_vbi = + &cx->streams[CX18_ENC_STREAM_TYPE_VBI]; + + CX18_DEBUG_INFO("close stopping capture\n"); + /* Special case: a running VBI capture for VBI insertion + in the mpeg stream. Need to stop that too. */ + if (id->type == CX18_ENC_STREAM_TYPE_MPG && + test_bit(CX18_F_S_STREAMING, &s_vbi->s_flags) && + !test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) { + CX18_DEBUG_INFO("close stopping embedded VBI capture\n"); + cx18_stop_v4l2_encode_stream(s_vbi, 0); + } + if (id->type == CX18_ENC_STREAM_TYPE_VBI && + test_bit(CX18_F_S_INTERNAL_USE, &s->s_flags)) + /* Also used internally, don't stop capturing */ + s->id = -1; + else + cx18_stop_v4l2_encode_stream(s, gop_end); + } + if (!gop_end) { + clear_bit(CX18_F_S_APPL_IO, &s->s_flags); + clear_bit(CX18_F_S_STREAMOFF, &s->s_flags); + cx18_release_stream(s); + } +} + +int cx18_v4l2_close(struct inode *inode, struct file *filp) +{ + struct cx18_open_id *id = filp->private_data; + struct cx18 *cx = id->cx; + struct cx18_stream *s = &cx->streams[id->type]; + + CX18_DEBUG_IOCTL("close() of %s\n", s->name); + + v4l2_prio_close(&cx->prio, &id->prio); + + /* Easy case first: this stream was never claimed by us */ + if (s->id != id->open_id) { + kfree(id); + return 0; + } + + /* 'Unclaim' this stream */ + + /* Stop radio */ + mutex_lock(&cx->serialize_lock); + if (id->type == CX18_ENC_STREAM_TYPE_RAD) { + /* Closing radio device, return to TV mode */ + cx18_mute(cx); + /* Mark that the radio is no longer in use */ + clear_bit(CX18_F_I_RADIO_USER, &cx->i_flags); + /* Switch tuner to TV */ + cx18_call_i2c_clients(cx, VIDIOC_S_STD, &cx->std); + /* Select correct audio input (i.e. TV tuner or Line in) */ + cx18_audio_set_io(cx); + if (atomic_read(&cx->capturing) > 0) { + /* Undo video mute */ + cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle, + cx->params.video_mute | + (cx->params.video_mute_yuv << 8)); + } + /* Done! Unmute and continue. */ + cx18_unmute(cx); + cx18_release_stream(s); + } else { + cx18_stop_capture(id, 0); + } + kfree(id); + mutex_unlock(&cx->serialize_lock); + return 0; +} + +static int cx18_serialized_open(struct cx18_stream *s, struct file *filp) +{ + struct cx18 *cx = s->cx; + struct cx18_open_id *item; + + CX18_DEBUG_FILE("open %s\n", s->name); + + /* Allocate memory */ + item = kmalloc(sizeof(struct cx18_open_id), GFP_KERNEL); + if (NULL == item) { + CX18_DEBUG_WARN("nomem on v4l2 open\n"); + return -ENOMEM; + } + item->cx = cx; + item->type = s->type; + v4l2_prio_open(&cx->prio, &item->prio); + + item->open_id = cx->open_id++; + filp->private_data = item; + + if (item->type == CX18_ENC_STREAM_TYPE_RAD) { + /* Try to claim this stream */ + if (cx18_claim_stream(item, item->type)) { + /* No, it's already in use */ + kfree(item); + return -EBUSY; + } + + if (!test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) { + if (atomic_read(&cx->capturing) > 0) { + /* switching to radio while capture is + in progress is not polite */ + cx18_release_stream(s); + kfree(item); + return -EBUSY; + } + } + + /* Mark that the radio is being used. */ + set_bit(CX18_F_I_RADIO_USER, &cx->i_flags); + /* We have the radio */ + cx18_mute(cx); + /* Switch tuner to radio */ + cx18_call_i2c_clients(cx, AUDC_SET_RADIO, NULL); + /* Select the correct audio input (i.e. radio tuner) */ + cx18_audio_set_io(cx); + /* Done! Unmute and continue. */ + cx18_unmute(cx); + } + return 0; +} + +int cx18_v4l2_open(struct inode *inode, struct file *filp) +{ + int res, x, y = 0; + struct cx18 *cx = NULL; + struct cx18_stream *s = NULL; + int minor = iminor(inode); + + /* Find which card this open was on */ + spin_lock(&cx18_cards_lock); + for (x = 0; cx == NULL && x < cx18_cards_active; x++) { + /* find out which stream this open was on */ + for (y = 0; y < CX18_MAX_STREAMS; y++) { + s = &cx18_cards[x]->streams[y]; + if (s->v4l2dev && s->v4l2dev->minor == minor) { + cx = cx18_cards[x]; + break; + } + } + } + spin_unlock(&cx18_cards_lock); + + if (cx == NULL) { + /* Couldn't find a device registered + on that minor, shouldn't happen! */ + printk(KERN_WARNING "No cx18 device found on minor %d\n", + minor); + return -ENXIO; + } + + mutex_lock(&cx->serialize_lock); + if (cx18_init_on_first_open(cx)) { + CX18_ERR("Failed to initialize on minor %d\n", minor); + mutex_unlock(&cx->serialize_lock); + return -ENXIO; + } + res = cx18_serialized_open(s, filp); + mutex_unlock(&cx->serialize_lock); + return res; +} + +void cx18_mute(struct cx18 *cx) +{ + if (atomic_read(&cx->capturing)) + cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2, + cx18_find_handle(cx), 1); + CX18_DEBUG_INFO("Mute\n"); +} + +void cx18_unmute(struct cx18 *cx) +{ + if (atomic_read(&cx->capturing)) { + cx18_msleep_timeout(100, 0); + cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 2, + cx18_find_handle(cx), 12); + cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2, + cx18_find_handle(cx), 0); + } + CX18_DEBUG_INFO("Unmute\n"); +} diff --git a/drivers/media/video/cx18/cx18-fileops.h b/drivers/media/video/cx18/cx18-fileops.h new file mode 100644 index 00000000000..16cdafbd24c --- /dev/null +++ b/drivers/media/video/cx18/cx18-fileops.h @@ -0,0 +1,45 @@ +/* + * cx18 file operation functions + * + * Derived from ivtv-fileops.h + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 + */ + +/* Testing/Debugging */ +int cx18_v4l2_open(struct inode *inode, struct file *filp); +ssize_t cx18_v4l2_read(struct file *filp, char __user *buf, size_t count, + loff_t *pos); +ssize_t cx18_v4l2_write(struct file *filp, const char __user *buf, size_t count, + loff_t *pos); +int cx18_v4l2_close(struct inode *inode, struct file *filp); +unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait); +int cx18_start_capture(struct cx18_open_id *id); +void cx18_stop_capture(struct cx18_open_id *id, int gop_end); +void cx18_mute(struct cx18 *cx); +void cx18_unmute(struct cx18 *cx); + +/* Utilities */ + +/* Try to claim a stream for the filehandle. Return 0 on success, + -EBUSY if stream already claimed. Once a stream is claimed, it + remains claimed until the associated filehandle is closed. */ +int cx18_claim_stream(struct cx18_open_id *id, int type); + +/* Release a previously claimed stream. */ +void cx18_release_stream(struct cx18_stream *s); diff --git a/drivers/media/video/cx18/cx18-firmware.c b/drivers/media/video/cx18/cx18-firmware.c new file mode 100644 index 00000000000..2694ce35063 --- /dev/null +++ b/drivers/media/video/cx18/cx18-firmware.c @@ -0,0 +1,373 @@ +/* + * cx18 firmware functions + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 "cx18-driver.h" +#include "cx18-scb.h" +#include "cx18-irq.h" +#include "cx18-firmware.h" +#include "cx18-cards.h" +#include <linux/firmware.h> + +#define CX18_PROC_SOFT_RESET 0xc70010 +#define CX18_DDR_SOFT_RESET 0xc70014 +#define CX18_CLOCK_SELECT1 0xc71000 +#define CX18_CLOCK_SELECT2 0xc71004 +#define CX18_HALF_CLOCK_SELECT1 0xc71008 +#define CX18_HALF_CLOCK_SELECT2 0xc7100C +#define CX18_CLOCK_POLARITY1 0xc71010 +#define CX18_CLOCK_POLARITY2 0xc71014 +#define CX18_ADD_DELAY_ENABLE1 0xc71018 +#define CX18_ADD_DELAY_ENABLE2 0xc7101C +#define CX18_CLOCK_ENABLE1 0xc71020 +#define CX18_CLOCK_ENABLE2 0xc71024 + +#define CX18_REG_BUS_TIMEOUT_EN 0xc72024 + +#define CX18_AUDIO_ENABLE 0xc72014 +#define CX18_REG_BUS_TIMEOUT_EN 0xc72024 + +#define CX18_FAST_CLOCK_PLL_INT 0xc78000 +#define CX18_FAST_CLOCK_PLL_FRAC 0xc78004 +#define CX18_FAST_CLOCK_PLL_POST 0xc78008 +#define CX18_FAST_CLOCK_PLL_PRESCALE 0xc7800C +#define CX18_FAST_CLOCK_PLL_ADJUST_BANDWIDTH 0xc78010 + +#define CX18_SLOW_CLOCK_PLL_INT 0xc78014 +#define CX18_SLOW_CLOCK_PLL_FRAC 0xc78018 +#define CX18_SLOW_CLOCK_PLL_POST 0xc7801C +#define CX18_MPEG_CLOCK_PLL_INT 0xc78040 +#define CX18_MPEG_CLOCK_PLL_FRAC 0xc78044 +#define CX18_MPEG_CLOCK_PLL_POST 0xc78048 +#define CX18_PLL_POWER_DOWN 0xc78088 +#define CX18_SW1_INT_STATUS 0xc73104 +#define CX18_SW1_INT_ENABLE_PCI 0xc7311C +#define CX18_SW2_INT_SET 0xc73140 +#define CX18_SW2_INT_STATUS 0xc73144 +#define CX18_ADEC_CONTROL 0xc78120 + +#define CX18_DDR_REQUEST_ENABLE 0xc80000 +#define CX18_DDR_CHIP_CONFIG 0xc80004 +#define CX18_DDR_REFRESH 0xc80008 +#define CX18_DDR_TIMING1 0xc8000C +#define CX18_DDR_TIMING2 0xc80010 +#define CX18_DDR_POWER_REG 0xc8001C + +#define CX18_DDR_TUNE_LANE 0xc80048 +#define CX18_DDR_INITIAL_EMRS 0xc80054 +#define CX18_DDR_MB_PER_ROW_7 0xc8009C +#define CX18_DDR_BASE_63_ADDR 0xc804FC + +#define CX18_WMB_CLIENT02 0xc90108 +#define CX18_WMB_CLIENT05 0xc90114 +#define CX18_WMB_CLIENT06 0xc90118 +#define CX18_WMB_CLIENT07 0xc9011C +#define CX18_WMB_CLIENT08 0xc90120 +#define CX18_WMB_CLIENT09 0xc90124 +#define CX18_WMB_CLIENT10 0xc90128 +#define CX18_WMB_CLIENT11 0xc9012C +#define CX18_WMB_CLIENT12 0xc90130 +#define CX18_WMB_CLIENT13 0xc90134 +#define CX18_WMB_CLIENT14 0xc90138 + +#define CX18_DSP0_INTERRUPT_MASK 0xd0004C + +/* Encoder/decoder firmware sizes */ +#define CX18_FW_CPU_SIZE (174716) +#define CX18_FW_APU_SIZE (141200) + +#define APU_ROM_SYNC1 0x6D676553 /* "mgeS" */ +#define APU_ROM_SYNC2 0x72646548 /* "rdeH" */ + +struct cx18_apu_rom_seghdr { + u32 sync1; + u32 sync2; + u32 addr; + u32 size; +}; + +static int load_cpu_fw_direct(const char *fn, u8 __iomem *mem, struct cx18 *cx, long size) +{ + const struct firmware *fw = NULL; + int retries = 3; + int i, j; + u32 __iomem *dst = (u32 __iomem *)mem; + const u32 *src; + +retry: + if (!retries || request_firmware(&fw, fn, &cx->dev->dev)) { + CX18_ERR("Unable to open firmware %s (must be %ld bytes)\n", + fn, size); + CX18_ERR("Did you put the firmware in the hotplug firmware directory?\n"); + return -ENOMEM; + } + + src = (const u32 *)fw->data; + + if (fw->size != size) { + /* Due to race conditions in firmware loading (esp. with + udev <0.95) the wrong file was sometimes loaded. So we check + filesizes to see if at least the right-sized file was + loaded. If not, then we retry. */ + CX18_INFO("retry: file loaded was not %s (expected size %ld, got %zd)\n", + fn, size, fw->size); + release_firmware(fw); + retries--; + goto retry; + } + for (i = 0; i < fw->size; i += 4096) { + setup_page(i); + for (j = i; j < fw->size && j < i + 4096; j += 4) { + /* no need for endianness conversion on the ppc */ + __raw_writel(*src, dst); + if (__raw_readl(dst) != *src) { + CX18_ERR("Mismatch at offset %x\n", i); + release_firmware(fw); + return -EIO; + } + dst++; + src++; + } + } + if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags)) + CX18_INFO("loaded %s firmware (%zd bytes)\n", fn, fw->size); + release_firmware(fw); + return size; +} + +static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx, long size) +{ + const struct firmware *fw = NULL; + int retries = 3; + int i, j; + const u32 *src; + struct cx18_apu_rom_seghdr seghdr; + const u8 *vers; + u32 offset = 0; + u32 apu_version = 0; + int sz; + +retry: + if (!retries || request_firmware(&fw, fn, &cx->dev->dev)) { + CX18_ERR("unable to open firmware %s (must be %ld bytes)\n", + fn, size); + CX18_ERR("did you put the firmware in the hotplug firmware directory?\n"); + return -ENOMEM; + } + + src = (const u32 *)fw->data; + vers = fw->data + sizeof(seghdr); + sz = fw->size; + + if (fw->size != size) { + /* Due to race conditions in firmware loading (esp. with + udev <0.95) the wrong file was sometimes loaded. So we check + filesizes to see if at least the right-sized file was + loaded. If not, then we retry. */ + CX18_INFO("retry: file loaded was not %s (expected size %ld, got %zd)\n", + fn, size, fw->size); + release_firmware(fw); + retries--; + goto retry; + } + apu_version = (vers[0] << 24) | (vers[4] << 16) | vers[32]; + while (offset + sizeof(seghdr) < size) { + /* TODO: byteswapping */ + memcpy(&seghdr, src + offset / 4, sizeof(seghdr)); + offset += sizeof(seghdr); + if (seghdr.sync1 != APU_ROM_SYNC1 || + seghdr.sync2 != APU_ROM_SYNC2) { + offset += seghdr.size; + continue; + } + CX18_DEBUG_INFO("load segment %x-%x\n", seghdr.addr, + seghdr.addr + seghdr.size - 1); + if (offset + seghdr.size > sz) + break; + for (i = 0; i < seghdr.size; i += 4096) { + setup_page(offset + i); + for (j = i; j < seghdr.size && j < i + 4096; j += 4) { + /* no need for endianness conversion on the ppc */ + __raw_writel(src[(offset + j) / 4], dst + seghdr.addr + j); + if (__raw_readl(dst + seghdr.addr + j) != src[(offset + j) / 4]) { + CX18_ERR("Mismatch at offset %x\n", offset + j); + release_firmware(fw); + return -EIO; + } + } + } + offset += seghdr.size; + } + if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags)) + CX18_INFO("loaded %s firmware V%08x (%zd bytes)\n", + fn, apu_version, fw->size); + release_firmware(fw); + /* Clear bit0 for APU to start from 0 */ + write_reg(read_reg(0xc72030) & ~1, 0xc72030); + return size; +} + +void cx18_halt_firmware(struct cx18 *cx) +{ + CX18_DEBUG_INFO("Preparing for firmware halt.\n"); + write_reg(0x000F000F, CX18_PROC_SOFT_RESET); /* stop the fw */ + write_reg(0x00020002, CX18_ADEC_CONTROL); +} + +void cx18_init_power(struct cx18 *cx, int lowpwr) +{ + /* power-down Spare and AOM PLLs */ + /* power-up fast, slow and mpeg PLLs */ + write_reg(0x00000008, CX18_PLL_POWER_DOWN); + + /* ADEC out of sleep */ + write_reg(0x00020000, CX18_ADEC_CONTROL); + + /* The fast clock is at 200/245 MHz */ + write_reg(lowpwr ? 0xD : 0x11, CX18_FAST_CLOCK_PLL_INT); + write_reg(lowpwr ? 0x1EFBF37 : 0x038E3D7, CX18_FAST_CLOCK_PLL_FRAC); + + write_reg(2, CX18_FAST_CLOCK_PLL_POST); + write_reg(1, CX18_FAST_CLOCK_PLL_PRESCALE); + write_reg(4, CX18_FAST_CLOCK_PLL_ADJUST_BANDWIDTH); + + /* set slow clock to 125/120 MHz */ + write_reg(lowpwr ? 0x11 : 0x10, CX18_SLOW_CLOCK_PLL_INT); + write_reg(lowpwr ? 0xEBAF05 : 0x18618A8, CX18_SLOW_CLOCK_PLL_FRAC); + write_reg(4, CX18_SLOW_CLOCK_PLL_POST); + + /* mpeg clock pll 54MHz */ + write_reg(0xF, CX18_MPEG_CLOCK_PLL_INT); + write_reg(0x2BCFEF, CX18_MPEG_CLOCK_PLL_FRAC); + write_reg(8, CX18_MPEG_CLOCK_PLL_POST); + + /* Defaults */ + /* APU = SC or SC/2 = 125/62.5 */ + /* EPU = SC = 125 */ + /* DDR = FC = 180 */ + /* ENC = SC = 125 */ + /* AI1 = SC = 125 */ + /* VIM2 = disabled */ + /* PCI = FC/2 = 90 */ + /* AI2 = disabled */ + /* DEMUX = disabled */ + /* AO = SC/2 = 62.5 */ + /* SER = 54MHz */ + /* VFC = disabled */ + /* USB = disabled */ + + write_reg(lowpwr ? 0xFFFF0020 : 0x00060004, CX18_CLOCK_SELECT1); + write_reg(lowpwr ? 0xFFFF0004 : 0x00060006, CX18_CLOCK_SELECT2); + + write_reg(0xFFFF0002, CX18_HALF_CLOCK_SELECT1); + write_reg(0xFFFF0104, CX18_HALF_CLOCK_SELECT2); + + write_reg(0xFFFF9026, CX18_CLOCK_ENABLE1); + write_reg(0xFFFF3105, CX18_CLOCK_ENABLE2); +} + +void cx18_init_memory(struct cx18 *cx) +{ + cx18_msleep_timeout(10, 0); + write_reg(0x10000, CX18_DDR_SOFT_RESET); + cx18_msleep_timeout(10, 0); + + write_reg(cx->card->ddr.chip_config, CX18_DDR_CHIP_CONFIG); + + cx18_msleep_timeout(10, 0); + + write_reg(cx->card->ddr.refresh, CX18_DDR_REFRESH); + write_reg(cx->card->ddr.timing1, CX18_DDR_TIMING1); + write_reg(cx->card->ddr.timing2, CX18_DDR_TIMING2); + + cx18_msleep_timeout(10, 0); + + /* Initialize DQS pad time */ + write_reg(cx->card->ddr.tune_lane, CX18_DDR_TUNE_LANE); + write_reg(cx->card->ddr.initial_emrs, CX18_DDR_INITIAL_EMRS); + + cx18_msleep_timeout(10, 0); + + write_reg(0x20000, CX18_DDR_SOFT_RESET); + cx18_msleep_timeout(10, 0); + + /* use power-down mode when idle */ + write_reg(0x00000010, CX18_DDR_POWER_REG); + + write_reg(0x10001, CX18_REG_BUS_TIMEOUT_EN); + + write_reg(0x48, CX18_DDR_MB_PER_ROW_7); + write_reg(0xE0000, CX18_DDR_BASE_63_ADDR); + + write_reg(0x00000101, CX18_WMB_CLIENT02); /* AO */ + write_reg(0x00000101, CX18_WMB_CLIENT09); /* AI2 */ + write_reg(0x00000101, CX18_WMB_CLIENT05); /* VIM1 */ + write_reg(0x00000101, CX18_WMB_CLIENT06); /* AI1 */ + write_reg(0x00000101, CX18_WMB_CLIENT07); /* 3D comb */ + write_reg(0x00000101, CX18_WMB_CLIENT10); /* ME */ + write_reg(0x00000101, CX18_WMB_CLIENT12); /* ENC */ + write_reg(0x00000101, CX18_WMB_CLIENT13); /* PK */ + write_reg(0x00000101, CX18_WMB_CLIENT11); /* RC */ + write_reg(0x00000101, CX18_WMB_CLIENT14); /* AVO */ +} + +int cx18_firmware_init(struct cx18 *cx) +{ + /* Allow chip to control CLKRUN */ + write_reg(0x5, CX18_DSP0_INTERRUPT_MASK); + + write_reg(0x000F000F, CX18_PROC_SOFT_RESET); /* stop the fw */ + + cx18_msleep_timeout(1, 0); + + sw1_irq_enable(IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU); + sw2_irq_enable(IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK); + + /* Only if the processor is not running */ + if (read_reg(CX18_PROC_SOFT_RESET) & 8) { + int sz = load_apu_fw_direct("v4l-cx23418-apu.fw", + cx->enc_mem, cx, CX18_FW_APU_SIZE); + + sz = sz <= 0 ? sz : load_cpu_fw_direct("v4l-cx23418-cpu.fw", + cx->enc_mem, cx, CX18_FW_CPU_SIZE); + + if (sz > 0) { + int retries = 0; + + /* start the CPU */ + write_reg(0x00080000, CX18_PROC_SOFT_RESET); + while (retries++ < 50) { /* Loop for max 500mS */ + if ((read_reg(CX18_PROC_SOFT_RESET) & 1) == 0) + break; + cx18_msleep_timeout(10, 0); + } + cx18_msleep_timeout(200, 0); + if (retries == 51) { + CX18_ERR("Could not start the CPU\n"); + return -EIO; + } + } + if (sz <= 0) + return -EIO; + } + /* initialize GPIO */ + write_reg(0x14001400, 0xC78110); + return 0; +} diff --git a/drivers/media/video/cx18/cx18-firmware.h b/drivers/media/video/cx18/cx18-firmware.h new file mode 100644 index 00000000000..38d4c05e849 --- /dev/null +++ b/drivers/media/video/cx18/cx18-firmware.h @@ -0,0 +1,25 @@ +/* + * cx18 firmware functions + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 + */ + +int cx18_firmware_init(struct cx18 *cx); +void cx18_halt_firmware(struct cx18 *cx); +void cx18_init_memory(struct cx18 *cx); +void cx18_init_power(struct cx18 *cx, int lowpwr); diff --git a/drivers/media/video/cx18/cx18-gpio.c b/drivers/media/video/cx18/cx18-gpio.c new file mode 100644 index 00000000000..19253e6b867 --- /dev/null +++ b/drivers/media/video/cx18/cx18-gpio.c @@ -0,0 +1,74 @@ +/* + * cx18 gpio functions + * + * Derived from ivtv-gpio.c + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 "cx18-driver.h" +#include "cx18-cards.h" +#include "cx18-gpio.h" +#include "tuner-xc2028.h" + +/********************* GPIO stuffs *********************/ + +/* GPIO registers */ +#define CX18_REG_GPIO_IN 0xc72010 +#define CX18_REG_GPIO_OUT1 0xc78100 +#define CX18_REG_GPIO_DIR1 0xc78108 +#define CX18_REG_GPIO_OUT2 0xc78104 +#define CX18_REG_GPIO_DIR2 0xc7810c + +/* + * HVR-1600 GPIO pins, courtesy of Hauppauge: + * + * gpio0: zilog ir process reset pin + * gpio1: zilog programming pin (you should never use this) + * gpio12: cx24227 reset pin + * gpio13: cs5345 reset pin +*/ + +void cx18_gpio_init(struct cx18 *cx) +{ + if (cx->card->gpio_init.direction == 0) + return; + + CX18_DEBUG_INFO("GPIO initial dir: %08x out: %08x\n", + read_reg(CX18_REG_GPIO_DIR1), read_reg(CX18_REG_GPIO_OUT1)); + + /* init output data then direction */ + write_reg(cx->card->gpio_init.direction << 16, CX18_REG_GPIO_DIR1); + write_reg(0, CX18_REG_GPIO_DIR2); + write_reg((cx->card->gpio_init.direction << 16) | + cx->card->gpio_init.initial_value, CX18_REG_GPIO_OUT1); + write_reg(0, CX18_REG_GPIO_OUT2); +} + +/* Xceive tuner reset function */ +int cx18_reset_tuner_gpio(void *dev, int cmd, int value) +{ + struct i2c_algo_bit_data *algo = dev; + struct cx18 *cx = algo->data; +/* int curdir, curout;*/ + + if (cmd != XC2028_TUNER_RESET) + return 0; + CX18_DEBUG_INFO("Resetting tuner\n"); + return 0; +} diff --git a/drivers/media/video/cx18/cx18-gpio.h b/drivers/media/video/cx18/cx18-gpio.h new file mode 100644 index 00000000000..41bac8856b5 --- /dev/null +++ b/drivers/media/video/cx18/cx18-gpio.h @@ -0,0 +1,24 @@ +/* + * cx18 gpio functions + * + * Derived from ivtv-gpio.h + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 + */ + +void cx18_gpio_init(struct cx18 *cx); +int cx18_reset_tuner_gpio(void *dev, int cmd, int value); diff --git a/drivers/media/video/cx18/cx18-i2c.c b/drivers/media/video/cx18/cx18-i2c.c new file mode 100644 index 00000000000..18c88d1e483 --- /dev/null +++ b/drivers/media/video/cx18/cx18-i2c.c @@ -0,0 +1,431 @@ +/* + * cx18 I2C functions + * + * Derived from ivtv-i2c.c + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 "cx18-driver.h" +#include "cx18-cards.h" +#include "cx18-gpio.h" +#include "cx18-av-core.h" + +#include <media/ir-kbd-i2c.h> + +#define CX18_REG_I2C_1_WR 0xf15000 +#define CX18_REG_I2C_1_RD 0xf15008 +#define CX18_REG_I2C_2_WR 0xf25100 +#define CX18_REG_I2C_2_RD 0xf25108 + +#define SETSCL_BIT 0x0001 +#define SETSDL_BIT 0x0002 +#define GETSCL_BIT 0x0004 +#define GETSDL_BIT 0x0008 + +#ifndef I2C_ADAP_CLASS_TV_ANALOG +#define I2C_ADAP_CLASS_TV_ANALOG I2C_CLASS_TV_ANALOG +#endif + +#define CX18_CS5345_I2C_ADDR 0x4c + +/* This array should match the CX18_HW_ defines */ +static const u8 hw_driverids[] = { + I2C_DRIVERID_TUNER, + I2C_DRIVERID_TVEEPROM, + I2C_DRIVERID_CS5345, + 0, /* CX18_HW_GPIO dummy driver ID */ + 0 /* CX18_HW_CX23418 dummy driver ID */ +}; + +/* This array should match the CX18_HW_ defines */ +static const u8 hw_addrs[] = { + 0, + 0, + CX18_CS5345_I2C_ADDR, + 0, /* CX18_HW_GPIO dummy driver ID */ + 0, /* CX18_HW_CX23418 dummy driver ID */ +}; + +/* This array should match the CX18_HW_ defines */ +/* This might well become a card-specific array */ +static const u8 hw_bus[] = { + 0, + 0, + 0, + 0, /* CX18_HW_GPIO dummy driver ID */ + 0, /* CX18_HW_CX23418 dummy driver ID */ +}; + +/* This array should match the CX18_HW_ defines */ +static const char * const hw_drivernames[] = { + "tuner", + "tveeprom", + "cs5345", + "gpio", + "cx23418", +}; + +int cx18_i2c_register(struct cx18 *cx, unsigned idx) +{ + struct i2c_board_info info; + struct i2c_client *c; + u8 id, bus; + int i; + + CX18_DEBUG_I2C("i2c client register\n"); + if (idx >= ARRAY_SIZE(hw_driverids) || hw_driverids[idx] == 0) + return -1; + id = hw_driverids[idx]; + bus = hw_bus[idx]; + memset(&info, 0, sizeof(info)); + strlcpy(info.driver_name, hw_drivernames[idx], + sizeof(info.driver_name)); + info.addr = hw_addrs[idx]; + for (i = 0; i < I2C_CLIENTS_MAX; i++) + if (cx->i2c_clients[i] == NULL) + break; + + if (i == I2C_CLIENTS_MAX) { + CX18_ERR("insufficient room for new I2C client!\n"); + return -ENOMEM; + } + + if (id != I2C_DRIVERID_TUNER) { + c = i2c_new_device(&cx->i2c_adap[bus], &info); + if (c->driver == NULL) + i2c_unregister_device(c); + else + cx->i2c_clients[i] = c; + return cx->i2c_clients[i] ? 0 : -ENODEV; + } + + /* special tuner handling */ + c = i2c_new_probed_device(&cx->i2c_adap[1], &info, cx->card_i2c->radio); + if (c && c->driver == NULL) + i2c_unregister_device(c); + else if (c) + cx->i2c_clients[i++] = c; + c = i2c_new_probed_device(&cx->i2c_adap[1], &info, cx->card_i2c->demod); + if (c && c->driver == NULL) + i2c_unregister_device(c); + else if (c) + cx->i2c_clients[i++] = c; + c = i2c_new_probed_device(&cx->i2c_adap[1], &info, cx->card_i2c->tv); + if (c && c->driver == NULL) + i2c_unregister_device(c); + else if (c) + cx->i2c_clients[i++] = c; + return 0; +} + +static int attach_inform(struct i2c_client *client) +{ + return 0; +} + +static int detach_inform(struct i2c_client *client) +{ + int i; + struct cx18 *cx = (struct cx18 *)i2c_get_adapdata(client->adapter); + + CX18_DEBUG_I2C("i2c client detach\n"); + for (i = 0; i < I2C_CLIENTS_MAX; i++) { + if (cx->i2c_clients[i] == client) { + cx->i2c_clients[i] = NULL; + break; + } + } + CX18_DEBUG_I2C("i2c detach [client=%s,%s]\n", + client->name, (i < I2C_CLIENTS_MAX) ? "ok" : "failed"); + + return 0; +} + +static void cx18_setscl(void *data, int state) +{ + struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx; + int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index; + u32 addr = bus_index ? CX18_REG_I2C_2_WR : CX18_REG_I2C_1_WR; + u32 r = read_reg(addr); + + if (state) + write_reg_sync(r | SETSCL_BIT, addr); + else + write_reg_sync(r & ~SETSCL_BIT, addr); +} + +static void cx18_setsda(void *data, int state) +{ + struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx; + int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index; + u32 addr = bus_index ? CX18_REG_I2C_2_WR : CX18_REG_I2C_1_WR; + u32 r = read_reg(addr); + + if (state) + write_reg_sync(r | SETSDL_BIT, addr); + else + write_reg_sync(r & ~SETSDL_BIT, addr); +} + +static int cx18_getscl(void *data) +{ + struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx; + int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index; + u32 addr = bus_index ? CX18_REG_I2C_2_RD : CX18_REG_I2C_1_RD; + + return read_reg(addr) & GETSCL_BIT; +} + +static int cx18_getsda(void *data) +{ + struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx; + int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index; + u32 addr = bus_index ? CX18_REG_I2C_2_RD : CX18_REG_I2C_1_RD; + + return read_reg(addr) & GETSDL_BIT; +} + +/* template for i2c-bit-algo */ +static struct i2c_adapter cx18_i2c_adap_template = { + .name = "cx18 i2c driver", + .id = I2C_HW_B_CX2341X, + .algo = NULL, /* set by i2c-algo-bit */ + .algo_data = NULL, /* filled from template */ + .client_register = attach_inform, + .client_unregister = detach_inform, + .owner = THIS_MODULE, +}; + +#define CX18_SCL_PERIOD (10) /* usecs. 10 usec is period for a 100 KHz clock */ +#define CX18_ALGO_BIT_TIMEOUT (2) /* seconds */ + +static struct i2c_algo_bit_data cx18_i2c_algo_template = { + .setsda = cx18_setsda, + .setscl = cx18_setscl, + .getsda = cx18_getsda, + .getscl = cx18_getscl, + .udelay = CX18_SCL_PERIOD/2, /* 1/2 clock period in usec*/ + .timeout = CX18_ALGO_BIT_TIMEOUT*HZ /* jiffies */ +}; + +static struct i2c_client cx18_i2c_client_template = { + .name = "cx18 internal", +}; + +int cx18_call_i2c_client(struct cx18 *cx, int addr, unsigned cmd, void *arg) +{ + struct i2c_client *client; + int retval; + int i; + + CX18_DEBUG_I2C("call_i2c_client addr=%02x\n", addr); + for (i = 0; i < I2C_CLIENTS_MAX; i++) { + client = cx->i2c_clients[i]; + if (client == NULL || client->driver == NULL || + client->driver->command == NULL) + continue; + if (addr == client->addr) { + retval = client->driver->command(client, cmd, arg); + return retval; + } + } + if (cmd != VIDIOC_G_CHIP_IDENT) + CX18_ERR("i2c addr 0x%02x not found for cmd 0x%x!\n", + addr, cmd); + return -ENODEV; +} + +/* Find the i2c device based on the driver ID and return + its i2c address or -ENODEV if no matching device was found. */ +static int cx18_i2c_id_addr(struct cx18 *cx, u32 id) +{ + struct i2c_client *client; + int retval = -ENODEV; + int i; + + for (i = 0; i < I2C_CLIENTS_MAX; i++) { + client = cx->i2c_clients[i]; + if (client == NULL || client->driver == NULL) + continue; + if (id == client->driver->id) { + retval = client->addr; + break; + } + } + return retval; +} + +/* Find the i2c device name matching the DRIVERID */ +static const char *cx18_i2c_id_name(u32 id) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(hw_driverids); i++) + if (hw_driverids[i] == id) + return hw_drivernames[i]; + return "unknown device"; +} + +/* Find the i2c device name matching the CX18_HW_ flag */ +static const char *cx18_i2c_hw_name(u32 hw) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(hw_driverids); i++) + if (1 << i == hw) + return hw_drivernames[i]; + return "unknown device"; +} + +/* Find the i2c device matching the CX18_HW_ flag and return + its i2c address or -ENODEV if no matching device was found. */ +int cx18_i2c_hw_addr(struct cx18 *cx, u32 hw) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(hw_driverids); i++) + if (1 << i == hw) + return cx18_i2c_id_addr(cx, hw_driverids[i]); + return -ENODEV; +} + +/* Calls i2c device based on CX18_HW_ flag. If hw == 0, then do nothing. + If hw == CX18_HW_GPIO then call the gpio handler. */ +int cx18_i2c_hw(struct cx18 *cx, u32 hw, unsigned int cmd, void *arg) +{ + int addr; + + if (hw == CX18_HW_GPIO || hw == 0) + return 0; + if (hw == CX18_HW_CX23418) + return cx18_av_cmd(cx, cmd, arg); + + addr = cx18_i2c_hw_addr(cx, hw); + if (addr < 0) { + CX18_ERR("i2c hardware 0x%08x (%s) not found for cmd 0x%x!\n", + hw, cx18_i2c_hw_name(hw), cmd); + return addr; + } + return cx18_call_i2c_client(cx, addr, cmd, arg); +} + +/* Calls i2c device based on I2C driver ID. */ +int cx18_i2c_id(struct cx18 *cx, u32 id, unsigned int cmd, void *arg) +{ + int addr; + + addr = cx18_i2c_id_addr(cx, id); + if (addr < 0) { + if (cmd != VIDIOC_G_CHIP_IDENT) + CX18_ERR("i2c ID 0x%08x (%s) not found for cmd 0x%x!\n", + id, cx18_i2c_id_name(id), cmd); + return addr; + } + return cx18_call_i2c_client(cx, addr, cmd, arg); +} + +/* broadcast cmd for all I2C clients and for the gpio subsystem */ +void cx18_call_i2c_clients(struct cx18 *cx, unsigned int cmd, void *arg) +{ + if (cx->i2c_adap[0].algo == NULL || cx->i2c_adap[1].algo == NULL) { + CX18_ERR("adapter is not set\n"); + return; + } + cx18_av_cmd(cx, cmd, arg); + i2c_clients_command(&cx->i2c_adap[0], cmd, arg); + i2c_clients_command(&cx->i2c_adap[1], cmd, arg); +} + +/* init + register i2c algo-bit adapter */ +int init_cx18_i2c(struct cx18 *cx) +{ + int i; + CX18_DEBUG_I2C("i2c init\n"); + + for (i = 0; i < 2; i++) { + memcpy(&cx->i2c_adap[i], &cx18_i2c_adap_template, + sizeof(struct i2c_adapter)); + memcpy(&cx->i2c_algo[i], &cx18_i2c_algo_template, + sizeof(struct i2c_algo_bit_data)); + cx->i2c_algo_cb_data[i].cx = cx; + cx->i2c_algo_cb_data[i].bus_index = i; + cx->i2c_algo[i].data = &cx->i2c_algo_cb_data[i]; + cx->i2c_adap[i].algo_data = &cx->i2c_algo[i]; + + sprintf(cx->i2c_adap[i].name + strlen(cx->i2c_adap[i].name), + " #%d-%d", cx->num, i); + i2c_set_adapdata(&cx->i2c_adap[i], cx); + + memcpy(&cx->i2c_client[i], &cx18_i2c_client_template, + sizeof(struct i2c_client)); + sprintf(cx->i2c_client[i].name + + strlen(cx->i2c_client[i].name), "%d", i); + cx->i2c_client[i].adapter = &cx->i2c_adap[i]; + cx->i2c_adap[i].dev.parent = &cx->dev->dev; + } + + if (read_reg(CX18_REG_I2C_2_WR) != 0x0003c02f) { + /* Reset/Unreset I2C hardware block */ + write_reg(0x10000000, 0xc71004); /* Clock select 220MHz */ + write_reg_sync(0x10001000, 0xc71024); /* Clock Enable */ + } + /* courtesy of Steven Toth <stoth@hauppauge.com> */ + write_reg_sync(0x00c00000, 0xc7001c); + mdelay(10); + write_reg_sync(0x00c000c0, 0xc7001c); + mdelay(10); + write_reg_sync(0x00c00000, 0xc7001c); + + write_reg_sync(0x00c00000, 0xc730c8); /* Set to edge-triggered intrs. */ + write_reg_sync(0x00c00000, 0xc730c4); /* Clear any stale intrs */ + + /* Hw I2C1 Clock Freq ~100kHz */ + write_reg_sync(0x00021c0f & ~4, CX18_REG_I2C_1_WR); + cx18_setscl(&cx->i2c_algo_cb_data[0], 1); + cx18_setsda(&cx->i2c_algo_cb_data[0], 1); + + /* Hw I2C2 Clock Freq ~100kHz */ + write_reg_sync(0x00021c0f & ~4, CX18_REG_I2C_2_WR); + cx18_setscl(&cx->i2c_algo_cb_data[1], 1); + cx18_setsda(&cx->i2c_algo_cb_data[1], 1); + + return i2c_bit_add_bus(&cx->i2c_adap[0]) || + i2c_bit_add_bus(&cx->i2c_adap[1]); +} + +void exit_cx18_i2c(struct cx18 *cx) +{ + int i; + CX18_DEBUG_I2C("i2c exit\n"); + write_reg(read_reg(CX18_REG_I2C_1_WR) | 4, CX18_REG_I2C_1_WR); + write_reg(read_reg(CX18_REG_I2C_2_WR) | 4, CX18_REG_I2C_2_WR); + + for (i = 0; i < 2; i++) { + i2c_del_adapter(&cx->i2c_adap[i]); + } +} + +/* + Hauppauge HVR1600 should have: + 32 cx24227 + 98 unknown + a0 eeprom + c2 tuner + e? zilog ir + */ diff --git a/drivers/media/video/cx18/cx18-i2c.h b/drivers/media/video/cx18/cx18-i2c.h new file mode 100644 index 00000000000..113c3f9a2cc --- /dev/null +++ b/drivers/media/video/cx18/cx18-i2c.h @@ -0,0 +1,33 @@ +/* + * cx18 I2C functions + * + * Derived from ivtv-i2c.h + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 + */ + +int cx18_i2c_hw_addr(struct cx18 *cx, u32 hw); +int cx18_i2c_hw(struct cx18 *cx, u32 hw, unsigned int cmd, void *arg); +int cx18_i2c_id(struct cx18 *cx, u32 id, unsigned int cmd, void *arg); +int cx18_call_i2c_client(struct cx18 *cx, int addr, unsigned cmd, void *arg); +void cx18_call_i2c_clients(struct cx18 *cx, unsigned int cmd, void *arg); +int cx18_i2c_register(struct cx18 *cx, unsigned idx); + +/* init + register i2c algo-bit adapter */ +int init_cx18_i2c(struct cx18 *cx); +void exit_cx18_i2c(struct cx18 *cx); diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c new file mode 100644 index 00000000000..dbdcb86ec5a --- /dev/null +++ b/drivers/media/video/cx18/cx18-ioctl.c @@ -0,0 +1,851 @@ +/* + * cx18 ioctl system call + * + * Derived from ivtv-ioctl.c + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 "cx18-driver.h" +#include "cx18-version.h" +#include "cx18-mailbox.h" +#include "cx18-i2c.h" +#include "cx18-queue.h" +#include "cx18-fileops.h" +#include "cx18-vbi.h" +#include "cx18-audio.h" +#include "cx18-video.h" +#include "cx18-streams.h" +#include "cx18-ioctl.h" +#include "cx18-gpio.h" +#include "cx18-controls.h" +#include "cx18-cards.h" +#include "cx18-av-core.h" +#include <media/tveeprom.h> +#include <media/v4l2-chip-ident.h> +#include <linux/i2c-id.h> + +u16 cx18_service2vbi(int type) +{ + switch (type) { + case V4L2_SLICED_TELETEXT_B: + return CX18_SLICED_TYPE_TELETEXT_B; + case V4L2_SLICED_CAPTION_525: + return CX18_SLICED_TYPE_CAPTION_525; + case V4L2_SLICED_WSS_625: + return CX18_SLICED_TYPE_WSS_625; + case V4L2_SLICED_VPS: + return CX18_SLICED_TYPE_VPS; + default: + return 0; + } +} + +static int valid_service_line(int field, int line, int is_pal) +{ + return (is_pal && line >= 6 && (line != 23 || field == 0)) || + (!is_pal && line >= 10 && line < 22); +} + +static u16 select_service_from_set(int field, int line, u16 set, int is_pal) +{ + u16 valid_set = (is_pal ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525); + int i; + + set = set & valid_set; + if (set == 0 || !valid_service_line(field, line, is_pal)) + return 0; + if (!is_pal) { + if (line == 21 && (set & V4L2_SLICED_CAPTION_525)) + return V4L2_SLICED_CAPTION_525; + } else { + if (line == 16 && field == 0 && (set & V4L2_SLICED_VPS)) + return V4L2_SLICED_VPS; + if (line == 23 && field == 0 && (set & V4L2_SLICED_WSS_625)) + return V4L2_SLICED_WSS_625; + if (line == 23) + return 0; + } + for (i = 0; i < 32; i++) { + if ((1 << i) & set) + return 1 << i; + } + return 0; +} + +void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal) +{ + u16 set = fmt->service_set; + int f, l; + + fmt->service_set = 0; + for (f = 0; f < 2; f++) { + for (l = 0; l < 24; l++) + fmt->service_lines[f][l] = select_service_from_set(f, l, set, is_pal); + } +} + +static int check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal) +{ + int f, l; + u16 set = 0; + + for (f = 0; f < 2; f++) { + for (l = 0; l < 24; l++) { + fmt->service_lines[f][l] = select_service_from_set(f, l, fmt->service_lines[f][l], is_pal); + set |= fmt->service_lines[f][l]; + } + } + return set != 0; +} + +u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt) +{ + int f, l; + u16 set = 0; + + for (f = 0; f < 2; f++) { + for (l = 0; l < 24; l++) + set |= fmt->service_lines[f][l]; + } + return set; +} + +static const struct { + v4l2_std_id std; + char *name; +} enum_stds[] = { + { V4L2_STD_PAL_BG | V4L2_STD_PAL_H, "PAL-BGH" }, + { V4L2_STD_PAL_DK, "PAL-DK" }, + { V4L2_STD_PAL_I, "PAL-I" }, + { V4L2_STD_PAL_M, "PAL-M" }, + { V4L2_STD_PAL_N, "PAL-N" }, + { V4L2_STD_PAL_Nc, "PAL-Nc" }, + { V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H, "SECAM-BGH" }, + { V4L2_STD_SECAM_DK, "SECAM-DK" }, + { V4L2_STD_SECAM_L, "SECAM-L" }, + { V4L2_STD_SECAM_LC, "SECAM-L'" }, + { V4L2_STD_NTSC_M, "NTSC-M" }, + { V4L2_STD_NTSC_M_JP, "NTSC-J" }, + { V4L2_STD_NTSC_M_KR, "NTSC-K" }, +}; + +static const struct v4l2_standard cx18_std_60hz = { + .frameperiod = {.numerator = 1001, .denominator = 30000}, + .framelines = 525, +}; + +static const struct v4l2_standard cx18_std_50hz = { + .frameperiod = { .numerator = 1, .denominator = 25 }, + .framelines = 625, +}; + +static int cx18_cxc(struct cx18 *cx, unsigned int cmd, void *arg) +{ + struct v4l2_register *regs = arg; + unsigned long flags; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (regs->reg >= CX18_MEM_OFFSET + CX18_MEM_SIZE) + return -EINVAL; + + spin_lock_irqsave(&cx18_cards_lock, flags); + if (cmd == VIDIOC_DBG_G_REGISTER) + regs->val = read_enc(regs->reg); + else + write_enc(regs->val, regs->reg); + spin_unlock_irqrestore(&cx18_cards_lock, flags); + return 0; +} + +static int cx18_get_fmt(struct cx18 *cx, int streamtype, struct v4l2_format *fmt) +{ + switch (fmt->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + fmt->fmt.pix.width = cx->params.width; + fmt->fmt.pix.height = cx->params.height; + fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + fmt->fmt.pix.field = V4L2_FIELD_INTERLACED; + if (streamtype == CX18_ENC_STREAM_TYPE_YUV) { + fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12; + /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */ + fmt->fmt.pix.sizeimage = + fmt->fmt.pix.height * fmt->fmt.pix.width + + fmt->fmt.pix.height * (fmt->fmt.pix.width / 2); + } else { + fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; + fmt->fmt.pix.sizeimage = 128 * 1024; + } + break; + + case V4L2_BUF_TYPE_VBI_CAPTURE: + fmt->fmt.vbi.sampling_rate = 27000000; + fmt->fmt.vbi.offset = 248; + fmt->fmt.vbi.samples_per_line = cx->vbi.raw_decoder_line_size - 4; + fmt->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; + fmt->fmt.vbi.start[0] = cx->vbi.start[0]; + fmt->fmt.vbi.start[1] = cx->vbi.start[1]; + fmt->fmt.vbi.count[0] = fmt->fmt.vbi.count[1] = cx->vbi.count; + break; + + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + { + struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; + + vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; + memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved)); + memset(vbifmt->service_lines, 0, sizeof(vbifmt->service_lines)); + + cx18_av_cmd(cx, VIDIOC_G_FMT, fmt); + vbifmt->service_set = cx18_get_service_set(vbifmt); + break; + } + default: + return -EINVAL; + } + return 0; +} + +static int cx18_try_or_set_fmt(struct cx18 *cx, int streamtype, + struct v4l2_format *fmt, int set_fmt) +{ + struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; + u16 set; + + /* set window size */ + if (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + int w = fmt->fmt.pix.width; + int h = fmt->fmt.pix.height; + + if (w > 720) + w = 720; + else if (w < 1) + w = 1; + if (h > (cx->is_50hz ? 576 : 480)) + h = (cx->is_50hz ? 576 : 480); + else if (h < 2) + h = 2; + cx18_get_fmt(cx, streamtype, fmt); + fmt->fmt.pix.width = w; + fmt->fmt.pix.height = h; + + if (!set_fmt || (cx->params.width == w && cx->params.height == h)) + return 0; + if (atomic_read(&cx->capturing) > 0) + return -EBUSY; + + cx->params.width = w; + cx->params.height = h; + if (w != 720 || h != (cx->is_50hz ? 576 : 480)) + cx->params.video_temporal_filter = 0; + else + cx->params.video_temporal_filter = 8; + cx18_av_cmd(cx, VIDIOC_S_FMT, fmt); + return cx18_get_fmt(cx, streamtype, fmt); + } + + /* set raw VBI format */ + if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) { + if (set_fmt && streamtype == CX18_ENC_STREAM_TYPE_VBI && + cx->vbi.sliced_in->service_set && + atomic_read(&cx->capturing) > 0) + return -EBUSY; + if (set_fmt) { + cx->vbi.sliced_in->service_set = 0; + cx18_av_cmd(cx, VIDIOC_S_FMT, &cx->vbi.in); + } + return cx18_get_fmt(cx, streamtype, fmt); + } + + /* any else but sliced VBI capture is an error */ + if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) + return -EINVAL; + + /* TODO: implement sliced VBI, for now silently return 0 */ + return 0; + + /* set sliced VBI capture format */ + vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; + memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved)); + + if (vbifmt->service_set) + cx18_expand_service_set(vbifmt, cx->is_50hz); + set = check_service_set(vbifmt, cx->is_50hz); + vbifmt->service_set = cx18_get_service_set(vbifmt); + + if (!set_fmt) + return 0; + if (set == 0) + return -EINVAL; + if (atomic_read(&cx->capturing) > 0 && cx->vbi.sliced_in->service_set == 0) + return -EBUSY; + cx18_av_cmd(cx, VIDIOC_S_FMT, fmt); + memcpy(cx->vbi.sliced_in, vbifmt, sizeof(*cx->vbi.sliced_in)); + return 0; +} + +static int cx18_debug_ioctls(struct file *filp, unsigned int cmd, void *arg) +{ + struct cx18_open_id *id = (struct cx18_open_id *)filp->private_data; + struct cx18 *cx = id->cx; + struct v4l2_register *reg = arg; + + switch (cmd) { + /* ioctls to allow direct access to the encoder registers for testing */ + case VIDIOC_DBG_G_REGISTER: + if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) + return cx18_cxc(cx, cmd, arg); + if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER) + return cx18_i2c_id(cx, reg->match_chip, cmd, arg); + return cx18_call_i2c_client(cx, reg->match_chip, cmd, arg); + + case VIDIOC_DBG_S_REGISTER: + if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) + return cx18_cxc(cx, cmd, arg); + if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER) + return cx18_i2c_id(cx, reg->match_chip, cmd, arg); + return cx18_call_i2c_client(cx, reg->match_chip, cmd, arg); + + case VIDIOC_G_CHIP_IDENT: { + struct v4l2_chip_ident *chip = arg; + + chip->ident = V4L2_IDENT_NONE; + chip->revision = 0; + if (reg->match_type == V4L2_CHIP_MATCH_HOST) { + if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) { + struct v4l2_chip_ident *chip = arg; + + chip->ident = V4L2_IDENT_CX23418; + } + return 0; + } + if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER) + return cx18_i2c_id(cx, reg->match_chip, cmd, arg); + if (reg->match_type == V4L2_CHIP_MATCH_I2C_ADDR) + return cx18_call_i2c_client(cx, reg->match_chip, cmd, arg); + return -EINVAL; + } + + case VIDIOC_INT_S_AUDIO_ROUTING: { + struct v4l2_routing *route = arg; + + cx18_audio_set_route(cx, route); + break; + } + + default: + return -EINVAL; + } + return 0; +} + +int cx18_v4l2_ioctls(struct cx18 *cx, struct file *filp, unsigned cmd, void *arg) +{ + struct cx18_open_id *id = NULL; + + if (filp) + id = (struct cx18_open_id *)filp->private_data; + + switch (cmd) { + case VIDIOC_G_PRIORITY: + { + enum v4l2_priority *p = arg; + + *p = v4l2_prio_max(&cx->prio); + break; + } + + case VIDIOC_S_PRIORITY: + { + enum v4l2_priority *prio = arg; + + return v4l2_prio_change(&cx->prio, &id->prio, *prio); + } + + case VIDIOC_QUERYCAP:{ + struct v4l2_capability *vcap = arg; + + memset(vcap, 0, sizeof(*vcap)); + strlcpy(vcap->driver, CX18_DRIVER_NAME, sizeof(vcap->driver)); + strlcpy(vcap->card, cx->card_name, sizeof(vcap->card)); + strlcpy(vcap->bus_info, pci_name(cx->dev), sizeof(vcap->bus_info)); + vcap->version = CX18_DRIVER_VERSION; /* version */ + vcap->capabilities = cx->v4l2_cap; /* capabilities */ + + /* reserved.. must set to 0! */ + vcap->reserved[0] = vcap->reserved[1] = + vcap->reserved[2] = vcap->reserved[3] = 0; + break; + } + + case VIDIOC_ENUMAUDIO:{ + struct v4l2_audio *vin = arg; + + return cx18_get_audio_input(cx, vin->index, vin); + } + + case VIDIOC_G_AUDIO:{ + struct v4l2_audio *vin = arg; + + vin->index = cx->audio_input; + return cx18_get_audio_input(cx, vin->index, vin); + } + + case VIDIOC_S_AUDIO:{ + struct v4l2_audio *vout = arg; + + if (vout->index >= cx->nof_audio_inputs) + return -EINVAL; + cx->audio_input = vout->index; + cx18_audio_set_io(cx); + break; + } + + case VIDIOC_ENUMINPUT:{ + struct v4l2_input *vin = arg; + + /* set it to defaults from our table */ + return cx18_get_input(cx, vin->index, vin); + } + + case VIDIOC_TRY_FMT: + case VIDIOC_S_FMT: { + struct v4l2_format *fmt = arg; + + return cx18_try_or_set_fmt(cx, id->type, fmt, cmd == VIDIOC_S_FMT); + } + + case VIDIOC_G_FMT: { + struct v4l2_format *fmt = arg; + int type = fmt->type; + + memset(fmt, 0, sizeof(*fmt)); + fmt->type = type; + return cx18_get_fmt(cx, id->type, fmt); + } + + case VIDIOC_CROPCAP: { + struct v4l2_cropcap *cropcap = arg; + + if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + cropcap->bounds.top = cropcap->bounds.left = 0; + cropcap->bounds.width = 720; + cropcap->bounds.height = cx->is_50hz ? 576 : 480; + cropcap->pixelaspect.numerator = cx->is_50hz ? 59 : 10; + cropcap->pixelaspect.denominator = cx->is_50hz ? 54 : 11; + cropcap->defrect = cropcap->bounds; + return 0; + } + + case VIDIOC_S_CROP: { + struct v4l2_crop *crop = arg; + + if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + return cx18_av_cmd(cx, VIDIOC_S_CROP, arg); + } + + case VIDIOC_G_CROP: { + struct v4l2_crop *crop = arg; + + if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + return cx18_av_cmd(cx, VIDIOC_G_CROP, arg); + } + + case VIDIOC_ENUM_FMT: { + static struct v4l2_fmtdesc formats[] = { + { 0, 0, 0, + "HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12, + { 0, 0, 0, 0 } + }, + { 1, 0, V4L2_FMT_FLAG_COMPRESSED, + "MPEG", V4L2_PIX_FMT_MPEG, + { 0, 0, 0, 0 } + } + }; + struct v4l2_fmtdesc *fmt = arg; + enum v4l2_buf_type type = fmt->type; + + switch (type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + break; + default: + return -EINVAL; + } + if (fmt->index > 1) + return -EINVAL; + *fmt = formats[fmt->index]; + fmt->type = type; + return 0; + } + + case VIDIOC_G_INPUT:{ + *(int *)arg = cx->active_input; + break; + } + + case VIDIOC_S_INPUT:{ + int inp = *(int *)arg; + + if (inp < 0 || inp >= cx->nof_inputs) + return -EINVAL; + + if (inp == cx->active_input) { + CX18_DEBUG_INFO("Input unchanged\n"); + break; + } + CX18_DEBUG_INFO("Changing input from %d to %d\n", + cx->active_input, inp); + + cx->active_input = inp; + /* Set the audio input to whatever is appropriate for the + input type. */ + cx->audio_input = cx->card->video_inputs[inp].audio_index; + + /* prevent others from messing with the streams until + we're finished changing inputs. */ + cx18_mute(cx); + cx18_video_set_io(cx); + cx18_audio_set_io(cx); + cx18_unmute(cx); + break; + } + + case VIDIOC_G_FREQUENCY:{ + struct v4l2_frequency *vf = arg; + + if (vf->tuner != 0) + return -EINVAL; + cx18_call_i2c_clients(cx, cmd, arg); + break; + } + + case VIDIOC_S_FREQUENCY:{ + struct v4l2_frequency vf = *(struct v4l2_frequency *)arg; + + if (vf.tuner != 0) + return -EINVAL; + + cx18_mute(cx); + CX18_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf.frequency); + cx18_call_i2c_clients(cx, cmd, &vf); + cx18_unmute(cx); + break; + } + + case VIDIOC_ENUMSTD:{ + struct v4l2_standard *vs = arg; + int idx = vs->index; + + if (idx < 0 || idx >= ARRAY_SIZE(enum_stds)) + return -EINVAL; + + *vs = (enum_stds[idx].std & V4L2_STD_525_60) ? + cx18_std_60hz : cx18_std_50hz; + vs->index = idx; + vs->id = enum_stds[idx].std; + strlcpy(vs->name, enum_stds[idx].name, sizeof(vs->name)); + break; + } + + case VIDIOC_G_STD:{ + *(v4l2_std_id *) arg = cx->std; + break; + } + + case VIDIOC_S_STD: { + v4l2_std_id std = *(v4l2_std_id *) arg; + + if ((std & V4L2_STD_ALL) == 0) + return -EINVAL; + + if (std == cx->std) + break; + + if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) || + atomic_read(&cx->capturing) > 0) { + /* Switching standard would turn off the radio or mess + with already running streams, prevent that by + returning EBUSY. */ + return -EBUSY; + } + + cx->std = std; + cx->is_60hz = (std & V4L2_STD_525_60) ? 1 : 0; + cx->params.is_50hz = cx->is_50hz = !cx->is_60hz; + cx->params.width = 720; + cx->params.height = cx->is_50hz ? 576 : 480; + cx->vbi.count = cx->is_50hz ? 18 : 12; + cx->vbi.start[0] = cx->is_50hz ? 6 : 10; + cx->vbi.start[1] = cx->is_50hz ? 318 : 273; + cx->vbi.sliced_decoder_line_size = cx->is_60hz ? 272 : 284; + CX18_DEBUG_INFO("Switching standard to %llx.\n", (unsigned long long)cx->std); + + /* Tuner */ + cx18_call_i2c_clients(cx, VIDIOC_S_STD, &cx->std); + break; + } + + case VIDIOC_S_TUNER: { /* Setting tuner can only set audio mode */ + struct v4l2_tuner *vt = arg; + + if (vt->index != 0) + return -EINVAL; + + cx18_call_i2c_clients(cx, VIDIOC_S_TUNER, vt); + break; + } + + case VIDIOC_G_TUNER: { + struct v4l2_tuner *vt = arg; + + if (vt->index != 0) + return -EINVAL; + + memset(vt, 0, sizeof(*vt)); + cx18_call_i2c_clients(cx, VIDIOC_G_TUNER, vt); + + if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) { + strlcpy(vt->name, "cx18 Radio Tuner", sizeof(vt->name)); + vt->type = V4L2_TUNER_RADIO; + } else { + strlcpy(vt->name, "cx18 TV Tuner", sizeof(vt->name)); + vt->type = V4L2_TUNER_ANALOG_TV; + } + break; + } + + case VIDIOC_G_SLICED_VBI_CAP: { + struct v4l2_sliced_vbi_cap *cap = arg; + int set = cx->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525; + int f, l; + enum v4l2_buf_type type = cap->type; + + memset(cap, 0, sizeof(*cap)); + cap->type = type; + if (type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) { + for (f = 0; f < 2; f++) { + for (l = 0; l < 24; l++) { + if (valid_service_line(f, l, cx->is_50hz)) + cap->service_lines[f][l] = set; + } + } + return 0; + } + return -EINVAL; + } + + case VIDIOC_ENCODER_CMD: + case VIDIOC_TRY_ENCODER_CMD: { + struct v4l2_encoder_cmd *enc = arg; + int try = cmd == VIDIOC_TRY_ENCODER_CMD; + + memset(&enc->raw, 0, sizeof(enc->raw)); + switch (enc->cmd) { + case V4L2_ENC_CMD_START: + enc->flags = 0; + if (try) + return 0; + return cx18_start_capture(id); + + case V4L2_ENC_CMD_STOP: + enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END; + if (try) + return 0; + cx18_stop_capture(id, enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END); + return 0; + + case V4L2_ENC_CMD_PAUSE: + enc->flags = 0; + if (try) + return 0; + if (!atomic_read(&cx->capturing)) + return -EPERM; + if (test_and_set_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags)) + return 0; + cx18_mute(cx); + cx18_vapi(cx, CX18_CPU_CAPTURE_PAUSE, 1, cx18_find_handle(cx)); + break; + + case V4L2_ENC_CMD_RESUME: + enc->flags = 0; + if (try) + return 0; + if (!atomic_read(&cx->capturing)) + return -EPERM; + if (!test_and_clear_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags)) + return 0; + cx18_vapi(cx, CX18_CPU_CAPTURE_RESUME, 1, cx18_find_handle(cx)); + cx18_unmute(cx); + break; + default: + return -EINVAL; + } + break; + } + + case VIDIOC_LOG_STATUS: + { + struct v4l2_input vidin; + struct v4l2_audio audin; + int i; + + CX18_INFO("================= START STATUS CARD #%d =================\n", cx->num); + if (cx->hw_flags & CX18_HW_TVEEPROM) { + struct tveeprom tv; + + cx18_read_eeprom(cx, &tv); + } + cx18_call_i2c_clients(cx, VIDIOC_LOG_STATUS, NULL); + cx18_get_input(cx, cx->active_input, &vidin); + cx18_get_audio_input(cx, cx->audio_input, &audin); + CX18_INFO("Video Input: %s\n", vidin.name); + CX18_INFO("Audio Input: %s\n", audin.name); + CX18_INFO("Tuner: %s\n", + test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ? + "Radio" : "TV"); + cx2341x_log_status(&cx->params, cx->name); + CX18_INFO("Status flags: 0x%08lx\n", cx->i_flags); + for (i = 0; i < CX18_MAX_STREAMS; i++) { + struct cx18_stream *s = &cx->streams[i]; + + if (s->v4l2dev == NULL || s->buffers == 0) + continue; + CX18_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n", + s->name, s->s_flags, + (s->buffers - s->q_free.buffers) * 100 / s->buffers, + (s->buffers * s->buf_size) / 1024, s->buffers); + } + CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n", + (long long)cx->mpg_data_received, + (long long)cx->vbi_data_inserted); + CX18_INFO("================== END STATUS CARD #%d ==================\n", cx->num); + break; + } + + default: + return -EINVAL; + } + return 0; +} + +static int cx18_v4l2_do_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, void *arg) +{ + struct cx18_open_id *id = (struct cx18_open_id *)filp->private_data; + struct cx18 *cx = id->cx; + int ret; + + /* check priority */ + switch (cmd) { + case VIDIOC_S_CTRL: + case VIDIOC_S_STD: + case VIDIOC_S_INPUT: + case VIDIOC_S_TUNER: + case VIDIOC_S_FREQUENCY: + case VIDIOC_S_FMT: + case VIDIOC_S_CROP: + case VIDIOC_S_EXT_CTRLS: + ret = v4l2_prio_check(&cx->prio, &id->prio); + if (ret) + return ret; + } + + switch (cmd) { + case VIDIOC_DBG_G_REGISTER: + case VIDIOC_DBG_S_REGISTER: + case VIDIOC_G_CHIP_IDENT: + case VIDIOC_INT_S_AUDIO_ROUTING: + case VIDIOC_INT_RESET: + if (cx18_debug & CX18_DBGFLG_IOCTL) { + printk(KERN_INFO "cx18%d ioctl: ", cx->num); + v4l_printk_ioctl(cmd); + } + return cx18_debug_ioctls(filp, cmd, arg); + + case VIDIOC_G_PRIORITY: + case VIDIOC_S_PRIORITY: + case VIDIOC_QUERYCAP: + case VIDIOC_ENUMINPUT: + case VIDIOC_G_INPUT: + case VIDIOC_S_INPUT: + case VIDIOC_G_FMT: + case VIDIOC_S_FMT: + case VIDIOC_TRY_FMT: + case VIDIOC_ENUM_FMT: + case VIDIOC_CROPCAP: + case VIDIOC_G_CROP: + case VIDIOC_S_CROP: + case VIDIOC_G_FREQUENCY: + case VIDIOC_S_FREQUENCY: + case VIDIOC_ENUMSTD: + case VIDIOC_G_STD: + case VIDIOC_S_STD: + case VIDIOC_S_TUNER: + case VIDIOC_G_TUNER: + case VIDIOC_ENUMAUDIO: + case VIDIOC_S_AUDIO: + case VIDIOC_G_AUDIO: + case VIDIOC_G_SLICED_VBI_CAP: + case VIDIOC_LOG_STATUS: + case VIDIOC_G_ENC_INDEX: + case VIDIOC_ENCODER_CMD: + case VIDIOC_TRY_ENCODER_CMD: + if (cx18_debug & CX18_DBGFLG_IOCTL) { + printk(KERN_INFO "cx18%d ioctl: ", cx->num); + v4l_printk_ioctl(cmd); + } + return cx18_v4l2_ioctls(cx, filp, cmd, arg); + + case VIDIOC_QUERYMENU: + case VIDIOC_QUERYCTRL: + case VIDIOC_S_CTRL: + case VIDIOC_G_CTRL: + case VIDIOC_S_EXT_CTRLS: + case VIDIOC_G_EXT_CTRLS: + case VIDIOC_TRY_EXT_CTRLS: + if (cx18_debug & CX18_DBGFLG_IOCTL) { + printk(KERN_INFO "cx18%d ioctl: ", cx->num); + v4l_printk_ioctl(cmd); + } + return cx18_control_ioctls(cx, cmd, arg); + + case 0x00005401: /* Handle isatty() calls */ + return -EINVAL; + default: + return v4l_compat_translate_ioctl(inode, filp, cmd, arg, + cx18_v4l2_do_ioctl); + } + return 0; +} + +int cx18_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + struct cx18_open_id *id = (struct cx18_open_id *)filp->private_data; + struct cx18 *cx = id->cx; + int res; + + mutex_lock(&cx->serialize_lock); + res = video_usercopy(inode, filp, cmd, arg, cx18_v4l2_do_ioctl); + mutex_unlock(&cx->serialize_lock); + return res; +} diff --git a/drivers/media/video/cx18/cx18-ioctl.h b/drivers/media/video/cx18/cx18-ioctl.h new file mode 100644 index 00000000000..9f4c7eb2897 --- /dev/null +++ b/drivers/media/video/cx18/cx18-ioctl.h @@ -0,0 +1,30 @@ +/* + * cx18 ioctl system call + * + * Derived from ivtv-ioctl.h + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 + */ + +u16 cx18_service2vbi(int type); +void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal); +u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt); +int cx18_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg); +int cx18_v4l2_ioctls(struct cx18 *cx, struct file *filp, unsigned cmd, + void *arg); diff --git a/drivers/media/video/cx18/cx18-irq.c b/drivers/media/video/cx18/cx18-irq.c new file mode 100644 index 00000000000..6e14f8bda55 --- /dev/null +++ b/drivers/media/video/cx18/cx18-irq.c @@ -0,0 +1,179 @@ +/* + * cx18 interrupt handling + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 "cx18-driver.h" +#include "cx18-firmware.h" +#include "cx18-fileops.h" +#include "cx18-queue.h" +#include "cx18-irq.h" +#include "cx18-ioctl.h" +#include "cx18-mailbox.h" +#include "cx18-vbi.h" +#include "cx18-scb.h" + +#define DMA_MAGIC_COOKIE 0x000001fe + +static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb) +{ + u32 handle = mb->args[0]; + struct cx18_stream *s = NULL; + struct cx18_buffer *buf; + u32 off; + int i; + int id; + + for (i = 0; i < CX18_MAX_STREAMS; i++) { + s = &cx->streams[i]; + if ((handle == s->handle) && (s->dvb.enabled)) + break; + if (s->v4l2dev && handle == s->handle) + break; + } + if (i == CX18_MAX_STREAMS) { + CX18_WARN("DMA done for unknown handle %d for stream %s\n", + handle, s->name); + mb->error = CXERR_NOT_OPEN; + mb->cmd = 0; + cx18_mb_ack(cx, mb); + return; + } + + off = mb->args[1]; + if (mb->args[2] != 1) + CX18_WARN("Ack struct = %d for %s\n", + mb->args[2], s->name); + id = read_enc(off); + buf = cx18_queue_find_buf(s, id, read_enc(off + 4)); + CX18_DEBUG_HI_DMA("DMA DONE for %s (buffer %d)\n", s->name, id); + if (buf) { + cx18_buf_sync_for_cpu(s, buf); + if (s->type == CX18_ENC_STREAM_TYPE_TS && s->dvb.enabled) { + /* process the buffer here */ + CX18_DEBUG_HI_DMA("TS recv and sent bytesused=%d\n", + buf->bytesused); + + dvb_dmx_swfilter(&s->dvb.demux, buf->buf, + buf->bytesused); + + cx18_buf_sync_for_device(s, buf); + cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle, + (void *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem, + 1, buf->id, s->buf_size); + } else + set_bit(CX18_F_B_NEED_BUF_SWAP, &buf->b_flags); + } else { + CX18_WARN("Could not find buf %d for stream %s\n", + read_enc(off), s->name); + } + mb->error = 0; + mb->cmd = 0; + cx18_mb_ack(cx, mb); + wake_up(&cx->dma_waitq); + if (s->id != -1) + wake_up(&s->waitq); +} + +static void epu_debug(struct cx18 *cx, struct cx18_mailbox *mb) +{ + char str[256] = { 0 }; + char *p; + + if (mb->args[1]) { + setup_page(mb->args[1]); + memcpy_fromio(str, cx->enc_mem + mb->args[1], 252); + str[252] = 0; + } + cx18_mb_ack(cx, mb); + CX18_DEBUG_INFO("%x %s\n", mb->args[0], str); + p = strchr(str, '.'); + if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags) && p && p > str) + CX18_INFO("FW version: %s\n", p - 1); +} + +static void hpu_cmd(struct cx18 *cx, u32 sw1) +{ + struct cx18_mailbox mb; + + if (sw1 & IRQ_CPU_TO_EPU) { + memcpy_fromio(&mb, &cx->scb->cpu2epu_mb, sizeof(mb)); + mb.error = 0; + + switch (mb.cmd) { + case CX18_EPU_DMA_DONE: + epu_dma_done(cx, &mb); + break; + case CX18_EPU_DEBUG: + epu_debug(cx, &mb); + break; + default: + CX18_WARN("Unexpected mailbox command %08x\n", mb.cmd); + break; + } + } + if (sw1 & (IRQ_APU_TO_EPU | IRQ_HPU_TO_EPU)) + CX18_WARN("Unexpected interrupt %08x\n", sw1); +} + +irqreturn_t cx18_irq_handler(int irq, void *dev_id) +{ + struct cx18 *cx = (struct cx18 *)dev_id; + u32 sw1, sw1_mask; + u32 sw2, sw2_mask; + u32 hw2, hw2_mask; + + spin_lock(&cx->dma_reg_lock); + + hw2_mask = read_reg(HW2_INT_MASK5_PCI); + hw2 = read_reg(HW2_INT_CLR_STATUS) & hw2_mask; + sw2_mask = read_reg(SW2_INT_ENABLE_PCI) | IRQ_EPU_TO_HPU_ACK; + sw2 = read_reg(SW2_INT_STATUS) & sw2_mask; + sw1_mask = read_reg(SW1_INT_ENABLE_PCI) | IRQ_EPU_TO_HPU; + sw1 = read_reg(SW1_INT_STATUS) & sw1_mask; + + write_reg(sw2&sw2_mask, SW2_INT_STATUS); + write_reg(sw1&sw1_mask, SW1_INT_STATUS); + write_reg(hw2&hw2_mask, HW2_INT_CLR_STATUS); + + if (sw1 || sw2 || hw2) + CX18_DEBUG_HI_IRQ("SW1: %x SW2: %x HW2: %x\n", sw1, sw2, hw2); + + /* To do: interrupt-based I2C handling + if (hw2 & 0x00c00000) { + } + */ + + if (sw2) { + if (sw2 & (cx->scb->cpu2hpu_irq_ack | cx->scb->cpu2epu_irq_ack)) + wake_up(&cx->mb_cpu_waitq); + if (sw2 & (cx->scb->apu2hpu_irq_ack | cx->scb->apu2epu_irq_ack)) + wake_up(&cx->mb_apu_waitq); + if (sw2 & cx->scb->epu2hpu_irq_ack) + wake_up(&cx->mb_epu_waitq); + if (sw2 & cx->scb->hpu2epu_irq_ack) + wake_up(&cx->mb_hpu_waitq); + } + + if (sw1) + hpu_cmd(cx, sw1); + spin_unlock(&cx->dma_reg_lock); + + return (hw2 | sw1 | sw2) ? IRQ_HANDLED : IRQ_NONE; +} diff --git a/drivers/media/video/cx18/cx18-irq.h b/drivers/media/video/cx18/cx18-irq.h new file mode 100644 index 00000000000..379f704f5cb --- /dev/null +++ b/drivers/media/video/cx18/cx18-irq.h @@ -0,0 +1,37 @@ +/* + * cx18 interrupt handling + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 + */ + +#define HW2_I2C1_INT (1 << 22) +#define HW2_I2C2_INT (1 << 23) +#define HW2_INT_CLR_STATUS 0xc730c4 +#define HW2_INT_MASK5_PCI 0xc730e4 +#define SW1_INT_SET 0xc73100 +#define SW1_INT_STATUS 0xc73104 +#define SW1_INT_ENABLE_PCI 0xc7311c +#define SW2_INT_SET 0xc73140 +#define SW2_INT_STATUS 0xc73144 +#define SW2_INT_ENABLE_PCI 0xc7315c + +irqreturn_t cx18_irq_handler(int irq, void *dev_id); + +void cx18_irq_work_handler(struct work_struct *work); +void cx18_dma_stream_dec_prepare(struct cx18_stream *s, u32 offset, int lock); +void cx18_unfinished_dma(unsigned long arg); diff --git a/drivers/media/video/cx18/cx18-mailbox.c b/drivers/media/video/cx18/cx18-mailbox.c new file mode 100644 index 00000000000..0c5f328bca5 --- /dev/null +++ b/drivers/media/video/cx18/cx18-mailbox.c @@ -0,0 +1,372 @@ +/* + * cx18 mailbox functions + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 <stdarg.h> + +#include "cx18-driver.h" +#include "cx18-scb.h" +#include "cx18-irq.h" +#include "cx18-mailbox.h" + +#define API_FAST (1 << 2) /* Short timeout */ +#define API_SLOW (1 << 3) /* Additional 300ms timeout */ + +#define APU 0 +#define CPU 1 +#define EPU 2 +#define HPU 3 + +struct cx18_api_info { + u32 cmd; + u8 flags; /* Flags, see above */ + u8 rpu; /* Processing unit */ + const char *name; /* The name of the command */ +}; + +#define API_ENTRY(rpu, x, f) { (x), (f), (rpu), #x } + +static const struct cx18_api_info api_info[] = { + /* MPEG encoder API */ + API_ENTRY(CPU, CX18_CPU_SET_CHANNEL_TYPE, 0), + API_ENTRY(CPU, CX18_EPU_DEBUG, 0), + API_ENTRY(CPU, CX18_CREATE_TASK, 0), + API_ENTRY(CPU, CX18_DESTROY_TASK, 0), + API_ENTRY(CPU, CX18_CPU_CAPTURE_START, API_SLOW), + API_ENTRY(CPU, CX18_CPU_CAPTURE_STOP, API_SLOW), + API_ENTRY(CPU, CX18_CPU_CAPTURE_PAUSE, 0), + API_ENTRY(CPU, CX18_CPU_CAPTURE_RESUME, 0), + API_ENTRY(CPU, CX18_CPU_SET_CHANNEL_TYPE, 0), + API_ENTRY(CPU, CX18_CPU_SET_STREAM_OUTPUT_TYPE, 0), + API_ENTRY(CPU, CX18_CPU_SET_VIDEO_IN, 0), + API_ENTRY(CPU, CX18_CPU_SET_VIDEO_RATE, 0), + API_ENTRY(CPU, CX18_CPU_SET_VIDEO_RESOLUTION, 0), + API_ENTRY(CPU, CX18_CPU_SET_FILTER_PARAM, 0), + API_ENTRY(CPU, CX18_CPU_SET_SPATIAL_FILTER_TYPE, 0), + API_ENTRY(CPU, CX18_CPU_SET_MEDIAN_CORING, 0), + API_ENTRY(CPU, CX18_CPU_SET_INDEXTABLE, 0), + API_ENTRY(CPU, CX18_CPU_SET_AUDIO_PARAMETERS, 0), + API_ENTRY(CPU, CX18_CPU_SET_VIDEO_MUTE, 0), + API_ENTRY(CPU, CX18_CPU_SET_AUDIO_MUTE, 0), + API_ENTRY(CPU, CX18_CPU_SET_MISC_PARAMETERS, 0), + API_ENTRY(CPU, CX18_CPU_SET_RAW_VBI_PARAM, API_SLOW), + API_ENTRY(CPU, CX18_CPU_SET_CAPTURE_LINE_NO, 0), + API_ENTRY(CPU, CX18_CPU_SET_COPYRIGHT, 0), + API_ENTRY(CPU, CX18_CPU_SET_AUDIO_PID, 0), + API_ENTRY(CPU, CX18_CPU_SET_VIDEO_PID, 0), + API_ENTRY(CPU, CX18_CPU_SET_VER_CROP_LINE, 0), + API_ENTRY(CPU, CX18_CPU_SET_GOP_STRUCTURE, 0), + API_ENTRY(CPU, CX18_CPU_SET_SCENE_CHANGE_DETECTION, 0), + API_ENTRY(CPU, CX18_CPU_SET_ASPECT_RATIO, 0), + API_ENTRY(CPU, CX18_CPU_SET_SKIP_INPUT_FRAME, 0), + API_ENTRY(CPU, CX18_CPU_SET_SLICED_VBI_PARAM, 0), + API_ENTRY(CPU, CX18_CPU_SET_USERDATA_PLACE_HOLDER, 0), + API_ENTRY(CPU, CX18_CPU_GET_ENC_PTS, 0), + API_ENTRY(CPU, CX18_CPU_DE_SET_MDL_ACK, 0), + API_ENTRY(CPU, CX18_CPU_DE_SET_MDL, API_FAST), + API_ENTRY(0, 0, 0), +}; + +static const struct cx18_api_info *find_api_info(u32 cmd) +{ + int i; + + for (i = 0; api_info[i].cmd; i++) + if (api_info[i].cmd == cmd) + return &api_info[i]; + return NULL; +} + +static struct cx18_mailbox *cx18_mb_is_complete(struct cx18 *cx, int rpu, + u32 *state, u32 *irq, u32 *req) +{ + struct cx18_mailbox *mb = NULL; + int wait_count = 0; + u32 ack; + + switch (rpu) { + case APU: + mb = &cx->scb->epu2apu_mb; + *state = readl(&cx->scb->apu_state); + *irq = readl(&cx->scb->epu2apu_irq); + break; + + case CPU: + mb = &cx->scb->epu2cpu_mb; + *state = readl(&cx->scb->cpu_state); + *irq = readl(&cx->scb->epu2cpu_irq); + break; + + case HPU: + mb = &cx->scb->epu2hpu_mb; + *state = readl(&cx->scb->hpu_state); + *irq = readl(&cx->scb->epu2hpu_irq); + break; + } + + if (mb == NULL) + return mb; + + do { + *req = readl(&mb->request); + ack = readl(&mb->ack); + wait_count++; + } while (*req != ack && wait_count < 600); + + if (*req == ack) { + (*req)++; + if (*req == 0 || *req == 0xffffffff) + *req = 1; + return mb; + } + return NULL; +} + +long cx18_mb_ack(struct cx18 *cx, const struct cx18_mailbox *mb) +{ + const struct cx18_api_info *info = find_api_info(mb->cmd); + struct cx18_mailbox *ack_mb; + u32 ack_irq; + u8 rpu = CPU; + + if (info == NULL && mb->cmd) { + CX18_WARN("Cannot ack unknown command %x\n", mb->cmd); + return -EINVAL; + } + if (info) + rpu = info->rpu; + + switch (rpu) { + case HPU: + ack_irq = IRQ_EPU_TO_HPU_ACK; + ack_mb = &cx->scb->hpu2epu_mb; + break; + case APU: + ack_irq = IRQ_EPU_TO_APU_ACK; + ack_mb = &cx->scb->apu2epu_mb; + break; + case CPU: + ack_irq = IRQ_EPU_TO_CPU_ACK; + ack_mb = &cx->scb->cpu2epu_mb; + break; + default: + CX18_WARN("Unknown RPU for command %x\n", mb->cmd); + return -EINVAL; + } + + setup_page(SCB_OFFSET); + write_sync(mb->request, &ack_mb->ack); + write_reg(ack_irq, SW2_INT_SET); + return 0; +} + + +static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[]) +{ + const struct cx18_api_info *info = find_api_info(cmd); + u32 state = 0, irq = 0, req, oldreq, err; + struct cx18_mailbox *mb; + wait_queue_head_t *waitq; + int timeout = 100; + int cnt = 0; + int sig = 0; + int i; + + if (info == NULL) { + CX18_WARN("unknown cmd %x\n", cmd); + return -EINVAL; + } + + if (cmd == CX18_CPU_DE_SET_MDL) + CX18_DEBUG_HI_API("%s\n", info->name); + else + CX18_DEBUG_API("%s\n", info->name); + setup_page(SCB_OFFSET); + mb = cx18_mb_is_complete(cx, info->rpu, &state, &irq, &req); + + if (mb == NULL) { + CX18_ERR("mb %s busy\n", info->name); + return -EBUSY; + } + + oldreq = req - 1; + writel(cmd, &mb->cmd); + for (i = 0; i < args; i++) + writel(data[i], &mb->args[i]); + writel(0, &mb->error); + writel(req, &mb->request); + + switch (info->rpu) { + case APU: waitq = &cx->mb_apu_waitq; break; + case CPU: waitq = &cx->mb_cpu_waitq; break; + case EPU: waitq = &cx->mb_epu_waitq; break; + case HPU: waitq = &cx->mb_hpu_waitq; break; + default: return -EINVAL; + } + if (info->flags & API_FAST) + timeout /= 2; + write_reg(irq, SW1_INT_SET); + + while (!sig && readl(&mb->ack) != readl(&mb->request) && cnt < 660) { + if (cnt > 200 && !in_atomic()) + sig = cx18_msleep_timeout(10, 1); + cnt++; + } + if (sig) + return -EINTR; + if (cnt == 660) { + writel(oldreq, &mb->request); + CX18_ERR("mb %s failed\n", info->name); + return -EINVAL; + } + for (i = 0; i < MAX_MB_ARGUMENTS; i++) + data[i] = readl(&mb->args[i]); + err = readl(&mb->error); + if (!in_atomic() && (info->flags & API_SLOW)) + cx18_msleep_timeout(300, 0); + if (err) + CX18_DEBUG_API("mailbox error %08x for command %s\n", err, + info->name); + return err ? -EIO : 0; +} + +int cx18_api(struct cx18 *cx, u32 cmd, int args, u32 data[]) +{ + int res = cx18_api_call(cx, cmd, args, data); + + /* Allow a single retry, probably already too late though. + If there is no free mailbox then that is usually an indication + of a more serious problem. */ + return (res == -EBUSY) ? cx18_api_call(cx, cmd, args, data) : res; +} + +static int cx18_set_filter_param(struct cx18_stream *s) +{ + struct cx18 *cx = s->cx; + u32 mode; + int ret; + + mode = (cx->filter_mode & 1) ? 2 : (cx->spatial_strength ? 1 : 0); + ret = cx18_vapi(cx, CX18_CPU_SET_FILTER_PARAM, 4, + s->handle, 1, mode, cx->spatial_strength); + mode = (cx->filter_mode & 2) ? 2 : (cx->temporal_strength ? 1 : 0); + ret = ret ? ret : cx18_vapi(cx, CX18_CPU_SET_FILTER_PARAM, 4, + s->handle, 0, mode, cx->temporal_strength); + ret = ret ? ret : cx18_vapi(cx, CX18_CPU_SET_FILTER_PARAM, 4, + s->handle, 2, cx->filter_mode >> 2, 0); + return ret; +} + +int cx18_api_func(void *priv, u32 cmd, int in, int out, + u32 data[CX2341X_MBOX_MAX_DATA]) +{ + struct cx18 *cx = priv; + struct cx18_stream *s = &cx->streams[CX18_ENC_STREAM_TYPE_MPG]; + + switch (cmd) { + case CX2341X_ENC_SET_OUTPUT_PORT: + return 0; + case CX2341X_ENC_SET_FRAME_RATE: + return cx18_vapi(cx, CX18_CPU_SET_VIDEO_IN, 6, + s->handle, 0, 0, 0, 0, data[0]); + case CX2341X_ENC_SET_FRAME_SIZE: + return cx18_vapi(cx, CX18_CPU_SET_VIDEO_RESOLUTION, 3, + s->handle, data[1], data[0]); + case CX2341X_ENC_SET_STREAM_TYPE: + return cx18_vapi(cx, CX18_CPU_SET_STREAM_OUTPUT_TYPE, 2, + s->handle, data[0]); + case CX2341X_ENC_SET_ASPECT_RATIO: + return cx18_vapi(cx, CX18_CPU_SET_ASPECT_RATIO, 2, + s->handle, data[0]); + + case CX2341X_ENC_SET_GOP_PROPERTIES: + return cx18_vapi(cx, CX18_CPU_SET_GOP_STRUCTURE, 3, + s->handle, data[0], data[1]); + case CX2341X_ENC_SET_GOP_CLOSURE: + return 0; + case CX2341X_ENC_SET_AUDIO_PROPERTIES: + return cx18_vapi(cx, CX18_CPU_SET_AUDIO_PARAMETERS, 2, + s->handle, data[0]); + case CX2341X_ENC_MUTE_AUDIO: + return cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2, + s->handle, data[0]); + case CX2341X_ENC_SET_BIT_RATE: + return cx18_vapi(cx, CX18_CPU_SET_VIDEO_RATE, 5, + s->handle, data[0], data[1], data[2], data[3]); + case CX2341X_ENC_MUTE_VIDEO: + return cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, + s->handle, data[0]); + case CX2341X_ENC_SET_FRAME_DROP_RATE: + return cx18_vapi(cx, CX18_CPU_SET_SKIP_INPUT_FRAME, 2, + s->handle, data[0]); + case CX2341X_ENC_MISC: + return cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 4, + s->handle, data[0], data[1], data[2]); + case CX2341X_ENC_SET_DNR_FILTER_MODE: + cx->filter_mode = (data[0] & 3) | (data[1] << 2); + return cx18_set_filter_param(s); + case CX2341X_ENC_SET_DNR_FILTER_PROPS: + cx->spatial_strength = data[0]; + cx->temporal_strength = data[1]; + return cx18_set_filter_param(s); + case CX2341X_ENC_SET_SPATIAL_FILTER_TYPE: + return cx18_vapi(cx, CX18_CPU_SET_SPATIAL_FILTER_TYPE, 3, + s->handle, data[0], data[1]); + case CX2341X_ENC_SET_CORING_LEVELS: + return cx18_vapi(cx, CX18_CPU_SET_MEDIAN_CORING, 5, + s->handle, data[0], data[1], data[2], data[3]); + } + CX18_WARN("Unknown cmd %x\n", cmd); + return 0; +} + +int cx18_vapi_result(struct cx18 *cx, u32 data[MAX_MB_ARGUMENTS], + u32 cmd, int args, ...) +{ + va_list ap; + int i; + + va_start(ap, args); + for (i = 0; i < args; i++) + data[i] = va_arg(ap, u32); + va_end(ap); + return cx18_api(cx, cmd, args, data); +} + +int cx18_vapi(struct cx18 *cx, u32 cmd, int args, ...) +{ + u32 data[MAX_MB_ARGUMENTS]; + va_list ap; + int i; + + if (cx == NULL) { + CX18_ERR("cx == NULL (cmd=%x)\n", cmd); + return 0; + } + if (args > MAX_MB_ARGUMENTS) { + CX18_ERR("args too big (cmd=%x)\n", cmd); + args = MAX_MB_ARGUMENTS; + } + va_start(ap, args); + for (i = 0; i < args; i++) + data[i] = va_arg(ap, u32); + va_end(ap); + return cx18_api(cx, cmd, args, data); +} diff --git a/drivers/media/video/cx18/cx18-mailbox.h b/drivers/media/video/cx18/cx18-mailbox.h new file mode 100644 index 00000000000..d995641536b --- /dev/null +++ b/drivers/media/video/cx18/cx18-mailbox.h @@ -0,0 +1,73 @@ +/* + * cx18 mailbox functions + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 _CX18_MAILBOX_H_ +#define _CX18_MAILBOX_H_ + +/* mailbox max args */ +#define MAX_MB_ARGUMENTS 6 +/* compatibility, should be same as the define in cx2341x.h */ +#define CX2341X_MBOX_MAX_DATA 16 + +#define MB_RESERVED_HANDLE_0 0 +#define MB_RESERVED_HANDLE_1 0xFFFFFFFF + +struct cx18; + +/* The cx18_mailbox struct is the mailbox structure which is used for passing + messages between processors */ +struct cx18_mailbox { + /* The sender sets a handle in 'request' after he fills the command. The + 'request' should be different than 'ack'. The sender, also, generates + an interrupt on XPU2YPU_irq where XPU is the sender and YPU is the + receiver. */ + u32 request; + /* The receiver detects a new command when 'req' is different than 'ack'. + He sets 'ack' to the same value as 'req' to clear the command. He, also, + generates an interrupt on YPU2XPU_irq where XPU is the sender and YPU + is the receiver. */ + u32 ack; + u32 reserved[6]; + /* 'cmd' identifies the command. The list of these commands are in + cx23418.h */ + u32 cmd; + /* Each command can have up to 6 arguments */ + u32 args[MAX_MB_ARGUMENTS]; + /* The return code can be one of the codes in the file cx23418.h. If the + command is completed successfuly, the error will be ERR_SYS_SUCCESS. + If it is pending, the code is ERR_SYS_PENDING. If it failed, the error + code would indicate the task from which the error originated and will + be one of the errors in cx23418.h. In that case, the following + applies ((error & 0xff) != 0). + If the command is pending, the return will be passed in a MB from the + receiver to the sender. 'req' will be returned in args[0] */ + u32 error; +}; + +int cx18_api(struct cx18 *cx, u32 cmd, int args, u32 data[]); +int cx18_vapi_result(struct cx18 *cx, u32 data[MAX_MB_ARGUMENTS], u32 cmd, + int args, ...); +int cx18_vapi(struct cx18 *cx, u32 cmd, int args, ...); +int cx18_api_func(void *priv, u32 cmd, int in, int out, + u32 data[CX2341X_MBOX_MAX_DATA]); +long cx18_mb_ack(struct cx18 *cx, const struct cx18_mailbox *mb); + +#endif diff --git a/drivers/media/video/cx18/cx18-queue.c b/drivers/media/video/cx18/cx18-queue.c new file mode 100644 index 00000000000..65af1bb507c --- /dev/null +++ b/drivers/media/video/cx18/cx18-queue.c @@ -0,0 +1,282 @@ +/* + * cx18 buffer queues + * + * Derived from ivtv-queue.c + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 "cx18-driver.h" +#include "cx18-streams.h" +#include "cx18-queue.h" +#include "cx18-scb.h" + +int cx18_buf_copy_from_user(struct cx18_stream *s, struct cx18_buffer *buf, + const char __user *src, int copybytes) +{ + if (s->buf_size - buf->bytesused < copybytes) + copybytes = s->buf_size - buf->bytesused; + if (copy_from_user(buf->buf + buf->bytesused, src, copybytes)) + return -EFAULT; + buf->bytesused += copybytes; + return copybytes; +} + +void cx18_buf_swap(struct cx18_buffer *buf) +{ + int i; + + for (i = 0; i < buf->bytesused; i += 4) + swab32s((u32 *)(buf->buf + i)); +} + +void cx18_queue_init(struct cx18_queue *q) +{ + INIT_LIST_HEAD(&q->list); + q->buffers = 0; + q->length = 0; + q->bytesused = 0; +} + +void cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf, + struct cx18_queue *q) +{ + unsigned long flags = 0; + + /* clear the buffer if it is going to be enqueued to the free queue */ + if (q == &s->q_free) { + buf->bytesused = 0; + buf->readpos = 0; + buf->b_flags = 0; + } + spin_lock_irqsave(&s->qlock, flags); + list_add_tail(&buf->list, &q->list); + q->buffers++; + q->length += s->buf_size; + q->bytesused += buf->bytesused - buf->readpos; + spin_unlock_irqrestore(&s->qlock, flags); +} + +struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q) +{ + struct cx18_buffer *buf = NULL; + unsigned long flags = 0; + + spin_lock_irqsave(&s->qlock, flags); + if (!list_empty(&q->list)) { + buf = list_entry(q->list.next, struct cx18_buffer, list); + list_del_init(q->list.next); + q->buffers--; + q->length -= s->buf_size; + q->bytesused -= buf->bytesused - buf->readpos; + } + spin_unlock_irqrestore(&s->qlock, flags); + return buf; +} + +struct cx18_buffer *cx18_queue_find_buf(struct cx18_stream *s, u32 id, + u32 bytesused) +{ + struct cx18 *cx = s->cx; + struct list_head *p; + + list_for_each(p, &s->q_free.list) { + struct cx18_buffer *buf = + list_entry(p, struct cx18_buffer, list); + + if (buf->id != id) + continue; + buf->bytesused = bytesused; + /* the transport buffers are handled differently, + so there is no need to move them to the full queue */ + if (s->type == CX18_ENC_STREAM_TYPE_TS) + return buf; + s->q_free.buffers--; + s->q_free.length -= s->buf_size; + s->q_full.buffers++; + s->q_full.length += s->buf_size; + s->q_full.bytesused += buf->bytesused; + list_move_tail(&buf->list, &s->q_full.list); + return buf; + } + CX18_ERR("Cannot find buffer %d for stream %s\n", id, s->name); + return NULL; +} + +static void cx18_queue_move_buf(struct cx18_stream *s, struct cx18_queue *from, + struct cx18_queue *to, int clear, int full) +{ + struct cx18_buffer *buf = + list_entry(from->list.next, struct cx18_buffer, list); + + list_move_tail(from->list.next, &to->list); + from->buffers--; + from->length -= s->buf_size; + from->bytesused -= buf->bytesused - buf->readpos; + /* special handling for q_free */ + if (clear) + buf->bytesused = buf->readpos = buf->b_flags = 0; + else if (full) { + /* special handling for stolen buffers, assume + all bytes are used. */ + buf->bytesused = s->buf_size; + buf->readpos = buf->b_flags = 0; + } + to->buffers++; + to->length += s->buf_size; + to->bytesused += buf->bytesused - buf->readpos; +} + +/* Move 'needed_bytes' worth of buffers from queue 'from' into queue 'to'. + If 'needed_bytes' == 0, then move all buffers from 'from' into 'to'. + If 'steal' != NULL, then buffers may also taken from that queue if + needed. + + The buffer is automatically cleared if it goes to the free queue. It is + also cleared if buffers need to be taken from the 'steal' queue and + the 'from' queue is the free queue. + + When 'from' is q_free, then needed_bytes is compared to the total + available buffer length, otherwise needed_bytes is compared to the + bytesused value. For the 'steal' queue the total available buffer + length is always used. + + -ENOMEM is returned if the buffers could not be obtained, 0 if all + buffers where obtained from the 'from' list and if non-zero then + the number of stolen buffers is returned. */ +int cx18_queue_move(struct cx18_stream *s, struct cx18_queue *from, + struct cx18_queue *steal, struct cx18_queue *to, int needed_bytes) +{ + unsigned long flags; + int rc = 0; + int from_free = from == &s->q_free; + int to_free = to == &s->q_free; + int bytes_available; + + spin_lock_irqsave(&s->qlock, flags); + if (needed_bytes == 0) { + from_free = 1; + needed_bytes = from->length; + } + + bytes_available = from_free ? from->length : from->bytesused; + bytes_available += steal ? steal->length : 0; + + if (bytes_available < needed_bytes) { + spin_unlock_irqrestore(&s->qlock, flags); + return -ENOMEM; + } + if (from_free) { + u32 old_length = to->length; + + while (to->length - old_length < needed_bytes) { + if (list_empty(&from->list)) + from = steal; + if (from == steal) + rc++; /* keep track of 'stolen' buffers */ + cx18_queue_move_buf(s, from, to, 1, 0); + } + } else { + u32 old_bytesused = to->bytesused; + + while (to->bytesused - old_bytesused < needed_bytes) { + if (list_empty(&from->list)) + from = steal; + if (from == steal) + rc++; /* keep track of 'stolen' buffers */ + cx18_queue_move_buf(s, from, to, to_free, rc); + } + } + spin_unlock_irqrestore(&s->qlock, flags); + return rc; +} + +void cx18_flush_queues(struct cx18_stream *s) +{ + cx18_queue_move(s, &s->q_io, NULL, &s->q_free, 0); + cx18_queue_move(s, &s->q_full, NULL, &s->q_free, 0); +} + +int cx18_stream_alloc(struct cx18_stream *s) +{ + struct cx18 *cx = s->cx; + int i; + + if (s->buffers == 0) + return 0; + + CX18_DEBUG_INFO("Allocate %s stream: %d x %d buffers (%dkB total)\n", + s->name, s->buffers, s->buf_size, + s->buffers * s->buf_size / 1024); + + if (((char *)&cx->scb->cpu_mdl[cx->mdl_offset + s->buffers] - + (char *)cx->scb) > SCB_RESERVED_SIZE) { + unsigned bufsz = (((char *)cx->scb) + SCB_RESERVED_SIZE - + ((char *)cx->scb->cpu_mdl)); + + CX18_ERR("Too many buffers, cannot fit in SCB area\n"); + CX18_ERR("Max buffers = %zd\n", + bufsz / sizeof(struct cx18_mdl)); + return -ENOMEM; + } + + s->mdl_offset = cx->mdl_offset; + + /* allocate stream buffers. Initially all buffers are in q_free. */ + for (i = 0; i < s->buffers; i++) { + struct cx18_buffer *buf = + kzalloc(sizeof(struct cx18_buffer), GFP_KERNEL); + + if (buf == NULL) + break; + buf->buf = kmalloc(s->buf_size, GFP_KERNEL); + if (buf->buf == NULL) { + kfree(buf); + break; + } + buf->id = cx->buffer_id++; + INIT_LIST_HEAD(&buf->list); + buf->dma_handle = pci_map_single(s->cx->dev, + buf->buf, s->buf_size, s->dma); + cx18_buf_sync_for_cpu(s, buf); + cx18_enqueue(s, buf, &s->q_free); + } + if (i == s->buffers) { + cx->mdl_offset += s->buffers; + return 0; + } + CX18_ERR("Couldn't allocate buffers for %s stream\n", s->name); + cx18_stream_free(s); + return -ENOMEM; +} + +void cx18_stream_free(struct cx18_stream *s) +{ + struct cx18_buffer *buf; + + /* move all buffers to q_free */ + cx18_flush_queues(s); + + /* empty q_free */ + while ((buf = cx18_dequeue(s, &s->q_free))) { + pci_unmap_single(s->cx->dev, buf->dma_handle, + s->buf_size, s->dma); + kfree(buf->buf); + kfree(buf); + } +} diff --git a/drivers/media/video/cx18/cx18-queue.h b/drivers/media/video/cx18/cx18-queue.h new file mode 100644 index 00000000000..f86c8a6fa6e --- /dev/null +++ b/drivers/media/video/cx18/cx18-queue.h @@ -0,0 +1,59 @@ +/* + * cx18 buffer queues + * + * Derived from ivtv-queue.h + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 + */ + +#define CX18_DMA_UNMAPPED ((u32) -1) + +/* cx18_buffer utility functions */ + +static inline void cx18_buf_sync_for_cpu(struct cx18_stream *s, + struct cx18_buffer *buf) +{ + pci_dma_sync_single_for_cpu(s->cx->dev, buf->dma_handle, + s->buf_size, s->dma); +} + +static inline void cx18_buf_sync_for_device(struct cx18_stream *s, + struct cx18_buffer *buf) +{ + pci_dma_sync_single_for_device(s->cx->dev, buf->dma_handle, + s->buf_size, s->dma); +} + +int cx18_buf_copy_from_user(struct cx18_stream *s, struct cx18_buffer *buf, + const char __user *src, int copybytes); +void cx18_buf_swap(struct cx18_buffer *buf); + +/* cx18_queue utility functions */ +void cx18_queue_init(struct cx18_queue *q); +void cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf, + struct cx18_queue *q); +struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q); +int cx18_queue_move(struct cx18_stream *s, struct cx18_queue *from, + struct cx18_queue *steal, struct cx18_queue *to, int needed_bytes); +struct cx18_buffer *cx18_queue_find_buf(struct cx18_stream *s, u32 id, + u32 bytesused); +void cx18_flush_queues(struct cx18_stream *s); + +/* cx18_stream utility functions */ +int cx18_stream_alloc(struct cx18_stream *s); +void cx18_stream_free(struct cx18_stream *s); diff --git a/drivers/media/video/cx18/cx18-scb.c b/drivers/media/video/cx18/cx18-scb.c new file mode 100644 index 00000000000..30bc803e30d --- /dev/null +++ b/drivers/media/video/cx18/cx18-scb.c @@ -0,0 +1,121 @@ +/* + * cx18 System Control Block initialization + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 "cx18-driver.h" +#include "cx18-scb.h" + +void cx18_init_scb(struct cx18 *cx) +{ + setup_page(SCB_OFFSET); + memset_io(cx->scb, 0, 0x10000); + + writel(IRQ_APU_TO_CPU, &cx->scb->apu2cpu_irq); + writel(IRQ_CPU_TO_APU_ACK, &cx->scb->cpu2apu_irq_ack); + writel(IRQ_HPU_TO_CPU, &cx->scb->hpu2cpu_irq); + writel(IRQ_CPU_TO_HPU_ACK, &cx->scb->cpu2hpu_irq_ack); + writel(IRQ_PPU_TO_CPU, &cx->scb->ppu2cpu_irq); + writel(IRQ_CPU_TO_PPU_ACK, &cx->scb->cpu2ppu_irq_ack); + writel(IRQ_EPU_TO_CPU, &cx->scb->epu2cpu_irq); + writel(IRQ_CPU_TO_EPU_ACK, &cx->scb->cpu2epu_irq_ack); + + writel(IRQ_CPU_TO_APU, &cx->scb->cpu2apu_irq); + writel(IRQ_APU_TO_CPU_ACK, &cx->scb->apu2cpu_irq_ack); + writel(IRQ_HPU_TO_APU, &cx->scb->hpu2apu_irq); + writel(IRQ_APU_TO_HPU_ACK, &cx->scb->apu2hpu_irq_ack); + writel(IRQ_PPU_TO_APU, &cx->scb->ppu2apu_irq); + writel(IRQ_APU_TO_PPU_ACK, &cx->scb->apu2ppu_irq_ack); + writel(IRQ_EPU_TO_APU, &cx->scb->epu2apu_irq); + writel(IRQ_APU_TO_EPU_ACK, &cx->scb->apu2epu_irq_ack); + + writel(IRQ_CPU_TO_HPU, &cx->scb->cpu2hpu_irq); + writel(IRQ_HPU_TO_CPU_ACK, &cx->scb->hpu2cpu_irq_ack); + writel(IRQ_APU_TO_HPU, &cx->scb->apu2hpu_irq); + writel(IRQ_HPU_TO_APU_ACK, &cx->scb->hpu2apu_irq_ack); + writel(IRQ_PPU_TO_HPU, &cx->scb->ppu2hpu_irq); + writel(IRQ_HPU_TO_PPU_ACK, &cx->scb->hpu2ppu_irq_ack); + writel(IRQ_EPU_TO_HPU, &cx->scb->epu2hpu_irq); + writel(IRQ_HPU_TO_EPU_ACK, &cx->scb->hpu2epu_irq_ack); + + writel(IRQ_CPU_TO_PPU, &cx->scb->cpu2ppu_irq); + writel(IRQ_PPU_TO_CPU_ACK, &cx->scb->ppu2cpu_irq_ack); + writel(IRQ_APU_TO_PPU, &cx->scb->apu2ppu_irq); + writel(IRQ_PPU_TO_APU_ACK, &cx->scb->ppu2apu_irq_ack); + writel(IRQ_HPU_TO_PPU, &cx->scb->hpu2ppu_irq); + writel(IRQ_PPU_TO_HPU_ACK, &cx->scb->ppu2hpu_irq_ack); + writel(IRQ_EPU_TO_PPU, &cx->scb->epu2ppu_irq); + writel(IRQ_PPU_TO_EPU_ACK, &cx->scb->ppu2epu_irq_ack); + + writel(IRQ_CPU_TO_EPU, &cx->scb->cpu2epu_irq); + writel(IRQ_EPU_TO_CPU_ACK, &cx->scb->epu2cpu_irq_ack); + writel(IRQ_APU_TO_EPU, &cx->scb->apu2epu_irq); + writel(IRQ_EPU_TO_APU_ACK, &cx->scb->epu2apu_irq_ack); + writel(IRQ_HPU_TO_EPU, &cx->scb->hpu2epu_irq); + writel(IRQ_EPU_TO_HPU_ACK, &cx->scb->epu2hpu_irq_ack); + writel(IRQ_PPU_TO_EPU, &cx->scb->ppu2epu_irq); + writel(IRQ_EPU_TO_PPU_ACK, &cx->scb->epu2ppu_irq_ack); + + writel(SCB_OFFSET + offsetof(struct cx18_scb, apu2cpu_mb), + &cx->scb->apu2cpu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, hpu2cpu_mb), + &cx->scb->hpu2cpu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, ppu2cpu_mb), + &cx->scb->ppu2cpu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, epu2cpu_mb), + &cx->scb->epu2cpu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, cpu2apu_mb), + &cx->scb->cpu2apu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, hpu2apu_mb), + &cx->scb->hpu2apu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, ppu2apu_mb), + &cx->scb->ppu2apu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, epu2apu_mb), + &cx->scb->epu2apu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, cpu2hpu_mb), + &cx->scb->cpu2hpu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, apu2hpu_mb), + &cx->scb->apu2hpu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, ppu2hpu_mb), + &cx->scb->ppu2hpu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, epu2hpu_mb), + &cx->scb->epu2hpu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, cpu2ppu_mb), + &cx->scb->cpu2ppu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, apu2ppu_mb), + &cx->scb->apu2ppu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, hpu2ppu_mb), + &cx->scb->hpu2ppu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, epu2ppu_mb), + &cx->scb->epu2ppu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, cpu2epu_mb), + &cx->scb->cpu2epu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, apu2epu_mb), + &cx->scb->apu2epu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, hpu2epu_mb), + &cx->scb->hpu2epu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, ppu2epu_mb), + &cx->scb->ppu2epu_mb_offset); + + writel(SCB_OFFSET + offsetof(struct cx18_scb, cpu_state), + &cx->scb->ipc_offset); + + writel(1, &cx->scb->hpu_state); + writel(1, &cx->scb->epu_state); +} diff --git a/drivers/media/video/cx18/cx18-scb.h b/drivers/media/video/cx18/cx18-scb.h new file mode 100644 index 00000000000..86b4cb15d16 --- /dev/null +++ b/drivers/media/video/cx18/cx18-scb.h @@ -0,0 +1,285 @@ +/* + * cx18 System Control Block initialization + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 CX18_SCB_H +#define CX18_SCB_H + +#include "cx18-mailbox.h" + +/* NOTE: All ACK interrupts are in the SW2 register. All non-ACK interrupts + are in the SW1 register. */ + +#define IRQ_APU_TO_CPU 0x00000001 +#define IRQ_CPU_TO_APU_ACK 0x00000001 +#define IRQ_HPU_TO_CPU 0x00000002 +#define IRQ_CPU_TO_HPU_ACK 0x00000002 +#define IRQ_PPU_TO_CPU 0x00000004 +#define IRQ_CPU_TO_PPU_ACK 0x00000004 +#define IRQ_EPU_TO_CPU 0x00000008 +#define IRQ_CPU_TO_EPU_ACK 0x00000008 + +#define IRQ_CPU_TO_APU 0x00000010 +#define IRQ_APU_TO_CPU_ACK 0x00000010 +#define IRQ_HPU_TO_APU 0x00000020 +#define IRQ_APU_TO_HPU_ACK 0x00000020 +#define IRQ_PPU_TO_APU 0x00000040 +#define IRQ_APU_TO_PPU_ACK 0x00000040 +#define IRQ_EPU_TO_APU 0x00000080 +#define IRQ_APU_TO_EPU_ACK 0x00000080 + +#define IRQ_CPU_TO_HPU 0x00000100 +#define IRQ_HPU_TO_CPU_ACK 0x00000100 +#define IRQ_APU_TO_HPU 0x00000200 +#define IRQ_HPU_TO_APU_ACK 0x00000200 +#define IRQ_PPU_TO_HPU 0x00000400 +#define IRQ_HPU_TO_PPU_ACK 0x00000400 +#define IRQ_EPU_TO_HPU 0x00000800 +#define IRQ_HPU_TO_EPU_ACK 0x00000800 + +#define IRQ_CPU_TO_PPU 0x00001000 +#define IRQ_PPU_TO_CPU_ACK 0x00001000 +#define IRQ_APU_TO_PPU 0x00002000 +#define IRQ_PPU_TO_APU_ACK 0x00002000 +#define IRQ_HPU_TO_PPU 0x00004000 +#define IRQ_PPU_TO_HPU_ACK 0x00004000 +#define IRQ_EPU_TO_PPU 0x00008000 +#define IRQ_PPU_TO_EPU_ACK 0x00008000 + +#define IRQ_CPU_TO_EPU 0x00010000 +#define IRQ_EPU_TO_CPU_ACK 0x00010000 +#define IRQ_APU_TO_EPU 0x00020000 +#define IRQ_EPU_TO_APU_ACK 0x00020000 +#define IRQ_HPU_TO_EPU 0x00040000 +#define IRQ_EPU_TO_HPU_ACK 0x00040000 +#define IRQ_PPU_TO_EPU 0x00080000 +#define IRQ_EPU_TO_PPU_ACK 0x00080000 + +#define SCB_OFFSET 0xDC0000 + +/* If Firmware uses fixed memory map, it shall not allocate the area + between SCB_OFFSET and SCB_OFFSET+SCB_RESERVED_SIZE-1 inclusive */ +#define SCB_RESERVED_SIZE 0x10000 + + +/* This structure is used by EPU to provide memory descriptors in its memory */ +struct cx18_mdl { + u32 paddr; /* Physical address of a buffer segment */ + u32 length; /* Length of the buffer segment */ +}; + +/* This structure is used by CPU to provide completed buffers information */ +struct cx18_mdl_ack { + u32 id; /* ID of a completed MDL */ + u32 data_used; /* Total data filled in the MDL for buffer 'id' */ +}; + +struct cx18_scb { + /* These fields form the System Control Block which is used at boot time + for localizing the IPC data as well as the code positions for all + processors. The offsets are from the start of this struct. */ + + /* Offset where to find the Inter-Processor Communication data */ + u32 ipc_offset; + u32 reserved01[7]; + /* Offset where to find the start of the CPU code */ + u32 cpu_code_offset; + u32 reserved02[3]; + /* Offset where to find the start of the APU code */ + u32 apu_code_offset; + u32 reserved03[3]; + /* Offset where to find the start of the HPU code */ + u32 hpu_code_offset; + u32 reserved04[3]; + /* Offset where to find the start of the PPU code */ + u32 ppu_code_offset; + u32 reserved05[3]; + + /* These fields form Inter-Processor Communication data which is used + by all processors to locate the information needed for communicating + with other processors */ + + /* Fields for CPU: */ + + /* bit 0: 1/0 processor ready/not ready. Set other bits to 0. */ + u32 cpu_state; + u32 reserved1[7]; + /* Offset to the mailbox used for sending commands from APU to CPU */ + u32 apu2cpu_mb_offset; + /* Value to write to register SW1 register set (0xC7003100) after the + command is ready */ + u32 apu2cpu_irq; + /* Value to write to register SW2 register set (0xC7003140) after the + command is cleared */ + u32 apu2cpu_irq_ack; + u32 reserved2[13]; + + u32 hpu2cpu_mb_offset; + u32 hpu2cpu_irq; + u32 hpu2cpu_irq_ack; + u32 reserved3[13]; + + u32 ppu2cpu_mb_offset; + u32 ppu2cpu_irq; + u32 ppu2cpu_irq_ack; + u32 reserved4[13]; + + u32 epu2cpu_mb_offset; + u32 epu2cpu_irq; + u32 epu2cpu_irq_ack; + u32 reserved5[13]; + u32 reserved6[8]; + + /* Fields for APU: */ + + u32 apu_state; + u32 reserved11[7]; + u32 cpu2apu_mb_offset; + u32 cpu2apu_irq; + u32 cpu2apu_irq_ack; + u32 reserved12[13]; + + u32 hpu2apu_mb_offset; + u32 hpu2apu_irq; + u32 hpu2apu_irq_ack; + u32 reserved13[13]; + + u32 ppu2apu_mb_offset; + u32 ppu2apu_irq; + u32 ppu2apu_irq_ack; + u32 reserved14[13]; + + u32 epu2apu_mb_offset; + u32 epu2apu_irq; + u32 epu2apu_irq_ack; + u32 reserved15[13]; + u32 reserved16[8]; + + /* Fields for HPU: */ + + u32 hpu_state; + u32 reserved21[7]; + u32 cpu2hpu_mb_offset; + u32 cpu2hpu_irq; + u32 cpu2hpu_irq_ack; + u32 reserved22[13]; + + u32 apu2hpu_mb_offset; + u32 apu2hpu_irq; + u32 apu2hpu_irq_ack; + u32 reserved23[13]; + + u32 ppu2hpu_mb_offset; + u32 ppu2hpu_irq; + u32 ppu2hpu_irq_ack; + u32 reserved24[13]; + + u32 epu2hpu_mb_offset; + u32 epu2hpu_irq; + u32 epu2hpu_irq_ack; + u32 reserved25[13]; + u32 reserved26[8]; + + /* Fields for PPU: */ + + u32 ppu_state; + u32 reserved31[7]; + u32 cpu2ppu_mb_offset; + u32 cpu2ppu_irq; + u32 cpu2ppu_irq_ack; + u32 reserved32[13]; + + u32 apu2ppu_mb_offset; + u32 apu2ppu_irq; + u32 apu2ppu_irq_ack; + u32 reserved33[13]; + + u32 hpu2ppu_mb_offset; + u32 hpu2ppu_irq; + u32 hpu2ppu_irq_ack; + u32 reserved34[13]; + + u32 epu2ppu_mb_offset; + u32 epu2ppu_irq; + u32 epu2ppu_irq_ack; + u32 reserved35[13]; + u32 reserved36[8]; + + /* Fields for EPU: */ + + u32 epu_state; + u32 reserved41[7]; + u32 cpu2epu_mb_offset; + u32 cpu2epu_irq; + u32 cpu2epu_irq_ack; + u32 reserved42[13]; + + u32 apu2epu_mb_offset; + u32 apu2epu_irq; + u32 apu2epu_irq_ack; + u32 reserved43[13]; + + u32 hpu2epu_mb_offset; + u32 hpu2epu_irq; + u32 hpu2epu_irq_ack; + u32 reserved44[13]; + + u32 ppu2epu_mb_offset; + u32 ppu2epu_irq; + u32 ppu2epu_irq_ack; + u32 reserved45[13]; + u32 reserved46[8]; + + u32 semaphores[8]; /* Semaphores */ + + u32 reserved50[32]; /* Reserved for future use */ + + struct cx18_mailbox apu2cpu_mb; + struct cx18_mailbox hpu2cpu_mb; + struct cx18_mailbox ppu2cpu_mb; + struct cx18_mailbox epu2cpu_mb; + + struct cx18_mailbox cpu2apu_mb; + struct cx18_mailbox hpu2apu_mb; + struct cx18_mailbox ppu2apu_mb; + struct cx18_mailbox epu2apu_mb; + + struct cx18_mailbox cpu2hpu_mb; + struct cx18_mailbox apu2hpu_mb; + struct cx18_mailbox ppu2hpu_mb; + struct cx18_mailbox epu2hpu_mb; + + struct cx18_mailbox cpu2ppu_mb; + struct cx18_mailbox apu2ppu_mb; + struct cx18_mailbox hpu2ppu_mb; + struct cx18_mailbox epu2ppu_mb; + + struct cx18_mailbox cpu2epu_mb; + struct cx18_mailbox apu2epu_mb; + struct cx18_mailbox hpu2epu_mb; + struct cx18_mailbox ppu2epu_mb; + + struct cx18_mdl_ack cpu_mdl_ack[CX18_MAX_STREAMS][2]; + struct cx18_mdl cpu_mdl[1]; +}; + +void cx18_init_scb(struct cx18 *cx); + +#endif diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c new file mode 100644 index 00000000000..afb141b2027 --- /dev/null +++ b/drivers/media/video/cx18/cx18-streams.c @@ -0,0 +1,566 @@ +/* + * cx18 init/start/stop/exit stream functions + * + * Derived from ivtv-streams.c + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 "cx18-driver.h" +#include "cx18-fileops.h" +#include "cx18-mailbox.h" +#include "cx18-i2c.h" +#include "cx18-queue.h" +#include "cx18-ioctl.h" +#include "cx18-streams.h" +#include "cx18-cards.h" +#include "cx18-scb.h" +#include "cx18-av-core.h" +#include "cx18-dvb.h" + +#define CX18_DSP0_INTERRUPT_MASK 0xd0004C + +static struct file_operations cx18_v4l2_enc_fops = { + .owner = THIS_MODULE, + .read = cx18_v4l2_read, + .open = cx18_v4l2_open, + .ioctl = cx18_v4l2_ioctl, + .release = cx18_v4l2_close, + .poll = cx18_v4l2_enc_poll, +}; + +/* offset from 0 to register ts v4l2 minors on */ +#define CX18_V4L2_ENC_TS_OFFSET 16 +/* offset from 0 to register pcm v4l2 minors on */ +#define CX18_V4L2_ENC_PCM_OFFSET 24 +/* offset from 0 to register yuv v4l2 minors on */ +#define CX18_V4L2_ENC_YUV_OFFSET 32 + +static struct { + const char *name; + int vfl_type; + int minor_offset; + int dma; + enum v4l2_buf_type buf_type; + struct file_operations *fops; +} cx18_stream_info[] = { + { /* CX18_ENC_STREAM_TYPE_MPG */ + "encoder MPEG", + VFL_TYPE_GRABBER, 0, + PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VIDEO_CAPTURE, + &cx18_v4l2_enc_fops + }, + { /* CX18_ENC_STREAM_TYPE_TS */ + "TS", + VFL_TYPE_GRABBER, -1, + PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VIDEO_CAPTURE, + &cx18_v4l2_enc_fops + }, + { /* CX18_ENC_STREAM_TYPE_YUV */ + "encoder YUV", + VFL_TYPE_GRABBER, CX18_V4L2_ENC_YUV_OFFSET, + PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VIDEO_CAPTURE, + &cx18_v4l2_enc_fops + }, + { /* CX18_ENC_STREAM_TYPE_VBI */ + "encoder VBI", + VFL_TYPE_VBI, 0, + PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VBI_CAPTURE, + &cx18_v4l2_enc_fops + }, + { /* CX18_ENC_STREAM_TYPE_PCM */ + "encoder PCM audio", + VFL_TYPE_GRABBER, CX18_V4L2_ENC_PCM_OFFSET, + PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_PRIVATE, + &cx18_v4l2_enc_fops + }, + { /* CX18_ENC_STREAM_TYPE_IDX */ + "encoder IDX", + VFL_TYPE_GRABBER, -1, + PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VIDEO_CAPTURE, + &cx18_v4l2_enc_fops + }, + { /* CX18_ENC_STREAM_TYPE_RAD */ + "encoder radio", + VFL_TYPE_RADIO, 0, + PCI_DMA_NONE, V4L2_BUF_TYPE_PRIVATE, + &cx18_v4l2_enc_fops + }, +}; + +static void cx18_stream_init(struct cx18 *cx, int type) +{ + struct cx18_stream *s = &cx->streams[type]; + struct video_device *dev = s->v4l2dev; + u32 max_size = cx->options.megabytes[type] * 1024 * 1024; + + /* we need to keep v4l2dev, so restore it afterwards */ + memset(s, 0, sizeof(*s)); + s->v4l2dev = dev; + + /* initialize cx18_stream fields */ + s->cx = cx; + s->type = type; + s->name = cx18_stream_info[type].name; + s->handle = 0xffffffff; + + s->dma = cx18_stream_info[type].dma; + s->buf_size = cx->stream_buf_size[type]; + if (s->buf_size) + s->buffers = max_size / s->buf_size; + if (s->buffers > 63) { + /* Each stream has a maximum of 63 buffers, + ensure we do not exceed that. */ + s->buffers = 63; + s->buf_size = (max_size / s->buffers) & ~0xfff; + } + spin_lock_init(&s->qlock); + init_waitqueue_head(&s->waitq); + s->id = -1; + cx18_queue_init(&s->q_free); + cx18_queue_init(&s->q_full); + cx18_queue_init(&s->q_io); +} + +static int cx18_prep_dev(struct cx18 *cx, int type) +{ + struct cx18_stream *s = &cx->streams[type]; + u32 cap = cx->v4l2_cap; + int minor_offset = cx18_stream_info[type].minor_offset; + int minor; + + /* These four fields are always initialized. If v4l2dev == NULL, then + this stream is not in use. In that case no other fields but these + four can be used. */ + s->v4l2dev = NULL; + s->cx = cx; + s->type = type; + s->name = cx18_stream_info[type].name; + + /* Check whether the radio is supported */ + if (type == CX18_ENC_STREAM_TYPE_RAD && !(cap & V4L2_CAP_RADIO)) + return 0; + + /* Check whether VBI is supported */ + if (type == CX18_ENC_STREAM_TYPE_VBI && + !(cap & (V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE))) + return 0; + + /* card number + user defined offset + device offset */ + minor = cx->num + cx18_first_minor + minor_offset; + + /* User explicitly selected 0 buffers for these streams, so don't + create them. */ + if (cx18_stream_info[type].dma != PCI_DMA_NONE && + cx->options.megabytes[type] == 0) { + CX18_INFO("Disabled %s device\n", cx18_stream_info[type].name); + return 0; + } + + cx18_stream_init(cx, type); + + if (minor_offset == -1) + return 0; + + /* allocate and initialize the v4l2 video device structure */ + s->v4l2dev = video_device_alloc(); + if (s->v4l2dev == NULL) { + CX18_ERR("Couldn't allocate v4l2 video_device for %s\n", + s->name); + return -ENOMEM; + } + + s->v4l2dev->type = + VID_TYPE_CAPTURE | VID_TYPE_TUNER | VID_TYPE_TELETEXT | + VID_TYPE_CLIPPING | VID_TYPE_SCALES | VID_TYPE_MPEG_ENCODER; + snprintf(s->v4l2dev->name, sizeof(s->v4l2dev->name), "cx18%d %s", + cx->num, s->name); + + s->v4l2dev->minor = minor; + s->v4l2dev->dev = &cx->dev->dev; + s->v4l2dev->fops = cx18_stream_info[type].fops; + s->v4l2dev->release = video_device_release; + + return 0; +} + +/* Initialize v4l2 variables and register v4l2 devices */ +int cx18_streams_setup(struct cx18 *cx) +{ + int type; + + /* Setup V4L2 Devices */ + for (type = 0; type < CX18_MAX_STREAMS; type++) { + /* Prepare device */ + if (cx18_prep_dev(cx, type)) + break; + + /* Allocate Stream */ + if (cx18_stream_alloc(&cx->streams[type])) + break; + } + if (type == CX18_MAX_STREAMS) + return 0; + + /* One or more streams could not be initialized. Clean 'em all up. */ + cx18_streams_cleanup(cx); + return -ENOMEM; +} + +static int cx18_reg_dev(struct cx18 *cx, int type) +{ + struct cx18_stream *s = &cx->streams[type]; + int vfl_type = cx18_stream_info[type].vfl_type; + int minor; + + /* TODO: Shouldn't this be a VFL_TYPE_TRANSPORT or something? + * We need a VFL_TYPE_TS defined. + */ + if (strcmp("TS", s->name) == 0) { + /* just return if no DVB is supported */ + if ((cx->card->hw_all & CX18_HW_DVB) == 0) + return 0; + if (cx18_dvb_register(s) < 0) { + CX18_ERR("DVB failed to register\n"); + return -EINVAL; + } + } + + if (s->v4l2dev == NULL) + return 0; + + minor = s->v4l2dev->minor; + + /* Register device. First try the desired minor, then any free one. */ + if (video_register_device(s->v4l2dev, vfl_type, minor) && + video_register_device(s->v4l2dev, vfl_type, -1)) { + CX18_ERR("Couldn't register v4l2 device for %s minor %d\n", + s->name, minor); + video_device_release(s->v4l2dev); + s->v4l2dev = NULL; + return -ENOMEM; + } + minor = s->v4l2dev->minor; + + switch (vfl_type) { + case VFL_TYPE_GRABBER: + CX18_INFO("Registered device video%d for %s (%d MB)\n", + minor, s->name, cx->options.megabytes[type]); + break; + + case VFL_TYPE_RADIO: + CX18_INFO("Registered device radio%d for %s\n", + minor - MINOR_VFL_TYPE_RADIO_MIN, s->name); + break; + + case VFL_TYPE_VBI: + if (cx->options.megabytes[type]) + CX18_INFO("Registered device vbi%d for %s (%d MB)\n", + minor - MINOR_VFL_TYPE_VBI_MIN, + s->name, cx->options.megabytes[type]); + else + CX18_INFO("Registered device vbi%d for %s\n", + minor - MINOR_VFL_TYPE_VBI_MIN, s->name); + break; + } + + return 0; +} + +/* Register v4l2 devices */ +int cx18_streams_register(struct cx18 *cx) +{ + int type; + int err = 0; + + /* Register V4L2 devices */ + for (type = 0; type < CX18_MAX_STREAMS; type++) + err |= cx18_reg_dev(cx, type); + + if (err == 0) + return 0; + + /* One or more streams could not be initialized. Clean 'em all up. */ + cx18_streams_cleanup(cx); + return -ENOMEM; +} + +/* Unregister v4l2 devices */ +void cx18_streams_cleanup(struct cx18 *cx) +{ + struct video_device *vdev; + int type; + + /* Teardown all streams */ + for (type = 0; type < CX18_MAX_STREAMS; type++) { + if (cx->streams[type].dvb.enabled) + cx18_dvb_unregister(&cx->streams[type]); + + vdev = cx->streams[type].v4l2dev; + + cx->streams[type].v4l2dev = NULL; + if (vdev == NULL) + continue; + + cx18_stream_free(&cx->streams[type]); + + /* Unregister device */ + video_unregister_device(vdev); + } +} + +static void cx18_vbi_setup(struct cx18_stream *s) +{ + struct cx18 *cx = s->cx; + int raw = cx->vbi.sliced_in->service_set == 0; + u32 data[CX2341X_MBOX_MAX_DATA]; + int lines; + + if (cx->is_60hz) { + cx->vbi.count = 12; + cx->vbi.start[0] = 10; + cx->vbi.start[1] = 273; + } else { /* PAL/SECAM */ + cx->vbi.count = 18; + cx->vbi.start[0] = 6; + cx->vbi.start[1] = 318; + } + + /* setup VBI registers */ + cx18_av_cmd(cx, VIDIOC_S_FMT, &cx->vbi.in); + + /* determine number of lines and total number of VBI bytes. + A raw line takes 1443 bytes: 2 * 720 + 4 byte frame header - 1 + The '- 1' byte is probably an unused U or V byte. Or something... + A sliced line takes 51 bytes: 4 byte frame header, 4 byte internal + header, 42 data bytes + checksum (to be confirmed) */ + if (raw) { + lines = cx->vbi.count * 2; + } else { + lines = cx->is_60hz ? 24 : 38; + if (cx->is_60hz) + lines += 2; + } + + cx->vbi.enc_size = lines * + (raw ? cx->vbi.raw_size : cx->vbi.sliced_size); + + data[0] = s->handle; + /* Lines per field */ + data[1] = (lines / 2) | ((lines / 2) << 16); + /* bytes per line */ + data[2] = (raw ? cx->vbi.raw_size : cx->vbi.sliced_size); + /* Every X number of frames a VBI interrupt arrives + (frames as in 25 or 30 fps) */ + data[3] = 1; + /* Setup VBI for the cx25840 digitizer */ + if (raw) { + data[4] = 0x20602060; + data[5] = 0x30703070; + } else { + data[4] = 0xB0F0B0F0; + data[5] = 0xA0E0A0E0; + } + + CX18_DEBUG_INFO("Setup VBI h: %d lines %x bpl %d fr %d %x %x\n", + data[0], data[1], data[2], data[3], data[4], data[5]); + + if (s->type == CX18_ENC_STREAM_TYPE_VBI) + cx18_api(cx, CX18_CPU_SET_RAW_VBI_PARAM, 6, data); +} + +int cx18_start_v4l2_encode_stream(struct cx18_stream *s) +{ + u32 data[MAX_MB_ARGUMENTS]; + struct cx18 *cx = s->cx; + struct list_head *p; + int ts = 0; + int captype = 0; + + if (s->v4l2dev == NULL && s->dvb.enabled == 0) + return -EINVAL; + + CX18_DEBUG_INFO("Start encoder stream %s\n", s->name); + + switch (s->type) { + case CX18_ENC_STREAM_TYPE_MPG: + captype = CAPTURE_CHANNEL_TYPE_MPEG; + cx->mpg_data_received = cx->vbi_data_inserted = 0; + cx->dualwatch_jiffies = jiffies; + cx->dualwatch_stereo_mode = cx->params.audio_properties & 0x300; + cx->search_pack_header = 0; + break; + + case CX18_ENC_STREAM_TYPE_TS: + captype = CAPTURE_CHANNEL_TYPE_TS; + ts = 1; + break; + case CX18_ENC_STREAM_TYPE_YUV: + captype = CAPTURE_CHANNEL_TYPE_YUV; + break; + case CX18_ENC_STREAM_TYPE_PCM: + captype = CAPTURE_CHANNEL_TYPE_PCM; + break; + case CX18_ENC_STREAM_TYPE_VBI: + captype = cx->vbi.sliced_in->service_set ? + CAPTURE_CHANNEL_TYPE_SLICED_VBI : CAPTURE_CHANNEL_TYPE_VBI; + cx->vbi.frame = 0; + cx->vbi.inserted_frame = 0; + memset(cx->vbi.sliced_mpeg_size, + 0, sizeof(cx->vbi.sliced_mpeg_size)); + break; + default: + return -EINVAL; + } + s->buffers_stolen = 0; + + /* mute/unmute video */ + cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, + s->handle, !!test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)); + + /* Clear Streamoff flags in case left from last capture */ + clear_bit(CX18_F_S_STREAMOFF, &s->s_flags); + + cx18_vapi_result(cx, data, CX18_CREATE_TASK, 1, CPU_CMD_MASK_CAPTURE); + s->handle = data[0]; + cx18_vapi(cx, CX18_CPU_SET_CHANNEL_TYPE, 2, s->handle, captype); + + if (atomic_read(&cx->capturing) == 0 && !ts) { + /* Stuff from Windows, we don't know what it is */ + cx18_vapi(cx, CX18_CPU_SET_VER_CROP_LINE, 2, s->handle, 0); + cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 3, 1); + cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 8, 0); + cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 4, 1); + cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 2, s->handle, 12); + + cx18_vapi(cx, CX18_CPU_SET_CAPTURE_LINE_NO, 3, + s->handle, cx->digitizer, cx->digitizer); + + /* Setup VBI */ + if (cx->v4l2_cap & V4L2_CAP_VBI_CAPTURE) + cx18_vbi_setup(s); + + /* assign program index info. + Mask 7: select I/P/B, Num_req: 400 max */ + cx18_vapi_result(cx, data, CX18_CPU_SET_INDEXTABLE, 1, 0); + + /* Setup API for Stream */ + cx2341x_update(cx, cx18_api_func, NULL, &cx->params); + } + + if (atomic_read(&cx->capturing) == 0) { + clear_bit(CX18_F_I_EOS, &cx->i_flags); + write_reg(7, CX18_DSP0_INTERRUPT_MASK); + } + + cx18_vapi(cx, CX18_CPU_DE_SET_MDL_ACK, 3, s->handle, + (void *)&cx->scb->cpu_mdl_ack[s->type][0] - cx->enc_mem, + (void *)&cx->scb->cpu_mdl_ack[s->type][1] - cx->enc_mem); + + list_for_each(p, &s->q_free.list) { + struct cx18_buffer *buf = list_entry(p, struct cx18_buffer, list); + + writel(buf->dma_handle, &cx->scb->cpu_mdl[buf->id].paddr); + writel(s->buf_size, &cx->scb->cpu_mdl[buf->id].length); + cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle, + (void *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem, 1, + buf->id, s->buf_size); + } + /* begin_capture */ + if (cx18_vapi(cx, CX18_CPU_CAPTURE_START, 1, s->handle)) { + CX18_DEBUG_WARN("Error starting capture!\n"); + cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle); + return -EINVAL; + } + + /* you're live! sit back and await interrupts :) */ + atomic_inc(&cx->capturing); + return 0; +} + +void cx18_stop_all_captures(struct cx18 *cx) +{ + int i; + + for (i = CX18_MAX_STREAMS - 1; i >= 0; i--) { + struct cx18_stream *s = &cx->streams[i]; + + if (s->v4l2dev == NULL && s->dvb.enabled == 0) + continue; + if (test_bit(CX18_F_S_STREAMING, &s->s_flags)) + cx18_stop_v4l2_encode_stream(s, 0); + } +} + +int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end) +{ + struct cx18 *cx = s->cx; + unsigned long then; + + if (s->v4l2dev == NULL && s->dvb.enabled == 0) + return -EINVAL; + + /* This function assumes that you are allowed to stop the capture + and that we are actually capturing */ + + CX18_DEBUG_INFO("Stop Capture\n"); + + if (atomic_read(&cx->capturing) == 0) + return 0; + + if (s->type == CX18_ENC_STREAM_TYPE_MPG) + cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 2, s->handle, !gop_end); + else + cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 1, s->handle); + + then = jiffies; + + if (s->type == CX18_ENC_STREAM_TYPE_MPG && gop_end) { + CX18_INFO("ignoring gop_end: not (yet?) supported by the firmware\n"); + } + + atomic_dec(&cx->capturing); + + /* Clear capture and no-read bits */ + clear_bit(CX18_F_S_STREAMING, &s->s_flags); + + cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle); + s->handle = 0xffffffff; + + if (atomic_read(&cx->capturing) > 0) + return 0; + + write_reg(5, CX18_DSP0_INTERRUPT_MASK); + wake_up(&s->waitq); + + return 0; +} + +u32 cx18_find_handle(struct cx18 *cx) +{ + int i; + + /* find first available handle to be used for global settings */ + for (i = 0; i < CX18_MAX_STREAMS; i++) { + struct cx18_stream *s = &cx->streams[i]; + + if (s->v4l2dev && s->handle) + return s->handle; + } + return 0; +} diff --git a/drivers/media/video/cx18/cx18-streams.h b/drivers/media/video/cx18/cx18-streams.h new file mode 100644 index 00000000000..8c7ba7d2fa7 --- /dev/null +++ b/drivers/media/video/cx18/cx18-streams.h @@ -0,0 +1,33 @@ +/* + * cx18 init/start/stop/exit stream functions + * + * Derived from ivtv-streams.h + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 + */ + +u32 cx18_find_handle(struct cx18 *cx); +int cx18_streams_setup(struct cx18 *cx); +int cx18_streams_register(struct cx18 *cx); +void cx18_streams_cleanup(struct cx18 *cx); + +/* Capture related */ +int cx18_start_v4l2_encode_stream(struct cx18_stream *s); +int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end); + +void cx18_stop_all_captures(struct cx18 *cx); diff --git a/drivers/media/video/cx18/cx18-vbi.c b/drivers/media/video/cx18/cx18-vbi.c new file mode 100644 index 00000000000..22e76ee3f44 --- /dev/null +++ b/drivers/media/video/cx18/cx18-vbi.c @@ -0,0 +1,208 @@ +/* + * cx18 Vertical Blank Interval support functions + * + * Derived from ivtv-vbi.c + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 "cx18-driver.h" +#include "cx18-vbi.h" +#include "cx18-ioctl.h" +#include "cx18-queue.h" +#include "cx18-av-core.h" + +static void copy_vbi_data(struct cx18 *cx, int lines, u32 pts_stamp) +{ + int line = 0; + int i; + u32 linemask[2] = { 0, 0 }; + unsigned short size; + static const u8 mpeg_hdr_data[] = { + 0x00, 0x00, 0x01, 0xba, 0x44, 0x00, 0x0c, 0x66, + 0x24, 0x01, 0x01, 0xd1, 0xd3, 0xfa, 0xff, 0xff, + 0x00, 0x00, 0x01, 0xbd, 0x00, 0x1a, 0x84, 0x80, + 0x07, 0x21, 0x00, 0x5d, 0x63, 0xa7, 0xff, 0xff + }; + const int sd = sizeof(mpeg_hdr_data); /* start of vbi data */ + int idx = cx->vbi.frame % CX18_VBI_FRAMES; + u8 *dst = &cx->vbi.sliced_mpeg_data[idx][0]; + + for (i = 0; i < lines; i++) { + struct v4l2_sliced_vbi_data *sdata = cx->vbi.sliced_data + i; + int f, l; + + if (sdata->id == 0) + continue; + + l = sdata->line - 6; + f = sdata->field; + if (f) + l += 18; + if (l < 32) + linemask[0] |= (1 << l); + else + linemask[1] |= (1 << (l - 32)); + dst[sd + 12 + line * 43] = cx18_service2vbi(sdata->id); + memcpy(dst + sd + 12 + line * 43 + 1, sdata->data, 42); + line++; + } + memcpy(dst, mpeg_hdr_data, sizeof(mpeg_hdr_data)); + if (line == 36) { + /* All lines are used, so there is no space for the linemask + (the max size of the VBI data is 36 * 43 + 4 bytes). + So in this case we use the magic number 'ITV0'. */ + memcpy(dst + sd, "ITV0", 4); + memcpy(dst + sd + 4, dst + sd + 12, line * 43); + size = 4 + ((43 * line + 3) & ~3); + } else { + memcpy(dst + sd, "cx0", 4); + memcpy(dst + sd + 4, &linemask[0], 8); + size = 12 + ((43 * line + 3) & ~3); + } + dst[4+16] = (size + 10) >> 8; + dst[5+16] = (size + 10) & 0xff; + dst[9+16] = 0x21 | ((pts_stamp >> 29) & 0x6); + dst[10+16] = (pts_stamp >> 22) & 0xff; + dst[11+16] = 1 | ((pts_stamp >> 14) & 0xff); + dst[12+16] = (pts_stamp >> 7) & 0xff; + dst[13+16] = 1 | ((pts_stamp & 0x7f) << 1); + cx->vbi.sliced_mpeg_size[idx] = sd + size; +} + +/* Compress raw VBI format, removes leading SAV codes and surplus space + after the field. + Returns new compressed size. */ +static u32 compress_raw_buf(struct cx18 *cx, u8 *buf, u32 size) +{ + u32 line_size = cx->vbi.raw_decoder_line_size; + u32 lines = cx->vbi.count; + u8 sav1 = cx->vbi.raw_decoder_sav_odd_field; + u8 sav2 = cx->vbi.raw_decoder_sav_even_field; + u8 *q = buf; + u8 *p; + int i; + + for (i = 0; i < lines; i++) { + p = buf + i * line_size; + + /* Look for SAV code */ + if (p[0] != 0xff || p[1] || p[2] || + (p[3] != sav1 && p[3] != sav2)) + break; + memcpy(q, p + 4, line_size - 4); + q += line_size - 4; + } + return lines * (line_size - 4); +} + + +/* Compressed VBI format, all found sliced blocks put next to one another + Returns new compressed size */ +static u32 compress_sliced_buf(struct cx18 *cx, u32 line, u8 *buf, + u32 size, u8 sav) +{ + u32 line_size = cx->vbi.sliced_decoder_line_size; + struct v4l2_decode_vbi_line vbi; + int i; + + /* find the first valid line */ + for (i = 0; i < size; i++, buf++) { + if (buf[0] == 0xff && !buf[1] && !buf[2] && buf[3] == sav) + break; + } + + size -= i; + if (size < line_size) + return line; + for (i = 0; i < size / line_size; i++) { + u8 *p = buf + i * line_size; + + /* Look for SAV code */ + if (p[0] != 0xff || p[1] || p[2] || p[3] != sav) + continue; + vbi.p = p + 4; + cx18_av_cmd(cx, VIDIOC_INT_DECODE_VBI_LINE, &vbi); + if (vbi.type) { + cx->vbi.sliced_data[line].id = vbi.type; + cx->vbi.sliced_data[line].field = vbi.is_second_field; + cx->vbi.sliced_data[line].line = vbi.line; + memcpy(cx->vbi.sliced_data[line].data, vbi.p, 42); + line++; + } + } + return line; +} + +void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf, + u64 pts_stamp, int streamtype) +{ + u8 *p = (u8 *) buf->buf; + u32 size = buf->bytesused; + int lines; + + if (streamtype != CX18_ENC_STREAM_TYPE_VBI) + return; + + /* Raw VBI data */ + if (cx->vbi.sliced_in->service_set == 0) { + u8 type; + + cx18_buf_swap(buf); + + type = p[3]; + + size = buf->bytesused = compress_raw_buf(cx, p, size); + + /* second field of the frame? */ + if (type == cx->vbi.raw_decoder_sav_even_field) { + /* Dirty hack needed for backwards + compatibility of old VBI software. */ + p += size - 4; + memcpy(p, &cx->vbi.frame, 4); + cx->vbi.frame++; + } + return; + } + + /* Sliced VBI data with data insertion */ + cx18_buf_swap(buf); + + /* first field */ + lines = compress_sliced_buf(cx, 0, p, size / 2, + cx->vbi.sliced_decoder_sav_odd_field); + /* second field */ + /* experimentation shows that the second half does not always + begin at the exact address. So start a bit earlier + (hence 32). */ + lines = compress_sliced_buf(cx, lines, p + size / 2 - 32, + size / 2 + 32, cx->vbi.sliced_decoder_sav_even_field); + /* always return at least one empty line */ + if (lines == 0) { + cx->vbi.sliced_data[0].id = 0; + cx->vbi.sliced_data[0].line = 0; + cx->vbi.sliced_data[0].field = 0; + lines = 1; + } + buf->bytesused = size = lines * sizeof(cx->vbi.sliced_data[0]); + memcpy(p, &cx->vbi.sliced_data[0], size); + + if (cx->vbi.insert_mpeg) + copy_vbi_data(cx, lines, pts_stamp); + cx->vbi.frame++; +} diff --git a/drivers/media/video/cx18/cx18-vbi.h b/drivers/media/video/cx18/cx18-vbi.h new file mode 100644 index 00000000000..c56ff7d28f2 --- /dev/null +++ b/drivers/media/video/cx18/cx18-vbi.h @@ -0,0 +1,26 @@ +/* + * cx18 Vertical Blank Interval support functions + * + * Derived from ivtv-vbi.h + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 + */ + +void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf, + u64 pts_stamp, int streamtype); +int cx18_used_line(struct cx18 *cx, int line, int field); diff --git a/drivers/media/video/cx18/cx18-version.h b/drivers/media/video/cx18/cx18-version.h new file mode 100644 index 00000000000..d5c7a6f968d --- /dev/null +++ b/drivers/media/video/cx18/cx18-version.h @@ -0,0 +1,34 @@ +/* + * cx18 driver version information + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 CX18_VERSION_H +#define CX18_VERSION_H + +#define CX18_DRIVER_NAME "cx18" +#define CX18_DRIVER_VERSION_MAJOR 1 +#define CX18_DRIVER_VERSION_MINOR 0 +#define CX18_DRIVER_VERSION_PATCHLEVEL 0 + +#define CX18_VERSION __stringify(CX18_DRIVER_VERSION_MAJOR) "." __stringify(CX18_DRIVER_VERSION_MINOR) "." __stringify(CX18_DRIVER_VERSION_PATCHLEVEL) +#define CX18_DRIVER_VERSION KERNEL_VERSION(CX18_DRIVER_VERSION_MAJOR, \ + CX18_DRIVER_VERSION_MINOR, CX18_DRIVER_VERSION_PATCHLEVEL) + +#endif diff --git a/drivers/media/video/cx18/cx18-video.c b/drivers/media/video/cx18/cx18-video.c new file mode 100644 index 00000000000..2e5c4193933 --- /dev/null +++ b/drivers/media/video/cx18/cx18-video.c @@ -0,0 +1,45 @@ +/* + * cx18 video interface functions + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 "cx18-driver.h" +#include "cx18-video.h" +#include "cx18-av-core.h" +#include "cx18-cards.h" + +void cx18_video_set_io(struct cx18 *cx) +{ + struct v4l2_routing route; + int inp = cx->active_input; + u32 type; + + route.input = cx->card->video_inputs[inp].video_input; + route.output = 0; + cx18_av_cmd(cx, VIDIOC_INT_S_VIDEO_ROUTING, &route); + + type = cx->card->video_inputs[inp].video_type; + + if (type == CX18_CARD_INPUT_VID_TUNER) + route.input = 0; /* Tuner */ + else if (type < CX18_CARD_INPUT_COMPOSITE1) + route.input = 2; /* S-Video */ + else + route.input = 1; /* Composite */ +} diff --git a/drivers/media/video/cx18/cx18-video.h b/drivers/media/video/cx18/cx18-video.h new file mode 100644 index 00000000000..529006a06e5 --- /dev/null +++ b/drivers/media/video/cx18/cx18-video.h @@ -0,0 +1,22 @@ +/* + * cx18 video interface functions + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 + */ + +void cx18_video_set_io(struct cx18 *cx); diff --git a/drivers/media/video/cx18/cx23418.h b/drivers/media/video/cx18/cx23418.h new file mode 100644 index 00000000000..33f78da9dba --- /dev/null +++ b/drivers/media/video/cx18/cx23418.h @@ -0,0 +1,458 @@ +/* + * cx18 header containing common defines. + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 CX23418_H +#define CX23418_H + +#include <media/cx2341x.h> + +#define MGR_CMD_MASK 0x40000000 +/* The MSB of the command code indicates that this is the completion of a + command */ +#define MGR_CMD_MASK_ACK (MGR_CMD_MASK | 0x80000000) + +/* Description: This command creates a new instance of a certain task + IN[0] - Task ID. This is one of the XPU_CMD_MASK_YYY where XPU is + the processor on which the task YYY will be created + OUT[0] - Task handle. This handle is passed along with commands to + dispatch to the right instance of the task + ReturnCode - One of the ERR_SYS_... */ +#define CX18_CREATE_TASK (MGR_CMD_MASK | 0x0001) + +/* Description: This command destroys an instance of a task + IN[0] - Task handle. Hanlde of the task to destroy + ReturnCode - One of the ERR_SYS_... */ +#define CX18_DESTROY_TASK (MGR_CMD_MASK | 0x0002) + +/* All commands for CPU have the following mask set */ +#define CPU_CMD_MASK 0x20000000 +#define CPU_CMD_MASK_ACK (CPU_CMD_MASK | 0x80000000) +#define CPU_CMD_MASK_CAPTURE (CPU_CMD_MASK | 0x00020000) +#define CPU_CMD_MASK_TS (CPU_CMD_MASK | 0x00040000) + +#define EPU_CMD_MASK 0x02000000 +#define EPU_CMD_MASK_DEBUG (EPU_CMD_MASK | 0x000000) +#define EPU_CMD_MASK_DE (EPU_CMD_MASK | 0x040000) + +/* Description: This command indicates that a Memory Descriptor List has been + filled with the requested channel type + IN[0] - Task handle. Handle of the task + IN[1] - Offset of the MDL_ACK from the beginning of the local DDR. + IN[2] - Number of CNXT_MDL_ACK structures in the array pointed to by IN[1] + ReturnCode - One of the ERR_DE_... */ +#define CX18_EPU_DMA_DONE (EPU_CMD_MASK_DE | 0x0001) + +/* Something interesting happened + IN[0] - A value to log + IN[1] - An offset of a string in the MiniMe memory; + 0/zero/NULL means "I have nothing to say" */ +#define CX18_EPU_DEBUG (EPU_CMD_MASK_DEBUG | 0x0003) + +/* Description: This command starts streaming with the set channel type + IN[0] - Task handle. Handle of the task to start + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_CAPTURE_START (CPU_CMD_MASK_CAPTURE | 0x0002) + +/* Description: This command stops streaming with the set channel type + IN[0] - Task handle. Handle of the task to stop + IN[1] - 0 = stop at end of GOP, 1 = stop at end of frame (MPEG only) + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_CAPTURE_STOP (CPU_CMD_MASK_CAPTURE | 0x0003) + +/* Description: This command pauses streaming with the set channel type + IN[0] - Task handle. Handle of the task to pause + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_CAPTURE_PAUSE (CPU_CMD_MASK_CAPTURE | 0x0007) + +/* Description: This command resumes streaming with the set channel type + IN[0] - Task handle. Handle of the task to resume + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_CAPTURE_RESUME (CPU_CMD_MASK_CAPTURE | 0x0008) + +#define CAPTURE_CHANNEL_TYPE_NONE 0 +#define CAPTURE_CHANNEL_TYPE_MPEG 1 +#define CAPTURE_CHANNEL_TYPE_INDEX 2 +#define CAPTURE_CHANNEL_TYPE_YUV 3 +#define CAPTURE_CHANNEL_TYPE_PCM 4 +#define CAPTURE_CHANNEL_TYPE_VBI 5 +#define CAPTURE_CHANNEL_TYPE_SLICED_VBI 6 +#define CAPTURE_CHANNEL_TYPE_TS 7 +#define CAPTURE_CHANNEL_TYPE_MAX 15 + +/* Description: This command sets the channel type. This can only be done + when stopped. + IN[0] - Task handle. Handle of the task to start + IN[1] - Channel Type. See Below. + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_CHANNEL_TYPE (CPU_CMD_MASK_CAPTURE + 1) + +/* Description: Set stream output type + IN[0] - task handle. Handle of the task to start + IN[1] - type + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_STREAM_OUTPUT_TYPE (CPU_CMD_MASK_CAPTURE | 0x0012) + +/* Description: Set video input resolution and frame rate + IN[0] - task handle + IN[1] - reserved + IN[2] - reserved + IN[3] - reserved + IN[4] - reserved + IN[5] - frame rate, 0 - 29.97f/s, 1 - 25f/s + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_VIDEO_IN (CPU_CMD_MASK_CAPTURE | 0x0004) + +/* Description: Set video frame rate + IN[0] - task handle. Handle of the task to start + IN[1] - video bit rate mode + IN[2] - video average rate + IN[3] - video peak rate + IN[4] - system mux rate + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_VIDEO_RATE (CPU_CMD_MASK_CAPTURE | 0x0005) + +/* Description: Set video output resolution + IN[0] - task handle + IN[1] - horizontal size + IN[2] - vertical size + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_VIDEO_RESOLUTION (CPU_CMD_MASK_CAPTURE | 0x0006) + +/* Description: This command set filter parameters + IN[0] - Task handle. Handle of the task + IN[1] - type, 0 - temporal, 1 - spatial, 2 - median + IN[2] - mode, temporal/spatial: 0 - disable, 1 - static, 2 - dynamic + median: 0 = disable, 1 = horizontal, 2 = vertical, + 3 = horizontal/vertical, 4 = diagonal + IN[3] - strength, temporal 0 - 31, spatial 0 - 15 + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_FILTER_PARAM (CPU_CMD_MASK_CAPTURE | 0x0009) + +/* Description: This command set spatial filter type + IN[0] - Task handle. + IN[1] - luma type: 0 = disable, 1 = 1D horizontal only, 2 = 1D vertical only, + 3 = 2D H/V separable, 4 = 2D symmetric non-separable + IN[2] - chroma type: 0 - diable, 1 = 1D horizontal + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_SPATIAL_FILTER_TYPE (CPU_CMD_MASK_CAPTURE | 0x000C) + +/* Description: This command set coring levels for median filter + IN[0] - Task handle. + IN[1] - luma_high + IN[2] - luma_low + IN[3] - chroma_high + IN[4] - chroma_low + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_MEDIAN_CORING (CPU_CMD_MASK_CAPTURE | 0x000E) + +/* Description: This command set the picture type mask for index file + IN[0] - 0 = disable index file output + 1 = output I picture + 2 = P picture + 4 = B picture + other = illegal */ +#define CX18_CPU_SET_INDEXTABLE (CPU_CMD_MASK_CAPTURE | 0x0010) + +/* Description: Set audio parameters + IN[0] - task handle. Handle of the task to start + IN[1] - audio parameter + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_AUDIO_PARAMETERS (CPU_CMD_MASK_CAPTURE | 0x0011) + +/* Description: Set video mute + IN[0] - task handle. Handle of the task to start + IN[1] - bit31-24: muteYvalue + bit23-16: muteUvalue + bit15-8: muteVvalue + bit0: 1:mute, 0: unmute + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_VIDEO_MUTE (CPU_CMD_MASK_CAPTURE | 0x0013) + +/* Description: Set audio mute + IN[0] - task handle. Handle of the task to start + IN[1] - mute/unmute + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_AUDIO_MUTE (CPU_CMD_MASK_CAPTURE | 0x0014) + +/* Description: Set stream output type + IN[0] - task handle. Handle of the task to start + IN[1] - subType + SET_INITIAL_SCR 1 + SET_QUALITY_MODE 2 + SET_VIM_PROTECT_MODE 3 + SET_PTS_CORRECTION 4 + SET_USB_FLUSH_MODE 5 + SET_MERAQPAR_ENABLE 6 + SET_NAV_PACK_INSERTION 7 + SET_SCENE_CHANGE_ENABLE 8 + IN[2] - parameter 1 + IN[3] - parameter 2 + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_MISC_PARAMETERS (CPU_CMD_MASK_CAPTURE | 0x0015) + +/* Description: Set raw VBI parameters + IN[0] - Task handle + IN[1] - No. of input lines per field: + bit[15:0]: field 1, + bit[31:16]: field 2 + IN[2] - No. of input bytes per line + IN[3] - No. of output frames per transfer + IN[4] - start code + IN[5] - stop code + ReturnCode */ +#define CX18_CPU_SET_RAW_VBI_PARAM (CPU_CMD_MASK_CAPTURE | 0x0016) + +/* Description: Set capture line No. + IN[0] - task handle. Handle of the task to start + IN[1] - height1 + IN[2] - height2 + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_CAPTURE_LINE_NO (CPU_CMD_MASK_CAPTURE | 0x0017) + +/* Description: Set copyright + IN[0] - task handle. Handle of the task to start + IN[1] - copyright + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_COPYRIGHT (CPU_CMD_MASK_CAPTURE | 0x0018) + +/* Description: Set audio PID + IN[0] - task handle. Handle of the task to start + IN[1] - PID + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_AUDIO_PID (CPU_CMD_MASK_CAPTURE | 0x0019) + +/* Description: Set video PID + IN[0] - task handle. Handle of the task to start + IN[1] - PID + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_VIDEO_PID (CPU_CMD_MASK_CAPTURE | 0x001A) + +/* Description: Set Vertical Crop Line + IN[0] - task handle. Handle of the task to start + IN[1] - Line + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_VER_CROP_LINE (CPU_CMD_MASK_CAPTURE | 0x001B) + +/* Description: Set COP structure + IN[0] - task handle. Handle of the task to start + IN[1] - M + IN[2] - N + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_GOP_STRUCTURE (CPU_CMD_MASK_CAPTURE | 0x001C) + +/* Description: Set Scene Change Detection + IN[0] - task handle. Handle of the task to start + IN[1] - scene change + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_SCENE_CHANGE_DETECTION (CPU_CMD_MASK_CAPTURE | 0x001D) + +/* Description: Set Aspect Ratio + IN[0] - task handle. Handle of the task to start + IN[1] - AspectRatio + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_ASPECT_RATIO (CPU_CMD_MASK_CAPTURE | 0x001E) + +/* Description: Set Skip Input Frame + IN[0] - task handle. Handle of the task to start + IN[1] - skip input frames + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_SKIP_INPUT_FRAME (CPU_CMD_MASK_CAPTURE | 0x001F) + +/* Description: Set sliced VBI parameters - + Note This API will only apply to MPEG and Sliced VBI Channels + IN[0] - Task handle + IN[1] - output type, 0 - CC, 1 - Moji, 2 - Teletext + IN[2] - start / stop line + bit[15:0] start line number + bit[31:16] stop line number + IN[3] - number of output frames per interrupt + IN[4] - VBI insertion mode + bit 0: output user data, 1 - enable + bit 1: output private stream, 1 - enable + bit 2: mux option, 0 - in GOP, 1 - in picture + bit[7:0] private stream ID + IN[5] - insertion period while mux option is in picture + ReturnCode - VBI data offset */ +#define CX18_CPU_SET_SLICED_VBI_PARAM (CPU_CMD_MASK_CAPTURE | 0x0020) + +/* Description: Set the user data place holder + IN[0] - type of data (0 for user) + IN[1] - Stuffing period + IN[2] - ID data size in word (less than 10) + IN[3] - Pointer to ID buffer */ +#define CX18_CPU_SET_USERDATA_PLACE_HOLDER (CPU_CMD_MASK_CAPTURE | 0x0021) + + +/* Description: + In[0] Task Handle + return parameter: + Out[0] Reserved + Out[1] Video PTS bit[32:2] of last output video frame. + Out[2] Video PTS bit[ 1:0] of last output video frame. + Out[3] Hardware Video PTS counter bit[31:0], + these bits get incremented on every 90kHz clock tick. + Out[4] Hardware Video PTS counter bit32, + these bits get incremented on every 90kHz clock tick. + ReturnCode */ +#define CX18_CPU_GET_ENC_PTS (CPU_CMD_MASK_CAPTURE | 0x0022) + +/* Below is the list of commands related to the data exchange */ +#define CPU_CMD_MASK_DE (CPU_CMD_MASK | 0x040000) + +/* Description: This command provides the physical base address of the local + DDR as viewed by EPU + IN[0] - Physical offset where EPU has the local DDR mapped + ReturnCode - One of the ERR_DE_... */ +#define CPU_CMD_DE_SetBase (CPU_CMD_MASK_DE | 0x0001) + +/* Description: This command provides the offsets in the device memory where + the 2 cx18_mdl_ack blocks reside + IN[0] - Task handle. Handle of the task to start + IN[1] - Offset of the first cx18_mdl_ack from the beginning of the + local DDR. + IN[2] - Offset of the second cx18_mdl_ack from the beginning of the + local DDR. + ReturnCode - One of the ERR_DE_... */ +#define CX18_CPU_DE_SET_MDL_ACK (CPU_CMD_MASK_DE | 0x0002) + +/* Description: This command provides the offset to a Memory Descriptor List + IN[0] - Task handle. Handle of the task to start + IN[1] - Offset of the MDL from the beginning of the local DDR. + IN[2] - Number of cx18_mdl structures in the array pointed to by IN[1] + IN[3] - Buffer ID + IN[4] - Total buffer length + ReturnCode - One of the ERR_DE_... */ +#define CX18_CPU_DE_SET_MDL (CPU_CMD_MASK_DE | 0x0005) + +/* Description: This command requests return of all current Memory + Descriptor Lists to the driver + IN[0] - Task handle. Handle of the task to start + ReturnCode - One of the ERR_DE_... */ +/* #define CX18_CPU_DE_ReleaseMDL (CPU_CMD_MASK_DE | 0x0006) */ + +/* Description: This command signals the cpu that the dat buffer has been + consumed and ready for re-use. + IN[0] - Task handle. Handle of the task + IN[1] - Offset of the data block from the beginning of the local DDR. + IN[2] - Number of bytes in the data block + ReturnCode - One of the ERR_DE_... */ +/* #define CX18_CPU_DE_RELEASE_BUFFER (CPU_CMD_MASK_DE | 0x0007) */ + +/* No Error / Success */ +#define CNXT_OK 0x000000 + +/* Received unknown command */ +#define CXERR_UNK_CMD 0x000001 + +/* First parameter in the command is invalid */ +#define CXERR_INVALID_PARAM1 0x000002 + +/* Second parameter in the command is invalid */ +#define CXERR_INVALID_PARAM2 0x000003 + +/* Device interface is not open/found */ +#define CXERR_DEV_NOT_FOUND 0x000004 + +/* Requested function is not implemented/available */ +#define CXERR_NOTSUPPORTED 0x000005 + +/* Invalid pointer is provided */ +#define CXERR_BADPTR 0x000006 + +/* Unable to allocate memory */ +#define CXERR_NOMEM 0x000007 + +/* Object/Link not found */ +#define CXERR_LINK 0x000008 + +/* Device busy, command cannot be executed */ +#define CXERR_BUSY 0x000009 + +/* File/device/handle is not open. */ +#define CXERR_NOT_OPEN 0x00000A + +/* Value is out of range */ +#define CXERR_OUTOFRANGE 0x00000B + +/* Buffer overflow */ +#define CXERR_OVERFLOW 0x00000C + +/* Version mismatch */ +#define CXERR_BADVER 0x00000D + +/* Operation timed out */ +#define CXERR_TIMEOUT 0x00000E + +/* Operation aborted */ +#define CXERR_ABORT 0x00000F + +/* Specified I2C device not found for read/write */ +#define CXERR_I2CDEV_NOTFOUND 0x000010 + +/* Error in I2C data xfer (but I2C device is present) */ +#define CXERR_I2CDEV_XFERERR 0x000011 + +/* Chanel changing component not ready */ +#define CXERR_CHANNELNOTREADY 0x000012 + +/* PPU (Presensation/Decoder) mail box is corrupted */ +#define CXERR_PPU_MB_CORRUPT 0x000013 + +/* CPU (Capture/Encoder) mail box is corrupted */ +#define CXERR_CPU_MB_CORRUPT 0x000014 + +/* APU (Audio) mail box is corrupted */ +#define CXERR_APU_MB_CORRUPT 0x000015 + +/* Unable to open file for reading */ +#define CXERR_FILE_OPEN_READ 0x000016 + +/* Unable to open file for writing */ +#define CXERR_FILE_OPEN_WRITE 0x000017 + +/* Unable to find the I2C section specified */ +#define CXERR_I2C_BADSECTION 0x000018 + +/* Error in I2C data xfer (but I2C device is present) */ +#define CXERR_I2CDEV_DATALOW 0x000019 + +/* Error in I2C data xfer (but I2C device is present) */ +#define CXERR_I2CDEV_CLOCKLOW 0x00001A + +/* No Interrupt received from HW (for I2C access) */ +#define CXERR_NO_HW_I2C_INTR 0x00001B + +/* RPU is not ready to accept commands! */ +#define CXERR_RPU_NOT_READY 0x00001C + +/* RPU is not ready to accept commands! */ +#define CXERR_RPU_NO_ACK 0x00001D + +/* The are no buffers ready. Try again soon! */ +#define CXERR_NODATA_AGAIN 0x00001E + +/* The stream is stopping. Function not alllowed now! */ +#define CXERR_STOPPING_STATUS 0x00001F + +/* Trying to access hardware when the power is turned OFF */ +#define CXERR_DEVPOWER_OFF 0x000020 + +#endif /* CX23418_H */ diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig index ca5fbce3a90..cadf936c367 100644 --- a/drivers/media/video/cx23885/Kconfig +++ b/drivers/media/video/cx23885/Kconfig @@ -4,19 +4,19 @@ config VIDEO_CX23885 select I2C_ALGOBIT select FW_LOADER select VIDEO_BTCX - select VIDEO_TUNER + select MEDIA_TUNER select VIDEO_TVEEPROM select VIDEO_IR select VIDEOBUF_DVB select VIDEO_CX25840 - select DVB_TUNER_MT2131 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2131 if !DVB_FE_CUSTOMISE select DVB_S5H1409 if !DVB_FE_CUSTOMISE select DVB_LGDT330X if !DVB_FE_CUSTOMISE select DVB_PLL if !DVB_FE_CUSTOMISE - select TUNER_XC2028 if !DVB_FE_CUSTOMIZE - select TUNER_TDA8290 if !DVB_FE_CUSTOMIZE - select DVB_TDA18271 if !DVB_FE_CUSTOMIZE - select DVB_TUNER_XC5000 if !DVB_FE_CUSTOMIZE + select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMIZE + select MEDIA_TUNER_TDA8290 if !DVB_FE_CUSTOMIZE + select MEDIA_TUNER_TDA18271 if !DVB_FE_CUSTOMIZE + select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMIZE select DVB_TDA10048 if !DVB_FE_CUSTOMIZE ---help--- This is a video4linux driver for Conexant 23885 based diff --git a/drivers/media/video/cx23885/Makefile b/drivers/media/video/cx23885/Makefile index d7b0721af06..29c23b44c13 100644 --- a/drivers/media/video/cx23885/Makefile +++ b/drivers/media/video/cx23885/Makefile @@ -3,6 +3,7 @@ cx23885-objs := cx23885-cards.o cx23885-video.o cx23885-vbi.o cx23885-core.o cx2 obj-$(CONFIG_VIDEO_CX23885) += cx23885.o EXTRA_CFLAGS += -Idrivers/media/video +EXTRA_CFLAGS += -Idrivers/media/common/tuners EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core EXTRA_CFLAGS += -Idrivers/media/dvb/frontends diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 7fde678b2c4..88823810497 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -1209,7 +1209,8 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, /* ----------------------------------------------------------------------- */ -static int cx25840_probe(struct i2c_client *client) +static int cx25840_probe(struct i2c_client *client, + const struct i2c_device_id *did) { struct cx25840_state *state; u32 id; diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig index 27635cdcbaf..b0d7d6a7a4c 100644 --- a/drivers/media/video/cx88/Kconfig +++ b/drivers/media/video/cx88/Kconfig @@ -5,7 +5,7 @@ config VIDEO_CX88 select FW_LOADER select VIDEO_BTCX select VIDEOBUF_DMA_SG - select VIDEO_TUNER + select MEDIA_TUNER select VIDEO_TVEEPROM select VIDEO_IR select VIDEO_WM8775 if VIDEO_HELPER_CHIPS_AUTO @@ -57,7 +57,7 @@ config VIDEO_CX88_DVB select DVB_NXT200X if !DVB_FE_CUSTOMISE select DVB_CX24123 if !DVB_FE_CUSTOMISE select DVB_ISL6421 if !DVB_FE_CUSTOMISE - select TUNER_SIMPLE if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE select DVB_S5H1411 if !DVB_FE_CUSTOMISE ---help--- This adds support for DVB/ATSC cards based on the diff --git a/drivers/media/video/cx88/Makefile b/drivers/media/video/cx88/Makefile index 532cee35eb3..6ec30f24257 100644 --- a/drivers/media/video/cx88/Makefile +++ b/drivers/media/video/cx88/Makefile @@ -10,5 +10,6 @@ obj-$(CONFIG_VIDEO_CX88_DVB) += cx88-dvb.o obj-$(CONFIG_VIDEO_CX88_VP3054) += cx88-vp3054-i2c.o EXTRA_CFLAGS += -Idrivers/media/video +EXTRA_CFLAGS += -Idrivers/media/common/tuners EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core EXTRA_CFLAGS += -Idrivers/media/dvb/frontends diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index 2b6b283cda1..aeba26dc0a3 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -57,6 +57,9 @@ MODULE_PARM_DESC(latency,"pci latency timer"); /* ------------------------------------------------------------------ */ /* board config info */ +/* If radio_type !=UNSET, radio_addr should be specified + */ + static const struct cx88_board cx88_boards[] = { [CX88_BOARD_UNKNOWN] = { .name = "UNKNOWN/GENERIC", @@ -2446,25 +2449,31 @@ EXPORT_SYMBOL_GPL(cx88_setup_xc3028); static void cx88_card_setup(struct cx88_core *core) { static u8 eeprom[256]; + struct tuner_setup tun_setup; + unsigned int mode_mask = T_RADIO | + T_ANALOG_TV | + T_DIGITAL_TV; + + memset(&tun_setup, 0, sizeof(tun_setup)); if (0 == core->i2c_rc) { core->i2c_client.addr = 0xa0 >> 1; - tveeprom_read(&core->i2c_client,eeprom,sizeof(eeprom)); + tveeprom_read(&core->i2c_client, eeprom, sizeof(eeprom)); } switch (core->boardnr) { case CX88_BOARD_HAUPPAUGE: case CX88_BOARD_HAUPPAUGE_ROSLYN: if (0 == core->i2c_rc) - hauppauge_eeprom(core,eeprom+8); + hauppauge_eeprom(core, eeprom+8); break; case CX88_BOARD_GDI: if (0 == core->i2c_rc) - gdi_eeprom(core,eeprom); + gdi_eeprom(core, eeprom); break; case CX88_BOARD_WINFAST2000XP_EXPERT: if (0 == core->i2c_rc) - leadtek_eeprom(core,eeprom); + leadtek_eeprom(core, eeprom); break; case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1: case CX88_BOARD_HAUPPAUGE_NOVASE2_S1: @@ -2474,7 +2483,7 @@ static void cx88_card_setup(struct cx88_core *core) case CX88_BOARD_HAUPPAUGE_HVR3000: case CX88_BOARD_HAUPPAUGE_HVR1300: if (0 == core->i2c_rc) - hauppauge_eeprom(core,eeprom); + hauppauge_eeprom(core, eeprom); break; case CX88_BOARD_KWORLD_DVBS_100: cx_write(MO_GP0_IO, 0x000007f8); @@ -2555,6 +2564,35 @@ static void cx88_card_setup(struct cx88_core *core) cx88_call_i2c_clients(core, TUNER_SET_CONFIG, &tea5767_cfg); } + } /*end switch() */ + + + /* Setup tuners */ + if ((core->board.radio_type != UNSET)) { + tun_setup.mode_mask = T_RADIO; + tun_setup.type = core->board.radio_type; + tun_setup.addr = core->board.radio_addr; + tun_setup.tuner_callback = cx88_tuner_callback; + cx88_call_i2c_clients(core, TUNER_SET_TYPE_ADDR, &tun_setup); + mode_mask &= ~T_RADIO; + } + + if (core->board.tuner_type != TUNER_ABSENT) { + tun_setup.mode_mask = mode_mask; + tun_setup.type = core->board.tuner_type; + tun_setup.addr = core->board.tuner_addr; + tun_setup.tuner_callback = cx88_tuner_callback; + + cx88_call_i2c_clients(core, TUNER_SET_TYPE_ADDR, &tun_setup); + } + + if (core->board.tda9887_conf) { + struct v4l2_priv_tun_config tda9887_cfg; + + tda9887_cfg.tuner = TUNER_TDA9887; + tda9887_cfg.priv = &core->board.tda9887_conf; + + cx88_call_i2c_clients(core, TUNER_SET_CONFIG, &tda9887_cfg); } if (core->board.tuner_type == TUNER_XC2028) { @@ -2572,6 +2610,7 @@ static void cx88_card_setup(struct cx88_core *core) ctl.fname); cx88_call_i2c_clients(core, TUNER_SET_CONFIG, &xc2028_cfg); } + cx88_call_i2c_clients (core, TUNER_SET_STANDBY, NULL); } /* ------------------------------------------------------------------ */ @@ -2710,7 +2749,6 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr) if (TUNER_ABSENT != core->board.tuner_type) request_module("tuner"); - cx88_call_i2c_clients (core, TUNER_SET_STANDBY, NULL); cx88_card_setup(core); cx88_ir_init(core, pci); diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c index c6b44732a08..00aa7a3f110 100644 --- a/drivers/media/video/cx88/cx88-i2c.c +++ b/drivers/media/video/cx88/cx88-i2c.c @@ -104,37 +104,7 @@ static int attach_inform(struct i2c_client *client) dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n", client->driver->driver.name, client->addr, client->name); - if (!client->driver->command) - return 0; - - if (core->board.radio_type != UNSET) { - if ((core->board.radio_addr==ADDR_UNSET)||(core->board.radio_addr==client->addr)) { - tun_setup.mode_mask = T_RADIO; - tun_setup.type = core->board.radio_type; - tun_setup.addr = core->board.radio_addr; - tun_setup.tuner_callback = cx88_tuner_callback; - client->driver->command (client, TUNER_SET_TYPE_ADDR, &tun_setup); - } - } - if (core->board.tuner_type != UNSET) { - if ((core->board.tuner_addr==ADDR_UNSET)||(core->board.tuner_addr==client->addr)) { - - tun_setup.mode_mask = T_ANALOG_TV; - tun_setup.type = core->board.tuner_type; - tun_setup.addr = core->board.tuner_addr; - tun_setup.tuner_callback = cx88_tuner_callback; - client->driver->command (client,TUNER_SET_TYPE_ADDR, &tun_setup); - } - } - - if (core->board.tda9887_conf) { - struct v4l2_priv_tun_config tda9887_cfg; - tda9887_cfg.tuner = TUNER_TDA9887; - tda9887_cfg.priv = &core->board.tda9887_conf; - - client->driver->command(client, TUNER_SET_CONFIG, &tda9887_cfg); - } return 0; } diff --git a/drivers/media/video/em28xx/Kconfig b/drivers/media/video/em28xx/Kconfig index 9caffed2b6b..c7c2896bbd8 100644 --- a/drivers/media/video/em28xx/Kconfig +++ b/drivers/media/video/em28xx/Kconfig @@ -1,7 +1,7 @@ config VIDEO_EM28XX tristate "Empia EM28xx USB video capture support" depends on VIDEO_DEV && I2C && INPUT - select VIDEO_TUNER + select MEDIA_TUNER select VIDEO_TVEEPROM select VIDEO_IR select VIDEOBUF_VMALLOC diff --git a/drivers/media/video/em28xx/Makefile b/drivers/media/video/em28xx/Makefile index 3d1c3cc337f..8137a8c94bf 100644 --- a/drivers/media/video/em28xx/Makefile +++ b/drivers/media/video/em28xx/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_VIDEO_EM28XX_ALSA) += em28xx-alsa.o obj-$(CONFIG_VIDEO_EM28XX_DVB) += em28xx-dvb.o EXTRA_CFLAGS += -Idrivers/media/video +EXTRA_CFLAGS += -Idrivers/media/common/tuners EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core EXTRA_CFLAGS += -Idrivers/media/dvb/frontends diff --git a/drivers/media/video/ivtv/Kconfig b/drivers/media/video/ivtv/Kconfig index b6171702c4d..eec115bf951 100644 --- a/drivers/media/video/ivtv/Kconfig +++ b/drivers/media/video/ivtv/Kconfig @@ -4,7 +4,7 @@ config VIDEO_IVTV select I2C_ALGOBIT select FW_LOADER select VIDEO_IR - select VIDEO_TUNER + select MEDIA_TUNER select VIDEO_TVEEPROM select VIDEO_CX2341X select VIDEO_CX25840 diff --git a/drivers/media/video/ivtv/Makefile b/drivers/media/video/ivtv/Makefile index a0389014fa8..26ce0d6eaee 100644 --- a/drivers/media/video/ivtv/Makefile +++ b/drivers/media/video/ivtv/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_VIDEO_IVTV) += ivtv.o obj-$(CONFIG_VIDEO_FB_IVTV) += ivtvfb.o EXTRA_CFLAGS += -Idrivers/media/video +EXTRA_CFLAGS += -Idrivers/media/common/tuners EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core EXTRA_CFLAGS += -Idrivers/media/dvb/frontends diff --git a/drivers/media/video/ivtv/ivtv-cards.c b/drivers/media/video/ivtv/ivtv-cards.c index e908649ea37..4fb8faefe2c 100644 --- a/drivers/media/video/ivtv/ivtv-cards.c +++ b/drivers/media/video/ivtv/ivtv-cards.c @@ -40,6 +40,8 @@ #define MSP_MONO MSP_INPUT(MSP_IN_MONO, MSP_IN_TUNER1, \ MSP_DSP_IN_SCART, MSP_DSP_IN_SCART) +#define V4L2_STD_NOT_MN (V4L2_STD_PAL|V4L2_STD_SECAM) + /* usual i2c tuner addresses to probe */ static struct ivtv_card_tuner_i2c ivtv_i2c_std = { .radio = { I2C_CLIENT_END }, @@ -298,7 +300,7 @@ static const struct ivtv_card ivtv_card_mpg600 = { .gpio_audio_detect = { .mask = 0x0900, .stereo = 0x0100 }, .tuners = { /* The PAL tuner is confirmed */ - { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FQ1216ME }, + { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FQ1216ME }, { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 }, }, .pci_list = ivtv_pci_mpg600, @@ -339,7 +341,7 @@ static const struct ivtv_card ivtv_card_mpg160 = { .lang1 = 0x0004, .lang2 = 0x0000, .both = 0x0008 }, .gpio_audio_detect = { .mask = 0x0900, .stereo = 0x0100 }, .tuners = { - { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FQ1216ME }, + { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FQ1216ME }, { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 }, }, .pci_list = ivtv_pci_mpg160, @@ -375,7 +377,7 @@ static const struct ivtv_card ivtv_card_pg600 = { { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL }, }, .tuners = { - { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FQ1216ME }, + { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FQ1216ME }, { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 }, }, .pci_list = ivtv_pci_pg600, @@ -416,7 +418,7 @@ static const struct ivtv_card ivtv_card_avc2410 = { on the country/region setting of the user to decide which tuner is available. */ .tuners = { - { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, + { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, { .std = V4L2_STD_ALL - V4L2_STD_NTSC_M_JP, .tuner = TUNER_PHILIPS_FM1236_MK3 }, { .std = V4L2_STD_NTSC_M_JP, .tuner = TUNER_PHILIPS_FQ1286 }, @@ -490,7 +492,7 @@ static const struct ivtv_card ivtv_card_tg5000tv = { .gpio_video_input = { .mask = 0x0030, .tuner = 0x0000, .composite = 0x0010, .svideo = 0x0020 }, .tuners = { - { .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 }, + { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PHILIPS_FQ1286 }, }, .pci_list = ivtv_pci_tg5000tv, .i2c = &ivtv_i2c_std, @@ -521,7 +523,7 @@ static const struct ivtv_card ivtv_card_va2000 = { { IVTV_CARD_INPUT_AUD_TUNER, MSP_TUNER }, }, .tuners = { - { .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 }, + { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PHILIPS_FQ1286 }, }, .pci_list = ivtv_pci_va2000, .i2c = &ivtv_i2c_std, @@ -565,7 +567,7 @@ static const struct ivtv_card ivtv_card_cx23416gyc = { .gpio_audio_freq = { .mask = 0xc000, .f32000 = 0x0000, .f44100 = 0x4000, .f48000 = 0x8000 }, .tuners = { - { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, + { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 }, }, .pci_list = ivtv_pci_cx23416gyc, @@ -597,7 +599,7 @@ static const struct ivtv_card ivtv_card_cx23416gyc_nogr = { .gpio_audio_freq = { .mask = 0xc000, .f32000 = 0x0000, .f44100 = 0x4000, .f48000 = 0x8000 }, .tuners = { - { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, + { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 }, }, .i2c = &ivtv_i2c_std, @@ -627,7 +629,7 @@ static const struct ivtv_card ivtv_card_cx23416gyc_nogrycs = { .gpio_audio_freq = { .mask = 0xc000, .f32000 = 0x0000, .f44100 = 0x4000, .f48000 = 0x8000 }, .tuners = { - { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, + { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 }, }, .i2c = &ivtv_i2c_std, @@ -667,7 +669,7 @@ static const struct ivtv_card ivtv_card_gv_mvprx = { .gpio_audio_input = { .mask = 0xffff, .tuner = 0x0200, .linein = 0x0300 }, .tuners = { /* This card has the Panasonic VP27 tuner */ - { .std = V4L2_STD_525_60, .tuner = TUNER_PANASONIC_VP27 }, + { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PANASONIC_VP27 }, }, .pci_list = ivtv_pci_gv_mvprx, .i2c = &ivtv_i2c_std, @@ -704,7 +706,7 @@ static const struct ivtv_card ivtv_card_gv_mvprx2e = { .gpio_audio_input = { .mask = 0xffff, .tuner = 0x0200, .linein = 0x0300 }, .tuners = { /* This card has the Panasonic VP27 tuner */ - { .std = V4L2_STD_525_60, .tuner = TUNER_PANASONIC_VP27 }, + { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PANASONIC_VP27 }, }, .pci_list = ivtv_pci_gv_mvprx2e, .i2c = &ivtv_i2c_std, @@ -739,7 +741,7 @@ static const struct ivtv_card ivtv_card_gotview_pci_dvd = { .gpio_init = { .direction = 0xf000, .initial_value = 0xA000 }, .tuners = { /* This card has a Philips FQ1216ME MK3 tuner */ - { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, + { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, }, .pci_list = ivtv_pci_gotview_pci_dvd, .i2c = &ivtv_i2c_std, @@ -778,7 +780,7 @@ static const struct ivtv_card ivtv_card_gotview_pci_dvd2 = { .gpio_audio_input = { .mask = 0x0800, .tuner = 0, .linein = 0, .radio = 0x0800 }, .tuners = { /* This card has a Philips FQ1216ME MK5 tuner */ - { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, + { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, }, .pci_list = ivtv_pci_gotview_pci_dvd2, .i2c = &ivtv_i2c_std, @@ -856,7 +858,7 @@ static const struct ivtv_card ivtv_card_dctmvtvp1 = { .gpio_video_input = { .mask = 0x0030, .tuner = 0x0000, .composite = 0x0010, .svideo = 0x0020}, .tuners = { - { .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 }, + { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PHILIPS_FQ1286 }, }, .pci_list = ivtv_pci_dctmvtvp1, .i2c = &ivtv_i2c_std, @@ -875,6 +877,7 @@ static const struct ivtv_card_pci_info ivtv_pci_pg600v2[] = { static const struct ivtv_card ivtv_card_pg600v2 = { .type = IVTV_CARD_PG600V2, .name = "Yuan PG600-2, GotView PCI DVD Lite", + .comment = "only Composite and S-Video inputs are supported, not the tuner\n", .v4l2_capabilities = IVTV_CAP_ENCODER, .hw_video = IVTV_HW_CX25840, .hw_audio = IVTV_HW_CX25840, @@ -921,6 +924,7 @@ static const struct ivtv_card ivtv_card_club3d = { }, .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, .gpio_init = { .direction = 0x1000, .initial_value = 0x1000 }, /* tuner reset */ + .xceive_pin = 12, .tuners = { { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, }, @@ -944,15 +948,22 @@ static const struct ivtv_card ivtv_card_avertv_mce116 = { .hw_video = IVTV_HW_CX25840, .hw_audio = IVTV_HW_CX25840, .hw_audio_ctrl = IVTV_HW_CX25840, - .hw_all = IVTV_HW_CX25840 | IVTV_HW_WM8739, + .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER | IVTV_HW_WM8739, .video_inputs = { - { IVTV_CARD_INPUT_SVIDEO1, 0, CX25840_SVIDEO3 }, - { IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE1 }, + { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, + { IVTV_CARD_INPUT_SVIDEO1, 1, CX25840_SVIDEO3 }, + { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 }, }, .audio_inputs = { + { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, 1 }, }, - .gpio_init = { .direction = 0xe000, .initial_value = 0x4000 }, /* enable line-in */ + /* enable line-in */ + .gpio_init = { .direction = 0xe400, .initial_value = 0x4400 }, + .xceive_pin = 10, + .tuners = { + { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, + }, .pci_list = ivtv_pci_avertv_mce116, .i2c = &ivtv_i2c_std, }; @@ -990,7 +1001,7 @@ static const struct ivtv_card ivtv_card_aver_pvr150 = { .gpio_audio_input = { .mask = 0x0800, .tuner = 0, .linein = 0, .radio = 0x0800 }, .tuners = { /* This card has a Partsnic PTI-5NF05 tuner */ - { .std = V4L2_STD_525_60, .tuner = TUNER_TCL_2002N }, + { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_TCL_2002N }, }, .pci_list = ivtv_pci_aver_pvr150, .i2c = &ivtv_i2c_radio, @@ -1058,12 +1069,48 @@ static const struct ivtv_card ivtv_card_asus_falcon2 = { }, .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, M52790_IN_TUNER }, .tuners = { - { .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FM1236_MK3 }, + { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PHILIPS_FM1236_MK3 }, }, .pci_list = ivtv_pci_asus_falcon2, .i2c = &ivtv_i2c_std, }; +/* ------------------------------------------------------------------------- */ + +/* AVerMedia M104 miniPCI card */ + +static const struct ivtv_card_pci_info ivtv_pci_aver_m104[] = { + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc136 }, + { 0, 0, 0 } +}; + +static const struct ivtv_card ivtv_card_aver_m104 = { + .type = IVTV_CARD_AVER_M104, + .name = "AVerMedia M104", + .comment = "Not yet supported!\n", + .v4l2_capabilities = 0, /*IVTV_CAP_ENCODER,*/ + .hw_video = IVTV_HW_CX25840, + .hw_audio = IVTV_HW_CX25840, + .hw_audio_ctrl = IVTV_HW_CX25840, + .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER | IVTV_HW_WM8739, + .video_inputs = { + { IVTV_CARD_INPUT_SVIDEO1, 0, CX25840_SVIDEO3 }, + { IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE1 }, + }, + .audio_inputs = { + { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, 1 }, + }, + .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, 2 }, + /* enable line-in + reset tuner */ + .gpio_init = { .direction = 0xe400, .initial_value = 0x4000 }, + .xceive_pin = 10, + .tuners = { + { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, + }, + .pci_list = ivtv_pci_aver_m104, + .i2c = &ivtv_i2c_std, +}; + static const struct ivtv_card *ivtv_card_list[] = { &ivtv_card_pvr250, &ivtv_card_pvr350, @@ -1089,6 +1136,7 @@ static const struct ivtv_card *ivtv_card_list[] = { &ivtv_card_asus_falcon2, &ivtv_card_aver_pvr150, &ivtv_card_aver_ezmaker, + &ivtv_card_aver_m104, /* Variations of standard cards but with the same PCI IDs. These cards must come last in this list. */ @@ -1120,7 +1168,8 @@ int ivtv_get_input(struct ivtv *itv, u16 index, struct v4l2_input *input) if (index >= itv->nof_inputs) return -EINVAL; input->index = index; - strcpy(input->name, input_strs[card_input->video_type - 1]); + strlcpy(input->name, input_strs[card_input->video_type - 1], + sizeof(input->name)); input->type = (card_input->video_type == IVTV_CARD_INPUT_VID_TUNER ? V4L2_INPUT_TYPE_TUNER : V4L2_INPUT_TYPE_CAMERA); input->audioset = (1 << itv->nof_audio_inputs) - 1; @@ -1137,7 +1186,7 @@ int ivtv_get_output(struct ivtv *itv, u16 index, struct v4l2_output *output) if (index >= itv->card->nof_outputs) return -EINVAL; output->index = index; - strcpy(output->name, card_output->name); + strlcpy(output->name, card_output->name, sizeof(output->name)); output->type = V4L2_OUTPUT_TYPE_ANALOG; output->audioset = 1; output->std = V4L2_STD_ALL; @@ -1156,7 +1205,8 @@ int ivtv_get_audio_input(struct ivtv *itv, u16 index, struct v4l2_audio *audio) memset(audio, 0, sizeof(*audio)); if (index >= itv->nof_audio_inputs) return -EINVAL; - strcpy(audio->name, input_strs[aud_input->audio_type - 1]); + strlcpy(audio->name, input_strs[aud_input->audio_type - 1], + sizeof(audio->name)); audio->index = index; audio->capability = V4L2_AUDCAP_STEREO; return 0; @@ -1167,6 +1217,6 @@ int ivtv_get_audio_output(struct ivtv *itv, u16 index, struct v4l2_audioout *aud memset(aud_output, 0, sizeof(*aud_output)); if (itv->card->video_outputs == NULL || index != 0) return -EINVAL; - strcpy(aud_output->name, "A/V Audio Out"); + strlcpy(aud_output->name, "A/V Audio Out", sizeof(aud_output->name)); return 0; } diff --git a/drivers/media/video/ivtv/ivtv-cards.h b/drivers/media/video/ivtv/ivtv-cards.h index 9186fa2ee5f..748485dcebb 100644 --- a/drivers/media/video/ivtv/ivtv-cards.h +++ b/drivers/media/video/ivtv/ivtv-cards.h @@ -48,7 +48,8 @@ #define IVTV_CARD_ASUS_FALCON2 21 /* ASUS Falcon2 */ #define IVTV_CARD_AVER_PVR150PLUS 22 /* AVerMedia PVR-150 Plus */ #define IVTV_CARD_AVER_EZMAKER 23 /* AVerMedia EZMaker PCI Deluxe */ -#define IVTV_CARD_LAST 23 +#define IVTV_CARD_AVER_M104 24 /* AverMedia M104 miniPCI card */ +#define IVTV_CARD_LAST 24 /* Variants of existing cards but with the same PCI IDs. The driver detects these based on other device information. @@ -244,6 +245,7 @@ struct ivtv_card_tuner_i2c { struct ivtv_card { int type; char *name; + char *comment; u32 v4l2_capabilities; u32 hw_video; /* hardware used to process video */ u32 hw_audio; /* hardware used to process audio */ @@ -256,6 +258,7 @@ struct ivtv_card { int nof_outputs; const struct ivtv_card_output *video_outputs; u8 gr_config; /* config byte for the ghost reduction device */ + u8 xceive_pin; /* XCeive tuner GPIO reset pin */ /* GPIO card-specific settings */ struct ivtv_gpio_init gpio_init; diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 065df53f80f..47b5649729d 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -190,6 +190,7 @@ MODULE_PARM_DESC(cardtype, "\t\t\t22 = ASUS Falcon2\n" "\t\t\t23 = AverMedia PVR-150 Plus\n" "\t\t\t24 = AverMedia EZMaker PCI Deluxe\n" + "\t\t\t25 = AverMedia M104 (not yet working)\n" "\t\t\t 0 = Autodetect (default)\n" "\t\t\t-1 = Ignore this card\n\t\t"); MODULE_PARM_DESC(pal, "Set PAL standard: BGH, DK, I, M, N, Nc, 60"); @@ -871,7 +872,7 @@ static void ivtv_load_and_init_modules(struct ivtv *itv) unsigned i; /* load modules */ -#ifndef CONFIG_VIDEO_TUNER +#ifndef CONFIG_MEDIA_TUNER hw = ivtv_request_module(itv, hw, "tuner", IVTV_HW_TUNER); #endif #ifndef CONFIG_VIDEO_CX25840 @@ -1097,6 +1098,13 @@ static int __devinit ivtv_probe(struct pci_dev *dev, The PCI IDs are not always reliable. */ ivtv_process_eeprom(itv); } + if (itv->card->comment) + IVTV_INFO("%s", itv->card->comment); + if (itv->card->v4l2_capabilities == 0) { + /* card was detected but is not supported */ + retval = -ENODEV; + goto free_i2c; + } if (itv->std == 0) { itv->std = V4L2_STD_NTSC_M; @@ -1195,13 +1203,6 @@ static int __devinit ivtv_probe(struct pci_dev *dev, ivtv_call_i2c_clients(itv, VIDIOC_INT_S_STD_OUTPUT, &itv->std); } - retval = ivtv_streams_setup(itv); - if (retval) { - IVTV_ERR("Error %d setting up streams\n", retval); - goto free_i2c; - } - - IVTV_DEBUG_IRQ("Masking interrupts\n"); /* clear interrupt mask, effectively disabling interrupts */ ivtv_set_irq_mask(itv, 0xffffffff); @@ -1210,32 +1211,38 @@ static int __devinit ivtv_probe(struct pci_dev *dev, IRQF_SHARED | IRQF_DISABLED, itv->name, (void *)itv); if (retval) { IVTV_ERR("Failed to register irq %d\n", retval); - goto free_streams; + goto free_i2c; + } + + retval = ivtv_streams_setup(itv); + if (retval) { + IVTV_ERR("Error %d setting up streams\n", retval); + goto free_irq; } retval = ivtv_streams_register(itv); if (retval) { IVTV_ERR("Error %d registering devices\n", retval); - goto free_irq; + goto free_streams; } IVTV_INFO("Initialized card #%d: %s\n", itv->num, itv->card_name); return 0; - free_irq: - free_irq(itv->dev->irq, (void *)itv); - free_streams: +free_streams: ivtv_streams_cleanup(itv); - free_i2c: +free_irq: + free_irq(itv->dev->irq, (void *)itv); +free_i2c: exit_ivtv_i2c(itv); - free_io: +free_io: ivtv_iounmap(itv); - free_mem: +free_mem: release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE); release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE); if (itv->has_cx23415) release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE); - free_workqueue: +free_workqueue: destroy_workqueue(itv->irq_work_queues); - err: +err: if (retval == 0) retval = -ENODEV; IVTV_ERR("Error %d on initialization\n", retval); diff --git a/drivers/media/video/ivtv/ivtv-gpio.c b/drivers/media/video/ivtv/ivtv-gpio.c index 688cd385668..d8ac09f3cce 100644 --- a/drivers/media/video/ivtv/ivtv-gpio.c +++ b/drivers/media/video/ivtv/ivtv-gpio.c @@ -128,20 +128,17 @@ int ivtv_reset_tuner_gpio(void *dev, int cmd, int value) { struct i2c_algo_bit_data *algo = dev; struct ivtv *itv = algo->data; - int curdir, curout; + u32 curout; if (cmd != XC2028_TUNER_RESET) return 0; IVTV_DEBUG_INFO("Resetting tuner\n"); curout = read_reg(IVTV_REG_GPIO_OUT); - curdir = read_reg(IVTV_REG_GPIO_DIR); - curdir |= (1 << 12); /* GPIO bit 12 */ - - curout &= ~(1 << 12); + curout &= ~(1 << itv->card->xceive_pin); write_reg(curout, IVTV_REG_GPIO_OUT); schedule_timeout_interruptible(msecs_to_jiffies(1)); - curout |= (1 << 12); + curout |= 1 << itv->card->xceive_pin; write_reg(curout, IVTV_REG_GPIO_OUT); schedule_timeout_interruptible(msecs_to_jiffies(1)); return 0; diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c index 9824eafee02..771adf47e94 100644 --- a/drivers/media/video/ivtv/ivtv-i2c.c +++ b/drivers/media/video/ivtv/ivtv-i2c.c @@ -167,7 +167,8 @@ int ivtv_i2c_register(struct ivtv *itv, unsigned idx) return -1; id = hw_driverids[idx]; memset(&info, 0, sizeof(info)); - strcpy(info.driver_name, hw_drivernames[idx]); + strlcpy(info.driver_name, hw_drivernames[idx], + sizeof(info.driver_name)); info.addr = hw_addrs[idx]; for (i = 0; itv->i2c_clients[i] && i < I2C_CLIENTS_MAX; i++) {} diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index 15cac181212..d508b5d0538 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -243,20 +243,31 @@ static int ivtv_validate_speed(int cur_speed, int new_speed) int fact = new_speed < 0 ? -1 : 1; int s; - if (new_speed < 0) new_speed = -new_speed; - if (cur_speed < 0) cur_speed = -cur_speed; + if (cur_speed == 0) + cur_speed = 1000; + if (new_speed < 0) + new_speed = -new_speed; + if (cur_speed < 0) + cur_speed = -cur_speed; if (cur_speed <= new_speed) { - if (new_speed > 1500) return fact * 2000; - if (new_speed > 1000) return fact * 1500; + if (new_speed > 1500) + return fact * 2000; + if (new_speed > 1000) + return fact * 1500; } else { - if (new_speed >= 2000) return fact * 2000; - if (new_speed >= 1500) return fact * 1500; - if (new_speed >= 1000) return fact * 1000; - } - if (new_speed == 0) return 1000; - if (new_speed == 1 || new_speed == 1000) return fact * new_speed; + if (new_speed >= 2000) + return fact * 2000; + if (new_speed >= 1500) + return fact * 1500; + if (new_speed >= 1000) + return fact * 1000; + } + if (new_speed == 0) + return 1000; + if (new_speed == 1 || new_speed == 1000) + return fact * new_speed; s = new_speed; new_speed = 1000 / new_speed; @@ -741,10 +752,9 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void struct v4l2_capability *vcap = arg; memset(vcap, 0, sizeof(*vcap)); - strcpy(vcap->driver, IVTV_DRIVER_NAME); /* driver name */ - strncpy(vcap->card, itv->card_name, - sizeof(vcap->card)-1); /* card type */ - strcpy(vcap->bus_info, pci_name(itv->dev)); /* bus info... */ + strlcpy(vcap->driver, IVTV_DRIVER_NAME, sizeof(vcap->driver)); + strlcpy(vcap->card, itv->card_name, sizeof(vcap->card)); + strlcpy(vcap->bus_info, pci_name(itv->dev), sizeof(vcap->bus_info)); vcap->version = IVTV_DRIVER_VERSION; /* version */ vcap->capabilities = itv->v4l2_cap; /* capabilities */ @@ -1018,7 +1028,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void ivtv_std_60hz : ivtv_std_50hz; vs->index = idx; vs->id = enum_stds[idx].std; - strcpy(vs->name, enum_stds[idx].name); + strlcpy(vs->name, enum_stds[idx].name, sizeof(vs->name)); break; } @@ -1102,10 +1112,10 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void ivtv_call_i2c_clients(itv, VIDIOC_G_TUNER, vt); if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) { - strcpy(vt->name, "ivtv Radio Tuner"); + strlcpy(vt->name, "ivtv Radio Tuner", sizeof(vt->name)); vt->type = V4L2_TUNER_RADIO; } else { - strcpy(vt->name, "ivtv TV Tuner"); + strlcpy(vt->name, "ivtv TV Tuner", sizeof(vt->name)); vt->type = V4L2_TUNER_ANALOG_TV; } break; diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c index a329c4689db..d8ba3a4a876 100644 --- a/drivers/media/video/ivtv/ivtv-irq.c +++ b/drivers/media/video/ivtv/ivtv-irq.c @@ -384,7 +384,7 @@ static void ivtv_dma_enc_start_xfer(struct ivtv_stream *s) ivtv_stream_sync_for_device(s); write_reg(s->sg_handle, IVTV_REG_ENCDMAADDR); write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x02, IVTV_REG_DMAXFER); - itv->dma_timer.expires = jiffies + msecs_to_jiffies(100); + itv->dma_timer.expires = jiffies + msecs_to_jiffies(300); add_timer(&itv->dma_timer); } @@ -400,7 +400,7 @@ static void ivtv_dma_dec_start_xfer(struct ivtv_stream *s) ivtv_stream_sync_for_device(s); write_reg(s->sg_handle, IVTV_REG_DECDMAADDR); write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x01, IVTV_REG_DMAXFER); - itv->dma_timer.expires = jiffies + msecs_to_jiffies(100); + itv->dma_timer.expires = jiffies + msecs_to_jiffies(300); add_timer(&itv->dma_timer); } diff --git a/drivers/media/video/ivtv/ivtv-version.h b/drivers/media/video/ivtv/ivtv-version.h index 0f1d4cc4b4d..02c5ab071d1 100644 --- a/drivers/media/video/ivtv/ivtv-version.h +++ b/drivers/media/video/ivtv/ivtv-version.h @@ -23,7 +23,7 @@ #define IVTV_DRIVER_NAME "ivtv" #define IVTV_DRIVER_VERSION_MAJOR 1 #define IVTV_DRIVER_VERSION_MINOR 2 -#define IVTV_DRIVER_VERSION_PATCHLEVEL 0 +#define IVTV_DRIVER_VERSION_PATCHLEVEL 1 #define IVTV_VERSION __stringify(IVTV_DRIVER_VERSION_MAJOR) "." __stringify(IVTV_DRIVER_VERSION_MINOR) "." __stringify(IVTV_DRIVER_VERSION_PATCHLEVEL) #define IVTV_DRIVER_VERSION KERNEL_VERSION(IVTV_DRIVER_VERSION_MAJOR,IVTV_DRIVER_VERSION_MINOR,IVTV_DRIVER_VERSION_PATCHLEVEL) diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c index 393d917cd67..62f70bd5e3c 100644 --- a/drivers/media/video/ivtv/ivtv-yuv.c +++ b/drivers/media/video/ivtv/ivtv-yuv.c @@ -1098,8 +1098,8 @@ void ivtv_yuv_setup_stream_frame(struct ivtv *itv) ivtv_yuv_next_free(itv); /* Copy V4L2 parameters to an ivtv_dma_frame struct... */ - dma_args.y_source = 0L; - dma_args.uv_source = 0L; + dma_args.y_source = NULL; + dma_args.uv_source = NULL; dma_args.src.left = 0; dma_args.src.top = 0; dma_args.src.width = yi->v4l2_src_w; diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c index 3b23fc05f7c..df789f683e6 100644 --- a/drivers/media/video/ivtv/ivtvfb.c +++ b/drivers/media/video/ivtv/ivtvfb.c @@ -532,7 +532,7 @@ static int ivtvfb_get_fix(struct ivtv *itv, struct fb_fix_screeninfo *fix) IVTVFB_DEBUG_INFO("ivtvfb_get_fix\n"); memset(fix, 0, sizeof(struct fb_fix_screeninfo)); - strcpy(fix->id, "cx23415 TV out"); + strlcpy(fix->id, "cx23415 TV out", sizeof(fix->id)); fix->smem_start = oi->video_pbase; fix->smem_len = oi->video_buffer_size; fix->type = FB_TYPE_PACKED_PIXELS; diff --git a/drivers/media/video/m52790.c b/drivers/media/video/m52790.c index d4bf14c284e..5b9dfa2c51b 100644 --- a/drivers/media/video/m52790.c +++ b/drivers/media/video/m52790.c @@ -126,7 +126,8 @@ static int m52790_command(struct i2c_client *client, unsigned int cmd, /* i2c implementation */ -static int m52790_probe(struct i2c_client *client) +static int m52790_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct m52790_state *state; diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c index b73c740f7fb..e6273162e12 100644 --- a/drivers/media/video/msp3400-driver.c +++ b/drivers/media/video/msp3400-driver.c @@ -805,7 +805,7 @@ static int msp_resume(struct i2c_client *client) /* ----------------------------------------------------------------------- */ -static int msp_probe(struct i2c_client *client) +static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct msp_state *state; int (*thread_func)(void *data) = NULL; diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c index 3fb5f63df1e..179e47049a4 100644 --- a/drivers/media/video/mt9m001.c +++ b/drivers/media/video/mt9m001.c @@ -372,7 +372,7 @@ static int mt9m001_set_register(struct soc_camera_device *icd, } #endif -const struct v4l2_queryctrl mt9m001_controls[] = { +static const struct v4l2_queryctrl mt9m001_controls[] = { { .id = V4L2_CID_VFLIP, .type = V4L2_CTRL_TYPE_BOOLEAN, @@ -620,7 +620,8 @@ static void mt9m001_video_remove(struct soc_camera_device *icd) soc_camera_video_stop(&mt9m001->icd); } -static int mt9m001_probe(struct i2c_client *client) +static int mt9m001_probe(struct i2c_client *client, + const struct i2c_device_id *did) { struct mt9m001 *mt9m001; struct soc_camera_device *icd; @@ -696,12 +697,19 @@ static int mt9m001_remove(struct i2c_client *client) return 0; } +static const struct i2c_device_id mt9m001_id[] = { + { "mt9m001", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, mt9m001_id); + static struct i2c_driver mt9m001_i2c_driver = { .driver = { .name = "mt9m001", }, .probe = mt9m001_probe, .remove = mt9m001_remove, + .id_table = mt9m001_id, }; static int __init mt9m001_mod_init(void) diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c index d4b9e274434..d1391ac5509 100644 --- a/drivers/media/video/mt9v022.c +++ b/drivers/media/video/mt9v022.c @@ -452,7 +452,7 @@ static int mt9v022_set_register(struct soc_camera_device *icd, } #endif -const struct v4l2_queryctrl mt9v022_controls[] = { +static const struct v4l2_queryctrl mt9v022_controls[] = { { .id = V4L2_CID_VFLIP, .type = V4L2_CTRL_TYPE_BOOLEAN, @@ -745,7 +745,8 @@ static void mt9v022_video_remove(struct soc_camera_device *icd) soc_camera_video_stop(&mt9v022->icd); } -static int mt9v022_probe(struct i2c_client *client) +static int mt9v022_probe(struct i2c_client *client, + const struct i2c_device_id *did) { struct mt9v022 *mt9v022; struct soc_camera_device *icd; @@ -818,12 +819,19 @@ static int mt9v022_remove(struct i2c_client *client) return 0; } +static const struct i2c_device_id mt9v022_id[] = { + { "mt9v022", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, mt9v022_id); + static struct i2c_driver mt9v022_i2c_driver = { .driver = { .name = "mt9v022", }, .probe = mt9v022_probe, .remove = mt9v022_remove, + .id_table = mt9v022_id, }; static int __init mt9v022_mod_init(void) diff --git a/drivers/media/video/pvrusb2/Kconfig b/drivers/media/video/pvrusb2/Kconfig index 158b3d0c653..9620c67fae7 100644 --- a/drivers/media/video/pvrusb2/Kconfig +++ b/drivers/media/video/pvrusb2/Kconfig @@ -1,14 +1,15 @@ config VIDEO_PVRUSB2 tristate "Hauppauge WinTV-PVR USB2 support" - depends on VIDEO_V4L2 && I2C && EXPERIMENTAL + depends on VIDEO_V4L2 && I2C select FW_LOADER - select VIDEO_TUNER + select MEDIA_TUNER select VIDEO_TVEEPROM select VIDEO_CX2341X select VIDEO_SAA711X select VIDEO_CX25840 select VIDEO_MSP3400 select VIDEO_WM8775 + select VIDEO_CS53L32A ---help--- This is a video4linux driver for Conexant 23416 based usb2 personal video recorder devices. @@ -16,32 +17,6 @@ config VIDEO_PVRUSB2 To compile this driver as a module, choose M here: the module will be called pvrusb2 -config VIDEO_PVRUSB2_ONAIR_CREATOR - bool "pvrusb2 driver support for OnAir Creator model" - depends on VIDEO_PVRUSB2 && EXPERIMENTAL - select VIDEO_SAA711X - select VIDEO_CS53L32A - ---help--- - - This option enables support for the OnAir Creator USB tuner - device. This is a hybrid device, however currently only - analog mode is supported. - - If you are in doubt, say Y. - -config VIDEO_PVRUSB2_ONAIR_USB2 - bool "pvrusb2 driver support for OnAir USB2 model" - depends on VIDEO_PVRUSB2 && EXPERIMENTAL - select VIDEO_SAA711X - select VIDEO_CS53L32A - ---help--- - - This option enables support for the OnAir USB2 tuner device - (also known as the Sasem tuner). This is a hybrid device, - however currently only analog mode is supported. - - If you are in doubt, say Y. - config VIDEO_PVRUSB2_SYSFS bool "pvrusb2 sysfs support (EXPERIMENTAL)" default y @@ -59,29 +34,23 @@ config VIDEO_PVRUSB2_SYSFS Note: This feature is experimental and subject to change. config VIDEO_PVRUSB2_DVB - bool "pvrusb2 DVB support (EXPERIMENTAL)" - default n + bool "pvrusb2 ATSC/DVB support (EXPERIMENTAL)" + default y depends on VIDEO_PVRUSB2 && DVB_CORE && EXPERIMENTAL select DVB_LGDT330X if !DVB_FE_CUSTOMISE select DVB_S5H1409 if !DVB_FE_CUSTOMISE select DVB_S5H1411 if !DVB_FE_CUSTOMISE select DVB_TDA10048 if !DVB_FE_CUSTOMIZE - select DVB_TDA18271 if !DVB_FE_CUSTOMIZE - select TUNER_SIMPLE if !DVB_FE_CUSTOMISE - select TUNER_TDA8290 if !DVB_FE_CUSTOMIZE + select MEDIA_TUNER_TDA18271 if !DVB_FE_CUSTOMIZE + select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_TDA8290 if !DVB_FE_CUSTOMIZE ---help--- - This option enables compilation of a DVB interface for the - pvrusb2 driver. Currently this is very very experimental. - It is also limiting - the DVB interface can only access the - digital side of hybrid devices, and there are going to be - issues if you attempt to mess with the V4L side at the same - time. Don't turn this on unless you know what you are - doing. - - If you are in doubt, say N. + This option enables a DVB interface for the pvrusb2 driver. + If your device does not support digital television, this + feature will have no affect on the driver's operation. - Note: This feature is very experimental and might break + If you are in doubt, say Y. config VIDEO_PVRUSB2_DEBUGIFC bool "pvrusb2 debug interface" diff --git a/drivers/media/video/pvrusb2/Makefile b/drivers/media/video/pvrusb2/Makefile index 5b3083c89aa..4fda2de69ab 100644 --- a/drivers/media/video/pvrusb2/Makefile +++ b/drivers/media/video/pvrusb2/Makefile @@ -16,5 +16,6 @@ pvrusb2-objs := pvrusb2-i2c-core.o pvrusb2-i2c-cmd-v4l2.o \ obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2.o EXTRA_CFLAGS += -Idrivers/media/video +EXTRA_CFLAGS += -Idrivers/media/common/tuners EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core EXTRA_CFLAGS += -Idrivers/media/dvb/frontends diff --git a/drivers/media/video/pvrusb2/pvrusb2-audio.c b/drivers/media/video/pvrusb2/pvrusb2-audio.c index 9a7c8e9c3e8..8d859ccd48e 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-audio.c +++ b/drivers/media/video/pvrusb2/pvrusb2-audio.c @@ -75,7 +75,7 @@ static void set_stereo(struct pvr2_msp3400_handler *ctxt) pvr2_trace(PVR2_TRACE_CHIPS,"i2c msp3400 v4l2 set_stereo"); if ((sid < ARRAY_SIZE(routing_schemes)) && - ((sp = routing_schemes + sid) != 0) && + ((sp = routing_schemes + sid) != NULL) && (hdw->input_val >= 0) && (hdw->input_val < sp->cnt)) { route.input = sp->def[hdw->input_val]; diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.c b/drivers/media/video/pvrusb2/pvrusb2-context.c index b5db6a5bab3..73dcb1c57ae 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-context.c +++ b/drivers/media/video/pvrusb2/pvrusb2-context.c @@ -195,7 +195,7 @@ static int pvr2_context_thread_func(void *foo) int pvr2_context_global_init(void) { pvr2_context_thread_ptr = kthread_run(pvr2_context_thread_func, - 0, + NULL, "pvrusb2-context"); return (pvr2_context_thread_ptr ? 0 : -ENOMEM); } diff --git a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c index 97350b048b8..29d50597c88 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c +++ b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c @@ -123,7 +123,7 @@ static void set_input(struct pvr2_v4l_cx2584x *ctxt) memset(&route,0,sizeof(route)); if ((sid < ARRAY_SIZE(routing_schemes)) && - ((sp = routing_schemes + sid) != 0) && + ((sp = routing_schemes + sid) != NULL) && (hdw->input_val >= 0) && (hdw->input_val < sp->cnt)) { vid_input = sp->def[hdw->input_val].vid; diff --git a/drivers/media/video/pvrusb2/pvrusb2-debug.h b/drivers/media/video/pvrusb2/pvrusb2-debug.h index 11537ddf8aa..707d2d9635d 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-debug.h +++ b/drivers/media/video/pvrusb2/pvrusb2-debug.h @@ -54,6 +54,7 @@ extern int pvrusb2_debug; #define PVR2_TRACE_DATA_FLOW (1 << 25) /* Track data flow */ #define PVR2_TRACE_DEBUGIFC (1 << 26) /* Debug interface actions */ #define PVR2_TRACE_GPIO (1 << 27) /* GPIO state bit changes */ +#define PVR2_TRACE_DVB_FEED (1 << 28) /* DVB transport feed debug */ #endif /* __PVRUSB2_HDW_INTERNAL_H */ diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/drivers/media/video/pvrusb2/pvrusb2-devattr.c index 3a141d93e1a..5bf6d8fda1f 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-devattr.c +++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.c @@ -153,7 +153,6 @@ static const struct pvr2_device_desc pvr2_device_gotview_2d = { -#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_CREATOR /*------------------------------------------------------------------------*/ /* OnAir Creator */ @@ -212,11 +211,9 @@ static const struct pvr2_device_desc pvr2_device_onair_creator = { .dvb_props = &pvr2_onair_creator_fe_props, #endif }; -#endif -#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_USB2 /*------------------------------------------------------------------------*/ /* OnAir USB 2.0 */ @@ -274,7 +271,6 @@ static const struct pvr2_device_desc pvr2_device_onair_usb2 = { .dvb_props = &pvr2_onair_usb2_fe_props, #endif }; -#endif @@ -497,14 +493,10 @@ struct usb_device_id pvr2_device_table[] = { .driver_info = (kernel_ulong_t)&pvr2_device_gotview_2}, { USB_DEVICE(0x1164, 0x0602), .driver_info = (kernel_ulong_t)&pvr2_device_gotview_2d}, -#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_CREATOR { USB_DEVICE(0x11ba, 0x1003), .driver_info = (kernel_ulong_t)&pvr2_device_onair_creator}, -#endif -#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_USB2 { USB_DEVICE(0x11ba, 0x1001), .driver_info = (kernel_ulong_t)&pvr2_device_onair_usb2}, -#endif { USB_DEVICE(0x2040, 0x7300), .driver_info = (kernel_ulong_t)&pvr2_device_73xxx}, { USB_DEVICE(0x2040, 0x7500), diff --git a/drivers/media/video/pvrusb2/pvrusb2-dvb.c b/drivers/media/video/pvrusb2/pvrusb2-dvb.c index 2e64f98d124..6ec4bf81fc7 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-dvb.c +++ b/drivers/media/video/pvrusb2/pvrusb2-dvb.c @@ -21,6 +21,7 @@ #include <linux/kthread.h> #include <linux/freezer.h> #include "dvbdev.h" +#include "pvrusb2-debug.h" #include "pvrusb2-hdw-internal.h" #include "pvrusb2-hdw.h" #include "pvrusb2-io.h" @@ -35,7 +36,7 @@ static int pvr2_dvb_feed_func(struct pvr2_dvb_adapter *adap) struct pvr2_buffer *bp; struct pvr2_stream *stream; - printk(KERN_DEBUG "dvb thread started\n"); + pvr2_trace(PVR2_TRACE_DVB_FEED, "dvb feed thread started"); set_freezable(); stream = adap->channel.stream->stream; @@ -82,7 +83,7 @@ static int pvr2_dvb_feed_func(struct pvr2_dvb_adapter *adap) /* If we get here and ret is < 0, then an error has occurred. Probably would be a good idea to communicate that to DVB core... */ - printk(KERN_DEBUG "dvb thread stopped\n"); + pvr2_trace(PVR2_TRACE_DVB_FEED, "dvb feed thread stopped"); return 0; } @@ -130,7 +131,7 @@ static void pvr2_dvb_stream_end(struct pvr2_dvb_adapter *adap) for (idx = 0; idx < PVR2_DVB_BUFFER_COUNT; idx++) { if (!(adap->buffer_storage[idx])) continue; kfree(adap->buffer_storage[idx]); - adap->buffer_storage[idx] = 0; + adap->buffer_storage[idx] = NULL; } adap->stream_run = 0; } @@ -142,7 +143,7 @@ static int pvr2_dvb_stream_do_start(struct pvr2_dvb_adapter *adap) unsigned int idx; int ret; struct pvr2_buffer *bp; - struct pvr2_stream *stream = 0; + struct pvr2_stream *stream = NULL; if (adap->stream_run) return -EIO; @@ -174,7 +175,7 @@ static int pvr2_dvb_stream_do_start(struct pvr2_dvb_adapter *adap) ret = pvr2_hdw_set_streaming(adap->channel.hdw, 1); if (ret < 0) return ret; - while ((bp = pvr2_stream_get_idle_buffer(stream)) != 0) { + while ((bp = pvr2_stream_get_idle_buffer(stream)) != NULL) { ret = pvr2_buffer_queue(bp); if (ret < 0) return ret; } @@ -210,7 +211,8 @@ static int pvr2_dvb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) do { if (onoff) { if (!adap->feedcount) { - printk(KERN_DEBUG "start feeding\n"); + pvr2_trace(PVR2_TRACE_DVB_FEED, + "start feeding demux"); ret = pvr2_dvb_stream_start(adap); if (ret < 0) break; } @@ -218,7 +220,8 @@ static int pvr2_dvb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) } else if (adap->feedcount > 0) { (adap->feedcount)--; if (!adap->feedcount) { - printk(KERN_DEBUG "stop feeding\n"); + pvr2_trace(PVR2_TRACE_DVB_FEED, + "stop feeding demux"); pvr2_dvb_stream_end(adap); } } @@ -230,15 +233,13 @@ static int pvr2_dvb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) static int pvr2_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed) { - printk(KERN_DEBUG "start pid: 0x%04x, feedtype: %d\n", - dvbdmxfeed->pid, dvbdmxfeed->type); + pvr2_trace(PVR2_TRACE_DVB_FEED, "start pid: 0x%04x", dvbdmxfeed->pid); return pvr2_dvb_ctrl_feed(dvbdmxfeed, 1); } static int pvr2_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) { - printk(KERN_DEBUG "stop pid: 0x%04x, feedtype: %d\n", - dvbdmxfeed->pid, dvbdmxfeed->type); + pvr2_trace(PVR2_TRACE_DVB_FEED, "stop pid: 0x%04x", dvbdmxfeed->pid); return pvr2_dvb_ctrl_feed(dvbdmxfeed, 0); } @@ -259,7 +260,8 @@ static int pvr2_dvb_adapter_init(struct pvr2_dvb_adapter *adap) &adap->channel.hdw->usb_dev->dev, adapter_nr); if (ret < 0) { - err("dvb_register_adapter failed: error %d", ret); + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "dvb_register_adapter failed: error %d", ret); goto err; } adap->dvb_adap.priv = adap; @@ -276,7 +278,8 @@ static int pvr2_dvb_adapter_init(struct pvr2_dvb_adapter *adap) ret = dvb_dmx_init(&adap->demux); if (ret < 0) { - err("dvb_dmx_init failed: error %d", ret); + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "dvb_dmx_init failed: error %d", ret); goto err_dmx; } @@ -286,7 +289,8 @@ static int pvr2_dvb_adapter_init(struct pvr2_dvb_adapter *adap) ret = dvb_dmxdev_init(&adap->dmxdev, &adap->dvb_adap); if (ret < 0) { - err("dvb_dmxdev_init failed: error %d", ret); + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "dvb_dmxdev_init failed: error %d", ret); goto err_dmx_dev; } @@ -304,7 +308,7 @@ err: static int pvr2_dvb_adapter_exit(struct pvr2_dvb_adapter *adap) { - printk(KERN_DEBUG "unregistering DVB devices\n"); + pvr2_trace(PVR2_TRACE_INFO, "unregistering DVB devices"); dvb_net_release(&adap->dvb_net); adap->demux.dmx.close(&adap->demux.dmx); dvb_dmxdev_release(&adap->dmxdev); @@ -320,7 +324,7 @@ static int pvr2_dvb_frontend_init(struct pvr2_dvb_adapter *adap) int ret = 0; if (dvb_props == NULL) { - err("fe_props not defined!"); + pvr2_trace(PVR2_TRACE_ERROR_LEGS, "fe_props not defined!"); return -EINVAL; } @@ -328,13 +332,15 @@ static int pvr2_dvb_frontend_init(struct pvr2_dvb_adapter *adap) &adap->channel, (1 << PVR2_CVAL_INPUT_DTV)); if (ret) { - err("failed to grab control of dtv input (code=%d)", + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "failed to grab control of dtv input (code=%d)", ret); return ret; } if (dvb_props->frontend_attach == NULL) { - err("frontend_attach not defined!"); + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "frontend_attach not defined!"); ret = -EINVAL; goto done; } @@ -342,7 +348,8 @@ static int pvr2_dvb_frontend_init(struct pvr2_dvb_adapter *adap) if ((dvb_props->frontend_attach(adap) == 0) && (adap->fe)) { if (dvb_register_frontend(&adap->dvb_adap, adap->fe)) { - err("frontend registration failed!"); + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "frontend registration failed!"); dvb_frontend_detach(adap->fe); adap->fe = NULL; ret = -ENODEV; @@ -359,7 +366,8 @@ static int pvr2_dvb_frontend_init(struct pvr2_dvb_adapter *adap) adap->fe->ops.ts_bus_ctrl = pvr2_dvb_bus_ctrl; } else { - err("no frontend was attached!"); + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "no frontend was attached!"); ret = -ENODEV; return ret; } diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c index 087a1824556..e9b5d4e9132 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c @@ -1261,7 +1261,7 @@ struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *mnp) fail: pvr2_trace(PVR2_TRACE_STRUCT,"Failure creating pvr2_v4l2 id=%p",vp); pvr2_v4l2_destroy_no_lock(vp); - return 0; + return NULL; } /* diff --git a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c index 7c47345501b..2433a316004 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c +++ b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c @@ -81,7 +81,7 @@ static void set_input(struct pvr2_v4l_decoder *ctxt) pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_input(%d)",hdw->input_val); if ((sid < ARRAY_SIZE(routing_schemes)) && - ((sp = routing_schemes + sid) != 0) && + ((sp = routing_schemes + sid) != NULL) && (hdw->input_val >= 0) && (hdw->input_val < sp->cnt)) { route.input = sp->def[hdw->input_val]; diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c index 416d05d4a96..e684108637a 100644 --- a/drivers/media/video/saa7115.c +++ b/drivers/media/video/saa7115.c @@ -1450,7 +1450,8 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar /* ----------------------------------------------------------------------- */ -static int saa7115_probe(struct i2c_client *client) +static int saa7115_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct saa711x_state *state; int i; diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c index 06c88db656b..e750cd65c1c 100644 --- a/drivers/media/video/saa7127.c +++ b/drivers/media/video/saa7127.c @@ -661,7 +661,8 @@ static int saa7127_command(struct i2c_client *client, /* ----------------------------------------------------------------------- */ -static int saa7127_probe(struct i2c_client *client) +static int saa7127_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct saa7127_state *state; struct v4l2_sliced_vbi_data vbi = { 0, 0, 0, 0 }; /* set to disabled */ diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig index e086f14d566..40e4c3bd2cb 100644 --- a/drivers/media/video/saa7134/Kconfig +++ b/drivers/media/video/saa7134/Kconfig @@ -3,7 +3,7 @@ config VIDEO_SAA7134 depends on VIDEO_DEV && PCI && I2C && INPUT select VIDEOBUF_DMA_SG select VIDEO_IR - select VIDEO_TUNER + select MEDIA_TUNER select VIDEO_TVEEPROM select CRC32 ---help--- @@ -35,9 +35,9 @@ config VIDEO_SAA7134_DVB select DVB_NXT200X if !DVB_FE_CUSTOMISE select DVB_TDA10086 if !DVB_FE_CUSTOMISE select DVB_TDA826X if !DVB_FE_CUSTOMISE - select DVB_TDA827X if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_TDA827X if !DVB_FE_CUSTOMISE select DVB_ISL6421 if !DVB_FE_CUSTOMISE - select TUNER_SIMPLE if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE ---help--- This adds support for DVB cards based on the Philips saa7134 chip. diff --git a/drivers/media/video/saa7134/Makefile b/drivers/media/video/saa7134/Makefile index 9aff937ba7a..3dbaa19a6d0 100644 --- a/drivers/media/video/saa7134/Makefile +++ b/drivers/media/video/saa7134/Makefile @@ -11,5 +11,6 @@ obj-$(CONFIG_VIDEO_SAA7134_ALSA) += saa7134-alsa.o obj-$(CONFIG_VIDEO_SAA7134_DVB) += saa7134-dvb.o EXTRA_CFLAGS += -Idrivers/media/video +EXTRA_CFLAGS += -Idrivers/media/common/tuners EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core EXTRA_CFLAGS += -Idrivers/media/dvb/frontends diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 98375955a84..b111903aa32 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -47,6 +47,9 @@ static char name_svideo[] = "S-Video"; /* ------------------------------------------------------------------ */ /* board config info */ +/* If radio_type !=UNSET, radio_addr should be specified + */ + struct saa7134_board saa7134_boards[] = { [SAA7134_BOARD_UNKNOWN] = { .name = "UNKNOWN/GENERIC", @@ -3087,7 +3090,7 @@ struct saa7134_board saa7134_boards[] = { .tuner_type = TUNER_PHILIPS_TD1316, /* untested */ .radio_type = TUNER_TEA5767, /* untested */ .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, + .radio_addr = 0x60, .tda9887_conf = TDA9887_PRESENT, .mpeg = SAA7134_MPEG_DVB, .inputs = {{ @@ -4247,6 +4250,36 @@ struct saa7134_board saa7134_boards[] = { .amux = LINE1, } }, }, + [SAA7134_BOARD_BEHOLD_H6] = { + /* Igor Kuznetsov <igk@igk.ru> */ + .name = "Beholder BeholdTV H6", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .inputs = {{ + .name = name_tv, + .vmux = 3, + .amux = TV, + .tv = 1, + }, { + .name = name_comp1, + .vmux = 1, + .amux = LINE1, + }, { + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + } }, + .radio = { + .name = name_radio, + .amux = LINE2, + }, + /* no DVB support for now */ + /* .mpeg = SAA7134_MPEG_DVB, */ + }, }; const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards); @@ -5197,6 +5230,12 @@ struct pci_device_id saa7134_pci_tbl[] = { .subvendor = 0x5ace, .subdevice = 0x6193, .driver_data = SAA7134_BOARD_BEHOLD_M6, + }, { + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x5ace, + .subdevice = 0x6191, + .driver_data = SAA7134_BOARD_BEHOLD_M6, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, @@ -5246,6 +5285,12 @@ struct pci_device_id saa7134_pci_tbl[] = { .subdevice = 0xc900, .driver_data = SAA7134_BOARD_VIDEOMATE_T750, }, { + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x5ace, + .subdevice = 0x6290, + .driver_data = SAA7134_BOARD_BEHOLD_H6, + }, { /* --- boards without eeprom + subsystem ID --- */ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, @@ -5577,20 +5622,87 @@ int saa7134_board_init1(struct saa7134_dev *dev) return 0; } +static void saa7134_tuner_setup(struct saa7134_dev *dev) +{ + struct tuner_setup tun_setup; + unsigned int mode_mask = T_RADIO | + T_ANALOG_TV | + T_DIGITAL_TV; + + memset(&tun_setup, 0, sizeof(tun_setup)); + tun_setup.tuner_callback = saa7134_tuner_callback; + + if (saa7134_boards[dev->board].radio_type != UNSET) { + tun_setup.type = saa7134_boards[dev->board].radio_type; + tun_setup.addr = saa7134_boards[dev->board].radio_addr; + + tun_setup.mode_mask = T_RADIO; + + saa7134_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup); + mode_mask &= ~T_RADIO; + } + + if ((dev->tuner_type != TUNER_ABSENT) && (dev->tuner_type != UNSET)) { + tun_setup.type = dev->tuner_type; + tun_setup.addr = dev->tuner_addr; + tun_setup.config = saa7134_boards[dev->board].tuner_config; + tun_setup.tuner_callback = saa7134_tuner_callback; + + tun_setup.mode_mask = mode_mask; + + saa7134_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup); + } + + if (dev->tda9887_conf) { + struct v4l2_priv_tun_config tda9887_cfg; + + tda9887_cfg.tuner = TUNER_TDA9887; + tda9887_cfg.priv = &dev->tda9887_conf; + + saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, + &tda9887_cfg); + } + + if (dev->tuner_type == TUNER_XC2028) { + struct v4l2_priv_tun_config xc2028_cfg; + struct xc2028_ctrl ctl; + + memset(&xc2028_cfg, 0, sizeof(ctl)); + memset(&ctl, 0, sizeof(ctl)); + + ctl.fname = XC2028_DEFAULT_FIRMWARE; + ctl.max_len = 64; + + switch (dev->board) { + case SAA7134_BOARD_AVERMEDIA_A16D: + ctl.demod = XC3028_FE_ZARLINK456; + break; + default: + ctl.demod = XC3028_FE_OREN538; + ctl.mts = 1; + } + + xc2028_cfg.tuner = TUNER_XC2028; + xc2028_cfg.priv = &ctl; + + saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, &xc2028_cfg); + } +} + /* stuff which needs working i2c */ int saa7134_board_init2(struct saa7134_dev *dev) { unsigned char buf; int board; - struct tuner_setup tun_setup; - tun_setup.config = 0; - tun_setup.tuner_callback = saa7134_tuner_callback; + + dev->tuner_type = saa7134_boards[dev->board].tuner_type; + dev->tuner_addr = saa7134_boards[dev->board].tuner_addr; switch (dev->board) { case SAA7134_BOARD_BMK_MPEX_NOTUNER: case SAA7134_BOARD_BMK_MPEX_TUNER: dev->i2c_client.addr = 0x60; - board = (i2c_master_recv(&dev->i2c_client,&buf,0) < 0) + board = (i2c_master_recv(&dev->i2c_client, &buf, 0) < 0) ? SAA7134_BOARD_BMK_MPEX_NOTUNER : SAA7134_BOARD_BMK_MPEX_TUNER; if (board == dev->board) @@ -5600,21 +5712,9 @@ int saa7134_board_init2(struct saa7134_dev *dev) saa7134_boards[dev->board].name); dev->tuner_type = saa7134_boards[dev->board].tuner_type; - if (TUNER_ABSENT != dev->tuner_type) { - tun_setup.mode_mask = T_RADIO | - T_ANALOG_TV | - T_DIGITAL_TV; - tun_setup.type = dev->tuner_type; - tun_setup.addr = ADDR_UNSET; - tun_setup.tuner_callback = saa7134_tuner_callback; - - saa7134_i2c_call_clients(dev, - TUNER_SET_TYPE_ADDR, - &tun_setup); - } break; case SAA7134_BOARD_MD7134: - { + { u8 subaddr; u8 data[3]; int ret, tuner_t; @@ -5667,30 +5767,8 @@ int saa7134_board_init2(struct saa7134_dev *dev) } printk(KERN_INFO "%s Tuner type is %d\n", dev->name, dev->tuner_type); - if (dev->tuner_type == TUNER_PHILIPS_FMD1216ME_MK3) { - struct v4l2_priv_tun_config tda9887_cfg; - - tda9887_cfg.tuner = TUNER_TDA9887; - tda9887_cfg.priv = &dev->tda9887_conf; - - dev->tda9887_conf = TDA9887_PRESENT | - TDA9887_PORT1_ACTIVE | - TDA9887_PORT2_ACTIVE; - - saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, - &tda9887_cfg); - } - - tun_setup.mode_mask = T_RADIO | - T_ANALOG_TV | - T_DIGITAL_TV; - tun_setup.type = dev->tuner_type; - tun_setup.addr = ADDR_UNSET; - - saa7134_i2c_call_clients(dev, - TUNER_SET_TYPE_ADDR, &tun_setup); - } break; + } case SAA7134_BOARD_PHILIPS_EUROPA: if (dev->autodetected && (dev->eedata[0x41] == 0x1c)) { /* Reconfigure board as Snake reference design */ @@ -5702,43 +5780,43 @@ int saa7134_board_init2(struct saa7134_dev *dev) } case SAA7134_BOARD_VIDEOMATE_DVBT_300: case SAA7134_BOARD_ASUS_EUROPA2_HYBRID: + { + /* The Philips EUROPA based hybrid boards have the tuner connected through * the channel decoder. We have to make it transparent to find it */ - { u8 data[] = { 0x07, 0x02}; struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; i2c_transfer(&dev->i2c_adap, &msg, 1); - tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV; - tun_setup.type = dev->tuner_type; - tun_setup.addr = dev->tuner_addr; - - saa7134_i2c_call_clients (dev, TUNER_SET_TYPE_ADDR,&tun_setup); - } break; + } case SAA7134_BOARD_PHILIPS_TIGER: case SAA7134_BOARD_PHILIPS_TIGER_S: - { + { u8 data[] = { 0x3c, 0x33, 0x60}; struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; - if(dev->autodetected && (dev->eedata[0x49] == 0x50)) { + if (dev->autodetected && (dev->eedata[0x49] == 0x50)) { dev->board = SAA7134_BOARD_PHILIPS_TIGER_S; printk(KERN_INFO "%s: Reconfigured board as %s\n", dev->name, saa7134_boards[dev->board].name); } - if(dev->board == SAA7134_BOARD_PHILIPS_TIGER_S) { - tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV; - tun_setup.type = TUNER_PHILIPS_TDA8290; - tun_setup.addr = 0x4b; - tun_setup.config = 2; + if (dev->board == SAA7134_BOARD_PHILIPS_TIGER_S) { + dev->tuner_type = TUNER_PHILIPS_TDA8290; + + saa7134_tuner_setup(dev); - saa7134_i2c_call_clients (dev, TUNER_SET_TYPE_ADDR,&tun_setup); data[2] = 0x68; + i2c_transfer(&dev->i2c_adap, &msg, 1); + + /* Tuner setup is handled before I2C transfer. + Due to that, there's no need to do it later + */ + return 0; } i2c_transfer(&dev->i2c_adap, &msg, 1); - } break; + } case SAA7134_BOARD_HAUPPAUGE_HVR1110: hauppauge_eeprom(dev, dev->eedata+0x80); /* break intentionally omitted */ @@ -5751,52 +5829,55 @@ int saa7134_board_init2(struct saa7134_dev *dev) case SAA7134_BOARD_AVERMEDIA_SUPER_007: case SAA7134_BOARD_TWINHAN_DTV_DVB_3056: case SAA7134_BOARD_CREATIX_CTX953: + { /* this is a hybrid board, initialize to analog mode * and configure firmware eeprom address */ - { u8 data[] = { 0x3c, 0x33, 0x60}; struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; i2c_transfer(&dev->i2c_adap, &msg, 1); - } break; + } case SAA7134_BOARD_FLYDVB_TRIO: - { + { u8 data[] = { 0x3c, 0x33, 0x62}; struct i2c_msg msg = {.addr=0x09, .flags=0, .buf=data, .len = sizeof(data)}; i2c_transfer(&dev->i2c_adap, &msg, 1); - } break; + } case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331: case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS: + { /* initialize analog mode */ - { u8 data[] = { 0x3c, 0x33, 0x6a}; struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; i2c_transfer(&dev->i2c_adap, &msg, 1); - } break; + } case SAA7134_BOARD_CINERGY_HT_PCMCIA: case SAA7134_BOARD_CINERGY_HT_PCI: + { /* initialize analog mode */ - { u8 data[] = { 0x3c, 0x33, 0x68}; struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; i2c_transfer(&dev->i2c_adap, &msg, 1); - } break; + } case SAA7134_BOARD_KWORLD_ATSC110: - { - /* enable tuner */ - int i; - static const u8 buffer [] = { 0x10,0x12,0x13,0x04,0x16,0x00,0x14,0x04,0x017,0x00 }; - dev->i2c_client.addr = 0x0a; - for (i = 0; i < 5; i++) - if (2 != i2c_master_send(&dev->i2c_client,&buffer[i*2],2)) - printk(KERN_WARNING "%s: Unable to enable tuner(%i).\n", - dev->name, i); - } + { + /* enable tuner */ + int i; + static const u8 buffer [] = { 0x10, 0x12, 0x13, 0x04, 0x16, + 0x00, 0x14, 0x04, 0x17, 0x00 }; + dev->i2c_client.addr = 0x0a; + for (i = 0; i < 5; i++) + if (2 != i2c_master_send(&dev->i2c_client, + &buffer[i*2], 2)) + printk(KERN_WARNING + "%s: Unable to enable tuner(%i).\n", + dev->name, i); break; + } case SAA7134_BOARD_VIDEOMATE_DVBT_200: case SAA7134_BOARD_VIDEOMATE_DVBT_200A: /* The T200 and the T200A share the same pci id. Consequently, @@ -5821,7 +5902,7 @@ int saa7134_board_init2(struct saa7134_dev *dev) } break; case SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM: - { + { struct v4l2_priv_tun_config tea5767_cfg; struct tea5767_ctrl ctl; @@ -5832,34 +5913,11 @@ int saa7134_board_init2(struct saa7134_dev *dev) tea5767_cfg.tuner = TUNER_TEA5767; tea5767_cfg.priv = &ctl; saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, &tea5767_cfg); - } break; } + } /* switch() */ - if (dev->tuner_type == TUNER_XC2028) { - struct v4l2_priv_tun_config xc2028_cfg; - struct xc2028_ctrl ctl; - - memset(&xc2028_cfg, 0, sizeof(ctl)); - memset(&ctl, 0, sizeof(ctl)); - - ctl.fname = XC2028_DEFAULT_FIRMWARE; - ctl.max_len = 64; - - switch (dev->board) { - case SAA7134_BOARD_AVERMEDIA_A16D: - ctl.demod = XC3028_FE_ZARLINK456; - break; - default: - ctl.demod = XC3028_FE_OREN538; - ctl.mts = 1; - } - - xc2028_cfg.tuner = TUNER_XC2028; - xc2028_cfg.priv = &ctl; - - saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, &xc2028_cfg); - } + saa7134_tuner_setup(dev); return 0; } diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c index 2ccfaba0c49..d8af3863f2d 100644 --- a/drivers/media/video/saa7134/saa7134-i2c.c +++ b/drivers/media/video/saa7134/saa7134-i2c.c @@ -324,8 +324,6 @@ static u32 functionality(struct i2c_adapter *adap) static int attach_inform(struct i2c_client *client) { struct saa7134_dev *dev = client->adapter->algo_data; - int tuner = dev->tuner_type; - struct tuner_setup tun_setup; d1printk( "%s i2c attach [addr=0x%x,client=%s]\n", client->driver->driver.name, client->addr, client->name); @@ -346,46 +344,6 @@ static int attach_inform(struct i2c_client *client) } } - if (!client->driver->command) - return 0; - - if (saa7134_boards[dev->board].radio_type != UNSET) { - - tun_setup.type = saa7134_boards[dev->board].radio_type; - tun_setup.addr = saa7134_boards[dev->board].radio_addr; - - if ((tun_setup.addr == ADDR_UNSET) || (tun_setup.addr == client->addr)) { - tun_setup.mode_mask = T_RADIO; - - client->driver->command(client, TUNER_SET_TYPE_ADDR, &tun_setup); - } - } - - if (tuner != UNSET) { - tun_setup.type = tuner; - tun_setup.addr = saa7134_boards[dev->board].tuner_addr; - tun_setup.config = saa7134_boards[dev->board].tuner_config; - tun_setup.tuner_callback = saa7134_tuner_callback; - - if ((tun_setup.addr == ADDR_UNSET)||(tun_setup.addr == client->addr)) { - - tun_setup.mode_mask = T_ANALOG_TV; - - client->driver->command(client,TUNER_SET_TYPE_ADDR, &tun_setup); - } - - if (tuner == TUNER_TDA9887) { - struct v4l2_priv_tun_config tda9887_cfg; - - tda9887_cfg.tuner = TUNER_TDA9887; - tda9887_cfg.priv = &dev->tda9887_conf; - - client->driver->command(client, TUNER_SET_CONFIG, - &tda9887_cfg); - } - } - - return 0; } diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index 767ff30832f..919632b10aa 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -531,6 +531,7 @@ void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir) break; case SAA7134_BOARD_BEHOLD_607_9FM: case SAA7134_BOARD_BEHOLD_M6: + case SAA7134_BOARD_BEHOLD_H6: snprintf(ir->c.name, sizeof(ir->c.name), "BeholdTV"); ir->get_key = get_key_beholdm6xx; ir->ir_codes = ir_codes_behold; diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 924ffd13637..34ff0d4998f 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -263,6 +263,7 @@ struct saa7134_format { #define SAA7134_BOARD_VIDEOMATE_T750 139 #define SAA7134_BOARD_AVERMEDIA_A700_PRO 140 #define SAA7134_BOARD_AVERMEDIA_A700_HYBRID 141 +#define SAA7134_BOARD_BEHOLD_H6 142 #define SAA7134_MAXBOARDS 8 diff --git a/drivers/media/video/saa717x.c b/drivers/media/video/saa717x.c index 53c5edbcf7e..72c4081feff 100644 --- a/drivers/media/video/saa717x.c +++ b/drivers/media/video/saa717x.c @@ -1418,7 +1418,8 @@ static int saa717x_command(struct i2c_client *client, unsigned cmd, void *arg) /* i2c implementation */ /* ----------------------------------------------------------------------- */ -static int saa717x_probe(struct i2c_client *client) +static int saa717x_probe(struct i2c_client *client, + const struct i2c_device_id *did) { struct saa717x_state *decoder; u8 id = 0; diff --git a/drivers/media/video/tcm825x.c b/drivers/media/video/tcm825x.c index 6943b447a1b..e57a6460577 100644 --- a/drivers/media/video/tcm825x.c +++ b/drivers/media/video/tcm825x.c @@ -840,7 +840,8 @@ static struct v4l2_int_device tcm825x_int_device = { }, }; -static int tcm825x_probe(struct i2c_client *client) +static int tcm825x_probe(struct i2c_client *client, + const struct i2c_device_id *did) { struct tcm825x_sensor *sensor = &tcm825x; int rval; diff --git a/drivers/media/video/tlv320aic23b.c b/drivers/media/video/tlv320aic23b.c index dc7b9c220b9..f1db54202de 100644 --- a/drivers/media/video/tlv320aic23b.c +++ b/drivers/media/video/tlv320aic23b.c @@ -125,7 +125,8 @@ static int tlv320aic23b_command(struct i2c_client *client, * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' */ -static int tlv320aic23b_probe(struct i2c_client *client) +static int tlv320aic23b_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct tlv320aic23b_state *state; diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 2b72e10e6b9..cc19c4abb46 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -33,6 +33,46 @@ #define PREFIX t->i2c->driver->driver.name +/** This macro allows us to probe dynamically, avoiding static links */ +#ifdef CONFIG_DVB_CORE_ATTACH +#define tuner_symbol_probe(FUNCTION, ARGS...) ({ \ + int __r = -EINVAL; \ + typeof(&FUNCTION) __a = symbol_request(FUNCTION); \ + if (__a) { \ + __r = (int) __a(ARGS); \ + } else { \ + printk(KERN_ERR "TUNER: Unable to find " \ + "symbol "#FUNCTION"()\n"); \ + } \ + symbol_put(FUNCTION); \ + __r; \ +}) + +static void tuner_detach(struct dvb_frontend *fe) +{ + if (fe->ops.tuner_ops.release) { + fe->ops.tuner_ops.release(fe); + symbol_put_addr(fe->ops.tuner_ops.release); + } + if (fe->ops.analog_ops.release) { + fe->ops.analog_ops.release(fe); + symbol_put_addr(fe->ops.analog_ops.release); + } +} +#else +#define tuner_symbol_probe(FUNCTION, ARGS...) ({ \ + FUNCTION(ARGS); \ +}) + +static void tuner_detach(struct dvb_frontend *fe) +{ + if (fe->ops.tuner_ops.release) + fe->ops.tuner_ops.release(fe); + if (fe->ops.analog_ops.release) + fe->ops.analog_ops.release(fe); +} +#endif + struct tuner { /* device */ struct dvb_frontend fe; @@ -56,7 +96,7 @@ struct tuner { /* standard i2c insmod options */ static unsigned short normal_i2c[] = { -#if defined(CONFIG_TUNER_TEA5761) || (defined(CONFIG_TUNER_TEA5761_MODULE) && defined(MODULE)) +#if defined(CONFIG_MEDIA_TUNER_TEA5761) || (defined(CONFIG_MEDIA_TUNER_TEA5761_MODULE) && defined(MODULE)) 0x10, #endif 0x42, 0x43, 0x4a, 0x4b, /* tda8290 */ @@ -139,22 +179,6 @@ static void fe_set_params(struct dvb_frontend *fe, fe_tuner_ops->set_analog_params(fe, params); } -static void fe_release(struct dvb_frontend *fe) -{ - if (fe->ops.tuner_ops.release) - fe->ops.tuner_ops.release(fe); - - /* DO NOT kfree(fe->analog_demod_priv) - * - * If we are in this function, analog_demod_priv contains a pointer - * to struct tuner *t. This will be kfree'd in tuner_detach(). - * - * Otherwise, fe->ops.analog_demod_ops->release will - * handle the cleanup for analog demodulator modules. - */ - fe->analog_demod_priv = NULL; -} - static void fe_standby(struct dvb_frontend *fe) { struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops; @@ -191,7 +215,6 @@ static void tuner_status(struct dvb_frontend *fe); static struct analog_demod_ops tuner_core_ops = { .set_params = fe_set_params, .standby = fe_standby, - .release = fe_release, .has_signal = fe_has_signal, .set_config = fe_set_config, .tuner_status = tuner_status @@ -323,7 +346,8 @@ static void attach_tda829x(struct tuner *t) .lna_cfg = t->config, .tuner_callback = t->tuner_callback, }; - tda829x_attach(&t->fe, t->i2c->adapter, t->i2c->addr, &cfg); + dvb_attach(tda829x_attach, + &t->fe, t->i2c->adapter, t->i2c->addr, &cfg); } static struct xc5000_config xc5000_cfg; @@ -356,12 +380,13 @@ static void set_type(struct i2c_client *c, unsigned int type, } /* discard private data, in case set_type() was previously called */ - if (analog_ops->release) - analog_ops->release(&t->fe); + tuner_detach(&t->fe); + t->fe.analog_demod_priv = NULL; switch (t->type) { case TUNER_MT2032: - microtune_attach(&t->fe, t->i2c->adapter, t->i2c->addr); + dvb_attach(microtune_attach, + &t->fe, t->i2c->adapter, t->i2c->addr); break; case TUNER_PHILIPS_TDA8290: { @@ -369,12 +394,14 @@ static void set_type(struct i2c_client *c, unsigned int type, break; } case TUNER_TEA5767: - if (!tea5767_attach(&t->fe, t->i2c->adapter, t->i2c->addr)) + if (!dvb_attach(tea5767_attach, &t->fe, + t->i2c->adapter, t->i2c->addr)) goto attach_failed; t->mode_mask = T_RADIO; break; case TUNER_TEA5761: - if (!tea5761_attach(&t->fe, t->i2c->adapter, t->i2c->addr)) + if (!dvb_attach(tea5761_attach, &t->fe, + t->i2c->adapter, t->i2c->addr)) goto attach_failed; t->mode_mask = T_RADIO; break; @@ -388,8 +415,8 @@ static void set_type(struct i2c_client *c, unsigned int type, buffer[2] = 0x86; buffer[3] = 0x54; i2c_master_send(c, buffer, 4); - if (!simple_tuner_attach(&t->fe, t->i2c->adapter, t->i2c->addr, - t->type)) + if (!dvb_attach(simple_tuner_attach, &t->fe, + t->i2c->adapter, t->i2c->addr, t->type)) goto attach_failed; break; case TUNER_PHILIPS_TD1316: @@ -397,9 +424,9 @@ static void set_type(struct i2c_client *c, unsigned int type, buffer[1] = 0xdc; buffer[2] = 0x86; buffer[3] = 0xa4; - i2c_master_send(c,buffer,4); - if (!simple_tuner_attach(&t->fe, t->i2c->adapter, - t->i2c->addr, t->type)) + i2c_master_send(c, buffer, 4); + if (!dvb_attach(simple_tuner_attach, &t->fe, + t->i2c->adapter, t->i2c->addr, t->type)) goto attach_failed; break; case TUNER_XC2028: @@ -409,12 +436,13 @@ static void set_type(struct i2c_client *c, unsigned int type, .i2c_addr = t->i2c->addr, .callback = t->tuner_callback, }; - if (!xc2028_attach(&t->fe, &cfg)) + if (!dvb_attach(xc2028_attach, &t->fe, &cfg)) goto attach_failed; break; } case TUNER_TDA9887: - tda9887_attach(&t->fe, t->i2c->adapter, t->i2c->addr); + dvb_attach(tda9887_attach, + &t->fe, t->i2c->adapter, t->i2c->addr); break; case TUNER_XC5000: { @@ -424,7 +452,8 @@ static void set_type(struct i2c_client *c, unsigned int type, xc5000_cfg.if_khz = 5380; xc5000_cfg.priv = c->adapter->algo_data; xc5000_cfg.tuner_callback = t->tuner_callback; - if (!xc5000_attach(&t->fe, t->i2c->adapter, &xc5000_cfg)) + if (!dvb_attach(xc5000_attach, + &t->fe, t->i2c->adapter, &xc5000_cfg)) goto attach_failed; xc_tuner_ops = &t->fe.ops.tuner_ops; @@ -433,8 +462,8 @@ static void set_type(struct i2c_client *c, unsigned int type, break; } default: - if (!simple_tuner_attach(&t->fe, t->i2c->adapter, - t->i2c->addr, t->type)) + if (!dvb_attach(simple_tuner_attach, &t->fe, + t->i2c->adapter, t->i2c->addr, t->type)) goto attach_failed; break; @@ -442,12 +471,14 @@ static void set_type(struct i2c_client *c, unsigned int type, if ((NULL == analog_ops->set_params) && (fe_tuner_ops->set_analog_params)) { + strlcpy(t->i2c->name, fe_tuner_ops->info.name, sizeof(t->i2c->name)); t->fe.analog_demod_priv = t; memcpy(analog_ops, &tuner_core_ops, sizeof(struct analog_demod_ops)); + } else { strlcpy(t->i2c->name, analog_ops->info.name, sizeof(t->i2c->name)); @@ -645,8 +676,8 @@ static void tuner_status(struct dvb_frontend *fe) { struct tuner *t = fe->analog_demod_priv; unsigned long freq, freq_fraction; - struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; - struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; + struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops; + struct analog_demod_ops *analog_ops = &fe->ops.analog_ops; const char *p; switch (t->mode) { @@ -730,8 +761,10 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; - if (tuner_debug>1) + if (tuner_debug > 1) { v4l_i2c_print_ioctl(client,cmd); + printk("\n"); + } switch (cmd) { /* --- configuration --- */ @@ -1073,7 +1106,8 @@ static void tuner_lookup(struct i2c_adapter *adap, /* During client attach, set_type is called by adapter's attach_inform callback. set_type must then be completed by tuner_probe. */ -static int tuner_probe(struct i2c_client *client) +static int tuner_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct tuner *t; struct tuner *radio; @@ -1111,8 +1145,9 @@ static int tuner_probe(struct i2c_client *client) if (!no_autodetect) { switch (client->addr) { case 0x10: - if (tea5761_autodetection(t->i2c->adapter, - t->i2c->addr) >= 0) { + if (tuner_symbol_probe(tea5761_autodetection, + t->i2c->adapter, + t->i2c->addr) >= 0) { t->type = TUNER_TEA5761; t->mode_mask = T_RADIO; t->mode = T_STANDBY; @@ -1131,8 +1166,8 @@ static int tuner_probe(struct i2c_client *client) case 0x4b: /* If chip is not tda8290, don't register. since it can be tda9887*/ - if (tda829x_probe(t->i2c->adapter, - t->i2c->addr) == 0) { + if (tuner_symbol_probe(tda829x_probe, t->i2c->adapter, + t->i2c->addr) == 0) { tuner_dbg("tda829x detected\n"); } else { /* Default is being tda9887 */ @@ -1144,7 +1179,8 @@ static int tuner_probe(struct i2c_client *client) } break; case 0x60: - if (tea5767_autodetection(t->i2c->adapter, t->i2c->addr) + if (tuner_symbol_probe(tea5767_autodetection, + t->i2c->adapter, t->i2c->addr) != EINVAL) { t->type = TUNER_TEA5767; t->mode_mask = T_RADIO; @@ -1233,10 +1269,9 @@ static int tuner_legacy_probe(struct i2c_adapter *adap) static int tuner_remove(struct i2c_client *client) { struct tuner *t = i2c_get_clientdata(client); - struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; - if (analog_ops->release) - analog_ops->release(&t->fe); + tuner_detach(&t->fe); + t->fe.analog_demod_priv = NULL; list_del(&t->list); kfree(t); diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c index f29a2cd0f2f..6f9945b04e1 100644 --- a/drivers/media/video/tvaudio.c +++ b/drivers/media/video/tvaudio.c @@ -1461,7 +1461,7 @@ static struct CHIPDESC chiplist[] = { /* ---------------------------------------------------------------------- */ /* i2c registration */ -static int chip_probe(struct i2c_client *client) +static int chip_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct CHIPSTATE *chip; struct CHIPDESC *desc; diff --git a/drivers/media/video/upd64031a.c b/drivers/media/video/upd64031a.c index bd201397a2a..93bfd19dec7 100644 --- a/drivers/media/video/upd64031a.c +++ b/drivers/media/video/upd64031a.c @@ -195,7 +195,8 @@ static int upd64031a_command(struct i2c_client *client, unsigned cmd, void *arg) /* i2c implementation */ -static int upd64031a_probe(struct i2c_client *client) +static int upd64031a_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct upd64031a_state *state; int i; diff --git a/drivers/media/video/upd64083.c b/drivers/media/video/upd64083.c index 2d9a88f70c8..9ab712a56ce 100644 --- a/drivers/media/video/upd64083.c +++ b/drivers/media/video/upd64083.c @@ -172,7 +172,8 @@ static int upd64083_command(struct i2c_client *client, unsigned cmd, void *arg) /* i2c implementation */ -static int upd64083_probe(struct i2c_client *client) +static int upd64083_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct upd64083_state *state; int i; diff --git a/drivers/media/video/usbvision/Kconfig b/drivers/media/video/usbvision/Kconfig index fc24ef05b3f..74e1d3075a2 100644 --- a/drivers/media/video/usbvision/Kconfig +++ b/drivers/media/video/usbvision/Kconfig @@ -1,7 +1,7 @@ config VIDEO_USBVISION tristate "USB video devices based on Nogatech NT1003/1004/1005" depends on I2C && VIDEO_V4L2 - select VIDEO_TUNER + select MEDIA_TUNER select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO ---help--- There are more than 50 different USB video devices based on diff --git a/drivers/media/video/usbvision/Makefile b/drivers/media/video/usbvision/Makefile index 9ac92a80c64..33871875094 100644 --- a/drivers/media/video/usbvision/Makefile +++ b/drivers/media/video/usbvision/Makefile @@ -3,3 +3,4 @@ usbvision-objs := usbvision-core.o usbvision-video.o usbvision-i2c.o usbvision- obj-$(CONFIG_VIDEO_USBVISION) += usbvision.o EXTRA_CFLAGS += -Idrivers/media/video +EXTRA_CFLAGS += -Idrivers/media/common/tuners diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c index 34deb68ae56..e9dd996fd5d 100644 --- a/drivers/media/video/v4l2-common.c +++ b/drivers/media/video/v4l2-common.c @@ -710,13 +710,14 @@ EXPORT_SYMBOL(v4l2_chip_ident_i2c_client); /* Helper function for I2C legacy drivers */ int v4l2_i2c_attach(struct i2c_adapter *adapter, int address, struct i2c_driver *driver, - const char *name, int (*probe)(struct i2c_client *)) + const char *name, + int (*probe)(struct i2c_client *, const struct i2c_device_id *)) { struct i2c_client *client; int err; client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (client == 0) + if (!client) return -ENOMEM; client->addr = address; @@ -724,7 +725,7 @@ int v4l2_i2c_attach(struct i2c_adapter *adapter, int address, struct i2c_driver client->driver = driver; strlcpy(client->name, name, sizeof(client->name)); - err = probe(client); + err = probe(client, NULL); if (err == 0) { i2c_attach_client(client); } else { diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c index fc51e4918bb..982f4463896 100644 --- a/drivers/media/video/videobuf-core.c +++ b/drivers/media/video/videobuf-core.c @@ -97,7 +97,10 @@ int videobuf_iolock(struct videobuf_queue *q, struct videobuf_buffer *vb, void *videobuf_queue_to_vmalloc (struct videobuf_queue *q, struct videobuf_buffer *buf) { - return CALL(q, vmalloc, buf); + if (q->int_ops->vmalloc) + return q->int_ops->vmalloc(buf); + else + return NULL; } EXPORT_SYMBOL_GPL(videobuf_queue_to_vmalloc); diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c index d545c98dd5e..01ea99c9bc1 100644 --- a/drivers/media/video/vino.c +++ b/drivers/media/video/vino.c @@ -13,7 +13,7 @@ /* * TODO: * - remove "mark pages reserved-hacks" from memory allocation code - * and implement nopage() + * and implement fault() * - check decimation, calculating and reporting image size when * using decimation * - implement read(), user mode buffers and overlay (?) diff --git a/drivers/media/video/vp27smpx.c b/drivers/media/video/vp27smpx.c index 282c81403c9..fac0deba24a 100644 --- a/drivers/media/video/vp27smpx.c +++ b/drivers/media/video/vp27smpx.c @@ -121,7 +121,8 @@ static int vp27smpx_command(struct i2c_client *client, unsigned cmd, void *arg) * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' */ -static int vp27smpx_probe(struct i2c_client *client) +static int vp27smpx_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct vp27smpx_state *state; diff --git a/drivers/media/video/wm8739.c b/drivers/media/video/wm8739.c index 31795b4f8b6..0f8ed8461fb 100644 --- a/drivers/media/video/wm8739.c +++ b/drivers/media/video/wm8739.c @@ -261,7 +261,8 @@ static int wm8739_command(struct i2c_client *client, unsigned cmd, void *arg) /* i2c implementation */ -static int wm8739_probe(struct i2c_client *client) +static int wm8739_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct wm8739_state *state; diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c index 869f9e7946b..67a409e60c4 100644 --- a/drivers/media/video/wm8775.c +++ b/drivers/media/video/wm8775.c @@ -159,7 +159,8 @@ static int wm8775_command(struct i2c_client *client, unsigned cmd, void *arg) * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' */ -static int wm8775_probe(struct i2c_client *client) +static int wm8775_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct wm8775_state *state; diff --git a/drivers/media/video/zoran_procfs.c b/drivers/media/video/zoran_procfs.c index 328ed6e7ac6..870bc5a70e3 100644 --- a/drivers/media/video/zoran_procfs.c +++ b/drivers/media/video/zoran_procfs.c @@ -180,6 +180,7 @@ static ssize_t zoran_write(struct file *file, const char __user *buffer, } static const struct file_operations zoran_operations = { + .owner = THIS_MODULE, .open = zoran_open, .read = seq_read, .write = zoran_write, @@ -195,10 +196,8 @@ zoran_proc_init (struct zoran *zr) char name[8]; snprintf(name, 7, "zoran%d", zr->id); - if ((zr->zoran_proc = create_proc_entry(name, 0, NULL))) { - zr->zoran_proc->data = zr; - zr->zoran_proc->owner = THIS_MODULE; - zr->zoran_proc->proc_fops = &zoran_operations; + zr->zoran_proc = proc_create_data(name, 0, NULL, &zoran_operations, zr); + if (zr->zoran_proc != NULL) { dprintk(2, KERN_INFO "%s: procfs entry /proc/%s allocated. data=%p\n", diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c index a9531489740..81483de8c0f 100644 --- a/drivers/message/i2o/i2o_block.c +++ b/drivers/message/i2o/i2o_block.c @@ -371,7 +371,7 @@ static int i2o_block_prep_req_fn(struct request_queue *q, struct request *req) /* connect the i2o_block_request to the request */ if (!req->special) { ireq = i2o_block_request_alloc(); - if (unlikely(IS_ERR(ireq))) { + if (IS_ERR(ireq)) { osm_debug("unable to allocate i2o_block_request!\n"); return BLKPREP_DEFER; } diff --git a/drivers/message/i2o/i2o_proc.c b/drivers/message/i2o/i2o_proc.c index 6fdd072201f..54a3016ff45 100644 --- a/drivers/message/i2o/i2o_proc.c +++ b/drivers/message/i2o/i2o_proc.c @@ -1893,13 +1893,11 @@ static int i2o_proc_create_entries(struct proc_dir_entry *dir, struct proc_dir_entry *tmp; while (i2o_pe->name) { - tmp = create_proc_entry(i2o_pe->name, i2o_pe->mode, dir); + tmp = proc_create_data(i2o_pe->name, i2o_pe->mode, dir, + i2o_pe->fops, data); if (!tmp) return -1; - tmp->data = data; - tmp->proc_fops = i2o_pe->fops; - i2o_pe++; } diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c index 13bac53db69..6e655b4c668 100644 --- a/drivers/mfd/sm501.c +++ b/drivers/mfd/sm501.c @@ -22,6 +22,7 @@ #include <linux/sm501.h> #include <linux/sm501-regs.h> +#include <linux/serial_8250.h> #include <asm/io.h> @@ -723,13 +724,14 @@ static void sm501_device_release(struct device *dev) */ static struct platform_device * -sm501_create_subdev(struct sm501_devdata *sm, - char *name, unsigned int res_count) +sm501_create_subdev(struct sm501_devdata *sm, char *name, + unsigned int res_count, unsigned int platform_data_size) { struct sm501_device *smdev; smdev = kzalloc(sizeof(struct sm501_device) + - sizeof(struct resource) * res_count, GFP_KERNEL); + (sizeof(struct resource) * res_count) + + platform_data_size, GFP_KERNEL); if (!smdev) return NULL; @@ -737,11 +739,15 @@ sm501_create_subdev(struct sm501_devdata *sm, smdev->pdev.name = name; smdev->pdev.id = sm->pdev_id; - smdev->pdev.resource = (struct resource *)(smdev+1); - smdev->pdev.num_resources = res_count; - smdev->pdev.dev.parent = sm->dev; + if (res_count) { + smdev->pdev.resource = (struct resource *)(smdev+1); + smdev->pdev.num_resources = res_count; + } + if (platform_data_size) + smdev->pdev.dev.platform_data = (void *)(smdev+1); + return &smdev->pdev; } @@ -829,7 +835,7 @@ static int sm501_register_usbhost(struct sm501_devdata *sm, { struct platform_device *pdev; - pdev = sm501_create_subdev(sm, "sm501-usb", 3); + pdev = sm501_create_subdev(sm, "sm501-usb", 3, 0); if (!pdev) return -ENOMEM; @@ -840,12 +846,55 @@ static int sm501_register_usbhost(struct sm501_devdata *sm, return sm501_register_device(sm, pdev); } +static void sm501_setup_uart_data(struct sm501_devdata *sm, + struct plat_serial8250_port *uart_data, + unsigned int offset) +{ + uart_data->membase = sm->regs + offset; + uart_data->mapbase = sm->io_res->start + offset; + uart_data->iotype = UPIO_MEM; + uart_data->irq = sm->irq; + uart_data->flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ; + uart_data->regshift = 2; + uart_data->uartclk = (9600 * 16); +} + +static int sm501_register_uart(struct sm501_devdata *sm, int devices) +{ + struct platform_device *pdev; + struct plat_serial8250_port *uart_data; + + pdev = sm501_create_subdev(sm, "serial8250", 0, + sizeof(struct plat_serial8250_port) * 3); + if (!pdev) + return -ENOMEM; + + uart_data = pdev->dev.platform_data; + + if (devices & SM501_USE_UART0) { + sm501_setup_uart_data(sm, uart_data++, 0x30000); + sm501_unit_power(sm->dev, SM501_GATE_UART0, 1); + sm501_modify_reg(sm->dev, SM501_IRQ_MASK, 1 << 12, 0); + sm501_modify_reg(sm->dev, SM501_GPIO63_32_CONTROL, 0x01e0, 0); + } + if (devices & SM501_USE_UART1) { + sm501_setup_uart_data(sm, uart_data++, 0x30020); + sm501_unit_power(sm->dev, SM501_GATE_UART1, 1); + sm501_modify_reg(sm->dev, SM501_IRQ_MASK, 1 << 13, 0); + sm501_modify_reg(sm->dev, SM501_GPIO63_32_CONTROL, 0x1e00, 0); + } + + pdev->id = PLAT8250_DEV_SM501; + + return sm501_register_device(sm, pdev); +} + static int sm501_register_display(struct sm501_devdata *sm, resource_size_t *mem_avail) { struct platform_device *pdev; - pdev = sm501_create_subdev(sm, "sm501-fb", 4); + pdev = sm501_create_subdev(sm, "sm501-fb", 4, 0); if (!pdev) return -ENOMEM; @@ -963,6 +1012,7 @@ static unsigned int sm501_mem_local[] = { static int sm501_init_dev(struct sm501_devdata *sm) { + struct sm501_initdata *idata; resource_size_t mem_avail; unsigned long dramctrl; unsigned long devid; @@ -980,6 +1030,9 @@ static int sm501_init_dev(struct sm501_devdata *sm) return -EINVAL; } + /* disable irqs */ + writel(0, sm->regs + SM501_IRQ_MASK); + dramctrl = readl(sm->regs + SM501_DRAM_CONTROL); mem_avail = sm501_mem_local[(dramctrl >> 13) & 0x7]; @@ -998,15 +1051,14 @@ static int sm501_init_dev(struct sm501_devdata *sm) /* check to see if we have some device initialisation */ - if (sm->platdata) { - struct sm501_platdata *pdata = sm->platdata; + idata = sm->platdata ? sm->platdata->init : NULL; + if (idata) { + sm501_init_regs(sm, idata); - if (pdata->init) { - sm501_init_regs(sm, sm->platdata->init); - - if (pdata->init->devices & SM501_USE_USB_HOST) - sm501_register_usbhost(sm, &mem_avail); - } + if (idata->devices & SM501_USE_USB_HOST) + sm501_register_usbhost(sm, &mem_avail); + if (idata->devices & (SM501_USE_UART0 | SM501_USE_UART1)) + sm501_register_uart(sm, idata->devices); } ret = sm501_check_clocks(sm); diff --git a/drivers/mfd/ucb1x00-ts.c b/drivers/mfd/ucb1x00-ts.c index 5e859486eaf..ad34e2d2252 100644 --- a/drivers/mfd/ucb1x00-ts.c +++ b/drivers/mfd/ucb1x00-ts.c @@ -204,8 +204,7 @@ static inline int ucb1x00_ts_pen_down(struct ucb1x00_ts *ts) static int ucb1x00_thread(void *_ts) { struct ucb1x00_ts *ts = _ts; - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); + DECLARE_WAITQUEUE(wait, current); int valid = 0; set_freezable(); @@ -234,7 +233,7 @@ static int ucb1x00_thread(void *_ts) if (ucb1x00_ts_pen_down(ts)) { - set_task_state(tsk, TASK_INTERRUPTIBLE); + set_current_state(TASK_INTERRUPTIBLE); ucb1x00_enable_irq(ts->ucb, UCB_IRQ_TSPX, machine_is_collie() ? UCB_RISING : UCB_FALLING); ucb1x00_disable(ts->ucb); @@ -262,7 +261,7 @@ static int ucb1x00_thread(void *_ts) valid = 1; } - set_task_state(tsk, TASK_INTERRUPTIBLE); + set_current_state(TASK_INTERRUPTIBLE); timeout = HZ / 100; } diff --git a/drivers/misc/hdpuftrs/hdpu_cpustate.c b/drivers/misc/hdpuftrs/hdpu_cpustate.c index 302e92418bb..ff51ab67231 100644 --- a/drivers/misc/hdpuftrs/hdpu_cpustate.c +++ b/drivers/misc/hdpuftrs/hdpu_cpustate.c @@ -210,13 +210,10 @@ static int hdpu_cpustate_probe(struct platform_device *pdev) return ret; } - proc_de = create_proc_entry("sky_cpustate", 0666, &proc_root); + proc_de = proc_create("sky_cpustate", 0666, NULL, &proc_cpustate); if (!proc_de) { printk(KERN_WARNING "sky_cpustate: " "Unable to create proc entry\n"); - } else { - proc_de->proc_fops = &proc_cpustate; - proc_de->owner = THIS_MODULE; } printk(KERN_INFO "Sky CPU State Driver v" SKY_CPUSTATE_VERSION "\n"); diff --git a/drivers/misc/hdpuftrs/hdpu_nexus.c b/drivers/misc/hdpuftrs/hdpu_nexus.c index 2fa36f7a6eb..08e26beefe6 100644 --- a/drivers/misc/hdpuftrs/hdpu_nexus.c +++ b/drivers/misc/hdpuftrs/hdpu_nexus.c @@ -102,22 +102,17 @@ static int hdpu_nexus_probe(struct platform_device *pdev) printk(KERN_ERR "sky_nexus: Could not map slot id\n"); } - hdpu_slot_id = create_proc_entry("sky_slot_id", 0666, &proc_root); + hdpu_slot_id = proc_create("sky_slot_id", 0666, NULL, &proc_slot_id); if (!hdpu_slot_id) { printk(KERN_WARNING "sky_nexus: " "Unable to create proc dir entry: sky_slot_id\n"); - } else { - hdpu_slot_id->proc_fops = &proc_slot_id; - hdpu_slot_id->owner = THIS_MODULE; } - hdpu_chassis_id = create_proc_entry("sky_chassis_id", 0666, &proc_root); - if (!hdpu_chassis_id) { + hdpu_chassis_id = proc_create("sky_chassis_id", 0666, NULL, + &proc_chassis_id); + if (!hdpu_chassis_id) printk(KERN_WARNING "sky_nexus: " "Unable to create proc dir entry: sky_chassis_id\n"); - } else { - hdpu_chassis_id->proc_fops = &proc_chassis_id; - hdpu_chassis_id->owner = THIS_MODULE; } return 0; @@ -128,8 +123,8 @@ static int hdpu_nexus_remove(struct platform_device *pdev) slot_id = -1; chassis_id = -1; - remove_proc_entry("sky_slot_id", &proc_root); - remove_proc_entry("sky_chassis_id", &proc_root); + remove_proc_entry("sky_slot_id", NULL); + remove_proc_entry("sky_chassis_id", NULL); hdpu_slot_id = 0; hdpu_chassis_id = 0; diff --git a/drivers/misc/ibmasm/command.c b/drivers/misc/ibmasm/command.c index 1a0e7978226..276d3fb6809 100644 --- a/drivers/misc/ibmasm/command.c +++ b/drivers/misc/ibmasm/command.c @@ -96,7 +96,7 @@ static inline void do_exec_command(struct service_processor *sp) { char tsbuf[32]; - dbg("%s:%d at %s\n", __FUNCTION__, __LINE__, get_timestamp(tsbuf)); + dbg("%s:%d at %s\n", __func__, __LINE__, get_timestamp(tsbuf)); if (ibmasm_send_i2o_message(sp)) { sp->current_command->status = IBMASM_CMD_FAILED; @@ -119,7 +119,7 @@ void ibmasm_exec_command(struct service_processor *sp, struct command *cmd) unsigned long flags; char tsbuf[32]; - dbg("%s:%d at %s\n", __FUNCTION__, __LINE__, get_timestamp(tsbuf)); + dbg("%s:%d at %s\n", __func__, __LINE__, get_timestamp(tsbuf)); spin_lock_irqsave(&sp->lock, flags); @@ -139,7 +139,7 @@ static void exec_next_command(struct service_processor *sp) unsigned long flags; char tsbuf[32]; - dbg("%s:%d at %s\n", __FUNCTION__, __LINE__, get_timestamp(tsbuf)); + dbg("%s:%d at %s\n", __func__, __LINE__, get_timestamp(tsbuf)); spin_lock_irqsave(&sp->lock, flags); sp->current_command = dequeue_command(sp); diff --git a/drivers/misc/ibmasm/heartbeat.c b/drivers/misc/ibmasm/heartbeat.c index 3036e785b3e..1bc4306572a 100644 --- a/drivers/misc/ibmasm/heartbeat.c +++ b/drivers/misc/ibmasm/heartbeat.c @@ -75,9 +75,9 @@ void ibmasm_heartbeat_exit(struct service_processor *sp) { char tsbuf[32]; - dbg("%s:%d at %s\n", __FUNCTION__, __LINE__, get_timestamp(tsbuf)); + dbg("%s:%d at %s\n", __func__, __LINE__, get_timestamp(tsbuf)); ibmasm_wait_for_response(sp->heartbeat, IBMASM_CMD_TIMEOUT_NORMAL); - dbg("%s:%d at %s\n", __FUNCTION__, __LINE__, get_timestamp(tsbuf)); + dbg("%s:%d at %s\n", __func__, __LINE__, get_timestamp(tsbuf)); suspend_heartbeats = 1; command_put(sp->heartbeat); } @@ -88,7 +88,7 @@ void ibmasm_receive_heartbeat(struct service_processor *sp, void *message, size struct dot_command_header *header = (struct dot_command_header *)cmd->buffer; char tsbuf[32]; - dbg("%s:%d at %s\n", __FUNCTION__, __LINE__, get_timestamp(tsbuf)); + dbg("%s:%d at %s\n", __func__, __LINE__, get_timestamp(tsbuf)); if (suspend_heartbeats) return; diff --git a/drivers/misc/intel_menlow.c b/drivers/misc/intel_menlow.c index 0c0bb3093e0..80a13635240 100644 --- a/drivers/misc/intel_menlow.c +++ b/drivers/misc/intel_menlow.c @@ -175,19 +175,17 @@ static int intel_menlow_memory_add(struct acpi_device *device) goto end; } - if (cdev) { - acpi_driver_data(device) = cdev; - result = sysfs_create_link(&device->dev.kobj, - &cdev->device.kobj, "thermal_cooling"); - if (result) - goto unregister; - - result = sysfs_create_link(&cdev->device.kobj, - &device->dev.kobj, "device"); - if (result) { - sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); - goto unregister; - } + acpi_driver_data(device) = cdev; + result = sysfs_create_link(&device->dev.kobj, + &cdev->device.kobj, "thermal_cooling"); + if (result) + goto unregister; + + result = sysfs_create_link(&cdev->device.kobj, + &device->dev.kobj, "device"); + if (result) { + sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); + goto unregister; } end: diff --git a/drivers/misc/ioc4.c b/drivers/misc/ioc4.c index 05172d2613d..6f76573e7c8 100644 --- a/drivers/misc/ioc4.c +++ b/drivers/misc/ioc4.c @@ -75,7 +75,7 @@ ioc4_register_submodule(struct ioc4_submodule *is) printk(KERN_WARNING "%s: IOC4 submodule %s probe failed " "for pci_dev %s", - __FUNCTION__, module_name(is->is_owner), + __func__, module_name(is->is_owner), pci_name(idd->idd_pdev)); } } @@ -102,7 +102,7 @@ ioc4_unregister_submodule(struct ioc4_submodule *is) printk(KERN_WARNING "%s: IOC4 submodule %s remove failed " "for pci_dev %s.\n", - __FUNCTION__, module_name(is->is_owner), + __func__, module_name(is->is_owner), pci_name(idd->idd_pdev)); } } @@ -282,7 +282,7 @@ ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) if ((ret = pci_enable_device(pdev))) { printk(KERN_WARNING "%s: Failed to enable IOC4 device for pci_dev %s.\n", - __FUNCTION__, pci_name(pdev)); + __func__, pci_name(pdev)); goto out; } pci_set_master(pdev); @@ -292,7 +292,7 @@ ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) if (!idd) { printk(KERN_WARNING "%s: Failed to allocate IOC4 data for pci_dev %s.\n", - __FUNCTION__, pci_name(pdev)); + __func__, pci_name(pdev)); ret = -ENODEV; goto out_idd; } @@ -307,7 +307,7 @@ ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) printk(KERN_WARNING "%s: Unable to find IOC4 misc resource " "for pci_dev %s.\n", - __FUNCTION__, pci_name(idd->idd_pdev)); + __func__, pci_name(idd->idd_pdev)); ret = -ENODEV; goto out_pci; } @@ -316,7 +316,7 @@ ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) printk(KERN_WARNING "%s: Unable to request IOC4 misc region " "for pci_dev %s.\n", - __FUNCTION__, pci_name(idd->idd_pdev)); + __func__, pci_name(idd->idd_pdev)); ret = -ENODEV; goto out_pci; } @@ -326,7 +326,7 @@ ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) printk(KERN_WARNING "%s: Unable to remap IOC4 misc region " "for pci_dev %s.\n", - __FUNCTION__, pci_name(idd->idd_pdev)); + __func__, pci_name(idd->idd_pdev)); ret = -ENODEV; goto out_misc_region; } @@ -372,7 +372,7 @@ ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) printk(KERN_WARNING "%s: IOC4 submodule 0x%s probe failed " "for pci_dev %s.\n", - __FUNCTION__, module_name(is->is_owner), + __func__, module_name(is->is_owner), pci_name(idd->idd_pdev)); } } @@ -406,7 +406,7 @@ ioc4_remove(struct pci_dev *pdev) printk(KERN_WARNING "%s: IOC4 submodule 0x%s remove failed " "for pci_dev %s.\n", - __FUNCTION__, module_name(is->is_owner), + __func__, module_name(is->is_owner), pci_name(idd->idd_pdev)); } } @@ -418,7 +418,7 @@ ioc4_remove(struct pci_dev *pdev) printk(KERN_WARNING "%s: Unable to get IOC4 misc mapping for pci_dev %s. " "Device removal may be incomplete.\n", - __FUNCTION__, pci_name(idd->idd_pdev)); + __func__, pci_name(idd->idd_pdev)); } release_mem_region(idd->idd_bar0, sizeof(struct ioc4_misc_regs)); diff --git a/drivers/misc/phantom.c b/drivers/misc/phantom.c index 7fa61e907e1..71d1c84e2fa 100644 --- a/drivers/misc/phantom.c +++ b/drivers/misc/phantom.c @@ -12,6 +12,7 @@ * or alternatively, you might use OpenHaptics provided by Sensable. */ +#include <linux/compat.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/device.h> @@ -91,11 +92,8 @@ static long phantom_ioctl(struct file *file, unsigned int cmd, unsigned long flags; unsigned int i; - if (_IOC_TYPE(cmd) != PH_IOC_MAGIC || - _IOC_NR(cmd) > PH_IOC_MAXNR) - return -ENOTTY; - switch (cmd) { + case PHN_SETREG: case PHN_SET_REG: if (copy_from_user(&r, argp, sizeof(r))) return -EFAULT; @@ -126,6 +124,7 @@ static long phantom_ioctl(struct file *file, unsigned int cmd, phantom_status(dev, dev->status & ~PHB_RUNNING); spin_unlock_irqrestore(&dev->regs_lock, flags); break; + case PHN_SETREGS: case PHN_SET_REGS: if (copy_from_user(&rs, argp, sizeof(rs))) return -EFAULT; @@ -143,6 +142,7 @@ static long phantom_ioctl(struct file *file, unsigned int cmd, } spin_unlock_irqrestore(&dev->regs_lock, flags); break; + case PHN_GETREG: case PHN_GET_REG: if (copy_from_user(&r, argp, sizeof(r))) return -EFAULT; @@ -155,6 +155,7 @@ static long phantom_ioctl(struct file *file, unsigned int cmd, if (copy_to_user(argp, &r, sizeof(r))) return -EFAULT; break; + case PHN_GETREGS: case PHN_GET_REGS: { u32 m; @@ -168,6 +169,7 @@ static long phantom_ioctl(struct file *file, unsigned int cmd, for (i = 0; i < m; i++) if (rs.mask & BIT(i)) rs.values[i] = ioread32(dev->iaddr + i); + atomic_set(&dev->counter, 0); spin_unlock_irqrestore(&dev->regs_lock, flags); if (copy_to_user(argp, &rs, sizeof(rs))) @@ -191,6 +193,20 @@ static long phantom_ioctl(struct file *file, unsigned int cmd, return 0; } +#ifdef CONFIG_COMPAT +static long phantom_compat_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + if (_IOC_NR(cmd) <= 3 && _IOC_SIZE(cmd) == sizeof(compat_uptr_t)) { + cmd &= ~(_IOC_SIZEMASK << _IOC_SIZESHIFT); + cmd |= sizeof(void *) << _IOC_SIZESHIFT; + } + return phantom_ioctl(filp, cmd, (unsigned long)compat_ptr(arg)); +} +#else +#define phantom_compat_ioctl NULL +#endif + static int phantom_open(struct inode *inode, struct file *file) { struct phantom_device *dev = container_of(inode->i_cdev, @@ -239,11 +255,12 @@ static unsigned int phantom_poll(struct file *file, poll_table *wait) pr_debug("phantom_poll: %d\n", atomic_read(&dev->counter)); poll_wait(file, &dev->wait, wait); - if (atomic_read(&dev->counter)) { + + if (!(dev->status & PHB_RUNNING)) + mask = POLLERR; + else if (atomic_read(&dev->counter)) mask = POLLIN | POLLRDNORM; - atomic_dec(&dev->counter); - } else if ((dev->status & PHB_RUNNING) == 0) - mask = POLLIN | POLLRDNORM | POLLERR; + pr_debug("phantom_poll end: %x/%d\n", mask, atomic_read(&dev->counter)); return mask; @@ -253,6 +270,7 @@ static struct file_operations phantom_file_ops = { .open = phantom_open, .release = phantom_release, .unlocked_ioctl = phantom_ioctl, + .compat_ioctl = phantom_compat_ioctl, .poll = phantom_poll, }; diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c index 02ff3d19b1c..00e48e2a9c1 100644 --- a/drivers/misc/sony-laptop.c +++ b/drivers/misc/sony-laptop.c @@ -961,7 +961,7 @@ static int sony_nc_resume(struct acpi_device *device) ret = acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset, item->value, NULL); if (ret < 0) { - printk("%s: %d\n", __FUNCTION__, ret); + printk("%s: %d\n", __func__, ret); break; } } @@ -1453,7 +1453,7 @@ static struct sonypi_eventtypes type4_events[] = { udelay(1); \ if (!n) \ dprintk("command failed at %s : %s (line %d)\n", \ - __FILE__, __FUNCTION__, __LINE__); \ + __FILE__, __func__, __LINE__); \ } static u8 sony_pic_call1(u8 dev) diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c index 365024b83d3..35508584ac2 100644 --- a/drivers/mmc/host/mmc_spi.c +++ b/drivers/mmc/host/mmc_spi.c @@ -340,7 +340,7 @@ checkstatus: /* SPI R3, R4, or R7 == R1 + 4 bytes */ case MMC_RSP_SPI_R3: - cmd->resp[1] = be32_to_cpu(get_unaligned((u32 *)cp)); + cmd->resp[1] = get_unaligned_be32(cp); break; /* SPI R1 == just one status byte */ diff --git a/drivers/mtd/maps/plat-ram.c b/drivers/mtd/maps/plat-ram.c index f0b10ca0502..3eb2643b232 100644 --- a/drivers/mtd/maps/plat-ram.c +++ b/drivers/mtd/maps/plat-ram.c @@ -209,7 +209,7 @@ static int platram_probe(struct platform_device *pdev) /* probe for the right mtd map driver * supplied by the platform_data struct */ - if (pdata->map_probes != 0) { + if (pdata->map_probes) { const char **map_probes = pdata->map_probes; for ( ; !info->mtd && *map_probes; map_probes++) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 8082c1d142d..f90a86ba7e2 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -469,7 +469,7 @@ config SNI_82596 config KORINA tristate "Korina (IDT RC32434) Ethernet support" - depends on NET_ETHERNET && MIKROTIK_RB500 + depends on NET_ETHERNET && MIKROTIK_RB532 help If you have a Mikrotik RouterBoard 500 or IDT RC32434 based system say Y. Otherwise say N. diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 6e91b4b7aab..6425603bc37 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -3282,17 +3282,14 @@ static int bond_create_proc_entry(struct bonding *bond) struct net_device *bond_dev = bond->dev; if (bond_proc_dir) { - bond->proc_entry = create_proc_entry(bond_dev->name, - S_IRUGO, - bond_proc_dir); + bond->proc_entry = proc_create_data(bond_dev->name, + S_IRUGO, bond_proc_dir, + &bond_info_fops, bond); if (bond->proc_entry == NULL) { printk(KERN_WARNING DRV_NAME ": Warning: Cannot create /proc/net/%s/%s\n", DRV_NAME, bond_dev->name); } else { - bond->proc_entry->data = bond; - bond->proc_entry->proc_fops = &bond_info_fops; - bond->proc_entry->owner = THIS_MODULE; memcpy(bond->proc_file_name, bond_dev->name, IFNAMSIZ); } } diff --git a/drivers/net/cxgb3/version.h b/drivers/net/cxgb3/version.h index 229303ff6a3..a0177fc55e2 100644 --- a/drivers/net/cxgb3/version.h +++ b/drivers/net/cxgb3/version.h @@ -38,7 +38,7 @@ #define DRV_VERSION "1.0-ko" /* Firmware version */ -#define FW_VERSION_MAJOR 5 +#define FW_VERSION_MAJOR 6 #define FW_VERSION_MINOR 0 #define FW_VERSION_MICRO 0 #endif /* __CHELSIO_VERSION_H */ diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 2d139ec7977..f3cba5e24ec 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -1802,7 +1802,7 @@ static int e100_rx_alloc_skb(struct nic *nic, struct rx *rx) * it is protected by the before last buffer's el bit being set */ if (rx->prev->skb) { struct rfd *prev_rfd = (struct rfd *)rx->prev->skb->data; - put_unaligned(cpu_to_le32(rx->dma_addr), &prev_rfd->link); + put_unaligned_le32(rx->dma_addr, &prev_rfd->link); } return 0; diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c index b53f6b6491b..e5c2380f50c 100644 --- a/drivers/net/hamachi.c +++ b/drivers/net/hamachi.c @@ -1508,7 +1508,7 @@ static int hamachi_rx(struct net_device *dev) hmp->rx_buf_sz, PCI_DMA_FROMDEVICE); buf_addr = (u8 *) hmp->rx_skbuff[entry]->data; - frame_status = le32_to_cpu(get_unaligned((__le32*)&(buf_addr[data_size - 12]))); + frame_status = get_unaligned_le32(&(buf_addr[data_size - 12])); if (hamachi_debug > 4) printk(KERN_DEBUG " hamachi_rx() status was %8.8x.\n", frame_status); diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index ce4fc2ec2fe..00527805e4f 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -1302,13 +1302,10 @@ static void ibmveth_proc_register_adapter(struct ibmveth_adapter *adapter) if (ibmveth_proc_dir) { char u_addr[10]; sprintf(u_addr, "%x", adapter->vdev->unit_address); - entry = create_proc_entry(u_addr, S_IFREG, ibmveth_proc_dir); - if (!entry) { + entry = proc_create_data(u_addr, S_IFREG, ibmveth_proc_dir, + &ibmveth_proc_fops, adapter); + if (!entry) ibmveth_error_printk("Cannot create adapter proc entry"); - } else { - entry->data = (void *) adapter; - entry->proc_fops = &ibmveth_proc_fops; - } } return; } diff --git a/drivers/net/irda/mcs7780.c b/drivers/net/irda/mcs7780.c index 93916cf33f2..ad92d3ff1c4 100644 --- a/drivers/net/irda/mcs7780.c +++ b/drivers/net/irda/mcs7780.c @@ -464,7 +464,7 @@ static void mcs_unwrap_fir(struct mcs_cb *mcs, __u8 *buf, int len) } fcs = ~(crc32_le(~0, buf, new_len)); - if(fcs != le32_to_cpu(get_unaligned((__le32 *)(buf+new_len)))) { + if(fcs != get_unaligned_le32(buf + new_len)) { IRDA_ERROR("crc error calc 0x%x len %d\n", fcs, new_len); mcs->stats.rx_errors++; mcs->stats.rx_crc_errors++; diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c index e59c485bc49..05196378274 100644 --- a/drivers/net/irda/stir4200.c +++ b/drivers/net/irda/stir4200.c @@ -329,7 +329,7 @@ static void fir_eof(struct stir_cb *stir) } fcs = ~(crc32_le(~0, rx_buff->data, len)); - if (fcs != le32_to_cpu(get_unaligned((__le32 *)(rx_buff->data+len)))) { + if (fcs != get_unaligned_le32(rx_buff->data + len)) { pr_debug("crc error calc 0x%x len %d\n", fcs, len); stir->stats.rx_errors++; stir->stats.rx_crc_errors++; diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c index acd082a96a4..d15e00b8591 100644 --- a/drivers/net/irda/vlsi_ir.c +++ b/drivers/net/irda/vlsi_ir.c @@ -1674,13 +1674,12 @@ vlsi_irda_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (vlsi_proc_root != NULL) { struct proc_dir_entry *ent; - ent = create_proc_entry(ndev->name, S_IFREG|S_IRUGO, vlsi_proc_root); + ent = proc_create_data(ndev->name, S_IFREG|S_IRUGO, + vlsi_proc_root, VLSI_PROC_FOPS, ndev); if (!ent) { IRDA_WARNING("%s: failed to create proc entry\n", __FUNCTION__); } else { - ent->data = ndev; - ent->proc_fops = VLSI_PROC_FOPS; ent->size = 0; } idev->proc_entry = ent; diff --git a/drivers/net/mlx4/cq.c b/drivers/net/mlx4/cq.c index 6fda0af9d0a..95e87a2f889 100644 --- a/drivers/net/mlx4/cq.c +++ b/drivers/net/mlx4/cq.c @@ -188,7 +188,8 @@ int mlx4_cq_resize(struct mlx4_dev *dev, struct mlx4_cq *cq, EXPORT_SYMBOL_GPL(mlx4_cq_resize); int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, struct mlx4_mtt *mtt, - struct mlx4_uar *uar, u64 db_rec, struct mlx4_cq *cq) + struct mlx4_uar *uar, u64 db_rec, struct mlx4_cq *cq, + int collapsed) { struct mlx4_priv *priv = mlx4_priv(dev); struct mlx4_cq_table *cq_table = &priv->cq_table; @@ -224,6 +225,7 @@ int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, struct mlx4_mtt *mtt, cq_context = mailbox->buf; memset(cq_context, 0, sizeof *cq_context); + cq_context->flags = cpu_to_be32(!!collapsed << 18); cq_context->logsize_usrpage = cpu_to_be32((ilog2(nent) << 24) | uar->index); cq_context->comp_eqn = priv->eq_table.eq[MLX4_EQ_COMP].eqn; cq_context->log_page_size = mtt->page_shift - MLX4_ICM_PAGE_SHIFT; diff --git a/drivers/net/mlx4/mr.c b/drivers/net/mlx4/mr.c index 79b317b88c8..cb46446b269 100644 --- a/drivers/net/mlx4/mr.c +++ b/drivers/net/mlx4/mr.c @@ -607,15 +607,9 @@ EXPORT_SYMBOL_GPL(mlx4_fmr_enable); void mlx4_fmr_unmap(struct mlx4_dev *dev, struct mlx4_fmr *fmr, u32 *lkey, u32 *rkey) { - u32 key; - if (!fmr->maps) return; - key = key_to_hw_index(fmr->mr.key); - key &= dev->caps.num_mpts - 1; - *lkey = *rkey = fmr->mr.key = hw_index_to_key(key); - fmr->maps = 0; *(u8 *) fmr->mpt = MLX4_MPT_STATUS_SW; diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index cead81e80f0..ef63c8d2bd7 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -2437,7 +2437,7 @@ static int myri10ge_sw_tso(struct sk_buff *skb, struct net_device *dev) int status; segs = skb_gso_segment(skb, dev->features & ~NETIF_F_TSO6); - if (unlikely(IS_ERR(segs))) + if (IS_ERR(segs)) goto drop; while (segs) { diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c index 4fad4ddb350..58a26a47af2 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c @@ -1052,11 +1052,9 @@ static int __init pppoe_proc_init(void) { struct proc_dir_entry *p; - p = create_proc_entry("pppoe", S_IRUGO, init_net.proc_net); + p = proc_net_fops_create(&init_net, "pppoe", S_IRUGO, &pppoe_seq_fops); if (!p) return -ENOMEM; - - p->proc_fops = &pppoe_seq_fops; return 0; } #else /* CONFIG_PROC_FS */ diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c index 3d10ca050b7..244d7830c92 100644 --- a/drivers/net/pppol2tp.c +++ b/drivers/net/pppol2tp.c @@ -2469,12 +2469,12 @@ static int __init pppol2tp_init(void) goto out_unregister_pppol2tp_proto; #ifdef CONFIG_PROC_FS - pppol2tp_proc = create_proc_entry("pppol2tp", 0, init_net.proc_net); + pppol2tp_proc = proc_net_fops_create(&init_net, "pppol2tp", 0, + &pppol2tp_proc_fops); if (!pppol2tp_proc) { err = -ENOMEM; goto out_unregister_pppox_proto; } - pppol2tp_proc->proc_fops = &pppol2tp_proc_fops; #endif /* CONFIG_PROC_FS */ printk(KERN_INFO "PPPoL2TP kernel driver, %s\n", PPPOL2TP_DRV_VERSION); diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c index e7fd08adbba..2b8fd68bc51 100644 --- a/drivers/net/rionet.c +++ b/drivers/net/rionet.c @@ -77,7 +77,7 @@ static int rionet_capable = 1; * could be made into a hash table to save memory depending * on system trade-offs. */ -static struct rio_dev *rionet_active[RIO_MAX_ROUTE_ENTRIES]; +static struct rio_dev **rionet_active; #define is_rionet_capable(pef, src_ops, dst_ops) \ ((pef & RIO_PEF_INB_MBOX) && \ @@ -195,7 +195,8 @@ static int rionet_start_xmit(struct sk_buff *skb, struct net_device *ndev) } if (eth->h_dest[0] & 0x01) { - for (i = 0; i < RIO_MAX_ROUTE_ENTRIES; i++) + for (i = 0; i < RIO_MAX_ROUTE_ENTRIES(rnet->mport->sys_size); + i++) if (rionet_active[i]) rionet_queue_tx_msg(skb, ndev, rionet_active[i]); @@ -385,6 +386,8 @@ static void rionet_remove(struct rio_dev *rdev) struct net_device *ndev = NULL; struct rionet_peer *peer, *tmp; + free_pages((unsigned long)rionet_active, rdev->net->hport->sys_size ? + __ilog2(sizeof(void *)) + 4 : 0); unregister_netdev(ndev); kfree(ndev); @@ -443,6 +446,15 @@ static int rionet_setup_netdev(struct rio_mport *mport) goto out; } + rionet_active = (struct rio_dev **)__get_free_pages(GFP_KERNEL, + mport->sys_size ? __ilog2(sizeof(void *)) + 4 : 0); + if (!rionet_active) { + rc = -ENOMEM; + goto out; + } + memset((void *)rionet_active, 0, sizeof(void *) * + RIO_MAX_ROUTE_ENTRIES(mport->sys_size)); + /* Set up private area */ rnet = (struct rionet_private *)ndev->priv; rnet->mport = mport; diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c index e83b166aa6b..432e837a176 100644 --- a/drivers/net/tehuti.c +++ b/drivers/net/tehuti.c @@ -649,7 +649,7 @@ static int bdx_ioctl_priv(struct net_device *ndev, struct ifreq *ifr, int cmd) DBG("%d 0x%x 0x%x\n", data[0], data[1], data[2]); } - if (!capable(CAP_NET_ADMIN)) + if (!capable(CAP_SYS_RAWIO)) return -EPERM; switch (data[0]) { diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index e3f74c9f78b..b66c75e3b8a 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -4361,7 +4361,7 @@ static int tg3_tso_bug(struct tg3 *tp, struct sk_buff *skb) } segs = skb_gso_segment(skb, tp->dev->features & ~NETIF_F_TSO); - if (unlikely(IS_ERR(segs))) + if (IS_ERR(segs)) goto tg3_tso_bug_end; do { diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c index 6c6fc325c8f..bc30c6e8fea 100644 --- a/drivers/net/tulip/de4x5.c +++ b/drivers/net/tulip/de4x5.c @@ -482,7 +482,6 @@ static char version[] __devinitdata = "de4x5.c:V0.546 2001/02/22 davies@maniac.ultranet.com\n"; #define c_char const char -#define TWIDDLE(a) (u_short)le16_to_cpu(get_unaligned((__le16 *)(a))) /* ** MII Information @@ -4405,7 +4404,7 @@ srom_infoleaf_info(struct net_device *dev) } } - lp->infoleaf_offset = TWIDDLE(p+1); + lp->infoleaf_offset = get_unaligned_le16(p + 1); return 0; } @@ -4476,7 +4475,7 @@ srom_exec(struct net_device *dev, u_char *p) while (count--) { gep_wr(((lp->chipset==DC21140) && (lp->ibn!=5) ? - *p++ : TWIDDLE(w++)), dev); + *p++ : get_unaligned_le16(w++)), dev); mdelay(2); /* 2ms per action */ } @@ -4711,10 +4710,10 @@ type1_infoblock(struct net_device *dev, u_char count, u_char *p) lp->active = *p++; lp->phy[lp->active].gep = (*p ? p : NULL); p += (*p + 1); lp->phy[lp->active].rst = (*p ? p : NULL); p += (*p + 1); - lp->phy[lp->active].mc = TWIDDLE(p); p += 2; - lp->phy[lp->active].ana = TWIDDLE(p); p += 2; - lp->phy[lp->active].fdx = TWIDDLE(p); p += 2; - lp->phy[lp->active].ttm = TWIDDLE(p); + lp->phy[lp->active].mc = get_unaligned_le16(p); p += 2; + lp->phy[lp->active].ana = get_unaligned_le16(p); p += 2; + lp->phy[lp->active].fdx = get_unaligned_le16(p); p += 2; + lp->phy[lp->active].ttm = get_unaligned_le16(p); return 0; } else if ((lp->media == INIT) && (lp->timeout < 0)) { lp->ibn = 1; @@ -4751,16 +4750,16 @@ type2_infoblock(struct net_device *dev, u_char count, u_char *p) lp->infoblock_media = (*p) & MEDIA_CODE; if ((*p++) & EXT_FIELD) { - lp->cache.csr13 = TWIDDLE(p); p += 2; - lp->cache.csr14 = TWIDDLE(p); p += 2; - lp->cache.csr15 = TWIDDLE(p); p += 2; + lp->cache.csr13 = get_unaligned_le16(p); p += 2; + lp->cache.csr14 = get_unaligned_le16(p); p += 2; + lp->cache.csr15 = get_unaligned_le16(p); p += 2; } else { lp->cache.csr13 = CSR13; lp->cache.csr14 = CSR14; lp->cache.csr15 = CSR15; } - lp->cache.gepc = ((s32)(TWIDDLE(p)) << 16); p += 2; - lp->cache.gep = ((s32)(TWIDDLE(p)) << 16); + lp->cache.gepc = ((s32)(get_unaligned_le16(p)) << 16); p += 2; + lp->cache.gep = ((s32)(get_unaligned_le16(p)) << 16); lp->infoblock_csr6 = OMR_SIA; lp->useMII = false; @@ -4792,10 +4791,10 @@ type3_infoblock(struct net_device *dev, u_char count, u_char *p) if (MOTO_SROM_BUG) lp->active = 0; lp->phy[lp->active].gep = (*p ? p : NULL); p += (2 * (*p) + 1); lp->phy[lp->active].rst = (*p ? p : NULL); p += (2 * (*p) + 1); - lp->phy[lp->active].mc = TWIDDLE(p); p += 2; - lp->phy[lp->active].ana = TWIDDLE(p); p += 2; - lp->phy[lp->active].fdx = TWIDDLE(p); p += 2; - lp->phy[lp->active].ttm = TWIDDLE(p); p += 2; + lp->phy[lp->active].mc = get_unaligned_le16(p); p += 2; + lp->phy[lp->active].ana = get_unaligned_le16(p); p += 2; + lp->phy[lp->active].fdx = get_unaligned_le16(p); p += 2; + lp->phy[lp->active].ttm = get_unaligned_le16(p); p += 2; lp->phy[lp->active].mci = *p; return 0; } else if ((lp->media == INIT) && (lp->timeout < 0)) { @@ -4835,8 +4834,8 @@ type4_infoblock(struct net_device *dev, u_char count, u_char *p) lp->cache.csr13 = CSR13; /* Hard coded defaults */ lp->cache.csr14 = CSR14; lp->cache.csr15 = CSR15; - lp->cache.gepc = ((s32)(TWIDDLE(p)) << 16); p += 2; - lp->cache.gep = ((s32)(TWIDDLE(p)) << 16); p += 2; + lp->cache.gepc = ((s32)(get_unaligned_le16(p)) << 16); p += 2; + lp->cache.gep = ((s32)(get_unaligned_le16(p)) << 16); p += 2; csr6 = *p++; flags = *p++; diff --git a/drivers/net/tulip/de4x5.h b/drivers/net/tulip/de4x5.h index 9fb8d7f0799..f5f33b3eb06 100644 --- a/drivers/net/tulip/de4x5.h +++ b/drivers/net/tulip/de4x5.h @@ -1017,4 +1017,4 @@ struct de4x5_ioctl { #define DE4X5_SET_OMR 0x0d /* Set the OMR Register contents */ #define DE4X5_GET_REG 0x0e /* Get the DE4X5 Registers */ -#define MOTO_SROM_BUG ((lp->active == 8) && (((le32_to_cpu(get_unaligned(((__le32 *)dev->dev_addr))))&0x00ffffff)==0x3e0008)) +#define MOTO_SROM_BUG (lp->active == 8 && (get_unaligned_le32(dev->dev_addr) & 0x00ffffff) == 0x3e0008) diff --git a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h index 908422f2f32..92c68a22f16 100644 --- a/drivers/net/tulip/tulip.h +++ b/drivers/net/tulip/tulip.h @@ -25,6 +25,7 @@ #include <linux/pci.h> #include <asm/io.h> #include <asm/irq.h> +#include <asm/unaligned.h> @@ -304,11 +305,7 @@ enum t21143_csr6_bits { #define RUN_AT(x) (jiffies + (x)) -#if defined(__i386__) /* AKA get_unaligned() */ -#define get_u16(ptr) (*(u16 *)(ptr)) -#else -#define get_u16(ptr) (((u8*)(ptr))[0] + (((u8*)(ptr))[1]<<8)) -#endif +#define get_u16(ptr) get_unaligned_le16((ptr)) struct medialeaf { u8 type; diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index fa1c1c329a2..f9d13fa05d6 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -327,8 +327,8 @@ static void tulip_up(struct net_device *dev) tp->dirty_rx = tp->dirty_tx = 0; if (tp->flags & MC_HASH_ONLY) { - u32 addr_low = le32_to_cpu(get_unaligned((__le32 *)dev->dev_addr)); - u32 addr_high = le16_to_cpu(get_unaligned((__le16 *)(dev->dev_addr+4))); + u32 addr_low = get_unaligned_le32(dev->dev_addr); + u32 addr_high = get_unaligned_le16(dev->dev_addr + 4); if (tp->chip_id == AX88140) { iowrite32(0, ioaddr + CSR13); iowrite32(addr_low, ioaddr + CSR14); @@ -1437,13 +1437,13 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, do value = ioread32(ioaddr + CSR9); while (value < 0 && --boguscnt > 0); - put_unaligned(cpu_to_le16(value), ((__le16*)dev->dev_addr) + i); + put_unaligned_le16(value, ((__le16 *)dev->dev_addr) + i); sum += value & 0xffff; } } else if (chip_idx == COMET) { /* No need to read the EEPROM. */ - put_unaligned(cpu_to_le32(ioread32(ioaddr + 0xA4)), (__le32 *)dev->dev_addr); - put_unaligned(cpu_to_le16(ioread32(ioaddr + 0xA8)), (__le16 *)(dev->dev_addr + 4)); + put_unaligned_le32(ioread32(ioaddr + 0xA4), dev->dev_addr); + put_unaligned_le16(ioread32(ioaddr + 0xA8), dev->dev_addr + 4); for (i = 0; i < 6; i ++) sum += dev->dev_addr[i]; } else { diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index c2642bc1d49..2c343aae38d 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -56,7 +56,7 @@ obj-$(CONFIG_RTL8187) += rtl8187.o obj-$(CONFIG_ADM8211) += adm8211.o -obj-$(CONFIG_IWLCORE) += iwlwifi/ +obj-$(CONFIG_IWLWIFI) += iwlwifi/ obj-$(CONFIG_RT2X00) += rt2x00/ obj-$(CONFIG_P54_COMMON) += p54/ diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 932d6b1c9d0..45f47c1c0a3 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -3657,7 +3657,7 @@ void mpi_receive_802_11 (struct airo_info *ai) ptr += hdrlen; if (hdrlen == 24) ptr += 6; - gap = le16_to_cpu(get_unaligned((__le16 *)ptr)); + gap = get_unaligned_le16(ptr); ptr += sizeof(__le16); if (gap) { if (gap <= 8) @@ -4347,24 +4347,28 @@ static int proc_config_open( struct inode *inode, struct file *file ); static int proc_wepkey_open( struct inode *inode, struct file *file ); static const struct file_operations proc_statsdelta_ops = { + .owner = THIS_MODULE, .read = proc_read, .open = proc_statsdelta_open, .release = proc_close }; static const struct file_operations proc_stats_ops = { + .owner = THIS_MODULE, .read = proc_read, .open = proc_stats_open, .release = proc_close }; static const struct file_operations proc_status_ops = { + .owner = THIS_MODULE, .read = proc_read, .open = proc_status_open, .release = proc_close }; static const struct file_operations proc_SSID_ops = { + .owner = THIS_MODULE, .read = proc_read, .write = proc_write, .open = proc_SSID_open, @@ -4372,6 +4376,7 @@ static const struct file_operations proc_SSID_ops = { }; static const struct file_operations proc_BSSList_ops = { + .owner = THIS_MODULE, .read = proc_read, .write = proc_write, .open = proc_BSSList_open, @@ -4379,6 +4384,7 @@ static const struct file_operations proc_BSSList_ops = { }; static const struct file_operations proc_APList_ops = { + .owner = THIS_MODULE, .read = proc_read, .write = proc_write, .open = proc_APList_open, @@ -4386,6 +4392,7 @@ static const struct file_operations proc_APList_ops = { }; static const struct file_operations proc_config_ops = { + .owner = THIS_MODULE, .read = proc_read, .write = proc_write, .open = proc_config_open, @@ -4393,6 +4400,7 @@ static const struct file_operations proc_config_ops = { }; static const struct file_operations proc_wepkey_ops = { + .owner = THIS_MODULE, .read = proc_read, .write = proc_write, .open = proc_wepkey_open, @@ -4411,10 +4419,6 @@ struct proc_data { void (*on_close) (struct inode *, struct file *); }; -#ifndef SETPROC_OPS -#define SETPROC_OPS(entry, ops) (entry)->proc_fops = &(ops) -#endif - static int setup_proc_entry( struct net_device *dev, struct airo_info *apriv ) { struct proc_dir_entry *entry; @@ -4430,100 +4434,76 @@ static int setup_proc_entry( struct net_device *dev, apriv->proc_entry->owner = THIS_MODULE; /* Setup the StatsDelta */ - entry = create_proc_entry("StatsDelta", - S_IFREG | (S_IRUGO&proc_perm), - apriv->proc_entry); + entry = proc_create_data("StatsDelta", + S_IFREG | (S_IRUGO&proc_perm), + apriv->proc_entry, &proc_statsdelta_ops, dev); if (!entry) goto fail_stats_delta; entry->uid = proc_uid; entry->gid = proc_gid; - entry->data = dev; - entry->owner = THIS_MODULE; - SETPROC_OPS(entry, proc_statsdelta_ops); /* Setup the Stats */ - entry = create_proc_entry("Stats", - S_IFREG | (S_IRUGO&proc_perm), - apriv->proc_entry); + entry = proc_create_data("Stats", + S_IFREG | (S_IRUGO&proc_perm), + apriv->proc_entry, &proc_stats_ops, dev); if (!entry) goto fail_stats; entry->uid = proc_uid; entry->gid = proc_gid; - entry->data = dev; - entry->owner = THIS_MODULE; - SETPROC_OPS(entry, proc_stats_ops); /* Setup the Status */ - entry = create_proc_entry("Status", - S_IFREG | (S_IRUGO&proc_perm), - apriv->proc_entry); + entry = proc_create_data("Status", + S_IFREG | (S_IRUGO&proc_perm), + apriv->proc_entry, &proc_status_ops, dev); if (!entry) goto fail_status; entry->uid = proc_uid; entry->gid = proc_gid; - entry->data = dev; - entry->owner = THIS_MODULE; - SETPROC_OPS(entry, proc_status_ops); /* Setup the Config */ - entry = create_proc_entry("Config", - S_IFREG | proc_perm, - apriv->proc_entry); + entry = proc_create_data("Config", + S_IFREG | proc_perm, + apriv->proc_entry, &proc_config_ops, dev); if (!entry) goto fail_config; entry->uid = proc_uid; entry->gid = proc_gid; - entry->data = dev; - entry->owner = THIS_MODULE; - SETPROC_OPS(entry, proc_config_ops); /* Setup the SSID */ - entry = create_proc_entry("SSID", - S_IFREG | proc_perm, - apriv->proc_entry); + entry = proc_create_data("SSID", + S_IFREG | proc_perm, + apriv->proc_entry, &proc_SSID_ops, dev); if (!entry) goto fail_ssid; entry->uid = proc_uid; entry->gid = proc_gid; - entry->data = dev; - entry->owner = THIS_MODULE; - SETPROC_OPS(entry, proc_SSID_ops); /* Setup the APList */ - entry = create_proc_entry("APList", - S_IFREG | proc_perm, - apriv->proc_entry); + entry = proc_create_data("APList", + S_IFREG | proc_perm, + apriv->proc_entry, &proc_APList_ops, dev); if (!entry) goto fail_aplist; entry->uid = proc_uid; entry->gid = proc_gid; - entry->data = dev; - entry->owner = THIS_MODULE; - SETPROC_OPS(entry, proc_APList_ops); /* Setup the BSSList */ - entry = create_proc_entry("BSSList", - S_IFREG | proc_perm, - apriv->proc_entry); + entry = proc_create_data("BSSList", + S_IFREG | proc_perm, + apriv->proc_entry, &proc_BSSList_ops, dev); if (!entry) goto fail_bsslist; entry->uid = proc_uid; entry->gid = proc_gid; - entry->data = dev; - entry->owner = THIS_MODULE; - SETPROC_OPS(entry, proc_BSSList_ops); /* Setup the WepKey */ - entry = create_proc_entry("WepKey", - S_IFREG | proc_perm, - apriv->proc_entry); + entry = proc_create_data("WepKey", + S_IFREG | proc_perm, + apriv->proc_entry, &proc_wepkey_ops, dev); if (!entry) goto fail_wepkey; entry->uid = proc_uid; entry->gid = proc_gid; - entry->data = dev; - entry->owner = THIS_MODULE; - SETPROC_OPS(entry, proc_wepkey_ops); return 0; @@ -5625,9 +5605,9 @@ static int __init airo_init_module( void ) int have_isa_dev = 0; #endif - airo_entry = create_proc_entry("aironet", + airo_entry = create_proc_entry("driver/aironet", S_IFDIR | airo_perm, - proc_root_driver); + NULL); if (airo_entry) { airo_entry->uid = proc_uid; @@ -5651,7 +5631,7 @@ static int __init airo_init_module( void ) airo_print_info("", "Finished probing for PCI adapters"); if (i) { - remove_proc_entry("aironet", proc_root_driver); + remove_proc_entry("driver/aironet", NULL); return i; } #endif @@ -5673,7 +5653,7 @@ static void __exit airo_cleanup_module( void ) #ifdef CONFIG_PCI pci_unregister_driver(&airo_driver); #endif - remove_proc_entry("aironet", proc_root_driver); + remove_proc_entry("driver/aironet", NULL); } /* diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index e18305b781c..4e5c8fc3520 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -58,10 +58,6 @@ #include "reg.h" #include "debug.h" -/* unaligned little endian access */ -#define LE_READ_2(_p) (le16_to_cpu(get_unaligned((__le16 *)(_p)))) -#define LE_READ_4(_p) (le32_to_cpu(get_unaligned((__le32 *)(_p)))) - enum { ATH_LED_TX, ATH_LED_RX, @@ -2909,9 +2905,9 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw, if (!mclist) break; /* calculate XOR of eight 6-bit values */ - val = LE_READ_4(mclist->dmi_addr + 0); + val = get_unaligned_le32(mclist->dmi_addr + 0); pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; - val = LE_READ_4(mclist->dmi_addr + 3); + val = get_unaligned_le32(mclist->dmi_addr + 3); pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; pos &= 0x3f; mfilt[pos / 32] |= (1 << (pos % 32)); diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 4bf8a99099f..8c24cd72aac 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -2171,7 +2171,7 @@ static int b43_write_initvals(struct b43_wldev *dev, goto err_format; array_size -= sizeof(iv->data.d32); - value = be32_to_cpu(get_unaligned(&iv->data.d32)); + value = get_unaligned_be32(&iv->data.d32); b43_write32(dev, offset, value); iv = (const struct b43_iv *)((const uint8_t *)iv + diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index ef829ee8ffd..14a5eea2573 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -1720,7 +1720,7 @@ static int b43legacy_write_initvals(struct b43legacy_wldev *dev, goto err_format; array_size -= sizeof(iv->data.d32); - value = be32_to_cpu(get_unaligned(&iv->data.d32)); + value = get_unaligned_be32(&iv->data.d32); b43legacy_write32(dev, offset, value); iv = (const struct b43legacy_iv *)((const uint8_t *)iv + diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index c4e631d14bf..9a25f550fd1 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -1,6 +1,11 @@ +config IWLWIFI + bool + default n + config IWLCORE tristate "Intel Wireless Wifi Core" depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL + select IWLWIFI config IWLWIFI_LEDS bool @@ -106,6 +111,7 @@ config IWL3945 tristate "Intel PRO/Wireless 3945ABG/BG Network Connection" depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL select FW_LOADER + select IWLWIFI ---help--- Select to build the driver supporting the: diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 598e4eef4f4..d3406830c8e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -554,40 +554,36 @@ static void iwl3945_add_radiotap(struct iwl3945_priv *priv, iwl3945_rt->rt_hdr.it_pad = 0; /* total header + data */ - put_unaligned(cpu_to_le16(sizeof(*iwl3945_rt)), - &iwl3945_rt->rt_hdr.it_len); + put_unaligned_le16(sizeof(*iwl3945_rt), &iwl3945_rt->rt_hdr.it_len); /* Indicate all the fields we add to the radiotap header */ - put_unaligned(cpu_to_le32((1 << IEEE80211_RADIOTAP_TSFT) | - (1 << IEEE80211_RADIOTAP_FLAGS) | - (1 << IEEE80211_RADIOTAP_RATE) | - (1 << IEEE80211_RADIOTAP_CHANNEL) | - (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | - (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) | - (1 << IEEE80211_RADIOTAP_ANTENNA)), - &iwl3945_rt->rt_hdr.it_present); + put_unaligned_le32((1 << IEEE80211_RADIOTAP_TSFT) | + (1 << IEEE80211_RADIOTAP_FLAGS) | + (1 << IEEE80211_RADIOTAP_RATE) | + (1 << IEEE80211_RADIOTAP_CHANNEL) | + (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | + (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) | + (1 << IEEE80211_RADIOTAP_ANTENNA), + &iwl3945_rt->rt_hdr.it_present); /* Zero the flags, we'll add to them as we go */ iwl3945_rt->rt_flags = 0; - put_unaligned(cpu_to_le64(tsf), &iwl3945_rt->rt_tsf); + put_unaligned_le64(tsf, &iwl3945_rt->rt_tsf); iwl3945_rt->rt_dbmsignal = signal; iwl3945_rt->rt_dbmnoise = noise; /* Convert the channel frequency and set the flags */ - put_unaligned(cpu_to_le16(stats->freq), &iwl3945_rt->rt_channelMHz); + put_unaligned_le16(stats->freq, &iwl3945_rt->rt_channelMHz); if (!(phy_flags_hw & RX_RES_PHY_FLAGS_BAND_24_MSK)) - put_unaligned(cpu_to_le16(IEEE80211_CHAN_OFDM | - IEEE80211_CHAN_5GHZ), + put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ, &iwl3945_rt->rt_chbitmask); else if (phy_flags_hw & RX_RES_PHY_FLAGS_MOD_CCK_MSK) - put_unaligned(cpu_to_le16(IEEE80211_CHAN_CCK | - IEEE80211_CHAN_2GHZ), + put_unaligned_le16(IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ, &iwl3945_rt->rt_chbitmask); else /* 802.11g */ - put_unaligned(cpu_to_le16(IEEE80211_CHAN_OFDM | - IEEE80211_CHAN_2GHZ), + put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ, &iwl3945_rt->rt_chbitmask); if (rate == -1) diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index e72c97a0d6c..1a409fcc80d 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -522,7 +522,7 @@ static int lbs_process_bss(struct bss_descriptor *bss, if (*bytesleft >= sizeof(beaconsize)) { /* Extract & convert beacon size from the command buffer */ - beaconsize = le16_to_cpu(get_unaligned((__le16 *)*pbeaconinfo)); + beaconsize = get_unaligned_le16(*pbeaconinfo); *bytesleft -= sizeof(beaconsize); *pbeaconinfo += sizeof(beaconsize); } diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index e34675c2f8f..5316074f39f 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -545,11 +545,11 @@ static void handle_rx_packet(struct zd_usb *usb, const u8 *buffer, * be padded. Unaligned access might also happen if the length_info * structure is not present. */ - if (get_unaligned(&length_info->tag) == cpu_to_le16(RX_LENGTH_INFO_TAG)) + if (get_unaligned_le16(&length_info->tag) == RX_LENGTH_INFO_TAG) { unsigned int l, k, n; for (i = 0, l = 0;; i++) { - k = le16_to_cpu(get_unaligned(&length_info->length[i])); + k = get_unaligned_le16(&length_info->length[i]); if (k == 0) return; n = l+k; diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c index 24640726f8b..57e1f495b9f 100644 --- a/drivers/net/yellowfin.c +++ b/drivers/net/yellowfin.c @@ -1062,7 +1062,7 @@ static int yellowfin_rx(struct net_device *dev) buf_addr = rx_skb->data; data_size = (le32_to_cpu(desc->dbdma_cmd) - le32_to_cpu(desc->result_status)) & 0xffff; - frame_status = le16_to_cpu(get_unaligned((__le16*)&(buf_addr[data_size - 2]))); + frame_status = get_unaligned_le16(&(buf_addr[data_size - 2])); if (yellowfin_debug > 4) printk(KERN_DEBUG " yellowfin_rx() status was %4.4x.\n", frame_status); diff --git a/drivers/nubus/proc.c b/drivers/nubus/proc.c index e07492be1f4..208dd12825b 100644 --- a/drivers/nubus/proc.c +++ b/drivers/nubus/proc.c @@ -21,6 +21,7 @@ #include <linux/kernel.h> #include <linux/nubus.h> #include <linux/proc_fs.h> +#include <linux/seq_file.h> #include <linux/init.h> #include <linux/module.h> @@ -28,38 +29,36 @@ #include <asm/byteorder.h> static int -get_nubus_dev_info(char *buf, char **start, off_t pos, int count) +nubus_devices_proc_show(struct seq_file *m, void *v) { struct nubus_dev *dev = nubus_devices; - off_t at = 0; - int len, cnt; - cnt = 0; - while (dev && count > cnt) { - len = sprintf(buf, "%x\t%04x %04x %04x %04x", + while (dev) { + seq_printf(m, "%x\t%04x %04x %04x %04x", dev->board->slot, dev->category, dev->type, dev->dr_sw, dev->dr_hw); - len += sprintf(buf+len, - "\t%08lx", - dev->board->slot_addr); - buf[len++] = '\n'; - at += len; - if (at >= pos) { - if (!*start) { - *start = buf + (pos - (at - len)); - cnt = at - pos; - } else - cnt += len; - buf += len; - } + seq_printf(m, "\t%08lx\n", dev->board->slot_addr); dev = dev->next; } - return (count > cnt) ? cnt : count; + return 0; +} + +static int nubus_devices_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, nubus_devices_proc_show, NULL); } +static const struct file_operations nubus_devices_proc_fops = { + .owner = THIS_MODULE, + .open = nubus_devices_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + static struct proc_dir_entry *proc_bus_nubus_dir; static void nubus_proc_subdir(struct nubus_dev* dev, @@ -171,8 +170,7 @@ void __init nubus_proc_init(void) { if (!MACH_IS_MAC) return; - proc_bus_nubus_dir = proc_mkdir("nubus", proc_bus); - create_proc_info_entry("devices", 0, proc_bus_nubus_dir, - get_nubus_dev_info); + proc_bus_nubus_dir = proc_mkdir("bus/nubus", NULL); + proc_create("devices", 0, proc_bus_nubus_dir, &nubus_devices_proc_fops); proc_bus_nubus_add_devices(); } diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index b07ba2a1411..9304c455507 100644 --- a/drivers/oprofile/buffer_sync.c +++ b/drivers/oprofile/buffer_sync.c @@ -491,7 +491,7 @@ typedef enum { */ void sync_buffer(int cpu) { - struct oprofile_cpu_buffer * cpu_buf = &cpu_buffer[cpu]; + struct oprofile_cpu_buffer *cpu_buf = &per_cpu(cpu_buffer, cpu); struct mm_struct *mm = NULL; struct task_struct * new; unsigned long cookie = 0; diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index c93d3d2640a..efcbf4b4579 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c @@ -27,7 +27,7 @@ #include "buffer_sync.h" #include "oprof.h" -struct oprofile_cpu_buffer cpu_buffer[NR_CPUS] __cacheline_aligned; +DEFINE_PER_CPU_SHARED_ALIGNED(struct oprofile_cpu_buffer, cpu_buffer); static void wq_sync_buffer(struct work_struct *work); @@ -39,7 +39,7 @@ void free_cpu_buffers(void) int i; for_each_online_cpu(i) - vfree(cpu_buffer[i].buffer); + vfree(per_cpu(cpu_buffer, i).buffer); } int alloc_cpu_buffers(void) @@ -49,7 +49,7 @@ int alloc_cpu_buffers(void) unsigned long buffer_size = fs_cpu_buffer_size; for_each_online_cpu(i) { - struct oprofile_cpu_buffer * b = &cpu_buffer[i]; + struct oprofile_cpu_buffer *b = &per_cpu(cpu_buffer, i); b->buffer = vmalloc_node(sizeof(struct op_sample) * buffer_size, cpu_to_node(i)); @@ -83,7 +83,7 @@ void start_cpu_work(void) work_enabled = 1; for_each_online_cpu(i) { - struct oprofile_cpu_buffer * b = &cpu_buffer[i]; + struct oprofile_cpu_buffer *b = &per_cpu(cpu_buffer, i); /* * Spread the work by 1 jiffy per cpu so they dont all @@ -100,7 +100,7 @@ void end_cpu_work(void) work_enabled = 0; for_each_online_cpu(i) { - struct oprofile_cpu_buffer * b = &cpu_buffer[i]; + struct oprofile_cpu_buffer *b = &per_cpu(cpu_buffer, i); cancel_delayed_work(&b->work); } @@ -227,7 +227,7 @@ static void oprofile_end_trace(struct oprofile_cpu_buffer * cpu_buf) void oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs, unsigned long event, int is_kernel) { - struct oprofile_cpu_buffer * cpu_buf = &cpu_buffer[smp_processor_id()]; + struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer); if (!backtrace_depth) { log_sample(cpu_buf, pc, is_kernel, event); @@ -254,13 +254,13 @@ void oprofile_add_sample(struct pt_regs * const regs, unsigned long event) void oprofile_add_pc(unsigned long pc, int is_kernel, unsigned long event) { - struct oprofile_cpu_buffer * cpu_buf = &cpu_buffer[smp_processor_id()]; + struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer); log_sample(cpu_buf, pc, is_kernel, event); } void oprofile_add_trace(unsigned long pc) { - struct oprofile_cpu_buffer * cpu_buf = &cpu_buffer[smp_processor_id()]; + struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer); if (!cpu_buf->tracing) return; diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h index c66c025abe7..13588174311 100644 --- a/drivers/oprofile/cpu_buffer.h +++ b/drivers/oprofile/cpu_buffer.h @@ -14,6 +14,7 @@ #include <linux/spinlock.h> #include <linux/workqueue.h> #include <linux/cache.h> +#include <linux/sched.h> struct task_struct; @@ -47,7 +48,7 @@ struct oprofile_cpu_buffer { struct delayed_work work; } ____cacheline_aligned; -extern struct oprofile_cpu_buffer cpu_buffer[]; +DECLARE_PER_CPU(struct oprofile_cpu_buffer, cpu_buffer); void cpu_buffer_reset(struct oprofile_cpu_buffer * cpu_buf); diff --git a/drivers/oprofile/oprofile_stats.c b/drivers/oprofile/oprofile_stats.c index d1f6d776e9e..f99b28e7b79 100644 --- a/drivers/oprofile/oprofile_stats.c +++ b/drivers/oprofile/oprofile_stats.c @@ -23,7 +23,7 @@ void oprofile_reset_stats(void) int i; for_each_possible_cpu(i) { - cpu_buf = &cpu_buffer[i]; + cpu_buf = &per_cpu(cpu_buffer, i); cpu_buf->sample_received = 0; cpu_buf->sample_lost_overflow = 0; cpu_buf->backtrace_aborted = 0; @@ -49,7 +49,7 @@ void oprofile_create_stats_files(struct super_block * sb, struct dentry * root) return; for_each_possible_cpu(i) { - cpu_buf = &cpu_buffer[i]; + cpu_buf = &per_cpu(cpu_buffer, i); snprintf(buf, 10, "cpu%d", i); cpudir = oprofilefs_mkdir(sb, dir, buf); diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c index 62db3c3fe4d..07d2a8d4498 100644 --- a/drivers/parisc/ccio-dma.c +++ b/drivers/parisc/ccio-dma.c @@ -1551,8 +1551,7 @@ static int __init ccio_probe(struct parisc_device *dev) { int i; struct ioc *ioc, **ioc_p = &ioc_list; - struct proc_dir_entry *info_entry, *bitmap_entry; - + ioc = kzalloc(sizeof(struct ioc), GFP_KERNEL); if (ioc == NULL) { printk(KERN_ERR MODULE_NAME ": memory allocation failure\n"); @@ -1580,13 +1579,10 @@ static int __init ccio_probe(struct parisc_device *dev) HBA_DATA(dev->dev.platform_data)->iommu = ioc; if (ioc_count == 0) { - info_entry = create_proc_entry(MODULE_NAME, 0, proc_runway_root); - if (info_entry) - info_entry->proc_fops = &ccio_proc_info_fops; - - bitmap_entry = create_proc_entry(MODULE_NAME"-bitmap", 0, proc_runway_root); - if (bitmap_entry) - bitmap_entry->proc_fops = &ccio_proc_bitmap_fops; + proc_create(MODULE_NAME, 0, proc_runway_root, + &ccio_proc_info_fops); + proc_create(MODULE_NAME"-bitmap", 0, proc_runway_root, + &ccio_proc_bitmap_fops); } ioc_count++; diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c index 8c4d2c13d5f..afc849bd3f5 100644 --- a/drivers/parisc/sba_iommu.c +++ b/drivers/parisc/sba_iommu.c @@ -1895,7 +1895,9 @@ sba_driver_callback(struct parisc_device *dev) int i; char *version; void __iomem *sba_addr = ioremap_nocache(dev->hpa.start, SBA_FUNC_SIZE); - struct proc_dir_entry *info_entry, *bitmap_entry, *root; +#ifdef CONFIG_PROC_FS + struct proc_dir_entry *root; +#endif sba_dump_ranges(sba_addr); @@ -1973,14 +1975,8 @@ sba_driver_callback(struct parisc_device *dev) break; } - info_entry = create_proc_entry("sba_iommu", 0, root); - bitmap_entry = create_proc_entry("sba_iommu-bitmap", 0, root); - - if (info_entry) - info_entry->proc_fops = &sba_proc_fops; - - if (bitmap_entry) - bitmap_entry->proc_fops = &sba_proc_bitmap_fops; + proc_create("sba_iommu", 0, root, &sba_proc_fops); + proc_create("sba_iommu-bitmap", 0, root, &sba_proc_bitmap_fops); #endif parisc_vmerge_boundary = IOVP_SIZE; diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c index a8580893820..e71092e8028 100644 --- a/drivers/parport/parport_pc.c +++ b/drivers/parport/parport_pc.c @@ -3082,6 +3082,7 @@ static struct pci_driver parport_pc_pci_driver; static int __init parport_pc_init_superio(int autoirq, int autodma) {return 0;} #endif /* CONFIG_PCI */ +#ifdef CONFIG_PNP static const struct pnp_device_id parport_pc_pnp_tbl[] = { /* Standard LPT Printer Port */ @@ -3148,6 +3149,9 @@ static struct pnp_driver parport_pc_pnp_driver = { .remove = parport_pc_pnp_remove, }; +#else +static struct pnp_driver parport_pc_pnp_driver; +#endif /* CONFIG_PNP */ static int __devinit parport_pc_platform_probe(struct platform_device *pdev) { diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index f14267e197d..8264a768043 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -93,11 +93,10 @@ struct controller { u8 slot_device_offset; u32 first_slot; /* First physical slot number */ /* PCIE only has 1 slot */ u8 slot_bus; /* Bus where the slots handled by this controller sit */ - u8 ctrlcap; + u32 slot_cap; u8 cap_base; struct timer_list poll_timer; volatile int cmd_busy; - spinlock_t lock; }; #define INT_BUTTON_IGNORE 0 @@ -137,13 +136,13 @@ struct controller { #define HP_SUPR_RM_SUP 0x00000020 #define EMI_PRSN 0x00020000 -#define ATTN_BUTTN(cap) (cap & ATTN_BUTTN_PRSN) -#define POWER_CTRL(cap) (cap & PWR_CTRL_PRSN) -#define MRL_SENS(cap) (cap & MRL_SENS_PRSN) -#define ATTN_LED(cap) (cap & ATTN_LED_PRSN) -#define PWR_LED(cap) (cap & PWR_LED_PRSN) -#define HP_SUPR_RM(cap) (cap & HP_SUPR_RM_SUP) -#define EMI(cap) (cap & EMI_PRSN) +#define ATTN_BUTTN(ctrl) ((ctrl)->slot_cap & ATTN_BUTTN_PRSN) +#define POWER_CTRL(ctrl) ((ctrl)->slot_cap & PWR_CTRL_PRSN) +#define MRL_SENS(ctrl) ((ctrl)->slot_cap & MRL_SENS_PRSN) +#define ATTN_LED(ctrl) ((ctrl)->slot_cap & ATTN_LED_PRSN) +#define PWR_LED(ctrl) ((ctrl)->slot_cap & PWR_LED_PRSN) +#define HP_SUPR_RM(ctrl) ((ctrl)->slot_cap & HP_SUPR_RM_SUP) +#define EMI(ctrl) ((ctrl)->slot_cap & EMI_PRSN) extern int pciehp_sysfs_enable_slot(struct slot *slot); extern int pciehp_sysfs_disable_slot(struct slot *slot); diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index aee19f013d8..43d8ddb2d67 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -41,6 +41,7 @@ int pciehp_debug; int pciehp_poll_mode; int pciehp_poll_time; int pciehp_force; +int pciehp_slot_with_bus; struct workqueue_struct *pciehp_wq; #define DRIVER_VERSION "0.4" @@ -55,10 +56,12 @@ module_param(pciehp_debug, bool, 0644); module_param(pciehp_poll_mode, bool, 0644); module_param(pciehp_poll_time, int, 0644); module_param(pciehp_force, bool, 0644); +module_param(pciehp_slot_with_bus, bool, 0644); MODULE_PARM_DESC(pciehp_debug, "Debugging mode enabled or not"); MODULE_PARM_DESC(pciehp_poll_mode, "Using polling mechanism for hot-plug events or not"); MODULE_PARM_DESC(pciehp_poll_time, "Polling mechanism frequency, in seconds"); MODULE_PARM_DESC(pciehp_force, "Force pciehp, even if _OSC and OSHP are missing"); +MODULE_PARM_DESC(pciehp_slot_with_bus, "Use bus number in the slot name"); #define PCIE_MODULE_NAME "pciehp" @@ -193,8 +196,12 @@ static void release_slot(struct hotplug_slot *hotplug_slot) static void make_slot_name(struct slot *slot) { - snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%04d_%04d", - slot->bus, slot->number); + if (pciehp_slot_with_bus) + snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%04d_%04d", + slot->bus, slot->number); + else + snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%d", + slot->number); } static int init_slots(struct controller *ctrl) @@ -251,7 +258,7 @@ static int init_slots(struct controller *ctrl) goto error_info; } /* create additional sysfs entries */ - if (EMI(ctrl->ctrlcap)) { + if (EMI(ctrl)) { retval = sysfs_create_file(&hotplug_slot->kobj, &hotplug_slot_attr_lock.attr); if (retval) { @@ -284,7 +291,7 @@ static void cleanup_slots(struct controller *ctrl) list_for_each_safe(tmp, next, &ctrl->slot_list) { slot = list_entry(tmp, struct slot, slot_list); list_del(&slot->slot_list); - if (EMI(ctrl->ctrlcap)) + if (EMI(ctrl)) sysfs_remove_file(&slot->hotplug_slot->kobj, &hotplug_slot_attr_lock.attr); cancel_delayed_work(&slot->work); @@ -305,7 +312,7 @@ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status) hotplug_slot->info->attention_status = status; - if (ATTN_LED(slot->ctrl->ctrlcap)) + if (ATTN_LED(slot->ctrl)) slot->hpc_ops->set_attention_status(slot, status); return 0; @@ -472,7 +479,7 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_ if (rc) /* -ENODEV: shouldn't happen, but deal with it */ value = 0; } - if ((POWER_CTRL(ctrl->ctrlcap)) && !value) { + if ((POWER_CTRL(ctrl)) && !value) { rc = t_slot->hpc_ops->power_off_slot(t_slot); /* Power off slot if not occupied*/ if (rc) goto err_out_free_ctrl_slot; diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index 0c481f7d2ab..0a7aa628e95 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c @@ -178,7 +178,7 @@ u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl) static void set_slot_off(struct controller *ctrl, struct slot * pslot) { /* turn off slot, turn on Amber LED, turn off Green LED if supported*/ - if (POWER_CTRL(ctrl->ctrlcap)) { + if (POWER_CTRL(ctrl)) { if (pslot->hpc_ops->power_off_slot(pslot)) { err("%s: Issue of Slot Power Off command failed\n", __func__); @@ -186,10 +186,10 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot) } } - if (PWR_LED(ctrl->ctrlcap)) + if (PWR_LED(ctrl)) pslot->hpc_ops->green_led_off(pslot); - if (ATTN_LED(ctrl->ctrlcap)) { + if (ATTN_LED(ctrl)) { if (pslot->hpc_ops->set_attention_status(pslot, 1)) { err("%s: Issue of Set Attention Led command failed\n", __func__); @@ -214,14 +214,14 @@ static int board_added(struct slot *p_slot) __func__, p_slot->device, ctrl->slot_device_offset, p_slot->hp_slot); - if (POWER_CTRL(ctrl->ctrlcap)) { + if (POWER_CTRL(ctrl)) { /* Power on slot */ retval = p_slot->hpc_ops->power_on_slot(p_slot); if (retval) return retval; } - if (PWR_LED(ctrl->ctrlcap)) + if (PWR_LED(ctrl)) p_slot->hpc_ops->green_led_blink(p_slot); /* Wait for ~1 second */ @@ -254,7 +254,7 @@ static int board_added(struct slot *p_slot) */ if (pcie_mch_quirk) pci_fixup_device(pci_fixup_final, ctrl->pci_dev); - if (PWR_LED(ctrl->ctrlcap)) + if (PWR_LED(ctrl)) p_slot->hpc_ops->green_led_on(p_slot); return 0; @@ -279,7 +279,7 @@ static int remove_board(struct slot *p_slot) dbg("In %s, hp_slot = %d\n", __func__, p_slot->hp_slot); - if (POWER_CTRL(ctrl->ctrlcap)) { + if (POWER_CTRL(ctrl)) { /* power off slot */ retval = p_slot->hpc_ops->power_off_slot(p_slot); if (retval) { @@ -289,7 +289,7 @@ static int remove_board(struct slot *p_slot) } } - if (PWR_LED(ctrl->ctrlcap)) + if (PWR_LED(ctrl)) /* turn off Green LED */ p_slot->hpc_ops->green_led_off(p_slot); @@ -327,7 +327,7 @@ static void pciehp_power_thread(struct work_struct *work) case POWERON_STATE: mutex_unlock(&p_slot->lock); if (pciehp_enable_slot(p_slot) && - PWR_LED(p_slot->ctrl->ctrlcap)) + PWR_LED(p_slot->ctrl)) p_slot->hpc_ops->green_led_off(p_slot); mutex_lock(&p_slot->lock); p_slot->state = STATIC_STATE; @@ -409,9 +409,9 @@ static void handle_button_press_event(struct slot *p_slot) "press.\n", p_slot->name); } /* blink green LED and turn off amber */ - if (PWR_LED(ctrl->ctrlcap)) + if (PWR_LED(ctrl)) p_slot->hpc_ops->green_led_blink(p_slot); - if (ATTN_LED(ctrl->ctrlcap)) + if (ATTN_LED(ctrl)) p_slot->hpc_ops->set_attention_status(p_slot, 0); schedule_delayed_work(&p_slot->work, 5*HZ); @@ -427,13 +427,13 @@ static void handle_button_press_event(struct slot *p_slot) dbg("%s: button cancel\n", __func__); cancel_delayed_work(&p_slot->work); if (p_slot->state == BLINKINGOFF_STATE) { - if (PWR_LED(ctrl->ctrlcap)) + if (PWR_LED(ctrl)) p_slot->hpc_ops->green_led_on(p_slot); } else { - if (PWR_LED(ctrl->ctrlcap)) + if (PWR_LED(ctrl)) p_slot->hpc_ops->green_led_off(p_slot); } - if (ATTN_LED(ctrl->ctrlcap)) + if (ATTN_LED(ctrl)) p_slot->hpc_ops->set_attention_status(p_slot, 0); info("PCI slot #%s - action canceled due to button press\n", p_slot->name); @@ -492,16 +492,16 @@ static void interrupt_event_handler(struct work_struct *work) handle_button_press_event(p_slot); break; case INT_POWER_FAULT: - if (!POWER_CTRL(ctrl->ctrlcap)) + if (!POWER_CTRL(ctrl)) break; - if (ATTN_LED(ctrl->ctrlcap)) + if (ATTN_LED(ctrl)) p_slot->hpc_ops->set_attention_status(p_slot, 1); - if (PWR_LED(ctrl->ctrlcap)) + if (PWR_LED(ctrl)) p_slot->hpc_ops->green_led_off(p_slot); break; case INT_PRESENCE_ON: case INT_PRESENCE_OFF: - if (!HP_SUPR_RM(ctrl->ctrlcap)) + if (!HP_SUPR_RM(ctrl)) break; dbg("Surprise Removal\n"); update_slot_info(p_slot); @@ -531,7 +531,7 @@ int pciehp_enable_slot(struct slot *p_slot) mutex_unlock(&p_slot->ctrl->crit_sect); return -ENODEV; } - if (MRL_SENS(p_slot->ctrl->ctrlcap)) { + if (MRL_SENS(p_slot->ctrl)) { rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); if (rc || getstatus) { info("%s: latch open on slot(%s)\n", __func__, @@ -541,7 +541,7 @@ int pciehp_enable_slot(struct slot *p_slot) } } - if (POWER_CTRL(p_slot->ctrl->ctrlcap)) { + if (POWER_CTRL(p_slot->ctrl)) { rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); if (rc || getstatus) { info("%s: already enabled on slot(%s)\n", __func__, @@ -576,7 +576,7 @@ int pciehp_disable_slot(struct slot *p_slot) /* Check to see if (latch closed, card present, power on) */ mutex_lock(&p_slot->ctrl->crit_sect); - if (!HP_SUPR_RM(p_slot->ctrl->ctrlcap)) { + if (!HP_SUPR_RM(p_slot->ctrl)) { ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); if (ret || !getstatus) { info("%s: no adapter on slot(%s)\n", __func__, @@ -586,7 +586,7 @@ int pciehp_disable_slot(struct slot *p_slot) } } - if (MRL_SENS(p_slot->ctrl->ctrlcap)) { + if (MRL_SENS(p_slot->ctrl)) { ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); if (ret || getstatus) { info("%s: latch open on slot(%s)\n", __func__, @@ -596,7 +596,7 @@ int pciehp_disable_slot(struct slot *p_slot) } } - if (POWER_CTRL(p_slot->ctrl->ctrlcap)) { + if (POWER_CTRL(p_slot->ctrl)) { ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); if (ret || !getstatus) { info("%s: already disabled slot(%s)\n", __func__, diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index b4bbd07d1e3..891f81a0400 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -221,6 +221,32 @@ static void start_int_poll_timer(struct controller *ctrl, int sec) add_timer(&ctrl->poll_timer); } +static inline int pciehp_request_irq(struct controller *ctrl) +{ + int retval, irq = ctrl->pci_dev->irq; + + /* Install interrupt polling timer. Start with 10 sec delay */ + if (pciehp_poll_mode) { + init_timer(&ctrl->poll_timer); + start_int_poll_timer(ctrl, 10); + return 0; + } + + /* Installs the interrupt handler */ + retval = request_irq(irq, pcie_isr, IRQF_SHARED, MY_NAME, ctrl); + if (retval) + err("Cannot get irq %d for the hotplug controller\n", irq); + return retval; +} + +static inline void pciehp_free_irq(struct controller *ctrl) +{ + if (pciehp_poll_mode) + del_timer_sync(&ctrl->poll_timer); + else + free_irq(ctrl->pci_dev->irq, ctrl); +} + static inline int pcie_wait_cmd(struct controller *ctrl) { int retval = 0; @@ -242,17 +268,15 @@ static inline int pcie_wait_cmd(struct controller *ctrl) /** * pcie_write_cmd - Issue controller command - * @slot: slot to which the command is issued + * @ctrl: controller to which the command is issued * @cmd: command value written to slot control register * @mask: bitmask of slot control register to be modified */ -static int pcie_write_cmd(struct slot *slot, u16 cmd, u16 mask) +static int pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask) { - struct controller *ctrl = slot->ctrl; int retval = 0; u16 slot_status; u16 slot_ctrl; - unsigned long flags; mutex_lock(&ctrl->ctrl_lock); @@ -270,24 +294,24 @@ static int pcie_write_cmd(struct slot *slot, u16 cmd, u16 mask) __func__); } - spin_lock_irqsave(&ctrl->lock, flags); retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); if (retval) { err("%s: Cannot read SLOTCTRL register\n", __func__); - goto out_spin_unlock; + goto out; } slot_ctrl &= ~mask; - slot_ctrl |= ((cmd & mask) | CMD_CMPL_INTR_ENABLE); + slot_ctrl |= (cmd & mask); + /* Don't enable command completed if caller is changing it. */ + if (!(mask & CMD_CMPL_INTR_ENABLE)) + slot_ctrl |= CMD_CMPL_INTR_ENABLE; ctrl->cmd_busy = 1; + smp_mb(); retval = pciehp_writew(ctrl, SLOTCTRL, slot_ctrl); if (retval) err("%s: Cannot write to SLOTCTRL register\n", __func__); - out_spin_unlock: - spin_unlock_irqrestore(&ctrl->lock, flags); - /* * Wait for command completion. */ @@ -467,12 +491,7 @@ static int hpc_toggle_emi(struct slot *slot) slot_cmd = EMI_CTRL; cmd_mask = EMI_CTRL; - if (!pciehp_poll_mode) { - slot_cmd = slot_cmd | HP_INTR_ENABLE; - cmd_mask = cmd_mask | HP_INTR_ENABLE; - } - - rc = pcie_write_cmd(slot, slot_cmd, cmd_mask); + rc = pcie_write_cmd(slot->ctrl, slot_cmd, cmd_mask); slot->last_emi_toggle = get_seconds(); return rc; @@ -499,12 +518,7 @@ static int hpc_set_attention_status(struct slot *slot, u8 value) default: return -1; } - if (!pciehp_poll_mode) { - slot_cmd = slot_cmd | HP_INTR_ENABLE; - cmd_mask = cmd_mask | HP_INTR_ENABLE; - } - - rc = pcie_write_cmd(slot, slot_cmd, cmd_mask); + rc = pcie_write_cmd(ctrl, slot_cmd, cmd_mask); dbg("%s: SLOTCTRL %x write cmd %x\n", __func__, ctrl->cap_base + SLOTCTRL, slot_cmd); @@ -519,13 +533,7 @@ static void hpc_set_green_led_on(struct slot *slot) slot_cmd = 0x0100; cmd_mask = PWR_LED_CTRL; - if (!pciehp_poll_mode) { - slot_cmd = slot_cmd | HP_INTR_ENABLE; - cmd_mask = cmd_mask | HP_INTR_ENABLE; - } - - pcie_write_cmd(slot, slot_cmd, cmd_mask); - + pcie_write_cmd(ctrl, slot_cmd, cmd_mask); dbg("%s: SLOTCTRL %x write cmd %x\n", __func__, ctrl->cap_base + SLOTCTRL, slot_cmd); } @@ -538,12 +546,7 @@ static void hpc_set_green_led_off(struct slot *slot) slot_cmd = 0x0300; cmd_mask = PWR_LED_CTRL; - if (!pciehp_poll_mode) { - slot_cmd = slot_cmd | HP_INTR_ENABLE; - cmd_mask = cmd_mask | HP_INTR_ENABLE; - } - - pcie_write_cmd(slot, slot_cmd, cmd_mask); + pcie_write_cmd(ctrl, slot_cmd, cmd_mask); dbg("%s: SLOTCTRL %x write cmd %x\n", __func__, ctrl->cap_base + SLOTCTRL, slot_cmd); } @@ -556,23 +559,19 @@ static void hpc_set_green_led_blink(struct slot *slot) slot_cmd = 0x0200; cmd_mask = PWR_LED_CTRL; - if (!pciehp_poll_mode) { - slot_cmd = slot_cmd | HP_INTR_ENABLE; - cmd_mask = cmd_mask | HP_INTR_ENABLE; - } - - pcie_write_cmd(slot, slot_cmd, cmd_mask); - + pcie_write_cmd(ctrl, slot_cmd, cmd_mask); dbg("%s: SLOTCTRL %x write cmd %x\n", __func__, ctrl->cap_base + SLOTCTRL, slot_cmd); } static void hpc_release_ctlr(struct controller *ctrl) { - if (pciehp_poll_mode) - del_timer(&ctrl->poll_timer); - else - free_irq(ctrl->pci_dev->irq, ctrl); + /* Mask Hot-plug Interrupt Enable */ + if (pcie_write_cmd(ctrl, 0, HP_INTR_ENABLE | CMD_CMPL_INTR_ENABLE)) + err("%s: Cannot mask hotplut interrupt enable\n", __func__); + + /* Free interrupt handler or interrupt polling timer */ + pciehp_free_irq(ctrl); /* * If this is the last controller to be released, destroy the @@ -612,19 +611,13 @@ static int hpc_power_on_slot(struct slot * slot) cmd_mask = PWR_CTRL; /* Enable detection that we turned off at slot power-off time */ if (!pciehp_poll_mode) { - slot_cmd = slot_cmd | - PWR_FAULT_DETECT_ENABLE | - MRL_DETECT_ENABLE | - PRSN_DETECT_ENABLE | - HP_INTR_ENABLE; - cmd_mask = cmd_mask | - PWR_FAULT_DETECT_ENABLE | - MRL_DETECT_ENABLE | - PRSN_DETECT_ENABLE | - HP_INTR_ENABLE; + slot_cmd |= (PWR_FAULT_DETECT_ENABLE | MRL_DETECT_ENABLE | + PRSN_DETECT_ENABLE); + cmd_mask |= (PWR_FAULT_DETECT_ENABLE | MRL_DETECT_ENABLE | + PRSN_DETECT_ENABLE); } - retval = pcie_write_cmd(slot, slot_cmd, cmd_mask); + retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask); if (retval) { err("%s: Write %x command failed!\n", __func__, slot_cmd); @@ -697,18 +690,13 @@ static int hpc_power_off_slot(struct slot * slot) * till the slot is powered on again. */ if (!pciehp_poll_mode) { - slot_cmd = (slot_cmd & - ~PWR_FAULT_DETECT_ENABLE & - ~MRL_DETECT_ENABLE & - ~PRSN_DETECT_ENABLE) | HP_INTR_ENABLE; - cmd_mask = cmd_mask | - PWR_FAULT_DETECT_ENABLE | - MRL_DETECT_ENABLE | - PRSN_DETECT_ENABLE | - HP_INTR_ENABLE; + slot_cmd &= ~(PWR_FAULT_DETECT_ENABLE | MRL_DETECT_ENABLE | + PRSN_DETECT_ENABLE); + cmd_mask |= (PWR_FAULT_DETECT_ENABLE | MRL_DETECT_ENABLE | + PRSN_DETECT_ENABLE); } - retval = pcie_write_cmd(slot, slot_cmd, cmd_mask); + retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask); if (retval) { err("%s: Write command failed!\n", __func__); retval = -1; @@ -733,139 +721,56 @@ static int hpc_power_off_slot(struct slot * slot) static irqreturn_t pcie_isr(int irq, void *dev_id) { struct controller *ctrl = (struct controller *)dev_id; - u16 slot_status, intr_detect, intr_loc; - u16 temp_word; - int hp_slot = 0; /* only 1 slot per PCI Express port */ - int rc = 0; - unsigned long flags; - - rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); - if (rc) { - err("%s: Cannot read SLOTSTATUS register\n", __func__); - return IRQ_NONE; - } - - intr_detect = (ATTN_BUTTN_PRESSED | PWR_FAULT_DETECTED | - MRL_SENS_CHANGED | PRSN_DETECT_CHANGED | CMD_COMPLETED); - - intr_loc = slot_status & intr_detect; - - /* Check to see if it was our interrupt */ - if ( !intr_loc ) - return IRQ_NONE; + u16 detected, intr_loc; - dbg("%s: intr_loc %x\n", __func__, intr_loc); - /* Mask Hot-plug Interrupt Enable */ - if (!pciehp_poll_mode) { - spin_lock_irqsave(&ctrl->lock, flags); - rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); - if (rc) { - err("%s: Cannot read SLOT_CTRL register\n", - __func__); - spin_unlock_irqrestore(&ctrl->lock, flags); + /* + * In order to guarantee that all interrupt events are + * serviced, we need to re-inspect Slot Status register after + * clearing what is presumed to be the last pending interrupt. + */ + intr_loc = 0; + do { + if (pciehp_readw(ctrl, SLOTSTATUS, &detected)) { + err("%s: Cannot read SLOTSTATUS\n", __func__); return IRQ_NONE; } - dbg("%s: pciehp_readw(SLOTCTRL) with value %x\n", - __func__, temp_word); - temp_word = (temp_word & ~HP_INTR_ENABLE & - ~CMD_CMPL_INTR_ENABLE) | 0x00; - rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); - if (rc) { - err("%s: Cannot write to SLOTCTRL register\n", - __func__); - spin_unlock_irqrestore(&ctrl->lock, flags); + detected &= (ATTN_BUTTN_PRESSED | PWR_FAULT_DETECTED | + MRL_SENS_CHANGED | PRSN_DETECT_CHANGED | + CMD_COMPLETED); + intr_loc |= detected; + if (!intr_loc) return IRQ_NONE; - } - spin_unlock_irqrestore(&ctrl->lock, flags); - - rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); - if (rc) { - err("%s: Cannot read SLOT_STATUS register\n", - __func__); + if (pciehp_writew(ctrl, SLOTSTATUS, detected)) { + err("%s: Cannot write to SLOTSTATUS\n", __func__); return IRQ_NONE; } - dbg("%s: pciehp_readw(SLOTSTATUS) with value %x\n", - __func__, slot_status); + } while (detected); - /* Clear command complete interrupt caused by this write */ - temp_word = 0x1f; - rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word); - if (rc) { - err("%s: Cannot write to SLOTSTATUS register\n", - __func__); - return IRQ_NONE; - } - } + dbg("%s: intr_loc %x\n", __FUNCTION__, intr_loc); + /* Check Command Complete Interrupt Pending */ if (intr_loc & CMD_COMPLETED) { - /* - * Command Complete Interrupt Pending - */ ctrl->cmd_busy = 0; + smp_mb(); wake_up_interruptible(&ctrl->queue); } + /* Check MRL Sensor Changed */ if (intr_loc & MRL_SENS_CHANGED) - pciehp_handle_switch_change(hp_slot, ctrl); + pciehp_handle_switch_change(0, ctrl); + /* Check Attention Button Pressed */ if (intr_loc & ATTN_BUTTN_PRESSED) - pciehp_handle_attention_button(hp_slot, ctrl); + pciehp_handle_attention_button(0, ctrl); + /* Check Presence Detect Changed */ if (intr_loc & PRSN_DETECT_CHANGED) - pciehp_handle_presence_change(hp_slot, ctrl); + pciehp_handle_presence_change(0, ctrl); + /* Check Power Fault Detected */ if (intr_loc & PWR_FAULT_DETECTED) - pciehp_handle_power_fault(hp_slot, ctrl); - - /* Clear all events after serving them */ - temp_word = 0x1F; - rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word); - if (rc) { - err("%s: Cannot write to SLOTSTATUS register\n", __func__); - return IRQ_NONE; - } - /* Unmask Hot-plug Interrupt Enable */ - if (!pciehp_poll_mode) { - spin_lock_irqsave(&ctrl->lock, flags); - rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); - if (rc) { - err("%s: Cannot read SLOTCTRL register\n", - __func__); - spin_unlock_irqrestore(&ctrl->lock, flags); - return IRQ_NONE; - } - - dbg("%s: Unmask Hot-plug Interrupt Enable\n", __func__); - temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE; - - rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); - if (rc) { - err("%s: Cannot write to SLOTCTRL register\n", - __func__); - spin_unlock_irqrestore(&ctrl->lock, flags); - return IRQ_NONE; - } - spin_unlock_irqrestore(&ctrl->lock, flags); - - rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); - if (rc) { - err("%s: Cannot read SLOT_STATUS register\n", - __func__); - return IRQ_NONE; - } - - /* Clear command complete interrupt caused by this write */ - temp_word = 0x1F; - rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word); - if (rc) { - err("%s: Cannot write to SLOTSTATUS failed\n", - __func__); - return IRQ_NONE; - } - dbg("%s: pciehp_writew(SLOTSTATUS) with value %x\n", - __func__, temp_word); - } + pciehp_handle_power_fault(0, ctrl); return IRQ_HANDLED; } @@ -1052,7 +957,7 @@ static struct hpc_ops pciehp_hpc_ops = { }; #ifdef CONFIG_ACPI -int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev) +static int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev) { acpi_status status; acpi_handle chandle, handle = DEVICE_ACPI_HANDLE(&(dev->dev)); @@ -1112,7 +1017,7 @@ int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev) break; } - err("Cannot get control of hotplug hardware for pci %s\n", + dbg("Cannot get control of hotplug hardware for pci %s\n", pci_name(dev)); kfree(string.pointer); @@ -1123,45 +1028,9 @@ int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev) static int pcie_init_hardware_part1(struct controller *ctrl, struct pcie_device *dev) { - int rc; - u16 temp_word; - u32 slot_cap; - u16 slot_status; - - rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap); - if (rc) { - err("%s: Cannot read SLOTCAP register\n", __func__); - return -1; - } - /* Mask Hot-plug Interrupt Enable */ - rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); - if (rc) { - err("%s: Cannot read SLOTCTRL register\n", __func__); - return -1; - } - - dbg("%s: SLOTCTRL %x value read %x\n", - __func__, ctrl->cap_base + SLOTCTRL, temp_word); - temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | - 0x00; - - rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); - if (rc) { - err("%s: Cannot write to SLOTCTRL register\n", __func__); - return -1; - } - - rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); - if (rc) { - err("%s: Cannot read SLOTSTATUS register\n", __func__); - return -1; - } - - temp_word = 0x1F; /* Clear all events */ - rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word); - if (rc) { - err("%s: Cannot write to SLOTSTATUS register\n", __func__); + if (pcie_write_cmd(ctrl, 0, HP_INTR_ENABLE | CMD_CMPL_INTR_ENABLE)) { + err("%s: Cannot mask hotplug interrupt enable\n", __func__); return -1; } return 0; @@ -1169,205 +1038,125 @@ static int pcie_init_hardware_part1(struct controller *ctrl, int pcie_init_hardware_part2(struct controller *ctrl, struct pcie_device *dev) { - int rc; - u16 temp_word; - u16 intr_enable = 0; - u32 slot_cap; - u16 slot_status; + u16 cmd, mask; - rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); - if (rc) { - err("%s: Cannot read SLOTCTRL register\n", __func__); - goto abort; - } - - intr_enable = intr_enable | PRSN_DETECT_ENABLE; - - rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap); - if (rc) { - err("%s: Cannot read SLOTCAP register\n", __func__); - goto abort; + /* + * We need to clear all events before enabling hotplug interrupt + * notification mechanism in order for hotplug controler to + * generate interrupts. + */ + if (pciehp_writew(ctrl, SLOTSTATUS, 0x1f)) { + err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__); + return -1; } - if (ATTN_BUTTN(slot_cap)) - intr_enable = intr_enable | ATTN_BUTTN_ENABLE; - - if (POWER_CTRL(slot_cap)) - intr_enable = intr_enable | PWR_FAULT_DETECT_ENABLE; - - if (MRL_SENS(slot_cap)) - intr_enable = intr_enable | MRL_DETECT_ENABLE; + cmd = PRSN_DETECT_ENABLE; + if (ATTN_BUTTN(ctrl)) + cmd |= ATTN_BUTTN_ENABLE; + if (POWER_CTRL(ctrl)) + cmd |= PWR_FAULT_DETECT_ENABLE; + if (MRL_SENS(ctrl)) + cmd |= MRL_DETECT_ENABLE; + if (!pciehp_poll_mode) + cmd |= HP_INTR_ENABLE; - temp_word = (temp_word & ~intr_enable) | intr_enable; + mask = PRSN_DETECT_ENABLE | ATTN_BUTTN_ENABLE | + PWR_FAULT_DETECT_ENABLE | MRL_DETECT_ENABLE | HP_INTR_ENABLE; - if (pciehp_poll_mode) { - temp_word = (temp_word & ~HP_INTR_ENABLE) | 0x0; - } else { - temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE; - } - - /* - * Unmask Hot-plug Interrupt Enable for the interrupt - * notification mechanism case. - */ - rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); - if (rc) { - err("%s: Cannot write to SLOTCTRL register\n", __func__); + if (pcie_write_cmd(ctrl, cmd, mask)) { + err("%s: Cannot enable software notification\n", __func__); goto abort; } - rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); - if (rc) { - err("%s: Cannot read SLOTSTATUS register\n", __func__); - goto abort_disable_intr; - } - - temp_word = 0x1F; /* Clear all events */ - rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word); - if (rc) { - err("%s: Cannot write to SLOTSTATUS register\n", __func__); - goto abort_disable_intr; - } - if (pciehp_force) { + if (pciehp_force) dbg("Bypassing BIOS check for pciehp use on %s\n", pci_name(ctrl->pci_dev)); - } else { - rc = pciehp_get_hp_hw_control_from_firmware(ctrl->pci_dev); - if (rc) - goto abort_disable_intr; - } + else if (pciehp_get_hp_hw_control_from_firmware(ctrl->pci_dev)) + goto abort_disable_intr; return 0; /* We end up here for the many possible ways to fail this API. */ abort_disable_intr: - rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); - if (!rc) { - temp_word &= ~(intr_enable | HP_INTR_ENABLE); - rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); - } - if (rc) + if (pcie_write_cmd(ctrl, 0, HP_INTR_ENABLE)) err("%s : disabling interrupts failed\n", __func__); abort: return -1; } -int pcie_init(struct controller *ctrl, struct pcie_device *dev) +static inline void dbg_ctrl(struct controller *ctrl) { - int rc; - u16 cap_reg; - u32 slot_cap; - int cap_base; - u16 slot_status, slot_ctrl; - struct pci_dev *pdev; - - pdev = dev->port; - ctrl->pci_dev = pdev; /* save pci_dev in context */ - - dbg("%s: hotplug controller vendor id 0x%x device id 0x%x\n", - __func__, pdev->vendor, pdev->device); + int i; + u16 reg16; + struct pci_dev *pdev = ctrl->pci_dev; - cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP); - if (cap_base == 0) { - dbg("%s: Can't find PCI_CAP_ID_EXP (0x10)\n", __func__); - goto abort; - } + if (!pciehp_debug) + return; - ctrl->cap_base = cap_base; + dbg("Hotplug Controller:\n"); + dbg(" Seg/Bus/Dev/Func/IRQ : %s IRQ %d\n", pci_name(pdev), pdev->irq); + dbg(" Vendor ID : 0x%04x\n", pdev->vendor); + dbg(" Device ID : 0x%04x\n", pdev->device); + dbg(" Subsystem ID : 0x%04x\n", pdev->subsystem_device); + dbg(" Subsystem Vendor ID : 0x%04x\n", pdev->subsystem_vendor); + dbg(" PCIe Cap offset : 0x%02x\n", ctrl->cap_base); + for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { + if (!pci_resource_len(pdev, i)) + continue; + dbg(" PCI resource [%d] : 0x%llx@0x%llx\n", i, + (unsigned long long)pci_resource_len(pdev, i), + (unsigned long long)pci_resource_start(pdev, i)); + } + dbg("Slot Capabilities : 0x%08x\n", ctrl->slot_cap); + dbg(" Physical Slot Number : %d\n", ctrl->first_slot); + dbg(" Attention Button : %3s\n", ATTN_BUTTN(ctrl) ? "yes" : "no"); + dbg(" Power Controller : %3s\n", POWER_CTRL(ctrl) ? "yes" : "no"); + dbg(" MRL Sensor : %3s\n", MRL_SENS(ctrl) ? "yes" : "no"); + dbg(" Attention Indicator : %3s\n", ATTN_LED(ctrl) ? "yes" : "no"); + dbg(" Power Indicator : %3s\n", PWR_LED(ctrl) ? "yes" : "no"); + dbg(" Hot-Plug Surprise : %3s\n", HP_SUPR_RM(ctrl) ? "yes" : "no"); + dbg(" EMI Present : %3s\n", EMI(ctrl) ? "yes" : "no"); + pciehp_readw(ctrl, SLOTSTATUS, ®16); + dbg("Slot Status : 0x%04x\n", reg16); + pciehp_readw(ctrl, SLOTSTATUS, ®16); + dbg("Slot Control : 0x%04x\n", reg16); +} - dbg("%s: pcie_cap_base %x\n", __func__, cap_base); +int pcie_init(struct controller *ctrl, struct pcie_device *dev) +{ + u32 slot_cap; + struct pci_dev *pdev = dev->port; - rc = pciehp_readw(ctrl, CAPREG, &cap_reg); - if (rc) { - err("%s: Cannot read CAPREG register\n", __func__); - goto abort; - } - dbg("%s: CAPREG offset %x cap_reg %x\n", - __func__, ctrl->cap_base + CAPREG, cap_reg); - - if (((cap_reg & SLOT_IMPL) == 0) || - (((cap_reg & DEV_PORT_TYPE) != 0x0040) - && ((cap_reg & DEV_PORT_TYPE) != 0x0060))) { - dbg("%s : This is not a root port or the port is not " - "connected to a slot\n", __func__); + ctrl->pci_dev = pdev; + ctrl->cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP); + if (!ctrl->cap_base) { + err("%s: Cannot find PCI Express capability\n", __func__); goto abort; } - - rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap); - if (rc) { + if (pciehp_readl(ctrl, SLOTCAP, &slot_cap)) { err("%s: Cannot read SLOTCAP register\n", __func__); goto abort; } - dbg("%s: SLOTCAP offset %x slot_cap %x\n", - __func__, ctrl->cap_base + SLOTCAP, slot_cap); - - if (!(slot_cap & HP_CAP)) { - dbg("%s : This slot is not hot-plug capable\n", __func__); - goto abort; - } - /* For debugging purpose */ - rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); - if (rc) { - err("%s: Cannot read SLOTSTATUS register\n", __func__); - goto abort; - } - dbg("%s: SLOTSTATUS offset %x slot_status %x\n", - __func__, ctrl->cap_base + SLOTSTATUS, slot_status); - - rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); - if (rc) { - err("%s: Cannot read SLOTCTRL register\n", __func__); - goto abort; - } - dbg("%s: SLOTCTRL offset %x slot_ctrl %x\n", - __func__, ctrl->cap_base + SLOTCTRL, slot_ctrl); - - for (rc = 0; rc < DEVICE_COUNT_RESOURCE; rc++) - if (pci_resource_len(pdev, rc) > 0) - dbg("pci resource[%d] start=0x%llx(len=0x%llx)\n", rc, - (unsigned long long)pci_resource_start(pdev, rc), - (unsigned long long)pci_resource_len(pdev, rc)); - - info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", - pdev->vendor, pdev->device, - pdev->subsystem_vendor, pdev->subsystem_device); + ctrl->slot_cap = slot_cap; + ctrl->first_slot = slot_cap >> 19; + ctrl->slot_device_offset = 0; + ctrl->num_slots = 1; + ctrl->hpc_ops = &pciehp_hpc_ops; mutex_init(&ctrl->crit_sect); mutex_init(&ctrl->ctrl_lock); - spin_lock_init(&ctrl->lock); - - /* setup wait queue */ init_waitqueue_head(&ctrl->queue); + dbg_ctrl(ctrl); - /* return PCI Controller Info */ - ctrl->slot_device_offset = 0; - ctrl->num_slots = 1; - ctrl->first_slot = slot_cap >> 19; - ctrl->ctrlcap = slot_cap & 0x0000007f; + info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", + pdev->vendor, pdev->device, + pdev->subsystem_vendor, pdev->subsystem_device); - rc = pcie_init_hardware_part1(ctrl, dev); - if (rc) + if (pcie_init_hardware_part1(ctrl, dev)) goto abort; - if (pciehp_poll_mode) { - /* Install interrupt polling timer. Start with 10 sec delay */ - init_timer(&ctrl->poll_timer); - start_int_poll_timer(ctrl, 10); - } else { - /* Installs the interrupt handler */ - rc = request_irq(ctrl->pci_dev->irq, pcie_isr, IRQF_SHARED, - MY_NAME, (void *)ctrl); - dbg("%s: request_irq %d for hpc%d (returns %d)\n", - __func__, ctrl->pci_dev->irq, - atomic_read(&pciehp_num_controllers), rc); - if (rc) { - err("Can't get irq %d for the hotplug controller\n", - ctrl->pci_dev->irq); - goto abort; - } - } - dbg("pciehp ctrl b:d:f:irq=0x%x:%x:%x:%x\n", pdev->bus->number, - PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), dev->irq); + if (pciehp_request_irq(ctrl)) + goto abort; /* * If this is the first controller to be initialized, @@ -1376,21 +1165,17 @@ int pcie_init(struct controller *ctrl, struct pcie_device *dev) if (atomic_add_return(1, &pciehp_num_controllers) == 1) { pciehp_wq = create_singlethread_workqueue("pciehpd"); if (!pciehp_wq) { - rc = -ENOMEM; goto abort_free_irq; } } - rc = pcie_init_hardware_part2(ctrl, dev); - if (rc == 0) { - ctrl->hpc_ops = &pciehp_hpc_ops; - return 0; - } + if (pcie_init_hardware_part2(ctrl, dev)) + goto abort_free_irq; + + return 0; + abort_free_irq: - if (pciehp_poll_mode) - del_timer_sync(&ctrl->poll_timer); - else - free_irq(ctrl->pci_dev->irq, ctrl); + pciehp_free_irq(ctrl); abort: return -1; } diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c index 43816d4b3c4..1648076600f 100644 --- a/drivers/pci/hotplug/shpchp_core.c +++ b/drivers/pci/hotplug/shpchp_core.c @@ -39,6 +39,7 @@ int shpchp_debug; int shpchp_poll_mode; int shpchp_poll_time; +int shpchp_slot_with_bus; struct workqueue_struct *shpchp_wq; #define DRIVER_VERSION "0.4" @@ -52,9 +53,11 @@ MODULE_LICENSE("GPL"); module_param(shpchp_debug, bool, 0644); module_param(shpchp_poll_mode, bool, 0644); module_param(shpchp_poll_time, int, 0644); +module_param(shpchp_slot_with_bus, bool, 0644); MODULE_PARM_DESC(shpchp_debug, "Debugging mode enabled or not"); MODULE_PARM_DESC(shpchp_poll_mode, "Using polling mechanism for hot-plug events or not"); MODULE_PARM_DESC(shpchp_poll_time, "Polling mechanism frequency, in seconds"); +MODULE_PARM_DESC(shpchp_slot_with_bus, "Use bus number in the slot name"); #define SHPC_MODULE_NAME "shpchp" @@ -100,8 +103,12 @@ static void release_slot(struct hotplug_slot *hotplug_slot) static void make_slot_name(struct slot *slot) { - snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%04d_%04d", - slot->bus, slot->number); + if (shpchp_slot_with_bus) + snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%04d_%04d", + slot->bus, slot->number); + else + snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%d", + slot->number); } static int init_slots(struct controller *ctrl) diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 26938da8f43..8c61304cbb3 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -123,7 +123,7 @@ static void msix_flush_writes(unsigned int irq) } } -static void msi_set_mask_bit(unsigned int irq, int flag) +static void msi_set_mask_bits(unsigned int irq, u32 mask, u32 flag) { struct msi_desc *entry; @@ -137,8 +137,8 @@ static void msi_set_mask_bit(unsigned int irq, int flag) pos = (long)entry->mask_base; pci_read_config_dword(entry->dev, pos, &mask_bits); - mask_bits &= ~(1); - mask_bits |= flag; + mask_bits &= ~(mask); + mask_bits |= flag & mask; pci_write_config_dword(entry->dev, pos, mask_bits); } else { msi_set_enable(entry->dev, !flag); @@ -241,13 +241,13 @@ void write_msi_msg(unsigned int irq, struct msi_msg *msg) void mask_msi_irq(unsigned int irq) { - msi_set_mask_bit(irq, 1); + msi_set_mask_bits(irq, 1, 1); msix_flush_writes(irq); } void unmask_msi_irq(unsigned int irq) { - msi_set_mask_bit(irq, 0); + msi_set_mask_bits(irq, 1, 0); msix_flush_writes(irq); } @@ -291,7 +291,8 @@ static void __pci_restore_msi_state(struct pci_dev *dev) msi_set_enable(dev, 0); write_msi_msg(dev->irq, &entry->msg); if (entry->msi_attrib.maskbit) - msi_set_mask_bit(dev->irq, entry->msi_attrib.masked); + msi_set_mask_bits(dev->irq, entry->msi_attrib.maskbits_mask, + entry->msi_attrib.masked); pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control); control &= ~(PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE); @@ -315,7 +316,7 @@ static void __pci_restore_msix_state(struct pci_dev *dev) list_for_each_entry(entry, &dev->msi_list, list) { write_msi_msg(entry->irq, &entry->msg); - msi_set_mask_bit(entry->irq, entry->msi_attrib.masked); + msi_set_mask_bits(entry->irq, 1, entry->msi_attrib.masked); } BUG_ON(list_empty(&dev->msi_list)); @@ -382,6 +383,7 @@ static int msi_capability_init(struct pci_dev *dev) pci_write_config_dword(dev, msi_mask_bits_reg(pos, is_64bit_address(control)), maskbits); + entry->msi_attrib.maskbits_mask = temp; } list_add_tail(&entry->list, &dev->msi_list); @@ -569,10 +571,9 @@ int pci_enable_msi(struct pci_dev* dev) } EXPORT_SYMBOL(pci_enable_msi); -void pci_disable_msi(struct pci_dev* dev) +void pci_msi_shutdown(struct pci_dev* dev) { struct msi_desc *entry; - int default_irq; if (!pci_msi_enable || !dev || !dev->msi_enabled) return; @@ -583,15 +584,31 @@ void pci_disable_msi(struct pci_dev* dev) BUG_ON(list_empty(&dev->msi_list)); entry = list_entry(dev->msi_list.next, struct msi_desc, list); - if (!entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) { - return; + /* Return the the pci reset with msi irqs unmasked */ + if (entry->msi_attrib.maskbit) { + u32 mask = entry->msi_attrib.maskbits_mask; + msi_set_mask_bits(dev->irq, mask, ~mask); } - - default_irq = entry->msi_attrib.default_irq; - msi_free_irqs(dev); + if (!entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) + return; /* Restore dev->irq to its default pin-assertion irq */ - dev->irq = default_irq; + dev->irq = entry->msi_attrib.default_irq; +} +void pci_disable_msi(struct pci_dev* dev) +{ + struct msi_desc *entry; + + if (!pci_msi_enable || !dev || !dev->msi_enabled) + return; + + pci_msi_shutdown(dev); + + entry = list_entry(dev->msi_list.next, struct msi_desc, list); + if (!entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) + return; + + msi_free_irqs(dev); } EXPORT_SYMBOL(pci_disable_msi); @@ -684,7 +701,7 @@ static void msix_free_all_irqs(struct pci_dev *dev) msi_free_irqs(dev); } -void pci_disable_msix(struct pci_dev* dev) +void pci_msix_shutdown(struct pci_dev* dev) { if (!pci_msi_enable || !dev || !dev->msix_enabled) return; @@ -692,6 +709,13 @@ void pci_disable_msix(struct pci_dev* dev) msix_set_enable(dev, 0); pci_intx_for_msi(dev, 1); dev->msix_enabled = 0; +} +void pci_disable_msix(struct pci_dev* dev) +{ + if (!pci_msi_enable || !dev || !dev->msix_enabled) + return; + + pci_msix_shutdown(dev); msix_free_all_irqs(dev); } diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index e8d94fafc28..72cf61ed8f9 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -360,6 +360,8 @@ static void pci_device_shutdown(struct device *dev) if (drv && drv->shutdown) drv->shutdown(pci_dev); + pci_msi_shutdown(pci_dev); + pci_msix_shutdown(pci_dev); } /** diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig index 25b04fb2517..5a0c6ad53f8 100644 --- a/drivers/pci/pcie/Kconfig +++ b/drivers/pci/pcie/Kconfig @@ -33,7 +33,7 @@ source "drivers/pci/pcie/aer/Kconfig" config PCIEASPM bool "PCI Express ASPM support(Experimental)" depends on PCI && EXPERIMENTAL && PCIEPORTBUS - default y + default n help This enables PCI Express ASPM (Active State Power Management) and Clock Power Management. ASPM supports state L0/L0s/L1. diff --git a/drivers/pci/pcie/aer/aerdrv_acpi.c b/drivers/pci/pcie/aer/aerdrv_acpi.c index 96ac54072f6..d39a78dbd02 100644 --- a/drivers/pci/pcie/aer/aerdrv_acpi.c +++ b/drivers/pci/pcie/aer/aerdrv_acpi.c @@ -31,7 +31,7 @@ int aer_osc_setup(struct pcie_device *pciedev) { acpi_status status = AE_NOT_FOUND; struct pci_dev *pdev = pciedev->port; - acpi_handle handle = 0; + acpi_handle handle = NULL; if (acpi_pci_disabled) return -1; diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index f991359f0c3..4a55bf38095 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -842,11 +842,14 @@ static void set_pcie_port_type(struct pci_dev *pdev) * reading the dword at 0x100 which must either be 0 or a valid extended * capability header. */ -int pci_cfg_space_size(struct pci_dev *dev) +int pci_cfg_space_size_ext(struct pci_dev *dev, unsigned check_exp_pcix) { int pos; u32 status; + if (!check_exp_pcix) + goto skip; + pos = pci_find_capability(dev, PCI_CAP_ID_EXP); if (!pos) { pos = pci_find_capability(dev, PCI_CAP_ID_PCIX); @@ -858,6 +861,7 @@ int pci_cfg_space_size(struct pci_dev *dev) goto fail; } + skip: if (pci_read_config_dword(dev, 256, &status) != PCIBIOS_SUCCESSFUL) goto fail; if (status == 0xffffffff) @@ -869,6 +873,11 @@ int pci_cfg_space_size(struct pci_dev *dev) return PCI_CFG_SPACE_SIZE; } +int pci_cfg_space_size(struct pci_dev *dev) +{ + return pci_cfg_space_size_ext(dev, 1); +} + static void pci_release_bus_bridge_dev(struct device *dev) { kfree(dev); @@ -964,7 +973,6 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus) dev->dev.release = pci_release_dev; pci_dev_get(dev); - set_dev_node(&dev->dev, pcibus_to_node(bus)); dev->dev.dma_mask = &dev->dma_mask; dev->dev.dma_parms = &dev->dma_parms; dev->dev.coherent_dma_mask = 0xffffffffull; @@ -1080,6 +1088,10 @@ unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus) return max; } +void __attribute__((weak)) set_pci_bus_resources_arch_default(struct pci_bus *b) +{ +} + struct pci_bus * pci_create_bus(struct device *parent, int bus, struct pci_ops *ops, void *sysdata) { @@ -1119,6 +1131,9 @@ struct pci_bus * pci_create_bus(struct device *parent, goto dev_reg_err; b->bridge = get_device(dev); + if (!parent) + set_dev_node(b->bridge, pcibus_to_node(b)); + b->dev.class = &pcibus_class; b->dev.parent = b->bridge; sprintf(b->dev.bus_id, "%04x:%02x", pci_domain_nr(b), bus); @@ -1136,6 +1151,8 @@ struct pci_bus * pci_create_bus(struct device *parent, b->resource[0] = &ioport_resource; b->resource[1] = &iomem_resource; + set_pci_bus_resources_arch_default(b); + return b; dev_create_file_err: diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c index ef18fcd641e..963a97642ae 100644 --- a/drivers/pci/proc.c +++ b/drivers/pci/proc.c @@ -293,6 +293,7 @@ static int proc_bus_pci_release(struct inode *inode, struct file *file) #endif /* HAVE_PCI_MMAP */ static const struct file_operations proc_bus_pci_operations = { + .owner = THIS_MODULE, .llseek = proc_bus_pci_lseek, .read = proc_bus_pci_read, .write = proc_bus_pci_write, @@ -406,11 +407,10 @@ int pci_proc_attach_device(struct pci_dev *dev) } sprintf(name, "%02x.%x", PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); - e = create_proc_entry(name, S_IFREG | S_IRUGO | S_IWUSR, bus->procdir); + e = proc_create_data(name, S_IFREG | S_IRUGO | S_IWUSR, bus->procdir, + &proc_bus_pci_operations, dev); if (!e) return -ENOMEM; - e->proc_fops = &proc_bus_pci_operations; - e->data = dev; e->size = dev->cfg_size; dev->procent = e; @@ -462,6 +462,7 @@ static int proc_bus_pci_dev_open(struct inode *inode, struct file *file) return seq_open(file, &proc_bus_pci_devices_op); } static const struct file_operations proc_bus_pci_dev_operations = { + .owner = THIS_MODULE, .open = proc_bus_pci_dev_open, .read = seq_read, .llseek = seq_lseek, @@ -470,12 +471,10 @@ static const struct file_operations proc_bus_pci_dev_operations = { static int __init pci_proc_init(void) { - struct proc_dir_entry *entry; struct pci_dev *dev = NULL; - proc_bus_pci_dir = proc_mkdir("pci", proc_bus); - entry = create_proc_entry("devices", 0, proc_bus_pci_dir); - if (entry) - entry->proc_fops = &proc_bus_pci_dev_operations; + proc_bus_pci_dir = proc_mkdir("bus/pci", NULL); + proc_create("devices", 0, proc_bus_pci_dir, + &proc_bus_pci_dev_operations); proc_initialized = 1; while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { pci_proc_attach_device(dev); diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig index 8d8852651fd..1b0eb5aaf65 100644 --- a/drivers/pcmcia/Kconfig +++ b/drivers/pcmcia/Kconfig @@ -38,7 +38,6 @@ config PCMCIA_DEBUG config PCMCIA tristate "16-bit PCMCIA support" select CRC32 - select HAVE_IDE default y ---help--- This option enables support for 16-bit PCMCIA cards. Most older diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c index 06a85d7d5aa..36379535f9d 100644 --- a/drivers/pcmcia/cistpl.c +++ b/drivers/pcmcia/cistpl.c @@ -402,15 +402,6 @@ EXPORT_SYMBOL(pcmcia_replace_cis); ======================================================================*/ -static inline u16 cis_get_u16(void *ptr) -{ - return le16_to_cpu(get_unaligned((__le16 *) ptr)); -} -static inline u32 cis_get_u32(void *ptr) -{ - return le32_to_cpu(get_unaligned((__le32 *) ptr)); -} - typedef struct tuple_flags { u_int link_space:4; u_int has_link:1; @@ -471,7 +462,7 @@ static int follow_link(struct pcmcia_socket *s, tuple_t *tuple) /* Get indirect link from the MFC tuple */ read_cis_cache(s, LINK_SPACE(tuple->Flags), tuple->LinkOffset, 5, link); - ofs = cis_get_u32(link + 1); + ofs = get_unaligned_le32(link + 1); SPACE(tuple->Flags) = (link[0] == CISTPL_MFC_ATTR); /* Move to the next indirect link */ tuple->LinkOffset += 5; @@ -679,8 +670,8 @@ static int parse_checksum(tuple_t *tuple, cistpl_checksum_t *csum) if (tuple->TupleDataLen < 5) return CS_BAD_TUPLE; p = (u_char *) tuple->TupleData; - csum->addr = tuple->CISOffset + cis_get_u16(p) - 2; - csum->len = cis_get_u16(p + 2); + csum->addr = tuple->CISOffset + get_unaligned_le16(p) - 2; + csum->len = get_unaligned_le16(p + 2); csum->sum = *(p + 4); return CS_SUCCESS; } @@ -691,7 +682,7 @@ static int parse_longlink(tuple_t *tuple, cistpl_longlink_t *link) { if (tuple->TupleDataLen < 4) return CS_BAD_TUPLE; - link->addr = cis_get_u32(tuple->TupleData); + link->addr = get_unaligned_le32(tuple->TupleData); return CS_SUCCESS; } @@ -710,7 +701,7 @@ static int parse_longlink_mfc(tuple_t *tuple, return CS_BAD_TUPLE; for (i = 0; i < link->nfn; i++) { link->fn[i].space = *p; p++; - link->fn[i].addr = cis_get_u32(p); + link->fn[i].addr = get_unaligned_le32(p); p += 4; } return CS_SUCCESS; @@ -800,8 +791,8 @@ static int parse_manfid(tuple_t *tuple, cistpl_manfid_t *m) { if (tuple->TupleDataLen < 4) return CS_BAD_TUPLE; - m->manf = cis_get_u16(tuple->TupleData); - m->card = cis_get_u16(tuple->TupleData + 2); + m->manf = get_unaligned_le16(tuple->TupleData); + m->card = get_unaligned_le16(tuple->TupleData + 2); return CS_SUCCESS; } @@ -1100,7 +1091,7 @@ static int parse_cftable_entry(tuple_t *tuple, break; case 0x20: entry->mem.nwin = 1; - entry->mem.win[0].len = cis_get_u16(p) << 8; + entry->mem.win[0].len = get_unaligned_le16(p) << 8; entry->mem.win[0].card_addr = 0; entry->mem.win[0].host_addr = 0; p += 2; @@ -1108,8 +1099,8 @@ static int parse_cftable_entry(tuple_t *tuple, break; case 0x40: entry->mem.nwin = 1; - entry->mem.win[0].len = cis_get_u16(p) << 8; - entry->mem.win[0].card_addr = cis_get_u16(p + 2) << 8; + entry->mem.win[0].len = get_unaligned_le16(p) << 8; + entry->mem.win[0].card_addr = get_unaligned_le16(p + 2) << 8; entry->mem.win[0].host_addr = 0; p += 4; if (p > q) return CS_BAD_TUPLE; @@ -1146,7 +1137,7 @@ static int parse_bar(tuple_t *tuple, cistpl_bar_t *bar) p = (u_char *)tuple->TupleData; bar->attr = *p; p += 2; - bar->size = cis_get_u32(p); + bar->size = get_unaligned_le32(p); return CS_SUCCESS; } @@ -1159,7 +1150,7 @@ static int parse_config_cb(tuple_t *tuple, cistpl_config_t *config) return CS_BAD_TUPLE; config->last_idx = *(++p); p++; - config->base = cis_get_u32(p); + config->base = get_unaligned_le32(p); config->subtuples = tuple->TupleDataLen - 6; return CS_SUCCESS; } @@ -1275,7 +1266,7 @@ static int parse_vers_2(tuple_t *tuple, cistpl_vers_2_t *v2) v2->vers = p[0]; v2->comply = p[1]; - v2->dindex = cis_get_u16(p +2 ); + v2->dindex = get_unaligned_le16(p +2 ); v2->vspec8 = p[6]; v2->vspec9 = p[7]; v2->nhdr = p[8]; @@ -1316,8 +1307,8 @@ static int parse_format(tuple_t *tuple, cistpl_format_t *fmt) fmt->type = p[0]; fmt->edc = p[1]; - fmt->offset = cis_get_u32(p + 2); - fmt->length = cis_get_u32(p + 6); + fmt->offset = get_unaligned_le32(p + 2); + fmt->length = get_unaligned_le32(p + 6); return CS_SUCCESS; } diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c index 27523c5f4da..5f186abca10 100644 --- a/drivers/pcmcia/pcmcia_ioctl.c +++ b/drivers/pcmcia/pcmcia_ioctl.c @@ -787,7 +787,7 @@ void __init pcmcia_setup_ioctl(void) { major_dev = i; #ifdef CONFIG_PROC_FS - proc_pccard = proc_mkdir("pccard", proc_bus); + proc_pccard = proc_mkdir("bus/pccard", NULL); if (proc_pccard) create_proc_read_entry("drivers",0,proc_pccard,proc_read_drivers,NULL); #endif @@ -798,7 +798,7 @@ void __exit pcmcia_cleanup_ioctl(void) { #ifdef CONFIG_PROC_FS if (proc_pccard) { remove_proc_entry("drivers", proc_pccard); - remove_proc_entry("pccard", proc_bus); + remove_proc_entry("bus/pccard", NULL); } #endif if (major_dev != -1) diff --git a/drivers/pnp/driver.c b/drivers/pnp/driver.c index 12a1645a2e4..e85cbf116db 100644 --- a/drivers/pnp/driver.c +++ b/drivers/pnp/driver.c @@ -167,7 +167,7 @@ static int pnp_bus_suspend(struct device *dev, pm_message_t state) return error; } - if (pnp_dev->protocol && pnp_dev->protocol->suspend) + if (pnp_dev->protocol->suspend) pnp_dev->protocol->suspend(pnp_dev, state); return 0; } @@ -181,7 +181,7 @@ static int pnp_bus_resume(struct device *dev) if (!pnp_drv) return 0; - if (pnp_dev->protocol && pnp_dev->protocol->resume) + if (pnp_dev->protocol->resume) pnp_dev->protocol->resume(pnp_dev); if (pnp_can_write(pnp_dev)) { diff --git a/drivers/pnp/isapnp/proc.c b/drivers/pnp/isapnp/proc.c index 2b8266c3d40..3f94edab25f 100644 --- a/drivers/pnp/isapnp/proc.c +++ b/drivers/pnp/isapnp/proc.c @@ -85,6 +85,7 @@ static ssize_t isapnp_proc_bus_read(struct file *file, char __user * buf, } static const struct file_operations isapnp_proc_bus_file_operations = { + .owner = THIS_MODULE, .llseek = isapnp_proc_bus_lseek, .read = isapnp_proc_bus_read, }; @@ -102,12 +103,10 @@ static int isapnp_proc_attach_device(struct pnp_dev *dev) return -ENOMEM; } sprintf(name, "%02x", dev->number); - e = dev->procent = create_proc_entry(name, S_IFREG | S_IRUGO, de); + e = dev->procent = proc_create_data(name, S_IFREG | S_IRUGO, de, + &isapnp_proc_bus_file_operations, dev); if (!e) return -ENOMEM; - e->proc_fops = &isapnp_proc_bus_file_operations; - e->owner = THIS_MODULE; - e->data = dev; e->size = 256; return 0; } @@ -116,7 +115,7 @@ int __init isapnp_proc_init(void) { struct pnp_dev *dev; - isapnp_proc_bus_dir = proc_mkdir("isapnp", proc_bus); + isapnp_proc_bus_dir = proc_mkdir("bus/isapnp", NULL); protocol_for_each_dev(&isapnp_protocol, dev) { isapnp_proc_attach_device(dev); } diff --git a/drivers/pnp/pnpbios/proc.c b/drivers/pnp/pnpbios/proc.c index bb19bc957ba..46d506f6625 100644 --- a/drivers/pnp/pnpbios/proc.c +++ b/drivers/pnp/pnpbios/proc.c @@ -256,7 +256,7 @@ int pnpbios_interface_attach_device(struct pnp_bios_node *node) */ int __init pnpbios_proc_init(void) { - proc_pnp = proc_mkdir("pnp", proc_bus); + proc_pnp = proc_mkdir("bus/pnp", NULL); if (!proc_pnp) return -EIO; proc_pnp_boot = proc_mkdir("boot", proc_pnp); @@ -294,5 +294,5 @@ void __exit pnpbios_proc_exit(void) remove_proc_entry("configuration_info", proc_pnp); remove_proc_entry("devices", proc_pnp); remove_proc_entry("boot", proc_pnp); - remove_proc_entry("pnp", proc_bus); + remove_proc_entry("bus/pnp", NULL); } diff --git a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c index 37993206ae5..e4daf4635c4 100644 --- a/drivers/pnp/quirks.c +++ b/drivers/pnp/quirks.c @@ -49,8 +49,11 @@ static void quirk_awe32_resources(struct pnp_dev *dev) port2->max += 0x400; port3->min += 0x800; port3->max += 0x800; + dev_info(&dev->dev, + "AWE32 quirk - added ioports 0x%lx and 0x%lx\n", + (unsigned long)port2->min, + (unsigned long)port3->min); } - printk(KERN_INFO "pnp: AWE32 quirk - adding two ports\n"); } static void quirk_cmi8330_resources(struct pnp_dev *dev) @@ -73,7 +76,8 @@ static void quirk_cmi8330_resources(struct pnp_dev *dev) IORESOURCE_DMA_8BIT) dma->map = 0x000A; } - printk(KERN_INFO "pnp: CMI8330 quirk - fixing interrupts and dma\n"); + dev_info(&dev->dev, "CMI8330 quirk - forced possible IRQs to 5, 7, 10 " + "and DMA channels to 1, 3\n"); } static void quirk_sb16audio_resources(struct pnp_dev *dev) @@ -104,8 +108,7 @@ static void quirk_sb16audio_resources(struct pnp_dev *dev) changed = 1; } if (changed) - printk(KERN_INFO - "pnp: SB audio device quirk - increasing port range\n"); + dev_info(&dev->dev, "SB audio device quirk - increased port range\n"); } @@ -214,8 +217,8 @@ void pnp_fixup_device(struct pnp_dev *dev) quirk = pnp_fixups[i].quirk_function; #ifdef DEBUG - dev_dbg(&dev->dev, "calling quirk 0x%p", quirk); - print_fn_descriptor_symbol(": %s()\n", + dev_dbg(&dev->dev, "calling "); + print_fn_descriptor_symbol("%s()\n", (unsigned long) *quirk); #endif (*quirk)(dev); diff --git a/drivers/power/ds2760_battery.c b/drivers/power/ds2760_battery.c index bdb9b7285b3..71be36f1870 100644 --- a/drivers/power/ds2760_battery.c +++ b/drivers/power/ds2760_battery.c @@ -262,7 +262,7 @@ static void ds2760_battery_work(struct work_struct *work) struct ds2760_device_info, monitor_work.work); const int interval = HZ * 60; - dev_dbg(di->dev, "%s\n", __FUNCTION__); + dev_dbg(di->dev, "%s\n", __func__); ds2760_battery_update_status(di); queue_delayed_work(di->monitor_wqueue, &di->monitor_work, interval); @@ -275,7 +275,7 @@ static void ds2760_battery_external_power_changed(struct power_supply *psy) { struct ds2760_device_info *di = to_ds2760_device_info(psy); - dev_dbg(di->dev, "%s\n", __FUNCTION__); + dev_dbg(di->dev, "%s\n", __func__); cancel_delayed_work(&di->monitor_work); queue_delayed_work(di->monitor_wqueue, &di->monitor_work, HZ/10); diff --git a/drivers/power/olpc_battery.c b/drivers/power/olpc_battery.c index af7a231092a..ab1e8289f07 100644 --- a/drivers/power/olpc_battery.c +++ b/drivers/power/olpc_battery.c @@ -315,7 +315,6 @@ static int __init olpc_bat_init(void) if (ret) goto battery_failed; - olpc_register_battery_callback(&olpc_battery_trigger_uevent); goto success; battery_failed: @@ -328,7 +327,6 @@ success: static void __exit olpc_bat_exit(void) { - olpc_deregister_battery_callback(); power_supply_unregister(&olpc_bat); power_supply_unregister(&olpc_ac); platform_device_unregister(bat_pdev); diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c index 03d6a38464e..138dd76ee34 100644 --- a/drivers/power/power_supply_core.c +++ b/drivers/power/power_supply_core.c @@ -39,7 +39,7 @@ static void power_supply_changed_work(struct work_struct *work) struct power_supply *psy = container_of(work, struct power_supply, changed_work); - dev_dbg(psy->dev, "%s\n", __FUNCTION__); + dev_dbg(psy->dev, "%s\n", __func__); class_for_each_device(power_supply_class, psy, __power_supply_changed_work); @@ -51,7 +51,7 @@ static void power_supply_changed_work(struct work_struct *work) void power_supply_changed(struct power_supply *psy) { - dev_dbg(psy->dev, "%s\n", __FUNCTION__); + dev_dbg(psy->dev, "%s\n", __func__); schedule_work(&psy->changed_work); } @@ -82,7 +82,7 @@ int power_supply_am_i_supplied(struct power_supply *psy) error = class_for_each_device(power_supply_class, psy, __power_supply_am_i_supplied); - dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, error); + dev_dbg(psy->dev, "%s %d\n", __func__, error); return error; } diff --git a/drivers/power/power_supply_leds.c b/drivers/power/power_supply_leds.c index fa3034f85c3..2dece40c544 100644 --- a/drivers/power/power_supply_leds.c +++ b/drivers/power/power_supply_leds.c @@ -24,7 +24,7 @@ static void power_supply_update_bat_leds(struct power_supply *psy) if (psy->get_property(psy, POWER_SUPPLY_PROP_STATUS, &status)) return; - dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, status.intval); + dev_dbg(psy->dev, "%s %d\n", __func__, status.intval); switch (status.intval) { case POWER_SUPPLY_STATUS_FULL: @@ -101,7 +101,7 @@ static void power_supply_update_gen_leds(struct power_supply *psy) if (psy->get_property(psy, POWER_SUPPLY_PROP_ONLINE, &online)) return; - dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, online.intval); + dev_dbg(psy->dev, "%s %d\n", __func__, online.intval); if (online.intval) led_trigger_event(psy->online_trig, LED_FULL); diff --git a/drivers/rapidio/Kconfig b/drivers/rapidio/Kconfig index 4142115d298..c32822ad84a 100644 --- a/drivers/rapidio/Kconfig +++ b/drivers/rapidio/Kconfig @@ -1,14 +1,6 @@ # # RapidIO configuration # -config RAPIDIO_8_BIT_TRANSPORT - bool "8-bit transport addressing" - depends on RAPIDIO - ---help--- - By default, the kernel assumes a 16-bit addressed RapidIO - network. By selecting this option, the kernel will support - an 8-bit addressed network. - config RAPIDIO_DISC_TIMEOUT int "Discovery timeout duration (seconds)" depends on RAPIDIO diff --git a/drivers/rapidio/rio-access.c b/drivers/rapidio/rio-access.c index 8b56bbdd011..a3824baca2e 100644 --- a/drivers/rapidio/rio-access.c +++ b/drivers/rapidio/rio-access.c @@ -48,7 +48,7 @@ int __rio_local_read_config_##size \ u32 data = 0; \ if (RIO_##size##_BAD) return RIO_BAD_SIZE; \ spin_lock_irqsave(&rio_config_lock, flags); \ - res = mport->ops->lcread(mport->id, offset, len, &data); \ + res = mport->ops->lcread(mport, mport->id, offset, len, &data); \ *value = (type)data; \ spin_unlock_irqrestore(&rio_config_lock, flags); \ return res; \ @@ -71,7 +71,7 @@ int __rio_local_write_config_##size \ unsigned long flags; \ if (RIO_##size##_BAD) return RIO_BAD_SIZE; \ spin_lock_irqsave(&rio_config_lock, flags); \ - res = mport->ops->lcwrite(mport->id, offset, len, value); \ + res = mport->ops->lcwrite(mport, mport->id, offset, len, value);\ spin_unlock_irqrestore(&rio_config_lock, flags); \ return res; \ } @@ -108,7 +108,7 @@ int rio_mport_read_config_##size \ u32 data = 0; \ if (RIO_##size##_BAD) return RIO_BAD_SIZE; \ spin_lock_irqsave(&rio_config_lock, flags); \ - res = mport->ops->cread(mport->id, destid, hopcount, offset, len, &data); \ + res = mport->ops->cread(mport, mport->id, destid, hopcount, offset, len, &data); \ *value = (type)data; \ spin_unlock_irqrestore(&rio_config_lock, flags); \ return res; \ @@ -131,7 +131,7 @@ int rio_mport_write_config_##size \ unsigned long flags; \ if (RIO_##size##_BAD) return RIO_BAD_SIZE; \ spin_lock_irqsave(&rio_config_lock, flags); \ - res = mport->ops->cwrite(mport->id, destid, hopcount, offset, len, value); \ + res = mport->ops->cwrite(mport, mport->id, destid, hopcount, offset, len, value); \ spin_unlock_irqrestore(&rio_config_lock, flags); \ return res; \ } @@ -166,7 +166,7 @@ int rio_mport_send_doorbell(struct rio_mport *mport, u16 destid, u16 data) unsigned long flags; spin_lock_irqsave(&rio_doorbell_lock, flags); - res = mport->ops->dsend(mport->id, destid, data); + res = mport->ops->dsend(mport, mport->id, destid, data); spin_unlock_irqrestore(&rio_doorbell_lock, flags); return res; diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c index 44420723a35..a926c896475 100644 --- a/drivers/rapidio/rio-scan.c +++ b/drivers/rapidio/rio-scan.c @@ -73,7 +73,7 @@ static u16 rio_get_device_id(struct rio_mport *port, u16 destid, u8 hopcount) rio_mport_read_config_32(port, destid, hopcount, RIO_DID_CSR, &result); - return RIO_GET_DID(result); + return RIO_GET_DID(port->sys_size, result); } /** @@ -88,7 +88,7 @@ static u16 rio_get_device_id(struct rio_mport *port, u16 destid, u8 hopcount) static void rio_set_device_id(struct rio_mport *port, u16 destid, u8 hopcount, u16 did) { rio_mport_write_config_32(port, destid, hopcount, RIO_DID_CSR, - RIO_SET_DID(did)); + RIO_SET_DID(port->sys_size, did)); } /** @@ -100,7 +100,8 @@ static void rio_set_device_id(struct rio_mport *port, u16 destid, u8 hopcount, u */ static void rio_local_set_device_id(struct rio_mport *port, u16 did) { - rio_local_write_config_32(port, RIO_DID_CSR, RIO_SET_DID(did)); + rio_local_write_config_32(port, RIO_DID_CSR, RIO_SET_DID(port->sys_size, + did)); } /** @@ -350,8 +351,18 @@ static struct rio_dev *rio_setup_device(struct rio_net *net, rswitch->switchid = next_switchid; rswitch->hopcount = hopcount; rswitch->destid = destid; + rswitch->route_table = kzalloc(sizeof(u8)* + RIO_MAX_ROUTE_ENTRIES(port->sys_size), + GFP_KERNEL); + if (!rswitch->route_table) { + kfree(rdev); + rdev = NULL; + kfree(rswitch); + goto out; + } /* Initialize switch route table */ - for (rdid = 0; rdid < RIO_MAX_ROUTE_ENTRIES; rdid++) + for (rdid = 0; rdid < RIO_MAX_ROUTE_ENTRIES(port->sys_size); + rdid++) rswitch->route_table[rdid] = RIO_INVALID_ROUTE; rdev->rswitch = rswitch; sprintf(rio_name(rdev), "%02x:s:%04x", rdev->net->id, @@ -480,7 +491,7 @@ static u16 rio_get_host_deviceid_lock(struct rio_mport *port, u8 hopcount) { u32 result; - rio_mport_read_config_32(port, RIO_ANY_DESTID, hopcount, + rio_mport_read_config_32(port, RIO_ANY_DESTID(port->sys_size), hopcount, RIO_HOST_DID_LOCK_CSR, &result); return (u16) (result & 0xffff); @@ -571,14 +582,16 @@ static int rio_enum_peer(struct rio_net *net, struct rio_mport *port, } /* Attempt to acquire device lock */ - rio_mport_write_config_32(port, RIO_ANY_DESTID, hopcount, + rio_mport_write_config_32(port, RIO_ANY_DESTID(port->sys_size), + hopcount, RIO_HOST_DID_LOCK_CSR, port->host_deviceid); while ((tmp = rio_get_host_deviceid_lock(port, hopcount)) < port->host_deviceid) { /* Delay a bit */ mdelay(1); /* Attempt to acquire device lock again */ - rio_mport_write_config_32(port, RIO_ANY_DESTID, hopcount, + rio_mport_write_config_32(port, RIO_ANY_DESTID(port->sys_size), + hopcount, RIO_HOST_DID_LOCK_CSR, port->host_deviceid); } @@ -590,7 +603,9 @@ static int rio_enum_peer(struct rio_net *net, struct rio_mport *port, } /* Setup new RIO device */ - if ((rdev = rio_setup_device(net, port, RIO_ANY_DESTID, hopcount, 1))) { + rdev = rio_setup_device(net, port, RIO_ANY_DESTID(port->sys_size), + hopcount, 1); + if (rdev) { /* Add device to the global and bus/net specific list. */ list_add_tail(&rdev->net_list, &net->devices); } else @@ -598,7 +613,8 @@ static int rio_enum_peer(struct rio_net *net, struct rio_mport *port, if (rio_is_switch(rdev)) { next_switchid++; - sw_inport = rio_get_swpinfo_inport(port, RIO_ANY_DESTID, hopcount); + sw_inport = rio_get_swpinfo_inport(port, + RIO_ANY_DESTID(port->sys_size), hopcount); rio_route_add_entry(port, rdev->rswitch, RIO_GLOBAL_TABLE, port->host_deviceid, sw_inport); rdev->rswitch->route_table[port->host_deviceid] = sw_inport; @@ -612,7 +628,8 @@ static int rio_enum_peer(struct rio_net *net, struct rio_mport *port, } num_ports = - rio_get_swpinfo_tports(port, RIO_ANY_DESTID, hopcount); + rio_get_swpinfo_tports(port, RIO_ANY_DESTID(port->sys_size), + hopcount); pr_debug( "RIO: found %s (vid %4.4x did %4.4x) with %d ports\n", rio_name(rdev), rdev->vid, rdev->did, num_ports); @@ -624,13 +641,15 @@ static int rio_enum_peer(struct rio_net *net, struct rio_mport *port, cur_destid = next_destid; if (rio_sport_is_active - (port, RIO_ANY_DESTID, hopcount, port_num)) { + (port, RIO_ANY_DESTID(port->sys_size), hopcount, + port_num)) { pr_debug( "RIO: scanning device on port %d\n", port_num); rio_route_add_entry(port, rdev->rswitch, - RIO_GLOBAL_TABLE, - RIO_ANY_DESTID, port_num); + RIO_GLOBAL_TABLE, + RIO_ANY_DESTID(port->sys_size), + port_num); if (rio_enum_peer(net, port, hopcount + 1) < 0) return -1; @@ -735,7 +754,8 @@ rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid, pr_debug( "RIO: scanning device on port %d\n", port_num); - for (ndestid = 0; ndestid < RIO_ANY_DESTID; + for (ndestid = 0; + ndestid < RIO_ANY_DESTID(port->sys_size); ndestid++) { rio_route_get_entry(port, rdev->rswitch, RIO_GLOBAL_TABLE, @@ -917,7 +937,9 @@ static void rio_build_route_tables(void) list_for_each_entry(rdev, &rio_devices, global_list) if (rio_is_switch(rdev)) - for (i = 0; i < RIO_MAX_ROUTE_ENTRIES; i++) { + for (i = 0; + i < RIO_MAX_ROUTE_ENTRIES(rdev->net->hport->sys_size); + i++) { if (rio_route_get_entry (rdev->net->hport, rdev->rswitch, RIO_GLOBAL_TABLE, i, &sport) < 0) @@ -981,7 +1003,8 @@ int rio_disc_mport(struct rio_mport *mport) del_timer_sync(&rio_enum_timer); pr_debug("done\n"); - if (rio_disc_peer(net, mport, RIO_ANY_DESTID, 0) < 0) { + if (rio_disc_peer(net, mport, RIO_ANY_DESTID(mport->sys_size), + 0) < 0) { printk(KERN_INFO "RIO: master port %d device has failed discovery\n", mport->id); diff --git a/drivers/rapidio/rio-sysfs.c b/drivers/rapidio/rio-sysfs.c index 659e31164cf..97a147f050d 100644 --- a/drivers/rapidio/rio-sysfs.c +++ b/drivers/rapidio/rio-sysfs.c @@ -43,7 +43,8 @@ static ssize_t routes_show(struct device *dev, struct device_attribute *attr, ch if (!rdev->rswitch) goto out; - for (i = 0; i < RIO_MAX_ROUTE_ENTRIES; i++) { + for (i = 0; i < RIO_MAX_ROUTE_ENTRIES(rdev->net->hport->sys_size); + i++) { if (rdev->rswitch->route_table[i] == RIO_INVALID_ROUTE) continue; str += diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c index 80c5f1ba2e4..680661abbc4 100644 --- a/drivers/rapidio/rio.c +++ b/drivers/rapidio/rio.c @@ -43,7 +43,7 @@ u16 rio_local_get_device_id(struct rio_mport *port) rio_local_read_config_32(port, RIO_DID_CSR, &result); - return (RIO_GET_DID(result)); + return (RIO_GET_DID(port->sys_size, result)); } /** diff --git a/drivers/rapidio/rio.h b/drivers/rapidio/rio.h index 80e3f03b504..7786d02581f 100644 --- a/drivers/rapidio/rio.h +++ b/drivers/rapidio/rio.h @@ -51,10 +51,5 @@ extern struct rio_route_ops __end_rio_route_ops[]; DECLARE_RIO_ROUTE_SECTION(.rio_route_ops, \ vid, did, add_hook, get_hook) -#ifdef CONFIG_RAPIDIO_8_BIT_TRANSPORT -#define RIO_GET_DID(x) ((x & 0x00ff0000) >> 16) -#define RIO_SET_DID(x) ((x & 0x000000ff) << 16) -#else -#define RIO_GET_DID(x) (x & 0xffff) -#define RIO_SET_DID(x) (x & 0xffff) -#endif +#define RIO_GET_DID(size, x) (size ? (x & 0xffff) : ((x & 0x00ff0000) >> 16)) +#define RIO_SET_DID(size, x) (size ? (x & 0xffff) : ((x & 0x000000ff) << 16)) diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 02a4c8cf2b2..6cc2c033023 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -20,10 +20,6 @@ menuconfig RTC_CLASS if RTC_CLASS -if GEN_RTC || RTC -comment "Conflicting RTC option has been selected, check GEN_RTC and RTC" -endif - config RTC_HCTOSYS bool "Set system time from RTC on startup and resume" depends on RTC_CLASS = y @@ -304,6 +300,7 @@ comment "Platform RTC drivers" config RTC_DRV_CMOS tristate "PC-style 'CMOS'" depends on X86 || ALPHA || ARM || M32R || ATARI || PPC || MIPS + default y if X86 help Say "yes" here to get direct support for the real time clock found in every PC or ACPI-based system, and some other boards. diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c index 52abffc86bc..39e64ab1ecb 100644 --- a/drivers/rtc/rtc-at91rm9200.c +++ b/drivers/rtc/rtc-at91rm9200.c @@ -83,7 +83,7 @@ static int at91_rtc_readtime(struct device *dev, struct rtc_time *tm) tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year); tm->tm_year = tm->tm_year - 1900; - pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__, + pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__, 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); @@ -97,7 +97,7 @@ static int at91_rtc_settime(struct device *dev, struct rtc_time *tm) { unsigned long cr; - pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__, + pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__, 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); @@ -142,7 +142,7 @@ static int at91_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm) alrm->enabled = (at91_sys_read(AT91_RTC_IMR) & AT91_RTC_ALARM) ? 1 : 0; - pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__, + pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__, 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); @@ -178,7 +178,7 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) if (alrm->enabled) at91_sys_write(AT91_RTC_IER, AT91_RTC_ALARM); - pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__, + pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__, at91_alarm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); @@ -193,7 +193,7 @@ static int at91_rtc_ioctl(struct device *dev, unsigned int cmd, { int ret = 0; - pr_debug("%s(): cmd=%08x, arg=%08lx.\n", __FUNCTION__, cmd, arg); + pr_debug("%s(): cmd=%08x, arg=%08lx.\n", __func__, cmd, arg); switch (cmd) { case RTC_AIE_OFF: /* alarm off */ @@ -265,7 +265,7 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id) rtc_update_irq(rtc, 1, events); - pr_debug("%s(): num=%ld, events=0x%02lx\n", __FUNCTION__, + pr_debug("%s(): num=%ld, events=0x%02lx\n", __func__, events >> 8, events & 0x000000FF); return IRQ_HANDLED; diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c index 56728a2a338..38d8742a4bd 100644 --- a/drivers/rtc/rtc-at91sam9.c +++ b/drivers/rtc/rtc-at91sam9.c @@ -288,7 +288,7 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *_rtc) rtc_update_irq(rtc->rtcdev, 1, events); - pr_debug("%s: num=%ld, events=0x%02lx\n", __FUNCTION__, + pr_debug("%s: num=%ld, events=0x%02lx\n", __func__, events >> 8, events & 0x000000FF); return IRQ_HANDLED; diff --git a/drivers/rtc/rtc-bfin.c b/drivers/rtc/rtc-bfin.c index 4f28045d9ef..8624f55d056 100644 --- a/drivers/rtc/rtc-bfin.c +++ b/drivers/rtc/rtc-bfin.c @@ -419,7 +419,7 @@ static int __devinit bfin_rtc_probe(struct platform_device *pdev) return -ENOMEM; rtc->rtc_dev = rtc_device_register(pdev->name, &pdev->dev, &bfin_rtc_ops, THIS_MODULE); - if (unlikely(IS_ERR(rtc))) { + if (IS_ERR(rtc)) { ret = PTR_ERR(rtc->rtc_dev); goto err; } diff --git a/drivers/rtc/rtc-ds1302.c b/drivers/rtc/rtc-ds1302.c index 7b002ceeaa7..b9397818f73 100644 --- a/drivers/rtc/rtc-ds1302.c +++ b/drivers/rtc/rtc-ds1302.c @@ -122,7 +122,7 @@ static int ds1302_rtc_read_time(struct device *dev, struct rtc_time *tm) dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, " "mday=%d, mon=%d, year=%d, wday=%d\n", - __FUNCTION__, + __func__, tm->tm_sec, tm->tm_min, tm->tm_hour, tm->tm_mday, tm->tm_mon + 1, tm->tm_year, tm->tm_wday); diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index f389a28720d..bbf97e65202 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -99,45 +99,38 @@ struct ds1307 { }; struct chip_desc { - char name[9]; unsigned nvram56:1; unsigned alarm:1; - enum ds_type type; }; -static const struct chip_desc chips[] = { { - .name = "ds1307", - .type = ds_1307, +static const struct chip_desc chips[] = { +[ds_1307] = { .nvram56 = 1, -}, { - .name = "ds1337", - .type = ds_1337, +}, +[ds_1337] = { .alarm = 1, -}, { - .name = "ds1338", - .type = ds_1338, +}, +[ds_1338] = { .nvram56 = 1, -}, { - .name = "ds1339", - .type = ds_1339, +}, +[ds_1339] = { .alarm = 1, -}, { - .name = "ds1340", - .type = ds_1340, -}, { - .name = "m41t00", - .type = m41t00, +}, +[ds_1340] = { +}, +[m41t00] = { }, }; -static inline const struct chip_desc *find_chip(const char *s) -{ - unsigned i; - - for (i = 0; i < ARRAY_SIZE(chips); i++) - if (strnicmp(s, chips[i].name, sizeof chips[i].name) == 0) - return &chips[i]; - return NULL; -} +static const struct i2c_device_id ds1307_id[] = { + { "ds1307", ds_1307 }, + { "ds1337", ds_1337 }, + { "ds1338", ds_1338 }, + { "ds1339", ds_1339 }, + { "ds1340", ds_1340 }, + { "m41t00", m41t00 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ds1307_id); static int ds1307_get_time(struct device *dev, struct rtc_time *t) { @@ -326,21 +319,15 @@ static struct bin_attribute nvram = { static struct i2c_driver ds1307_driver; -static int __devinit ds1307_probe(struct i2c_client *client) +static int __devinit ds1307_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct ds1307 *ds1307; int err = -ENODEV; int tmp; - const struct chip_desc *chip; + const struct chip_desc *chip = &chips[id->driver_data]; struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); - chip = find_chip(client->name); - if (!chip) { - dev_err(&client->dev, "unknown chip type '%s'\n", - client->name); - return -ENODEV; - } - if (!i2c_check_functionality(adapter, I2C_FUNC_I2C | I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) return -EIO; @@ -361,7 +348,7 @@ static int __devinit ds1307_probe(struct i2c_client *client) ds1307->msg[1].len = sizeof(ds1307->regs); ds1307->msg[1].buf = ds1307->regs; - ds1307->type = chip->type; + ds1307->type = id->driver_data; switch (ds1307->type) { case ds_1337: @@ -550,6 +537,7 @@ static struct i2c_driver ds1307_driver = { }, .probe = ds1307_probe, .remove = __devexit_p(ds1307_remove), + .id_table = ds1307_id, }; static int __init ds1307_init(void) diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c index 45bda186bef..fa2d2f8b3f4 100644 --- a/drivers/rtc/rtc-ds1374.c +++ b/drivers/rtc/rtc-ds1374.c @@ -41,6 +41,12 @@ #define DS1374_REG_SR_AF 0x01 /* Alarm Flag */ #define DS1374_REG_TCR 0x09 /* Trickle Charge */ +static const struct i2c_device_id ds1374_id[] = { + { "rtc-ds1374", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ds1374_id); + struct ds1374 { struct i2c_client *client; struct rtc_device *rtc; @@ -355,7 +361,8 @@ static const struct rtc_class_ops ds1374_rtc_ops = { .ioctl = ds1374_ioctl, }; -static int ds1374_probe(struct i2c_client *client) +static int ds1374_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct ds1374 *ds1374; int ret; @@ -429,6 +436,7 @@ static struct i2c_driver ds1374_driver = { }, .probe = ds1374_probe, .remove = __devexit_p(ds1374_remove), + .id_table = ds1374_id, }; static int __init ds1374_init(void) diff --git a/drivers/rtc/rtc-ds1511.c b/drivers/rtc/rtc-ds1511.c index d08912f18dd..a83a40b3eba 100644 --- a/drivers/rtc/rtc-ds1511.c +++ b/drivers/rtc/rtc-ds1511.c @@ -181,8 +181,7 @@ ds1511_wdog_disable(void) * stupidly, some callers call with year unmolested; * and some call with year = year - 1900. thanks. */ - int -ds1511_rtc_set_time(struct device *dev, struct rtc_time *rtc_tm) +static int ds1511_rtc_set_time(struct device *dev, struct rtc_time *rtc_tm) { u8 mon, day, dow, hrs, min, sec, yrs, cen; unsigned int flags; @@ -245,8 +244,7 @@ ds1511_rtc_set_time(struct device *dev, struct rtc_time *rtc_tm) return 0; } - int -ds1511_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm) +static int ds1511_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm) { unsigned int century; unsigned int flags; diff --git a/drivers/rtc/rtc-ds1672.c b/drivers/rtc/rtc-ds1672.c index e0900ca678e..6fa4556f5f5 100644 --- a/drivers/rtc/rtc-ds1672.c +++ b/drivers/rtc/rtc-ds1672.c @@ -50,13 +50,13 @@ static int ds1672_get_datetime(struct i2c_client *client, struct rtc_time *tm) /* read date registers */ if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) { - dev_err(&client->dev, "%s: read error\n", __FUNCTION__); + dev_err(&client->dev, "%s: read error\n", __func__); return -EIO; } dev_dbg(&client->dev, "%s: raw read data - counters=%02x,%02x,%02x,%02x\n", - __FUNCTION__, buf[0], buf[1], buf[2], buf[3]); + __func__, buf[0], buf[1], buf[2], buf[3]); time = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; @@ -64,7 +64,7 @@ static int ds1672_get_datetime(struct i2c_client *client, struct rtc_time *tm) dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, " "mday=%d, mon=%d, year=%d, wday=%d\n", - __FUNCTION__, tm->tm_sec, tm->tm_min, tm->tm_hour, + __func__, tm->tm_sec, tm->tm_min, tm->tm_hour, tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); return 0; @@ -84,7 +84,7 @@ static int ds1672_set_mmss(struct i2c_client *client, unsigned long secs) xfer = i2c_master_send(client, buf, 6); if (xfer != 6) { - dev_err(&client->dev, "%s: send: %d\n", __FUNCTION__, xfer); + dev_err(&client->dev, "%s: send: %d\n", __func__, xfer); return -EIO; } @@ -98,7 +98,7 @@ static int ds1672_set_datetime(struct i2c_client *client, struct rtc_time *tm) dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, " "mday=%d, mon=%d, year=%d, wday=%d\n", - __FUNCTION__, + __func__, tm->tm_sec, tm->tm_min, tm->tm_hour, tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); @@ -133,7 +133,7 @@ static int ds1672_get_control(struct i2c_client *client, u8 *status) /* read control register */ if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) { - dev_err(&client->dev, "%s: read error\n", __FUNCTION__); + dev_err(&client->dev, "%s: read error\n", __func__); return -EIO; } @@ -199,7 +199,7 @@ static int ds1672_probe(struct i2c_adapter *adapter, int address, int kind) struct i2c_client *client; struct rtc_device *rtc; - dev_dbg(&adapter->dev, "%s\n", __FUNCTION__); + dev_dbg(&adapter->dev, "%s\n", __func__); if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { err = -ENODEV; diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c index 725b0c73c33..fbb90b1e409 100644 --- a/drivers/rtc/rtc-isl1208.c +++ b/drivers/rtc/rtc-isl1208.c @@ -15,16 +15,15 @@ #include <linux/bcd.h> #include <linux/rtc.h> -#define DRV_NAME "isl1208" -#define DRV_VERSION "0.2" +#define DRV_VERSION "0.3" /* Register map */ /* rtc section */ #define ISL1208_REG_SC 0x00 #define ISL1208_REG_MN 0x01 #define ISL1208_REG_HR 0x02 -#define ISL1208_REG_HR_MIL (1<<7) /* 24h/12h mode */ -#define ISL1208_REG_HR_PM (1<<5) /* PM/AM bit in 12h mode */ +#define ISL1208_REG_HR_MIL (1<<7) /* 24h/12h mode */ +#define ISL1208_REG_HR_PM (1<<5) /* PM/AM bit in 12h mode */ #define ISL1208_REG_DT 0x03 #define ISL1208_REG_MO 0x04 #define ISL1208_REG_YR 0x05 @@ -33,14 +32,14 @@ /* control/status section */ #define ISL1208_REG_SR 0x07 -#define ISL1208_REG_SR_ARST (1<<7) /* auto reset */ -#define ISL1208_REG_SR_XTOSCB (1<<6) /* crystal oscillator */ -#define ISL1208_REG_SR_WRTC (1<<4) /* write rtc */ -#define ISL1208_REG_SR_ALM (1<<2) /* alarm */ -#define ISL1208_REG_SR_BAT (1<<1) /* battery */ -#define ISL1208_REG_SR_RTCF (1<<0) /* rtc fail */ +#define ISL1208_REG_SR_ARST (1<<7) /* auto reset */ +#define ISL1208_REG_SR_XTOSCB (1<<6) /* crystal oscillator */ +#define ISL1208_REG_SR_WRTC (1<<4) /* write rtc */ +#define ISL1208_REG_SR_ALM (1<<2) /* alarm */ +#define ISL1208_REG_SR_BAT (1<<1) /* battery */ +#define ISL1208_REG_SR_RTCF (1<<0) /* rtc fail */ #define ISL1208_REG_INT 0x08 -#define ISL1208_REG_09 0x09 /* reserved */ +#define ISL1208_REG_09 0x09 /* reserved */ #define ISL1208_REG_ATR 0x0a #define ISL1208_REG_DTR 0x0b @@ -58,39 +57,21 @@ #define ISL1208_REG_USR2 0x13 #define ISL1208_USR_SECTION_LEN 2 -/* i2c configuration */ -#define ISL1208_I2C_ADDR 0xde - -static const unsigned short normal_i2c[] = { - ISL1208_I2C_ADDR>>1, I2C_CLIENT_END -}; -I2C_CLIENT_INSMOD; /* defines addr_data */ - -static int isl1208_attach_adapter(struct i2c_adapter *adapter); -static int isl1208_detach_client(struct i2c_client *client); - -static struct i2c_driver isl1208_driver = { - .driver = { - .name = DRV_NAME, - }, - .id = I2C_DRIVERID_ISL1208, - .attach_adapter = &isl1208_attach_adapter, - .detach_client = &isl1208_detach_client, -}; +static struct i2c_driver isl1208_driver; /* block read */ static int isl1208_i2c_read_regs(struct i2c_client *client, u8 reg, u8 buf[], - unsigned len) + unsigned len) { u8 reg_addr[1] = { reg }; struct i2c_msg msgs[2] = { - { client->addr, client->flags, sizeof(reg_addr), reg_addr }, - { client->addr, client->flags | I2C_M_RD, len, buf } + {client->addr, 0, sizeof(reg_addr), reg_addr} + , + {client->addr, I2C_M_RD, len, buf} }; int ret; - BUG_ON(len == 0); BUG_ON(reg > ISL1208_REG_USR2); BUG_ON(reg + len > ISL1208_REG_USR2 + 1); @@ -103,15 +84,14 @@ isl1208_i2c_read_regs(struct i2c_client *client, u8 reg, u8 buf[], /* block write */ static int isl1208_i2c_set_regs(struct i2c_client *client, u8 reg, u8 const buf[], - unsigned len) + unsigned len) { u8 i2c_buf[ISL1208_REG_USR2 + 2]; struct i2c_msg msgs[1] = { - { client->addr, client->flags, len + 1, i2c_buf } + {client->addr, 0, len + 1, i2c_buf} }; int ret; - BUG_ON(len == 0); BUG_ON(reg > ISL1208_REG_USR2); BUG_ON(reg + len > ISL1208_REG_USR2 + 1); @@ -125,7 +105,8 @@ isl1208_i2c_set_regs(struct i2c_client *client, u8 reg, u8 const buf[], } /* simple check to see wether we have a isl1208 */ -static int isl1208_i2c_validate_client(struct i2c_client *client) +static int +isl1208_i2c_validate_client(struct i2c_client *client) { u8 regs[ISL1208_RTC_SECTION_LEN] = { 0, }; u8 zero_mask[ISL1208_RTC_SECTION_LEN] = { @@ -139,24 +120,29 @@ static int isl1208_i2c_validate_client(struct i2c_client *client) return ret; for (i = 0; i < ISL1208_RTC_SECTION_LEN; ++i) { - if (regs[i] & zero_mask[i]) /* check if bits are cleared */ + if (regs[i] & zero_mask[i]) /* check if bits are cleared */ return -ENODEV; } return 0; } -static int isl1208_i2c_get_sr(struct i2c_client *client) +static int +isl1208_i2c_get_sr(struct i2c_client *client) { - return i2c_smbus_read_byte_data(client, ISL1208_REG_SR) == -1 ? -EIO:0; + int sr = i2c_smbus_read_byte_data(client, ISL1208_REG_SR); + if (sr < 0) + return -EIO; + + return sr; } -static int isl1208_i2c_get_atr(struct i2c_client *client) +static int +isl1208_i2c_get_atr(struct i2c_client *client) { int atr = i2c_smbus_read_byte_data(client, ISL1208_REG_ATR); - if (atr < 0) - return -EIO; + return atr; /* The 6bit value in the ATR register controls the load * capacitance C_load * in steps of 0.25pF @@ -169,51 +155,54 @@ static int isl1208_i2c_get_atr(struct i2c_client *client) * */ - atr &= 0x3f; /* mask out lsb */ - atr ^= 1<<5; /* invert 6th bit */ - atr += 2*9; /* add offset of 4.5pF; unit[atr] = 0.25pF */ + atr &= 0x3f; /* mask out lsb */ + atr ^= 1 << 5; /* invert 6th bit */ + atr += 2 * 9; /* add offset of 4.5pF; unit[atr] = 0.25pF */ return atr; } -static int isl1208_i2c_get_dtr(struct i2c_client *client) +static int +isl1208_i2c_get_dtr(struct i2c_client *client) { int dtr = i2c_smbus_read_byte_data(client, ISL1208_REG_DTR); - if (dtr < 0) return -EIO; /* dtr encodes adjustments of {-60,-40,-20,0,20,40,60} ppm */ - dtr = ((dtr & 0x3) * 20) * (dtr & (1<<2) ? -1 : 1); + dtr = ((dtr & 0x3) * 20) * (dtr & (1 << 2) ? -1 : 1); return dtr; } -static int isl1208_i2c_get_usr(struct i2c_client *client) +static int +isl1208_i2c_get_usr(struct i2c_client *client) { u8 buf[ISL1208_USR_SECTION_LEN] = { 0, }; int ret; - ret = isl1208_i2c_read_regs (client, ISL1208_REG_USR1, buf, - ISL1208_USR_SECTION_LEN); + ret = isl1208_i2c_read_regs(client, ISL1208_REG_USR1, buf, + ISL1208_USR_SECTION_LEN); if (ret < 0) return ret; return (buf[1] << 8) | buf[0]; } -static int isl1208_i2c_set_usr(struct i2c_client *client, u16 usr) +static int +isl1208_i2c_set_usr(struct i2c_client *client, u16 usr) { u8 buf[ISL1208_USR_SECTION_LEN]; buf[0] = usr & 0xff; buf[1] = (usr >> 8) & 0xff; - return isl1208_i2c_set_regs (client, ISL1208_REG_USR1, buf, - ISL1208_USR_SECTION_LEN); + return isl1208_i2c_set_regs(client, ISL1208_REG_USR1, buf, + ISL1208_USR_SECTION_LEN); } -static int isl1208_rtc_proc(struct device *dev, struct seq_file *seq) +static int +isl1208_rtc_proc(struct device *dev, struct seq_file *seq) { struct i2c_client *const client = to_i2c_client(dev); int sr, dtr, atr, usr; @@ -230,20 +219,19 @@ static int isl1208_rtc_proc(struct device *dev, struct seq_file *seq) (sr & ISL1208_REG_SR_ALM) ? " ALM" : "", (sr & ISL1208_REG_SR_WRTC) ? " WRTC" : "", (sr & ISL1208_REG_SR_XTOSCB) ? " XTOSCB" : "", - (sr & ISL1208_REG_SR_ARST) ? " ARST" : "", - sr); + (sr & ISL1208_REG_SR_ARST) ? " ARST" : "", sr); seq_printf(seq, "batt_status\t: %s\n", (sr & ISL1208_REG_SR_RTCF) ? "bad" : "okay"); dtr = isl1208_i2c_get_dtr(client); - if (dtr >= 0 -1) + if (dtr >= 0 - 1) seq_printf(seq, "digital_trim\t: %d ppm\n", dtr); atr = isl1208_i2c_get_atr(client); if (atr >= 0) seq_printf(seq, "analog_trim\t: %d.%.2d pF\n", - atr>>2, (atr&0x3)*25); + atr >> 2, (atr & 0x3) * 25); usr = isl1208_i2c_get_usr(client); if (usr >= 0) @@ -252,9 +240,8 @@ static int isl1208_rtc_proc(struct device *dev, struct seq_file *seq) return 0; } - -static int isl1208_i2c_read_time(struct i2c_client *client, - struct rtc_time *tm) +static int +isl1208_i2c_read_time(struct i2c_client *client, struct rtc_time *tm) { int sr; u8 regs[ISL1208_RTC_SECTION_LEN] = { 0, }; @@ -274,27 +261,30 @@ static int isl1208_i2c_read_time(struct i2c_client *client, tm->tm_sec = BCD2BIN(regs[ISL1208_REG_SC]); tm->tm_min = BCD2BIN(regs[ISL1208_REG_MN]); - { /* HR field has a more complex interpretation */ + + /* HR field has a more complex interpretation */ + { const u8 _hr = regs[ISL1208_REG_HR]; - if (_hr & ISL1208_REG_HR_MIL) /* 24h format */ + if (_hr & ISL1208_REG_HR_MIL) /* 24h format */ tm->tm_hour = BCD2BIN(_hr & 0x3f); - else { // 12h format + else { + /* 12h format */ tm->tm_hour = BCD2BIN(_hr & 0x1f); - if (_hr & ISL1208_REG_HR_PM) /* PM flag set */ + if (_hr & ISL1208_REG_HR_PM) /* PM flag set */ tm->tm_hour += 12; } } tm->tm_mday = BCD2BIN(regs[ISL1208_REG_DT]); - tm->tm_mon = BCD2BIN(regs[ISL1208_REG_MO]) - 1; /* rtc starts at 1 */ + tm->tm_mon = BCD2BIN(regs[ISL1208_REG_MO]) - 1; /* rtc starts at 1 */ tm->tm_year = BCD2BIN(regs[ISL1208_REG_YR]) + 100; tm->tm_wday = BCD2BIN(regs[ISL1208_REG_DW]); return 0; } -static int isl1208_i2c_read_alarm(struct i2c_client *client, - struct rtc_wkalrm *alarm) +static int +isl1208_i2c_read_alarm(struct i2c_client *client, struct rtc_wkalrm *alarm) { struct rtc_time *const tm = &alarm->time; u8 regs[ISL1208_ALARM_SECTION_LEN] = { 0, }; @@ -307,7 +297,7 @@ static int isl1208_i2c_read_alarm(struct i2c_client *client, } sr = isl1208_i2c_read_regs(client, ISL1208_REG_SCA, regs, - ISL1208_ALARM_SECTION_LEN); + ISL1208_ALARM_SECTION_LEN); if (sr < 0) { dev_err(&client->dev, "%s: reading alarm section failed\n", __func__); @@ -315,23 +305,25 @@ static int isl1208_i2c_read_alarm(struct i2c_client *client, } /* MSB of each alarm register is an enable bit */ - tm->tm_sec = BCD2BIN(regs[ISL1208_REG_SCA-ISL1208_REG_SCA] & 0x7f); - tm->tm_min = BCD2BIN(regs[ISL1208_REG_MNA-ISL1208_REG_SCA] & 0x7f); - tm->tm_hour = BCD2BIN(regs[ISL1208_REG_HRA-ISL1208_REG_SCA] & 0x3f); - tm->tm_mday = BCD2BIN(regs[ISL1208_REG_DTA-ISL1208_REG_SCA] & 0x3f); - tm->tm_mon = BCD2BIN(regs[ISL1208_REG_MOA-ISL1208_REG_SCA] & 0x1f)-1; - tm->tm_wday = BCD2BIN(regs[ISL1208_REG_DWA-ISL1208_REG_SCA] & 0x03); + tm->tm_sec = BCD2BIN(regs[ISL1208_REG_SCA - ISL1208_REG_SCA] & 0x7f); + tm->tm_min = BCD2BIN(regs[ISL1208_REG_MNA - ISL1208_REG_SCA] & 0x7f); + tm->tm_hour = BCD2BIN(regs[ISL1208_REG_HRA - ISL1208_REG_SCA] & 0x3f); + tm->tm_mday = BCD2BIN(regs[ISL1208_REG_DTA - ISL1208_REG_SCA] & 0x3f); + tm->tm_mon = + BCD2BIN(regs[ISL1208_REG_MOA - ISL1208_REG_SCA] & 0x1f) - 1; + tm->tm_wday = BCD2BIN(regs[ISL1208_REG_DWA - ISL1208_REG_SCA] & 0x03); return 0; } -static int isl1208_rtc_read_time(struct device *dev, struct rtc_time *tm) +static int +isl1208_rtc_read_time(struct device *dev, struct rtc_time *tm) { return isl1208_i2c_read_time(to_i2c_client(dev), tm); } -static int isl1208_i2c_set_time(struct i2c_client *client, - struct rtc_time const *tm) +static int +isl1208_i2c_set_time(struct i2c_client *client, struct rtc_time const *tm) { int sr; u8 regs[ISL1208_RTC_SECTION_LEN] = { 0, }; @@ -353,7 +345,7 @@ static int isl1208_i2c_set_time(struct i2c_client *client, } /* set WRTC */ - sr = i2c_smbus_write_byte_data (client, ISL1208_REG_SR, + sr = i2c_smbus_write_byte_data(client, ISL1208_REG_SR, sr | ISL1208_REG_SR_WRTC); if (sr < 0) { dev_err(&client->dev, "%s: writing SR failed\n", __func__); @@ -369,7 +361,7 @@ static int isl1208_i2c_set_time(struct i2c_client *client, } /* clear WRTC again */ - sr = i2c_smbus_write_byte_data (client, ISL1208_REG_SR, + sr = i2c_smbus_write_byte_data(client, ISL1208_REG_SR, sr & ~ISL1208_REG_SR_WRTC); if (sr < 0) { dev_err(&client->dev, "%s: writing SR failed\n", __func__); @@ -380,70 +372,69 @@ static int isl1208_i2c_set_time(struct i2c_client *client, } -static int isl1208_rtc_set_time(struct device *dev, struct rtc_time *tm) +static int +isl1208_rtc_set_time(struct device *dev, struct rtc_time *tm) { return isl1208_i2c_set_time(to_i2c_client(dev), tm); } -static int isl1208_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) +static int +isl1208_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) { return isl1208_i2c_read_alarm(to_i2c_client(dev), alarm); } static const struct rtc_class_ops isl1208_rtc_ops = { - .proc = isl1208_rtc_proc, - .read_time = isl1208_rtc_read_time, - .set_time = isl1208_rtc_set_time, - .read_alarm = isl1208_rtc_read_alarm, - //.set_alarm = isl1208_rtc_set_alarm, + .proc = isl1208_rtc_proc, + .read_time = isl1208_rtc_read_time, + .set_time = isl1208_rtc_set_time, + .read_alarm = isl1208_rtc_read_alarm, + /*.set_alarm = isl1208_rtc_set_alarm, */ }; /* sysfs interface */ -static ssize_t isl1208_sysfs_show_atrim(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t +isl1208_sysfs_show_atrim(struct device *dev, + struct device_attribute *attr, char *buf) { - int atr; - - atr = isl1208_i2c_get_atr(to_i2c_client(dev)); + int atr = isl1208_i2c_get_atr(to_i2c_client(dev)); if (atr < 0) return atr; - return sprintf(buf, "%d.%.2d pF\n", atr>>2, (atr&0x3)*25); + return sprintf(buf, "%d.%.2d pF\n", atr >> 2, (atr & 0x3) * 25); } + static DEVICE_ATTR(atrim, S_IRUGO, isl1208_sysfs_show_atrim, NULL); -static ssize_t isl1208_sysfs_show_dtrim(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t +isl1208_sysfs_show_dtrim(struct device *dev, + struct device_attribute *attr, char *buf) { - int dtr; - - dtr = isl1208_i2c_get_dtr(to_i2c_client(dev)); + int dtr = isl1208_i2c_get_dtr(to_i2c_client(dev)); if (dtr < 0) return dtr; return sprintf(buf, "%d ppm\n", dtr); } + static DEVICE_ATTR(dtrim, S_IRUGO, isl1208_sysfs_show_dtrim, NULL); -static ssize_t isl1208_sysfs_show_usr(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t +isl1208_sysfs_show_usr(struct device *dev, + struct device_attribute *attr, char *buf) { - int usr; - - usr = isl1208_i2c_get_usr(to_i2c_client(dev)); + int usr = isl1208_i2c_get_usr(to_i2c_client(dev)); if (usr < 0) return usr; return sprintf(buf, "0x%.4x\n", usr); } -static ssize_t isl1208_sysfs_store_usr(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t +isl1208_sysfs_store_usr(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { int usr = -1; @@ -460,124 +451,123 @@ static ssize_t isl1208_sysfs_store_usr(struct device *dev, return isl1208_i2c_set_usr(to_i2c_client(dev), usr) ? -EIO : count; } + static DEVICE_ATTR(usr, S_IRUGO | S_IWUSR, isl1208_sysfs_show_usr, isl1208_sysfs_store_usr); static int -isl1208_probe(struct i2c_adapter *adapter, int addr, int kind) +isl1208_sysfs_register(struct device *dev) { - int rc = 0; - struct i2c_client *new_client = NULL; - struct rtc_device *rtc = NULL; + int err; - if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { - rc = -ENODEV; - goto failout; + err = device_create_file(dev, &dev_attr_atrim); + if (err) + return err; + + err = device_create_file(dev, &dev_attr_dtrim); + if (err) { + device_remove_file(dev, &dev_attr_atrim); + return err; } - new_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (new_client == NULL) { - rc = -ENOMEM; - goto failout; + err = device_create_file(dev, &dev_attr_usr); + if (err) { + device_remove_file(dev, &dev_attr_atrim); + device_remove_file(dev, &dev_attr_dtrim); } - new_client->addr = addr; - new_client->adapter = adapter; - new_client->driver = &isl1208_driver; - new_client->flags = 0; - strcpy(new_client->name, DRV_NAME); + return 0; +} - if (kind < 0) { - rc = isl1208_i2c_validate_client(new_client); - if (rc < 0) - goto failout; - } +static int +isl1208_sysfs_unregister(struct device *dev) +{ + device_remove_file(dev, &dev_attr_atrim); + device_remove_file(dev, &dev_attr_atrim); + device_remove_file(dev, &dev_attr_usr); + + return 0; +} + +static int +isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + int rc = 0; + struct rtc_device *rtc; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + return -ENODEV; - rc = i2c_attach_client(new_client); - if (rc < 0) - goto failout; + if (isl1208_i2c_validate_client(client) < 0) + return -ENODEV; - dev_info(&new_client->dev, + dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n"); rtc = rtc_device_register(isl1208_driver.driver.name, - &new_client->dev, - &isl1208_rtc_ops, THIS_MODULE); + &client->dev, &isl1208_rtc_ops, + THIS_MODULE); + if (IS_ERR(rtc)) + return PTR_ERR(rtc); - if (IS_ERR(rtc)) { - rc = PTR_ERR(rtc); - goto failout_detach; - } - - i2c_set_clientdata(new_client, rtc); + i2c_set_clientdata(client, rtc); - rc = isl1208_i2c_get_sr(new_client); + rc = isl1208_i2c_get_sr(client); if (rc < 0) { - dev_err(&new_client->dev, "reading status failed\n"); - goto failout_unregister; + dev_err(&client->dev, "reading status failed\n"); + goto exit_unregister; } if (rc & ISL1208_REG_SR_RTCF) - dev_warn(&new_client->dev, "rtc power failure detected, " + dev_warn(&client->dev, "rtc power failure detected, " "please set clock.\n"); - rc = device_create_file(&new_client->dev, &dev_attr_atrim); - if (rc < 0) - goto failout_unregister; - rc = device_create_file(&new_client->dev, &dev_attr_dtrim); - if (rc < 0) - goto failout_atrim; - rc = device_create_file(&new_client->dev, &dev_attr_usr); - if (rc < 0) - goto failout_dtrim; + rc = isl1208_sysfs_register(&client->dev); + if (rc) + goto exit_unregister; return 0; - failout_dtrim: - device_remove_file(&new_client->dev, &dev_attr_dtrim); - failout_atrim: - device_remove_file(&new_client->dev, &dev_attr_atrim); - failout_unregister: +exit_unregister: rtc_device_unregister(rtc); - failout_detach: - i2c_detach_client(new_client); - failout: - kfree(new_client); - return rc; -} -static int -isl1208_attach_adapter (struct i2c_adapter *adapter) -{ - return i2c_probe(adapter, &addr_data, isl1208_probe); + return rc; } static int -isl1208_detach_client(struct i2c_client *client) +isl1208_remove(struct i2c_client *client) { - int rc; - struct rtc_device *const rtc = i2c_get_clientdata(client); + struct rtc_device *rtc = i2c_get_clientdata(client); - if (rtc) - rtc_device_unregister(rtc); /* do we need to kfree? */ - - rc = i2c_detach_client(client); - if (rc) - return rc; - - kfree(client); + isl1208_sysfs_unregister(&client->dev); + rtc_device_unregister(rtc); return 0; } -/* module management */ +static const struct i2c_device_id isl1208_id[] = { + { "isl1208", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, isl1208_id); + +static struct i2c_driver isl1208_driver = { + .driver = { + .name = "rtc-isl1208", + }, + .probe = isl1208_probe, + .remove = isl1208_remove, + .id_table = isl1208_id, +}; -static int __init isl1208_init(void) +static int __init +isl1208_init(void) { return i2c_add_driver(&isl1208_driver); } -static void __exit isl1208_exit(void) +static void __exit +isl1208_exit(void) { i2c_del_driver(&isl1208_driver); } diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c index 1cb33cac123..316bfaa8087 100644 --- a/drivers/rtc/rtc-m41t80.c +++ b/drivers/rtc/rtc-m41t80.c @@ -60,48 +60,21 @@ #define DRV_VERSION "0.05" -struct m41t80_chip_info { - const char *name; - u8 features; -}; - -static const struct m41t80_chip_info m41t80_chip_info_tbl[] = { - { - .name = "m41t80", - .features = 0, - }, - { - .name = "m41t81", - .features = M41T80_FEATURE_HT, - }, - { - .name = "m41t81s", - .features = M41T80_FEATURE_HT | M41T80_FEATURE_BL, - }, - { - .name = "m41t82", - .features = M41T80_FEATURE_HT | M41T80_FEATURE_BL, - }, - { - .name = "m41t83", - .features = M41T80_FEATURE_HT | M41T80_FEATURE_BL, - }, - { - .name = "m41st84", - .features = M41T80_FEATURE_HT | M41T80_FEATURE_BL, - }, - { - .name = "m41st85", - .features = M41T80_FEATURE_HT | M41T80_FEATURE_BL, - }, - { - .name = "m41st87", - .features = M41T80_FEATURE_HT | M41T80_FEATURE_BL, - }, +static const struct i2c_device_id m41t80_id[] = { + { "m41t80", 0 }, + { "m41t81", M41T80_FEATURE_HT }, + { "m41t81s", M41T80_FEATURE_HT | M41T80_FEATURE_BL }, + { "m41t82", M41T80_FEATURE_HT | M41T80_FEATURE_BL }, + { "m41t83", M41T80_FEATURE_HT | M41T80_FEATURE_BL }, + { "m41st84", M41T80_FEATURE_HT | M41T80_FEATURE_BL }, + { "m41st85", M41T80_FEATURE_HT | M41T80_FEATURE_BL }, + { "m41st87", M41T80_FEATURE_HT | M41T80_FEATURE_BL }, + { } }; +MODULE_DEVICE_TABLE(i2c, m41t80_id); struct m41t80_data { - const struct m41t80_chip_info *chip; + u8 features; struct rtc_device *rtc; }; @@ -208,7 +181,7 @@ static int m41t80_rtc_proc(struct device *dev, struct seq_file *seq) struct m41t80_data *clientdata = i2c_get_clientdata(client); u8 reg; - if (clientdata->chip->features & M41T80_FEATURE_BL) { + if (clientdata->features & M41T80_FEATURE_BL) { reg = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS); seq_printf(seq, "battery\t\t: %s\n", (reg & M41T80_FLAGS_BATT_LOW) ? "exhausted" : "ok"); @@ -756,12 +729,12 @@ static struct notifier_block wdt_notifier = { * ***************************************************************************** */ -static int m41t80_probe(struct i2c_client *client) +static int m41t80_probe(struct i2c_client *client, + const struct i2c_device_id *id) { - int i, rc = 0; + int rc = 0; struct rtc_device *rtc = NULL; struct rtc_time tm; - const struct m41t80_chip_info *chip; struct m41t80_data *clientdata = NULL; if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C @@ -773,19 +746,6 @@ static int m41t80_probe(struct i2c_client *client) dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n"); - chip = NULL; - for (i = 0; i < ARRAY_SIZE(m41t80_chip_info_tbl); i++) { - if (!strcmp(m41t80_chip_info_tbl[i].name, client->name)) { - chip = &m41t80_chip_info_tbl[i]; - break; - } - } - if (!chip) { - dev_err(&client->dev, "%s is not supported\n", client->name); - rc = -ENODEV; - goto exit; - } - clientdata = kzalloc(sizeof(*clientdata), GFP_KERNEL); if (!clientdata) { rc = -ENOMEM; @@ -801,7 +761,7 @@ static int m41t80_probe(struct i2c_client *client) } clientdata->rtc = rtc; - clientdata->chip = chip; + clientdata->features = id->driver_data; i2c_set_clientdata(client, clientdata); /* Make sure HT (Halt Update) bit is cleared */ @@ -810,7 +770,7 @@ static int m41t80_probe(struct i2c_client *client) goto ht_err; if (rc & M41T80_ALHOUR_HT) { - if (chip->features & M41T80_FEATURE_HT) { + if (clientdata->features & M41T80_FEATURE_HT) { m41t80_get_datetime(client, &tm); dev_info(&client->dev, "HT bit was set!\n"); dev_info(&client->dev, @@ -842,7 +802,7 @@ static int m41t80_probe(struct i2c_client *client) goto exit; #ifdef CONFIG_RTC_DRV_M41T80_WDT - if (chip->features & M41T80_FEATURE_HT) { + if (clientdata->features & M41T80_FEATURE_HT) { rc = misc_register(&wdt_dev); if (rc) goto exit; @@ -878,7 +838,7 @@ static int m41t80_remove(struct i2c_client *client) struct rtc_device *rtc = clientdata->rtc; #ifdef CONFIG_RTC_DRV_M41T80_WDT - if (clientdata->chip->features & M41T80_FEATURE_HT) { + if (clientdata->features & M41T80_FEATURE_HT) { misc_deregister(&wdt_dev); unregister_reboot_notifier(&wdt_notifier); } @@ -896,6 +856,7 @@ static struct i2c_driver m41t80_driver = { }, .probe = m41t80_probe, .remove = m41t80_remove, + .id_table = m41t80_id, }; static int __init m41t80_rtc_init(void) diff --git a/drivers/rtc/rtc-max6900.c b/drivers/rtc/rtc-max6900.c index 7683412970c..ded3c0abad8 100644 --- a/drivers/rtc/rtc-max6900.c +++ b/drivers/rtc/rtc-max6900.c @@ -98,7 +98,7 @@ static int max6900_i2c_read_regs(struct i2c_client *client, u8 *buf) rc = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); if (rc != ARRAY_SIZE(msgs)) { dev_err(&client->dev, "%s: register read failed\n", - __FUNCTION__); + __func__); return -EIO; } return 0; @@ -150,7 +150,7 @@ static int max6900_i2c_write_regs(struct i2c_client *client, u8 const *buf) write_failed: dev_err(&client->dev, "%s: register write failed\n", - __FUNCTION__); + __func__); return -EIO; } @@ -214,7 +214,7 @@ static int max6900_i2c_clear_write_protect(struct i2c_client *client) rc = i2c_smbus_write_byte_data (client, MAX6900_REG_CONTROL_WRITE, 0); if (rc < 0) { dev_err(&client->dev, "%s: control register write failed\n", - __FUNCTION__); + __func__); return -EIO; } return 0; diff --git a/drivers/rtc/rtc-max6902.c b/drivers/rtc/rtc-max6902.c index 1f956dc5d56..12f0310ae89 100644 --- a/drivers/rtc/rtc-max6902.c +++ b/drivers/rtc/rtc-max6902.c @@ -140,7 +140,7 @@ static int max6902_get_datetime(struct device *dev, struct rtc_time *dt) dt->tm_year -= 1900; #ifdef MAX6902_DEBUG - printk("\n%s : Read RTC values\n",__FUNCTION__); + printk("\n%s : Read RTC values\n",__func__); printk("tm_hour: %i\n",dt->tm_hour); printk("tm_min : %i\n",dt->tm_min); printk("tm_sec : %i\n",dt->tm_sec); @@ -158,7 +158,7 @@ static int max6902_set_datetime(struct device *dev, struct rtc_time *dt) dt->tm_year = dt->tm_year+1900; #ifdef MAX6902_DEBUG - printk("\n%s : Setting RTC values\n",__FUNCTION__); + printk("\n%s : Setting RTC values\n",__func__); printk("tm_sec : %i\n",dt->tm_sec); printk("tm_min : %i\n",dt->tm_min); printk("tm_hour: %i\n",dt->tm_hour); diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c index b3317fcc16c..0fc4c363078 100644 --- a/drivers/rtc/rtc-pcf8563.c +++ b/drivers/rtc/rtc-pcf8563.c @@ -18,17 +18,7 @@ #include <linux/bcd.h> #include <linux/rtc.h> -#define DRV_VERSION "0.4.2" - -/* Addresses to scan: none - * This chip cannot be reliably autodetected. An empty eeprom - * located at 0x51 will pass the validation routine due to - * the way the registers are implemented. - */ -static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; - -/* Module parameters */ -I2C_CLIENT_INSMOD; +#define DRV_VERSION "0.4.3" #define PCF8563_REG_ST1 0x00 /* status */ #define PCF8563_REG_ST2 0x01 @@ -53,8 +43,10 @@ I2C_CLIENT_INSMOD; #define PCF8563_SC_LV 0x80 /* low voltage */ #define PCF8563_MO_C 0x80 /* century */ +static struct i2c_driver pcf8563_driver; + struct pcf8563 { - struct i2c_client client; + struct rtc_device *rtc; /* * The meaning of MO_C bit varies by the chip type. * From PCF8563 datasheet: this bit is toggled when the years @@ -72,16 +64,13 @@ struct pcf8563 { int c_polarity; /* 0: MO_C=1 means 19xx, otherwise MO_C=1 means 20xx */ }; -static int pcf8563_probe(struct i2c_adapter *adapter, int address, int kind); -static int pcf8563_detach(struct i2c_client *client); - /* * In the routines that deal directly with the pcf8563 hardware, we use * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch. */ static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm) { - struct pcf8563 *pcf8563 = container_of(client, struct pcf8563, client); + struct pcf8563 *pcf8563 = i2c_get_clientdata(client); unsigned char buf[13] = { PCF8563_REG_ST1 }; struct i2c_msg msgs[] = { @@ -91,7 +80,7 @@ static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm) /* read registers */ if ((i2c_transfer(client->adapter, msgs, 2)) != 2) { - dev_err(&client->dev, "%s: read error\n", __FUNCTION__); + dev_err(&client->dev, "%s: read error\n", __func__); return -EIO; } @@ -102,7 +91,7 @@ static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm) dev_dbg(&client->dev, "%s: raw data is st1=%02x, st2=%02x, sec=%02x, min=%02x, hr=%02x, " "mday=%02x, wday=%02x, mon=%02x, year=%02x\n", - __FUNCTION__, + __func__, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8]); @@ -123,7 +112,7 @@ static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm) dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, " "mday=%d, mon=%d, year=%d, wday=%d\n", - __FUNCTION__, + __func__, tm->tm_sec, tm->tm_min, tm->tm_hour, tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); @@ -138,13 +127,13 @@ static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm) static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm) { - struct pcf8563 *pcf8563 = container_of(client, struct pcf8563, client); + struct pcf8563 *pcf8563 = i2c_get_clientdata(client); int i, err; unsigned char buf[9]; dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, " "mday=%d, mon=%d, year=%d, wday=%d\n", - __FUNCTION__, + __func__, tm->tm_sec, tm->tm_min, tm->tm_hour, tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); @@ -174,7 +163,7 @@ static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm) if (err != sizeof(data)) { dev_err(&client->dev, "%s: err=%d addr=%02x, data=%02x\n", - __FUNCTION__, err, data[0], data[1]); + __func__, err, data[0], data[1]); return -EIO; } }; @@ -219,7 +208,7 @@ static int pcf8563_validate_client(struct i2c_client *client) if (xfer != ARRAY_SIZE(msgs)) { dev_err(&client->dev, "%s: could not read register 0x%02X\n", - __FUNCTION__, pattern[i].reg); + __func__, pattern[i].reg); return -EIO; } @@ -231,7 +220,7 @@ static int pcf8563_validate_client(struct i2c_client *client) dev_dbg(&client->dev, "%s: pattern=%d, reg=%x, mask=0x%02x, min=%d, " "max=%d, value=%d, raw=0x%02X\n", - __FUNCTION__, i, pattern[i].reg, pattern[i].mask, + __func__, i, pattern[i].reg, pattern[i].mask, pattern[i].min, pattern[i].max, value, buf); @@ -257,100 +246,75 @@ static const struct rtc_class_ops pcf8563_rtc_ops = { .set_time = pcf8563_rtc_set_time, }; -static int pcf8563_attach(struct i2c_adapter *adapter) -{ - return i2c_probe(adapter, &addr_data, pcf8563_probe); -} - -static struct i2c_driver pcf8563_driver = { - .driver = { - .name = "pcf8563", - }, - .id = I2C_DRIVERID_PCF8563, - .attach_adapter = &pcf8563_attach, - .detach_client = &pcf8563_detach, -}; - -static int pcf8563_probe(struct i2c_adapter *adapter, int address, int kind) +static int pcf8563_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct pcf8563 *pcf8563; - struct i2c_client *client; - struct rtc_device *rtc; int err = 0; - dev_dbg(&adapter->dev, "%s\n", __FUNCTION__); + dev_dbg(&client->dev, "%s\n", __func__); - if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { - err = -ENODEV; - goto exit; - } + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + return -ENODEV; - if (!(pcf8563 = kzalloc(sizeof(struct pcf8563), GFP_KERNEL))) { - err = -ENOMEM; - goto exit; - } - - client = &pcf8563->client; - client->addr = address; - client->driver = &pcf8563_driver; - client->adapter = adapter; - - strlcpy(client->name, pcf8563_driver.driver.name, I2C_NAME_SIZE); + pcf8563 = kzalloc(sizeof(struct pcf8563), GFP_KERNEL); + if (!pcf8563) + return -ENOMEM; /* Verify the chip is really an PCF8563 */ - if (kind < 0) { - if (pcf8563_validate_client(client) < 0) { - err = -ENODEV; - goto exit_kfree; - } - } - - /* Inform the i2c layer */ - if ((err = i2c_attach_client(client))) + if (pcf8563_validate_client(client) < 0) { + err = -ENODEV; goto exit_kfree; + } dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n"); - rtc = rtc_device_register(pcf8563_driver.driver.name, &client->dev, - &pcf8563_rtc_ops, THIS_MODULE); + pcf8563->rtc = rtc_device_register(pcf8563_driver.driver.name, + &client->dev, &pcf8563_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) { - err = PTR_ERR(rtc); - goto exit_detach; + if (IS_ERR(pcf8563->rtc)) { + err = PTR_ERR(pcf8563->rtc); + goto exit_kfree; } - i2c_set_clientdata(client, rtc); + i2c_set_clientdata(client, pcf8563); return 0; -exit_detach: - i2c_detach_client(client); - exit_kfree: kfree(pcf8563); -exit: return err; } -static int pcf8563_detach(struct i2c_client *client) +static int pcf8563_remove(struct i2c_client *client) { - struct pcf8563 *pcf8563 = container_of(client, struct pcf8563, client); - int err; - struct rtc_device *rtc = i2c_get_clientdata(client); + struct pcf8563 *pcf8563 = i2c_get_clientdata(client); - if (rtc) - rtc_device_unregister(rtc); - - if ((err = i2c_detach_client(client))) - return err; + if (pcf8563->rtc) + rtc_device_unregister(pcf8563->rtc); kfree(pcf8563); return 0; } +static const struct i2c_device_id pcf8563_id[] = { + { "pcf8563", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, pcf8563_id); + +static struct i2c_driver pcf8563_driver = { + .driver = { + .name = "rtc-pcf8563", + }, + .probe = pcf8563_probe, + .remove = pcf8563_remove, + .id_table = pcf8563_id, +}; + static int __init pcf8563_init(void) { return i2c_add_driver(&pcf8563_driver); diff --git a/drivers/rtc/rtc-pcf8583.c b/drivers/rtc/rtc-pcf8583.c index 8b399700750..3d09d8f0b1f 100644 --- a/drivers/rtc/rtc-pcf8583.c +++ b/drivers/rtc/rtc-pcf8583.c @@ -15,7 +15,7 @@ #include <linux/i2c.h> #include <linux/slab.h> #include <linux/string.h> -#include <linux/mc146818rtc.h> +#include <linux/rtc.h> #include <linux/init.h> #include <linux/errno.h> #include <linux/bcd.h> diff --git a/drivers/rtc/rtc-proc.c b/drivers/rtc/rtc-proc.c index 8d300e6d0d9..0c6257a034f 100644 --- a/drivers/rtc/rtc-proc.c +++ b/drivers/rtc/rtc-proc.c @@ -108,12 +108,10 @@ void rtc_proc_add_device(struct rtc_device *rtc) if (rtc->id == 0) { struct proc_dir_entry *ent; - ent = create_proc_entry("driver/rtc", 0, NULL); - if (ent) { - ent->proc_fops = &rtc_proc_fops; + ent = proc_create_data("driver/rtc", 0, NULL, + &rtc_proc_fops, rtc); + if (ent) ent->owner = rtc->owner; - ent->data = rtc; - } } } diff --git a/drivers/rtc/rtc-rs5c313.c b/drivers/rtc/rtc-rs5c313.c index 664e89a817e..1c14d4497c4 100644 --- a/drivers/rtc/rtc-rs5c313.c +++ b/drivers/rtc/rtc-rs5c313.c @@ -228,7 +228,7 @@ static int rs5c313_rtc_read_time(struct device *dev, struct rtc_time *tm) ndelay(700); /* CE:L */ if (cnt++ > 100) { - dev_err(dev, "%s: timeout error\n", __FUNCTION__); + dev_err(dev, "%s: timeout error\n", __func__); return -EIO; } } @@ -289,7 +289,7 @@ static int rs5c313_rtc_set_time(struct device *dev, struct rtc_time *tm) ndelay(700); /* CE:L */ if (cnt++ > 100) { - dev_err(dev, "%s: timeout error\n", __FUNCTION__); + dev_err(dev, "%s: timeout error\n", __func__); return -EIO; } } diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c index 6b67b509792..56caf6b2c3e 100644 --- a/drivers/rtc/rtc-rs5c372.c +++ b/drivers/rtc/rtc-rs5c372.c @@ -69,6 +69,15 @@ enum rtc_type { rtc_rv5c387a, }; +static const struct i2c_device_id rs5c372_id[] = { + { "rs5c372a", rtc_rs5c372a }, + { "rs5c372b", rtc_rs5c372b }, + { "rv5c386", rtc_rv5c386 }, + { "rv5c387a", rtc_rv5c387a }, + { } +}; +MODULE_DEVICE_TABLE(i2c, rs5c372_id); + /* REVISIT: this assumes that: * - we're in the 21st century, so it's safe to ignore the century * bit for rv5c38[67] (REG_MONTH bit 7); @@ -99,7 +108,7 @@ static int rs5c_get_regs(struct rs5c372 *rs5c) * least 80219 chips; this works around that bug. */ if ((i2c_transfer(client->adapter, msgs, 1)) != 1) { - pr_debug("%s: can't read registers\n", rs5c->rtc->name); + dev_warn(&client->dev, "can't read registers\n"); return -EIO; } @@ -166,7 +175,7 @@ static int rs5c372_get_datetime(struct i2c_client *client, struct rtc_time *tm) dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, " "mday=%d, mon=%d, year=%d, wday=%d\n", - __FUNCTION__, + __func__, tm->tm_sec, tm->tm_min, tm->tm_hour, tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); @@ -181,7 +190,7 @@ static int rs5c372_set_datetime(struct i2c_client *client, struct rtc_time *tm) dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d " "mday=%d, mon=%d, year=%d, wday=%d\n", - __FUNCTION__, + __func__, tm->tm_sec, tm->tm_min, tm->tm_hour, tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); @@ -195,7 +204,7 @@ static int rs5c372_set_datetime(struct i2c_client *client, struct rtc_time *tm) buf[7] = BIN2BCD(tm->tm_year - 100); if ((i2c_master_send(client, buf, 8)) != 8) { - dev_err(&client->dev, "%s: write error\n", __FUNCTION__); + dev_err(&client->dev, "%s: write error\n", __func__); return -EIO; } @@ -220,7 +229,7 @@ static int rs5c372_get_trim(struct i2c_client *client, int *osc, int *trim) *osc = (tmp & RS5C372_TRIM_XSL) ? 32000 : 32768; if (trim) { - dev_dbg(&client->dev, "%s: raw trim=%x\n", __FUNCTION__, tmp); + dev_dbg(&client->dev, "%s: raw trim=%x\n", __func__, tmp); tmp &= RS5C372_TRIM_MASK; if (tmp & 0x3e) { int t = tmp & 0x3f; @@ -494,13 +503,14 @@ static void rs5c_sysfs_unregister(struct device *dev) static struct i2c_driver rs5c372_driver; -static int rs5c372_probe(struct i2c_client *client) +static int rs5c372_probe(struct i2c_client *client, + const struct i2c_device_id *id) { int err = 0; struct rs5c372 *rs5c372; struct rtc_time tm; - dev_dbg(&client->dev, "%s\n", __FUNCTION__); + dev_dbg(&client->dev, "%s\n", __func__); if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { err = -ENODEV; @@ -512,29 +522,17 @@ static int rs5c372_probe(struct i2c_client *client) goto exit; } - /* we read registers 0x0f then 0x00-0x0f; skip the first one */ - rs5c372->regs=&rs5c372->buf[1]; - rs5c372->client = client; i2c_set_clientdata(client, rs5c372); + rs5c372->type = id->driver_data; + + /* we read registers 0x0f then 0x00-0x0f; skip the first one */ + rs5c372->regs = &rs5c372->buf[1]; err = rs5c_get_regs(rs5c372); if (err < 0) goto exit_kfree; - if (strcmp(client->name, "rs5c372a") == 0) - rs5c372->type = rtc_rs5c372a; - else if (strcmp(client->name, "rs5c372b") == 0) - rs5c372->type = rtc_rs5c372b; - else if (strcmp(client->name, "rv5c386") == 0) - rs5c372->type = rtc_rv5c386; - else if (strcmp(client->name, "rv5c387a") == 0) - rs5c372->type = rtc_rv5c387a; - else { - rs5c372->type = rtc_rs5c372b; - dev_warn(&client->dev, "assuming rs5c372b\n"); - } - /* clock may be set for am/pm or 24 hr time */ switch (rs5c372->type) { case rtc_rs5c372a: @@ -651,6 +649,7 @@ static struct i2c_driver rs5c372_driver = { }, .probe = rs5c372_probe, .remove = rs5c372_remove, + .id_table = rs5c372_id, }; static __init int rs5c372_init(void) diff --git a/drivers/rtc/rtc-s35390a.c b/drivers/rtc/rtc-s35390a.c index e8abc90c32c..29f47bacfc7 100644 --- a/drivers/rtc/rtc-s35390a.c +++ b/drivers/rtc/rtc-s35390a.c @@ -34,6 +34,12 @@ #define S35390A_FLAG_RESET 0x80 #define S35390A_FLAG_TEST 0x01 +static const struct i2c_device_id s35390a_id[] = { + { "s35390a", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, s35390a_id); + struct s35390a { struct i2c_client *client[8]; struct rtc_device *rtc; @@ -195,7 +201,8 @@ static const struct rtc_class_ops s35390a_rtc_ops = { static struct i2c_driver s35390a_driver; -static int s35390a_probe(struct i2c_client *client) +static int s35390a_probe(struct i2c_client *client, + const struct i2c_device_id *id) { int err; unsigned int i; @@ -296,6 +303,7 @@ static struct i2c_driver s35390a_driver = { }, .probe = s35390a_probe, .remove = s35390a_remove, + .id_table = s35390a_id, }; static int __init s35390a_rtc_init(void) diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index 9f4d5129a49..f26e0cad8f1 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -68,7 +68,7 @@ static void s3c_rtc_setaie(int to) { unsigned int tmp; - pr_debug("%s: aie=%d\n", __FUNCTION__, to); + pr_debug("%s: aie=%d\n", __func__, to); tmp = readb(s3c_rtc_base + S3C2410_RTCALM) & ~S3C2410_RTCALM_ALMEN; @@ -82,7 +82,7 @@ static void s3c_rtc_setpie(int to) { unsigned int tmp; - pr_debug("%s: pie=%d\n", __FUNCTION__, to); + pr_debug("%s: pie=%d\n", __func__, to); spin_lock_irq(&s3c_rtc_pie_lock); tmp = readb(s3c_rtc_base + S3C2410_TICNT) & ~S3C2410_TICNT_ENABLE; @@ -457,7 +457,7 @@ static int s3c_rtc_probe(struct platform_device *pdev) struct resource *res; int ret; - pr_debug("%s: probe=%p\n", __FUNCTION__, pdev); + pr_debug("%s: probe=%p\n", __func__, pdev); /* find the IRQs */ diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index c594b34c676..110699bb478 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c @@ -361,7 +361,7 @@ static int sh_rtc_read_time(struct device *dev, struct rtc_time *tm) dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, " "mday=%d, mon=%d, year=%d, wday=%d\n", - __FUNCTION__, + __func__, tm->tm_sec, tm->tm_min, tm->tm_hour, tm->tm_mday, tm->tm_mon + 1, tm->tm_year, tm->tm_wday); diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c index 4d27ccc4fc0..2531ce4c9db 100644 --- a/drivers/rtc/rtc-sysfs.c +++ b/drivers/rtc/rtc-sysfs.c @@ -145,6 +145,8 @@ rtc_sysfs_set_wakealarm(struct device *dev, struct device_attribute *attr, unsigned long now, alarm; struct rtc_wkalrm alm; struct rtc_device *rtc = to_rtc_device(dev); + char *buf_ptr; + int adjust = 0; /* Only request alarms that trigger in the future. Disable them * by writing another time, e.g. 0 meaning Jan 1 1970 UTC. @@ -154,7 +156,15 @@ rtc_sysfs_set_wakealarm(struct device *dev, struct device_attribute *attr, return retval; rtc_tm_to_time(&alm.time, &now); - alarm = simple_strtoul(buf, NULL, 0); + buf_ptr = (char *)buf; + if (*buf_ptr == '+') { + buf_ptr++; + adjust = 1; + } + alarm = simple_strtoul(buf_ptr, NULL, 0); + if (adjust) { + alarm += now; + } if (alarm > now) { /* Avoid accidentally clobbering active alarms; we can't * entirely prevent that here, without even the minimal diff --git a/drivers/rtc/rtc-test.c b/drivers/rtc/rtc-test.c index 254c9fce27d..bc930022004 100644 --- a/drivers/rtc/rtc-test.c +++ b/drivers/rtc/rtc-test.c @@ -147,7 +147,7 @@ static int __devexit test_remove(struct platform_device *plat_dev) return 0; } -static struct platform_driver test_drv = { +static struct platform_driver test_driver = { .probe = test_probe, .remove = __devexit_p(test_remove), .driver = { @@ -160,7 +160,7 @@ static int __init test_init(void) { int err; - if ((err = platform_driver_register(&test_drv))) + if ((err = platform_driver_register(&test_driver))) return err; if ((test0 = platform_device_alloc("rtc-test", 0)) == NULL) { @@ -191,7 +191,7 @@ exit_free_test0: platform_device_put(test0); exit_driver_unregister: - platform_driver_unregister(&test_drv); + platform_driver_unregister(&test_driver); return err; } @@ -199,7 +199,7 @@ static void __exit test_exit(void) { platform_device_unregister(test0); platform_device_unregister(test1); - platform_driver_unregister(&test_drv); + platform_driver_unregister(&test_driver); } MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>"); diff --git a/drivers/rtc/rtc-v3020.c b/drivers/rtc/rtc-v3020.c index 24203a06051..10025d84026 100644 --- a/drivers/rtc/rtc-v3020.c +++ b/drivers/rtc/rtc-v3020.c @@ -107,7 +107,7 @@ static int v3020_read_time(struct device *dev, struct rtc_time *dt) dt->tm_year = BCD2BIN(tmp)+100; #ifdef DEBUG - printk("\n%s : Read RTC values\n",__FUNCTION__); + printk("\n%s : Read RTC values\n",__func__); printk("tm_hour: %i\n",dt->tm_hour); printk("tm_min : %i\n",dt->tm_min); printk("tm_sec : %i\n",dt->tm_sec); @@ -126,7 +126,7 @@ static int v3020_set_time(struct device *dev, struct rtc_time *dt) struct v3020 *chip = dev_get_drvdata(dev); #ifdef DEBUG - printk("\n%s : Setting RTC values\n",__FUNCTION__); + printk("\n%s : Setting RTC values\n",__func__); printk("tm_sec : %i\n",dt->tm_sec); printk("tm_min : %i\n",dt->tm_min); printk("tm_hour: %i\n",dt->tm_hour); diff --git a/drivers/rtc/rtc-x1205.c b/drivers/rtc/rtc-x1205.c index b90fb1866ce..eaf55945f21 100644 --- a/drivers/rtc/rtc-x1205.c +++ b/drivers/rtc/rtc-x1205.c @@ -22,20 +22,7 @@ #include <linux/rtc.h> #include <linux/delay.h> -#define DRV_VERSION "1.0.7" - -/* Addresses to scan: none. This chip is located at - * 0x6f and uses a two bytes register addressing. - * Two bytes need to be written to read a single register, - * while most other chips just require one and take the second - * one as the data to be written. To prevent corrupting - * unknown chips, the user must explicitly set the probe parameter. - */ - -static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; - -/* Insmod parameters */ -I2C_CLIENT_INSMOD; +#define DRV_VERSION "1.0.8" /* offsets into CCR area */ @@ -91,19 +78,7 @@ I2C_CLIENT_INSMOD; #define X1205_HR_MIL 0x80 /* Set in ccr.hour for 24 hr mode */ -/* Prototypes */ -static int x1205_attach(struct i2c_adapter *adapter); -static int x1205_detach(struct i2c_client *client); -static int x1205_probe(struct i2c_adapter *adapter, int address, int kind); - -static struct i2c_driver x1205_driver = { - .driver = { - .name = "x1205", - }, - .id = I2C_DRIVERID_X1205, - .attach_adapter = &x1205_attach, - .detach_client = &x1205_detach, -}; +static struct i2c_driver x1205_driver; /* * In the routines that deal directly with the x1205 hardware, we use @@ -124,14 +99,14 @@ static int x1205_get_datetime(struct i2c_client *client, struct rtc_time *tm, /* read date registers */ if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) { - dev_err(&client->dev, "%s: read error\n", __FUNCTION__); + dev_err(&client->dev, "%s: read error\n", __func__); return -EIO; } dev_dbg(&client->dev, "%s: raw read data - sec=%02x, min=%02x, hr=%02x, " "mday=%02x, mon=%02x, year=%02x, wday=%02x, y2k=%02x\n", - __FUNCTION__, + __func__, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); @@ -146,7 +121,7 @@ static int x1205_get_datetime(struct i2c_client *client, struct rtc_time *tm, dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, " "mday=%d, mon=%d, year=%d, wday=%d\n", - __FUNCTION__, + __func__, tm->tm_sec, tm->tm_min, tm->tm_hour, tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); @@ -164,7 +139,7 @@ static int x1205_get_status(struct i2c_client *client, unsigned char *sr) /* read status register */ if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) { - dev_err(&client->dev, "%s: read error\n", __FUNCTION__); + dev_err(&client->dev, "%s: read error\n", __func__); return -EIO; } @@ -187,7 +162,7 @@ static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm, dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d\n", - __FUNCTION__, + __func__, tm->tm_sec, tm->tm_min, tm->tm_hour); buf[CCR_SEC] = BIN2BCD(tm->tm_sec); @@ -200,7 +175,7 @@ static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm, if (datetoo) { dev_dbg(&client->dev, "%s: mday=%d, mon=%d, year=%d, wday=%d\n", - __FUNCTION__, + __func__, tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); buf[CCR_MDAY] = BIN2BCD(tm->tm_mday); @@ -216,12 +191,12 @@ static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm, /* this sequence is required to unlock the chip */ if ((xfer = i2c_master_send(client, wel, 3)) != 3) { - dev_err(&client->dev, "%s: wel - %d\n", __FUNCTION__, xfer); + dev_err(&client->dev, "%s: wel - %d\n", __func__, xfer); return -EIO; } if ((xfer = i2c_master_send(client, rwel, 3)) != 3) { - dev_err(&client->dev, "%s: rwel - %d\n", __FUNCTION__, xfer); + dev_err(&client->dev, "%s: rwel - %d\n", __func__, xfer); return -EIO; } @@ -233,7 +208,7 @@ static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm, if (xfer != 3) { dev_err(&client->dev, "%s: xfer=%d addr=%02x, data=%02x\n", - __FUNCTION__, + __func__, xfer, rdata[1], rdata[2]); return -EIO; } @@ -241,7 +216,7 @@ static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm, /* disable further writes */ if ((xfer = i2c_master_send(client, diswe, 3)) != 3) { - dev_err(&client->dev, "%s: diswe - %d\n", __FUNCTION__, xfer); + dev_err(&client->dev, "%s: diswe - %d\n", __func__, xfer); return -EIO; } @@ -274,11 +249,11 @@ static int x1205_get_dtrim(struct i2c_client *client, int *trim) /* read dtr register */ if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) { - dev_err(&client->dev, "%s: read error\n", __FUNCTION__); + dev_err(&client->dev, "%s: read error\n", __func__); return -EIO; } - dev_dbg(&client->dev, "%s: raw dtr=%x\n", __FUNCTION__, dtr); + dev_dbg(&client->dev, "%s: raw dtr=%x\n", __func__, dtr); *trim = 0; @@ -306,11 +281,11 @@ static int x1205_get_atrim(struct i2c_client *client, int *trim) /* read atr register */ if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) { - dev_err(&client->dev, "%s: read error\n", __FUNCTION__); + dev_err(&client->dev, "%s: read error\n", __func__); return -EIO; } - dev_dbg(&client->dev, "%s: raw atr=%x\n", __FUNCTION__, atr); + dev_dbg(&client->dev, "%s: raw atr=%x\n", __func__, atr); /* atr is a two's complement value on 6 bits, * perform sign extension. The formula is @@ -319,11 +294,11 @@ static int x1205_get_atrim(struct i2c_client *client, int *trim) if (atr & 0x20) atr |= 0xC0; - dev_dbg(&client->dev, "%s: raw atr=%x (%d)\n", __FUNCTION__, atr, atr); + dev_dbg(&client->dev, "%s: raw atr=%x (%d)\n", __func__, atr, atr); *trim = (atr * 250) + 11000; - dev_dbg(&client->dev, "%s: real=%d\n", __FUNCTION__, *trim); + dev_dbg(&client->dev, "%s: real=%d\n", __func__, *trim); return 0; } @@ -377,7 +352,7 @@ static int x1205_validate_client(struct i2c_client *client) if ((xfer = i2c_transfer(client->adapter, msgs, 2)) != 2) { dev_err(&client->dev, "%s: could not read register %x\n", - __FUNCTION__, probe_zero_pattern[i]); + __func__, probe_zero_pattern[i]); return -EIO; } @@ -385,7 +360,7 @@ static int x1205_validate_client(struct i2c_client *client) if ((buf & probe_zero_pattern[i+1]) != 0) { dev_err(&client->dev, "%s: register=%02x, zero pattern=%d, value=%x\n", - __FUNCTION__, probe_zero_pattern[i], i, buf); + __func__, probe_zero_pattern[i], i, buf); return -ENODEV; } @@ -405,7 +380,7 @@ static int x1205_validate_client(struct i2c_client *client) if ((xfer = i2c_transfer(client->adapter, msgs, 2)) != 2) { dev_err(&client->dev, "%s: could not read register %x\n", - __FUNCTION__, probe_limits_pattern[i].reg); + __func__, probe_limits_pattern[i].reg); return -EIO; } @@ -416,7 +391,7 @@ static int x1205_validate_client(struct i2c_client *client) value < probe_limits_pattern[i].min) { dev_dbg(&client->dev, "%s: register=%x, lim pattern=%d, value=%d\n", - __FUNCTION__, probe_limits_pattern[i].reg, + __func__, probe_limits_pattern[i].reg, i, value); return -ENODEV; @@ -497,58 +472,50 @@ static ssize_t x1205_sysfs_show_dtrim(struct device *dev, } static DEVICE_ATTR(dtrim, S_IRUGO, x1205_sysfs_show_dtrim, NULL); -static int x1205_attach(struct i2c_adapter *adapter) +static int x1205_sysfs_register(struct device *dev) { - return i2c_probe(adapter, &addr_data, x1205_probe); + int err; + + err = device_create_file(dev, &dev_attr_atrim); + if (err) + return err; + + err = device_create_file(dev, &dev_attr_dtrim); + if (err) + device_remove_file(dev, &dev_attr_atrim); + + return err; } -static int x1205_probe(struct i2c_adapter *adapter, int address, int kind) +static void x1205_sysfs_unregister(struct device *dev) +{ + device_remove_file(dev, &dev_attr_atrim); + device_remove_file(dev, &dev_attr_dtrim); +} + + +static int x1205_probe(struct i2c_client *client, + const struct i2c_device_id *id) { int err = 0; unsigned char sr; - struct i2c_client *client; struct rtc_device *rtc; - dev_dbg(&adapter->dev, "%s\n", __FUNCTION__); - - if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { - err = -ENODEV; - goto exit; - } - - if (!(client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL))) { - err = -ENOMEM; - goto exit; - } - - /* I2C client */ - client->addr = address; - client->driver = &x1205_driver; - client->adapter = adapter; - - strlcpy(client->name, x1205_driver.driver.name, I2C_NAME_SIZE); + dev_dbg(&client->dev, "%s\n", __func__); - /* Verify the chip is really an X1205 */ - if (kind < 0) { - if (x1205_validate_client(client) < 0) { - err = -ENODEV; - goto exit_kfree; - } - } + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + return -ENODEV; - /* Inform the i2c layer */ - if ((err = i2c_attach_client(client))) - goto exit_kfree; + if (x1205_validate_client(client) < 0) + return -ENODEV; dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n"); rtc = rtc_device_register(x1205_driver.driver.name, &client->dev, &x1205_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) { - err = PTR_ERR(rtc); - goto exit_detach; - } + if (IS_ERR(rtc)) + return PTR_ERR(rtc); i2c_set_clientdata(client, rtc); @@ -565,45 +532,42 @@ static int x1205_probe(struct i2c_adapter *adapter, int address, int kind) else dev_err(&client->dev, "couldn't read status\n"); - err = device_create_file(&client->dev, &dev_attr_atrim); - if (err) goto exit_devreg; - err = device_create_file(&client->dev, &dev_attr_dtrim); - if (err) goto exit_atrim; + err = x1205_sysfs_register(&client->dev); + if (err) + goto exit_devreg; return 0; -exit_atrim: - device_remove_file(&client->dev, &dev_attr_atrim); - exit_devreg: rtc_device_unregister(rtc); -exit_detach: - i2c_detach_client(client); - -exit_kfree: - kfree(client); - -exit: return err; } -static int x1205_detach(struct i2c_client *client) +static int x1205_remove(struct i2c_client *client) { - int err; struct rtc_device *rtc = i2c_get_clientdata(client); - if (rtc) - rtc_device_unregister(rtc); - - if ((err = i2c_detach_client(client))) - return err; - - kfree(client); - + rtc_device_unregister(rtc); + x1205_sysfs_unregister(&client->dev); return 0; } +static const struct i2c_device_id x1205_id[] = { + { "x1205", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, x1205_id); + +static struct i2c_driver x1205_driver = { + .driver = { + .name = "rtc-x1205", + }, + .probe = x1205_probe, + .remove = x1205_remove, + .id_table = x1205_id, +}; + static int __init x1205_init(void) { return i2c_add_driver(&x1205_driver); diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c index 556063e8f7a..03c0e40a92f 100644 --- a/drivers/s390/block/dasd_proc.c +++ b/drivers/s390/block/dasd_proc.c @@ -157,6 +157,7 @@ static int dasd_devices_open(struct inode *inode, struct file *file) } static const struct file_operations dasd_devices_file_ops = { + .owner = THIS_MODULE, .open = dasd_devices_open, .read = seq_read, .llseek = seq_lseek, @@ -311,17 +312,16 @@ out_error: int dasd_proc_init(void) { - dasd_proc_root_entry = proc_mkdir("dasd", &proc_root); + dasd_proc_root_entry = proc_mkdir("dasd", NULL); if (!dasd_proc_root_entry) goto out_nodasd; dasd_proc_root_entry->owner = THIS_MODULE; - dasd_devices_entry = create_proc_entry("devices", - S_IFREG | S_IRUGO | S_IWUSR, - dasd_proc_root_entry); + dasd_devices_entry = proc_create("devices", + S_IFREG | S_IRUGO | S_IWUSR, + dasd_proc_root_entry, + &dasd_devices_file_ops); if (!dasd_devices_entry) goto out_nodevices; - dasd_devices_entry->proc_fops = &dasd_devices_file_ops; - dasd_devices_entry->owner = THIS_MODULE; dasd_statistics_entry = create_proc_entry("statistics", S_IFREG | S_IRUGO | S_IWUSR, dasd_proc_root_entry); @@ -335,7 +335,7 @@ dasd_proc_init(void) out_nostatistics: remove_proc_entry("devices", dasd_proc_root_entry); out_nodevices: - remove_proc_entry("dasd", &proc_root); + remove_proc_entry("dasd", NULL); out_nodasd: return -ENOENT; } @@ -345,5 +345,5 @@ dasd_proc_exit(void) { remove_proc_entry("devices", dasd_proc_root_entry); remove_proc_entry("statistics", dasd_proc_root_entry); - remove_proc_entry("dasd", &proc_root); + remove_proc_entry("dasd", NULL); } diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index 04787eab101..bb52d2fbac1 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c @@ -36,7 +36,7 @@ static int dcssblk_open(struct inode *inode, struct file *filp); static int dcssblk_release(struct inode *inode, struct file *filp); static int dcssblk_make_request(struct request_queue *q, struct bio *bio); static int dcssblk_direct_access(struct block_device *bdev, sector_t secnum, - unsigned long *data); + void **kaddr, unsigned long *pfn); static char dcssblk_segments[DCSSBLK_PARM_LEN] = "\0"; @@ -636,7 +636,7 @@ fail: static int dcssblk_direct_access (struct block_device *bdev, sector_t secnum, - unsigned long *data) + void **kaddr, unsigned long *pfn) { struct dcssblk_dev_info *dev_info; unsigned long pgoff; @@ -649,7 +649,9 @@ dcssblk_direct_access (struct block_device *bdev, sector_t secnum, pgoff = secnum / (PAGE_SIZE / 512); if ((pgoff+1)*PAGE_SIZE-1 > dev_info->end - dev_info->start) return -ERANGE; - *data = (unsigned long) (dev_info->start+pgoff*PAGE_SIZE); + *kaddr = (void *) (dev_info->start+pgoff*PAGE_SIZE); + *pfn = virt_to_phys(*kaddr) >> PAGE_SHIFT; + return 0; } diff --git a/drivers/s390/char/tape_proc.c b/drivers/s390/char/tape_proc.c index c9b96d51b28..e7c888c14e7 100644 --- a/drivers/s390/char/tape_proc.c +++ b/drivers/s390/char/tape_proc.c @@ -111,6 +111,7 @@ static int tape_proc_open(struct inode *inode, struct file *file) static const struct file_operations tape_proc_ops = { + .owner = THIS_MODULE, .open = tape_proc_open, .read = seq_read, .llseek = seq_lseek, @@ -124,14 +125,12 @@ void tape_proc_init(void) { tape_proc_devices = - create_proc_entry ("tapedevices", S_IFREG | S_IRUGO | S_IWUSR, - &proc_root); + proc_create("tapedevices", S_IFREG | S_IRUGO | S_IWUSR, NULL, + &tape_proc_ops); if (tape_proc_devices == NULL) { PRINT_WARN("tape: Cannot register procfs entry tapedevices\n"); return; } - tape_proc_devices->proc_fops = &tape_proc_ops; - tape_proc_devices->owner = THIS_MODULE; } /* @@ -141,5 +140,5 @@ void tape_proc_cleanup(void) { if (tape_proc_devices != NULL) - remove_proc_entry ("tapedevices", &proc_root); + remove_proc_entry ("tapedevices", NULL); } diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c index e8597ec9224..40ef948fcb3 100644 --- a/drivers/s390/cio/blacklist.c +++ b/drivers/s390/cio/blacklist.c @@ -374,13 +374,10 @@ cio_ignore_proc_init (void) { struct proc_dir_entry *entry; - entry = create_proc_entry ("cio_ignore", S_IFREG | S_IRUGO | S_IWUSR, - &proc_root); + entry = proc_create("cio_ignore", S_IFREG | S_IRUGO | S_IWUSR, NULL, + &cio_ignore_proc_fops); if (!entry) return -ENOENT; - - entry->proc_fops = &cio_ignore_proc_fops; - return 0; } diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c index 10aa1e78080..43876e28737 100644 --- a/drivers/s390/cio/qdio.c +++ b/drivers/s390/cio/qdio.c @@ -3632,7 +3632,7 @@ qdio_add_procfs_entry(void) { proc_perf_file_registration=0; qdio_perf_proc_file=create_proc_entry(QDIO_PERF, - S_IFREG|0444,&proc_root); + S_IFREG|0444,NULL); if (qdio_perf_proc_file) { qdio_perf_proc_file->read_proc=&qdio_perf_procfile_read; } else proc_perf_file_registration=-1; @@ -3647,7 +3647,7 @@ static void qdio_remove_procfs_entry(void) { if (!proc_perf_file_registration) /* means if it went ok earlier */ - remove_proc_entry(QDIO_PERF,&proc_root); + remove_proc_entry(QDIO_PERF,NULL); } /** diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c index a09b2d3fdf5..f5215fd4b73 100644 --- a/drivers/scsi/aha152x.c +++ b/drivers/scsi/aha152x.c @@ -994,13 +994,13 @@ static int aha152x_internal_queue(Scsi_Cmnd *SCpnt, struct completion *complete, SCpnt->SCp.sent_command = 0; if(SCpnt->SCp.phase & (resetting|check_condition)) { - if(SCpnt->host_scribble==0 || SCSEM(SCpnt) || SCNEXT(SCpnt)) { + if (!SCpnt->host_scribble || SCSEM(SCpnt) || SCNEXT(SCpnt)) { printk(ERR_LEAD "cannot reuse command\n", CMDINFO(SCpnt)); return FAILED; } } else { SCpnt->host_scribble = kmalloc(sizeof(struct aha152x_scdata), GFP_ATOMIC); - if(SCpnt->host_scribble==0) { + if(!SCpnt->host_scribble) { printk(ERR_LEAD "allocation failed\n", CMDINFO(SCpnt)); return FAILED; } @@ -1162,7 +1162,7 @@ static int aha152x_device_reset(Scsi_Cmnd * SCpnt) } DO_LOCK(flags); - issued = remove_SC(&ISSUE_SC, SCpnt)==0; + issued = remove_SC(&ISSUE_SC, SCpnt) == NULL; disconnected = issued && remove_SC(&DISCONNECTED_SC, SCpnt); DO_UNLOCK(flags); diff --git a/drivers/scsi/aic7xxx/aic7770_osm.c b/drivers/scsi/aic7xxx/aic7770_osm.c index 1ac119733ba..f220e5e436a 100644 --- a/drivers/scsi/aic7xxx/aic7770_osm.c +++ b/drivers/scsi/aic7xxx/aic7770_osm.c @@ -50,7 +50,7 @@ aic7770_map_registers(struct ahc_softc *ahc, u_int port) /* * Lock out other contenders for our i/o space. */ - if (request_region(port, AHC_EISA_IOSIZE, "aic7xxx") == 0) + if (!request_region(port, AHC_EISA_IOSIZE, "aic7xxx")) return (ENOMEM); ahc->tag = BUS_SPACE_PIO; ahc->bsh.ioport = port; diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c index 0d7628f1f1e..00f5b986857 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c @@ -352,7 +352,7 @@ ahc_linux_pci_reserve_io_region(struct ahc_softc *ahc, resource_size_t *base) *base = pci_resource_start(ahc->dev_softc, 0); if (*base == 0) return (ENOMEM); - if (request_region(*base, 256, "aic7xxx") == 0) + if (!request_region(*base, 256, "aic7xxx")) return (ENOMEM); return (0); } @@ -369,7 +369,7 @@ ahc_linux_pci_reserve_mem_region(struct ahc_softc *ahc, start = pci_resource_start(ahc->dev_softc, 1); if (start != 0) { *bus_addr = start; - if (request_mem_region(start, 0x1000, "aic7xxx") == 0) + if (!request_mem_region(start, 0x1000, "aic7xxx")) error = ENOMEM; if (error == 0) { *maddr = ioremap_nocache(start, 256); diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c index c9dd8392aab..ac92ac143b4 100644 --- a/drivers/scsi/dpt_i2o.c +++ b/drivers/scsi/dpt_i2o.c @@ -153,7 +153,7 @@ static DEFINE_SPINLOCK(adpt_post_wait_lock); static u8 adpt_read_blink_led(adpt_hba* host) { - if(host->FwDebugBLEDflag_P != 0) { + if (host->FwDebugBLEDflag_P) { if( readb(host->FwDebugBLEDflag_P) == 0xbc ){ return readb(host->FwDebugBLEDvalue_P); } diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c index 2cd6b4959eb..c33bcb284df 100644 --- a/drivers/scsi/fdomain.c +++ b/drivers/scsi/fdomain.c @@ -1443,7 +1443,7 @@ static int fdomain_16x0_queue(struct scsi_cmnd *SCpnt, current_SC->SCp.this_residual = current_SC->SCp.buffer->length; current_SC->SCp.buffers_residual = scsi_sg_count(current_SC) - 1; } else { - current_SC->SCp.ptr = 0; + current_SC->SCp.ptr = NULL; current_SC->SCp.this_residual = 0; current_SC->SCp.buffer = NULL; current_SC->SCp.buffers_residual = 0; diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c index 32553639ade..44d8d5163a1 100644 --- a/drivers/scsi/ide-scsi.c +++ b/drivers/scsi/ide-scsi.c @@ -134,6 +134,7 @@ static inline idescsi_scsi_t *drive_to_idescsi(ide_drive_t *ide_drive) static void idescsi_input_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc, unsigned int bcount) { + ide_hwif_t *hwif = drive->hwif; int count; char *buf; @@ -145,14 +146,12 @@ static void idescsi_input_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc, local_irq_save(flags); buf = kmap_atomic(sg_page(pc->sg), KM_IRQ0) + pc->sg->offset; - drive->hwif->atapi_input_bytes(drive, - buf + pc->b_count, count); + hwif->input_data(drive, NULL, buf + pc->b_count, count); kunmap_atomic(buf - pc->sg->offset, KM_IRQ0); local_irq_restore(flags); } else { buf = sg_virt(pc->sg); - drive->hwif->atapi_input_bytes(drive, - buf + pc->b_count, count); + hwif->input_data(drive, NULL, buf + pc->b_count, count); } bcount -= count; pc->b_count += count; if (pc->b_count == pc->sg->length) { @@ -165,13 +164,14 @@ static void idescsi_input_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc, if (bcount) { printk (KERN_ERR "ide-scsi: scatter gather table too small, discarding data\n"); - ide_atapi_discard_data(drive, bcount); + ide_pad_transfer(drive, 0, bcount); } } static void idescsi_output_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc, unsigned int bcount) { + ide_hwif_t *hwif = drive->hwif; int count; char *buf; @@ -183,14 +183,12 @@ static void idescsi_output_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc, local_irq_save(flags); buf = kmap_atomic(sg_page(pc->sg), KM_IRQ0) + pc->sg->offset; - drive->hwif->atapi_output_bytes(drive, - buf + pc->b_count, count); + hwif->output_data(drive, NULL, buf + pc->b_count, count); kunmap_atomic(buf - pc->sg->offset, KM_IRQ0); local_irq_restore(flags); } else { buf = sg_virt(pc->sg); - drive->hwif->atapi_output_bytes(drive, - buf + pc->b_count, count); + hwif->output_data(drive, NULL, buf + pc->b_count, count); } bcount -= count; pc->b_count += count; if (pc->b_count == pc->sg->length) { @@ -203,7 +201,7 @@ static void idescsi_output_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc, if (bcount) { printk (KERN_ERR "ide-scsi: scatter gather table too small, padding with zeros\n"); - ide_atapi_write_zeros(drive, bcount); + ide_pad_transfer(drive, 1, bcount); } } @@ -258,7 +256,8 @@ idescsi_atapi_error(ide_drive_t *drive, struct request *rq, u8 stat, u8 err) if (ide_read_status(drive) & (BUSY_STAT | DRQ_STAT)) /* force an abort */ - hwif->OUTB(WIN_IDLEIMMEDIATE, hwif->io_ports.command_addr); + hwif->OUTBSYNC(drive, WIN_IDLEIMMEDIATE, + hwif->io_ports.command_addr); rq->errors++; @@ -431,14 +430,15 @@ static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive) idescsi_input_buffers(drive, pc, temp); else - drive->hwif->atapi_input_bytes(drive, pc->cur_pos, temp); + hwif->input_data(drive, NULL, + pc->cur_pos, temp); printk(KERN_ERR "ide-scsi: transferred" " %d of %d bytes\n", temp, bcount); } pc->xferred += temp; pc->cur_pos += temp; - ide_atapi_discard_data(drive, bcount - temp); + ide_pad_transfer(drive, 0, bcount - temp); ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), idescsi_expiry); return ide_started; } @@ -452,15 +452,13 @@ static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive) if (pc->sg) idescsi_input_buffers(drive, pc, bcount); else - hwif->atapi_input_bytes(drive, pc->cur_pos, - bcount); + hwif->input_data(drive, NULL, pc->cur_pos, bcount); } else { pc->flags |= PC_FLAG_WRITING; if (pc->sg) idescsi_output_buffers(drive, pc, bcount); else - hwif->atapi_output_bytes(drive, pc->cur_pos, - bcount); + hwif->output_data(drive, NULL, pc->cur_pos, bcount); } /* Update the current position */ pc->xferred += bcount; @@ -493,8 +491,10 @@ static ide_startstop_t idescsi_transfer_pc(ide_drive_t *drive) BUG_ON(HWGROUP(drive)->handler != NULL); /* Set the interrupt routine */ ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), idescsi_expiry); + /* Send the actual packet */ - drive->hwif->atapi_output_bytes(drive, scsi->pc->c, 12); + hwif->output_data(drive, NULL, scsi->pc->c, 12); + if (pc->flags & PC_FLAG_DMA_OK) { pc->flags |= PC_FLAG_DMA_IN_PROGRESS; hwif->dma_ops->dma_start(drive); @@ -574,7 +574,7 @@ static ide_startstop_t idescsi_issue_pc(ide_drive_t *drive, return ide_started; } else { /* Issue the packet command */ - hwif->OUTB(WIN_PACKETCMD, hwif->io_ports.command_addr); + ide_execute_pkt_cmd(drive); return idescsi_transfer_pc(drive); } } diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index b135a1ed4b2..18551aaf5e0 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -4996,7 +4996,7 @@ static int __init megaraid_init(void) max_mbox_busy_wait = MBOX_BUSY_WAIT; #ifdef CONFIG_PROC_FS - mega_proc_dir_entry = proc_mkdir("megaraid", &proc_root); + mega_proc_dir_entry = proc_mkdir("megaraid", NULL); if (!mega_proc_dir_entry) { printk(KERN_WARNING "megaraid: failed to create megaraid root\n"); @@ -5005,7 +5005,7 @@ static int __init megaraid_init(void) error = pci_register_driver(&megaraid_pci_driver); if (error) { #ifdef CONFIG_PROC_FS - remove_proc_entry("megaraid", &proc_root); + remove_proc_entry("megaraid", NULL); #endif return error; } @@ -5035,7 +5035,7 @@ static void __exit megaraid_exit(void) pci_unregister_driver(&megaraid_pci_driver); #ifdef CONFIG_PROC_FS - remove_proc_entry("megaraid", &proc_root); + remove_proc_entry("megaraid", NULL); #endif } diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c index d8928940042..ceab4f73caf 100644 --- a/drivers/scsi/ncr53c8xx.c +++ b/drivers/scsi/ncr53c8xx.c @@ -8186,7 +8186,7 @@ static void insert_into_waiting_list(struct ncb *np, struct scsi_cmnd *cmd) cmd->next_wcmd = NULL; if (!(wcmd = np->waiting_list)) np->waiting_list = cmd; else { - while ((wcmd->next_wcmd) != 0) + while (wcmd->next_wcmd) wcmd = (struct scsi_cmnd *) wcmd->next_wcmd; wcmd->next_wcmd = (char *) cmd; } @@ -8222,7 +8222,7 @@ static void process_waiting_list(struct ncb *np, int sts) #ifdef DEBUG_WAITING_LIST if (waiting_list) printk("%s: waiting_list=%lx processing sts=%d\n", ncr_name(np), (u_long) waiting_list, sts); #endif - while ((wcmd = waiting_list) != 0) { + while (wcmd = waiting_list) { waiting_list = (struct scsi_cmnd *) wcmd->next_wcmd; wcmd->next_wcmd = NULL; if (sts == DID_OK) { diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 07103c399fe..f6600bfb5bd 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -1773,7 +1773,7 @@ static int scsi_debug_slave_alloc(struct scsi_device *sdp) if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n", sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); - set_bit(QUEUE_FLAG_BIDI, &sdp->request_queue->queue_flags); + queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue); return 0; } diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index b8de041bc0a..a235802f298 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -449,37 +449,40 @@ int scsi_get_device_flags(struct scsi_device *sdev, } #ifdef CONFIG_SCSI_PROC_FS -/* - * proc_scsi_dev_info_read: dump the scsi_dev_info_list via - * /proc/scsi/device_info - */ -static int proc_scsi_devinfo_read(char *buffer, char **start, - off_t offset, int length) +static int devinfo_seq_show(struct seq_file *m, void *v) { - struct scsi_dev_info_list *devinfo; - int size, len = 0; - off_t begin = 0; - off_t pos = 0; + struct scsi_dev_info_list *devinfo = + list_entry(v, struct scsi_dev_info_list, dev_info_list); - list_for_each_entry(devinfo, &scsi_dev_info_list, dev_info_list) { - size = sprintf(buffer + len, "'%.8s' '%.16s' 0x%x\n", + seq_printf(m, "'%.8s' '%.16s' 0x%x\n", devinfo->vendor, devinfo->model, devinfo->flags); - len += size; - pos = begin + len; - if (pos < offset) { - len = 0; - begin = pos; - } - if (pos > offset + length) - goto stop_output; - } + return 0; +} + +static void * devinfo_seq_start(struct seq_file *m, loff_t *pos) +{ + return seq_list_start(&scsi_dev_info_list, *pos); +} -stop_output: - *start = buffer + (offset - begin); /* Start of wanted data */ - len -= (offset - begin); /* Start slop */ - if (len > length) - len = length; /* Ending slop */ - return (len); +static void * devinfo_seq_next(struct seq_file *m, void *v, loff_t *pos) +{ + return seq_list_next(v, &scsi_dev_info_list, pos); +} + +static void devinfo_seq_stop(struct seq_file *m, void *v) +{ +} + +static const struct seq_operations scsi_devinfo_seq_ops = { + .start = devinfo_seq_start, + .next = devinfo_seq_next, + .stop = devinfo_seq_stop, + .show = devinfo_seq_show, +}; + +static int proc_scsi_devinfo_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &scsi_devinfo_seq_ops); } /* @@ -489,11 +492,12 @@ stop_output: * integer value of flag to the scsi device info list. * To use, echo "vendor:model:flag" > /proc/scsi/device_info */ -static int proc_scsi_devinfo_write(struct file *file, const char __user *buf, - unsigned long length, void *data) +static ssize_t proc_scsi_devinfo_write(struct file *file, + const char __user *buf, + size_t length, loff_t *ppos) { char *buffer; - int err = length; + ssize_t err = length; if (!buf || length>PAGE_SIZE) return -EINVAL; @@ -517,6 +521,15 @@ out: free_page((unsigned long)buffer); return err; } + +static const struct file_operations scsi_devinfo_proc_fops = { + .owner = THIS_MODULE, + .open = proc_scsi_devinfo_open, + .read = seq_read, + .write = proc_scsi_devinfo_write, + .llseek = seq_lseek, + .release = seq_release, +}; #endif /* CONFIG_SCSI_PROC_FS */ module_param_string(dev_flags, scsi_dev_flags, sizeof(scsi_dev_flags), 0); @@ -577,15 +590,13 @@ int __init scsi_init_devinfo(void) } #ifdef CONFIG_SCSI_PROC_FS - p = create_proc_entry("scsi/device_info", 0, NULL); + p = proc_create("scsi/device_info", 0, NULL, &scsi_devinfo_proc_fops); if (!p) { error = -ENOMEM; goto out; } p->owner = THIS_MODULE; - p->get_info = proc_scsi_devinfo_read; - p->write_proc = proc_scsi_devinfo_write; #endif /* CONFIG_SCSI_PROC_FS */ out: diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 221f31e36d2..1eaba6cd80f 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -1771,6 +1771,7 @@ scsi_reset_provider(struct scsi_device *dev, int flag) unsigned long flags; int rtn; + blk_rq_init(NULL, &req); scmd->request = &req; memset(&scmd->eh_timeout, 0, sizeof(scmd->eh_timeout)); diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 67f412bb497..d545ad1cf47 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -536,6 +536,9 @@ static void scsi_run_queue(struct request_queue *q) !shost->host_blocked && !shost->host_self_blocked && !((shost->can_queue > 0) && (shost->host_busy >= shost->can_queue))) { + + int flagset; + /* * As long as shost is accepting commands and we have * starved queues, call blk_run_queue. scsi_request_fn @@ -549,19 +552,20 @@ static void scsi_run_queue(struct request_queue *q) sdev = list_entry(shost->starved_list.next, struct scsi_device, starved_entry); list_del_init(&sdev->starved_entry); - spin_unlock_irqrestore(shost->host_lock, flags); - + spin_unlock(shost->host_lock); + + spin_lock(sdev->request_queue->queue_lock); + flagset = test_bit(QUEUE_FLAG_REENTER, &q->queue_flags) && + !test_bit(QUEUE_FLAG_REENTER, + &sdev->request_queue->queue_flags); + if (flagset) + queue_flag_set(QUEUE_FLAG_REENTER, sdev->request_queue); + __blk_run_queue(sdev->request_queue); + if (flagset) + queue_flag_clear(QUEUE_FLAG_REENTER, sdev->request_queue); + spin_unlock(sdev->request_queue->queue_lock); - if (test_bit(QUEUE_FLAG_REENTER, &q->queue_flags) && - !test_and_set_bit(QUEUE_FLAG_REENTER, - &sdev->request_queue->queue_flags)) { - blk_run_queue(sdev->request_queue); - clear_bit(QUEUE_FLAG_REENTER, - &sdev->request_queue->queue_flags); - } else - blk_run_queue(sdev->request_queue); - - spin_lock_irqsave(shost->host_lock, flags); + spin_lock(shost->host_lock); if (unlikely(!list_empty(&sdev->starved_entry))) /* * sdev lost a race, and was put back on the @@ -1585,8 +1589,9 @@ struct request_queue *__scsi_alloc_queue(struct Scsi_Host *shost, blk_queue_max_segment_size(q, dma_get_max_seg_size(dev)); + /* New queue, no concurrency on queue_flags */ if (!shost->use_clustering) - clear_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags); + queue_flag_clear_unlocked(QUEUE_FLAG_CLUSTER, q); /* * set a reasonable default alignment on word boundaries: the diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c index 3a1c99d5c77..e4a0d2f9b35 100644 --- a/drivers/scsi/scsi_proc.c +++ b/drivers/scsi/scsi_proc.c @@ -413,6 +413,7 @@ static int proc_scsi_open(struct inode *inode, struct file *file) } static const struct file_operations proc_scsi_operations = { + .owner = THIS_MODULE, .open = proc_scsi_open, .read = seq_read, .write = proc_scsi_write, @@ -431,10 +432,9 @@ int __init scsi_init_procfs(void) if (!proc_scsi) goto err1; - pde = create_proc_entry("scsi/scsi", 0, NULL); + pde = proc_create("scsi/scsi", 0, NULL, &proc_scsi_operations); if (!pde) goto err2; - pde->proc_fops = &proc_scsi_operations; return 0; diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index fcd7455ffc3..a00eee6f7be 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -1828,7 +1828,7 @@ void scsi_scan_host(struct Scsi_Host *shost) } p = kthread_run(do_scan_async, data, "scsi_scan_%d", shost->host_no); - if (unlikely(IS_ERR(p))) + if (IS_ERR(p)) do_scan_async(data); } EXPORT_SYMBOL(scsi_scan_host); diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c index 7899e3dda9b..f4461d35ffb 100644 --- a/drivers/scsi/scsi_transport_sas.c +++ b/drivers/scsi/scsi_transport_sas.c @@ -248,8 +248,7 @@ static int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy) else q->queuedata = shost; - set_bit(QUEUE_FLAG_BIDI, &q->queue_flags); - + queue_flag_set_unlocked(QUEUE_FLAG_BIDI, q); return 0; } diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 3cea17dd5db..01cefbb2d53 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -860,7 +860,6 @@ static int sd_sync_cache(struct scsi_disk *sdkp) static void sd_prepare_flush(struct request_queue *q, struct request *rq) { - memset(rq->cmd, 0, sizeof(rq->cmd)); rq->cmd_type = REQ_TYPE_BLOCK_PC; rq->timeout = SD_TIMEOUT; rq->cmd[0] = SYNCHRONIZE_CACHE; diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 2029422bc04..c9d7f721b9e 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -2667,7 +2667,6 @@ sg_proc_init(void) { int k, mask; int num_leaves = ARRAY_SIZE(sg_proc_leaf_arr); - struct proc_dir_entry *pdep; struct sg_proc_leaf * leaf; sg_proc_sgp = proc_mkdir(sg_proc_sg_dirname, NULL); @@ -2676,13 +2675,10 @@ sg_proc_init(void) for (k = 0; k < num_leaves; ++k) { leaf = &sg_proc_leaf_arr[k]; mask = leaf->fops->write ? S_IRUGO | S_IWUSR : S_IRUGO; - pdep = create_proc_entry(leaf->name, mask, sg_proc_sgp); - if (pdep) { - leaf->fops->owner = THIS_MODULE, - leaf->fops->read = seq_read, - leaf->fops->llseek = seq_lseek, - pdep->proc_fops = leaf->fops; - } + leaf->fops->owner = THIS_MODULE; + leaf->fops->read = seq_read; + leaf->fops->llseek = seq_lseek; + proc_create(leaf->name, mask, sg_proc_sgp, leaf->fops); } return 0; } diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.c b/drivers/scsi/sym53c8xx_2/sym_hipd.c index 35142b5341b..22a6aae7869 100644 --- a/drivers/scsi/sym53c8xx_2/sym_hipd.c +++ b/drivers/scsi/sym53c8xx_2/sym_hipd.c @@ -1647,7 +1647,7 @@ static void sym_flush_comp_queue(struct sym_hcb *np, int cam_status) SYM_QUEHEAD *qp; struct sym_ccb *cp; - while ((qp = sym_remque_head(&np->comp_ccbq)) != 0) { + while ((qp = sym_remque_head(&np->comp_ccbq)) != NULL) { struct scsi_cmnd *cmd; cp = sym_que_entry(qp, struct sym_ccb, link_ccbq); sym_insque_tail(&cp->link_ccbq, &np->busy_ccbq); @@ -3168,7 +3168,7 @@ int sym_clear_tasks(struct sym_hcb *np, int cam_status, int target, int lun, int * the COMP queue and put back other ones into * the BUSY queue. */ - while ((qp = sym_remque_head(&qtmp)) != 0) { + while ((qp = sym_remque_head(&qtmp)) != NULL) { struct scsi_cmnd *cmd; cp = sym_que_entry(qp, struct sym_ccb, link_ccbq); cmd = cp->cmd; @@ -5729,7 +5729,7 @@ void sym_hcb_free(struct sym_hcb *np) sym_mfree_dma(np->dqueue, sizeof(u32)*(MAX_QUEUE*2), "DQUEUE"); if (np->actccbs) { - while ((qp = sym_remque_head(&np->free_ccbq)) != 0) { + while ((qp = sym_remque_head(&np->free_ccbq)) != NULL) { cp = sym_que_entry(qp, struct sym_ccb, link_ccbq); sym_mfree_dma(cp, sizeof(*cp), "CCB"); } diff --git a/drivers/scsi/ultrastor.c b/drivers/scsi/ultrastor.c index f385dce8dfb..27aa40f3980 100644 --- a/drivers/scsi/ultrastor.c +++ b/drivers/scsi/ultrastor.c @@ -951,7 +951,7 @@ static int ultrastor_abort(struct scsi_cmnd *SCpnt) printk("abort: command mismatch, %p != %p\n", config.mscp[mscp_index].SCint, SCpnt); #endif - if (config.mscp[mscp_index].SCint == 0) + if (config.mscp[mscp_index].SCint == NULL) return FAILED; if (config.mscp[mscp_index].SCint != SCpnt) panic("Bad abort"); @@ -1101,7 +1101,7 @@ static void ultrastor_interrupt(void *dev_id) SCtmp = mscp->SCint; mscp->SCint = NULL; - if (SCtmp == 0) + if (!SCtmp) { #if ULTRASTOR_DEBUG & (UD_ABORT|UD_INTERRUPT) printk("MSCP %d (%x): no command\n", mscp_index, (unsigned int) mscp); diff --git a/drivers/serial/68360serial.c b/drivers/serial/68360serial.c index 2aa6bfe8fdb..f5946360187 100644 --- a/drivers/serial/68360serial.c +++ b/drivers/serial/68360serial.c @@ -51,6 +51,7 @@ extern int kgdb_output_string (const char* s, unsigned int count); /* #ifdef CONFIG_SERIAL_CONSOLE */ /* This seems to be a post 2.0 thing - mles */ #include <linux/console.h> +#include <linux/jiffies.h> /* this defines the index into rs_table for the port to use */ @@ -1729,7 +1730,7 @@ static void rs_360_wait_until_sent(struct tty_struct *tty, int timeout) msleep_interruptible(jiffies_to_msecs(char_time)); if (signal_pending(current)) break; - if (timeout && ((orig_jiffies + timeout) < jiffies)) + if (timeout && (time_after(jiffies, orig_jiffies + timeout))) break; /* The 'tx_cur' is really the next buffer to send. We * have to back up to the previous BD and wait for it diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 96a585e1cee..ea41f262645 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -1868,6 +1868,7 @@ static int serial8250_startup(struct uart_port *port) } if (is_real_interrupt(up->port.irq)) { + unsigned char iir1; /* * Test for UARTs that do not reassert THRE when the * transmitter is idle and the interrupt has already @@ -1881,7 +1882,7 @@ static int serial8250_startup(struct uart_port *port) wait_for_xmitr(up, UART_LSR_THRE); serial_out_sync(up, UART_IER, UART_IER_THRI); udelay(1); /* allow THRE to set */ - serial_in(up, UART_IIR); + iir1 = serial_in(up, UART_IIR); serial_out(up, UART_IER, 0); serial_out_sync(up, UART_IER, UART_IER_THRI); udelay(1); /* allow a working UART time to re-assert THRE */ @@ -1894,7 +1895,7 @@ static int serial8250_startup(struct uart_port *port) * If the interrupt is not reasserted, setup a timer to * kick the UART on a regular basis. */ - if (iir & UART_IIR_NO_INT) { + if (!(iir1 & UART_IIR_NO_INT) && (iir & UART_IIR_NO_INT)) { pr_debug("ttyS%d - using backup timer\n", port->line); up->timer.function = serial8250_backup_timeout; up->timer.data = (unsigned long)up; @@ -2228,7 +2229,9 @@ serial8250_set_termios(struct uart_port *port, struct ktermios *termios, } serial8250_set_mctrl(&up->port, up->port.mctrl); spin_unlock_irqrestore(&up->port.lock, flags); - tty_termios_encode_baud_rate(termios, baud, baud); + /* Don't rewrite B0 */ + if (tty_termios_baud_rate(termios)) + tty_termios_encode_baud_rate(termios, baud, baud); } static void diff --git a/drivers/serial/8250_au1x00.c b/drivers/serial/8250_au1x00.c deleted file mode 100644 index 58015fd14be..00000000000 --- a/drivers/serial/8250_au1x00.c +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Serial Device Initialisation for Au1x00 - * - * (C) Copyright Embedded Alley Solutions, Inc 2005 - * Author: Pantelis Antoniou <pantelis@embeddedalley.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/module.h> -#include <linux/serial_core.h> -#include <linux/signal.h> -#include <linux/slab.h> -#include <linux/types.h> - -#include <linux/serial_8250.h> - -#include <asm/mach-au1x00/au1000.h> - -#include "8250.h" - -#define PORT(_base, _irq) \ - { \ - .iobase = _base, \ - .membase = (void __iomem *)_base,\ - .mapbase = CPHYSADDR(_base), \ - .irq = _irq, \ - .uartclk = 0, /* filled */ \ - .regshift = 2, \ - .iotype = UPIO_AU, \ - .flags = UPF_SKIP_TEST \ - } - -static struct plat_serial8250_port au1x00_data[] = { -#if defined(CONFIG_SOC_AU1000) - PORT(UART0_ADDR, AU1000_UART0_INT), - PORT(UART1_ADDR, AU1000_UART1_INT), - PORT(UART2_ADDR, AU1000_UART2_INT), - PORT(UART3_ADDR, AU1000_UART3_INT), -#elif defined(CONFIG_SOC_AU1500) - PORT(UART0_ADDR, AU1500_UART0_INT), - PORT(UART3_ADDR, AU1500_UART3_INT), -#elif defined(CONFIG_SOC_AU1100) - PORT(UART0_ADDR, AU1100_UART0_INT), - PORT(UART1_ADDR, AU1100_UART1_INT), - /* The internal UART2 does not exist on the AU1100 processor. */ - PORT(UART3_ADDR, AU1100_UART3_INT), -#elif defined(CONFIG_SOC_AU1550) - PORT(UART0_ADDR, AU1550_UART0_INT), - PORT(UART1_ADDR, AU1550_UART1_INT), - PORT(UART3_ADDR, AU1550_UART3_INT), -#elif defined(CONFIG_SOC_AU1200) - PORT(UART0_ADDR, AU1200_UART0_INT), - PORT(UART1_ADDR, AU1200_UART1_INT), -#endif - { }, -}; - -static struct platform_device au1x00_device = { - .name = "serial8250", - .id = PLAT8250_DEV_AU1X00, - .dev = { - .platform_data = au1x00_data, - }, -}; - -static int __init au1x00_init(void) -{ - int i; - unsigned int uartclk; - - /* get uart clock */ - uartclk = get_au1x00_uart_baud_base() * 16; - - /* fill up uartclk */ - for (i = 0; au1x00_data[i].flags ; i++) - au1x00_data[i].uartclk = uartclk; - - return platform_device_register(&au1x00_device); -} - -/* XXX: Yes, I know this doesn't yet work. */ -static void __exit au1x00_exit(void) -{ - platform_device_unregister(&au1x00_device); -} - -module_init(au1x00_init); -module_exit(au1x00_exit); - -MODULE_AUTHOR("Pantelis Antoniou <pantelis@embeddedalley.com>"); -MODULE_DESCRIPTION("8250 serial probe module for Au1x000 cards"); -MODULE_LICENSE("GPL"); diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c index f97224ce59d..6e57382b913 100644 --- a/drivers/serial/8250_pci.c +++ b/drivers/serial/8250_pci.c @@ -775,7 +775,7 @@ pci_default_setup(struct serial_private *priv, struct pciserial_board *board, * This list is ordered alphabetically by vendor then device. * Specific entries must come before more generic entries. */ -static struct pci_serial_quirk pci_serial_quirks[] = { +static struct pci_serial_quirk pci_serial_quirks[] __refdata = { /* * ADDI-DATA GmbH communication cards <info@addi-data.com> */ diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index f7cd9504d81..34b809e3b59 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -262,12 +262,12 @@ config SERIAL_8250_ACORN cards. If unsure, say N. config SERIAL_8250_AU1X00 - bool "AU1X00 serial port support" + bool "Au1x00 serial port support" depends on SERIAL_8250 != n && SOC_AU1X00 help - If you have an Au1x00 board and want to use the serial port, say Y - to this option. The driver can handle 1 or 2 serial ports. - If unsure, say N. + If you have an Au1x00 SOC based board and want to use the serial port, + say Y to this option. The driver can handle up to 4 serial ports, + depending on the SOC. If unsure, say N. config SERIAL_8250_RM9K bool "Support for MIPS RM9xxx integrated serial port" diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index 3cbea549472..f02ff9fad01 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -20,7 +20,6 @@ obj-$(CONFIG_SERIAL_8250_BOCA) += 8250_boca.o obj-$(CONFIG_SERIAL_8250_EXAR_ST16C554) += 8250_exar_st16c554.o obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o obj-$(CONFIG_SERIAL_8250_MCA) += 8250_mca.o -obj-$(CONFIG_SERIAL_8250_AU1X00) += 8250_au1x00.o obj-$(CONFIG_SERIAL_AMBA_PL010) += amba-pl010.o obj-$(CONFIG_SERIAL_AMBA_PL011) += amba-pl011.o obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c index 55492fa095a..c065a704a93 100644 --- a/drivers/serial/atmel_serial.c +++ b/drivers/serial/atmel_serial.c @@ -96,7 +96,6 @@ /* PDC registers */ #define UART_PUT_PTCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_PTCR) -#define UART_GET_TCR(port) __raw_readl((port)->membase + ATMEL_PDC_TCR) #define UART_GET_PTSR(port) __raw_readl((port)->membase + ATMEL_PDC_PTSR) #define UART_PUT_RPR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_RPR) diff --git a/drivers/serial/crisv10.c b/drivers/serial/crisv10.c index 383c4e660cd..88e7c1d5b91 100644 --- a/drivers/serial/crisv10.c +++ b/drivers/serial/crisv10.c @@ -3582,6 +3582,8 @@ rs_tiocmset(struct tty_struct *tty, struct file *file, { struct e100_serial *info = (struct e100_serial *)tty->driver_data; + lock_kernel(); + if (clear & TIOCM_RTS) e100_rts(info, 0); if (clear & TIOCM_DTR) @@ -3601,6 +3603,8 @@ rs_tiocmset(struct tty_struct *tty, struct file *file, e100_ri_out(info, 1); if (set & TIOCM_CD) e100_cd_out(info, 1); + + unlock_kernel(); return 0; } @@ -3610,6 +3614,7 @@ rs_tiocmget(struct tty_struct *tty, struct file *file) struct e100_serial *info = (struct e100_serial *)tty->driver_data; unsigned int result; + lock_kernel(); result = (!E100_RTS_GET(info) ? TIOCM_RTS : 0) | (!E100_DTR_GET(info) ? TIOCM_DTR : 0) @@ -3618,6 +3623,8 @@ rs_tiocmget(struct tty_struct *tty, struct file *file) | (!E100_CD_GET(info) ? TIOCM_CAR : 0) | (!E100_CTS_GET(info) ? TIOCM_CTS : 0); + unlock_kernel(); + #ifdef SERIAL_DEBUG_IO printk(KERN_DEBUG "ser%i: modem state: %i 0x%08X\n", info->line, result, result); diff --git a/drivers/serial/dz.c b/drivers/serial/dz.c index 116211fcd36..0dddd68b20d 100644 --- a/drivers/serial/dz.c +++ b/drivers/serial/dz.c @@ -819,7 +819,7 @@ static void dz_console_putchar(struct uart_port *uport, int ch) dz_out(dport, DZ_TCR, mask); iob(); udelay(2); - } while (loops--); + } while (--loops); if (loops) /* Cannot send otherwise. */ dz_out(dport, DZ_TDR, ch); diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index a9ca03ead3e..977ce820ce3 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c @@ -329,13 +329,15 @@ EXPORT_SYMBOL(uart_update_timeout); * If it's still invalid, we try 9600 baud. * * Update the @termios structure to reflect the baud rate - * we're actually going to be using. + * we're actually going to be using. Don't do this for the case + * where B0 is requested ("hang up"). */ unsigned int uart_get_baud_rate(struct uart_port *port, struct ktermios *termios, struct ktermios *old, unsigned int min, unsigned int max) { unsigned int try, baud, altbaud = 38400; + int hung_up = 0; upf_t flags = port->flags & UPF_SPD_MASK; if (flags == UPF_SPD_HI) @@ -360,8 +362,10 @@ uart_get_baud_rate(struct uart_port *port, struct ktermios *termios, /* * Special case: B0 rate. */ - if (baud == 0) + if (baud == 0) { + hung_up = 1; baud = 9600; + } if (baud >= min && baud <= max) return baud; @@ -373,7 +377,9 @@ uart_get_baud_rate(struct uart_port *port, struct ktermios *termios, termios->c_cflag &= ~CBAUD; if (old) { baud = tty_termios_baud_rate(old); - tty_termios_encode_baud_rate(termios, baud, baud); + if (!hung_up) + tty_termios_encode_baud_rate(termios, + baud, baud); old = NULL; continue; } @@ -382,7 +388,8 @@ uart_get_baud_rate(struct uart_port *port, struct ktermios *termios, * As a last resort, if the quotient is zero, * default to 9600 bps */ - tty_termios_encode_baud_rate(termios, 9600, 9600); + if (!hung_up) + tty_termios_encode_baud_rate(termios, 9600, 9600); } return 0; diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c index 3271379a36d..90a20a152eb 100644 --- a/drivers/serial/sunzilog.c +++ b/drivers/serial/sunzilog.c @@ -1231,7 +1231,7 @@ static inline struct console *SUNZILOG_CONSOLE(void) #define SUNZILOG_CONSOLE() (NULL) #endif -static void __devinit sunzilog_init_kbdms(struct uart_sunzilog_port *up, int channel) +static void __devinit sunzilog_init_kbdms(struct uart_sunzilog_port *up) { int baud, brg; @@ -1305,7 +1305,7 @@ static void __devinit sunzilog_init_hw(struct uart_sunzilog_port *up) up->curregs[R7] = 0x7E; /* SDLC Flag */ up->curregs[R9] = NV; up->curregs[R7p] = 0x00; - sunzilog_init_kbdms(up, up->port.line); + sunzilog_init_kbdms(up); /* Only enable interrupts if an ISR handler available */ if (up->flags & SUNZILOG_FLAG_ISR_HANDLER) up->curregs[R9] |= MIE; diff --git a/drivers/serial/vr41xx_siu.c b/drivers/serial/vr41xx_siu.c index 98ab649c1ff..bb6ce6bba32 100644 --- a/drivers/serial/vr41xx_siu.c +++ b/drivers/serial/vr41xx_siu.c @@ -1,7 +1,7 @@ /* * Driver for NEC VR4100 series Serial Interface Unit. * - * Copyright (C) 2004-2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp> + * Copyright (C) 2004-2008 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp> * * Based on drivers/serial/8250.c, by Russell King. * @@ -840,6 +840,19 @@ static int __devinit siu_console_init(void) console_initcall(siu_console_init); +void __init vr41xx_siu_early_setup(struct uart_port *port) +{ + if (port->type == PORT_UNKNOWN) + return; + + siu_uart_ports[port->line].line = port->line; + siu_uart_ports[port->line].type = port->type; + siu_uart_ports[port->line].uartclk = SIU_BAUD_BASE * 16; + siu_uart_ports[port->line].mapbase = port->mapbase; + siu_uart_ports[port->line].mapbase = port->mapbase; + siu_uart_ports[port->line].ops = &siu_uart_ops; +} + #define SERIAL_VR41XX_CONSOLE &siu_console #else #define SERIAL_VR41XX_CONSOLE NULL diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index d8107890db1..fae9e8f3d09 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -5,11 +5,9 @@ # nobody's needed a slave side API yet. The master-role API is not # fully appropriate there, so it'd need some thought to do well. # -menu "SPI support" - depends on HAS_IOMEM - -config SPI +menuconfig SPI bool "SPI support" + depends on HAS_IOMEM help The "Serial Peripheral Interface" is a low level synchronous protocol. Chips that support SPI can have data transfer rates @@ -28,9 +26,11 @@ config SPI (half duplex), SSP, SSI, and PSP. This driver framework should work with most such devices and controllers. +if SPI + config SPI_DEBUG boolean "Debug support for SPI drivers" - depends on SPI && DEBUG_KERNEL + depends on DEBUG_KERNEL help Say "yes" to enable debug messaging (like dev_dbg and pr_debug), sysfs, and debugfs support in SPI controller and protocol drivers. @@ -245,5 +245,4 @@ config SPI_TLE62X0 # (slave support would go here) -endmenu # "SPI support" - +endif # SPI diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c index 1749a27be06..02c8e305b14 100644 --- a/drivers/spi/atmel_spi.c +++ b/drivers/spi/atmel_spi.c @@ -616,7 +616,7 @@ static int atmel_spi_transfer(struct spi_device *spi, struct spi_message *msg) return -ESHUTDOWN; list_for_each_entry(xfer, &msg->transfers, transfer_list) { - if (!(xfer->tx_buf || xfer->rx_buf)) { + if (!(xfer->tx_buf || xfer->rx_buf) && xfer->len) { dev_dbg(&spi->dev, "missing rx or tx buf\n"); return -EINVAL; } diff --git a/drivers/spi/omap_uwire.c b/drivers/spi/omap_uwire.c index 5f00bd6500e..d9ae111c27a 100644 --- a/drivers/spi/omap_uwire.c +++ b/drivers/spi/omap_uwire.c @@ -151,7 +151,7 @@ static int wait_uwire_csr_flag(u16 mask, u16 val, int might_not_catch) if (time_after(jiffies, max_jiffies)) { printk(KERN_ERR "%s: timeout. reg=%#06x " "mask=%#06x val=%#06x\n", - __FUNCTION__, w, mask, val); + __func__, w, mask, val); return -1; } c++; @@ -437,7 +437,7 @@ static int uwire_setup_transfer(struct spi_device *spi, struct spi_transfer *t) } omap_uwire_configure_mode(spi->chip_select, flags); pr_debug("%s: uwire flags %02x, armxor %lu KHz, SCK %lu KHz\n", - __FUNCTION__, flags, + __func__, flags, clk_get_rate(uwire->ck) / 1000, rate / 1000); status = 0; diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c index 147e26a78d6..654bb58be63 100644 --- a/drivers/spi/pxa2xx_spi.c +++ b/drivers/spi/pxa2xx_spi.c @@ -67,8 +67,11 @@ MODULE_ALIAS("platform:pxa2xx-spi"); | SSCR1_SPH | SSCR1_SPO | SSCR1_LBM) #define DEFINE_SSP_REG(reg, off) \ -static inline u32 read_##reg(void *p) { return __raw_readl(p + (off)); } \ -static inline void write_##reg(u32 v, void *p) { __raw_writel(v, p + (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) @@ -106,7 +109,7 @@ struct driver_data { u32 *null_dma_buf; /* SSP register addresses */ - void *ioaddr; + void __iomem *ioaddr; u32 ssdr_physical; /* SSP masks*/ @@ -173,7 +176,7 @@ static int flush(struct driver_data *drv_data) { unsigned long limit = loops_per_jiffy << 1; - void *reg = drv_data->ioaddr; + void __iomem *reg = drv_data->ioaddr; do { while (read_SSSR(reg) & SSSR_RNE) { @@ -191,7 +194,7 @@ static void null_cs_control(u32 command) static int null_writer(struct driver_data *drv_data) { - void *reg = drv_data->ioaddr; + void __iomem *reg = drv_data->ioaddr; u8 n_bytes = drv_data->n_bytes; if (((read_SSSR(reg) & 0x00000f00) == 0x00000f00) @@ -206,7 +209,7 @@ static int null_writer(struct driver_data *drv_data) static int null_reader(struct driver_data *drv_data) { - void *reg = drv_data->ioaddr; + void __iomem *reg = drv_data->ioaddr; u8 n_bytes = drv_data->n_bytes; while ((read_SSSR(reg) & SSSR_RNE) @@ -220,7 +223,7 @@ static int null_reader(struct driver_data *drv_data) static int u8_writer(struct driver_data *drv_data) { - void *reg = drv_data->ioaddr; + void __iomem *reg = drv_data->ioaddr; if (((read_SSSR(reg) & 0x00000f00) == 0x00000f00) || (drv_data->tx == drv_data->tx_end)) @@ -234,7 +237,7 @@ static int u8_writer(struct driver_data *drv_data) static int u8_reader(struct driver_data *drv_data) { - void *reg = drv_data->ioaddr; + void __iomem *reg = drv_data->ioaddr; while ((read_SSSR(reg) & SSSR_RNE) && (drv_data->rx < drv_data->rx_end)) { @@ -247,7 +250,7 @@ static int u8_reader(struct driver_data *drv_data) static int u16_writer(struct driver_data *drv_data) { - void *reg = drv_data->ioaddr; + void __iomem *reg = drv_data->ioaddr; if (((read_SSSR(reg) & 0x00000f00) == 0x00000f00) || (drv_data->tx == drv_data->tx_end)) @@ -261,7 +264,7 @@ static int u16_writer(struct driver_data *drv_data) static int u16_reader(struct driver_data *drv_data) { - void *reg = drv_data->ioaddr; + void __iomem *reg = drv_data->ioaddr; while ((read_SSSR(reg) & SSSR_RNE) && (drv_data->rx < drv_data->rx_end)) { @@ -274,7 +277,7 @@ static int u16_reader(struct driver_data *drv_data) static int u32_writer(struct driver_data *drv_data) { - void *reg = drv_data->ioaddr; + void __iomem *reg = drv_data->ioaddr; if (((read_SSSR(reg) & 0x00000f00) == 0x00000f00) || (drv_data->tx == drv_data->tx_end)) @@ -288,7 +291,7 @@ static int u32_writer(struct driver_data *drv_data) static int u32_reader(struct driver_data *drv_data) { - void *reg = drv_data->ioaddr; + void __iomem *reg = drv_data->ioaddr; while ((read_SSSR(reg) & SSSR_RNE) && (drv_data->rx < drv_data->rx_end)) { @@ -412,7 +415,7 @@ static void giveback(struct driver_data *drv_data) msg->complete(msg->context); } -static int wait_ssp_rx_stall(void *ioaddr) +static int wait_ssp_rx_stall(void const __iomem *ioaddr) { unsigned long limit = loops_per_jiffy << 1; @@ -432,9 +435,9 @@ static int wait_dma_channel_stop(int channel) return limit; } -void dma_error_stop(struct driver_data *drv_data, const char *msg) +static void dma_error_stop(struct driver_data *drv_data, const char *msg) { - void *reg = drv_data->ioaddr; + void __iomem *reg = drv_data->ioaddr; /* Stop and reset */ DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL; @@ -456,7 +459,7 @@ void dma_error_stop(struct driver_data *drv_data, const char *msg) static void dma_transfer_complete(struct driver_data *drv_data) { - void *reg = drv_data->ioaddr; + void __iomem *reg = drv_data->ioaddr; struct spi_message *msg = drv_data->cur_msg; /* Clear and disable interrupts on SSP and DMA channels*/ @@ -536,7 +539,7 @@ static void dma_handler(int channel, void *data) static irqreturn_t dma_transfer(struct driver_data *drv_data) { u32 irq_status; - void *reg = drv_data->ioaddr; + void __iomem *reg = drv_data->ioaddr; irq_status = read_SSSR(reg) & drv_data->mask_sr; if (irq_status & SSSR_ROR) { @@ -570,7 +573,7 @@ static irqreturn_t dma_transfer(struct driver_data *drv_data) static void int_error_stop(struct driver_data *drv_data, const char* msg) { - void *reg = drv_data->ioaddr; + void __iomem *reg = drv_data->ioaddr; /* Stop and reset SSP */ write_SSSR(drv_data->clear_sr, reg); @@ -588,7 +591,7 @@ static void int_error_stop(struct driver_data *drv_data, const char* msg) static void int_transfer_complete(struct driver_data *drv_data) { - void *reg = drv_data->ioaddr; + void __iomem *reg = drv_data->ioaddr; /* Stop SSP */ write_SSSR(drv_data->clear_sr, reg); @@ -614,7 +617,7 @@ static void int_transfer_complete(struct driver_data *drv_data) static irqreturn_t interrupt_transfer(struct driver_data *drv_data) { - void *reg = drv_data->ioaddr; + void __iomem *reg = drv_data->ioaddr; u32 irq_mask = (read_SSCR1(reg) & SSCR1_TIE) ? drv_data->mask_sr : drv_data->mask_sr & ~SSSR_TFS; @@ -675,7 +678,7 @@ 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 *reg = drv_data->ioaddr; + void __iomem *reg = drv_data->ioaddr; if (!drv_data->cur_msg) { @@ -695,7 +698,8 @@ static irqreturn_t ssp_int(int irq, void *dev_id) return drv_data->transfer_handler(drv_data); } -int set_dma_burst_and_threshold(struct chip_data *chip, struct spi_device *spi, +static int set_dma_burst_and_threshold(struct chip_data *chip, + struct spi_device *spi, u8 bits_per_word, u32 *burst_code, u32 *threshold) { @@ -809,7 +813,7 @@ static void pump_transfers(unsigned long data) struct spi_transfer *previous = NULL; struct chip_data *chip = NULL; struct ssp_device *ssp = drv_data->ssp; - void *reg = drv_data->ioaddr; + void __iomem *reg = drv_data->ioaddr; u32 clk_div = 0; u8 bits = 0; u32 speed = 0; @@ -1338,7 +1342,7 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct pxa2xx_spi_master *platform_info; struct spi_master *master; - struct driver_data *drv_data = 0; + struct driver_data *drv_data = NULL; struct ssp_device *ssp; int status = 0; diff --git a/drivers/spi/spi_bitbang.c b/drivers/spi/spi_bitbang.c index 71e881419cd..96cc39ecb6e 100644 --- a/drivers/spi/spi_bitbang.c +++ b/drivers/spi/spi_bitbang.c @@ -214,7 +214,7 @@ int spi_bitbang_setup(struct spi_device *spi) return retval; dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u nsec/bit\n", - __FUNCTION__, spi->mode & (SPI_CPOL | SPI_CPHA), + __func__, spi->mode & (SPI_CPOL | SPI_CPHA), spi->bits_per_word, 2 * cs->nsecs); /* NOTE we _need_ to call chipselect() early, ideally with adapter diff --git a/drivers/spi/spi_imx.c b/drivers/spi/spi_imx.c index d4ba640366b..c730d05bfeb 100644 --- a/drivers/spi/spi_imx.c +++ b/drivers/spi/spi_imx.c @@ -270,19 +270,26 @@ struct chip_data { static void pump_messages(struct work_struct *work); -static int flush(struct driver_data *drv_data) +static void flush(struct driver_data *drv_data) { - unsigned long limit = loops_per_jiffy << 1; void __iomem *regs = drv_data->regs; - volatile u32 d; + u32 control; dev_dbg(&drv_data->pdev->dev, "flush\n"); + + /* Wait for end of transaction */ do { - while (readl(regs + SPI_INT_STATUS) & SPI_STATUS_RR) - d = readl(regs + SPI_RXDATA); - } while ((readl(regs + SPI_CONTROL) & SPI_CONTROL_XCH) && limit--); + control = readl(regs + SPI_CONTROL); + } while (control & SPI_CONTROL_XCH); + + /* Release chip select if requested, transfer delays are + handled in pump_transfers */ + if (drv_data->cs_change) + drv_data->cs_control(SPI_CS_DEASSERT); - return limit; + /* Disable SPI to flush FIFOs */ + writel(control & ~SPI_CONTROL_SPIEN, regs + SPI_CONTROL); + writel(control, regs + SPI_CONTROL); } static void restore_state(struct driver_data *drv_data) @@ -570,6 +577,7 @@ static void giveback(struct spi_message *message, struct driver_data *drv_data) writel(0, regs + SPI_INT_STATUS); writel(0, regs + SPI_DMA); + /* Unconditioned deselct */ drv_data->cs_control(SPI_CS_DEASSERT); message->state = NULL; @@ -592,13 +600,10 @@ static void dma_err_handler(int channel, void *data, int errcode) /* Disable both rx and tx dma channels */ imx_dma_disable(drv_data->rx_channel); imx_dma_disable(drv_data->tx_channel); - - if (flush(drv_data) == 0) - dev_err(&drv_data->pdev->dev, - "dma_err_handler - flush failed\n"); - unmap_dma_buffers(drv_data); + flush(drv_data); + msg->state = ERROR_STATE; tasklet_schedule(&drv_data->pump_transfers); } @@ -612,8 +617,7 @@ static void dma_tx_handler(int channel, void *data) imx_dma_disable(channel); /* Now waits for TX FIFO empty */ - writel(readl(drv_data->regs + SPI_INT_STATUS) | SPI_INTEN_TE, - drv_data->regs + SPI_INT_STATUS); + writel(SPI_INTEN_TE, drv_data->regs + SPI_INT_STATUS); } static irqreturn_t dma_transfer(struct driver_data *drv_data) @@ -621,19 +625,18 @@ static irqreturn_t dma_transfer(struct driver_data *drv_data) u32 status; struct spi_message *msg = drv_data->cur_msg; void __iomem *regs = drv_data->regs; - unsigned long limit; status = readl(regs + SPI_INT_STATUS); - if ((status & SPI_INTEN_RO) && (status & SPI_STATUS_RO)) { + if ((status & (SPI_INTEN_RO | SPI_STATUS_RO)) + == (SPI_INTEN_RO | SPI_STATUS_RO)) { writel(status & ~SPI_INTEN, regs + SPI_INT_STATUS); + imx_dma_disable(drv_data->tx_channel); imx_dma_disable(drv_data->rx_channel); unmap_dma_buffers(drv_data); - if (flush(drv_data) == 0) - dev_err(&drv_data->pdev->dev, - "dma_transfer - flush failed\n"); + flush(drv_data); dev_warn(&drv_data->pdev->dev, "dma_transfer - fifo overun\n"); @@ -649,20 +652,17 @@ static irqreturn_t dma_transfer(struct driver_data *drv_data) if (drv_data->rx) { /* Wait end of transfer before read trailing data */ - limit = loops_per_jiffy << 1; - while ((readl(regs + SPI_CONTROL) & SPI_CONTROL_XCH) && - limit--); - - if (limit == 0) - dev_err(&drv_data->pdev->dev, - "dma_transfer - end of tx failed\n"); - else - dev_dbg(&drv_data->pdev->dev, - "dma_transfer - end of tx\n"); + while (readl(regs + SPI_CONTROL) & SPI_CONTROL_XCH) + cpu_relax(); imx_dma_disable(drv_data->rx_channel); unmap_dma_buffers(drv_data); + /* Release chip select if requested, transfer delays are + handled in pump_transfers() */ + if (drv_data->cs_change) + drv_data->cs_control(SPI_CS_DEASSERT); + /* Calculate number of trailing data and read them */ dev_dbg(&drv_data->pdev->dev, "dma_transfer - test = 0x%08X\n", @@ -676,19 +676,12 @@ static irqreturn_t dma_transfer(struct driver_data *drv_data) /* Write only transfer */ unmap_dma_buffers(drv_data); - if (flush(drv_data) == 0) - dev_err(&drv_data->pdev->dev, - "dma_transfer - flush failed\n"); + flush(drv_data); } /* End of transfer, update total byte transfered */ msg->actual_length += drv_data->len; - /* Release chip select if requested, transfer delays are - handled in pump_transfers() */ - if (drv_data->cs_change) - drv_data->cs_control(SPI_CS_DEASSERT); - /* Move to next transfer */ msg->state = next_transfer(drv_data); @@ -711,44 +704,43 @@ static irqreturn_t interrupt_wronly_transfer(struct driver_data *drv_data) status = readl(regs + SPI_INT_STATUS); - while (status & SPI_STATUS_TH) { + if (status & SPI_INTEN_TE) { + /* TXFIFO Empty Interrupt on the last transfered word */ + writel(status & ~SPI_INTEN, regs + SPI_INT_STATUS); dev_dbg(&drv_data->pdev->dev, - "interrupt_wronly_transfer - status = 0x%08X\n", status); + "interrupt_wronly_transfer - end of tx\n"); - /* Pump data */ - if (write(drv_data)) { - writel(readl(regs + SPI_INT_STATUS) & ~SPI_INTEN, - regs + SPI_INT_STATUS); + flush(drv_data); - dev_dbg(&drv_data->pdev->dev, - "interrupt_wronly_transfer - end of tx\n"); + /* Update total byte transfered */ + msg->actual_length += drv_data->len; - if (flush(drv_data) == 0) - dev_err(&drv_data->pdev->dev, - "interrupt_wronly_transfer - " - "flush failed\n"); + /* Move to next transfer */ + msg->state = next_transfer(drv_data); - /* End of transfer, update total byte transfered */ - msg->actual_length += drv_data->len; + /* Schedule transfer tasklet */ + tasklet_schedule(&drv_data->pump_transfers); - /* Release chip select if requested, transfer delays are - handled in pump_transfers */ - if (drv_data->cs_change) - drv_data->cs_control(SPI_CS_DEASSERT); + return IRQ_HANDLED; + } else { + while (status & SPI_STATUS_TH) { + dev_dbg(&drv_data->pdev->dev, + "interrupt_wronly_transfer - status = 0x%08X\n", + status); - /* Move to next transfer */ - msg->state = next_transfer(drv_data); + /* Pump data */ + if (write(drv_data)) { + /* End of TXFIFO writes, + now wait until TXFIFO is empty */ + writel(SPI_INTEN_TE, regs + SPI_INT_STATUS); + return IRQ_HANDLED; + } - /* Schedule transfer tasklet */ - tasklet_schedule(&drv_data->pump_transfers); + status = readl(regs + SPI_INT_STATUS); - return IRQ_HANDLED; + /* We did something */ + handled = IRQ_HANDLED; } - - status = readl(regs + SPI_INT_STATUS); - - /* We did something */ - handled = IRQ_HANDLED; } return handled; @@ -758,45 +750,31 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data) { struct spi_message *msg = drv_data->cur_msg; void __iomem *regs = drv_data->regs; - u32 status; + u32 status, control; irqreturn_t handled = IRQ_NONE; unsigned long limit; status = readl(regs + SPI_INT_STATUS); - while (status & (SPI_STATUS_TH | SPI_STATUS_RO)) { + if (status & SPI_INTEN_TE) { + /* TXFIFO Empty Interrupt on the last transfered word */ + writel(status & ~SPI_INTEN, regs + SPI_INT_STATUS); dev_dbg(&drv_data->pdev->dev, - "interrupt_transfer - status = 0x%08X\n", status); - - if (status & SPI_STATUS_RO) { - writel(readl(regs + SPI_INT_STATUS) & ~SPI_INTEN, - regs + SPI_INT_STATUS); - - dev_warn(&drv_data->pdev->dev, - "interrupt_transfer - fifo overun\n" - " data not yet written = %d\n" - " data not yet read = %d\n", - data_to_write(drv_data), - data_to_read(drv_data)); - - if (flush(drv_data) == 0) - dev_err(&drv_data->pdev->dev, - "interrupt_transfer - flush failed\n"); - - msg->state = ERROR_STATE; - tasklet_schedule(&drv_data->pump_transfers); + "interrupt_transfer - end of tx\n"); - return IRQ_HANDLED; - } - - /* Pump data */ - read(drv_data); - if (write(drv_data)) { - writel(readl(regs + SPI_INT_STATUS) & ~SPI_INTEN, - regs + SPI_INT_STATUS); + if (msg->state == ERROR_STATE) { + /* RXFIFO overrun was detected and message aborted */ + flush(drv_data); + } else { + /* Wait for end of transaction */ + do { + control = readl(regs + SPI_CONTROL); + } while (control & SPI_CONTROL_XCH); - dev_dbg(&drv_data->pdev->dev, - "interrupt_transfer - end of tx\n"); + /* Release chip select if requested, transfer delays are + handled in pump_transfers */ + if (drv_data->cs_change) + drv_data->cs_control(SPI_CS_DEASSERT); /* Read trailing bytes */ limit = loops_per_jiffy << 1; @@ -810,27 +788,54 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data) dev_dbg(&drv_data->pdev->dev, "interrupt_transfer - end of rx\n"); - /* End of transfer, update total byte transfered */ + /* Update total byte transfered */ msg->actual_length += drv_data->len; - /* Release chip select if requested, transfer delays are - handled in pump_transfers */ - if (drv_data->cs_change) - drv_data->cs_control(SPI_CS_DEASSERT); - /* Move to next transfer */ msg->state = next_transfer(drv_data); + } - /* Schedule transfer tasklet */ - tasklet_schedule(&drv_data->pump_transfers); + /* Schedule transfer tasklet */ + tasklet_schedule(&drv_data->pump_transfers); - return IRQ_HANDLED; - } + return IRQ_HANDLED; + } else { + while (status & (SPI_STATUS_TH | SPI_STATUS_RO)) { + dev_dbg(&drv_data->pdev->dev, + "interrupt_transfer - status = 0x%08X\n", + status); + + if (status & SPI_STATUS_RO) { + /* RXFIFO overrun, abort message end wait + until TXFIFO is empty */ + writel(SPI_INTEN_TE, regs + SPI_INT_STATUS); + + dev_warn(&drv_data->pdev->dev, + "interrupt_transfer - fifo overun\n" + " data not yet written = %d\n" + " data not yet read = %d\n", + data_to_write(drv_data), + data_to_read(drv_data)); + + msg->state = ERROR_STATE; + + return IRQ_HANDLED; + } - status = readl(regs + SPI_INT_STATUS); + /* Pump data */ + read(drv_data); + if (write(drv_data)) { + /* End of TXFIFO writes, + now wait until TXFIFO is empty */ + writel(SPI_INTEN_TE, regs + SPI_INT_STATUS); + return IRQ_HANDLED; + } - /* We did something */ - handled = IRQ_HANDLED; + status = readl(regs + SPI_INT_STATUS); + + /* We did something */ + handled = IRQ_HANDLED; + } } return handled; diff --git a/drivers/spi/spi_mpc83xx.c b/drivers/spi/spi_mpc83xx.c index be15a621320..189f706b9e4 100644 --- a/drivers/spi/spi_mpc83xx.c +++ b/drivers/spi/spi_mpc83xx.c @@ -310,7 +310,7 @@ static int mpc83xx_spi_setup(struct spi_device *spi) return retval; dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u nsec\n", - __FUNCTION__, spi->mode & (SPI_CPOL | SPI_CPHA), + __func__, spi->mode & (SPI_CPOL | SPI_CPHA), spi->bits_per_word, 2 * mpc83xx_spi->nsecs); /* NOTE we _need_ to call chipselect() early, ideally with adapter diff --git a/drivers/spi/spi_s3c24xx.c b/drivers/spi/spi_s3c24xx.c index b7476b88819..34bfb7dd776 100644 --- a/drivers/spi/spi_s3c24xx.c +++ b/drivers/spi/spi_s3c24xx.c @@ -169,7 +169,7 @@ static int s3c24xx_spi_setup(struct spi_device *spi) } dev_dbg(&spi->dev, "%s: mode %d, %u bpw, %d hz\n", - __FUNCTION__, spi->mode, spi->bits_per_word, + __func__, spi->mode, spi->bits_per_word, spi->max_speed_hz); return 0; diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c index cf6aef34fe2..113a0468ffc 100644 --- a/drivers/spi/xilinx_spi.c +++ b/drivers/spi/xilinx_spi.c @@ -151,13 +151,13 @@ static int xilinx_spi_setup_transfer(struct spi_device *spi, hz = (t) ? t->speed_hz : spi->max_speed_hz; if (bits_per_word != 8) { dev_err(&spi->dev, "%s, unsupported bits_per_word=%d\n", - __FUNCTION__, bits_per_word); + __func__, bits_per_word); return -EINVAL; } if (hz && xspi->speed_hz > hz) { dev_err(&spi->dev, "%s, unsupported clock rate %uHz\n", - __FUNCTION__, hz); + __func__, hz); return -EINVAL; } @@ -181,7 +181,7 @@ static int xilinx_spi_setup(struct spi_device *spi) if (spi->mode & ~MODEBITS) { dev_err(&spi->dev, "%s, unsupported mode bits %x\n", - __FUNCTION__, spi->mode & ~MODEBITS); + __func__, spi->mode & ~MODEBITS); return -EINVAL; } @@ -190,7 +190,7 @@ static int xilinx_spi_setup(struct spi_device *spi) return retval; dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u nsec/bit\n", - __FUNCTION__, spi->mode & MODEBITS, spi->bits_per_word, 0); + __func__, spi->mode & MODEBITS, spi->bits_per_word, 0); return 0; } diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c index d470c72b737..5ea3093bc40 100644 --- a/drivers/usb/atm/cxacru.c +++ b/drivers/usb/atm/cxacru.c @@ -38,6 +38,7 @@ #include <linux/device.h> #include <linux/firmware.h> #include <linux/mutex.h> +#include <asm/unaligned.h> #include "usbatm.h" @@ -573,7 +574,7 @@ static int cxacru_cm_get_array(struct cxacru_data *instance, enum cxacru_cm_requ u32 *data, int size) { int ret, len; - u32 *buf; + __le32 *buf; int offb, offd; const int stride = CMD_PACKET_SIZE / (4 * 2) - 1; int buflen = ((size - 1) / stride + 1 + size * 2) * 4; @@ -837,7 +838,7 @@ static int cxacru_fw(struct usb_device *usb_dev, enum cxacru_fw_request fw, buf[offb++] = l; buf[offb++] = code1; buf[offb++] = code2; - *((u32 *) (buf + offb)) = cpu_to_le32(addr); + put_unaligned(cpu_to_le32(addr), (__le32 *)(buf + offb)); offb += 4; addr += l; if(l) @@ -874,8 +875,9 @@ static void cxacru_upload_firmware(struct cxacru_data *instance, int off; struct usbatm_data *usbatm = instance->usbatm; struct usb_device *usb_dev = usbatm->usb_dev; - u16 signature[] = { usb_dev->descriptor.idVendor, usb_dev->descriptor.idProduct }; - u32 val; + __le16 signature[] = { usb_dev->descriptor.idVendor, + usb_dev->descriptor.idProduct }; + __le32 val; dbg("cxacru_upload_firmware"); @@ -955,7 +957,7 @@ static void cxacru_upload_firmware(struct cxacru_data *instance, /* Load config data (le32), doing one packet at a time */ if (cf) for (off = 0; off < cf->size / 4; ) { - u32 buf[CMD_PACKET_SIZE / 4 - 1]; + __le32 buf[CMD_PACKET_SIZE / 4 - 1]; int i, len = min_t(int, cf->size / 4 - off, CMD_PACKET_SIZE / 4 / 2 - 1); buf[0] = cpu_to_le32(len); for (i = 0; i < len; i++, off++) { diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index abb7d7410e6..5f71ff3aee3 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -305,8 +305,6 @@ enum { */ #define FW_GET_BYTE(p) *((__u8 *) (p)) -#define FW_GET_WORD(p) le16_to_cpu(get_unaligned((__le16 *) (p))) -#define FW_GET_LONG(p) le32_to_cpu(get_unaligned((__le32 *) (p))) #define FW_DIR "ueagle-atm/" #define NB_MODEM 4 @@ -621,7 +619,7 @@ static void uea_upload_pre_firmware(const struct firmware *fw_entry, void *conte if (size < 4) goto err_fw_corrupted; - crc = FW_GET_LONG(pfw); + crc = get_unaligned_le32(pfw); pfw += 4; size -= 4; if (crc32_be(0, pfw, size) != crc) @@ -640,7 +638,7 @@ static void uea_upload_pre_firmware(const struct firmware *fw_entry, void *conte while (size > 3) { u8 len = FW_GET_BYTE(pfw); - u16 add = FW_GET_WORD(pfw + 1); + u16 add = get_unaligned_le16(pfw + 1); size -= len + 3; if (size < 0) @@ -738,7 +736,7 @@ static int check_dsp_e1(u8 *dsp, unsigned int len) for (i = 0; i < pagecount; i++) { - pageoffset = FW_GET_LONG(dsp + p); + pageoffset = get_unaligned_le32(dsp + p); p += 4; if (pageoffset == 0) @@ -759,7 +757,7 @@ static int check_dsp_e1(u8 *dsp, unsigned int len) return 1; pp += 2; /* skip blockaddr */ - blocksize = FW_GET_WORD(dsp + pp); + blocksize = get_unaligned_le16(dsp + pp); pp += 2; /* enough space for block data? */ @@ -928,7 +926,7 @@ static void uea_load_page_e1(struct work_struct *work) goto bad1; p += 4 * pageno; - pageoffset = FW_GET_LONG(p); + pageoffset = get_unaligned_le32(p); if (pageoffset == 0) goto bad1; @@ -945,10 +943,10 @@ static void uea_load_page_e1(struct work_struct *work) bi.wOvlOffset = cpu_to_le16(ovl | 0x8000); for (i = 0; i < blockcount; i++) { - blockaddr = FW_GET_WORD(p); + blockaddr = get_unaligned_le16(p); p += 2; - blocksize = FW_GET_WORD(p); + blocksize = get_unaligned_le16(p); p += 2; bi.wSize = cpu_to_le16(blocksize); @@ -996,7 +994,7 @@ static void __uea_load_page_e4(struct uea_softc *sc, u8 pageno, int boot) blockoffset = sc->dsp_firm->data + le32_to_cpu(blockidx->PageOffset); bi.dwSize = cpu_to_be32(blocksize); - bi.dwAddress = swab32(blockidx->PageAddress); + bi.dwAddress = cpu_to_be32(le32_to_cpu(blockidx->PageAddress)); uea_dbg(INS_TO_USBDEV(sc), "sending block %u for DSP page %u size %u address %x\n", @@ -1040,7 +1038,7 @@ static void uea_load_page_e4(struct work_struct *work) return; p = (struct l1_code *) sc->dsp_firm->data; - if (pageno >= p->page_header[0].PageNumber) { + if (pageno >= le16_to_cpu(p->page_header[0].PageNumber)) { uea_err(INS_TO_USBDEV(sc), "invalid DSP page %u requested\n", pageno); return; } @@ -1065,7 +1063,7 @@ static void uea_load_page_e4(struct work_struct *work) bi.bPageNumber = 0xff; bi.wReserved = cpu_to_be16(UEA_RESERVED); bi.dwSize = cpu_to_be32(E4_PAGE_BYTES(p->page_header[0].PageSize)); - bi.dwAddress = swab32(p->page_header[0].PageAddress); + bi.dwAddress = cpu_to_be32(le32_to_cpu(p->page_header[0].PageAddress)); /* send block info through the IDMA pipe */ if (uea_idma_write(sc, &bi, E4_BLOCK_INFO_SIZE)) @@ -1152,9 +1150,9 @@ static int uea_cmv_e1(struct uea_softc *sc, cmv.bDirection = E1_HOSTTOMODEM; cmv.bFunction = function; cmv.wIndex = cpu_to_le16(sc->cmv_dsc.e1.idx); - put_unaligned(cpu_to_le32(address), &cmv.dwSymbolicAddress); + put_unaligned_le32(address, &cmv.dwSymbolicAddress); cmv.wOffsetAddress = cpu_to_le16(offset); - put_unaligned(cpu_to_le32(data >> 16 | data << 16), &cmv.dwData); + put_unaligned_le32(data >> 16 | data << 16, &cmv.dwData); ret = uea_request(sc, UEA_E1_SET_BLOCK, UEA_MPTX_START, sizeof(cmv), &cmv); if (ret < 0) @@ -1646,7 +1644,7 @@ static int request_cmvs(struct uea_softc *sc, if (size < 5) goto err_fw_corrupted; - crc = FW_GET_LONG(data); + crc = get_unaligned_le32(data); data += 4; size -= 4; if (crc32_be(0, data, size) != crc) @@ -1696,9 +1694,9 @@ static int uea_send_cmvs_e1(struct uea_softc *sc) "please update your firmware\n"); for (i = 0; i < len; i++) { - ret = uea_write_cmv_e1(sc, FW_GET_LONG(&cmvs_v1[i].address), - FW_GET_WORD(&cmvs_v1[i].offset), - FW_GET_LONG(&cmvs_v1[i].data)); + ret = uea_write_cmv_e1(sc, get_unaligned_le32(&cmvs_v1[i].address), + get_unaligned_le16(&cmvs_v1[i].offset), + get_unaligned_le32(&cmvs_v1[i].data)); if (ret < 0) goto out; } @@ -1706,9 +1704,9 @@ static int uea_send_cmvs_e1(struct uea_softc *sc) struct uea_cmvs_v2 *cmvs_v2 = cmvs_ptr; for (i = 0; i < len; i++) { - ret = uea_write_cmv_e1(sc, FW_GET_LONG(&cmvs_v2[i].address), - (u16) FW_GET_LONG(&cmvs_v2[i].offset), - FW_GET_LONG(&cmvs_v2[i].data)); + ret = uea_write_cmv_e1(sc, get_unaligned_le32(&cmvs_v2[i].address), + (u16) get_unaligned_le32(&cmvs_v2[i].offset), + get_unaligned_le32(&cmvs_v2[i].data)); if (ret < 0) goto out; } @@ -1759,10 +1757,10 @@ static int uea_send_cmvs_e4(struct uea_softc *sc) for (i = 0; i < len; i++) { ret = uea_write_cmv_e4(sc, 1, - FW_GET_LONG(&cmvs_v2[i].group), - FW_GET_LONG(&cmvs_v2[i].address), - FW_GET_LONG(&cmvs_v2[i].offset), - FW_GET_LONG(&cmvs_v2[i].data)); + get_unaligned_le32(&cmvs_v2[i].group), + get_unaligned_le32(&cmvs_v2[i].address), + get_unaligned_le32(&cmvs_v2[i].offset), + get_unaligned_le32(&cmvs_v2[i].data)); if (ret < 0) goto out; } @@ -1964,7 +1962,7 @@ static void uea_dispatch_cmv_e1(struct uea_softc *sc, struct intr_pkt *intr) if (UEA_CHIP_VERSION(sc) == ADI930 && cmv->bFunction == E1_MAKEFUNCTION(2, 2)) { cmv->wIndex = cpu_to_le16(dsc->idx); - put_unaligned(cpu_to_le32(dsc->address), &cmv->dwSymbolicAddress); + put_unaligned_le32(dsc->address, &cmv->dwSymbolicAddress); cmv->wOffsetAddress = cpu_to_le16(dsc->offset); } else goto bad2; @@ -1978,11 +1976,11 @@ static void uea_dispatch_cmv_e1(struct uea_softc *sc, struct intr_pkt *intr) /* in case of MEMACCESS */ if (le16_to_cpu(cmv->wIndex) != dsc->idx || - le32_to_cpu(get_unaligned(&cmv->dwSymbolicAddress)) != dsc->address || + get_unaligned_le32(&cmv->dwSymbolicAddress) != dsc->address || le16_to_cpu(cmv->wOffsetAddress) != dsc->offset) goto bad2; - sc->data = le32_to_cpu(get_unaligned(&cmv->dwData)); + sc->data = get_unaligned_le32(&cmv->dwData); sc->data = sc->data << 16 | sc->data >> 16; wake_up_cmv_ack(sc); diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 7b572e75e73..cefe7f2c6f7 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -280,7 +280,7 @@ static void acm_ctrl_irq(struct urb *urb) case USB_CDC_NOTIFY_SERIAL_STATE: - newctrl = le16_to_cpu(get_unaligned((__le16 *) data)); + newctrl = get_unaligned_le16(data); if (acm->tty && !acm->clocal && (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) { dbg("calling hangup"); diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c index 8607846e3c3..1d253dd4ea8 100644 --- a/drivers/usb/core/inode.c +++ b/drivers/usb/core/inode.c @@ -773,7 +773,7 @@ int __init usbfs_init(void) usb_register_notify(&usbfs_nb); /* create mount point for usbfs */ - usbdir = proc_mkdir("usb", proc_bus); + usbdir = proc_mkdir("bus/usb", NULL); return 0; } @@ -783,6 +783,6 @@ void usbfs_cleanup(void) usb_unregister_notify(&usbfs_nb); unregister_filesystem(&usb_fs_type); if (usbdir) - remove_proc_entry("usb", proc_bus); + remove_proc_entry("bus/usb", NULL); } diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c index fc6f3483be4..ce337cb5d13 100644 --- a/drivers/usb/gadget/amd5536udc.c +++ b/drivers/usb/gadget/amd5536udc.c @@ -328,6 +328,7 @@ udc_ep_enable(struct usb_ep *usbep, const struct usb_endpoint_descriptor *desc) u32 tmp; unsigned long iflags; u8 udc_csr_epix; + unsigned maxpacket; if (!usbep || usbep->name == ep0_string @@ -354,9 +355,10 @@ udc_ep_enable(struct usb_ep *usbep, const struct usb_endpoint_descriptor *desc) writel(tmp, &dev->ep[ep->num].regs->ctl); /* set max packet size */ + maxpacket = le16_to_cpu(desc->wMaxPacketSize); tmp = readl(&dev->ep[ep->num].regs->bufout_maxpkt); - tmp = AMD_ADDBITS(tmp, desc->wMaxPacketSize, UDC_EP_MAX_PKT_SIZE); - ep->ep.maxpacket = desc->wMaxPacketSize; + tmp = AMD_ADDBITS(tmp, maxpacket, UDC_EP_MAX_PKT_SIZE); + ep->ep.maxpacket = maxpacket; writel(tmp, &dev->ep[ep->num].regs->bufout_maxpkt); /* IN ep */ @@ -370,8 +372,8 @@ udc_ep_enable(struct usb_ep *usbep, const struct usb_endpoint_descriptor *desc) /* double buffering: fifo size = 2 x max packet size */ tmp = AMD_ADDBITS( tmp, - desc->wMaxPacketSize * UDC_EPIN_BUFF_SIZE_MULT - / UDC_DWORD_BYTES, + maxpacket * UDC_EPIN_BUFF_SIZE_MULT + / UDC_DWORD_BYTES, UDC_EPIN_BUFF_SIZE); writel(tmp, &dev->ep[ep->num].regs->bufin_framenum); @@ -390,7 +392,7 @@ udc_ep_enable(struct usb_ep *usbep, const struct usb_endpoint_descriptor *desc) /* set max packet size UDC CSR */ tmp = readl(&dev->csr->ne[ep->num - UDC_CSR_EP_OUT_IX_OFS]); - tmp = AMD_ADDBITS(tmp, desc->wMaxPacketSize, + tmp = AMD_ADDBITS(tmp, maxpacket, UDC_CSR_NE_MAX_PKT); writel(tmp, &dev->csr->ne[ep->num - UDC_CSR_EP_OUT_IX_OFS]); @@ -407,7 +409,7 @@ udc_ep_enable(struct usb_ep *usbep, const struct usb_endpoint_descriptor *desc) /* set ep values */ tmp = readl(&dev->csr->ne[udc_csr_epix]); /* max packet */ - tmp = AMD_ADDBITS(tmp, desc->wMaxPacketSize, UDC_CSR_NE_MAX_PKT); + tmp = AMD_ADDBITS(tmp, maxpacket, UDC_CSR_NE_MAX_PKT); /* ep number */ tmp = AMD_ADDBITS(tmp, desc->bEndpointAddress, UDC_CSR_NE_NUM); /* ep direction */ @@ -2832,7 +2834,7 @@ __acquires(dev->lock) /* make usb request for gadget driver */ memset(&setup_data, 0 , sizeof(union udc_setup_data)); setup_data.request.bRequest = USB_REQ_SET_CONFIGURATION; - setup_data.request.wValue = dev->cur_config; + setup_data.request.wValue = cpu_to_le16(dev->cur_config); /* programm the NE registers */ for (i = 0; i < UDC_EP_NUM; i++) { @@ -2881,8 +2883,8 @@ __acquires(dev->lock) memset(&setup_data, 0 , sizeof(union udc_setup_data)); setup_data.request.bRequest = USB_REQ_SET_INTERFACE; setup_data.request.bRequestType = USB_RECIP_INTERFACE; - setup_data.request.wValue = dev->cur_alt; - setup_data.request.wIndex = dev->cur_intf; + setup_data.request.wValue = cpu_to_le16(dev->cur_alt); + setup_data.request.wIndex = cpu_to_le16(dev->cur_intf); DBG(dev, "SET_INTERFACE interrupt: alt=%d intf=%d\n", dev->cur_alt, dev->cur_intf); diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index 9b913afb2e6..274c60a970c 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -231,6 +231,7 @@ static int proc_udc_open(struct inode *inode, struct file *file) } static const struct file_operations proc_ops = { + .owner = THIS_MODULE, .open = proc_udc_open, .read = seq_read, .llseek = seq_lseek, @@ -239,15 +240,7 @@ static const struct file_operations proc_ops = { static void create_debug_file(struct at91_udc *udc) { - struct proc_dir_entry *pde; - - pde = create_proc_entry (debug_filename, 0, NULL); - udc->pde = pde; - if (pde == NULL) - return; - - pde->proc_fops = &proc_ops; - pde->data = udc; + udc->pde = proc_create_data(debug_filename, 0, NULL, &proc_ops, udc); } static void remove_debug_file(struct at91_udc *udc) diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 66293105d13..42036192a03 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -1555,8 +1555,7 @@ hub_descriptor (struct usb_hub_descriptor *desc) memset (desc, 0, sizeof *desc); desc->bDescriptorType = 0x29; desc->bDescLength = 9; - desc->wHubCharacteristics = (__force __u16) - (__constant_cpu_to_le16 (0x0001)); + desc->wHubCharacteristics = cpu_to_le16(0x0001); desc->bNbrPorts = 1; desc->bitmap [0] = 0xff; desc->bitmap [1] = 0xff; diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c index ff3a8513e64..7f4d4828e3a 100644 --- a/drivers/usb/gadget/gmidi.c +++ b/drivers/usb/gadget/gmidi.c @@ -229,7 +229,7 @@ static const struct usb_ac_header_descriptor_1 ac_header_desc = { .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = USB_MS_HEADER, .bcdADC = __constant_cpu_to_le16(0x0100), - .wTotalLength = USB_DT_AC_HEADER_SIZE(1), + .wTotalLength = __constant_cpu_to_le16(USB_DT_AC_HEADER_SIZE(1)), .bInCollection = 1, .baInterfaceNr = { [0] = GMIDI_MS_INTERFACE, @@ -253,9 +253,9 @@ static const struct usb_ms_header_descriptor ms_header_desc = { .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = USB_MS_HEADER, .bcdMSC = __constant_cpu_to_le16(0x0100), - .wTotalLength = USB_DT_MS_HEADER_SIZE + .wTotalLength = __constant_cpu_to_le16(USB_DT_MS_HEADER_SIZE + 2*USB_DT_MIDI_IN_SIZE - + 2*USB_DT_MIDI_OUT_SIZE(1), + + 2*USB_DT_MIDI_OUT_SIZE(1)), }; #define JACK_IN_EMB 1 diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index 64a592cbbe7..be6613afedb 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -127,7 +127,7 @@ goku_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) /* enabling the no-toggle interrupt mode would need an api hook */ mode = 0; - max = le16_to_cpu(get_unaligned(&desc->wMaxPacketSize)); + max = get_unaligned_le16(&desc->wMaxPacketSize); switch (max) { case 64: mode++; case 32: mode++; diff --git a/drivers/usb/gadget/m66592-udc.h b/drivers/usb/gadget/m66592-udc.h index be0a4c1f80a..f118f00f146 100644 --- a/drivers/usb/gadget/m66592-udc.h +++ b/drivers/usb/gadget/m66592-udc.h @@ -485,7 +485,7 @@ struct m66592 { struct m66592_ep *epaddr2ep[16]; struct usb_request *ep0_req; /* for internal request */ - u16 ep0_data; /* for internal request */ + __le16 ep0_data; /* for internal request */ u16 old_vbus; struct timer_list timer; diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index 95f7662376f..881d74c3d96 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -2504,6 +2504,7 @@ static int proc_udc_open(struct inode *inode, struct file *file) } static const struct file_operations proc_ops = { + .owner = THIS_MODULE, .open = proc_udc_open, .read = seq_read, .llseek = seq_lseek, @@ -2512,11 +2513,7 @@ static const struct file_operations proc_ops = { static void create_proc_file(void) { - struct proc_dir_entry *pde; - - pde = create_proc_entry (proc_filename, 0, NULL); - if (pde) - pde->proc_fops = &proc_ops; + proc_create(proc_filename, 0, NULL, &proc_ops); } static void remove_proc_file(void) diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c index bd58dd504f6..d0677f5d3cd 100644 --- a/drivers/usb/gadget/rndis.c +++ b/drivers/usb/gadget/rndis.c @@ -183,14 +183,10 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, DBG("query OID %08x value, len %d:\n", OID, buf_len); for (i = 0; i < buf_len; i += 16) { DBG("%03d: %08x %08x %08x %08x\n", i, - le32_to_cpu(get_unaligned((__le32 *) - &buf[i])), - le32_to_cpu(get_unaligned((__le32 *) - &buf[i + 4])), - le32_to_cpu(get_unaligned((__le32 *) - &buf[i + 8])), - le32_to_cpu(get_unaligned((__le32 *) - &buf[i + 12]))); + get_unaligned_le32(&buf[i]), + get_unaligned_le32(&buf[i + 4]), + get_unaligned_le32(&buf[i + 8]), + get_unaligned_le32(&buf[i + 12])); } } @@ -666,7 +662,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, break; case OID_PNP_QUERY_POWER: DBG("%s: OID_PNP_QUERY_POWER D%d\n", __func__, - le32_to_cpu(get_unaligned((__le32 *)buf)) - 1); + get_unaligned_le32(buf) - 1); /* only suspend is a real power state, and * it can't be entered by OID_PNP_SET_POWER... */ @@ -705,14 +701,10 @@ static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len, DBG("set OID %08x value, len %d:\n", OID, buf_len); for (i = 0; i < buf_len; i += 16) { DBG("%03d: %08x %08x %08x %08x\n", i, - le32_to_cpu(get_unaligned((__le32 *) - &buf[i])), - le32_to_cpu(get_unaligned((__le32 *) - &buf[i + 4])), - le32_to_cpu(get_unaligned((__le32 *) - &buf[i + 8])), - le32_to_cpu(get_unaligned((__le32 *) - &buf[i + 12]))); + get_unaligned_le32(&buf[i]), + get_unaligned_le32(&buf[i + 4]), + get_unaligned_le32(&buf[i + 8]), + get_unaligned_le32(&buf[i + 12])); } } @@ -726,8 +718,7 @@ static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len, * PROMISCUOUS, DIRECTED, * MULTICAST, ALL_MULTICAST, BROADCAST */ - *params->filter = (u16) le32_to_cpu(get_unaligned( - (__le32 *)buf)); + *params->filter = (u16)get_unaligned_le32(buf); DBG("%s: OID_GEN_CURRENT_PACKET_FILTER %08x\n", __func__, *params->filter); @@ -777,7 +768,7 @@ update_linkstate: * resuming, Windows forces a reset, and then SET_POWER D0. * FIXME ... then things go batty; Windows wedges itself. */ - i = le32_to_cpu(get_unaligned((__le32 *)buf)); + i = get_unaligned_le32(buf); DBG("%s: OID_PNP_SET_POWER D%d\n", __func__, i - 1); switch (i) { case NdisDeviceStateD0: @@ -1064,8 +1055,8 @@ int rndis_msg_parser (u8 configNr, u8 *buf) return -ENOMEM; tmp = (__le32 *) buf; - MsgType = le32_to_cpu(get_unaligned(tmp++)); - MsgLength = le32_to_cpu(get_unaligned(tmp++)); + MsgType = get_unaligned_le32(tmp++); + MsgLength = get_unaligned_le32(tmp++); if (configNr >= RNDIS_MAX_CONFIGS) return -ENOTSUPP; @@ -1296,10 +1287,9 @@ int rndis_rm_hdr(struct sk_buff *skb) tmp++; /* DataOffset, DataLength */ - if (!skb_pull(skb, le32_to_cpu(get_unaligned(tmp++)) - + 8 /* offset of DataOffset */)) + if (!skb_pull(skb, get_unaligned_le32(tmp++) + 8)) return -EOVERFLOW; - skb_trim(skb, le32_to_cpu(get_unaligned(tmp++))); + skb_trim(skb, get_unaligned_le32(tmp++)); return 0; } diff --git a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c index 878e428a0ec..4154be375c7 100644 --- a/drivers/usb/gadget/usbstring.c +++ b/drivers/usb/gadget/usbstring.c @@ -74,7 +74,7 @@ static int utf8_to_utf16le(const char *s, __le16 *cp, unsigned len) goto fail; } else uchar = c; - put_unaligned (cpu_to_le16 (uchar), cp++); + put_unaligned_le16(uchar, cp++); count++; len--; } diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index 4af90df8e7d..0f82fdcaef0 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c @@ -398,7 +398,7 @@ static void qh_lines ( unsigned size = *sizep; char *next = *nextp; char mark; - u32 list_end = EHCI_LIST_END(ehci); + __le32 list_end = EHCI_LIST_END(ehci); if (qh->hw_qtd_next == list_end) /* NEC does this */ mark = '@'; diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index efffef64f59..382587c4457 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -530,7 +530,7 @@ ehci_hub_descriptor ( if (HCS_INDICATOR (ehci->hcs_params)) temp |= 0x0080; /* per-port indicators (LEDs) */ #endif - desc->wHubCharacteristics = (__force __u16)cpu_to_le16 (temp); + desc->wHubCharacteristics = cpu_to_le16(temp); } /*-------------------------------------------------------------------------*/ @@ -770,7 +770,7 @@ static int ehci_hub_control ( if (status & ~0xffff) /* only if wPortChange is interesting */ #endif dbg_port (ehci, "GetStatus", wIndex + 1, temp); - put_unaligned(cpu_to_le32 (status), (__le32 *) buf); + put_unaligned_le32(status, buf); break; case SetHubFeature: switch (wValue) { diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 5ae689139dd..b85b54160cd 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -285,7 +285,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) int stopped; unsigned count = 0; u8 state; - u32 halt = HALT_BIT(ehci); + __le32 halt = HALT_BIT(ehci); if (unlikely (list_empty (&qh->qtd_list))) return count; @@ -883,7 +883,7 @@ static struct ehci_qh *qh_append_tds ( ) { struct ehci_qh *qh = NULL; - u32 qh_addr_mask = cpu_to_hc32(ehci, 0x7f); + __hc32 qh_addr_mask = cpu_to_hc32(ehci, 0x7f); qh = (struct ehci_qh *) *ptr; if (unlikely (qh == NULL)) { diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index 5be3bb3e6a9..17dc2eccda8 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c @@ -736,14 +736,14 @@ static int ohci_hub_control ( break; case GetHubStatus: temp = roothub_status (ohci) & ~(RH_HS_CRWE | RH_HS_DRWE); - put_unaligned(cpu_to_le32 (temp), (__le32 *) buf); + put_unaligned_le32(temp, buf); break; case GetPortStatus: if (!wIndex || wIndex > ports) goto error; wIndex--; temp = roothub_portstatus (ohci, wIndex); - put_unaligned(cpu_to_le32 (temp), (__le32 *) buf); + put_unaligned_le32(temp, buf); #ifndef OHCI_VERBOSE_DEBUG if (*(u16*)(buf+2)) /* only if wPortChange is interesting */ diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index f4fa93dabdd..16667342b3c 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -993,7 +993,7 @@ static void prepare_setup_packet(struct r8a66597 *r8a66597, struct r8a66597_td *td) { int i; - u16 *p = (u16 *)td->urb->setup_packet; + __le16 *p = (__le16 *)td->urb->setup_packet; unsigned long setup_addr = USBREQ; r8a66597_write(r8a66597, make_devsel(td->address) | td->maxpacket, @@ -1001,7 +1001,7 @@ static void prepare_setup_packet(struct r8a66597 *r8a66597, r8a66597_write(r8a66597, ~(SIGN | SACK), INTSTS1); for (i = 0; i < 4; i++) { - r8a66597_write(r8a66597, cpu_to_le16(p[i]), setup_addr); + r8a66597_write(r8a66597, le16_to_cpu(p[i]), setup_addr); setup_addr += 2; } r8a66597_write(r8a66597, SUREQ, DCPCTR); @@ -2131,7 +2131,7 @@ static int r8a66597_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, case GetPortStatus: if (wIndex > R8A66597_MAX_ROOT_HUB) goto error; - *(u32 *)buf = cpu_to_le32(rh->port); + *(__le32 *)buf = cpu_to_le32(rh->port); break; case SetPortFeature: if (wIndex > R8A66597_MAX_ROOT_HUB) diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index 274276cf862..426575247b2 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -1100,7 +1100,7 @@ sl811h_hub_descriptor ( /* no overcurrent errors detection/handling */ temp |= 0x0010; - desc->wHubCharacteristics = (__force __u16)cpu_to_le16(temp); + desc->wHubCharacteristics = cpu_to_le16(temp); /* two bitmaps: ports removable, and legacy PortPwrCtrlMask */ desc->bitmap[0] = 0 << 1; @@ -1506,15 +1506,7 @@ static const char proc_filename[] = "driver/sl811h"; static void create_debug_file(struct sl811 *sl811) { - struct proc_dir_entry *pde; - - pde = create_proc_entry(proc_filename, 0, NULL); - if (pde == NULL) - return; - - pde->proc_fops = &proc_ops; - pde->data = sl811; - sl811->pde = pde; + sl811->pde = proc_create_data(proc_filename, 0, NULL, &proc_ops, sl811); } static void remove_debug_file(struct sl811 *sl811) diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c index a238817762a..9b1bb347dc2 100644 --- a/drivers/usb/serial/aircable.c +++ b/drivers/usb/serial/aircable.c @@ -209,7 +209,7 @@ static void aircable_send(struct usb_serial_port *port) int count, result; struct aircable_private *priv = usb_get_serial_port_data(port); unsigned char* buf; - u16 *dbuf; + __le16 *dbuf; dbg("%s - port %d", __func__, port->number); if (port->write_urb_busy) return; @@ -227,7 +227,7 @@ static void aircable_send(struct usb_serial_port *port) buf[0] = TX_HEADER_0; buf[1] = TX_HEADER_1; - dbuf = (u16 *)&buf[2]; + dbuf = (__le16 *)&buf[2]; *dbuf = cpu_to_le16((u16)count); serial_buf_get(priv->tx_buf,buf + HCI_HEADER_LENGTH, MAX_HCI_FRAMESIZE); diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index 32121794808..0230d3c0888 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -541,7 +541,7 @@ static int cypress_earthmate_startup (struct usb_serial *serial) /* All Earthmate devices use the separated-count packet format! Idiotic. */ priv->pkt_fmt = packet_format_1; - if (serial->dev->descriptor.idProduct != PRODUCT_ID_EARTHMATEUSB) { + if (serial->dev->descriptor.idProduct != cpu_to_le16(PRODUCT_ID_EARTHMATEUSB)) { /* The old original USB Earthmate seemed able to handle GET_CONFIG requests; everything they've produced since that time crashes if this command is diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 23f51a41093..c7329f43d9c 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1104,7 +1104,7 @@ static int ftdi_mtxorb_hack_setup(struct usb_serial *serial) struct usb_endpoint_descriptor *ep_desc = &ep->desc; if (ep->enabled && ep_desc->wMaxPacketSize == 0) { - ep_desc->wMaxPacketSize = 0x40; + ep_desc->wMaxPacketSize = cpu_to_le16(0x40); info("Fixing invalid wMaxPacketSize on read pipe"); } diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index ce2e487f324..06b52f4098f 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -2993,7 +2993,7 @@ static int edge_startup (struct usb_serial *serial) usb_fill_bulk_urb(edge_serial->read_urb, dev, usb_rcvbulkpipe(dev, endpoint->bEndpointAddress), edge_serial->bulk_in_buffer, - endpoint->wMaxPacketSize, + le16_to_cpu(endpoint->wMaxPacketSize), edge_bulk_in_callback, edge_serial); bulk_in_found = true; diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index b395ac75988..f328948d74e 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -54,6 +54,7 @@ #include <linux/tty_flip.h> #include <linux/module.h> #include <asm/uaccess.h> +#include <asm/unaligned.h> #include <linux/usb.h> #include <linux/usb/serial.h> #include "kl5kusb105.h" @@ -235,7 +236,7 @@ static int klsi_105_get_line_state(struct usb_serial_port *port, if (rc < 0) err("Reading line status failed (error = %d)", rc); else { - status = le16_to_cpu(*(u16 *)status_buf); + status = le16_to_cpu(get_unaligned((__le16 *)status_buf)); info("%s - read status %x %x", __func__, status_buf[0], status_buf[1]); diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c index d92bb6501c8..a9625c180dc 100644 --- a/drivers/usb/serial/oti6858.c +++ b/drivers/usb/serial/oti6858.c @@ -98,7 +98,7 @@ struct oti6858_buf { /* format of the control packet */ struct oti6858_control_pkt { - u16 divisor; /* baud rate = 96000000 / (16 * divisor), LE */ + __le16 divisor; /* baud rate = 96000000 / (16 * divisor), LE */ #define OTI6858_MAX_BAUD_RATE 3000000 u8 frame_fmt; #define FMT_STOP_BITS_MASK 0xc0 @@ -211,7 +211,7 @@ struct oti6858_private { struct delayed_work delayed_write_work; struct { - u16 divisor; + __le16 divisor; u8 frame_fmt; u8 control; } pending_setup; @@ -450,7 +450,7 @@ static void oti6858_set_termios(struct usb_serial_port *port, unsigned long flags; unsigned int cflag; u8 frame_fmt, control; - u16 divisor; + __le16 divisor; int br; dbg("%s(port = %d)", __func__, port->number); @@ -505,11 +505,12 @@ static void oti6858_set_termios(struct usb_serial_port *port, divisor = 0; } else { int real_br; + int new_divisor; br = min(br, OTI6858_MAX_BAUD_RATE); - divisor = (96000000 + 8 * br) / (16 * br); - real_br = 96000000 / (16 * divisor); - divisor = cpu_to_le16(divisor); + new_divisor = (96000000 + 8 * br) / (16 * br); + real_br = 96000000 / (16 * new_divisor); + divisor = cpu_to_le16(new_divisor); tty_encode_baud_rate(port->tty, real_br, real_br); } diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c index 2282d620186..55b2570b8b8 100644 --- a/drivers/usb/serial/spcp8x5.c +++ b/drivers/usb/serial/spcp8x5.c @@ -310,17 +310,18 @@ static int spcp8x5_startup(struct usb_serial *serial) struct spcp8x5_private *priv; int i; enum spcp8x5_type type = SPCP825_007_TYPE; + u16 product = le16_to_cpu(serial->dev->descriptor.idProduct); - if (serial->dev->descriptor.idProduct == 0x0201) + if (product == 0x0201) type = SPCP825_007_TYPE; - else if (serial->dev->descriptor.idProduct == 0x0231) + else if (product == 0x0231) type = SPCP835_TYPE; - else if (serial->dev->descriptor.idProduct == 0x0235) + else if (product == 0x0235) type = SPCP825_008_TYPE; - else if (serial->dev->descriptor.idProduct == 0x0204) + else if (product == 0x0204) type = SPCP825_INTERMATIC_TYPE; - else if (serial->dev->descriptor.idProduct == 0x0471 && - serial->dev->descriptor.idVendor == 0x081e) + else if (product == 0x0471 && + serial->dev->descriptor.idVendor == cpu_to_le16(0x081e)) type = SPCP825_PHILIP_TYPE; dev_dbg(&serial->dev->dev, "device type = %d\n", (int)type); diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index e3dc8f8d0c3..a576dc26173 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -139,6 +139,30 @@ config FB_SYS_IMAGEBLIT blitting. This is used by drivers that don't provide their own (accelerated) version and the framebuffer is in system RAM. +menuconfig FB_FOREIGN_ENDIAN + bool "Framebuffer foreign endianness support" + depends on FB + ---help--- + This menu will let you enable support for the framebuffers with + non-native endianness (e.g. Little-Endian framebuffer on a + Big-Endian machine). Most probably you don't have such hardware, + so it's safe to say "n" here. + +choice + prompt "Choice endianness support" + depends on FB_FOREIGN_ENDIAN + +config FB_BOTH_ENDIAN + bool "Support for Big- and Little-Endian framebuffers" + +config FB_BIG_ENDIAN + bool "Support for Big-Endian framebuffers only" + +config FB_LITTLE_ENDIAN + bool "Support for Little-Endian framebuffers only" + +endchoice + config FB_SYS_FOPS tristate depends on FB @@ -149,6 +173,16 @@ config FB_DEFERRED_IO depends on FB default y +config FB_METRONOME + tristate + depends on FB + depends on FB_DEFERRED_IO + +config FB_HECUBA + tristate + depends on FB + depends on FB_DEFERRED_IO + config FB_SVGALIB tristate depends on FB @@ -546,7 +580,7 @@ config FB_VGA16 config FB_BF54X_LQ043 tristate "SHARP LQ043 TFT LCD (BF548 EZKIT)" - depends on FB && (BF54x) + depends on FB && (BF54x) && !BF542 select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT @@ -674,20 +708,18 @@ config FB_IMAC help This is the frame buffer device driver for the Intel-based Macintosh -config FB_HECUBA - tristate "Hecuba board support" +config FB_N411 + tristate "N411 Apollo/Hecuba devkit support" depends on FB && X86 && MMU select FB_SYS_FILLRECT select FB_SYS_COPYAREA select FB_SYS_IMAGEBLIT select FB_SYS_FOPS select FB_DEFERRED_IO + select FB_HECUBA help - This enables support for the Hecuba board. This driver was tested - with an E-Ink 800x600 display and x86 SBCs through a 16 bit GPIO - interface (8 bit data, 4 bit control). If you anticipate using - this driver, say Y or M; otherwise say N. You must specify the - GPIO IO address to be used for setting control and data. + This enables support for the Apollo display controller in its + Hecuba form using the n411 devkit. config FB_HGA tristate "Hercules mono graphics support" @@ -1087,7 +1119,7 @@ config FB_CARILLO_RANCH This driver supports the LE80578 (Carillo Ranch) board config FB_INTEL - tristate "Intel 830M/845G/852GM/855GM/865G/915G/945G support (EXPERIMENTAL)" + tristate "Intel 830M/845G/852GM/855GM/865G/915G/945G/945GM/965G/965GM support (EXPERIMENTAL)" depends on FB && EXPERIMENTAL && PCI && X86 select AGP select AGP_INTEL @@ -1097,7 +1129,7 @@ config FB_INTEL select FB_CFB_IMAGEBLIT help This driver supports the on-board graphics built in to the Intel - 830M/845G/852GM/855GM/865G/915G/915GM/945G/945GM chipsets. + 830M/845G/852GM/855GM/865G/915G/915GM/945G/945GM/965G/965GM chipsets. Say Y if you have and plan to use such a board. If you say Y here and want DDC/I2C support you must first say Y to @@ -1779,6 +1811,16 @@ config FB_MBX_DEBUG If unsure, say N. +config FB_FSL_DIU + tristate "Freescale DIU framebuffer support" + depends on FB && FSL_SOC + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select PPC_LIB_RHEAP + ---help--- + Framebuffer driver for the Freescale SoC DIU + config FB_W100 tristate "W100 frame buffer support" depends on FB && PXA_SHARPSL @@ -1893,19 +1935,18 @@ config FB_XILINX framebuffer. ML300 carries a 640*480 LCD display on the board, ML403 uses a standard DB15 VGA connector. -config FB_METRONOME - tristate "Metronome display controller support" +config FB_AM200EPD + tristate "AM-200 E-Ink EPD devkit support" depends on FB && ARCH_PXA && MMU select FB_SYS_FILLRECT select FB_SYS_COPYAREA select FB_SYS_IMAGEBLIT select FB_SYS_FOPS select FB_DEFERRED_IO + select FB_METRONOME help - This enables support for the Metronome display controller. Tested - with an E-Ink 800x600 display and Gumstix Connex through an AMLCD - interface. Please read <file:Documentation/fb/metronomefb.txt> - for more information. + This enables support for the Metronome display controller used on + the E-Ink AM-200 EPD devkit. config FB_VIRTUAL tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)" diff --git a/drivers/video/Makefile b/drivers/video/Makefile index f172b9b7331..04bca35403f 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_FB_DEFERRED_IO) += fb_defio.o # Hardware specific drivers go first obj-$(CONFIG_FB_AMIGA) += amifb.o c2p.o +obj-$(CONFIG_FB_AM200EPD) += am200epd.o obj-$(CONFIG_FB_ARC) += arcfb.o obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o @@ -107,6 +108,7 @@ obj-$(CONFIG_FB_METRONOME) += metronomefb.o obj-$(CONFIG_FB_S1D13XXX) += s1d13xxxfb.o obj-$(CONFIG_FB_IMX) += imxfb.o obj-$(CONFIG_FB_S3C2410) += s3c2410fb.o +obj-$(CONFIG_FB_FSL_DIU) += fsl-diu-fb.o obj-$(CONFIG_FB_PNX4008_DUM) += pnx4008/ obj-$(CONFIG_FB_PNX4008_DUM_RGB) += pnx4008/ obj-$(CONFIG_FB_IBM_GXT4500) += gxt4500.o diff --git a/drivers/video/am200epd.c b/drivers/video/am200epd.c new file mode 100644 index 00000000000..51e26c1f5e8 --- /dev/null +++ b/drivers/video/am200epd.c @@ -0,0 +1,295 @@ +/* + * linux/drivers/video/am200epd.c -- Platform device for AM200 EPD kit + * + * Copyright (C) 2008, Jaya Kumar + * + * 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. + * + * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven. + * + * This work was made possible by help and equipment support from E-Ink + * Corporation. http://support.eink.com/community + * + * This driver is written to be used with the Metronome display controller. + * on the AM200 EPD prototype kit/development kit with an E-Ink 800x600 + * Vizplex EPD on a Gumstix board using the Lyre interface board. + * + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/list.h> +#include <linux/uaccess.h> +#include <linux/irq.h> + +#include <video/metronomefb.h> + +#include <asm/arch/pxa-regs.h> + +/* register offsets for gpio control */ +#define LED_GPIO_PIN 51 +#define STDBY_GPIO_PIN 48 +#define RST_GPIO_PIN 49 +#define RDY_GPIO_PIN 32 +#define ERR_GPIO_PIN 17 +#define PCBPWR_GPIO_PIN 16 + +#define AF_SEL_GPIO_N 0x3 +#define GAFR0_U_OFFSET(pin) ((pin - 16) * 2) +#define GAFR1_L_OFFSET(pin) ((pin - 32) * 2) +#define GAFR1_U_OFFSET(pin) ((pin - 48) * 2) +#define GPDR1_OFFSET(pin) (pin - 32) +#define GPCR1_OFFSET(pin) (pin - 32) +#define GPSR1_OFFSET(pin) (pin - 32) +#define GPCR0_OFFSET(pin) (pin) +#define GPSR0_OFFSET(pin) (pin) + +static void am200_set_gpio_output(int pin, int val) +{ + u8 index; + + index = pin >> 4; + + switch (index) { + case 1: + if (val) + GPSR0 |= (1 << GPSR0_OFFSET(pin)); + else + GPCR0 |= (1 << GPCR0_OFFSET(pin)); + break; + case 2: + break; + case 3: + if (val) + GPSR1 |= (1 << GPSR1_OFFSET(pin)); + else + GPCR1 |= (1 << GPCR1_OFFSET(pin)); + break; + default: + printk(KERN_ERR "unimplemented\n"); + } +} + +static void __devinit am200_init_gpio_pin(int pin, int dir) +{ + u8 index; + /* dir 0 is output, 1 is input + - do 2 things here: + - set gpio alternate function to standard gpio + - set gpio direction to input or output */ + + index = pin >> 4; + switch (index) { + case 1: + GAFR0_U &= ~(AF_SEL_GPIO_N << GAFR0_U_OFFSET(pin)); + + if (dir) + GPDR0 &= ~(1 << pin); + else + GPDR0 |= (1 << pin); + break; + case 2: + GAFR1_L &= ~(AF_SEL_GPIO_N << GAFR1_L_OFFSET(pin)); + + if (dir) + GPDR1 &= ~(1 << GPDR1_OFFSET(pin)); + else + GPDR1 |= (1 << GPDR1_OFFSET(pin)); + break; + case 3: + GAFR1_U &= ~(AF_SEL_GPIO_N << GAFR1_U_OFFSET(pin)); + + if (dir) + GPDR1 &= ~(1 << GPDR1_OFFSET(pin)); + else + GPDR1 |= (1 << GPDR1_OFFSET(pin)); + break; + default: + printk(KERN_ERR "unimplemented\n"); + } +} + +static void am200_init_gpio_regs(struct metronomefb_par *par) +{ + am200_init_gpio_pin(LED_GPIO_PIN, 0); + am200_set_gpio_output(LED_GPIO_PIN, 0); + + am200_init_gpio_pin(STDBY_GPIO_PIN, 0); + am200_set_gpio_output(STDBY_GPIO_PIN, 0); + + am200_init_gpio_pin(RST_GPIO_PIN, 0); + am200_set_gpio_output(RST_GPIO_PIN, 0); + + am200_init_gpio_pin(RDY_GPIO_PIN, 1); + + am200_init_gpio_pin(ERR_GPIO_PIN, 1); + + am200_init_gpio_pin(PCBPWR_GPIO_PIN, 0); + am200_set_gpio_output(PCBPWR_GPIO_PIN, 0); +} + +static void am200_disable_lcd_controller(struct metronomefb_par *par) +{ + LCSR = 0xffffffff; /* Clear LCD Status Register */ + LCCR0 |= LCCR0_DIS; /* Disable LCD Controller */ + + /* we reset and just wait for things to settle */ + msleep(200); +} + +static void am200_enable_lcd_controller(struct metronomefb_par *par) +{ + LCSR = 0xffffffff; + FDADR0 = par->metromem_desc_dma; + LCCR0 |= LCCR0_ENB; +} + +static void am200_init_lcdc_regs(struct metronomefb_par *par) +{ + /* here we do: + - disable the lcd controller + - setup lcd control registers + - setup dma descriptor + - reenable lcd controller + */ + + /* disable the lcd controller */ + am200_disable_lcd_controller(par); + + /* setup lcd control registers */ + LCCR0 = LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM | LCCR0_PAS + | LCCR0_QDM | LCCR0_BM | LCCR0_OUM; + + LCCR1 = (par->info->var.xres/2 - 1) /* pixels per line */ + | (27 << 10) /* hsync pulse width - 1 */ + | (33 << 16) /* eol pixel count */ + | (33 << 24); /* bol pixel count */ + + LCCR2 = (par->info->var.yres - 1) /* lines per panel */ + | (24 << 10) /* vsync pulse width - 1 */ + | (2 << 16) /* eof pixel count */ + | (0 << 24); /* bof pixel count */ + + LCCR3 = 2 /* pixel clock divisor */ + | (24 << 8) /* AC Bias pin freq */ + | LCCR3_16BPP /* BPP */ + | LCCR3_PCP; /* PCP falling edge */ + +} + +static void am200_post_dma_setup(struct metronomefb_par *par) +{ + par->metromem_desc->mFDADR0 = par->metromem_desc_dma; + par->metromem_desc->mFSADR0 = par->metromem_dma; + par->metromem_desc->mFIDR0 = 0; + par->metromem_desc->mLDCMD0 = par->info->var.xres + * par->info->var.yres; + am200_enable_lcd_controller(par); +} + +static void am200_free_irq(struct fb_info *info) +{ + free_irq(IRQ_GPIO(RDY_GPIO_PIN), info); +} + +static irqreturn_t am200_handle_irq(int irq, void *dev_id) +{ + struct fb_info *info = dev_id; + struct metronomefb_par *par = info->par; + + wake_up_interruptible(&par->waitq); + return IRQ_HANDLED; +} + +static int am200_setup_irq(struct fb_info *info) +{ + int retval; + + retval = request_irq(IRQ_GPIO(RDY_GPIO_PIN), am200_handle_irq, + IRQF_DISABLED, "AM200", info); + if (retval) { + printk(KERN_ERR "am200epd: request_irq failed: %d\n", retval); + return retval; + } + + return set_irq_type(IRQ_GPIO(RDY_GPIO_PIN), IRQT_FALLING); +} + +static void am200_set_rst(struct metronomefb_par *par, int state) +{ + am200_set_gpio_output(RST_GPIO_PIN, state); +} + +static void am200_set_stdby(struct metronomefb_par *par, int state) +{ + am200_set_gpio_output(STDBY_GPIO_PIN, state); +} + +static int am200_wait_event(struct metronomefb_par *par) +{ + return wait_event_timeout(par->waitq, (GPLR1 & 0x01), HZ); +} + +static int am200_wait_event_intr(struct metronomefb_par *par) +{ + return wait_event_interruptible_timeout(par->waitq, (GPLR1 & 0x01), HZ); +} + +static struct metronome_board am200_board = { + .owner = THIS_MODULE, + .free_irq = am200_free_irq, + .setup_irq = am200_setup_irq, + .init_gpio_regs = am200_init_gpio_regs, + .init_lcdc_regs = am200_init_lcdc_regs, + .post_dma_setup = am200_post_dma_setup, + .set_rst = am200_set_rst, + .set_stdby = am200_set_stdby, + .met_wait_event = am200_wait_event, + .met_wait_event_intr = am200_wait_event_intr, +}; + +static struct platform_device *am200_device; + +static int __init am200_init(void) +{ + int ret; + + /* request our platform independent driver */ + request_module("metronomefb"); + + am200_device = platform_device_alloc("metronomefb", -1); + if (!am200_device) + return -ENOMEM; + + platform_device_add_data(am200_device, &am200_board, + sizeof(am200_board)); + + /* this _add binds metronomefb to am200. metronomefb refcounts am200 */ + ret = platform_device_add(am200_device); + + if (ret) + platform_device_put(am200_device); + + return ret; +} + +static void __exit am200_exit(void) +{ + platform_device_unregister(am200_device); +} + +module_init(am200_init); +module_exit(am200_exit); + +MODULE_DESCRIPTION("board driver for am200 metronome epd kit"); +MODULE_AUTHOR("Jaya Kumar"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c index 4c9ec3f58c5..e6492c1048b 100644 --- a/drivers/video/amifb.c +++ b/drivers/video/amifb.c @@ -96,7 +96,7 @@ #endif #ifdef DEBUG -# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) +# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __func__ , ## args) #else # define DPRINTK(fmt, args...) #endif diff --git a/drivers/video/arkfb.c b/drivers/video/arkfb.c index 8a1b07c7439..5001bd4ef46 100644 --- a/drivers/video/arkfb.c +++ b/drivers/video/arkfb.c @@ -101,7 +101,7 @@ static const struct svga_timing_regs ark_timing_regs = { /* Module parameters */ -static char *mode = "640x480-8@60"; +static char *mode_option __devinitdata = "640x480-8@60"; #ifdef CONFIG_MTRR static int mtrr = 1; @@ -111,8 +111,10 @@ MODULE_AUTHOR("(c) 2007 Ondrej Zajicek <santiago@crfreenet.org>"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("fbdev driver for ARK 2000PV"); -module_param(mode, charp, 0444); -MODULE_PARM_DESC(mode, "Default video mode ('640x480-8@60', etc)"); +module_param(mode_option, charp, 0444); +MODULE_PARM_DESC(mode_option, "Default video mode ('640x480-8@60', etc)"); +module_param_named(mode, mode_option, charp, 0444); +MODULE_PARM_DESC(mode, "Default video mode ('640x480-8@60', etc) (deprecated)"); #ifdef CONFIG_MTRR module_param(mtrr, int, 0444); @@ -941,7 +943,7 @@ static int __devinit ark_pci_probe(struct pci_dev *dev, const struct pci_device_ } /* Allocate and fill driver data structure */ - info = framebuffer_alloc(sizeof(struct arkfb_info), NULL); + info = framebuffer_alloc(sizeof(struct arkfb_info), &(dev->dev)); if (! info) { dev_err(&(dev->dev), "cannot allocate memory\n"); return -ENOMEM; @@ -956,20 +958,20 @@ static int __devinit ark_pci_probe(struct pci_dev *dev, const struct pci_device_ /* Prepare PCI device */ rc = pci_enable_device(dev); if (rc < 0) { - dev_err(&(dev->dev), "cannot enable PCI device\n"); + dev_err(info->dev, "cannot enable PCI device\n"); goto err_enable_device; } rc = pci_request_regions(dev, "arkfb"); if (rc < 0) { - dev_err(&(dev->dev), "cannot reserve framebuffer region\n"); + dev_err(info->dev, "cannot reserve framebuffer region\n"); goto err_request_regions; } par->dac = ics5342_init(ark_dac_read_regs, ark_dac_write_regs, info); if (! par->dac) { rc = -ENOMEM; - dev_err(&(dev->dev), "RAMDAC initialization failed\n"); + dev_err(info->dev, "RAMDAC initialization failed\n"); goto err_dac; } @@ -980,7 +982,7 @@ static int __devinit ark_pci_probe(struct pci_dev *dev, const struct pci_device_ info->screen_base = pci_iomap(dev, 0, 0); if (! info->screen_base) { rc = -ENOMEM; - dev_err(&(dev->dev), "iomap for framebuffer failed\n"); + dev_err(info->dev, "iomap for framebuffer failed\n"); goto err_iomap; } @@ -999,22 +1001,22 @@ static int __devinit ark_pci_probe(struct pci_dev *dev, const struct pci_device_ info->pseudo_palette = (void*) (par->pseudo_palette); /* Prepare startup mode */ - rc = fb_find_mode(&(info->var), info, mode, NULL, 0, NULL, 8); + rc = fb_find_mode(&(info->var), info, mode_option, NULL, 0, NULL, 8); if (! ((rc == 1) || (rc == 2))) { rc = -EINVAL; - dev_err(&(dev->dev), "mode %s not found\n", mode); + dev_err(info->dev, "mode %s not found\n", mode_option); goto err_find_mode; } rc = fb_alloc_cmap(&info->cmap, 256, 0); if (rc < 0) { - dev_err(&(dev->dev), "cannot allocate colormap\n"); + dev_err(info->dev, "cannot allocate colormap\n"); goto err_alloc_cmap; } rc = register_framebuffer(info); if (rc < 0) { - dev_err(&(dev->dev), "cannot register framebugger\n"); + dev_err(info->dev, "cannot register framebugger\n"); goto err_reg_fb; } @@ -1088,7 +1090,7 @@ static int ark_pci_suspend (struct pci_dev* dev, pm_message_t state) struct fb_info *info = pci_get_drvdata(dev); struct arkfb_info *par = info->par; - dev_info(&(dev->dev), "suspend\n"); + dev_info(info->dev, "suspend\n"); acquire_console_sem(); mutex_lock(&(par->open_lock)); @@ -1119,7 +1121,7 @@ static int ark_pci_resume (struct pci_dev* dev) struct fb_info *info = pci_get_drvdata(dev); struct arkfb_info *par = info->par; - dev_info(&(dev->dev), "resume\n"); + dev_info(info->dev, "resume\n"); acquire_console_sem(); mutex_lock(&(par->open_lock)); @@ -1190,7 +1192,7 @@ static int __init arkfb_init(void) return -ENODEV; if (option && *option) - mode = option; + mode_option = option; #endif pr_debug("arkfb: initializing\n"); diff --git a/drivers/video/atafb.c b/drivers/video/atafb.c index 5d4fbaa53a6..dff35474b85 100644 --- a/drivers/video/atafb.c +++ b/drivers/video/atafb.c @@ -1270,7 +1270,7 @@ again: gstart = (prescale / 2 + plen * left_margin) / prescale; /* gend1 is for hde (gend-gstart multiple of align), shifter's xres */ - gend1 = gstart + ((xres + align - 1) / align) * align * plen / prescale; + gend1 = gstart + roundup(xres, align) * plen / prescale; /* gend2 is for hbb, visible xres (rest to gend1 is cut off by hblank) */ gend2 = gstart + xres * plen / prescale; par->HHT = plen * (left_margin + xres + right_margin) / diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c index fc65c02306d..8ffdf357876 100644 --- a/drivers/video/atmel_lcdfb.c +++ b/drivers/video/atmel_lcdfb.c @@ -31,7 +31,8 @@ #define ATMEL_LCDC_CVAL_DEFAULT 0xc8 #define ATMEL_LCDC_DMA_BURST_LEN 8 -#if defined(CONFIG_ARCH_AT91SAM9263) || defined(CONFIG_ARCH_AT91CAP9) +#if defined(CONFIG_ARCH_AT91SAM9263) || defined(CONFIG_ARCH_AT91CAP9) || \ + defined(CONFIG_ARCH_AT91SAM9RL) #define ATMEL_LCDC_FIFO_SIZE 2048 #else #define ATMEL_LCDC_FIFO_SIZE 512 @@ -250,6 +251,8 @@ static int atmel_lcdfb_alloc_video_memory(struct atmel_lcdfb_info *sinfo) return -ENOMEM; } + memset(info->screen_base, 0, info->fix.smem_len); + return 0; } @@ -336,19 +339,35 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var, break; case 15: case 16: - var->red.offset = 0; + if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) { + /* RGB:565 mode */ + var->red.offset = 11; + var->blue.offset = 0; + var->green.length = 6; + } else { + /* BGR:555 mode */ + var->red.offset = 0; + var->blue.offset = 10; + var->green.length = 5; + } var->green.offset = 5; - var->blue.offset = 10; - var->red.length = var->green.length = var->blue.length = 5; + var->red.length = var->blue.length = 5; break; case 32: var->transp.offset = 24; var->transp.length = 8; /* fall through */ case 24: - var->red.offset = 0; + if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) { + /* RGB:888 mode */ + var->red.offset = 16; + var->blue.offset = 0; + } else { + /* BGR:888 mode */ + var->red.offset = 0; + var->blue.offset = 16; + } var->green.offset = 8; - var->blue.offset = 16; var->red.length = var->green.length = var->blue.length = 8; break; default: @@ -634,7 +653,6 @@ static int __init atmel_lcdfb_init_fbinfo(struct atmel_lcdfb_info *sinfo) struct fb_info *info = sinfo->info; int ret = 0; - memset_io(info->screen_base, 0, info->fix.smem_len); info->var.activate |= FB_ACTIVATE_FORCE | FB_ACTIVATE_NOW; dev_info(info->device, @@ -696,6 +714,7 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev) sinfo->atmel_lcdfb_power_control = pdata_sinfo->atmel_lcdfb_power_control; sinfo->guard_time = pdata_sinfo->guard_time; sinfo->lcdcon_is_backlight = pdata_sinfo->lcdcon_is_backlight; + sinfo->lcd_wiring_mode = pdata_sinfo->lcd_wiring_mode; } else { dev_err(dev, "cannot get default configuration\n"); goto free_info; @@ -764,6 +783,11 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev) info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len); if (!info->screen_base) goto release_intmem; + + /* + * Don't clear the framebuffer -- someone may have set + * up a splash image. + */ } else { /* alocate memory buffer */ ret = atmel_lcdfb_alloc_video_memory(sinfo); @@ -903,10 +927,42 @@ static int __exit atmel_lcdfb_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM + +static int atmel_lcdfb_suspend(struct platform_device *pdev, pm_message_t mesg) +{ + struct fb_info *info = platform_get_drvdata(pdev); + struct atmel_lcdfb_info *sinfo = info->par; + + sinfo->saved_lcdcon = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL); + lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, 0); + if (sinfo->atmel_lcdfb_power_control) + sinfo->atmel_lcdfb_power_control(0); + atmel_lcdfb_stop_clock(sinfo); + return 0; +} + +static int atmel_lcdfb_resume(struct platform_device *pdev) +{ + struct fb_info *info = platform_get_drvdata(pdev); + struct atmel_lcdfb_info *sinfo = info->par; + + atmel_lcdfb_start_clock(sinfo); + if (sinfo->atmel_lcdfb_power_control) + sinfo->atmel_lcdfb_power_control(1); + lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, sinfo->saved_lcdcon); + return 0; +} + +#else +#define atmel_lcdfb_suspend NULL +#define atmel_lcdfb_resume NULL +#endif + static struct platform_driver atmel_lcdfb_driver = { .remove = __exit_p(atmel_lcdfb_remove), - -// FIXME need suspend, resume + .suspend = atmel_lcdfb_suspend, + .resume = atmel_lcdfb_resume, .driver = { .name = "atmel_lcdfb", diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c index cbd3308b669..24ee96c4e9e 100644 --- a/drivers/video/aty/aty128fb.c +++ b/drivers/video/aty/aty128fb.c @@ -91,7 +91,7 @@ #undef DEBUG #ifdef DEBUG -#define DBG(fmt, args...) printk(KERN_DEBUG "aty128fb: %s " fmt, __FUNCTION__, ##args); +#define DBG(fmt, args...) printk(KERN_DEBUG "aty128fb: %s " fmt, __func__, ##args); #else #define DBG(fmt, args...) #endif @@ -1885,7 +1885,7 @@ static int __devinit aty128_init(struct pci_dev *pdev, const struct pci_device_i /* range check to make sure */ if (ent->driver_data < ARRAY_SIZE(r128_family)) - strncat(video_card, r128_family[ent->driver_data], sizeof(video_card)); + strlcat(video_card, r128_family[ent->driver_data], sizeof(video_card)); printk(KERN_INFO "aty128fb: %s [chip rev 0x%x] ", video_card, chip_rev); diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index 62f9c6e387c..e4bcf5376a9 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c @@ -2621,10 +2621,13 @@ static int __devinit aty_init(struct fb_info *info) #endif /* CONFIG_FB_ATY_CT */ info->var = var; - fb_alloc_cmap(&info->cmap, 256, 0); + if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) + goto aty_init_exit; - if (register_framebuffer(info) < 0) + if (register_framebuffer(info) < 0) { + fb_dealloc_cmap(&info->cmap); goto aty_init_exit; + } fb_list = info; diff --git a/drivers/video/aty/mach64_ct.c b/drivers/video/aty/mach64_ct.c index cc9e9779b75..c50c7cf26fe 100644 --- a/drivers/video/aty/mach64_ct.c +++ b/drivers/video/aty/mach64_ct.c @@ -197,7 +197,7 @@ static int aty_dsp_gt(const struct fb_info *info, u32 bpp, struct pll_ct *pll) pll->dsp_config = (dsp_precision << 20) | (pll->dsp_loop_latency << 16) | dsp_xclks; #ifdef DEBUG printk("atyfb(%s): dsp_config 0x%08x, dsp_on_off 0x%08x\n", - __FUNCTION__, pll->dsp_config, pll->dsp_on_off); + __func__, pll->dsp_config, pll->dsp_on_off); #endif return 0; } @@ -225,7 +225,7 @@ static int aty_valid_pll_ct(const struct fb_info *info, u32 vclk_per, struct pll (par->ref_clk_per * pll->pll_ref_div); #ifdef DEBUG printk("atyfb(%s): pllvclk=%d MHz, vclk=%d MHz\n", - __FUNCTION__, pllvclk, pllvclk / pll->vclk_post_div_real); + __func__, pllvclk, pllvclk / pll->vclk_post_div_real); #endif pll->pll_vclk_cntl = 0x03; /* VCLK = PLL_VCLK/VCLKx_POST */ @@ -269,7 +269,7 @@ static u32 aty_pll_to_var_ct(const struct fb_info *info, const union aty_pll *pl } #endif #ifdef DEBUG - printk("atyfb(%s): calculated 0x%08X(%i)\n", __FUNCTION__, ret, ret); + printk("atyfb(%s): calculated 0x%08X(%i)\n", __func__, ret, ret); #endif return ret; } @@ -284,11 +284,11 @@ void aty_set_pll_ct(const struct fb_info *info, const union aty_pll *pll) #ifdef DEBUG printk("atyfb(%s): about to program:\n" "pll_ext_cntl=0x%02x pll_gen_cntl=0x%02x pll_vclk_cntl=0x%02x\n", - __FUNCTION__, + __func__, pll->ct.pll_ext_cntl, pll->ct.pll_gen_cntl, pll->ct.pll_vclk_cntl); printk("atyfb(%s): setting clock %lu for FeedBackDivider %i, ReferenceDivider %i, PostDivider %i(%i)\n", - __FUNCTION__, + __func__, par->clk_wr_offset, pll->ct.vclk_fb_div, pll->ct.pll_ref_div, pll->ct.vclk_post_div, pll->ct.vclk_post_div_real); #endif @@ -428,7 +428,7 @@ static int __devinit aty_init_pll_ct(const struct fb_info *info, #ifdef DEBUG printk("atyfb(%s): mclk_fb_mult=%d, xclk_post_div=%d\n", - __FUNCTION__, pll->ct.mclk_fb_mult, pll->ct.xclk_post_div); + __func__, pll->ct.mclk_fb_mult, pll->ct.xclk_post_div); #endif memcntl = aty_ld_le32(MEM_CNTL, par); @@ -540,7 +540,7 @@ static int __devinit aty_init_pll_ct(const struct fb_info *info, pllmclk = (1000000 * pll->ct.mclk_fb_mult * pll->ct.mclk_fb_div) / (par->ref_clk_per * pll->ct.pll_ref_div); printk("atyfb(%s): pllmclk=%d MHz, xclk=%d MHz\n", - __FUNCTION__, pllmclk, pllmclk / pll->ct.xclk_post_div_real); + __func__, pllmclk, pllmclk / pll->ct.xclk_post_div_real); #endif if (M64_HAS(SDRAM_MAGIC_PLL) && (par->ram_type >= SDRAM)) @@ -581,7 +581,7 @@ static int __devinit aty_init_pll_ct(const struct fb_info *info, pllsclk = (1000000 * 2 * pll->ct.sclk_fb_div) / (par->ref_clk_per * pll->ct.pll_ref_div); printk("atyfb(%s): use sclk, pllsclk=%d MHz, sclk=mclk=%d MHz\n", - __FUNCTION__, pllsclk, pllsclk / sclk_post_div_real); + __func__, pllsclk, pllsclk / sclk_post_div_real); #endif } diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c index 62867cb63fe..72cd0d2f14e 100644 --- a/drivers/video/aty/radeon_base.c +++ b/drivers/video/aty/radeon_base.c @@ -52,11 +52,14 @@ #define RADEON_VERSION "0.2.0" +#include "radeonfb.h" + #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/kernel.h> #include <linux/errno.h> #include <linux/string.h> +#include <linux/ctype.h> #include <linux/mm.h> #include <linux/slab.h> #include <linux/delay.h> @@ -91,7 +94,6 @@ #include "../edid.h" // MOVE THAT TO include/video #include "ati_ids.h" -#include "radeonfb.h" #define MAX_MAPPED_VRAM (2048*2048*4) #define MIN_MAPPED_VRAM (1024*768*1) @@ -1488,7 +1490,7 @@ static void radeon_calc_pll_regs(struct radeonfb_info *rinfo, struct radeon_regs freq = rinfo->pll.ppll_max; if (freq*12 < rinfo->pll.ppll_min) freq = rinfo->pll.ppll_min / 12; - RTRACE("freq = %lu, PLL min = %u, PLL max = %u\n", + pr_debug("freq = %lu, PLL min = %u, PLL max = %u\n", freq, rinfo->pll.ppll_min, rinfo->pll.ppll_max); for (post_div = &post_divs[0]; post_div->divider; ++post_div) { @@ -1509,7 +1511,7 @@ static void radeon_calc_pll_regs(struct radeonfb_info *rinfo, struct radeon_regs post_div = &post_divs[post_div->bitvalue]; pll_output_freq = post_div->divider * freq; } - RTRACE("ref_div = %d, ref_clk = %d, output_freq = %d\n", + pr_debug("ref_div = %d, ref_clk = %d, output_freq = %d\n", rinfo->pll.ref_div, rinfo->pll.ref_clk, pll_output_freq); @@ -1519,7 +1521,7 @@ static void radeon_calc_pll_regs(struct radeonfb_info *rinfo, struct radeon_regs post_div = &post_divs[post_div->bitvalue]; pll_output_freq = post_div->divider * freq; } - RTRACE("ref_div = %d, ref_clk = %d, output_freq = %d\n", + pr_debug("ref_div = %d, ref_clk = %d, output_freq = %d\n", rinfo->pll.ref_div, rinfo->pll.ref_clk, pll_output_freq); @@ -1528,9 +1530,9 @@ static void radeon_calc_pll_regs(struct radeonfb_info *rinfo, struct radeon_regs regs->ppll_ref_div = rinfo->pll.ref_div; regs->ppll_div_3 = fb_div | (post_div->bitvalue << 16); - RTRACE("post div = 0x%x\n", post_div->bitvalue); - RTRACE("fb_div = 0x%x\n", fb_div); - RTRACE("ppll_div_3 = 0x%x\n", regs->ppll_div_3); + pr_debug("post div = 0x%x\n", post_div->bitvalue); + pr_debug("fb_div = 0x%x\n", fb_div); + pr_debug("ppll_div_3 = 0x%x\n", regs->ppll_div_3); } static int radeonfb_set_par(struct fb_info *info) @@ -1602,9 +1604,9 @@ static int radeonfb_set_par(struct fb_info *info) dotClock = 1000000000 / pixClock; freq = dotClock / 10; /* x100 */ - RTRACE("hStart = %d, hEnd = %d, hTotal = %d\n", + pr_debug("hStart = %d, hEnd = %d, hTotal = %d\n", hSyncStart, hSyncEnd, hTotal); - RTRACE("vStart = %d, vEnd = %d, vTotal = %d\n", + pr_debug("vStart = %d, vEnd = %d, vTotal = %d\n", vSyncStart, vSyncEnd, vTotal); hsync_wid = (hSyncEnd - hSyncStart) / 8; @@ -1713,16 +1715,16 @@ static int radeonfb_set_par(struct fb_info *info) newmode->surf_info[i] = 0; } - RTRACE("h_total_disp = 0x%x\t hsync_strt_wid = 0x%x\n", + pr_debug("h_total_disp = 0x%x\t hsync_strt_wid = 0x%x\n", newmode->crtc_h_total_disp, newmode->crtc_h_sync_strt_wid); - RTRACE("v_total_disp = 0x%x\t vsync_strt_wid = 0x%x\n", + pr_debug("v_total_disp = 0x%x\t vsync_strt_wid = 0x%x\n", newmode->crtc_v_total_disp, newmode->crtc_v_sync_strt_wid); rinfo->bpp = mode->bits_per_pixel; rinfo->depth = depth; - RTRACE("pixclock = %lu\n", (unsigned long)pixClock); - RTRACE("freq = %lu\n", (unsigned long)freq); + pr_debug("pixclock = %lu\n", (unsigned long)pixClock); + pr_debug("freq = %lu\n", (unsigned long)freq); /* We use PPLL_DIV_3 */ newmode->clk_cntl_index = 0x300; @@ -1986,7 +1988,7 @@ static void fixup_memory_mappings(struct radeonfb_info *rinfo) if (rinfo->has_CRTC2) OUTREG(CRTC2_GEN_CNTL, save_crtc2_gen_cntl); - RTRACE("aper_base: %08x MC_FB_LOC to: %08x, MC_AGP_LOC to: %08x\n", + pr_debug("aper_base: %08x MC_FB_LOC to: %08x, MC_AGP_LOC to: %08x\n", aper_base, ((aper_base + aper_size - 1) & 0xffff0000) | (aper_base >> 16), 0xffff0000 | (agp_base >> 16)); @@ -2083,7 +2085,7 @@ static void radeon_identify_vram(struct radeonfb_info *rinfo) * ToDo: identify these cases */ - RTRACE("radeonfb (%s): Found %ldk of %s %d bits wide videoram\n", + pr_debug("radeonfb (%s): Found %ldk of %s %d bits wide videoram\n", pci_name(rinfo->pdev), rinfo->video_ram / 1024, rinfo->vram_ddr ? "DDR" : "SDRAM", @@ -2158,8 +2160,9 @@ static int __devinit radeonfb_pci_register (struct pci_dev *pdev, struct fb_info *info; struct radeonfb_info *rinfo; int ret; + unsigned char c1, c2; - RTRACE("radeonfb_pci_register BEGIN\n"); + pr_debug("radeonfb_pci_register BEGIN\n"); /* Enable device in PCI config */ ret = pci_enable_device(pdev); @@ -2185,9 +2188,15 @@ static int __devinit radeonfb_pci_register (struct pci_dev *pdev, rinfo->lvds_timer.function = radeon_lvds_timer_func; rinfo->lvds_timer.data = (unsigned long)rinfo; - strcpy(rinfo->name, "ATI Radeon XX "); - rinfo->name[11] = ent->device >> 8; - rinfo->name[12] = ent->device & 0xFF; + c1 = ent->device >> 8; + c2 = ent->device & 0xff; + if (isprint(c1) && isprint(c2)) + snprintf(rinfo->name, sizeof(rinfo->name), + "ATI Radeon %x \"%c%c\"", ent->device & 0xffff, c1, c2); + else + snprintf(rinfo->name, sizeof(rinfo->name), + "ATI Radeon %x", ent->device & 0xffff); + rinfo->family = ent->driver_data & CHIP_FAMILY_MASK; rinfo->chipset = pdev->device; rinfo->has_CRTC2 = (ent->driver_data & CHIP_HAS_CRTC2) != 0; @@ -2278,7 +2287,7 @@ static int __devinit radeonfb_pci_register (struct pci_dev *pdev, goto err_unmap_rom; } - RTRACE("radeonfb (%s): mapped %ldk videoram\n", pci_name(rinfo->pdev), + pr_debug("radeonfb (%s): mapped %ldk videoram\n", pci_name(rinfo->pdev), rinfo->mapped_vram/1024); /* @@ -2373,7 +2382,7 @@ static int __devinit radeonfb_pci_register (struct pci_dev *pdev, if (rinfo->bios_seg) radeon_unmap_ROM(rinfo, pdev); - RTRACE("radeonfb_pci_register END\n"); + pr_debug("radeonfb_pci_register END\n"); return 0; err_unmap_fb: diff --git a/drivers/video/aty/radeon_i2c.c b/drivers/video/aty/radeon_i2c.c index 7db9de68171..f9e7c29ad9b 100644 --- a/drivers/video/aty/radeon_i2c.c +++ b/drivers/video/aty/radeon_i2c.c @@ -1,3 +1,5 @@ +#include "radeonfb.h" + #include <linux/module.h> #include <linux/kernel.h> #include <linux/delay.h> @@ -11,7 +13,6 @@ #include <asm/io.h> #include <video/radeon.h> -#include "radeonfb.h" #include "../edid.h" static void radeon_gpio_setscl(void* data, int state) @@ -77,7 +78,7 @@ static int radeon_setup_i2c_bus(struct radeon_i2c_chan *chan, const char *name) chan->algo.setscl = radeon_gpio_setscl; chan->algo.getsda = radeon_gpio_getsda; chan->algo.getscl = radeon_gpio_getscl; - chan->algo.udelay = 40; + chan->algo.udelay = 10; chan->algo.timeout = 20; chan->algo.data = chan; @@ -148,21 +149,21 @@ int radeon_probe_i2c_connector(struct radeonfb_info *rinfo, int conn, if (out_edid) *out_edid = edid; if (!edid) { - RTRACE("radeonfb: I2C (port %d) ... not found\n", conn); + pr_debug("radeonfb: I2C (port %d) ... not found\n", conn); return MT_NONE; } if (edid[0x14] & 0x80) { /* Fix detection using BIOS tables */ if (rinfo->is_mobility /*&& conn == ddc_dvi*/ && (INREG(LVDS_GEN_CNTL) & LVDS_ON)) { - RTRACE("radeonfb: I2C (port %d) ... found LVDS panel\n", conn); + pr_debug("radeonfb: I2C (port %d) ... found LVDS panel\n", conn); return MT_LCD; } else { - RTRACE("radeonfb: I2C (port %d) ... found TMDS panel\n", conn); + pr_debug("radeonfb: I2C (port %d) ... found TMDS panel\n", conn); return MT_DFP; } } - RTRACE("radeonfb: I2C (port %d) ... found CRT display\n", conn); + pr_debug("radeonfb: I2C (port %d) ... found CRT display\n", conn); return MT_CRT; } diff --git a/drivers/video/aty/radeon_monitor.c b/drivers/video/aty/radeon_monitor.c index 2030ed81342..b4d4b88afc0 100644 --- a/drivers/video/aty/radeon_monitor.c +++ b/drivers/video/aty/radeon_monitor.c @@ -69,11 +69,11 @@ static int __devinit radeon_parse_montype_prop(struct device_node *dp, u8 **out_ u8 *tmp; int i, mt = MT_NONE; - RTRACE("analyzing OF properties...\n"); + pr_debug("analyzing OF properties...\n"); pmt = of_get_property(dp, "display-type", NULL); if (!pmt) return MT_NONE; - RTRACE("display-type: %s\n", pmt); + pr_debug("display-type: %s\n", pmt); /* OF says "LCD" for DFP as well, we discriminate from the caller of this * function */ @@ -117,7 +117,7 @@ static int __devinit radeon_probe_OF_head(struct radeonfb_info *rinfo, int head_ { struct device_node *dp; - RTRACE("radeon_probe_OF_head\n"); + pr_debug("radeon_probe_OF_head\n"); dp = rinfo->of_node; while (dp == NULL) @@ -135,7 +135,7 @@ static int __devinit radeon_probe_OF_head(struct radeonfb_info *rinfo, int head_ if (!pname) return MT_NONE; len = strlen(pname); - RTRACE("head: %s (letter: %c, head_no: %d)\n", + pr_debug("head: %s (letter: %c, head_no: %d)\n", pname, pname[len-1], head_no); if (pname[len-1] == 'A' && head_no == 0) { int mt = radeon_parse_montype_prop(dp, out_EDID, 0); @@ -185,7 +185,7 @@ static int __devinit radeon_get_panel_info_BIOS(struct radeonfb_info *rinfo) rinfo->panel_info.xres, rinfo->panel_info.yres); rinfo->panel_info.pwr_delay = BIOS_IN16(tmp + 44); - RTRACE("BIOS provided panel power delay: %d\n", rinfo->panel_info.pwr_delay); + pr_debug("BIOS provided panel power delay: %d\n", rinfo->panel_info.pwr_delay); if (rinfo->panel_info.pwr_delay > 2000 || rinfo->panel_info.pwr_delay <= 0) rinfo->panel_info.pwr_delay = 2000; @@ -199,16 +199,16 @@ static int __devinit radeon_get_panel_info_BIOS(struct radeonfb_info *rinfo) rinfo->panel_info.fbk_divider > 3) { rinfo->panel_info.use_bios_dividers = 1; printk(KERN_INFO "radeondb: BIOS provided dividers will be used\n"); - RTRACE("ref_divider = %x\n", rinfo->panel_info.ref_divider); - RTRACE("post_divider = %x\n", rinfo->panel_info.post_divider); - RTRACE("fbk_divider = %x\n", rinfo->panel_info.fbk_divider); + pr_debug("ref_divider = %x\n", rinfo->panel_info.ref_divider); + pr_debug("post_divider = %x\n", rinfo->panel_info.post_divider); + pr_debug("fbk_divider = %x\n", rinfo->panel_info.fbk_divider); } - RTRACE("Scanning BIOS table ...\n"); + pr_debug("Scanning BIOS table ...\n"); for(i=0; i<32; i++) { tmp0 = BIOS_IN16(tmp+64+i*2); if (tmp0 == 0) break; - RTRACE(" %d x %d\n", BIOS_IN16(tmp0), BIOS_IN16(tmp0+2)); + pr_debug(" %d x %d\n", BIOS_IN16(tmp0), BIOS_IN16(tmp0+2)); if ((BIOS_IN16(tmp0) == rinfo->panel_info.xres) && (BIOS_IN16(tmp0+2) == rinfo->panel_info.yres)) { rinfo->panel_info.hblank = (BIOS_IN16(tmp0+17) - BIOS_IN16(tmp0+19)) * 8; @@ -227,19 +227,19 @@ static int __devinit radeon_get_panel_info_BIOS(struct radeonfb_info *rinfo) /* Mark panel infos valid */ rinfo->panel_info.valid = 1; - RTRACE("Found panel in BIOS table:\n"); - RTRACE(" hblank: %d\n", rinfo->panel_info.hblank); - RTRACE(" hOver_plus: %d\n", rinfo->panel_info.hOver_plus); - RTRACE(" hSync_width: %d\n", rinfo->panel_info.hSync_width); - RTRACE(" vblank: %d\n", rinfo->panel_info.vblank); - RTRACE(" vOver_plus: %d\n", rinfo->panel_info.vOver_plus); - RTRACE(" vSync_width: %d\n", rinfo->panel_info.vSync_width); - RTRACE(" clock: %d\n", rinfo->panel_info.clock); + pr_debug("Found panel in BIOS table:\n"); + pr_debug(" hblank: %d\n", rinfo->panel_info.hblank); + pr_debug(" hOver_plus: %d\n", rinfo->panel_info.hOver_plus); + pr_debug(" hSync_width: %d\n", rinfo->panel_info.hSync_width); + pr_debug(" vblank: %d\n", rinfo->panel_info.vblank); + pr_debug(" vOver_plus: %d\n", rinfo->panel_info.vOver_plus); + pr_debug(" vSync_width: %d\n", rinfo->panel_info.vSync_width); + pr_debug(" clock: %d\n", rinfo->panel_info.clock); return 1; } } - RTRACE("Didn't find panel in BIOS table !\n"); + pr_debug("Didn't find panel in BIOS table !\n"); return 0; } @@ -271,18 +271,18 @@ static void __devinit radeon_parse_connector_info(struct radeonfb_info *rinfo) * DEBUG is enabled */ chips = BIOS_IN8(offset++) >> 4; - RTRACE("%d chips in connector info\n", chips); + pr_debug("%d chips in connector info\n", chips); for (i = 0; i < chips; i++) { tmp = BIOS_IN8(offset++); connectors = tmp & 0x0f; - RTRACE(" - chip %d has %d connectors\n", tmp >> 4, connectors); + pr_debug(" - chip %d has %d connectors\n", tmp >> 4, connectors); for (conn = 0; ; conn++) { tmp = BIOS_IN16(offset); if (tmp == 0) break; offset += 2; type = (tmp >> 12) & 0x0f; - RTRACE(" * connector %d of type %d (%s) : %04x\n", + pr_debug(" * connector %d of type %d (%s) : %04x\n", conn, type, __conn_type_table[type], tmp); } } @@ -449,7 +449,7 @@ void __devinit radeon_probe_screens(struct radeonfb_info *rinfo, * a layout for each card ? */ - RTRACE("Using specified monitor layout: %s", monitor_layout); + pr_debug("Using specified monitor layout: %s", monitor_layout); #ifdef CONFIG_FB_RADEON_I2C if (!ignore_edid) { if (rinfo->mon1_type != MT_NONE) @@ -479,9 +479,9 @@ void __devinit radeon_probe_screens(struct radeonfb_info *rinfo, * Auto-detecting display type (well... trying to ...) */ - RTRACE("Starting monitor auto detection...\n"); + pr_debug("Starting monitor auto detection...\n"); -#if DEBUG && defined(CONFIG_FB_RADEON_I2C) +#if defined(DEBUG) && defined(CONFIG_FB_RADEON_I2C) { u8 *EDIDs[4] = { NULL, NULL, NULL, NULL }; int mon_types[4] = {MT_NONE, MT_NONE, MT_NONE, MT_NONE}; @@ -756,7 +756,7 @@ void __devinit radeon_check_modes(struct radeonfb_info *rinfo, const char *mode_ if (!rinfo->panel_info.use_bios_dividers && rinfo->mon1_type != MT_CRT && rinfo->mon1_EDID) { struct fb_var_screeninfo var; - RTRACE("Parsing EDID data for panel info\n"); + pr_debug("Parsing EDID data for panel info\n"); if (fb_parse_edid(rinfo->mon1_EDID, &var) == 0) { if (var.xres >= rinfo->panel_info.xres && var.yres >= rinfo->panel_info.yres) @@ -776,7 +776,7 @@ void __devinit radeon_check_modes(struct radeonfb_info *rinfo, const char *mode_ if (rinfo->mon1_type != MT_CRT && rinfo->panel_info.valid) { struct fb_var_screeninfo *var = &info->var; - RTRACE("Setting up default mode based on panel info\n"); + pr_debug("Setting up default mode based on panel info\n"); var->xres = rinfo->panel_info.xres; var->yres = rinfo->panel_info.yres; var->xres_virtual = rinfo->panel_info.xres; @@ -824,7 +824,7 @@ void __devinit radeon_check_modes(struct radeonfb_info *rinfo, const char *mode_ int dbsize; char modename[32]; - RTRACE("Guessing panel info...\n"); + pr_debug("Guessing panel info...\n"); if (rinfo->panel_info.xres == 0 || rinfo->panel_info.yres == 0) { u32 tmp = INREG(FP_HORZ_STRETCH) & HORZ_PANEL_SIZE; rinfo->panel_info.xres = ((tmp >> HORZ_PANEL_SHIFT) + 1) * 8; diff --git a/drivers/video/aty/radeonfb.h b/drivers/video/aty/radeonfb.h index 5eac1ce52e7..c347e38cd0b 100644 --- a/drivers/video/aty/radeonfb.h +++ b/drivers/video/aty/radeonfb.h @@ -1,6 +1,10 @@ #ifndef __RADEONFB_H__ #define __RADEONFB_H__ +#ifdef CONFIG_FB_RADEON_DEBUG +#define DEBUG 1 +#endif + #include <linux/module.h> #include <linux/kernel.h> #include <linux/sched.h> @@ -365,22 +369,6 @@ struct radeonfb_info { /* - * Debugging stuffs - */ -#ifdef CONFIG_FB_RADEON_DEBUG -#define DEBUG 1 -#else -#define DEBUG 0 -#endif - -#if DEBUG -#define RTRACE printk -#else -#define RTRACE if(0) printk -#endif - - -/* * IO macros */ diff --git a/drivers/video/bf54x-lq043fb.c b/drivers/video/bf54x-lq043fb.c index eefba3d0e4b..49834a67a62 100644 --- a/drivers/video/bf54x-lq043fb.c +++ b/drivers/video/bf54x-lq043fb.c @@ -336,7 +336,7 @@ static int bfin_bf54x_fb_check_var(struct fb_var_screeninfo *var, { if (var->bits_per_pixel != LCD_BPP) { - pr_debug("%s: depth not supported: %u BPP\n", __FUNCTION__, + pr_debug("%s: depth not supported: %u BPP\n", __func__, var->bits_per_pixel); return -EINVAL; } @@ -345,7 +345,7 @@ static int bfin_bf54x_fb_check_var(struct fb_var_screeninfo *var, info->var.xres_virtual != var->xres_virtual || info->var.yres_virtual != var->yres_virtual) { pr_debug("%s: Resolution not supported: X%u x Y%u \n", - __FUNCTION__, var->xres, var->yres); + __func__, var->xres, var->yres); return -EINVAL; } @@ -355,7 +355,7 @@ static int bfin_bf54x_fb_check_var(struct fb_var_screeninfo *var, if ((info->fix.line_length * var->yres_virtual) > info->fix.smem_len) { pr_debug("%s: Memory Limit requested yres_virtual = %u\n", - __FUNCTION__, var->yres_virtual); + __func__, var->yres_virtual); return -ENOMEM; } @@ -652,7 +652,7 @@ static int __init bfin_bf54x_probe(struct platform_device *pdev) goto out7; } - if (request_irq(info->irq, (void *)bfin_bf54x_irq_error, IRQF_DISABLED, + if (request_irq(info->irq, bfin_bf54x_irq_error, IRQF_DISABLED, "PPI ERROR", info) < 0) { printk(KERN_ERR DRIVER_NAME ": unable to request PPI ERROR IRQ\n"); diff --git a/drivers/video/bw2.c b/drivers/video/bw2.c index 833b10c8406..275d9dab0c6 100644 --- a/drivers/video/bw2.c +++ b/drivers/video/bw2.c @@ -339,7 +339,7 @@ static int __devinit bw2_probe(struct of_device *op, const struct of_device_id * dev_set_drvdata(&op->dev, info); - printk("%s: bwtwo at %lx:%lx\n", + printk(KERN_INFO "%s: bwtwo at %lx:%lx\n", dp->full_name, par->which_io, par->physbase); return 0; @@ -399,10 +399,9 @@ static int __init bw2_init(void) static void __exit bw2_exit(void) { - return of_unregister_driver(&bw2_driver); + of_unregister_driver(&bw2_driver); } - module_init(bw2_init); module_exit(bw2_exit); diff --git a/drivers/video/cfbcopyarea.c b/drivers/video/cfbcopyarea.c index b07e419b12d..df03f3776dc 100644 --- a/drivers/video/cfbcopyarea.c +++ b/drivers/video/cfbcopyarea.c @@ -44,15 +44,16 @@ */ static void -bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src, - int src_idx, int bits, unsigned n, u32 bswapmask) +bitcpy(struct fb_info *p, unsigned long __iomem *dst, int dst_idx, + const unsigned long __iomem *src, int src_idx, int bits, + unsigned n, u32 bswapmask) { unsigned long first, last; int const shift = dst_idx-src_idx; int left, right; - first = fb_shifted_pixels_mask_long(dst_idx, bswapmask); - last = ~fb_shifted_pixels_mask_long((dst_idx+n) % bits, bswapmask); + first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask); + last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask); if (!shift) { // Same alignment for source and dest @@ -202,8 +203,9 @@ bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src */ static void -bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src, - int src_idx, int bits, unsigned n, u32 bswapmask) +bitcpy_rev(struct fb_info *p, unsigned long __iomem *dst, int dst_idx, + const unsigned long __iomem *src, int src_idx, int bits, + unsigned n, u32 bswapmask) { unsigned long first, last; int shift; @@ -221,8 +223,9 @@ bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem shift = dst_idx-src_idx; - first = fb_shifted_pixels_mask_long(bits - 1 - dst_idx, bswapmask); - last = ~fb_shifted_pixels_mask_long(bits - 1 - ((dst_idx-n) % bits), bswapmask); + first = fb_shifted_pixels_mask_long(p, bits - 1 - dst_idx, bswapmask); + last = ~fb_shifted_pixels_mask_long(p, bits - 1 - ((dst_idx-n) % bits), + bswapmask); if (!shift) { // Same alignment for source and dest @@ -404,7 +407,7 @@ void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) dst_idx &= (bytes - 1); src += src_idx >> (ffs(bits) - 1); src_idx &= (bytes - 1); - bitcpy_rev(dst, dst_idx, src, src_idx, bits, + bitcpy_rev(p, dst, dst_idx, src, src_idx, bits, width*p->var.bits_per_pixel, bswapmask); } } else { @@ -413,7 +416,7 @@ void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) dst_idx &= (bytes - 1); src += src_idx >> (ffs(bits) - 1); src_idx &= (bytes - 1); - bitcpy(dst, dst_idx, src, src_idx, bits, + bitcpy(p, dst, dst_idx, src, src_idx, bits, width*p->var.bits_per_pixel, bswapmask); dst_idx += bits_per_line; src_idx += bits_per_line; diff --git a/drivers/video/cfbfillrect.c b/drivers/video/cfbfillrect.c index 23d70a12e4d..64b35766b2a 100644 --- a/drivers/video/cfbfillrect.c +++ b/drivers/video/cfbfillrect.c @@ -36,16 +36,16 @@ */ static void -bitfill_aligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat, - unsigned n, int bits, u32 bswapmask) +bitfill_aligned(struct fb_info *p, unsigned long __iomem *dst, int dst_idx, + unsigned long pat, unsigned n, int bits, u32 bswapmask) { unsigned long first, last; if (!n) return; - first = fb_shifted_pixels_mask_long(dst_idx, bswapmask); - last = ~fb_shifted_pixels_mask_long((dst_idx+n) % bits, bswapmask); + first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask); + last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask); if (dst_idx+n <= bits) { // Single word @@ -93,16 +93,16 @@ bitfill_aligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat, */ static void -bitfill_unaligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat, - int left, int right, unsigned n, int bits) +bitfill_unaligned(struct fb_info *p, unsigned long __iomem *dst, int dst_idx, + unsigned long pat, int left, int right, unsigned n, int bits) { unsigned long first, last; if (!n) return; - first = FB_SHIFT_HIGH(~0UL, dst_idx); - last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits)); + first = FB_SHIFT_HIGH(p, ~0UL, dst_idx); + last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits)); if (dst_idx+n <= bits) { // Single word @@ -147,8 +147,9 @@ bitfill_unaligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat, * Aligned pattern invert using 32/64-bit memory accesses */ static void -bitfill_aligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat, - unsigned n, int bits, u32 bswapmask) +bitfill_aligned_rev(struct fb_info *p, unsigned long __iomem *dst, + int dst_idx, unsigned long pat, unsigned n, int bits, + u32 bswapmask) { unsigned long val = pat, dat; unsigned long first, last; @@ -156,8 +157,8 @@ bitfill_aligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat, if (!n) return; - first = fb_shifted_pixels_mask_long(dst_idx, bswapmask); - last = ~fb_shifted_pixels_mask_long((dst_idx+n) % bits, bswapmask); + first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask); + last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask); if (dst_idx+n <= bits) { // Single word @@ -217,16 +218,17 @@ bitfill_aligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat, */ static void -bitfill_unaligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat, - int left, int right, unsigned n, int bits) +bitfill_unaligned_rev(struct fb_info *p, unsigned long __iomem *dst, + int dst_idx, unsigned long pat, int left, int right, + unsigned n, int bits) { unsigned long first, last, dat; if (!n) return; - first = FB_SHIFT_HIGH(~0UL, dst_idx); - last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits)); + first = FB_SHIFT_HIGH(p, ~0UL, dst_idx); + last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits)); if (dst_idx+n <= bits) { // Single word @@ -306,7 +308,8 @@ void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) p->fbops->fb_sync(p); if (!left) { u32 bswapmask = fb_compute_bswapmask(p); - void (*fill_op32)(unsigned long __iomem *dst, int dst_idx, + void (*fill_op32)(struct fb_info *p, + unsigned long __iomem *dst, int dst_idx, unsigned long pat, unsigned n, int bits, u32 bswapmask) = NULL; @@ -325,16 +328,17 @@ void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) while (height--) { dst += dst_idx >> (ffs(bits) - 1); dst_idx &= (bits - 1); - fill_op32(dst, dst_idx, pat, width*bpp, bits, bswapmask); + fill_op32(p, dst, dst_idx, pat, width*bpp, bits, + bswapmask); dst_idx += p->fix.line_length*8; } } else { int right; int r; int rot = (left-dst_idx) % bpp; - void (*fill_op)(unsigned long __iomem *dst, int dst_idx, - unsigned long pat, int left, int right, - unsigned n, int bits) = NULL; + void (*fill_op)(struct fb_info *p, unsigned long __iomem *dst, + int dst_idx, unsigned long pat, int left, + int right, unsigned n, int bits) = NULL; /* rotate pattern to correct start position */ pat = pat << rot | pat >> (bpp-rot); @@ -355,7 +359,7 @@ void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) while (height--) { dst += dst_idx >> (ffs(bits) - 1); dst_idx &= (bits - 1); - fill_op(dst, dst_idx, pat, left, right, + fill_op(p, dst, dst_idx, pat, left, right, width*bpp, bits); r = (p->fix.line_length*8) % bpp; pat = pat << (bpp-r) | pat >> r; diff --git a/drivers/video/cfbimgblt.c b/drivers/video/cfbimgblt.c index f598907b42a..baed57d3cff 100644 --- a/drivers/video/cfbimgblt.c +++ b/drivers/video/cfbimgblt.c @@ -38,35 +38,31 @@ #define DEBUG #ifdef DEBUG -#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt,__FUNCTION__,## args) +#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt,__func__,## args) #else #define DPRINTK(fmt, args...) #endif -static const u32 cfb_tab8[] = { -#if defined(__BIG_ENDIAN) +static const u32 cfb_tab8_be[] = { 0x00000000,0x000000ff,0x0000ff00,0x0000ffff, 0x00ff0000,0x00ff00ff,0x00ffff00,0x00ffffff, 0xff000000,0xff0000ff,0xff00ff00,0xff00ffff, 0xffff0000,0xffff00ff,0xffffff00,0xffffffff -#elif defined(__LITTLE_ENDIAN) +}; + +static const u32 cfb_tab8_le[] = { 0x00000000,0xff000000,0x00ff0000,0xffff0000, 0x0000ff00,0xff00ff00,0x00ffff00,0xffffff00, 0x000000ff,0xff0000ff,0x00ff00ff,0xffff00ff, 0x0000ffff,0xff00ffff,0x00ffffff,0xffffffff -#else -#error FIXME: No endianness?? -#endif }; -static const u32 cfb_tab16[] = { -#if defined(__BIG_ENDIAN) +static const u32 cfb_tab16_be[] = { 0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff -#elif defined(__LITTLE_ENDIAN) +}; + +static const u32 cfb_tab16_le[] = { 0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff -#else -#error FIXME: No endianness?? -#endif }; static const u32 cfb_tab32[] = { @@ -98,7 +94,8 @@ static inline void color_imageblit(const struct fb_image *image, val = 0; if (start_index) { - u32 start_mask = ~fb_shifted_pixels_mask_u32(start_index, bswapmask); + u32 start_mask = ~fb_shifted_pixels_mask_u32(p, + start_index, bswapmask); val = FB_READL(dst) & start_mask; shift = start_index; } @@ -108,20 +105,21 @@ static inline void color_imageblit(const struct fb_image *image, color = palette[*src]; else color = *src; - color <<= FB_LEFT_POS(bpp); - val |= FB_SHIFT_HIGH(color, shift ^ bswapmask); + color <<= FB_LEFT_POS(p, bpp); + val |= FB_SHIFT_HIGH(p, color, shift ^ bswapmask); if (shift >= null_bits) { FB_WRITEL(val, dst++); val = (shift == null_bits) ? 0 : - FB_SHIFT_LOW(color, 32 - shift); + FB_SHIFT_LOW(p, color, 32 - shift); } shift += bpp; shift &= (32 - 1); src++; } if (shift) { - u32 end_mask = fb_shifted_pixels_mask_u32(shift, bswapmask); + u32 end_mask = fb_shifted_pixels_mask_u32(p, shift, + bswapmask); FB_WRITEL((FB_READL(dst) & end_mask) | val, dst); } @@ -152,8 +150,8 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info * u32 bswapmask = fb_compute_bswapmask(p); dst2 = (u32 __iomem *) dst1; - fgcolor <<= FB_LEFT_POS(bpp); - bgcolor <<= FB_LEFT_POS(bpp); + fgcolor <<= FB_LEFT_POS(p, bpp); + bgcolor <<= FB_LEFT_POS(p, bpp); for (i = image->height; i--; ) { shift = val = 0; @@ -164,7 +162,8 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info * /* write leading bits */ if (start_index) { - u32 start_mask = ~fb_shifted_pixels_mask_u32(start_index, bswapmask); + u32 start_mask = ~fb_shifted_pixels_mask_u32(p, + start_index, bswapmask); val = FB_READL(dst) & start_mask; shift = start_index; } @@ -172,13 +171,13 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info * while (j--) { l--; color = (*s & (1 << l)) ? fgcolor : bgcolor; - val |= FB_SHIFT_HIGH(color, shift ^ bswapmask); + val |= FB_SHIFT_HIGH(p, color, shift ^ bswapmask); /* Did the bitshift spill bits to the next long? */ if (shift >= null_bits) { FB_WRITEL(val, dst++); val = (shift == null_bits) ? 0 : - FB_SHIFT_LOW(color,32 - shift); + FB_SHIFT_LOW(p, color, 32 - shift); } shift += bpp; shift &= (32 - 1); @@ -187,7 +186,8 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info * /* write trailing bits */ if (shift) { - u32 end_mask = fb_shifted_pixels_mask_u32(shift, bswapmask); + u32 end_mask = fb_shifted_pixels_mask_u32(p, shift, + bswapmask); FB_WRITEL((FB_READL(dst) & end_mask) | val, dst); } @@ -223,13 +223,13 @@ static inline void fast_imageblit(const struct fb_image *image, struct fb_info * u32 __iomem *dst; const u32 *tab = NULL; int i, j, k; - + switch (bpp) { case 8: - tab = cfb_tab8; + tab = fb_be_math(p) ? cfb_tab8_be : cfb_tab8_le; break; case 16: - tab = cfb_tab16; + tab = fb_be_math(p) ? cfb_tab16_be : cfb_tab16_le; break; case 32: default: diff --git a/drivers/video/cg14.c b/drivers/video/cg14.c index fdc9f43ec30..0db0fecba93 100644 --- a/drivers/video/cg14.c +++ b/drivers/video/cg14.c @@ -556,7 +556,7 @@ static int __devinit cg14_probe(struct of_device *op, const struct of_device_id dev_set_drvdata(&op->dev, info); - printk("%s: cgfourteen at %lx:%lx, %dMB\n", + printk(KERN_INFO "%s: cgfourteen at %lx:%lx, %dMB\n", dp->full_name, par->iospace, par->physbase, par->ramsize >> 20); @@ -605,7 +605,7 @@ static struct of_platform_driver cg14_driver = { .remove = __devexit_p(cg14_remove), }; -int __init cg14_init(void) +static int __init cg14_init(void) { if (fb_get_options("cg14fb", NULL)) return -ENODEV; @@ -613,7 +613,7 @@ int __init cg14_init(void) return of_register_driver(&cg14_driver, &of_bus_type); } -void __exit cg14_exit(void) +static void __exit cg14_exit(void) { of_unregister_driver(&cg14_driver); } diff --git a/drivers/video/cg3.c b/drivers/video/cg3.c index a5c7fb33152..010ea53978f 100644 --- a/drivers/video/cg3.c +++ b/drivers/video/cg3.c @@ -419,7 +419,7 @@ static int __devinit cg3_probe(struct of_device *op, dev_set_drvdata(&op->dev, info); - printk("%s: cg3 at %lx:%lx\n", + printk(KERN_INFO "%s: cg3 at %lx:%lx\n", dp->full_name, par->which_io, par->physbase); return 0; diff --git a/drivers/video/cg6.c b/drivers/video/cg6.c index 549891d76ef..fc90db6da65 100644 --- a/drivers/video/cg6.c +++ b/drivers/video/cg6.c @@ -781,7 +781,7 @@ static int __devinit cg6_probe(struct of_device *op, dev_set_drvdata(&op->dev, info); - printk("%s: CGsix [%s] at %lx:%lx\n", + printk(KERN_INFO "%s: CGsix [%s] at %lx:%lx\n", dp->full_name, info->fix.id, par->which_io, par->physbase); diff --git a/drivers/video/cirrusfb.c b/drivers/video/cirrusfb.c index f7e2d5add83..35ac9d956b3 100644 --- a/drivers/video/cirrusfb.c +++ b/drivers/video/cirrusfb.c @@ -81,7 +81,7 @@ /* debug output */ #ifdef CIRRUSFB_DEBUG #define DPRINTK(fmt, args...) \ - printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) + printk(KERN_DEBUG "%s: " fmt, __func__ , ## args) #else #define DPRINTK(fmt, args...) #endif @@ -91,7 +91,7 @@ #define assert(expr) \ if (!(expr)) { \ printk("Assertion failed! %s,%s,%s,line=%d\n", \ - #expr, __FILE__, __FUNCTION__, __LINE__); \ + #expr, __FILE__, __func__, __LINE__); \ } #else #define assert(expr) @@ -3117,7 +3117,7 @@ static void bestclock(long freq, long *best, long *nom, } } } - d = ((143181 * n) + f - 1) / f; + d = DIV_ROUND_UP(143181 * n, f); if ((d >= 7) && (d <= 63)) { if (d > 31) d = (d / 2) * 2; diff --git a/drivers/video/clps711xfb.c b/drivers/video/clps711xfb.c index 17b5267f44d..9f8a389dc7a 100644 --- a/drivers/video/clps711xfb.c +++ b/drivers/video/clps711xfb.c @@ -381,7 +381,7 @@ int __init clps711xfb_init(void) /* Register the /proc entries. */ clps7111fb_backlight_proc_entry = create_proc_entry("backlight", 0444, - &proc_root); + NULL); if (clps7111fb_backlight_proc_entry == NULL) { printk("Couldn't create the /proc entry for the backlight.\n"); return -EINVAL; diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 022282494d3..ad31983b43e 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -92,7 +92,7 @@ #include "fbcon.h" #ifdef FBCONDEBUG -# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) +# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __func__ , ## args) #else # define DPRINTK(fmt, args...) #endif @@ -620,8 +620,7 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info, if (fb_get_color_depth(&info->var, &info->fix) == 1) erase &= ~0x400; logo_height = fb_prepare_logo(info, ops->rotate); - logo_lines = (logo_height + vc->vc_font.height - 1) / - vc->vc_font.height; + logo_lines = DIV_ROUND_UP(logo_height, vc->vc_font.height); q = (unsigned short *) (vc->vc_origin + vc->vc_size_row * rows); step = logo_lines * cols; @@ -1882,7 +1881,7 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir, scr_memsetw((unsigned short *) (vc->vc_origin + vc->vc_size_row * (b - count)), - vc->vc_video_erase_char, + vc->vc_scrl_erase_char, vc->vc_size_row * count); return 1; break; @@ -1954,7 +1953,7 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir, scr_memsetw((unsigned short *) (vc->vc_origin + vc->vc_size_row * (b - count)), - vc->vc_video_erase_char, + vc->vc_scrl_erase_char, vc->vc_size_row * count); return 1; } @@ -1973,7 +1972,7 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir, scr_memsetw((unsigned short *) (vc->vc_origin + vc->vc_size_row * t), - vc->vc_video_erase_char, + vc->vc_scrl_erase_char, vc->vc_size_row * count); return 1; break; @@ -2043,7 +2042,7 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir, scr_memsetw((unsigned short *) (vc->vc_origin + vc->vc_size_row * t), - vc->vc_video_erase_char, + vc->vc_scrl_erase_char, vc->vc_size_row * count); return 1; } diff --git a/drivers/video/console/fbcon.h b/drivers/video/console/fbcon.h index 3706307e70e..0135e039545 100644 --- a/drivers/video/console/fbcon.h +++ b/drivers/video/console/fbcon.h @@ -104,10 +104,14 @@ struct fbcon_ops { #define attr_blink(s) \ ((s) & 0x8000) -#define mono_col(info) \ - (~(0xfff << (max((info)->var.green.length, \ - max((info)->var.red.length, \ - (info)->var.blue.length)))) & 0xff) + +static inline int mono_col(const struct fb_info *info) +{ + __u32 max_len; + max_len = max(info->var.green.length, info->var.red.length); + max_len = max(info->var.blue.length, max_len); + return ~(0xfff << (max_len & 0xff)); +} static inline int attr_col_ec(int shift, struct vc_data *vc, struct fb_info *info, int is_fg) diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c index bd8d995fe25..38a296bbdfc 100644 --- a/drivers/video/console/mdacon.c +++ b/drivers/video/console/mdacon.c @@ -531,7 +531,7 @@ static void mdacon_cursor(struct vc_data *c, int mode) static int mdacon_scroll(struct vc_data *c, int t, int b, int dir, int lines) { - u16 eattr = mda_convert_attr(c->vc_video_erase_char); + u16 eattr = mda_convert_attr(c->vc_scrl_erase_char); if (!lines) return 0; diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c index 67a682d6cc7..a11cc2fdd4c 100644 --- a/drivers/video/console/sticon.c +++ b/drivers/video/console/sticon.c @@ -170,12 +170,12 @@ static int sticon_scroll(struct vc_data *conp, int t, int b, int dir, int count) switch (dir) { case SM_UP: sti_bmove(sti, t + count, 0, t, 0, b - t - count, conp->vc_cols); - sti_clear(sti, b - count, 0, count, conp->vc_cols, conp->vc_video_erase_char); + sti_clear(sti, b - count, 0, count, conp->vc_cols, conp->vc_scrl_erase_char); break; case SM_DOWN: sti_bmove(sti, t, 0, t + count, 0, b - t - count, conp->vc_cols); - sti_clear(sti, t, 0, count, conp->vc_cols, conp->vc_video_erase_char); + sti_clear(sti, t, 0, count, conp->vc_cols, conp->vc_scrl_erase_char); break; } diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index 6df29a62d72..bd1f57b259d 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -1350,7 +1350,7 @@ static int vgacon_scroll(struct vc_data *c, int t, int b, int dir, } else c->vc_origin += delta; scr_memsetw((u16 *) (c->vc_origin + c->vc_screenbuf_size - - delta), c->vc_video_erase_char, + delta), c->vc_scrl_erase_char, delta); } else { if (oldo - delta < vga_vram_base) { @@ -1363,7 +1363,7 @@ static int vgacon_scroll(struct vc_data *c, int t, int b, int dir, } else c->vc_origin -= delta; c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size; - scr_memsetw((u16 *) (c->vc_origin), c->vc_video_erase_char, + scr_memsetw((u16 *) (c->vc_origin), c->vc_scrl_erase_char, delta); } c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size; diff --git a/drivers/video/fb_draw.h b/drivers/video/fb_draw.h index a2a0618d86a..1db622192bd 100644 --- a/drivers/video/fb_draw.h +++ b/drivers/video/fb_draw.h @@ -94,41 +94,44 @@ static inline unsigned long fb_rev_pixels_in_long(unsigned long val, return val; } -static inline u32 fb_shifted_pixels_mask_u32(u32 index, u32 bswapmask) +static inline u32 fb_shifted_pixels_mask_u32(struct fb_info *p, u32 index, + u32 bswapmask) { u32 mask; if (!bswapmask) { - mask = FB_SHIFT_HIGH(~(u32)0, index); + mask = FB_SHIFT_HIGH(p, ~(u32)0, index); } else { - mask = 0xff << FB_LEFT_POS(8); - mask = FB_SHIFT_LOW(mask, index & (bswapmask)) & mask; - mask = FB_SHIFT_HIGH(mask, index & ~(bswapmask)); + mask = 0xff << FB_LEFT_POS(p, 8); + mask = FB_SHIFT_LOW(p, mask, index & (bswapmask)) & mask; + mask = FB_SHIFT_HIGH(p, mask, index & ~(bswapmask)); #if defined(__i386__) || defined(__x86_64__) /* Shift argument is limited to 0 - 31 on x86 based CPU's */ if(index + bswapmask < 32) #endif - mask |= FB_SHIFT_HIGH(~(u32)0, + mask |= FB_SHIFT_HIGH(p, ~(u32)0, (index + bswapmask) & ~(bswapmask)); } return mask; } -static inline unsigned long fb_shifted_pixels_mask_long(u32 index, u32 bswapmask) +static inline unsigned long fb_shifted_pixels_mask_long(struct fb_info *p, + u32 index, + u32 bswapmask) { unsigned long mask; if (!bswapmask) { - mask = FB_SHIFT_HIGH(~0UL, index); + mask = FB_SHIFT_HIGH(p, ~0UL, index); } else { - mask = 0xff << FB_LEFT_POS(8); - mask = FB_SHIFT_LOW(mask, index & (bswapmask)) & mask; - mask = FB_SHIFT_HIGH(mask, index & ~(bswapmask)); + mask = 0xff << FB_LEFT_POS(p, 8); + mask = FB_SHIFT_LOW(p, mask, index & (bswapmask)) & mask; + mask = FB_SHIFT_HIGH(p, mask, index & ~(bswapmask)); #if defined(__i386__) || defined(__x86_64__) /* Shift argument is limited to 0 - 31 on x86 based CPU's */ if(index + bswapmask < BITS_PER_LONG) #endif - mask |= FB_SHIFT_HIGH(~0UL, + mask |= FB_SHIFT_HIGH(p, ~0UL, (index + bswapmask) & ~(bswapmask)); } return mask; @@ -158,8 +161,8 @@ static inline unsigned long fb_rev_pixels_in_long(unsigned long val, return val; } -#define fb_shifted_pixels_mask_u32(i, b) FB_SHIFT_HIGH(~(u32)0, (i)) -#define fb_shifted_pixels_mask_long(i, b) FB_SHIFT_HIGH(~0UL, (i)) +#define fb_shifted_pixels_mask_u32(p, i, b) FB_SHIFT_HIGH((p), ~(u32)0, (i)) +#define fb_shifted_pixels_mask_long(p, i, b) FB_SHIFT_HIGH((p), ~0UL, (i)) #define fb_compute_bswapmask(...) 0 #endif /* CONFIG_FB_CFB_REV_PIXELS_IN_BYTE */ diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 01072f4b3e8..776f7fcd2fb 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -26,6 +26,7 @@ #include <linux/init.h> #include <linux/linux_logo.h> #include <linux/proc_fs.h> +#include <linux/seq_file.h> #include <linux/console.h> #ifdef CONFIG_KMOD #include <linux/kmod.h> @@ -632,27 +633,51 @@ int fb_prepare_logo(struct fb_info *info, int rotate) { return 0; } int fb_show_logo(struct fb_info *info, int rotate) { return 0; } #endif /* CONFIG_LOGO */ -static int fbmem_read_proc(char *buf, char **start, off_t offset, - int len, int *eof, void *private) +static void *fb_seq_start(struct seq_file *m, loff_t *pos) { - struct fb_info **fi; - int clen; - - clen = 0; - for (fi = registered_fb; fi < ®istered_fb[FB_MAX] && clen < 4000; - fi++) - if (*fi) - clen += sprintf(buf + clen, "%d %s\n", - (*fi)->node, - (*fi)->fix.id); - *start = buf + offset; - if (clen > offset) - clen -= offset; - else - clen = 0; - return clen < len ? clen : len; + return (*pos < FB_MAX) ? pos : NULL; +} + +static void *fb_seq_next(struct seq_file *m, void *v, loff_t *pos) +{ + (*pos)++; + return (*pos < FB_MAX) ? pos : NULL; +} + +static void fb_seq_stop(struct seq_file *m, void *v) +{ +} + +static int fb_seq_show(struct seq_file *m, void *v) +{ + int i = *(loff_t *)v; + struct fb_info *fi = registered_fb[i]; + + if (fi) + seq_printf(m, "%d %s\n", fi->node, fi->fix.id); + return 0; +} + +static const struct seq_operations proc_fb_seq_ops = { + .start = fb_seq_start, + .next = fb_seq_next, + .stop = fb_seq_stop, + .show = fb_seq_show, +}; + +static int proc_fb_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &proc_fb_seq_ops); } +static const struct file_operations fb_proc_fops = { + .owner = THIS_MODULE, + .open = proc_fb_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + static ssize_t fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { @@ -1057,7 +1082,7 @@ fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, case FBIOPUT_CON2FBMAP: if (copy_from_user(&con2fb, argp, sizeof(con2fb))) return - EFAULT; - if (con2fb.console < 0 || con2fb.console > MAX_NR_CONSOLES) + if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES) return -EINVAL; if (con2fb.framebuffer < 0 || con2fb.framebuffer >= FB_MAX) return -EINVAL; @@ -1352,6 +1377,32 @@ static const struct file_operations fb_fops = { struct class *fb_class; EXPORT_SYMBOL(fb_class); + +static int fb_check_foreignness(struct fb_info *fi) +{ + const bool foreign_endian = fi->flags & FBINFO_FOREIGN_ENDIAN; + + fi->flags &= ~FBINFO_FOREIGN_ENDIAN; + +#ifdef __BIG_ENDIAN + fi->flags |= foreign_endian ? 0 : FBINFO_BE_MATH; +#else + fi->flags |= foreign_endian ? FBINFO_BE_MATH : 0; +#endif /* __BIG_ENDIAN */ + + if (fi->flags & FBINFO_BE_MATH && !fb_be_math(fi)) { + pr_err("%s: enable CONFIG_FB_BIG_ENDIAN to " + "support this framebuffer\n", fi->fix.id); + return -ENOSYS; + } else if (!(fi->flags & FBINFO_BE_MATH) && fb_be_math(fi)) { + pr_err("%s: enable CONFIG_FB_LITTLE_ENDIAN to " + "support this framebuffer\n", fi->fix.id); + return -ENOSYS; + } + + return 0; +} + /** * register_framebuffer - registers a frame buffer device * @fb_info: frame buffer info structure @@ -1371,6 +1422,10 @@ register_framebuffer(struct fb_info *fb_info) if (num_registered_fb == FB_MAX) return -ENXIO; + + if (fb_check_foreignness(fb_info)) + return -ENOSYS; + num_registered_fb++; for (i = 0 ; i < FB_MAX; i++) if (!registered_fb[i]) @@ -1503,7 +1558,7 @@ void fb_set_suspend(struct fb_info *info, int state) static int __init fbmem_init(void) { - create_proc_read_entry("fb", 0, NULL, fbmem_read_proc, NULL); + proc_create("fb", 0, NULL, &fb_proc_fops); if (register_chrdev(FB_MAJOR,"fb",&fb_fops)) printk("unable to get major %d for fb devs\n", FB_MAJOR); diff --git a/drivers/video/ffb.c b/drivers/video/ffb.c index d7e24889650..93dca3e2aa5 100644 --- a/drivers/video/ffb.c +++ b/drivers/video/ffb.c @@ -32,7 +32,6 @@ static int ffb_setcolreg(unsigned, unsigned, unsigned, unsigned, unsigned, struct fb_info *); static int ffb_blank(int, struct fb_info *); -static void ffb_init_fix(struct fb_info *); static void ffb_imageblit(struct fb_info *, const struct fb_image *); static void ffb_fillrect(struct fb_info *, const struct fb_fillrect *); @@ -1001,7 +1000,7 @@ static int __devinit ffb_probe(struct of_device *op, dev_set_drvdata(&op->dev, info); - printk("%s: %s at %016lx, type %d, " + printk(KERN_INFO "%s: %s at %016lx, type %d, " "DAC pnum[%x] rev[%d] manuf_rev[%d]\n", dp->full_name, ((par->flags & FFB_FLAG_AFB) ? "AFB" : "FFB"), @@ -1062,7 +1061,7 @@ static struct of_platform_driver ffb_driver = { .remove = __devexit_p(ffb_remove), }; -int __init ffb_init(void) +static int __init ffb_init(void) { if (fb_get_options("ffb", NULL)) return -ENODEV; @@ -1070,7 +1069,7 @@ int __init ffb_init(void) return of_register_driver(&ffb_driver, &of_bus_type); } -void __exit ffb_exit(void) +static void __exit ffb_exit(void) { of_unregister_driver(&ffb_driver); } diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c new file mode 100644 index 00000000000..b50bb03cb5a --- /dev/null +++ b/drivers/video/fsl-diu-fb.c @@ -0,0 +1,1721 @@ +/* + * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved. + * + * Freescale DIU Frame Buffer device driver + * + * Authors: Hongjun Chen <hong-jun.chen@freescale.com> + * Paul Widmer <paul.widmer@freescale.com> + * Srikanth Srinivasan <srikanth.srinivasan@freescale.com> + * York Sun <yorksun@freescale.com> + * + * Based on imxfb.c Copyright (C) 2004 S.Hauer, Pengutronix + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/slab.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/dma-mapping.h> +#include <linux/platform_device.h> +#include <linux/interrupt.h> +#include <linux/clk.h> +#include <linux/uaccess.h> +#include <linux/vmalloc.h> + +#include <linux/of_platform.h> + +#include <sysdev/fsl_soc.h> +#include "fsl-diu-fb.h" + +/* + * These parameters give default parameters + * for video output 1024x768, + * FIXME - change timing to proper amounts + * hsync 31.5kHz, vsync 60Hz + */ +static struct fb_videomode __devinitdata fsl_diu_default_mode = { + .refresh = 60, + .xres = 1024, + .yres = 768, + .pixclock = 15385, + .left_margin = 160, + .right_margin = 24, + .upper_margin = 29, + .lower_margin = 3, + .hsync_len = 136, + .vsync_len = 6, + .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .vmode = FB_VMODE_NONINTERLACED +}; + +static struct fb_videomode __devinitdata fsl_diu_mode_db[] = { + { + .name = "1024x768-60", + .refresh = 60, + .xres = 1024, + .yres = 768, + .pixclock = 15385, + .left_margin = 160, + .right_margin = 24, + .upper_margin = 29, + .lower_margin = 3, + .hsync_len = 136, + .vsync_len = 6, + .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .vmode = FB_VMODE_NONINTERLACED + }, + { + .name = "1024x768-70", + .refresh = 70, + .xres = 1024, + .yres = 768, + .pixclock = 16886, + .left_margin = 3, + .right_margin = 3, + .upper_margin = 2, + .lower_margin = 2, + .hsync_len = 40, + .vsync_len = 18, + .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .vmode = FB_VMODE_NONINTERLACED + }, + { + .name = "1024x768-75", + .refresh = 75, + .xres = 1024, + .yres = 768, + .pixclock = 15009, + .left_margin = 3, + .right_margin = 3, + .upper_margin = 2, + .lower_margin = 2, + .hsync_len = 80, + .vsync_len = 32, + .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .vmode = FB_VMODE_NONINTERLACED + }, + { + .name = "1280x1024-60", + .refresh = 60, + .xres = 1280, + .yres = 1024, + .pixclock = 9375, + .left_margin = 38, + .right_margin = 128, + .upper_margin = 2, + .lower_margin = 7, + .hsync_len = 216, + .vsync_len = 37, + .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .vmode = FB_VMODE_NONINTERLACED + }, + { + .name = "1280x1024-70", + .refresh = 70, + .xres = 1280, + .yres = 1024, + .pixclock = 9380, + .left_margin = 6, + .right_margin = 6, + .upper_margin = 4, + .lower_margin = 4, + .hsync_len = 60, + .vsync_len = 94, + .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .vmode = FB_VMODE_NONINTERLACED + }, + { + .name = "1280x1024-75", + .refresh = 75, + .xres = 1280, + .yres = 1024, + .pixclock = 9380, + .left_margin = 6, + .right_margin = 6, + .upper_margin = 4, + .lower_margin = 4, + .hsync_len = 60, + .vsync_len = 15, + .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .vmode = FB_VMODE_NONINTERLACED + }, + { + .name = "320x240", /* for AOI only */ + .refresh = 60, + .xres = 320, + .yres = 240, + .pixclock = 15385, + .left_margin = 0, + .right_margin = 0, + .upper_margin = 0, + .lower_margin = 0, + .hsync_len = 0, + .vsync_len = 0, + .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .vmode = FB_VMODE_NONINTERLACED + }, + { + .name = "1280x480-60", + .refresh = 60, + .xres = 1280, + .yres = 480, + .pixclock = 18939, + .left_margin = 353, + .right_margin = 47, + .upper_margin = 39, + .lower_margin = 4, + .hsync_len = 8, + .vsync_len = 2, + .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .vmode = FB_VMODE_NONINTERLACED + }, +}; + +static char *fb_mode = "1024x768-32@60"; +static unsigned long default_bpp = 32; +static int monitor_port; + +#if defined(CONFIG_NOT_COHERENT_CACHE) +static u8 *coherence_data; +static size_t coherence_data_size; +static unsigned int d_cache_line_size; +#endif + +static DEFINE_SPINLOCK(diu_lock); + +struct fsl_diu_data { + struct fb_info *fsl_diu_info[FSL_AOI_NUM - 1]; + /*FSL_AOI_NUM has one dummy AOI */ + struct device_attribute dev_attr; + struct diu_ad *dummy_ad; + void *dummy_aoi_virt; + unsigned int irq; + int fb_enabled; + int monitor_port; +}; + +struct mfb_info { + int index; + int type; + char *id; + int registered; + int blank; + unsigned long pseudo_palette[16]; + struct diu_ad *ad; + int cursor_reset; + unsigned char g_alpha; + unsigned int count; + int x_aoi_d; /* aoi display x offset to physical screen */ + int y_aoi_d; /* aoi display y offset to physical screen */ + struct fsl_diu_data *parent; +}; + + +static struct mfb_info mfb_template[] = { + { /* AOI 0 for plane 0 */ + .index = 0, + .type = MFB_TYPE_OUTPUT, + .id = "Panel0", + .registered = 0, + .count = 0, + .x_aoi_d = 0, + .y_aoi_d = 0, + }, + { /* AOI 0 for plane 1 */ + .index = 1, + .type = MFB_TYPE_OUTPUT, + .id = "Panel1 AOI0", + .registered = 0, + .g_alpha = 0xff, + .count = 0, + .x_aoi_d = 0, + .y_aoi_d = 0, + }, + { /* AOI 1 for plane 1 */ + .index = 2, + .type = MFB_TYPE_OUTPUT, + .id = "Panel1 AOI1", + .registered = 0, + .g_alpha = 0xff, + .count = 0, + .x_aoi_d = 0, + .y_aoi_d = 480, + }, + { /* AOI 0 for plane 2 */ + .index = 3, + .type = MFB_TYPE_OUTPUT, + .id = "Panel2 AOI0", + .registered = 0, + .g_alpha = 0xff, + .count = 0, + .x_aoi_d = 640, + .y_aoi_d = 0, + }, + { /* AOI 1 for plane 2 */ + .index = 4, + .type = MFB_TYPE_OUTPUT, + .id = "Panel2 AOI1", + .registered = 0, + .g_alpha = 0xff, + .count = 0, + .x_aoi_d = 640, + .y_aoi_d = 480, + }, +}; + +static struct diu_hw dr = { + .mode = MFB_MODE1, + .reg_lock = __SPIN_LOCK_UNLOCKED(diu_hw.reg_lock), +}; + +static struct diu_pool pool; + +/* To allocate memory for framebuffer. First try __get_free_pages(). If it + * fails, try rh_alloc. The reason is __get_free_pages() cannot allocate + * very large memory (more than 4MB). We don't want to allocate all memory + * in rheap since small memory allocation/deallocation will fragment the + * rheap and make the furture large allocation fail. + */ + +void *fsl_diu_alloc(unsigned long size, phys_addr_t *phys) +{ + void *virt; + + pr_debug("size=%lu\n", size); + + virt = (void *)__get_free_pages(GFP_DMA | __GFP_ZERO, get_order(size)); + if (virt) { + *phys = virt_to_phys(virt); + pr_debug("virt %p, phys=%llx\n", virt, (uint64_t) *phys); + return virt; + } + if (!diu_ops.diu_mem) { + printk(KERN_INFO "%s: no diu_mem." + " To reserve more memory, put 'diufb=15M' " + "in the command line\n", __func__); + return NULL; + } + + virt = (void *)rh_alloc(&diu_ops.diu_rh_info, size, "DIU"); + if (virt) { + *phys = virt_to_bus(virt); + memset(virt, 0, size); + } + + pr_debug("rh virt=%p phys=%lx\n", virt, *phys); + + return virt; +} + +void fsl_diu_free(void *p, unsigned long size) +{ + pr_debug("p=%p size=%lu\n", p, size); + + if (!p) + return; + + if ((p >= diu_ops.diu_mem) && + (p < (diu_ops.diu_mem + diu_ops.diu_size))) { + pr_debug("rh\n"); + rh_free(&diu_ops.diu_rh_info, (unsigned long) p); + } else { + pr_debug("dma\n"); + free_pages((unsigned long)p, get_order(size)); + } +} + +static int fsl_diu_enable_panel(struct fb_info *info) +{ + struct mfb_info *pmfbi, *cmfbi, *mfbi = info->par; + struct diu *hw = dr.diu_reg; + struct diu_ad *ad = mfbi->ad; + struct fsl_diu_data *machine_data = mfbi->parent; + int res = 0; + + pr_debug("enable_panel index %d\n", mfbi->index); + if (mfbi->type != MFB_TYPE_OFF) { + switch (mfbi->index) { + case 0: /* plane 0 */ + if (hw->desc[0] != ad->paddr) + out_be32(&hw->desc[0], ad->paddr); + break; + case 1: /* plane 1 AOI 0 */ + cmfbi = machine_data->fsl_diu_info[2]->par; + if (hw->desc[1] != ad->paddr) { /* AOI0 closed */ + if (cmfbi->count > 0) /* AOI1 open */ + ad->next_ad = + cpu_to_le32(cmfbi->ad->paddr); + else + ad->next_ad = 0; + out_be32(&hw->desc[1], ad->paddr); + } + break; + case 3: /* plane 2 AOI 0 */ + cmfbi = machine_data->fsl_diu_info[4]->par; + if (hw->desc[2] != ad->paddr) { /* AOI0 closed */ + if (cmfbi->count > 0) /* AOI1 open */ + ad->next_ad = + cpu_to_le32(cmfbi->ad->paddr); + else + ad->next_ad = 0; + out_be32(&hw->desc[2], ad->paddr); + } + break; + case 2: /* plane 1 AOI 1 */ + pmfbi = machine_data->fsl_diu_info[1]->par; + ad->next_ad = 0; + if (hw->desc[1] == machine_data->dummy_ad->paddr) + out_be32(&hw->desc[1], ad->paddr); + else /* AOI0 open */ + pmfbi->ad->next_ad = cpu_to_le32(ad->paddr); + break; + case 4: /* plane 2 AOI 1 */ + pmfbi = machine_data->fsl_diu_info[3]->par; + ad->next_ad = 0; + if (hw->desc[2] == machine_data->dummy_ad->paddr) + out_be32(&hw->desc[2], ad->paddr); + else /* AOI0 was open */ + pmfbi->ad->next_ad = cpu_to_le32(ad->paddr); + break; + default: + res = -EINVAL; + break; + } + } else + res = -EINVAL; + return res; +} + +static int fsl_diu_disable_panel(struct fb_info *info) +{ + struct mfb_info *pmfbi, *cmfbi, *mfbi = info->par; + struct diu *hw = dr.diu_reg; + struct diu_ad *ad = mfbi->ad; + struct fsl_diu_data *machine_data = mfbi->parent; + int res = 0; + + switch (mfbi->index) { + case 0: /* plane 0 */ + if (hw->desc[0] != machine_data->dummy_ad->paddr) + out_be32(&hw->desc[0], + machine_data->dummy_ad->paddr); + break; + case 1: /* plane 1 AOI 0 */ + cmfbi = machine_data->fsl_diu_info[2]->par; + if (cmfbi->count > 0) /* AOI1 is open */ + out_be32(&hw->desc[1], cmfbi->ad->paddr); + /* move AOI1 to the first */ + else /* AOI1 was closed */ + out_be32(&hw->desc[1], + machine_data->dummy_ad->paddr); + /* close AOI 0 */ + break; + case 3: /* plane 2 AOI 0 */ + cmfbi = machine_data->fsl_diu_info[4]->par; + if (cmfbi->count > 0) /* AOI1 is open */ + out_be32(&hw->desc[2], cmfbi->ad->paddr); + /* move AOI1 to the first */ + else /* AOI1 was closed */ + out_be32(&hw->desc[2], + machine_data->dummy_ad->paddr); + /* close AOI 0 */ + break; + case 2: /* plane 1 AOI 1 */ + pmfbi = machine_data->fsl_diu_info[1]->par; + if (hw->desc[1] != ad->paddr) { + /* AOI1 is not the first in the chain */ + if (pmfbi->count > 0) + /* AOI0 is open, must be the first */ + pmfbi->ad->next_ad = 0; + } else /* AOI1 is the first in the chain */ + out_be32(&hw->desc[1], machine_data->dummy_ad->paddr); + /* close AOI 1 */ + break; + case 4: /* plane 2 AOI 1 */ + pmfbi = machine_data->fsl_diu_info[3]->par; + if (hw->desc[2] != ad->paddr) { + /* AOI1 is not the first in the chain */ + if (pmfbi->count > 0) + /* AOI0 is open, must be the first */ + pmfbi->ad->next_ad = 0; + } else /* AOI1 is the first in the chain */ + out_be32(&hw->desc[2], machine_data->dummy_ad->paddr); + /* close AOI 1 */ + break; + default: + res = -EINVAL; + break; + } + + return res; +} + +static void enable_lcdc(struct fb_info *info) +{ + struct diu *hw = dr.diu_reg; + struct mfb_info *mfbi = info->par; + struct fsl_diu_data *machine_data = mfbi->parent; + + if (!machine_data->fb_enabled) { + out_be32(&hw->diu_mode, dr.mode); + machine_data->fb_enabled++; + } +} + +static void disable_lcdc(struct fb_info *info) +{ + struct diu *hw = dr.diu_reg; + struct mfb_info *mfbi = info->par; + struct fsl_diu_data *machine_data = mfbi->parent; + + if (machine_data->fb_enabled) { + out_be32(&hw->diu_mode, 0); + machine_data->fb_enabled = 0; + } +} + +static void adjust_aoi_size_position(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct mfb_info *lower_aoi_mfbi, *upper_aoi_mfbi, *mfbi = info->par; + struct fsl_diu_data *machine_data = mfbi->parent; + int available_height, upper_aoi_bottom, index = mfbi->index; + int lower_aoi_is_open, upper_aoi_is_open; + __u32 base_plane_width, base_plane_height, upper_aoi_height; + + base_plane_width = machine_data->fsl_diu_info[0]->var.xres; + base_plane_height = machine_data->fsl_diu_info[0]->var.yres; + + switch (index) { + case 0: + if (mfbi->x_aoi_d != 0) + mfbi->x_aoi_d = 0; + if (mfbi->y_aoi_d != 0) + mfbi->y_aoi_d = 0; + break; + case 1: /* AOI 0 */ + case 3: + lower_aoi_mfbi = machine_data->fsl_diu_info[index+1]->par; + lower_aoi_is_open = lower_aoi_mfbi->count > 0 ? 1 : 0; + if (var->xres > base_plane_width) + var->xres = base_plane_width; + if ((mfbi->x_aoi_d + var->xres) > base_plane_width) + mfbi->x_aoi_d = base_plane_width - var->xres; + + if (lower_aoi_is_open) + available_height = lower_aoi_mfbi->y_aoi_d; + else + available_height = base_plane_height; + if (var->yres > available_height) + var->yres = available_height; + if ((mfbi->y_aoi_d + var->yres) > available_height) + mfbi->y_aoi_d = available_height - var->yres; + break; + case 2: /* AOI 1 */ + case 4: + upper_aoi_mfbi = machine_data->fsl_diu_info[index-1]->par; + upper_aoi_height = + machine_data->fsl_diu_info[index-1]->var.yres; + upper_aoi_bottom = upper_aoi_mfbi->y_aoi_d + upper_aoi_height; + upper_aoi_is_open = upper_aoi_mfbi->count > 0 ? 1 : 0; + if (var->xres > base_plane_width) + var->xres = base_plane_width; + if ((mfbi->x_aoi_d + var->xres) > base_plane_width) + mfbi->x_aoi_d = base_plane_width - var->xres; + if (mfbi->y_aoi_d < 0) + mfbi->y_aoi_d = 0; + if (upper_aoi_is_open) { + if (mfbi->y_aoi_d < upper_aoi_bottom) + mfbi->y_aoi_d = upper_aoi_bottom; + available_height = base_plane_height + - upper_aoi_bottom; + } else + available_height = base_plane_height; + if (var->yres > available_height) + var->yres = available_height; + if ((mfbi->y_aoi_d + var->yres) > base_plane_height) + mfbi->y_aoi_d = base_plane_height - var->yres; + break; + } +} +/* + * Checks to see if the hardware supports the state requested by var passed + * in. This function does not alter the hardware state! If the var passed in + * is slightly off by what the hardware can support then we alter the var + * PASSED in to what we can do. If the hardware doesn't support mode change + * a -EINVAL will be returned by the upper layers. + */ +static int fsl_diu_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + unsigned long htotal, vtotal; + + pr_debug("check_var xres: %d\n", var->xres); + pr_debug("check_var yres: %d\n", var->yres); + + if (var->xres_virtual < var->xres) + var->xres_virtual = var->xres; + if (var->yres_virtual < var->yres) + var->yres_virtual = var->yres; + + if (var->xoffset < 0) + var->xoffset = 0; + + if (var->yoffset < 0) + var->yoffset = 0; + + if (var->xoffset + info->var.xres > info->var.xres_virtual) + var->xoffset = info->var.xres_virtual - info->var.xres; + + if (var->yoffset + info->var.yres > info->var.yres_virtual) + var->yoffset = info->var.yres_virtual - info->var.yres; + + if ((var->bits_per_pixel != 32) && (var->bits_per_pixel != 24) && + (var->bits_per_pixel != 16)) + var->bits_per_pixel = default_bpp; + + switch (var->bits_per_pixel) { + case 16: + var->red.length = 5; + var->red.offset = 11; + var->red.msb_right = 0; + + var->green.length = 6; + var->green.offset = 5; + var->green.msb_right = 0; + + var->blue.length = 5; + var->blue.offset = 0; + var->blue.msb_right = 0; + + var->transp.length = 0; + var->transp.offset = 0; + var->transp.msb_right = 0; + break; + case 24: + var->red.length = 8; + var->red.offset = 0; + var->red.msb_right = 0; + + var->green.length = 8; + var->green.offset = 8; + var->green.msb_right = 0; + + var->blue.length = 8; + var->blue.offset = 16; + var->blue.msb_right = 0; + + var->transp.length = 0; + var->transp.offset = 0; + var->transp.msb_right = 0; + break; + case 32: + var->red.length = 8; + var->red.offset = 16; + var->red.msb_right = 0; + + var->green.length = 8; + var->green.offset = 8; + var->green.msb_right = 0; + + var->blue.length = 8; + var->blue.offset = 0; + var->blue.msb_right = 0; + + var->transp.length = 8; + var->transp.offset = 24; + var->transp.msb_right = 0; + + break; + } + /* If the pixclock is below the minimum spec'd value then set to + * refresh rate for 60Hz since this is supported by most monitors. + * Refer to Documentation/fb/ for calculations. + */ + if ((var->pixclock < MIN_PIX_CLK) || (var->pixclock > MAX_PIX_CLK)) { + htotal = var->xres + var->right_margin + var->hsync_len + + var->left_margin; + vtotal = var->yres + var->lower_margin + var->vsync_len + + var->upper_margin; + var->pixclock = (vtotal * htotal * 6UL) / 100UL; + var->pixclock = KHZ2PICOS(var->pixclock); + pr_debug("pixclock set for 60Hz refresh = %u ps\n", + var->pixclock); + } + + var->height = -1; + var->width = -1; + var->grayscale = 0; + + /* Copy nonstd field to/from sync for fbset usage */ + var->sync |= var->nonstd; + var->nonstd |= var->sync; + + adjust_aoi_size_position(var, info); + return 0; +} + +static void set_fix(struct fb_info *info) +{ + struct fb_fix_screeninfo *fix = &info->fix; + struct fb_var_screeninfo *var = &info->var; + struct mfb_info *mfbi = info->par; + + strncpy(fix->id, mfbi->id, strlen(mfbi->id)); + fix->line_length = var->xres_virtual * var->bits_per_pixel / 8; + fix->type = FB_TYPE_PACKED_PIXELS; + fix->accel = FB_ACCEL_NONE; + fix->visual = FB_VISUAL_TRUECOLOR; + fix->xpanstep = 1; + fix->ypanstep = 1; +} + +static void update_lcdc(struct fb_info *info) +{ + struct fb_var_screeninfo *var = &info->var; + struct mfb_info *mfbi = info->par; + struct fsl_diu_data *machine_data = mfbi->parent; + struct diu *hw; + int i, j; + char __iomem *cursor_base, *gamma_table_base; + + u32 temp; + + hw = dr.diu_reg; + + if (mfbi->type == MFB_TYPE_OFF) { + fsl_diu_disable_panel(info); + return; + } + + diu_ops.set_monitor_port(machine_data->monitor_port); + gamma_table_base = pool.gamma.vaddr; + cursor_base = pool.cursor.vaddr; + /* Prep for DIU init - gamma table, cursor table */ + + for (i = 0; i <= 2; i++) + for (j = 0; j <= 255; j++) + *gamma_table_base++ = j; + + diu_ops.set_gamma_table(machine_data->monitor_port, pool.gamma.vaddr); + + pr_debug("update-lcdc: HW - %p\n Disabling DIU\n", hw); + disable_lcdc(info); + + /* Program DIU registers */ + + out_be32(&hw->gamma, pool.gamma.paddr); + out_be32(&hw->cursor, pool.cursor.paddr); + + out_be32(&hw->bgnd, 0x007F7F7F); /* BGND */ + out_be32(&hw->bgnd_wb, 0); /* BGND_WB */ + out_be32(&hw->disp_size, (var->yres << 16 | var->xres)); + /* DISP SIZE */ + pr_debug("DIU xres: %d\n", var->xres); + pr_debug("DIU yres: %d\n", var->yres); + + out_be32(&hw->wb_size, 0); /* WB SIZE */ + out_be32(&hw->wb_mem_addr, 0); /* WB MEM ADDR */ + + /* Horizontal and vertical configuration register */ + temp = var->left_margin << 22 | /* BP_H */ + var->hsync_len << 11 | /* PW_H */ + var->right_margin; /* FP_H */ + + out_be32(&hw->hsyn_para, temp); + + temp = var->upper_margin << 22 | /* BP_V */ + var->vsync_len << 11 | /* PW_V */ + var->lower_margin; /* FP_V */ + + out_be32(&hw->vsyn_para, temp); + + pr_debug("DIU right_margin - %d\n", var->right_margin); + pr_debug("DIU left_margin - %d\n", var->left_margin); + pr_debug("DIU hsync_len - %d\n", var->hsync_len); + pr_debug("DIU upper_margin - %d\n", var->upper_margin); + pr_debug("DIU lower_margin - %d\n", var->lower_margin); + pr_debug("DIU vsync_len - %d\n", var->vsync_len); + pr_debug("DIU HSYNC - 0x%08x\n", hw->hsyn_para); + pr_debug("DIU VSYNC - 0x%08x\n", hw->vsyn_para); + + diu_ops.set_pixel_clock(var->pixclock); + + out_be32(&hw->syn_pol, 0); /* SYNC SIGNALS POLARITY */ + out_be32(&hw->thresholds, 0x00037800); /* The Thresholds */ + out_be32(&hw->int_status, 0); /* INTERRUPT STATUS */ + out_be32(&hw->plut, 0x01F5F666); + + /* Enable the DIU */ + enable_lcdc(info); +} + +static int map_video_memory(struct fb_info *info) +{ + phys_addr_t phys; + + pr_debug("info->var.xres_virtual = %d\n", info->var.xres_virtual); + pr_debug("info->var.yres_virtual = %d\n", info->var.yres_virtual); + pr_debug("info->fix.line_length = %d\n", info->fix.line_length); + + info->fix.smem_len = info->fix.line_length * info->var.yres_virtual; + pr_debug("MAP_VIDEO_MEMORY: smem_len = %d\n", info->fix.smem_len); + info->screen_base = fsl_diu_alloc(info->fix.smem_len, &phys); + if (info->screen_base == 0) { + printk(KERN_ERR "Unable to allocate fb memory\n"); + return -ENOMEM; + } + info->fix.smem_start = (unsigned long) phys; + info->screen_size = info->fix.smem_len; + + pr_debug("Allocated fb @ paddr=0x%08lx, size=%d.\n", + info->fix.smem_start, + info->fix.smem_len); + pr_debug("screen base %p\n", info->screen_base); + + return 0; +} + +static void unmap_video_memory(struct fb_info *info) +{ + fsl_diu_free(info->screen_base, info->fix.smem_len); + info->screen_base = 0; + info->fix.smem_start = 0; + info->fix.smem_len = 0; +} + +/* + * Using the fb_var_screeninfo in fb_info we set the resolution of this + * particular framebuffer. This function alters the fb_fix_screeninfo stored + * in fb_info. It does not alter var in fb_info since we are using that + * data. This means we depend on the data in var inside fb_info to be + * supported by the hardware. fsl_diu_check_var is always called before + * fsl_diu_set_par to ensure this. + */ +static int fsl_diu_set_par(struct fb_info *info) +{ + unsigned long len; + struct fb_var_screeninfo *var = &info->var; + struct mfb_info *mfbi = info->par; + struct fsl_diu_data *machine_data = mfbi->parent; + struct diu_ad *ad = mfbi->ad; + struct diu *hw; + + hw = dr.diu_reg; + + set_fix(info); + mfbi->cursor_reset = 1; + + len = info->var.yres_virtual * info->fix.line_length; + /* Alloc & dealloc each time resolution/bpp change */ + if (len != info->fix.smem_len) { + if (info->fix.smem_start) + unmap_video_memory(info); + pr_debug("SET PAR: smem_len = %d\n", info->fix.smem_len); + + /* Memory allocation for framebuffer */ + if (map_video_memory(info)) { + printk(KERN_ERR "Unable to allocate fb memory 1\n"); + return -ENOMEM; + } + } + + ad->pix_fmt = + diu_ops.get_pixel_format(var->bits_per_pixel, + machine_data->monitor_port); + ad->addr = cpu_to_le32(info->fix.smem_start); + ad->src_size_g_alpha = cpu_to_le32((var->yres << 12) | + var->xres) | mfbi->g_alpha; + /* fix me. AOI should not be greater than display size */ + ad->aoi_size = cpu_to_le32((var->yres << 16) | var->xres); + ad->offset_xyi = 0; + ad->offset_xyd = cpu_to_le32((mfbi->y_aoi_d << 16) | mfbi->x_aoi_d); + + /* Disable chroma keying function */ + ad->ckmax_r = 0; + ad->ckmax_g = 0; + ad->ckmax_b = 0; + + ad->ckmin_r = 255; + ad->ckmin_g = 255; + ad->ckmin_b = 255; + + if (mfbi->index == 0) + update_lcdc(info); + return 0; +} + +static inline __u32 CNVT_TOHW(__u32 val, __u32 width) +{ + return ((val<<width) + 0x7FFF - val)>>16; +} + +/* + * Set a single color register. The values supplied have a 16 bit magnitude + * which needs to be scaled in this function for the hardware. Things to take + * into consideration are how many color registers, if any, are supported with + * the current color visual. With truecolor mode no color palettes are + * supported. Here a psuedo palette is created which we store the value in + * pseudo_palette in struct fb_info. For pseudocolor mode we have a limited + * color palette. + */ +static int fsl_diu_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, struct fb_info *info) +{ + int ret = 1; + + /* + * If greyscale is true, then we convert the RGB value + * to greyscale no matter what visual we are using. + */ + if (info->var.grayscale) + red = green = blue = (19595 * red + 38470 * green + + 7471 * blue) >> 16; + switch (info->fix.visual) { + case FB_VISUAL_TRUECOLOR: + /* + * 16-bit True Colour. We encode the RGB value + * according to the RGB bitfield information. + */ + if (regno < 16) { + u32 *pal = info->pseudo_palette; + u32 v; + + red = CNVT_TOHW(red, info->var.red.length); + green = CNVT_TOHW(green, info->var.green.length); + blue = CNVT_TOHW(blue, info->var.blue.length); + transp = CNVT_TOHW(transp, info->var.transp.length); + + v = (red << info->var.red.offset) | + (green << info->var.green.offset) | + (blue << info->var.blue.offset) | + (transp << info->var.transp.offset); + + pal[regno] = v; + ret = 0; + } + break; + case FB_VISUAL_STATIC_PSEUDOCOLOR: + case FB_VISUAL_PSEUDOCOLOR: + break; + } + + return ret; +} + +/* + * Pan (or wrap, depending on the `vmode' field) the display using the + * 'xoffset' and 'yoffset' fields of the 'var' structure. If the values + * don't fit, return -EINVAL. + */ +static int fsl_diu_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + if ((info->var.xoffset == var->xoffset) && + (info->var.yoffset == var->yoffset)) + return 0; /* No change, do nothing */ + + if (var->xoffset < 0 || var->yoffset < 0 + || var->xoffset + info->var.xres > info->var.xres_virtual + || var->yoffset + info->var.yres > info->var.yres_virtual) + return -EINVAL; + + info->var.xoffset = var->xoffset; + info->var.yoffset = var->yoffset; + + if (var->vmode & FB_VMODE_YWRAP) + info->var.vmode |= FB_VMODE_YWRAP; + else + info->var.vmode &= ~FB_VMODE_YWRAP; + + return 0; +} + +/* + * Blank the screen if blank_mode != 0, else unblank. Return 0 if blanking + * succeeded, != 0 if un-/blanking failed. + * blank_mode == 2: suspend vsync + * blank_mode == 3: suspend hsync + * blank_mode == 4: powerdown + */ +static int fsl_diu_blank(int blank_mode, struct fb_info *info) +{ + struct mfb_info *mfbi = info->par; + + mfbi->blank = blank_mode; + + switch (blank_mode) { + case FB_BLANK_VSYNC_SUSPEND: + case FB_BLANK_HSYNC_SUSPEND: + /* FIXME: fixes to enable_panel and enable lcdc needed */ + case FB_BLANK_NORMAL: + /* fsl_diu_disable_panel(info);*/ + break; + case FB_BLANK_POWERDOWN: + /* disable_lcdc(info); */ + break; + case FB_BLANK_UNBLANK: + /* fsl_diu_enable_panel(info);*/ + break; + } + + return 0; +} + +static int fsl_diu_ioctl(struct fb_info *info, unsigned int cmd, + unsigned long arg) +{ + struct mfb_info *mfbi = info->par; + struct diu_ad *ad = mfbi->ad; + struct mfb_chroma_key ck; + unsigned char global_alpha; + struct aoi_display_offset aoi_d; + __u32 pix_fmt; + void __user *buf = (void __user *)arg; + + if (!arg) + return -EINVAL; + switch (cmd) { + case MFB_SET_PIXFMT: + if (copy_from_user(&pix_fmt, buf, sizeof(pix_fmt))) + return -EFAULT; + ad->pix_fmt = pix_fmt; + pr_debug("Set pixel format to 0x%08x\n", ad->pix_fmt); + break; + case MFB_GET_PIXFMT: + pix_fmt = ad->pix_fmt; + if (copy_to_user(buf, &pix_fmt, sizeof(pix_fmt))) + return -EFAULT; + pr_debug("get pixel format 0x%08x\n", ad->pix_fmt); + break; + case MFB_SET_AOID: + if (copy_from_user(&aoi_d, buf, sizeof(aoi_d))) + return -EFAULT; + mfbi->x_aoi_d = aoi_d.x_aoi_d; + mfbi->y_aoi_d = aoi_d.y_aoi_d; + pr_debug("set AOI display offset of index %d to (%d,%d)\n", + mfbi->index, aoi_d.x_aoi_d, aoi_d.y_aoi_d); + fsl_diu_check_var(&info->var, info); + fsl_diu_set_par(info); + break; + case MFB_GET_AOID: + aoi_d.x_aoi_d = mfbi->x_aoi_d; + aoi_d.y_aoi_d = mfbi->y_aoi_d; + if (copy_to_user(buf, &aoi_d, sizeof(aoi_d))) + return -EFAULT; + pr_debug("get AOI display offset of index %d (%d,%d)\n", + mfbi->index, aoi_d.x_aoi_d, aoi_d.y_aoi_d); + break; + case MFB_GET_ALPHA: + global_alpha = mfbi->g_alpha; + if (copy_to_user(buf, &global_alpha, sizeof(global_alpha))) + return -EFAULT; + pr_debug("get global alpha of index %d\n", mfbi->index); + break; + case MFB_SET_ALPHA: + /* set panel information */ + if (copy_from_user(&global_alpha, buf, sizeof(global_alpha))) + return -EFAULT; + ad->src_size_g_alpha = (ad->src_size_g_alpha & (~0xff)) | + (global_alpha & 0xff); + mfbi->g_alpha = global_alpha; + pr_debug("set global alpha for index %d\n", mfbi->index); + break; + case MFB_SET_CHROMA_KEY: + /* set panel winformation */ + if (copy_from_user(&ck, buf, sizeof(ck))) + return -EFAULT; + + if (ck.enable && + (ck.red_max < ck.red_min || + ck.green_max < ck.green_min || + ck.blue_max < ck.blue_min)) + return -EINVAL; + + if (!ck.enable) { + ad->ckmax_r = 0; + ad->ckmax_g = 0; + ad->ckmax_b = 0; + ad->ckmin_r = 255; + ad->ckmin_g = 255; + ad->ckmin_b = 255; + } else { + ad->ckmax_r = ck.red_max; + ad->ckmax_g = ck.green_max; + ad->ckmax_b = ck.blue_max; + ad->ckmin_r = ck.red_min; + ad->ckmin_g = ck.green_min; + ad->ckmin_b = ck.blue_min; + } + pr_debug("set chroma key\n"); + break; + case FBIOGET_GWINFO: + if (mfbi->type == MFB_TYPE_OFF) + return -ENODEV; + /* get graphic window information */ + if (copy_to_user(buf, ad, sizeof(*ad))) + return -EFAULT; + break; + case FBIOGET_HWCINFO: + pr_debug("FBIOGET_HWCINFO:0x%08x\n", FBIOGET_HWCINFO); + break; + case FBIOPUT_MODEINFO: + pr_debug("FBIOPUT_MODEINFO:0x%08x\n", FBIOPUT_MODEINFO); + break; + case FBIOGET_DISPINFO: + pr_debug("FBIOGET_DISPINFO:0x%08x\n", FBIOGET_DISPINFO); + break; + + default: + printk(KERN_ERR "Unknown ioctl command (0x%08X)\n", cmd); + return -ENOIOCTLCMD; + } + + return 0; +} + +/* turn on fb if count == 1 + */ +static int fsl_diu_open(struct fb_info *info, int user) +{ + struct mfb_info *mfbi = info->par; + int res = 0; + + spin_lock(&diu_lock); + mfbi->count++; + if (mfbi->count == 1) { + pr_debug("open plane index %d\n", mfbi->index); + fsl_diu_check_var(&info->var, info); + res = fsl_diu_set_par(info); + if (res < 0) + mfbi->count--; + else { + res = fsl_diu_enable_panel(info); + if (res < 0) + mfbi->count--; + } + } + + spin_unlock(&diu_lock); + return res; +} + +/* turn off fb if count == 0 + */ +static int fsl_diu_release(struct fb_info *info, int user) +{ + struct mfb_info *mfbi = info->par; + int res = 0; + + spin_lock(&diu_lock); + mfbi->count--; + if (mfbi->count == 0) { + pr_debug("release plane index %d\n", mfbi->index); + res = fsl_diu_disable_panel(info); + if (res < 0) + mfbi->count++; + } + spin_unlock(&diu_lock); + return res; +} + +static struct fb_ops fsl_diu_ops = { + .owner = THIS_MODULE, + .fb_check_var = fsl_diu_check_var, + .fb_set_par = fsl_diu_set_par, + .fb_setcolreg = fsl_diu_setcolreg, + .fb_blank = fsl_diu_blank, + .fb_pan_display = fsl_diu_pan_display, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_ioctl = fsl_diu_ioctl, + .fb_open = fsl_diu_open, + .fb_release = fsl_diu_release, +}; + +static int init_fbinfo(struct fb_info *info) +{ + struct mfb_info *mfbi = info->par; + + info->device = NULL; + info->var.activate = FB_ACTIVATE_NOW; + info->fbops = &fsl_diu_ops; + info->flags = FBINFO_FLAG_DEFAULT; + info->pseudo_palette = &mfbi->pseudo_palette; + + /* Allocate colormap */ + fb_alloc_cmap(&info->cmap, 16, 0); + return 0; +} + +static int install_fb(struct fb_info *info) +{ + int rc; + struct mfb_info *mfbi = info->par; + const char *aoi_mode, *init_aoi_mode = "320x240"; + + if (init_fbinfo(info)) + return -EINVAL; + + if (mfbi->index == 0) /* plane 0 */ + aoi_mode = fb_mode; + else + aoi_mode = init_aoi_mode; + pr_debug("mode used = %s\n", aoi_mode); + rc = fb_find_mode(&info->var, info, aoi_mode, fsl_diu_mode_db, + ARRAY_SIZE(fsl_diu_mode_db), &fsl_diu_default_mode, default_bpp); + + switch (rc) { + case 1: + pr_debug("using mode specified in @mode\n"); + break; + case 2: + pr_debug("using mode specified in @mode " + "with ignored refresh rate\n"); + break; + case 3: + pr_debug("using mode default mode\n"); + break; + case 4: + pr_debug("using mode from list\n"); + break; + default: + pr_debug("rc = %d\n", rc); + pr_debug("failed to find mode\n"); + return -EINVAL; + break; + } + + pr_debug("xres_virtual %d\n", info->var.xres_virtual); + pr_debug("bits_per_pixel %d\n", info->var.bits_per_pixel); + + pr_debug("info->var.yres_virtual = %d\n", info->var.yres_virtual); + pr_debug("info->fix.line_length = %d\n", info->fix.line_length); + + if (mfbi->type == MFB_TYPE_OFF) + mfbi->blank = FB_BLANK_NORMAL; + else + mfbi->blank = FB_BLANK_UNBLANK; + + if (fsl_diu_check_var(&info->var, info)) { + printk(KERN_ERR "fb_check_var failed"); + fb_dealloc_cmap(&info->cmap); + return -EINVAL; + } + + if (fsl_diu_set_par(info)) { + printk(KERN_ERR "fb_set_par failed"); + fb_dealloc_cmap(&info->cmap); + return -EINVAL; + } + + if (register_framebuffer(info) < 0) { + printk(KERN_ERR "register_framebuffer failed"); + unmap_video_memory(info); + fb_dealloc_cmap(&info->cmap); + return -EINVAL; + } + + mfbi->registered = 1; + printk(KERN_INFO "fb%d: %s fb device registered successfully.\n", + info->node, info->fix.id); + + return 0; +} + +static void __exit uninstall_fb(struct fb_info *info) +{ + struct mfb_info *mfbi = info->par; + + if (!mfbi->registered) + return; + + unregister_framebuffer(info); + unmap_video_memory(info); + if (&info->cmap) + fb_dealloc_cmap(&info->cmap); + + mfbi->registered = 0; +} + +static irqreturn_t fsl_diu_isr(int irq, void *dev_id) +{ + struct diu *hw = dr.diu_reg; + unsigned int status = in_be32(&hw->int_status); + + if (status) { + /* This is the workaround for underrun */ + if (status & INT_UNDRUN) { + out_be32(&hw->diu_mode, 0); + pr_debug("Err: DIU occurs underrun!\n"); + udelay(1); + out_be32(&hw->diu_mode, 1); + } +#if defined(CONFIG_NOT_COHERENT_CACHE) + else if (status & INT_VSYNC) { + unsigned int i; + for (i = 0; i < coherence_data_size; + i += d_cache_line_size) + __asm__ __volatile__ ( + "dcbz 0, %[input]" + ::[input]"r"(&coherence_data[i])); + } +#endif + return IRQ_HANDLED; + } + return IRQ_NONE; +} + +static int request_irq_local(int irq) +{ + unsigned long status, ints; + struct diu *hw; + int ret; + + hw = dr.diu_reg; + + /* Read to clear the status */ + status = in_be32(&hw->int_status); + + ret = request_irq(irq, fsl_diu_isr, 0, "diu", 0); + if (ret) + pr_info("Request diu IRQ failed.\n"); + else { + ints = INT_PARERR | INT_LS_BF_VS; +#if !defined(CONFIG_NOT_COHERENT_CACHE) + ints |= INT_VSYNC; +#endif + if (dr.mode == MFB_MODE2 || dr.mode == MFB_MODE3) + ints |= INT_VSYNC_WB; + + /* Read to clear the status */ + status = in_be32(&hw->int_status); + out_be32(&hw->int_mask, ints); + } + return ret; +} + +static void free_irq_local(int irq) +{ + struct diu *hw = dr.diu_reg; + + /* Disable all LCDC interrupt */ + out_be32(&hw->int_mask, 0x1f); + + free_irq(irq, 0); +} + +#ifdef CONFIG_PM +/* + * Power management hooks. Note that we won't be called from IRQ context, + * unlike the blank functions above, so we may sleep. + */ +static int fsl_diu_suspend(struct of_device *dev, pm_message_t state) +{ + struct fsl_diu_data *machine_data; + + machine_data = dev_get_drvdata(&ofdev->dev); + disable_lcdc(machine_data->fsl_diu_info[0]); + + return 0; +} + +static int fsl_diu_resume(struct of_device *dev) +{ + struct fsl_diu_data *machine_data; + + machine_data = dev_get_drvdata(&ofdev->dev); + enable_lcdc(machine_data->fsl_diu_info[0]); + + return 0; +} + +#else +#define fsl_diu_suspend NULL +#define fsl_diu_resume NULL +#endif /* CONFIG_PM */ + +/* Align to 64-bit(8-byte), 32-byte, etc. */ +static int allocate_buf(struct diu_addr *buf, u32 size, u32 bytes_align) +{ + u32 offset, ssize; + u32 mask; + dma_addr_t paddr = 0; + + ssize = size + bytes_align; + buf->vaddr = dma_alloc_coherent(0, ssize, &paddr, GFP_DMA | __GFP_ZERO); + if (!buf->vaddr) + return -ENOMEM; + + buf->paddr = (__u32) paddr; + + mask = bytes_align - 1; + offset = (u32)buf->paddr & mask; + if (offset) { + buf->offset = bytes_align - offset; + buf->paddr = (u32)buf->paddr + offset; + } else + buf->offset = 0; + return 0; +} + +static void free_buf(struct diu_addr *buf, u32 size, u32 bytes_align) +{ + dma_free_coherent(0, size + bytes_align, + buf->vaddr, (buf->paddr - buf->offset)); + return; +} + +static ssize_t store_monitor(struct device *device, + struct device_attribute *attr, const char *buf, size_t count) +{ + int old_monitor_port; + unsigned long val; + struct fsl_diu_data *machine_data = + container_of(attr, struct fsl_diu_data, dev_attr); + + if (strict_strtoul(buf, 10, &val)) + return 0; + + old_monitor_port = machine_data->monitor_port; + machine_data->monitor_port = diu_ops.set_sysfs_monitor_port(val); + + if (old_monitor_port != machine_data->monitor_port) { + /* All AOIs need adjust pixel format + * fsl_diu_set_par only change the pixsel format here + * unlikely to fail. */ + fsl_diu_set_par(machine_data->fsl_diu_info[0]); + fsl_diu_set_par(machine_data->fsl_diu_info[1]); + fsl_diu_set_par(machine_data->fsl_diu_info[2]); + fsl_diu_set_par(machine_data->fsl_diu_info[3]); + fsl_diu_set_par(machine_data->fsl_diu_info[4]); + } + return count; +} + +static ssize_t show_monitor(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct fsl_diu_data *machine_data = + container_of(attr, struct fsl_diu_data, dev_attr); + return diu_ops.show_monitor_port(machine_data->monitor_port, buf); +} + +static int fsl_diu_probe(struct of_device *ofdev, + const struct of_device_id *match) +{ + struct device_node *np = ofdev->node; + struct mfb_info *mfbi; + phys_addr_t dummy_ad_addr; + int ret, i, error = 0; + struct resource res; + struct fsl_diu_data *machine_data; + + machine_data = kzalloc(sizeof(struct fsl_diu_data), GFP_KERNEL); + if (!machine_data) + return -ENOMEM; + + for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) { + machine_data->fsl_diu_info[i] = + framebuffer_alloc(sizeof(struct mfb_info), &ofdev->dev); + if (!machine_data->fsl_diu_info[i]) { + dev_err(&ofdev->dev, "cannot allocate memory\n"); + ret = -ENOMEM; + goto error2; + } + mfbi = machine_data->fsl_diu_info[i]->par; + memcpy(mfbi, &mfb_template[i], sizeof(struct mfb_info)); + mfbi->parent = machine_data; + } + + ret = of_address_to_resource(np, 0, &res); + if (ret) { + dev_err(&ofdev->dev, "could not obtain DIU address\n"); + goto error; + } + if (!res.start) { + dev_err(&ofdev->dev, "invalid DIU address\n"); + goto error; + } + dev_dbg(&ofdev->dev, "%s, res.start: 0x%08x\n", __func__, res.start); + + dr.diu_reg = ioremap(res.start, sizeof(struct diu)); + if (!dr.diu_reg) { + dev_err(&ofdev->dev, "Err: can't map DIU registers!\n"); + ret = -EFAULT; + goto error2; + } + + out_be32(&dr.diu_reg->diu_mode, 0); /* disable DIU anyway*/ + + /* Get the IRQ of the DIU */ + machine_data->irq = irq_of_parse_and_map(np, 0); + + if (!machine_data->irq) { + dev_err(&ofdev->dev, "could not get DIU IRQ\n"); + ret = -EINVAL; + goto error; + } + machine_data->monitor_port = monitor_port; + + /* Area descriptor memory pool aligns to 64-bit boundary */ + if (allocate_buf(&pool.ad, sizeof(struct diu_ad) * FSL_AOI_NUM, 8)) + return -ENOMEM; + + /* Get memory for Gamma Table - 32-byte aligned memory */ + if (allocate_buf(&pool.gamma, 768, 32)) { + ret = -ENOMEM; + goto error; + } + + /* For performance, cursor bitmap buffer aligns to 32-byte boundary */ + if (allocate_buf(&pool.cursor, MAX_CURS * MAX_CURS * 2, 32)) { + ret = -ENOMEM; + goto error; + } + + i = ARRAY_SIZE(machine_data->fsl_diu_info); + machine_data->dummy_ad = (struct diu_ad *) + ((u32)pool.ad.vaddr + pool.ad.offset) + i; + machine_data->dummy_ad->paddr = pool.ad.paddr + + i * sizeof(struct diu_ad); + machine_data->dummy_aoi_virt = fsl_diu_alloc(64, &dummy_ad_addr); + if (!machine_data->dummy_aoi_virt) { + ret = -ENOMEM; + goto error; + } + machine_data->dummy_ad->addr = cpu_to_le32(dummy_ad_addr); + machine_data->dummy_ad->pix_fmt = 0x88882317; + machine_data->dummy_ad->src_size_g_alpha = cpu_to_le32((4 << 12) | 4); + machine_data->dummy_ad->aoi_size = cpu_to_le32((4 << 16) | 2); + machine_data->dummy_ad->offset_xyi = 0; + machine_data->dummy_ad->offset_xyd = 0; + machine_data->dummy_ad->next_ad = 0; + + out_be32(&dr.diu_reg->desc[0], machine_data->dummy_ad->paddr); + out_be32(&dr.diu_reg->desc[1], machine_data->dummy_ad->paddr); + out_be32(&dr.diu_reg->desc[2], machine_data->dummy_ad->paddr); + + for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) { + machine_data->fsl_diu_info[i]->fix.smem_start = 0; + mfbi = machine_data->fsl_diu_info[i]->par; + mfbi->ad = (struct diu_ad *)((u32)pool.ad.vaddr + + pool.ad.offset) + i; + mfbi->ad->paddr = pool.ad.paddr + i * sizeof(struct diu_ad); + ret = install_fb(machine_data->fsl_diu_info[i]); + if (ret) { + dev_err(&ofdev->dev, + "Failed to register framebuffer %d\n", + i); + goto error; + } + } + + if (request_irq_local(machine_data->irq)) { + dev_err(machine_data->fsl_diu_info[0]->dev, + "could not request irq for diu."); + goto error; + } + + machine_data->dev_attr.attr.name = "monitor"; + machine_data->dev_attr.attr.mode = S_IRUGO|S_IWUSR; + machine_data->dev_attr.show = show_monitor; + machine_data->dev_attr.store = store_monitor; + error = device_create_file(machine_data->fsl_diu_info[0]->dev, + &machine_data->dev_attr); + if (error) { + dev_err(machine_data->fsl_diu_info[0]->dev, + "could not create sysfs %s file\n", + machine_data->dev_attr.attr.name); + } + + dev_set_drvdata(&ofdev->dev, machine_data); + return 0; + +error: + for (i = ARRAY_SIZE(machine_data->fsl_diu_info); + i > 0; i--) + uninstall_fb(machine_data->fsl_diu_info[i - 1]); + if (pool.ad.vaddr) + free_buf(&pool.ad, sizeof(struct diu_ad) * FSL_AOI_NUM, 8); + if (pool.gamma.vaddr) + free_buf(&pool.gamma, 768, 32); + if (pool.cursor.vaddr) + free_buf(&pool.cursor, MAX_CURS * MAX_CURS * 2, 32); + if (machine_data->dummy_aoi_virt) + fsl_diu_free(machine_data->dummy_aoi_virt, 64); + iounmap(dr.diu_reg); + +error2: + for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) + if (machine_data->fsl_diu_info[i]) + framebuffer_release(machine_data->fsl_diu_info[i]); + kfree(machine_data); + + return ret; +} + + +static int fsl_diu_remove(struct of_device *ofdev) +{ + struct fsl_diu_data *machine_data; + int i; + + machine_data = dev_get_drvdata(&ofdev->dev); + disable_lcdc(machine_data->fsl_diu_info[0]); + free_irq_local(machine_data->irq); + for (i = ARRAY_SIZE(machine_data->fsl_diu_info); i > 0; i--) + uninstall_fb(machine_data->fsl_diu_info[i - 1]); + if (pool.ad.vaddr) + free_buf(&pool.ad, sizeof(struct diu_ad) * FSL_AOI_NUM, 8); + if (pool.gamma.vaddr) + free_buf(&pool.gamma, 768, 32); + if (pool.cursor.vaddr) + free_buf(&pool.cursor, MAX_CURS * MAX_CURS * 2, 32); + if (machine_data->dummy_aoi_virt) + fsl_diu_free(machine_data->dummy_aoi_virt, 64); + iounmap(dr.diu_reg); + for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) + if (machine_data->fsl_diu_info[i]) + framebuffer_release(machine_data->fsl_diu_info[i]); + kfree(machine_data); + + return 0; +} + +#ifndef MODULE +static int __init fsl_diu_setup(char *options) +{ + char *opt; + unsigned long val; + + if (!options || !*options) + return 0; + + while ((opt = strsep(&options, ",")) != NULL) { + if (!*opt) + continue; + if (!strncmp(opt, "monitor=", 8)) { + if (!strict_strtoul(opt + 8, 10, &val) && (val <= 2)) + monitor_port = val; + } else if (!strncmp(opt, "bpp=", 4)) { + if (!strict_strtoul(opt + 4, 10, &val)) + default_bpp = val; + } else + fb_mode = opt; + } + + return 0; +} +#endif + +static struct of_device_id fsl_diu_match[] = { + { + .compatible = "fsl,diu", + }, + {} +}; +MODULE_DEVICE_TABLE(of, fsl_diu_match); + +static struct of_platform_driver fsl_diu_driver = { + .owner = THIS_MODULE, + .name = "fsl_diu", + .match_table = fsl_diu_match, + .probe = fsl_diu_probe, + .remove = fsl_diu_remove, + .suspend = fsl_diu_suspend, + .resume = fsl_diu_resume, +}; + +static int __init fsl_diu_init(void) +{ +#ifdef CONFIG_NOT_COHERENT_CACHE + struct device_node *np; + const u32 *prop; +#endif + int ret; +#ifndef MODULE + char *option; + + /* + * For kernel boot options (in 'video=xxxfb:<options>' format) + */ + if (fb_get_options("fslfb", &option)) + return -ENODEV; + fsl_diu_setup(option); +#endif + printk(KERN_INFO "Freescale DIU driver\n"); + +#ifdef CONFIG_NOT_COHERENT_CACHE + np = of_find_node_by_type(NULL, "cpu"); + if (!np) { + printk(KERN_ERR "Err: can't find device node 'cpu'\n"); + return -ENODEV; + } + + prop = of_get_property(np, "d-cache-size", NULL); + if (prop == NULL) + return -ENODEV; + + /* Freescale PLRU requires 13/8 times the cache size to do a proper + displacement flush + */ + coherence_data_size = *prop * 13; + coherence_data_size /= 8; + + prop = of_get_property(np, "d-cache-line-size", NULL); + if (prop == NULL) + return -ENODEV; + d_cache_line_size = *prop; + + of_node_put(np); + coherence_data = vmalloc(coherence_data_size); + if (!coherence_data) + return -ENOMEM; +#endif + ret = of_register_platform_driver(&fsl_diu_driver); + if (ret) { + printk(KERN_ERR + "fsl-diu: failed to register platform driver\n"); +#if defined(CONFIG_NOT_COHERENT_CACHE) + vfree(coherence_data); +#endif + iounmap(dr.diu_reg); + } + return ret; +} + +static void __exit fsl_diu_exit(void) +{ + of_unregister_platform_driver(&fsl_diu_driver); +#if defined(CONFIG_NOT_COHERENT_CACHE) + vfree(coherence_data); +#endif +} + +module_init(fsl_diu_init); +module_exit(fsl_diu_exit); + +MODULE_AUTHOR("York Sun <yorksun@freescale.com>"); +MODULE_DESCRIPTION("Freescale DIU framebuffer driver"); +MODULE_LICENSE("GPL"); + +module_param_named(mode, fb_mode, charp, 0); +MODULE_PARM_DESC(mode, + "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" "); +module_param_named(bpp, default_bpp, ulong, 0); +MODULE_PARM_DESC(bpp, "Specify bit-per-pixel if not specified mode"); +module_param_named(monitor, monitor_port, int, 0); +MODULE_PARM_DESC(monitor, + "Specify the monitor port (0, 1 or 2) if supported by the platform"); + diff --git a/drivers/video/fsl-diu-fb.h b/drivers/video/fsl-diu-fb.h new file mode 100644 index 00000000000..fc295d7ea46 --- /dev/null +++ b/drivers/video/fsl-diu-fb.h @@ -0,0 +1,223 @@ +/* + * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved. + * + * Freescale DIU Frame Buffer device driver + * + * Authors: Hongjun Chen <hong-jun.chen@freescale.com> + * Paul Widmer <paul.widmer@freescale.com> + * Srikanth Srinivasan <srikanth.srinivasan@freescale.com> + * York Sun <yorksun@freescale.com> + * + * Based on imxfb.c Copyright (C) 2004 S.Hauer, Pengutronix + * + * 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 __FSL_DIU_FB_H__ +#define __FSL_DIU_FB_H__ + +/* Arbitrary threshold to determine the allocation method + * See mpc8610fb_set_par(), map_video_memory(), and unmap_video_memory() + */ +#define MEM_ALLOC_THRESHOLD (1024*768*4+32) +/* Minimum value that the pixel clock can be set to in pico seconds + * This is determined by platform clock/3 where the minimum platform + * clock is 533MHz. This gives 5629 pico seconds. + */ +#define MIN_PIX_CLK 5629 +#define MAX_PIX_CLK 96096 + +#include <linux/types.h> + +struct mfb_alpha { + int enable; + int alpha; +}; + +struct mfb_chroma_key { + int enable; + __u8 red_max; + __u8 green_max; + __u8 blue_max; + __u8 red_min; + __u8 green_min; + __u8 blue_min; +}; + +struct aoi_display_offset { + int x_aoi_d; + int y_aoi_d; +}; + +#define MFB_SET_CHROMA_KEY _IOW('M', 1, struct mfb_chroma_key) +#define MFB_WAIT_FOR_VSYNC _IOW('F', 0x20, u_int32_t) +#define MFB_SET_BRIGHTNESS _IOW('M', 3, __u8) + +#define MFB_SET_ALPHA 0x80014d00 +#define MFB_GET_ALPHA 0x40014d00 +#define MFB_SET_AOID 0x80084d04 +#define MFB_GET_AOID 0x40084d04 +#define MFB_SET_PIXFMT 0x80014d08 +#define MFB_GET_PIXFMT 0x40014d08 + +#define FBIOGET_GWINFO 0x46E0 +#define FBIOPUT_GWINFO 0x46E1 + +#ifdef __KERNEL__ +#include <linux/spinlock.h> + +/* + * These are the fields of area descriptor(in DDR memory) for every plane + */ +struct diu_ad { + /* Word 0(32-bit) in DDR memory */ +/* __u16 comp; */ +/* __u16 pixel_s:2; */ +/* __u16 pallete:1; */ +/* __u16 red_c:2; */ +/* __u16 green_c:2; */ +/* __u16 blue_c:2; */ +/* __u16 alpha_c:3; */ +/* __u16 byte_f:1; */ +/* __u16 res0:3; */ + + __be32 pix_fmt; /* hard coding pixel format */ + + /* Word 1(32-bit) in DDR memory */ + __le32 addr; + + /* Word 2(32-bit) in DDR memory */ +/* __u32 delta_xs:11; */ +/* __u32 res1:1; */ +/* __u32 delta_ys:11; */ +/* __u32 res2:1; */ +/* __u32 g_alpha:8; */ + __le32 src_size_g_alpha; + + /* Word 3(32-bit) in DDR memory */ +/* __u32 delta_xi:11; */ +/* __u32 res3:5; */ +/* __u32 delta_yi:11; */ +/* __u32 res4:3; */ +/* __u32 flip:2; */ + __le32 aoi_size; + + /* Word 4(32-bit) in DDR memory */ + /*__u32 offset_xi:11; + __u32 res5:5; + __u32 offset_yi:11; + __u32 res6:5; + */ + __le32 offset_xyi; + + /* Word 5(32-bit) in DDR memory */ + /*__u32 offset_xd:11; + __u32 res7:5; + __u32 offset_yd:11; + __u32 res8:5; */ + __le32 offset_xyd; + + + /* Word 6(32-bit) in DDR memory */ + __u8 ckmax_r; + __u8 ckmax_g; + __u8 ckmax_b; + __u8 res9; + + /* Word 7(32-bit) in DDR memory */ + __u8 ckmin_r; + __u8 ckmin_g; + __u8 ckmin_b; + __u8 res10; +/* __u32 res10:8; */ + + /* Word 8(32-bit) in DDR memory */ + __le32 next_ad; + + /* Word 9(32-bit) in DDR memory, just for 64-bit aligned */ + __u32 paddr; +} __attribute__ ((packed)); + +/* DIU register map */ +struct diu { + __be32 desc[3]; + __be32 gamma; + __be32 pallete; + __be32 cursor; + __be32 curs_pos; + __be32 diu_mode; + __be32 bgnd; + __be32 bgnd_wb; + __be32 disp_size; + __be32 wb_size; + __be32 wb_mem_addr; + __be32 hsyn_para; + __be32 vsyn_para; + __be32 syn_pol; + __be32 thresholds; + __be32 int_status; + __be32 int_mask; + __be32 colorbar[8]; + __be32 filling; + __be32 plut; +} __attribute__ ((packed)); + +struct diu_hw { + struct diu *diu_reg; + spinlock_t reg_lock; + + __u32 mode; /* DIU operation mode */ +}; + +struct diu_addr { + __u8 __iomem *vaddr; /* Virtual address */ + dma_addr_t paddr; /* Physical address */ + __u32 offset; +}; + +struct diu_pool { + struct diu_addr ad; + struct diu_addr gamma; + struct diu_addr pallete; + struct diu_addr cursor; +}; + +#define FSL_DIU_BASE_OFFSET 0x2C000 /* Offset of DIU */ +#define INT_LCDC 64 /* DIU interrupt number */ + +#define FSL_AOI_NUM 6 /* 5 AOIs and one dummy AOI */ + /* 1 for plane 0, 2 for plane 1&2 each */ + +/* Minimum X and Y resolutions */ +#define MIN_XRES 64 +#define MIN_YRES 64 + +/* HW cursor parameters */ +#define MAX_CURS 32 + +/* Modes of operation of DIU */ +#define MFB_MODE0 0 /* DIU off */ +#define MFB_MODE1 1 /* All three planes output to display */ +#define MFB_MODE2 2 /* Plane 1 to display, planes 2+3 written back*/ +#define MFB_MODE3 3 /* All three planes written back to memory */ +#define MFB_MODE4 4 /* Color bar generation */ + +/* INT_STATUS/INT_MASK field descriptions */ +#define INT_VSYNC 0x01 /* Vsync interrupt */ +#define INT_VSYNC_WB 0x02 /* Vsync interrupt for write back operation */ +#define INT_UNDRUN 0x04 /* Under run exception interrupt */ +#define INT_PARERR 0x08 /* Display parameters error interrupt */ +#define INT_LS_BF_VS 0x10 /* Lines before vsync. interrupt */ + +/* Panels'operation modes */ +#define MFB_TYPE_OUTPUT 0 /* Panel output to display */ +#define MFB_TYPE_OFF 1 /* Panel off */ +#define MFB_TYPE_WB 2 /* Panel written back to memory */ +#define MFB_TYPE_TEST 3 /* Panel generate color bar */ + +#endif /* __KERNEL__ */ +#endif /* __FSL_DIU_FB_H__ */ diff --git a/drivers/video/geode/Kconfig b/drivers/video/geode/Kconfig index 7608429b394..c5d8ba4b9fc 100644 --- a/drivers/video/geode/Kconfig +++ b/drivers/video/geode/Kconfig @@ -38,26 +38,6 @@ config FB_GEODE_GX If unsure, say N. -config FB_GEODE_GX_SET_FBSIZE - bool "Manually specify the Geode GX framebuffer size" - depends on FB_GEODE_GX - default n - ---help--- - If you want to manually specify the size of your GX framebuffer, - say Y here, otherwise say N to dynamically probe it. - - Say N unless you know what you are doing. - -config FB_GEODE_GX_FBSIZE - hex "Size of the GX framebuffer, in bytes" - depends on FB_GEODE_GX_SET_FBSIZE - default "0x1600000" - ---help--- - Specify the size of the GX framebuffer. Normally, you will - want this to be MB aligned. Common values are 0x80000 (8MB) - and 0x1600000 (16MB). Don't change this unless you know what - you are doing - config FB_GEODE_GX1 tristate "AMD Geode GX1 framebuffer support (EXPERIMENTAL)" depends on FB && FB_GEODE && EXPERIMENTAL diff --git a/drivers/video/geode/Makefile b/drivers/video/geode/Makefile index 957304b45fb..5c98da12688 100644 --- a/drivers/video/geode/Makefile +++ b/drivers/video/geode/Makefile @@ -5,5 +5,5 @@ obj-$(CONFIG_FB_GEODE_GX) += gxfb.o obj-$(CONFIG_FB_GEODE_LX) += lxfb.o gx1fb-objs := gx1fb_core.o display_gx1.o video_cs5530.o -gxfb-objs := gxfb_core.o display_gx.o video_gx.o +gxfb-objs := gxfb_core.o display_gx.o video_gx.o suspend_gx.o lxfb-objs := lxfb_core.o lxfb_ops.o diff --git a/drivers/video/geode/display_gx.c b/drivers/video/geode/display_gx.c index 0f16e4bffc6..e759895bf3d 100644 --- a/drivers/video/geode/display_gx.c +++ b/drivers/video/geode/display_gx.c @@ -17,31 +17,40 @@ #include <asm/io.h> #include <asm/div64.h> #include <asm/delay.h> +#include <asm/geode.h> -#include "geodefb.h" -#include "display_gx.h" +#include "gxfb.h" -#ifdef CONFIG_FB_GEODE_GX_SET_FBSIZE -unsigned int gx_frame_buffer_size(void) -{ - return CONFIG_FB_GEODE_GX_FBSIZE; -} -#else unsigned int gx_frame_buffer_size(void) { unsigned int val; - /* FB size is reported by a virtual register */ + if (!geode_has_vsa2()) { + uint32_t hi, lo; + + /* The number of pages is (PMAX - PMIN)+1 */ + rdmsr(MSR_GLIU_P2D_RO0, lo, hi); + + /* PMAX */ + val = ((hi & 0xff) << 12) | ((lo & 0xfff00000) >> 20); + /* PMIN */ + val -= (lo & 0x000fffff); + val += 1; + + /* The page size is 4k */ + return (val << 12); + } + + /* FB size can be obtained from the VSA II */ /* Virtual register class = 0x02 */ /* VG_MEM_SIZE(512Kb units) = 0x00 */ - outw(0xFC53, 0xAC1C); - outw(0x0200, 0xAC1C); + outw(VSA_VR_UNLOCK, VSA_VRC_INDEX); + outw(VSA_VR_MEM_SIZE, VSA_VRC_INDEX); - val = (unsigned int)(inw(0xAC1E)) & 0xFFl; + val = (unsigned int)(inw(VSA_VRC_DATA)) & 0xFFl; return (val << 19); } -#endif int gx_line_delta(int xres, int bpp) { @@ -49,75 +58,76 @@ int gx_line_delta(int xres, int bpp) return (xres * (bpp >> 3) + 7) & ~0x7; } -static void gx_set_mode(struct fb_info *info) +void gx_set_mode(struct fb_info *info) { - struct geodefb_par *par = info->par; + struct gxfb_par *par = info->par; u32 gcfg, dcfg; int hactive, hblankstart, hsyncstart, hsyncend, hblankend, htotal; int vactive, vblankstart, vsyncstart, vsyncend, vblankend, vtotal; /* Unlock the display controller registers. */ - readl(par->dc_regs + DC_UNLOCK); - writel(DC_UNLOCK_CODE, par->dc_regs + DC_UNLOCK); + write_dc(par, DC_UNLOCK, DC_UNLOCK_UNLOCK); - gcfg = readl(par->dc_regs + DC_GENERAL_CFG); - dcfg = readl(par->dc_regs + DC_DISPLAY_CFG); + gcfg = read_dc(par, DC_GENERAL_CFG); + dcfg = read_dc(par, DC_DISPLAY_CFG); /* Disable the timing generator. */ - dcfg &= ~(DC_DCFG_TGEN); - writel(dcfg, par->dc_regs + DC_DISPLAY_CFG); + dcfg &= ~DC_DISPLAY_CFG_TGEN; + write_dc(par, DC_DISPLAY_CFG, dcfg); /* Wait for pending memory requests before disabling the FIFO load. */ udelay(100); /* Disable FIFO load and compression. */ - gcfg &= ~(DC_GCFG_DFLE | DC_GCFG_CMPE | DC_GCFG_DECE); - writel(gcfg, par->dc_regs + DC_GENERAL_CFG); + gcfg &= ~(DC_GENERAL_CFG_DFLE | DC_GENERAL_CFG_CMPE | + DC_GENERAL_CFG_DECE); + write_dc(par, DC_GENERAL_CFG, gcfg); /* Setup DCLK and its divisor. */ - par->vid_ops->set_dclk(info); + gx_set_dclk_frequency(info); /* * Setup new mode. */ /* Clear all unused feature bits. */ - gcfg &= DC_GCFG_YUVM | DC_GCFG_VDSE; + gcfg &= DC_GENERAL_CFG_YUVM | DC_GENERAL_CFG_VDSE; dcfg = 0; /* Set FIFO priority (default 6/5) and enable. */ /* FIXME: increase fifo priority for 1280x1024 and higher modes? */ - gcfg |= (6 << DC_GCFG_DFHPEL_POS) | (5 << DC_GCFG_DFHPSL_POS) | DC_GCFG_DFLE; + gcfg |= (6 << DC_GENERAL_CFG_DFHPEL_SHIFT) | + (5 << DC_GENERAL_CFG_DFHPSL_SHIFT) | DC_GENERAL_CFG_DFLE; /* Framebuffer start offset. */ - writel(0, par->dc_regs + DC_FB_ST_OFFSET); + write_dc(par, DC_FB_ST_OFFSET, 0); /* Line delta and line buffer length. */ - writel(info->fix.line_length >> 3, par->dc_regs + DC_GFX_PITCH); - writel(((info->var.xres * info->var.bits_per_pixel/8) >> 3) + 2, - par->dc_regs + DC_LINE_SIZE); + write_dc(par, DC_GFX_PITCH, info->fix.line_length >> 3); + write_dc(par, DC_LINE_SIZE, + ((info->var.xres * info->var.bits_per_pixel/8) >> 3) + 2); /* Enable graphics and video data and unmask address lines. */ - dcfg |= DC_DCFG_GDEN | DC_DCFG_VDEN | DC_DCFG_A20M | DC_DCFG_A18M; + dcfg |= DC_DISPLAY_CFG_GDEN | DC_DISPLAY_CFG_VDEN | + DC_DISPLAY_CFG_A20M | DC_DISPLAY_CFG_A18M; /* Set pixel format. */ switch (info->var.bits_per_pixel) { case 8: - dcfg |= DC_DCFG_DISP_MODE_8BPP; + dcfg |= DC_DISPLAY_CFG_DISP_MODE_8BPP; break; case 16: - dcfg |= DC_DCFG_DISP_MODE_16BPP; - dcfg |= DC_DCFG_16BPP_MODE_565; + dcfg |= DC_DISPLAY_CFG_DISP_MODE_16BPP; break; case 32: - dcfg |= DC_DCFG_DISP_MODE_24BPP; - dcfg |= DC_DCFG_PALB; + dcfg |= DC_DISPLAY_CFG_DISP_MODE_24BPP; + dcfg |= DC_DISPLAY_CFG_PALB; break; } /* Enable timing generator. */ - dcfg |= DC_DCFG_TGEN; + dcfg |= DC_DISPLAY_CFG_TGEN; /* Horizontal and vertical timings. */ hactive = info->var.xres; @@ -134,28 +144,34 @@ static void gx_set_mode(struct fb_info *info) vblankend = vsyncend + info->var.upper_margin; vtotal = vblankend; - writel((hactive - 1) | ((htotal - 1) << 16), par->dc_regs + DC_H_ACTIVE_TIMING); - writel((hblankstart - 1) | ((hblankend - 1) << 16), par->dc_regs + DC_H_BLANK_TIMING); - writel((hsyncstart - 1) | ((hsyncend - 1) << 16), par->dc_regs + DC_H_SYNC_TIMING); + write_dc(par, DC_H_ACTIVE_TIMING, (hactive - 1) | + ((htotal - 1) << 16)); + write_dc(par, DC_H_BLANK_TIMING, (hblankstart - 1) | + ((hblankend - 1) << 16)); + write_dc(par, DC_H_SYNC_TIMING, (hsyncstart - 1) | + ((hsyncend - 1) << 16)); - writel((vactive - 1) | ((vtotal - 1) << 16), par->dc_regs + DC_V_ACTIVE_TIMING); - writel((vblankstart - 1) | ((vblankend - 1) << 16), par->dc_regs + DC_V_BLANK_TIMING); - writel((vsyncstart - 1) | ((vsyncend - 1) << 16), par->dc_regs + DC_V_SYNC_TIMING); + write_dc(par, DC_V_ACTIVE_TIMING, (vactive - 1) | + ((vtotal - 1) << 16)); + write_dc(par, DC_V_BLANK_TIMING, (vblankstart - 1) | + ((vblankend - 1) << 16)); + write_dc(par, DC_V_SYNC_TIMING, (vsyncstart - 1) | + ((vsyncend - 1) << 16)); /* Write final register values. */ - writel(dcfg, par->dc_regs + DC_DISPLAY_CFG); - writel(gcfg, par->dc_regs + DC_GENERAL_CFG); + write_dc(par, DC_DISPLAY_CFG, dcfg); + write_dc(par, DC_GENERAL_CFG, gcfg); - par->vid_ops->configure_display(info); + gx_configure_display(info); /* Relock display controller registers */ - writel(0, par->dc_regs + DC_UNLOCK); + write_dc(par, DC_UNLOCK, DC_UNLOCK_LOCK); } -static void gx_set_hw_palette_reg(struct fb_info *info, unsigned regno, - unsigned red, unsigned green, unsigned blue) +void gx_set_hw_palette_reg(struct fb_info *info, unsigned regno, + unsigned red, unsigned green, unsigned blue) { - struct geodefb_par *par = info->par; + struct gxfb_par *par = info->par; int val; /* Hardware palette is in RGB 8-8-8 format. */ @@ -163,11 +179,6 @@ static void gx_set_hw_palette_reg(struct fb_info *info, unsigned regno, val |= (green) & 0x00ff00; val |= (blue >> 8) & 0x0000ff; - writel(regno, par->dc_regs + DC_PAL_ADDRESS); - writel(val, par->dc_regs + DC_PAL_DATA); + write_dc(par, DC_PAL_ADDRESS, regno); + write_dc(par, DC_PAL_DATA, val); } - -struct geode_dc_ops gx_dc_ops = { - .set_mode = gx_set_mode, - .set_palette_reg = gx_set_hw_palette_reg, -}; diff --git a/drivers/video/geode/display_gx.h b/drivers/video/geode/display_gx.h deleted file mode 100644 index 0af33f329e8..00000000000 --- a/drivers/video/geode/display_gx.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Geode GX display controller - * - * Copyright (C) 2006 Arcom Control Systems 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. - */ -#ifndef __DISPLAY_GX_H__ -#define __DISPLAY_GX_H__ - -unsigned int gx_frame_buffer_size(void); -int gx_line_delta(int xres, int bpp); - -extern struct geode_dc_ops gx_dc_ops; - -/* MSR that tells us if a TFT or CRT is attached */ -#define GLD_MSR_CONFIG 0xC0002001 -#define GLD_MSR_CONFIG_DM_FP 0x40 - -/* Display controller registers */ - -#define DC_UNLOCK 0x00 -# define DC_UNLOCK_CODE 0x00004758 - -#define DC_GENERAL_CFG 0x04 -# define DC_GCFG_DFLE 0x00000001 -# define DC_GCFG_CURE 0x00000002 -# define DC_GCFG_ICNE 0x00000004 -# define DC_GCFG_VIDE 0x00000008 -# define DC_GCFG_CMPE 0x00000020 -# define DC_GCFG_DECE 0x00000040 -# define DC_GCFG_VGAE 0x00000080 -# define DC_GCFG_DFHPSL_MASK 0x00000F00 -# define DC_GCFG_DFHPSL_POS 8 -# define DC_GCFG_DFHPEL_MASK 0x0000F000 -# define DC_GCFG_DFHPEL_POS 12 -# define DC_GCFG_STFM 0x00010000 -# define DC_GCFG_FDTY 0x00020000 -# define DC_GCFG_VGAFT 0x00040000 -# define DC_GCFG_VDSE 0x00080000 -# define DC_GCFG_YUVM 0x00100000 -# define DC_GCFG_VFSL 0x00800000 -# define DC_GCFG_SIGE 0x01000000 -# define DC_GCFG_SGRE 0x02000000 -# define DC_GCFG_SGFR 0x04000000 -# define DC_GCFG_CRC_MODE 0x08000000 -# define DC_GCFG_DIAG 0x10000000 -# define DC_GCFG_CFRW 0x20000000 - -#define DC_DISPLAY_CFG 0x08 -# define DC_DCFG_TGEN 0x00000001 -# define DC_DCFG_GDEN 0x00000008 -# define DC_DCFG_VDEN 0x00000010 -# define DC_DCFG_TRUP 0x00000040 -# define DC_DCFG_DISP_MODE_MASK 0x00000300 -# define DC_DCFG_DISP_MODE_8BPP 0x00000000 -# define DC_DCFG_DISP_MODE_16BPP 0x00000100 -# define DC_DCFG_DISP_MODE_24BPP 0x00000200 -# define DC_DCFG_16BPP_MODE_MASK 0x00000c00 -# define DC_DCFG_16BPP_MODE_565 0x00000000 -# define DC_DCFG_16BPP_MODE_555 0x00000100 -# define DC_DCFG_16BPP_MODE_444 0x00000200 -# define DC_DCFG_DCEN 0x00080000 -# define DC_DCFG_PALB 0x02000000 -# define DC_DCFG_FRLK 0x04000000 -# define DC_DCFG_VISL 0x08000000 -# define DC_DCFG_FRSL 0x20000000 -# define DC_DCFG_A18M 0x40000000 -# define DC_DCFG_A20M 0x80000000 - -#define DC_FB_ST_OFFSET 0x10 - -#define DC_LINE_SIZE 0x30 -# define DC_LINE_SIZE_FB_LINE_SIZE_MASK 0x000007ff -# define DC_LINE_SIZE_FB_LINE_SIZE_POS 0 -# define DC_LINE_SIZE_CB_LINE_SIZE_MASK 0x007f0000 -# define DC_LINE_SIZE_CB_LINE_SIZE_POS 16 -# define DC_LINE_SIZE_VID_LINE_SIZE_MASK 0xff000000 -# define DC_LINE_SIZE_VID_LINE_SIZE_POS 24 - -#define DC_GFX_PITCH 0x34 -# define DC_GFX_PITCH_FB_PITCH_MASK 0x0000ffff -# define DC_GFX_PITCH_FB_PITCH_POS 0 -# define DC_GFX_PITCH_CB_PITCH_MASK 0xffff0000 -# define DC_GFX_PITCH_CB_PITCH_POS 16 - -#define DC_H_ACTIVE_TIMING 0x40 -#define DC_H_BLANK_TIMING 0x44 -#define DC_H_SYNC_TIMING 0x48 -#define DC_V_ACTIVE_TIMING 0x50 -#define DC_V_BLANK_TIMING 0x54 -#define DC_V_SYNC_TIMING 0x58 - -#define DC_PAL_ADDRESS 0x70 -#define DC_PAL_DATA 0x74 - -#define DC_GLIU0_MEM_OFFSET 0x84 -#endif /* !__DISPLAY_GX1_H__ */ diff --git a/drivers/video/geode/gxfb.h b/drivers/video/geode/gxfb.h new file mode 100644 index 00000000000..16a96f8fd8c --- /dev/null +++ b/drivers/video/geode/gxfb.h @@ -0,0 +1,358 @@ +/* + * Copyright (C) 2008 Andres Salomon <dilinger@debian.org> + * + * Geode GX2 header information + * + * 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 _GXFB_H_ +#define _GXFB_H_ + +#include <linux/io.h> + +#define GP_REG_COUNT (0x50 / 4) +#define DC_REG_COUNT (0x90 / 4) +#define VP_REG_COUNT (0x138 / 8) +#define FP_REG_COUNT (0x68 / 8) + +#define DC_PAL_COUNT 0x104 + +struct gxfb_par { + int enable_crt; + void __iomem *dc_regs; + void __iomem *vid_regs; + void __iomem *gp_regs; +#ifdef CONFIG_PM + int powered_down; + + /* register state, for power management functionality */ + struct { + uint64_t padsel; + uint64_t dotpll; + } msr; + + uint32_t gp[GP_REG_COUNT]; + uint32_t dc[DC_REG_COUNT]; + uint64_t vp[VP_REG_COUNT]; + uint64_t fp[FP_REG_COUNT]; + + uint32_t pal[DC_PAL_COUNT]; +#endif +}; + +unsigned int gx_frame_buffer_size(void); +int gx_line_delta(int xres, int bpp); +void gx_set_mode(struct fb_info *info); +void gx_set_hw_palette_reg(struct fb_info *info, unsigned regno, + unsigned red, unsigned green, unsigned blue); + +void gx_set_dclk_frequency(struct fb_info *info); +void gx_configure_display(struct fb_info *info); +int gx_blank_display(struct fb_info *info, int blank_mode); + +#ifdef CONFIG_PM +int gx_powerdown(struct fb_info *info); +int gx_powerup(struct fb_info *info); +#endif + + +/* Graphics Processor registers (table 6-23 from the data book) */ +enum gp_registers { + GP_DST_OFFSET = 0, + GP_SRC_OFFSET, + GP_STRIDE, + GP_WID_HEIGHT, + + GP_SRC_COLOR_FG, + GP_SRC_COLOR_BG, + GP_PAT_COLOR_0, + GP_PAT_COLOR_1, + + GP_PAT_COLOR_2, + GP_PAT_COLOR_3, + GP_PAT_COLOR_4, + GP_PAT_COLOR_5, + + GP_PAT_DATA_0, + GP_PAT_DATA_1, + GP_RASTER_MODE, + GP_VECTOR_MODE, + + GP_BLT_MODE, + GP_BLT_STATUS, + GP_HST_SRC, + GP_BASE_OFFSET, /* 0x4c */ +}; + +#define GP_BLT_STATUS_BLT_PENDING (1 << 2) +#define GP_BLT_STATUS_BLT_BUSY (1 << 0) + + +/* Display Controller registers (table 6-38 from the data book) */ +enum dc_registers { + DC_UNLOCK = 0, + DC_GENERAL_CFG, + DC_DISPLAY_CFG, + DC_RSVD_0, + + DC_FB_ST_OFFSET, + DC_CB_ST_OFFSET, + DC_CURS_ST_OFFSET, + DC_ICON_ST_OFFSET, + + DC_VID_Y_ST_OFFSET, + DC_VID_U_ST_OFFSET, + DC_VID_V_ST_OFFSET, + DC_RSVD_1, + + DC_LINE_SIZE, + DC_GFX_PITCH, + DC_VID_YUV_PITCH, + DC_RSVD_2, + + DC_H_ACTIVE_TIMING, + DC_H_BLANK_TIMING, + DC_H_SYNC_TIMING, + DC_RSVD_3, + + DC_V_ACTIVE_TIMING, + DC_V_BLANK_TIMING, + DC_V_SYNC_TIMING, + DC_RSVD_4, + + DC_CURSOR_X, + DC_CURSOR_Y, + DC_ICON_X, + DC_LINE_CNT, + + DC_PAL_ADDRESS, + DC_PAL_DATA, + DC_DFIFO_DIAG, + DC_CFIFO_DIAG, + + DC_VID_DS_DELTA, + DC_GLIU0_MEM_OFFSET, + DC_RSVD_5, + DC_DV_ACC, /* 0x8c */ +}; + +#define DC_UNLOCK_LOCK 0x00000000 +#define DC_UNLOCK_UNLOCK 0x00004758 /* magic value */ + +#define DC_GENERAL_CFG_YUVM (1 << 20) +#define DC_GENERAL_CFG_VDSE (1 << 19) +#define DC_GENERAL_CFG_DFHPEL_SHIFT 12 +#define DC_GENERAL_CFG_DFHPSL_SHIFT 8 +#define DC_GENERAL_CFG_DECE (1 << 6) +#define DC_GENERAL_CFG_CMPE (1 << 5) +#define DC_GENERAL_CFG_VIDE (1 << 3) +#define DC_GENERAL_CFG_ICNE (1 << 2) +#define DC_GENERAL_CFG_CURE (1 << 1) +#define DC_GENERAL_CFG_DFLE (1 << 0) + +#define DC_DISPLAY_CFG_A20M (1 << 31) +#define DC_DISPLAY_CFG_A18M (1 << 30) +#define DC_DISPLAY_CFG_PALB (1 << 25) +#define DC_DISPLAY_CFG_DISP_MODE_24BPP (1 << 9) +#define DC_DISPLAY_CFG_DISP_MODE_16BPP (1 << 8) +#define DC_DISPLAY_CFG_DISP_MODE_8BPP (0) +#define DC_DISPLAY_CFG_VDEN (1 << 4) +#define DC_DISPLAY_CFG_GDEN (1 << 3) +#define DC_DISPLAY_CFG_TGEN (1 << 0) + + +/* + * Video Processor registers (table 6-54). + * There is space for 64 bit values, but we never use more than the + * lower 32 bits. The actual register save/restore code only bothers + * to restore those 32 bits. + */ +enum vp_registers { + VP_VCFG = 0, + VP_DCFG, + + VP_VX, + VP_VY, + + VP_VS, + VP_VCK, + + VP_VCM, + VP_GAR, + + VP_GDR, + VP_RSVD_0, + + VP_MISC, + VP_CCS, + + VP_RSVD_1, + VP_RSVD_2, + + VP_RSVD_3, + VP_VDC, + + VP_VCO, + VP_CRC, + + VP_CRC32, + VP_VDE, + + VP_CCK, + VP_CCM, + + VP_CC1, + VP_CC2, + + VP_A1X, + VP_A1Y, + + VP_A1C, + VP_A1T, + + VP_A2X, + VP_A2Y, + + VP_A2C, + VP_A2T, + + VP_A3X, + VP_A3Y, + + VP_A3C, + VP_A3T, + + VP_VRR, + VP_AWT, + + VP_VTM, /* 0x130 */ +}; + +#define VP_VCFG_VID_EN (1 << 0) + +#define VP_DCFG_DAC_VREF (1 << 26) +#define VP_DCFG_GV_GAM (1 << 21) +#define VP_DCFG_VG_CK (1 << 20) +#define VP_DCFG_CRT_SYNC_SKW_DEFAULT (1 << 16) +#define VP_DCFG_CRT_SYNC_SKW ((1 << 14) | (1 << 15) | (1 << 16)) +#define VP_DCFG_CRT_VSYNC_POL (1 << 9) +#define VP_DCFG_CRT_HSYNC_POL (1 << 8) +#define VP_DCFG_FP_DATA_EN (1 << 7) /* undocumented */ +#define VP_DCFG_FP_PWR_EN (1 << 6) /* undocumented */ +#define VP_DCFG_DAC_BL_EN (1 << 3) +#define VP_DCFG_VSYNC_EN (1 << 2) +#define VP_DCFG_HSYNC_EN (1 << 1) +#define VP_DCFG_CRT_EN (1 << 0) + +#define VP_MISC_GAM_EN (1 << 0) +#define VP_MISC_DACPWRDN (1 << 10) +#define VP_MISC_APWRDN (1 << 11) + + +/* + * Flat Panel registers (table 6-55). + * Also 64 bit registers; see above note about 32-bit handling. + */ + +/* we're actually in the VP register space, starting at address 0x400 */ +#define VP_FP_START 0x400 + +enum fp_registers { + FP_PT1 = 0, + FP_PT2, + + FP_PM, + FP_DFC, + + FP_BLFSR, + FP_RLFSR, + + FP_FMI, + FP_FMD, + + FP_RSVD_0, + FP_DCA, + + FP_DMD, + FP_CRC, + + FP_FBB, /* 0x460 */ +}; + +#define FP_PT1_VSIZE_SHIFT 16 /* undocumented? */ +#define FP_PT1_VSIZE_MASK 0x7FF0000 /* undocumented? */ + +#define FP_PT2_HSP (1 << 22) +#define FP_PT2_VSP (1 << 23) + +#define FP_PM_P (1 << 24) /* panel power on */ +#define FP_PM_PANEL_PWR_UP (1 << 3) /* r/o */ +#define FP_PM_PANEL_PWR_DOWN (1 << 2) /* r/o */ +#define FP_PM_PANEL_OFF (1 << 1) /* r/o */ +#define FP_PM_PANEL_ON (1 << 0) /* r/o */ + +#define FP_DFC_NFI ((1 << 4) | (1 << 5) | (1 << 6)) + + +/* register access functions */ + +static inline uint32_t read_gp(struct gxfb_par *par, int reg) +{ + return readl(par->gp_regs + 4*reg); +} + +static inline void write_gp(struct gxfb_par *par, int reg, uint32_t val) +{ + writel(val, par->gp_regs + 4*reg); +} + +static inline uint32_t read_dc(struct gxfb_par *par, int reg) +{ + return readl(par->dc_regs + 4*reg); +} + +static inline void write_dc(struct gxfb_par *par, int reg, uint32_t val) +{ + writel(val, par->dc_regs + 4*reg); +} + +static inline uint32_t read_vp(struct gxfb_par *par, int reg) +{ + return readl(par->vid_regs + 8*reg); +} + +static inline void write_vp(struct gxfb_par *par, int reg, uint32_t val) +{ + writel(val, par->vid_regs + 8*reg); +} + +static inline uint32_t read_fp(struct gxfb_par *par, int reg) +{ + return readl(par->vid_regs + 8*reg + VP_FP_START); +} + +static inline void write_fp(struct gxfb_par *par, int reg, uint32_t val) +{ + writel(val, par->vid_regs + 8*reg + VP_FP_START); +} + + +/* MSRs are defined in asm/geode.h; their bitfields are here */ + +#define MSR_GLCP_SYS_RSTPLL_DOTPOSTDIV3 (1 << 3) +#define MSR_GLCP_SYS_RSTPLL_DOTPREMULT2 (1 << 2) +#define MSR_GLCP_SYS_RSTPLL_DOTPREDIV2 (1 << 1) + +#define MSR_GLCP_DOTPLL_LOCK (1 << 25) /* r/o */ +#define MSR_GLCP_DOTPLL_BYPASS (1 << 15) +#define MSR_GLCP_DOTPLL_DOTRESET (1 << 0) + +#define MSR_GX_MSR_PADSEL_MASK 0x3FFFFFFF /* undocumented? */ +#define MSR_GX_MSR_PADSEL_TFT 0x1FFFFFFF /* undocumented? */ + +#define MSR_GX_GLD_MSR_CONFIG_FP (1 << 3) + +#endif diff --git a/drivers/video/geode/gxfb_core.c b/drivers/video/geode/gxfb_core.c index cf841efa229..de2b8f9876a 100644 --- a/drivers/video/geode/gxfb_core.c +++ b/drivers/video/geode/gxfb_core.c @@ -28,17 +28,20 @@ #include <linux/slab.h> #include <linux/delay.h> #include <linux/fb.h> +#include <linux/console.h> +#include <linux/suspend.h> #include <linux/init.h> #include <linux/pci.h> +#include <asm/geode.h> -#include "geodefb.h" -#include "display_gx.h" -#include "video_gx.h" +#include "gxfb.h" static char *mode_option; +static int vram; +static int vt_switch; /* Modes relevant to the GX (taken from modedb.c) */ -static const struct fb_videomode gx_modedb[] __initdata = { +static struct fb_videomode gx_modedb[] __initdata = { /* 640x480-60 VESA */ { NULL, 60, 640, 480, 39682, 48, 16, 33, 10, 96, 2, 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, @@ -105,6 +108,35 @@ static const struct fb_videomode gx_modedb[] __initdata = { FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, }; +#ifdef CONFIG_OLPC +#include <asm/olpc.h> + +static struct fb_videomode gx_dcon_modedb[] __initdata = { + /* The only mode the DCON has is 1200x900 */ + { NULL, 50, 1200, 900, 17460, 24, 8, 4, 5, 8, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, 0 } +}; + +static void __init get_modedb(struct fb_videomode **modedb, unsigned int *size) +{ + if (olpc_has_dcon()) { + *modedb = (struct fb_videomode *) gx_dcon_modedb; + *size = ARRAY_SIZE(gx_dcon_modedb); + } else { + *modedb = (struct fb_videomode *) gx_modedb; + *size = ARRAY_SIZE(gx_modedb); + } +} + +#else +static void __init get_modedb(struct fb_videomode **modedb, unsigned int *size) +{ + *modedb = (struct fb_videomode *) gx_modedb; + *size = ARRAY_SIZE(gx_modedb); +} +#endif + static int gxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { if (var->xres > 1600 || var->yres > 1200) @@ -139,8 +171,6 @@ static int gxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) static int gxfb_set_par(struct fb_info *info) { - struct geodefb_par *par = info->par; - if (info->var.bits_per_pixel > 8) { info->fix.visual = FB_VISUAL_TRUECOLOR; fb_dealloc_cmap(&info->cmap); @@ -151,7 +181,7 @@ static int gxfb_set_par(struct fb_info *info) info->fix.line_length = gx_line_delta(info->var.xres, info->var.bits_per_pixel); - par->dc_ops->set_mode(info); + gx_set_mode(info); return 0; } @@ -167,8 +197,6 @@ static int gxfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info) { - struct geodefb_par *par = info->par; - if (info->var.grayscale) { /* grayscale = 0.30*R + 0.59*G + 0.11*B */ red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; @@ -191,7 +219,7 @@ static int gxfb_setcolreg(unsigned regno, unsigned red, unsigned green, if (regno >= 256) return -EINVAL; - par->dc_ops->set_palette_reg(info, regno, red, green, blue); + gx_set_hw_palette_reg(info, regno, red, green, blue); } return 0; @@ -199,15 +227,12 @@ static int gxfb_setcolreg(unsigned regno, unsigned red, unsigned green, static int gxfb_blank(int blank_mode, struct fb_info *info) { - struct geodefb_par *par = info->par; - - return par->vid_ops->blank_display(info, blank_mode); + return gx_blank_display(info, blank_mode); } static int __init gxfb_map_video_memory(struct fb_info *info, struct pci_dev *dev) { - struct geodefb_par *par = info->par; - int fb_len; + struct gxfb_par *par = info->par; int ret; ret = pci_enable_device(dev); @@ -229,24 +254,31 @@ static int __init gxfb_map_video_memory(struct fb_info *info, struct pci_dev *de if (!par->dc_regs) return -ENOMEM; - ret = pci_request_region(dev, 0, "gxfb (framebuffer)"); + ret = pci_request_region(dev, 1, "gxfb (graphics processor)"); if (ret < 0) return ret; - if ((fb_len = gx_frame_buffer_size()) < 0) + par->gp_regs = ioremap(pci_resource_start(dev, 1), + pci_resource_len(dev, 1)); + + if (!par->gp_regs) return -ENOMEM; + + ret = pci_request_region(dev, 0, "gxfb (framebuffer)"); + if (ret < 0) + return ret; + info->fix.smem_start = pci_resource_start(dev, 0); - info->fix.smem_len = fb_len; + info->fix.smem_len = vram ? vram : gx_frame_buffer_size(); info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len); if (!info->screen_base) return -ENOMEM; - /* Set the 16MB aligned base address of the graphics memory region + /* Set the 16MiB aligned base address of the graphics memory region * in the display controller */ - writel(info->fix.smem_start & 0xFF000000, - par->dc_regs + DC_GLIU0_MEM_OFFSET); + write_dc(par, DC_GLIU0_MEM_OFFSET, info->fix.smem_start & 0xFF000000); - dev_info(&dev->dev, "%d Kibyte of video memory at 0x%lx\n", + dev_info(&dev->dev, "%d KiB of video memory at 0x%lx\n", info->fix.smem_len / 1024, info->fix.smem_start); return 0; @@ -266,11 +298,12 @@ static struct fb_ops gxfb_ops = { static struct fb_info * __init gxfb_init_fbinfo(struct device *dev) { - struct geodefb_par *par; + struct gxfb_par *par; struct fb_info *info; /* Alloc enough space for the pseudo palette. */ - info = framebuffer_alloc(sizeof(struct geodefb_par) + sizeof(u32) * 16, dev); + info = framebuffer_alloc(sizeof(struct gxfb_par) + sizeof(u32) * 16, + dev); if (!info) return NULL; @@ -296,29 +329,64 @@ static struct fb_info * __init gxfb_init_fbinfo(struct device *dev) info->flags = FBINFO_DEFAULT; info->node = -1; - info->pseudo_palette = (void *)par + sizeof(struct geodefb_par); + info->pseudo_palette = (void *)par + sizeof(struct gxfb_par); info->var.grayscale = 0; return info; } +#ifdef CONFIG_PM +static int gxfb_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct fb_info *info = pci_get_drvdata(pdev); + + if (state.event == PM_EVENT_SUSPEND) { + acquire_console_sem(); + gx_powerdown(info); + fb_set_suspend(info, 1); + release_console_sem(); + } + + /* there's no point in setting PCI states; we emulate PCI, so + * we don't end up getting power savings anyways */ + + return 0; +} + +static int gxfb_resume(struct pci_dev *pdev) +{ + struct fb_info *info = pci_get_drvdata(pdev); + int ret; + + acquire_console_sem(); + ret = gx_powerup(info); + if (ret) { + printk(KERN_ERR "gxfb: power up failed!\n"); + return ret; + } + + fb_set_suspend(info, 0); + release_console_sem(); + return 0; +} +#endif + static int __init gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *id) { - struct geodefb_par *par; + struct gxfb_par *par; struct fb_info *info; int ret; unsigned long val; + struct fb_videomode *modedb_ptr; + unsigned int modedb_size; + info = gxfb_init_fbinfo(&pdev->dev); if (!info) return -ENOMEM; par = info->par; - /* GX display controller and GX video device. */ - par->dc_ops = &gx_dc_ops; - par->vid_ops = &gx_vid_ops; - if ((ret = gxfb_map_video_memory(info, pdev)) < 0) { dev_err(&pdev->dev, "failed to map frame buffer or controller registers\n"); goto err; @@ -326,15 +394,16 @@ static int __init gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *i /* Figure out if this is a TFT or CRT part */ - rdmsrl(GLD_MSR_CONFIG, val); + rdmsrl(MSR_GX_GLD_MSR_CONFIG, val); - if ((val & GLD_MSR_CONFIG_DM_FP) == GLD_MSR_CONFIG_DM_FP) + if ((val & MSR_GX_GLD_MSR_CONFIG_FP) == MSR_GX_GLD_MSR_CONFIG_FP) par->enable_crt = 0; else par->enable_crt = 1; + get_modedb(&modedb_ptr, &modedb_size); ret = fb_find_mode(&info->var, info, mode_option, - gx_modedb, ARRAY_SIZE(gx_modedb), NULL, 16); + modedb_ptr, modedb_size, NULL, 16); if (ret == 0 || ret == 4) { dev_err(&pdev->dev, "could not find valid video mode\n"); ret = -EINVAL; @@ -348,6 +417,8 @@ static int __init gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *i gxfb_check_var(&info->var, info); gxfb_set_par(info); + pm_set_vt_switch(vt_switch); + if (register_framebuffer(info) < 0) { ret = -EINVAL; goto err; @@ -369,6 +440,10 @@ static int __init gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *i iounmap(par->dc_regs); pci_release_region(pdev, 2); } + if (par->gp_regs) { + iounmap(par->gp_regs); + pci_release_region(pdev, 1); + } if (info) framebuffer_release(info); @@ -378,7 +453,7 @@ static int __init gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *i static void gxfb_remove(struct pci_dev *pdev) { struct fb_info *info = pci_get_drvdata(pdev); - struct geodefb_par *par = info->par; + struct gxfb_par *par = info->par; unregister_framebuffer(info); @@ -391,15 +466,16 @@ static void gxfb_remove(struct pci_dev *pdev) iounmap(par->dc_regs); pci_release_region(pdev, 2); + iounmap(par->gp_regs); + pci_release_region(pdev, 1); + pci_set_drvdata(pdev, NULL); framebuffer_release(info); } static struct pci_device_id gxfb_id_table[] = { - { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_GX_VIDEO, - PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16, - 0xff0000, 0 }, + { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_GX_VIDEO) }, { 0, } }; @@ -410,6 +486,10 @@ static struct pci_driver gxfb_driver = { .id_table = gxfb_id_table, .probe = gxfb_probe, .remove = gxfb_remove, +#ifdef CONFIG_PM + .suspend = gxfb_suspend, + .resume = gxfb_resume, +#endif }; #ifndef MODULE @@ -456,5 +536,11 @@ module_exit(gxfb_cleanup); module_param(mode_option, charp, 0); MODULE_PARM_DESC(mode_option, "video mode (<x>x<y>[-<bpp>][@<refr>])"); +module_param(vram, int, 0); +MODULE_PARM_DESC(vram, "video memory size"); + +module_param(vt_switch, int, 0); +MODULE_PARM_DESC(vt_switch, "enable VT switch during suspend/resume"); + MODULE_DESCRIPTION("Framebuffer driver for the AMD Geode GX"); MODULE_LICENSE("GPL"); diff --git a/drivers/video/geode/lxfb.h b/drivers/video/geode/lxfb.h index ca13c48d19b..3b9416f4ee2 100644 --- a/drivers/video/geode/lxfb.h +++ b/drivers/video/geode/lxfb.h @@ -3,17 +3,46 @@ #include <linux/fb.h> +#define GP_REG_COUNT (0x7c / 4) +#define DC_REG_COUNT (0xf0 / 4) +#define VP_REG_COUNT (0x158 / 8) +#define FP_REG_COUNT (0x60 / 8) + +#define DC_PAL_COUNT 0x104 +#define DC_HFILT_COUNT 0x100 +#define DC_VFILT_COUNT 0x100 +#define VP_COEFF_SIZE 0x1000 + #define OUTPUT_CRT 0x01 #define OUTPUT_PANEL 0x02 struct lxfb_par { int output; - int panel_width; - int panel_height; void __iomem *gp_regs; void __iomem *dc_regs; - void __iomem *df_regs; + void __iomem *vp_regs; +#ifdef CONFIG_PM + int powered_down; + + /* register state, for power mgmt functionality */ + struct { + uint64_t padsel; + uint64_t dotpll; + uint64_t dfglcfg; + uint64_t dcspare; + } msr; + + uint32_t gp[GP_REG_COUNT]; + uint32_t dc[DC_REG_COUNT]; + uint64_t vp[VP_REG_COUNT]; + uint64_t fp[FP_REG_COUNT]; + + uint32_t pal[DC_PAL_COUNT]; + uint32_t hcoeff[DC_HFILT_COUNT * 2]; + uint32_t vcoeff[DC_VFILT_COUNT]; + uint32_t vp_coeff[VP_COEFF_SIZE / 4]; +#endif }; static inline unsigned int lx_get_pitch(unsigned int xres, int bpp) @@ -29,171 +58,383 @@ int lx_blank_display(struct fb_info *, int); void lx_set_palette_reg(struct fb_info *, unsigned int, unsigned int, unsigned int, unsigned int); -/* MSRS */ +#ifdef CONFIG_PM +int lx_powerdown(struct fb_info *info); +int lx_powerup(struct fb_info *info); +#endif + + +/* Graphics Processor registers (table 6-29 from the data book) */ +enum gp_registers { + GP_DST_OFFSET = 0, + GP_SRC_OFFSET, + GP_STRIDE, + GP_WID_HEIGHT, + + GP_SRC_COLOR_FG, + GP_SRC_COLOR_BG, + GP_PAT_COLOR_0, + GP_PAT_COLOR_1, + + GP_PAT_COLOR_2, + GP_PAT_COLOR_3, + GP_PAT_COLOR_4, + GP_PAT_COLOR_5, + + GP_PAT_DATA_0, + GP_PAT_DATA_1, + GP_RASTER_MODE, + GP_VECTOR_MODE, + + GP_BLT_MODE, + GP_BLT_STATUS, + GP_HST_SRC, + GP_BASE_OFFSET, + + GP_CMD_TOP, + GP_CMD_BOT, + GP_CMD_READ, + GP_CMD_WRITE, + + GP_CH3_OFFSET, + GP_CH3_MODE_STR, + GP_CH3_WIDHI, + GP_CH3_HSRC, + + GP_LUT_INDEX, + GP_LUT_DATA, + GP_INT_CNTRL, /* 0x78 */ +}; + +#define GP_BLT_STATUS_CE (1 << 4) /* cmd buf empty */ +#define GP_BLT_STATUS_PB (1 << 0) /* primative busy */ + + +/* Display Controller registers (table 6-47 from the data book) */ +enum dc_registers { + DC_UNLOCK = 0, + DC_GENERAL_CFG, + DC_DISPLAY_CFG, + DC_ARB_CFG, + + DC_FB_ST_OFFSET, + DC_CB_ST_OFFSET, + DC_CURS_ST_OFFSET, + DC_RSVD_0, + + DC_VID_Y_ST_OFFSET, + DC_VID_U_ST_OFFSET, + DC_VID_V_ST_OFFSET, + DC_DV_TOP, + + DC_LINE_SIZE, + DC_GFX_PITCH, + DC_VID_YUV_PITCH, + DC_RSVD_1, + + DC_H_ACTIVE_TIMING, + DC_H_BLANK_TIMING, + DC_H_SYNC_TIMING, + DC_RSVD_2, + + DC_V_ACTIVE_TIMING, + DC_V_BLANK_TIMING, + DC_V_SYNC_TIMING, + DC_FB_ACTIVE, + + DC_CURSOR_X, + DC_CURSOR_Y, + DC_RSVD_3, + DC_LINE_CNT, + + DC_PAL_ADDRESS, + DC_PAL_DATA, + DC_DFIFO_DIAG, + DC_CFIFO_DIAG, + + DC_VID_DS_DELTA, + DC_GLIU0_MEM_OFFSET, + DC_DV_CTL, + DC_DV_ACCESS, + + DC_GFX_SCALE, + DC_IRQ_FILT_CTL, + DC_FILT_COEFF1, + DC_FILT_COEFF2, + + DC_VBI_EVEN_CTL, + DC_VBI_ODD_CTL, + DC_VBI_HOR, + DC_VBI_LN_ODD, + + DC_VBI_LN_EVEN, + DC_VBI_PITCH, + DC_CLR_KEY, + DC_CLR_KEY_MASK, + + DC_CLR_KEY_X, + DC_CLR_KEY_Y, + DC_IRQ, + DC_RSVD_4, + + DC_RSVD_5, + DC_GENLK_CTL, + DC_VID_EVEN_Y_ST_OFFSET, + DC_VID_EVEN_U_ST_OFFSET, + + DC_VID_EVEN_V_ST_OFFSET, + DC_V_ACTIVE_EVEN_TIMING, + DC_V_BLANK_EVEN_TIMING, + DC_V_SYNC_EVEN_TIMING, /* 0xec */ +}; + +#define DC_UNLOCK_LOCK 0x00000000 +#define DC_UNLOCK_UNLOCK 0x00004758 /* magic value */ + +#define DC_GENERAL_CFG_FDTY (1 << 17) +#define DC_GENERAL_CFG_DFHPEL_SHIFT (12) +#define DC_GENERAL_CFG_DFHPSL_SHIFT (8) +#define DC_GENERAL_CFG_VGAE (1 << 7) +#define DC_GENERAL_CFG_DECE (1 << 6) +#define DC_GENERAL_CFG_CMPE (1 << 5) +#define DC_GENERAL_CFG_VIDE (1 << 3) +#define DC_GENERAL_CFG_DFLE (1 << 0) + +#define DC_DISPLAY_CFG_VISL (1 << 27) +#define DC_DISPLAY_CFG_PALB (1 << 25) +#define DC_DISPLAY_CFG_DCEN (1 << 24) +#define DC_DISPLAY_CFG_DISP_MODE_24BPP (1 << 9) +#define DC_DISPLAY_CFG_DISP_MODE_16BPP (1 << 8) +#define DC_DISPLAY_CFG_DISP_MODE_8BPP (0) +#define DC_DISPLAY_CFG_TRUP (1 << 6) +#define DC_DISPLAY_CFG_VDEN (1 << 4) +#define DC_DISPLAY_CFG_GDEN (1 << 3) +#define DC_DISPLAY_CFG_TGEN (1 << 0) + +#define DC_DV_TOP_DV_TOP_EN (1 << 0) + +#define DC_DV_CTL_DV_LINE_SIZE ((1 << 10) | (1 << 11)) +#define DC_DV_CTL_DV_LINE_SIZE_1K (0) +#define DC_DV_CTL_DV_LINE_SIZE_2K (1 << 10) +#define DC_DV_CTL_DV_LINE_SIZE_4K (1 << 11) +#define DC_DV_CTL_DV_LINE_SIZE_8K ((1 << 10) | (1 << 11)) +#define DC_DV_CTL_CLEAR_DV_RAM (1 << 0) + +#define DC_IRQ_FILT_CTL_H_FILT_SEL (1 << 10) + +#define DC_CLR_KEY_CLR_KEY_EN (1 << 24) + +#define DC_IRQ_VIP_VSYNC_IRQ_STATUS (1 << 21) /* undocumented? */ +#define DC_IRQ_STATUS (1 << 20) /* undocumented? */ +#define DC_IRQ_VIP_VSYNC_LOSS_IRQ_MASK (1 << 1) +#define DC_IRQ_MASK (1 << 0) -#define MSR_LX_GLD_CONFIG 0x48002001 -#define MSR_LX_GLCP_DOTPLL 0x4c000015 -#define MSR_LX_DF_PADSEL 0x48002011 -#define MSR_LX_DC_SPARE 0x80000011 -#define MSR_LX_DF_GLCONFIG 0x48002001 - -#define MSR_LX_GLIU0_P2D_RO0 0x10000029 - -#define GLCP_DOTPLL_RESET (1 << 0) -#define GLCP_DOTPLL_BYPASS (1 << 15) -#define GLCP_DOTPLL_HALFPIX (1 << 24) -#define GLCP_DOTPLL_LOCK (1 << 25) - -#define DF_CONFIG_OUTPUT_MASK 0x38 -#define DF_OUTPUT_PANEL 0x08 -#define DF_OUTPUT_CRT 0x00 -#define DF_SIMULTANEOUS_CRT_AND_FP (1 << 15) - -#define DF_DEFAULT_TFT_PAD_SEL_LOW 0xDFFFFFFF -#define DF_DEFAULT_TFT_PAD_SEL_HIGH 0x0000003F - -#define DC_SPARE_DISABLE_CFIFO_HGO 0x00000800 -#define DC_SPARE_VFIFO_ARB_SELECT 0x00000400 -#define DC_SPARE_WM_LPEN_OVRD 0x00000200 -#define DC_SPARE_LOAD_WM_LPEN_MASK 0x00000100 -#define DC_SPARE_DISABLE_INIT_VID_PRI 0x00000080 -#define DC_SPARE_DISABLE_VFIFO_WM 0x00000040 -#define DC_SPARE_DISABLE_CWD_CHECK 0x00000020 -#define DC_SPARE_PIX8_PAN_FIX 0x00000010 -#define DC_SPARE_FIRST_REQ_MASK 0x00000002 - -/* Registers */ - -#define DC_UNLOCK 0x00 -#define DC_UNLOCK_CODE 0x4758 +#define DC_GENLK_CTL_FLICK_SEL_MASK (0x0F << 28) +#define DC_GENLK_CTL_ALPHA_FLICK_EN (1 << 25) +#define DC_GENLK_CTL_FLICK_EN (1 << 24) +#define DC_GENLK_CTL_GENLK_EN (1 << 18) -#define DC_GENERAL_CFG 0x04 -#define DC_GCFG_DFLE (1 << 0) -#define DC_GCFG_VIDE (1 << 3) -#define DC_GCFG_VGAE (1 << 7) -#define DC_GCFG_CMPE (1 << 5) -#define DC_GCFG_DECE (1 << 6) -#define DC_GCFG_FDTY (1 << 17) -#define DC_DISPLAY_CFG 0x08 -#define DC_DCFG_TGEN (1 << 0) -#define DC_DCFG_GDEN (1 << 3) -#define DC_DCFG_VDEN (1 << 4) -#define DC_DCFG_TRUP (1 << 6) -#define DC_DCFG_DCEN (1 << 24) -#define DC_DCFG_PALB (1 << 25) -#define DC_DCFG_VISL (1 << 27) +/* + * Video Processor registers (table 6-71). + * There is space for 64 bit values, but we never use more than the + * lower 32 bits. The actual register save/restore code only bothers + * to restore those 32 bits. + */ +enum vp_registers { + VP_VCFG = 0, + VP_DCFG, -#define DC_DCFG_16BPP 0x0 + VP_VX, + VP_VY, -#define DC_DCFG_DISP_MODE_MASK 0x00000300 -#define DC_DCFG_DISP_MODE_8BPP 0x00000000 -#define DC_DCFG_DISP_MODE_16BPP 0x00000100 -#define DC_DCFG_DISP_MODE_24BPP 0x00000200 -#define DC_DCFG_DISP_MODE_32BPP 0x00000300 + VP_SCL, + VP_VCK, + VP_VCM, + VP_PAR, -#define DC_ARB_CFG 0x0C + VP_PDR, + VP_SLR, -#define DC_FB_START 0x10 -#define DC_CB_START 0x14 -#define DC_CURSOR_START 0x18 + VP_MISC, + VP_CCS, -#define DC_DV_TOP 0x2C -#define DC_DV_TOP_ENABLE (1 << 0) + VP_VYS, + VP_VXS, -#define DC_LINE_SIZE 0x30 -#define DC_GRAPHICS_PITCH 0x34 -#define DC_H_ACTIVE_TIMING 0x40 -#define DC_H_BLANK_TIMING 0x44 -#define DC_H_SYNC_TIMING 0x48 -#define DC_V_ACTIVE_TIMING 0x50 -#define DC_V_BLANK_TIMING 0x54 -#define DC_V_SYNC_TIMING 0x58 -#define DC_FB_ACTIVE 0x5C + VP_RSVD_0, + VP_VDC, + + VP_RSVD_1, + VP_CRC, + + VP_CRC32, + VP_VDE, + + VP_CCK, + VP_CCM, + + VP_CC1, + VP_CC2, + + VP_A1X, + VP_A1Y, + + VP_A1C, + VP_A1T, + + VP_A2X, + VP_A2Y, + + VP_A2C, + VP_A2T, + + VP_A3X, + VP_A3Y, + + VP_A3C, + VP_A3T, + + VP_VRR, + VP_AWT, + + VP_VTM, + VP_VYE, + + VP_A1YE, + VP_A2YE, + + VP_A3YE, /* 0x150 */ + + VP_VCR = 0x1000, /* 0x1000 - 0x1fff */ +}; -#define DC_PAL_ADDRESS 0x70 -#define DC_PAL_DATA 0x74 +#define VP_VCFG_VID_EN (1 << 0) -#define DC_PHY_MEM_OFFSET 0x84 +#define VP_DCFG_GV_GAM (1 << 21) +#define VP_DCFG_PWR_SEQ_DELAY ((1 << 17) | (1 << 18) | (1 << 19)) +#define VP_DCFG_PWR_SEQ_DELAY_DEFAULT (1 << 19) /* undocumented */ +#define VP_DCFG_CRT_SYNC_SKW ((1 << 14) | (1 << 15) | (1 << 16)) +#define VP_DCFG_CRT_SYNC_SKW_DEFAULT (1 << 16) +#define VP_DCFG_CRT_VSYNC_POL (1 << 9) +#define VP_DCFG_CRT_HSYNC_POL (1 << 8) +#define VP_DCFG_DAC_BL_EN (1 << 3) +#define VP_DCFG_VSYNC_EN (1 << 2) +#define VP_DCFG_HSYNC_EN (1 << 1) +#define VP_DCFG_CRT_EN (1 << 0) -#define DC_DV_CTL 0x88 -#define DC_DV_LINE_SIZE_MASK 0x00000C00 -#define DC_DV_LINE_SIZE_1024 0x00000000 -#define DC_DV_LINE_SIZE_2048 0x00000400 -#define DC_DV_LINE_SIZE_4096 0x00000800 -#define DC_DV_LINE_SIZE_8192 0x00000C00 +#define VP_MISC_APWRDN (1 << 11) +#define VP_MISC_DACPWRDN (1 << 10) +#define VP_MISC_BYP_BOTH (1 << 0) -#define DC_GFX_SCALE 0x90 -#define DC_IRQ_FILT_CTL 0x94 +/* + * Flat Panel registers (table 6-71). + * Also 64 bit registers; see above note about 32-bit handling. + */ +/* we're actually in the VP register space, starting at address 0x400 */ +#define VP_FP_START 0x400 -#define DC_IRQ 0xC8 -#define DC_IRQ_MASK (1 << 0) -#define DC_VSYNC_IRQ_MASK (1 << 1) -#define DC_IRQ_STATUS (1 << 20) -#define DC_VSYNC_IRQ_STATUS (1 << 21) - -#define DC_GENLCK_CTRL 0xD4 -#define DC_GENLCK_ENABLE (1 << 18) -#define DC_GC_ALPHA_FLICK_ENABLE (1 << 25) -#define DC_GC_FLICKER_FILTER_ENABLE (1 << 24) -#define DC_GC_FLICKER_FILTER_MASK (0x0F << 28) - -#define DC_COLOR_KEY 0xB8 -#define DC_CLR_KEY_ENABLE (1 << 24) - - -#define DC3_DV_LINE_SIZE_MASK 0x00000C00 -#define DC3_DV_LINE_SIZE_1024 0x00000000 -#define DC3_DV_LINE_SIZE_2048 0x00000400 -#define DC3_DV_LINE_SIZE_4096 0x00000800 -#define DC3_DV_LINE_SIZE_8192 0x00000C00 - -#define DF_VIDEO_CFG 0x0 -#define DF_VCFG_VID_EN (1 << 0) - -#define DF_DISPLAY_CFG 0x08 - -#define DF_DCFG_CRT_EN (1 << 0) -#define DF_DCFG_HSYNC_EN (1 << 1) -#define DF_DCFG_VSYNC_EN (1 << 2) -#define DF_DCFG_DAC_BL_EN (1 << 3) -#define DF_DCFG_CRT_HSYNC_POL (1 << 8) -#define DF_DCFG_CRT_VSYNC_POL (1 << 9) -#define DF_DCFG_GV_PAL_BYP (1 << 21) +enum fp_registers { + FP_PT1 = 0, + FP_PT2, -#define DF_DCFG_CRT_SYNC_SKW_INIT 0x10000 -#define DF_DCFG_CRT_SYNC_SKW_MASK 0x1c000 + FP_PM, + FP_DFC, -#define DF_DCFG_PWR_SEQ_DLY_INIT 0x80000 -#define DF_DCFG_PWR_SEQ_DLY_MASK 0xe0000 + FP_RSVD_0, + FP_RSVD_1, -#define DF_MISC 0x50 + FP_RSVD_2, + FP_RSVD_3, + + FP_RSVD_4, + FP_DCA, + + FP_DMD, + FP_CRC, /* 0x458 */ +}; + +#define FP_PT2_SCRC (1 << 27) /* shfclk free */ + +#define FP_PM_P (1 << 24) /* panel power ctl */ +#define FP_PM_PANEL_PWR_UP (1 << 3) /* r/o */ +#define FP_PM_PANEL_PWR_DOWN (1 << 2) /* r/o */ +#define FP_PM_PANEL_OFF (1 << 1) /* r/o */ +#define FP_PM_PANEL_ON (1 << 0) /* r/o */ + +#define FP_DFC_BC ((1 << 4) | (1 << 5) | (1 << 6)) + + +/* register access functions */ + +static inline uint32_t read_gp(struct lxfb_par *par, int reg) +{ + return readl(par->gp_regs + 4*reg); +} + +static inline void write_gp(struct lxfb_par *par, int reg, uint32_t val) +{ + writel(val, par->gp_regs + 4*reg); +} + +static inline uint32_t read_dc(struct lxfb_par *par, int reg) +{ + return readl(par->dc_regs + 4*reg); +} + +static inline void write_dc(struct lxfb_par *par, int reg, uint32_t val) +{ + writel(val, par->dc_regs + 4*reg); +} + +static inline uint32_t read_vp(struct lxfb_par *par, int reg) +{ + return readl(par->vp_regs + 8*reg); +} + +static inline void write_vp(struct lxfb_par *par, int reg, uint32_t val) +{ + writel(val, par->vp_regs + 8*reg); +} + +static inline uint32_t read_fp(struct lxfb_par *par, int reg) +{ + return readl(par->vp_regs + 8*reg + VP_FP_START); +} + +static inline void write_fp(struct lxfb_par *par, int reg, uint32_t val) +{ + writel(val, par->vp_regs + 8*reg + VP_FP_START); +} -#define DF_MISC_GAM_BYPASS (1 << 0) -#define DF_MISC_DAC_PWRDN (1 << 10) -#define DF_MISC_A_PWRDN (1 << 11) -#define DF_PAR 0x38 -#define DF_PDR 0x40 -#define DF_ALPHA_CONTROL_1 0xD8 -#define DF_VIDEO_REQUEST 0x120 +/* MSRs are defined in asm/geode.h; their bitfields are here */ -#define DF_PANEL_TIM1 0x400 -#define DF_DEFAULT_TFT_PMTIM1 0x0 +#define MSR_GLCP_DOTPLL_LOCK (1 << 25) /* r/o */ +#define MSR_GLCP_DOTPLL_HALFPIX (1 << 24) +#define MSR_GLCP_DOTPLL_BYPASS (1 << 15) +#define MSR_GLCP_DOTPLL_DOTRESET (1 << 0) -#define DF_PANEL_TIM2 0x408 -#define DF_DEFAULT_TFT_PMTIM2 0x08000000 +/* note: this is actually the VP's GLD_MSR_CONFIG */ +#define MSR_LX_GLD_MSR_CONFIG_FMT ((1 << 3) | (1 << 4) | (1 << 5)) +#define MSR_LX_GLD_MSR_CONFIG_FMT_FP (1 << 3) +#define MSR_LX_GLD_MSR_CONFIG_FMT_CRT (0) +#define MSR_LX_GLD_MSR_CONFIG_FPC (1 << 15) /* FP *and* CRT */ -#define DF_FP_PM 0x410 -#define DF_FP_PM_P (1 << 24) +#define MSR_LX_MSR_PADSEL_TFT_SEL_LOW 0xDFFFFFFF /* ??? */ +#define MSR_LX_MSR_PADSEL_TFT_SEL_HIGH 0x0000003F /* ??? */ -#define DF_DITHER_CONTROL 0x418 -#define DF_DEFAULT_TFT_DITHCTL 0x00000070 -#define GP_BLT_STATUS 0x44 -#define GP_BS_BLT_BUSY (1 << 0) -#define GP_BS_CB_EMPTY (1 << 4) +#define MSR_LX_SPARE_MSR_DIS_CFIFO_HGO (1 << 11) /* undocumented */ +#define MSR_LX_SPARE_MSR_VFIFO_ARB_SEL (1 << 10) /* undocumented */ +#define MSR_LX_SPARE_MSR_WM_LPEN_OVRD (1 << 9) /* undocumented */ +#define MSR_LX_SPARE_MSR_LOAD_WM_LPEN_M (1 << 8) /* undocumented */ +#define MSR_LX_SPARE_MSR_DIS_INIT_V_PRI (1 << 7) /* undocumented */ +#define MSR_LX_SPARE_MSR_DIS_VIFO_WM (1 << 6) +#define MSR_LX_SPARE_MSR_DIS_CWD_CHECK (1 << 5) /* undocumented */ +#define MSR_LX_SPARE_MSR_PIX8_PAN_FIX (1 << 4) /* undocumented */ +#define MSR_LX_SPARE_MSR_FIRST_REQ_MASK (1 << 1) /* undocumented */ #endif diff --git a/drivers/video/geode/lxfb_core.c b/drivers/video/geode/lxfb_core.c index eb6b8817153..2cd9b74d222 100644 --- a/drivers/video/geode/lxfb_core.c +++ b/drivers/video/geode/lxfb_core.c @@ -17,6 +17,7 @@ #include <linux/console.h> #include <linux/mm.h> #include <linux/slab.h> +#include <linux/suspend.h> #include <linux/delay.h> #include <linux/fb.h> #include <linux/init.h> @@ -27,14 +28,15 @@ static char *mode_option; static int noclear, nopanel, nocrt; -static int fbsize; +static int vram; +static int vt_switch; /* Most of these modes are sorted in ascending order, but * since the first entry in this table is the "default" mode, * we try to make it something sane - 640x480-60 is sane */ -static const struct fb_videomode geode_modedb[] __initdata = { +static struct fb_videomode geode_modedb[] __initdata = { /* 640x480-60 */ { NULL, 60, 640, 480, 39682, 48, 8, 25, 2, 88, 2, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, @@ -215,6 +217,35 @@ static const struct fb_videomode geode_modedb[] __initdata = { 0, FB_VMODE_NONINTERLACED, 0 }, }; +#ifdef CONFIG_OLPC +#include <asm/olpc.h> + +static struct fb_videomode olpc_dcon_modedb[] __initdata = { + /* The only mode the DCON has is 1200x900 */ + { NULL, 50, 1200, 900, 17460, 24, 8, 4, 5, 8, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, 0 } +}; + +static void __init get_modedb(struct fb_videomode **modedb, unsigned int *size) +{ + if (olpc_has_dcon()) { + *modedb = (struct fb_videomode *) olpc_dcon_modedb; + *size = ARRAY_SIZE(olpc_dcon_modedb); + } else { + *modedb = (struct fb_videomode *) geode_modedb; + *size = ARRAY_SIZE(geode_modedb); + } +} + +#else +static void __init get_modedb(struct fb_videomode **modedb, unsigned int *size) +{ + *modedb = (struct fb_videomode *) geode_modedb; + *size = ARRAY_SIZE(geode_modedb); +} +#endif + static int lxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { if (var->xres > 1920 || var->yres > 1440) @@ -333,13 +364,13 @@ static int __init lxfb_map_video_memory(struct fb_info *info, if (ret) return ret; - ret = pci_request_region(dev, 3, "lxfb-vip"); + ret = pci_request_region(dev, 3, "lxfb-vp"); if (ret) return ret; info->fix.smem_start = pci_resource_start(dev, 0); - info->fix.smem_len = fbsize ? fbsize : lx_framebuffer_size(); + info->fix.smem_len = vram ? vram : lx_framebuffer_size(); info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len); @@ -360,18 +391,15 @@ static int __init lxfb_map_video_memory(struct fb_info *info, if (par->dc_regs == NULL) return ret; - par->df_regs = ioremap(pci_resource_start(dev, 3), + par->vp_regs = ioremap(pci_resource_start(dev, 3), pci_resource_len(dev, 3)); - if (par->df_regs == NULL) + if (par->vp_regs == NULL) return ret; - writel(DC_UNLOCK_CODE, par->dc_regs + DC_UNLOCK); - - writel(info->fix.smem_start & 0xFF000000, - par->dc_regs + DC_PHY_MEM_OFFSET); - - writel(0, par->dc_regs + DC_UNLOCK); + write_dc(par, DC_UNLOCK, DC_UNLOCK_UNLOCK); + write_dc(par, DC_GLIU0_MEM_OFFSET, info->fix.smem_start & 0xFF000000); + write_dc(par, DC_UNLOCK, DC_UNLOCK_LOCK); dev_info(&dev->dev, "%d KB of video memory at 0x%lx\n", info->fix.smem_len / 1024, info->fix.smem_start); @@ -431,6 +459,45 @@ static struct fb_info * __init lxfb_init_fbinfo(struct device *dev) return info; } +#ifdef CONFIG_PM +static int lxfb_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct fb_info *info = pci_get_drvdata(pdev); + + if (state.event == PM_EVENT_SUSPEND) { + acquire_console_sem(); + lx_powerdown(info); + fb_set_suspend(info, 1); + release_console_sem(); + } + + /* there's no point in setting PCI states; we emulate PCI, so + * we don't end up getting power savings anyways */ + + return 0; +} + +static int lxfb_resume(struct pci_dev *pdev) +{ + struct fb_info *info = pci_get_drvdata(pdev); + int ret; + + acquire_console_sem(); + ret = lx_powerup(info); + if (ret) { + printk(KERN_ERR "lxfb: power up failed!\n"); + return ret; + } + + fb_set_suspend(info, 0); + release_console_sem(); + return 0; +} +#else +#define lxfb_suspend NULL +#define lxfb_resume NULL +#endif + static int __init lxfb_probe(struct pci_dev *pdev, const struct pci_device_id *id) { @@ -439,7 +506,7 @@ static int __init lxfb_probe(struct pci_dev *pdev, int ret; struct fb_videomode *modedb_ptr; - int modedb_size; + unsigned int modedb_size; info = lxfb_init_fbinfo(&pdev->dev); @@ -464,9 +531,7 @@ static int __init lxfb_probe(struct pci_dev *pdev, /* Set up the mode database */ - modedb_ptr = (struct fb_videomode *) geode_modedb; - modedb_size = ARRAY_SIZE(geode_modedb); - + get_modedb(&modedb_ptr, &modedb_size); ret = fb_find_mode(&info->var, info, mode_option, modedb_ptr, modedb_size, NULL, 16); @@ -487,6 +552,8 @@ static int __init lxfb_probe(struct pci_dev *pdev, lxfb_check_var(&info->var, info); lxfb_set_par(info); + pm_set_vt_switch(vt_switch); + if (register_framebuffer(info) < 0) { ret = -EINVAL; goto err; @@ -510,8 +577,8 @@ err: iounmap(par->dc_regs); pci_release_region(pdev, 2); } - if (par->df_regs) { - iounmap(par->df_regs); + if (par->vp_regs) { + iounmap(par->vp_regs); pci_release_region(pdev, 3); } @@ -537,7 +604,7 @@ static void lxfb_remove(struct pci_dev *pdev) iounmap(par->dc_regs); pci_release_region(pdev, 2); - iounmap(par->df_regs); + iounmap(par->vp_regs); pci_release_region(pdev, 3); pci_set_drvdata(pdev, NULL); @@ -556,6 +623,8 @@ static struct pci_driver lxfb_driver = { .id_table = lxfb_id_table, .probe = lxfb_probe, .remove = lxfb_remove, + .suspend = lxfb_suspend, + .resume = lxfb_resume, }; #ifndef MODULE @@ -570,9 +639,7 @@ static int __init lxfb_setup(char *options) if (!*opt) continue; - if (!strncmp(opt, "fbsize:", 7)) - fbsize = simple_strtoul(opt+7, NULL, 0); - else if (!strcmp(opt, "noclear")) + if (!strcmp(opt, "noclear")) noclear = 1; else if (!strcmp(opt, "nopanel")) nopanel = 1; @@ -609,8 +676,11 @@ module_exit(lxfb_cleanup); module_param(mode_option, charp, 0); MODULE_PARM_DESC(mode_option, "video mode (<x>x<y>[-<bpp>][@<refr>])"); -module_param(fbsize, int, 0); -MODULE_PARM_DESC(fbsize, "video memory size"); +module_param(vram, int, 0); +MODULE_PARM_DESC(vram, "video memory size"); + +module_param(vt_switch, int, 0); +MODULE_PARM_DESC(vt_switch, "enable VT switch during suspend/resume"); MODULE_DESCRIPTION("Framebuffer driver for the AMD Geode LX"); MODULE_LICENSE("GPL"); diff --git a/drivers/video/geode/lxfb_ops.c b/drivers/video/geode/lxfb_ops.c index 4fbc99be96e..cd9d4cc2695 100644 --- a/drivers/video/geode/lxfb_ops.c +++ b/drivers/video/geode/lxfb_ops.c @@ -13,6 +13,7 @@ #include <linux/fb.h> #include <linux/uaccess.h> #include <linux/delay.h> +#include <asm/geode.h> #include "lxfb.h" @@ -34,35 +35,85 @@ static const struct { unsigned int pllval; unsigned int freq; } pll_table[] = { - { 0x000031AC, 24923 }, - { 0x0000215D, 25175 }, - { 0x00001087, 27000 }, - { 0x0000216C, 28322 }, - { 0x0000218D, 28560 }, - { 0x000010C9, 31200 }, - { 0x00003147, 31500 }, - { 0x000010A7, 33032 }, - { 0x00002159, 35112 }, - { 0x00004249, 35500 }, - { 0x00000057, 36000 }, - { 0x0000219A, 37889 }, - { 0x00002158, 39168 }, - { 0x00000045, 40000 }, - { 0x00000089, 43163 }, - { 0x000010E7, 44900 }, - { 0x00002136, 45720 }, - { 0x00003207, 49500 }, - { 0x00002187, 50000 }, - { 0x00004286, 56250 }, - { 0x000010E5, 60065 }, - { 0x00004214, 65000 }, - { 0x00001105, 68179 }, - { 0x000031E4, 74250 }, - { 0x00003183, 75000 }, - { 0x00004284, 78750 }, - { 0x00001104, 81600 }, - { 0x00006363, 94500 }, - { 0x00005303, 97520 }, + { 0x000131AC, 6231 }, + { 0x0001215D, 6294 }, + { 0x00011087, 6750 }, + { 0x0001216C, 7081 }, + { 0x0001218D, 7140 }, + { 0x000110C9, 7800 }, + { 0x00013147, 7875 }, + { 0x000110A7, 8258 }, + { 0x00012159, 8778 }, + { 0x00014249, 8875 }, + { 0x00010057, 9000 }, + { 0x0001219A, 9472 }, + { 0x00012158, 9792 }, + { 0x00010045, 10000 }, + { 0x00010089, 10791 }, + { 0x000110E7, 11225 }, + { 0x00012136, 11430 }, + { 0x00013207, 12375 }, + { 0x00012187, 12500 }, + { 0x00014286, 14063 }, + { 0x000110E5, 15016 }, + { 0x00014214, 16250 }, + { 0x00011105, 17045 }, + { 0x000131E4, 18563 }, + { 0x00013183, 18750 }, + { 0x00014284, 19688 }, + { 0x00011104, 20400 }, + { 0x00016363, 23625 }, + { 0x00015303, 24380 }, + { 0x000031AC, 24923 }, + { 0x0000215D, 25175 }, + { 0x00001087, 27000 }, + { 0x0000216C, 28322 }, + { 0x0000218D, 28560 }, + { 0x00010041, 29913 }, + { 0x000010C9, 31200 }, + { 0x00003147, 31500 }, + { 0x000141A1, 32400 }, + { 0x000010A7, 33032 }, + { 0x00012182, 33375 }, + { 0x000141B1, 33750 }, + { 0x00002159, 35112 }, + { 0x00004249, 35500 }, + { 0x00000057, 36000 }, + { 0x000141E1, 37125 }, + { 0x0000219A, 37889 }, + { 0x00002158, 39168 }, + { 0x00000045, 40000 }, + { 0x000131A1, 40500 }, + { 0x00010061, 42301 }, + { 0x00000089, 43163 }, + { 0x00012151, 43875 }, + { 0x000010E7, 44900 }, + { 0x00002136, 45720 }, + { 0x000152E1, 47250 }, + { 0x00010071, 48000 }, + { 0x00003207, 49500 }, + { 0x00002187, 50000 }, + { 0x00014291, 50625 }, + { 0x00011101, 51188 }, + { 0x00017481, 54563 }, + { 0x00004286, 56250 }, + { 0x00014170, 57375 }, + { 0x00016210, 58500 }, + { 0x000010E5, 60065 }, + { 0x00013140, 62796 }, + { 0x00004214, 65000 }, + { 0x00016250, 65250 }, + { 0x00001105, 68179 }, + { 0x000141C0, 69600 }, + { 0x00015220, 70160 }, + { 0x00010050, 72000 }, + { 0x000031E4, 74250 }, + { 0x00003183, 75000 }, + { 0x00004284, 78750 }, + { 0x00012130, 80052 }, + { 0x00001104, 81600 }, + { 0x00006363, 94500 }, + { 0x00005303, 97520 }, { 0x00002183, 100187 }, { 0x00002122, 101420 }, { 0x00001081, 108000 }, @@ -101,16 +152,16 @@ static void lx_set_dotpll(u32 pllval) u32 dotpll_lo, dotpll_hi; int i; - rdmsr(MSR_LX_GLCP_DOTPLL, dotpll_lo, dotpll_hi); + rdmsr(MSR_GLCP_DOTPLL, dotpll_lo, dotpll_hi); - if ((dotpll_lo & GLCP_DOTPLL_LOCK) && (dotpll_hi == pllval)) + if ((dotpll_lo & MSR_GLCP_DOTPLL_LOCK) && (dotpll_hi == pllval)) return; dotpll_hi = pllval; - dotpll_lo &= ~(GLCP_DOTPLL_BYPASS | GLCP_DOTPLL_HALFPIX); - dotpll_lo |= GLCP_DOTPLL_RESET; + dotpll_lo &= ~(MSR_GLCP_DOTPLL_BYPASS | MSR_GLCP_DOTPLL_HALFPIX); + dotpll_lo |= MSR_GLCP_DOTPLL_DOTRESET; - wrmsr(MSR_LX_GLCP_DOTPLL, dotpll_lo, dotpll_hi); + wrmsr(MSR_GLCP_DOTPLL, dotpll_lo, dotpll_hi); /* Wait 100us for the PLL to lock */ @@ -119,15 +170,15 @@ static void lx_set_dotpll(u32 pllval) /* Now, loop for the lock bit */ for (i = 0; i < 1000; i++) { - rdmsr(MSR_LX_GLCP_DOTPLL, dotpll_lo, dotpll_hi); - if (dotpll_lo & GLCP_DOTPLL_LOCK) + rdmsr(MSR_GLCP_DOTPLL, dotpll_lo, dotpll_hi); + if (dotpll_lo & MSR_GLCP_DOTPLL_LOCK) break; } /* Clear the reset bit */ - dotpll_lo &= ~GLCP_DOTPLL_RESET; - wrmsr(MSR_LX_GLCP_DOTPLL, dotpll_lo, dotpll_hi); + dotpll_lo &= ~MSR_GLCP_DOTPLL_DOTRESET; + wrmsr(MSR_GLCP_DOTPLL, dotpll_lo, dotpll_hi); } /* Set the clock based on the frequency specified by the current mode */ @@ -137,7 +188,7 @@ static void lx_set_clock(struct fb_info *info) unsigned int diff, min, best = 0; unsigned int freq, i; - freq = (unsigned int) (0x3b9aca00 / info->var.pixclock); + freq = (unsigned int) (1000000000 / info->var.pixclock); min = abs(pll_table[0].freq - freq); @@ -149,7 +200,7 @@ static void lx_set_clock(struct fb_info *info) } } - lx_set_dotpll(pll_table[best].pllval & 0x7FFF); + lx_set_dotpll(pll_table[best].pllval & 0x00017FFF); } static void lx_graphics_disable(struct fb_info *info) @@ -159,63 +210,62 @@ static void lx_graphics_disable(struct fb_info *info) /* Note: This assumes that the video is in a quitet state */ - writel(0, par->df_regs + DF_ALPHA_CONTROL_1); - writel(0, par->df_regs + DF_ALPHA_CONTROL_1 + 32); - writel(0, par->df_regs + DF_ALPHA_CONTROL_1 + 64); + write_vp(par, VP_A1T, 0); + write_vp(par, VP_A2T, 0); + write_vp(par, VP_A3T, 0); /* Turn off the VGA and video enable */ - val = readl (par->dc_regs + DC_GENERAL_CFG) & - ~(DC_GCFG_VGAE | DC_GCFG_VIDE); + val = read_dc(par, DC_GENERAL_CFG) & ~(DC_GENERAL_CFG_VGAE | + DC_GENERAL_CFG_VIDE); - writel(val, par->dc_regs + DC_GENERAL_CFG); + write_dc(par, DC_GENERAL_CFG, val); - val = readl(par->df_regs + DF_VIDEO_CFG) & ~DF_VCFG_VID_EN; - writel(val, par->df_regs + DF_VIDEO_CFG); + val = read_vp(par, VP_VCFG) & ~VP_VCFG_VID_EN; + write_vp(par, VP_VCFG, val); - writel( DC_IRQ_MASK | DC_VSYNC_IRQ_MASK | - DC_IRQ_STATUS | DC_VSYNC_IRQ_STATUS, - par->dc_regs + DC_IRQ); + write_dc(par, DC_IRQ, DC_IRQ_MASK | DC_IRQ_VIP_VSYNC_LOSS_IRQ_MASK | + DC_IRQ_STATUS | DC_IRQ_VIP_VSYNC_IRQ_STATUS); - val = readl(par->dc_regs + DC_GENLCK_CTRL) & ~DC_GENLCK_ENABLE; - writel(val, par->dc_regs + DC_GENLCK_CTRL); + val = read_dc(par, DC_GENLK_CTL) & ~DC_GENLK_CTL_GENLK_EN; + write_dc(par, DC_GENLK_CTL, val); - val = readl(par->dc_regs + DC_COLOR_KEY) & ~DC_CLR_KEY_ENABLE; - writel(val & ~DC_CLR_KEY_ENABLE, par->dc_regs + DC_COLOR_KEY); + val = read_dc(par, DC_CLR_KEY); + write_dc(par, DC_CLR_KEY, val & ~DC_CLR_KEY_CLR_KEY_EN); - /* We don't actually blank the panel, due to the long latency - involved with bringing it back */ + /* turn off the panel */ + write_fp(par, FP_PM, read_fp(par, FP_PM) & ~FP_PM_P); - val = readl(par->df_regs + DF_MISC) | DF_MISC_DAC_PWRDN; - writel(val, par->df_regs + DF_MISC); + val = read_vp(par, VP_MISC) | VP_MISC_DACPWRDN; + write_vp(par, VP_MISC, val); /* Turn off the display */ - val = readl(par->df_regs + DF_DISPLAY_CFG); - writel(val & ~(DF_DCFG_CRT_EN | DF_DCFG_HSYNC_EN | DF_DCFG_VSYNC_EN | - DF_DCFG_DAC_BL_EN), par->df_regs + DF_DISPLAY_CFG); + val = read_vp(par, VP_DCFG); + write_vp(par, VP_DCFG, val & ~(VP_DCFG_CRT_EN | VP_DCFG_HSYNC_EN | + VP_DCFG_VSYNC_EN | VP_DCFG_DAC_BL_EN)); - gcfg = readl(par->dc_regs + DC_GENERAL_CFG); - gcfg &= ~(DC_GCFG_CMPE | DC_GCFG_DECE); - writel(gcfg, par->dc_regs + DC_GENERAL_CFG); + gcfg = read_dc(par, DC_GENERAL_CFG); + gcfg &= ~(DC_GENERAL_CFG_CMPE | DC_GENERAL_CFG_DECE); + write_dc(par, DC_GENERAL_CFG, gcfg); /* Turn off the TGEN */ - val = readl(par->dc_regs + DC_DISPLAY_CFG); - val &= ~DC_DCFG_TGEN; - writel(val, par->dc_regs + DC_DISPLAY_CFG); + val = read_dc(par, DC_DISPLAY_CFG); + val &= ~DC_DISPLAY_CFG_TGEN; + write_dc(par, DC_DISPLAY_CFG, val); /* Wait 1000 usecs to ensure that the TGEN is clear */ udelay(1000); /* Turn off the FIFO loader */ - gcfg &= ~DC_GCFG_DFLE; - writel(gcfg, par->dc_regs + DC_GENERAL_CFG); + gcfg &= ~DC_GENERAL_CFG_DFLE; + write_dc(par, DC_GENERAL_CFG, gcfg); /* Lastly, wait for the GP to go idle */ do { - val = readl(par->gp_regs + GP_BLT_STATUS); - } while ((val & GP_BS_BLT_BUSY) || !(val & GP_BS_CB_EMPTY)); + val = read_gp(par, GP_BLT_STATUS); + } while ((val & GP_BLT_STATUS_PB) || !(val & GP_BLT_STATUS_CE)); } static void lx_graphics_enable(struct fb_info *info) @@ -224,80 +274,85 @@ static void lx_graphics_enable(struct fb_info *info) u32 temp, config; /* Set the video request register */ - writel(0, par->df_regs + DF_VIDEO_REQUEST); + write_vp(par, VP_VRR, 0); /* Set up the polarities */ - config = readl(par->df_regs + DF_DISPLAY_CFG); + config = read_vp(par, VP_DCFG); - config &= ~(DF_DCFG_CRT_SYNC_SKW_MASK | DF_DCFG_PWR_SEQ_DLY_MASK | - DF_DCFG_CRT_HSYNC_POL | DF_DCFG_CRT_VSYNC_POL); + config &= ~(VP_DCFG_CRT_SYNC_SKW | VP_DCFG_PWR_SEQ_DELAY | + VP_DCFG_CRT_HSYNC_POL | VP_DCFG_CRT_VSYNC_POL); - config |= (DF_DCFG_CRT_SYNC_SKW_INIT | DF_DCFG_PWR_SEQ_DLY_INIT | - DF_DCFG_GV_PAL_BYP); + config |= (VP_DCFG_CRT_SYNC_SKW_DEFAULT | VP_DCFG_PWR_SEQ_DELAY_DEFAULT + | VP_DCFG_GV_GAM); if (info->var.sync & FB_SYNC_HOR_HIGH_ACT) - config |= DF_DCFG_CRT_HSYNC_POL; + config |= VP_DCFG_CRT_HSYNC_POL; if (info->var.sync & FB_SYNC_VERT_HIGH_ACT) - config |= DF_DCFG_CRT_VSYNC_POL; + config |= VP_DCFG_CRT_VSYNC_POL; if (par->output & OUTPUT_PANEL) { u32 msrlo, msrhi; - writel(DF_DEFAULT_TFT_PMTIM1, - par->df_regs + DF_PANEL_TIM1); - writel(DF_DEFAULT_TFT_PMTIM2, - par->df_regs + DF_PANEL_TIM2); - writel(DF_DEFAULT_TFT_DITHCTL, - par->df_regs + DF_DITHER_CONTROL); + write_fp(par, FP_PT1, 0); + write_fp(par, FP_PT2, FP_PT2_SCRC); + write_fp(par, FP_DFC, FP_DFC_BC); - msrlo = DF_DEFAULT_TFT_PAD_SEL_LOW; - msrhi = DF_DEFAULT_TFT_PAD_SEL_HIGH; + msrlo = MSR_LX_MSR_PADSEL_TFT_SEL_LOW; + msrhi = MSR_LX_MSR_PADSEL_TFT_SEL_HIGH; - wrmsr(MSR_LX_DF_PADSEL, msrlo, msrhi); + wrmsr(MSR_LX_MSR_PADSEL, msrlo, msrhi); } if (par->output & OUTPUT_CRT) { - config |= DF_DCFG_CRT_EN | DF_DCFG_HSYNC_EN | - DF_DCFG_VSYNC_EN | DF_DCFG_DAC_BL_EN; + config |= VP_DCFG_CRT_EN | VP_DCFG_HSYNC_EN | + VP_DCFG_VSYNC_EN | VP_DCFG_DAC_BL_EN; } - writel(config, par->df_regs + DF_DISPLAY_CFG); + write_vp(par, VP_DCFG, config); /* Turn the CRT dacs back on */ if (par->output & OUTPUT_CRT) { - temp = readl(par->df_regs + DF_MISC); - temp &= ~(DF_MISC_DAC_PWRDN | DF_MISC_A_PWRDN); - writel(temp, par->df_regs + DF_MISC); + temp = read_vp(par, VP_MISC); + temp &= ~(VP_MISC_DACPWRDN | VP_MISC_APWRDN); + write_vp(par, VP_MISC, temp); } /* Turn the panel on (if it isn't already) */ - - if (par->output & OUTPUT_PANEL) { - temp = readl(par->df_regs + DF_FP_PM); - - if (!(temp & 0x09)) - writel(temp | DF_FP_PM_P, par->df_regs + DF_FP_PM); - } - - temp = readl(par->df_regs + DF_MISC); - temp = readl(par->df_regs + DF_DISPLAY_CFG); + if (par->output & OUTPUT_PANEL) + write_fp(par, FP_PM, read_fp(par, FP_PM) | FP_PM_P); } unsigned int lx_framebuffer_size(void) { unsigned int val; + if (!geode_has_vsa2()) { + uint32_t hi, lo; + + /* The number of pages is (PMAX - PMIN)+1 */ + rdmsr(MSR_GLIU_P2D_RO0, lo, hi); + + /* PMAX */ + val = ((hi & 0xff) << 12) | ((lo & 0xfff00000) >> 20); + /* PMIN */ + val -= (lo & 0x000fffff); + val += 1; + + /* The page size is 4k */ + return (val << 12); + } + /* The frame buffer size is reported by a VSM in VSA II */ /* Virtual Register Class = 0x02 */ /* VG_MEM_SIZE (1MB units) = 0x00 */ - outw(0xFC53, 0xAC1C); - outw(0x0200, 0xAC1C); + outw(VSA_VR_UNLOCK, VSA_VRC_INDEX); + outw(VSA_VR_MEM_SIZE, VSA_VRC_INDEX); - val = (unsigned int)(inw(0xAC1E)) & 0xFE; + val = (unsigned int)(inw(VSA_VRC_DATA)) & 0xFE; return (val << 20); } @@ -313,7 +368,7 @@ void lx_set_mode(struct fb_info *info) int vactive, vblankstart, vsyncstart, vsyncend, vblankend, vtotal; /* Unlock the DC registers */ - writel(DC_UNLOCK_CODE, par->dc_regs + DC_UNLOCK); + write_dc(par, DC_UNLOCK, DC_UNLOCK_UNLOCK); lx_graphics_disable(info); @@ -321,102 +376,104 @@ void lx_set_mode(struct fb_info *info) /* Set output mode */ - rdmsrl(MSR_LX_DF_GLCONFIG, msrval); - msrval &= ~DF_CONFIG_OUTPUT_MASK; + rdmsrl(MSR_LX_GLD_MSR_CONFIG, msrval); + msrval &= ~MSR_LX_GLD_MSR_CONFIG_FMT; if (par->output & OUTPUT_PANEL) { - msrval |= DF_OUTPUT_PANEL; + msrval |= MSR_LX_GLD_MSR_CONFIG_FMT_FP; if (par->output & OUTPUT_CRT) - msrval |= DF_SIMULTANEOUS_CRT_AND_FP; + msrval |= MSR_LX_GLD_MSR_CONFIG_FPC; else - msrval &= ~DF_SIMULTANEOUS_CRT_AND_FP; - } else { - msrval |= DF_OUTPUT_CRT; - } + msrval &= ~MSR_LX_GLD_MSR_CONFIG_FPC; + } else + msrval |= MSR_LX_GLD_MSR_CONFIG_FMT_CRT; - wrmsrl(MSR_LX_DF_GLCONFIG, msrval); + wrmsrl(MSR_LX_GLD_MSR_CONFIG, msrval); /* Clear the various buffers */ /* FIXME: Adjust for panning here */ - writel(0, par->dc_regs + DC_FB_START); - writel(0, par->dc_regs + DC_CB_START); - writel(0, par->dc_regs + DC_CURSOR_START); + write_dc(par, DC_FB_ST_OFFSET, 0); + write_dc(par, DC_CB_ST_OFFSET, 0); + write_dc(par, DC_CURS_ST_OFFSET, 0); /* FIXME: Add support for interlacing */ /* FIXME: Add support for scaling */ - val = readl(par->dc_regs + DC_GENLCK_CTRL); - val &= ~(DC_GC_ALPHA_FLICK_ENABLE | - DC_GC_FLICKER_FILTER_ENABLE | DC_GC_FLICKER_FILTER_MASK); + val = read_dc(par, DC_GENLK_CTL); + val &= ~(DC_GENLK_CTL_ALPHA_FLICK_EN | DC_GENLK_CTL_FLICK_EN | + DC_GENLK_CTL_FLICK_SEL_MASK); /* Default scaling params */ - writel((0x4000 << 16) | 0x4000, par->dc_regs + DC_GFX_SCALE); - writel(0, par->dc_regs + DC_IRQ_FILT_CTL); - writel(val, par->dc_regs + DC_GENLCK_CTRL); + write_dc(par, DC_GFX_SCALE, (0x4000 << 16) | 0x4000); + write_dc(par, DC_IRQ_FILT_CTL, 0); + write_dc(par, DC_GENLK_CTL, val); /* FIXME: Support compression */ if (info->fix.line_length > 4096) - dv = DC_DV_LINE_SIZE_8192; + dv = DC_DV_CTL_DV_LINE_SIZE_8K; else if (info->fix.line_length > 2048) - dv = DC_DV_LINE_SIZE_4096; + dv = DC_DV_CTL_DV_LINE_SIZE_4K; else if (info->fix.line_length > 1024) - dv = DC_DV_LINE_SIZE_2048; + dv = DC_DV_CTL_DV_LINE_SIZE_2K; else - dv = DC_DV_LINE_SIZE_1024; + dv = DC_DV_CTL_DV_LINE_SIZE_1K; max = info->fix.line_length * info->var.yres; max = (max + 0x3FF) & 0xFFFFFC00; - writel(max | DC_DV_TOP_ENABLE, par->dc_regs + DC_DV_TOP); + write_dc(par, DC_DV_TOP, max | DC_DV_TOP_DV_TOP_EN); - val = readl(par->dc_regs + DC_DV_CTL) & ~DC_DV_LINE_SIZE_MASK; - writel(val | dv, par->dc_regs + DC_DV_CTL); + val = read_dc(par, DC_DV_CTL) & ~DC_DV_CTL_DV_LINE_SIZE; + write_dc(par, DC_DV_CTL, val | dv); size = info->var.xres * (info->var.bits_per_pixel >> 3); - writel(info->fix.line_length >> 3, par->dc_regs + DC_GRAPHICS_PITCH); - writel((size + 7) >> 3, par->dc_regs + DC_LINE_SIZE); + write_dc(par, DC_GFX_PITCH, info->fix.line_length >> 3); + write_dc(par, DC_LINE_SIZE, (size + 7) >> 3); /* Set default watermark values */ - rdmsrl(MSR_LX_DC_SPARE, msrval); - - msrval &= ~(DC_SPARE_DISABLE_CFIFO_HGO | DC_SPARE_VFIFO_ARB_SELECT | - DC_SPARE_LOAD_WM_LPEN_MASK | DC_SPARE_WM_LPEN_OVRD | - DC_SPARE_DISABLE_INIT_VID_PRI | DC_SPARE_DISABLE_VFIFO_WM); - msrval |= DC_SPARE_DISABLE_VFIFO_WM | DC_SPARE_DISABLE_INIT_VID_PRI; - wrmsrl(MSR_LX_DC_SPARE, msrval); - - gcfg = DC_GCFG_DFLE; /* Display fifo enable */ - gcfg |= 0xB600; /* Set default priority */ - gcfg |= DC_GCFG_FDTY; /* Set the frame dirty mode */ - - dcfg = DC_DCFG_VDEN; /* Enable video data */ - dcfg |= DC_DCFG_GDEN; /* Enable graphics */ - dcfg |= DC_DCFG_TGEN; /* Turn on the timing generator */ - dcfg |= DC_DCFG_TRUP; /* Update timings immediately */ - dcfg |= DC_DCFG_PALB; /* Palette bypass in > 8 bpp modes */ - dcfg |= DC_DCFG_VISL; - dcfg |= DC_DCFG_DCEN; /* Always center the display */ + rdmsrl(MSR_LX_SPARE_MSR, msrval); + + msrval &= ~(MSR_LX_SPARE_MSR_DIS_CFIFO_HGO + | MSR_LX_SPARE_MSR_VFIFO_ARB_SEL + | MSR_LX_SPARE_MSR_LOAD_WM_LPEN_M + | MSR_LX_SPARE_MSR_WM_LPEN_OVRD); + msrval |= MSR_LX_SPARE_MSR_DIS_VIFO_WM | + MSR_LX_SPARE_MSR_DIS_INIT_V_PRI; + wrmsrl(MSR_LX_SPARE_MSR, msrval); + + gcfg = DC_GENERAL_CFG_DFLE; /* Display fifo enable */ + gcfg |= (0x6 << DC_GENERAL_CFG_DFHPSL_SHIFT) | /* default priority */ + (0xb << DC_GENERAL_CFG_DFHPEL_SHIFT); + gcfg |= DC_GENERAL_CFG_FDTY; /* Set the frame dirty mode */ + + dcfg = DC_DISPLAY_CFG_VDEN; /* Enable video data */ + dcfg |= DC_DISPLAY_CFG_GDEN; /* Enable graphics */ + dcfg |= DC_DISPLAY_CFG_TGEN; /* Turn on the timing generator */ + dcfg |= DC_DISPLAY_CFG_TRUP; /* Update timings immediately */ + dcfg |= DC_DISPLAY_CFG_PALB; /* Palette bypass in > 8 bpp modes */ + dcfg |= DC_DISPLAY_CFG_VISL; + dcfg |= DC_DISPLAY_CFG_DCEN; /* Always center the display */ /* Set the current BPP mode */ switch (info->var.bits_per_pixel) { case 8: - dcfg |= DC_DCFG_DISP_MODE_8BPP; + dcfg |= DC_DISPLAY_CFG_DISP_MODE_8BPP; break; case 16: - dcfg |= DC_DCFG_DISP_MODE_16BPP | DC_DCFG_16BPP; + dcfg |= DC_DISPLAY_CFG_DISP_MODE_16BPP; break; case 32: case 24: - dcfg |= DC_DCFG_DISP_MODE_24BPP; + dcfg |= DC_DISPLAY_CFG_DISP_MODE_24BPP; break; } @@ -436,35 +493,31 @@ void lx_set_mode(struct fb_info *info) vblankend = vsyncend + info->var.upper_margin; vtotal = vblankend; - writel((hactive - 1) | ((htotal - 1) << 16), - par->dc_regs + DC_H_ACTIVE_TIMING); - writel((hblankstart - 1) | ((hblankend - 1) << 16), - par->dc_regs + DC_H_BLANK_TIMING); - writel((hsyncstart - 1) | ((hsyncend - 1) << 16), - par->dc_regs + DC_H_SYNC_TIMING); - - writel((vactive - 1) | ((vtotal - 1) << 16), - par->dc_regs + DC_V_ACTIVE_TIMING); + write_dc(par, DC_H_ACTIVE_TIMING, (hactive - 1) | ((htotal - 1) << 16)); + write_dc(par, DC_H_BLANK_TIMING, + (hblankstart - 1) | ((hblankend - 1) << 16)); + write_dc(par, DC_H_SYNC_TIMING, + (hsyncstart - 1) | ((hsyncend - 1) << 16)); - writel((vblankstart - 1) | ((vblankend - 1) << 16), - par->dc_regs + DC_V_BLANK_TIMING); + write_dc(par, DC_V_ACTIVE_TIMING, (vactive - 1) | ((vtotal - 1) << 16)); + write_dc(par, DC_V_BLANK_TIMING, + (vblankstart - 1) | ((vblankend - 1) << 16)); + write_dc(par, DC_V_SYNC_TIMING, + (vsyncstart - 1) | ((vsyncend - 1) << 16)); - writel((vsyncstart - 1) | ((vsyncend - 1) << 16), - par->dc_regs + DC_V_SYNC_TIMING); - - writel( (info->var.xres - 1) << 16 | (info->var.yres - 1), - par->dc_regs + DC_FB_ACTIVE); + write_dc(par, DC_FB_ACTIVE, + (info->var.xres - 1) << 16 | (info->var.yres - 1)); /* And re-enable the graphics output */ lx_graphics_enable(info); /* Write the two main configuration registers */ - writel(dcfg, par->dc_regs + DC_DISPLAY_CFG); - writel(0, par->dc_regs + DC_ARB_CFG); - writel(gcfg, par->dc_regs + DC_GENERAL_CFG); + write_dc(par, DC_DISPLAY_CFG, dcfg); + write_dc(par, DC_ARB_CFG, 0); + write_dc(par, DC_GENERAL_CFG, gcfg); /* Lock the DC registers */ - writel(0, par->dc_regs + DC_UNLOCK); + write_dc(par, DC_UNLOCK, DC_UNLOCK_LOCK); } void lx_set_palette_reg(struct fb_info *info, unsigned regno, @@ -479,58 +532,310 @@ void lx_set_palette_reg(struct fb_info *info, unsigned regno, val |= (green) & 0x00ff00; val |= (blue >> 8) & 0x0000ff; - writel(regno, par->dc_regs + DC_PAL_ADDRESS); - writel(val, par->dc_regs + DC_PAL_DATA); + write_dc(par, DC_PAL_ADDRESS, regno); + write_dc(par, DC_PAL_DATA, val); } int lx_blank_display(struct fb_info *info, int blank_mode) { struct lxfb_par *par = info->par; u32 dcfg, fp_pm; - int blank, hsync, vsync; + int blank, hsync, vsync, crt; /* CRT power saving modes. */ switch (blank_mode) { case FB_BLANK_UNBLANK: - blank = 0; hsync = 1; vsync = 1; + blank = 0; hsync = 1; vsync = 1; crt = 1; break; case FB_BLANK_NORMAL: - blank = 1; hsync = 1; vsync = 1; + blank = 1; hsync = 1; vsync = 1; crt = 1; break; case FB_BLANK_VSYNC_SUSPEND: - blank = 1; hsync = 1; vsync = 0; + blank = 1; hsync = 1; vsync = 0; crt = 1; break; case FB_BLANK_HSYNC_SUSPEND: - blank = 1; hsync = 0; vsync = 1; + blank = 1; hsync = 0; vsync = 1; crt = 1; break; case FB_BLANK_POWERDOWN: - blank = 1; hsync = 0; vsync = 0; + blank = 1; hsync = 0; vsync = 0; crt = 0; break; default: return -EINVAL; } - dcfg = readl(par->df_regs + DF_DISPLAY_CFG); - dcfg &= ~(DF_DCFG_DAC_BL_EN - | DF_DCFG_HSYNC_EN | DF_DCFG_VSYNC_EN); + dcfg = read_vp(par, VP_DCFG); + dcfg &= ~(VP_DCFG_DAC_BL_EN | VP_DCFG_HSYNC_EN | VP_DCFG_VSYNC_EN | + VP_DCFG_CRT_EN); if (!blank) - dcfg |= DF_DCFG_DAC_BL_EN; + dcfg |= VP_DCFG_DAC_BL_EN; if (hsync) - dcfg |= DF_DCFG_HSYNC_EN; + dcfg |= VP_DCFG_HSYNC_EN; if (vsync) - dcfg |= DF_DCFG_VSYNC_EN; - writel(dcfg, par->df_regs + DF_DISPLAY_CFG); + dcfg |= VP_DCFG_VSYNC_EN; + if (crt) + dcfg |= VP_DCFG_CRT_EN; + write_vp(par, VP_DCFG, dcfg); /* Power on/off flat panel */ if (par->output & OUTPUT_PANEL) { - fp_pm = readl(par->df_regs + DF_FP_PM); + fp_pm = read_fp(par, FP_PM); if (blank_mode == FB_BLANK_POWERDOWN) - fp_pm &= ~DF_FP_PM_P; + fp_pm &= ~FP_PM_P; else - fp_pm |= DF_FP_PM_P; - writel(fp_pm, par->df_regs + DF_FP_PM); + fp_pm |= FP_PM_P; + write_fp(par, FP_PM, fp_pm); } return 0; } + +#ifdef CONFIG_PM + +static void lx_save_regs(struct lxfb_par *par) +{ + uint32_t filt; + int i; + + /* wait for the BLT engine to stop being busy */ + do { + i = read_gp(par, GP_BLT_STATUS); + } while ((i & GP_BLT_STATUS_PB) || !(i & GP_BLT_STATUS_CE)); + + /* save MSRs */ + rdmsrl(MSR_LX_MSR_PADSEL, par->msr.padsel); + rdmsrl(MSR_GLCP_DOTPLL, par->msr.dotpll); + rdmsrl(MSR_LX_GLD_MSR_CONFIG, par->msr.dfglcfg); + rdmsrl(MSR_LX_SPARE_MSR, par->msr.dcspare); + + write_dc(par, DC_UNLOCK, DC_UNLOCK_UNLOCK); + + /* save registers */ + memcpy(par->gp, par->gp_regs, sizeof(par->gp)); + memcpy(par->dc, par->dc_regs, sizeof(par->dc)); + memcpy(par->vp, par->vp_regs, sizeof(par->vp)); + memcpy(par->fp, par->vp_regs + VP_FP_START, sizeof(par->fp)); + + /* save the palette */ + write_dc(par, DC_PAL_ADDRESS, 0); + for (i = 0; i < ARRAY_SIZE(par->pal); i++) + par->pal[i] = read_dc(par, DC_PAL_DATA); + + /* save the horizontal filter coefficients */ + filt = par->dc[DC_IRQ_FILT_CTL] | DC_IRQ_FILT_CTL_H_FILT_SEL; + for (i = 0; i < ARRAY_SIZE(par->hcoeff); i += 2) { + write_dc(par, DC_IRQ_FILT_CTL, (filt & 0xffffff00) | i); + par->hcoeff[i] = read_dc(par, DC_FILT_COEFF1); + par->hcoeff[i + 1] = read_dc(par, DC_FILT_COEFF2); + } + + /* save the vertical filter coefficients */ + filt &= ~DC_IRQ_FILT_CTL_H_FILT_SEL; + for (i = 0; i < ARRAY_SIZE(par->vcoeff); i++) { + write_dc(par, DC_IRQ_FILT_CTL, (filt & 0xffffff00) | i); + par->vcoeff[i] = read_dc(par, DC_FILT_COEFF1); + } + + /* save video coeff ram */ + memcpy(par->vp_coeff, par->vp_regs + VP_VCR, sizeof(par->vp_coeff)); +} + +static void lx_restore_gfx_proc(struct lxfb_par *par) +{ + int i; + + /* a bunch of registers require GP_RASTER_MODE to be set first */ + write_gp(par, GP_RASTER_MODE, par->gp[GP_RASTER_MODE]); + + for (i = 0; i < ARRAY_SIZE(par->gp); i++) { + switch (i) { + case GP_RASTER_MODE: + case GP_VECTOR_MODE: + case GP_BLT_MODE: + case GP_BLT_STATUS: + case GP_HST_SRC: + /* FIXME: restore LUT data */ + case GP_LUT_INDEX: + case GP_LUT_DATA: + /* don't restore these registers */ + break; + + default: + write_gp(par, i, par->gp[i]); + } + } +} + +static void lx_restore_display_ctlr(struct lxfb_par *par) +{ + uint32_t filt; + int i; + + wrmsrl(MSR_LX_SPARE_MSR, par->msr.dcspare); + + for (i = 0; i < ARRAY_SIZE(par->dc); i++) { + switch (i) { + case DC_UNLOCK: + /* unlock the DC; runs first */ + write_dc(par, DC_UNLOCK, DC_UNLOCK_UNLOCK); + break; + + case DC_GENERAL_CFG: + case DC_DISPLAY_CFG: + /* disable all while restoring */ + write_dc(par, i, 0); + break; + + case DC_DV_CTL: + /* set all ram to dirty */ + write_dc(par, i, par->dc[i] | DC_DV_CTL_CLEAR_DV_RAM); + + case DC_RSVD_1: + case DC_RSVD_2: + case DC_RSVD_3: + case DC_LINE_CNT: + case DC_PAL_ADDRESS: + case DC_PAL_DATA: + case DC_DFIFO_DIAG: + case DC_CFIFO_DIAG: + case DC_FILT_COEFF1: + case DC_FILT_COEFF2: + case DC_RSVD_4: + case DC_RSVD_5: + /* don't restore these registers */ + break; + + default: + write_dc(par, i, par->dc[i]); + } + } + + /* restore the palette */ + write_dc(par, DC_PAL_ADDRESS, 0); + for (i = 0; i < ARRAY_SIZE(par->pal); i++) + write_dc(par, DC_PAL_DATA, par->pal[i]); + + /* restore the horizontal filter coefficients */ + filt = par->dc[DC_IRQ_FILT_CTL] | DC_IRQ_FILT_CTL_H_FILT_SEL; + for (i = 0; i < ARRAY_SIZE(par->hcoeff); i += 2) { + write_dc(par, DC_IRQ_FILT_CTL, (filt & 0xffffff00) | i); + write_dc(par, DC_FILT_COEFF1, par->hcoeff[i]); + write_dc(par, DC_FILT_COEFF2, par->hcoeff[i + 1]); + } + + /* restore the vertical filter coefficients */ + filt &= ~DC_IRQ_FILT_CTL_H_FILT_SEL; + for (i = 0; i < ARRAY_SIZE(par->vcoeff); i++) { + write_dc(par, DC_IRQ_FILT_CTL, (filt & 0xffffff00) | i); + write_dc(par, DC_FILT_COEFF1, par->vcoeff[i]); + } +} + +static void lx_restore_video_proc(struct lxfb_par *par) +{ + int i; + + wrmsrl(MSR_LX_GLD_MSR_CONFIG, par->msr.dfglcfg); + wrmsrl(MSR_LX_MSR_PADSEL, par->msr.padsel); + + for (i = 0; i < ARRAY_SIZE(par->vp); i++) { + switch (i) { + case VP_VCFG: + case VP_DCFG: + case VP_PAR: + case VP_PDR: + case VP_CCS: + case VP_RSVD_0: + /* case VP_VDC: */ /* why should this not be restored? */ + case VP_RSVD_1: + case VP_CRC32: + /* don't restore these registers */ + break; + + default: + write_vp(par, i, par->vp[i]); + } + } + + /* restore video coeff ram */ + memcpy(par->vp_regs + VP_VCR, par->vp_coeff, sizeof(par->vp_coeff)); +} + +static void lx_restore_regs(struct lxfb_par *par) +{ + int i; + + lx_set_dotpll((u32) (par->msr.dotpll >> 32)); + lx_restore_gfx_proc(par); + lx_restore_display_ctlr(par); + lx_restore_video_proc(par); + + /* Flat Panel */ + for (i = 0; i < ARRAY_SIZE(par->fp); i++) { + switch (i) { + case FP_PM: + case FP_RSVD_0: + case FP_RSVD_1: + case FP_RSVD_2: + case FP_RSVD_3: + case FP_RSVD_4: + /* don't restore these registers */ + break; + + default: + write_fp(par, i, par->fp[i]); + } + } + + /* control the panel */ + if (par->fp[FP_PM] & FP_PM_P) { + /* power on the panel if not already power{ed,ing} on */ + if (!(read_fp(par, FP_PM) & + (FP_PM_PANEL_ON|FP_PM_PANEL_PWR_UP))) + write_fp(par, FP_PM, par->fp[FP_PM]); + } else { + /* power down the panel if not already power{ed,ing} down */ + if (!(read_fp(par, FP_PM) & + (FP_PM_PANEL_OFF|FP_PM_PANEL_PWR_DOWN))) + write_fp(par, FP_PM, par->fp[FP_PM]); + } + + /* turn everything on */ + write_vp(par, VP_VCFG, par->vp[VP_VCFG]); + write_vp(par, VP_DCFG, par->vp[VP_DCFG]); + write_dc(par, DC_DISPLAY_CFG, par->dc[DC_DISPLAY_CFG]); + /* do this last; it will enable the FIFO load */ + write_dc(par, DC_GENERAL_CFG, par->dc[DC_GENERAL_CFG]); + + /* lock the door behind us */ + write_dc(par, DC_UNLOCK, DC_UNLOCK_LOCK); +} + +int lx_powerdown(struct fb_info *info) +{ + struct lxfb_par *par = info->par; + + if (par->powered_down) + return 0; + + lx_save_regs(par); + lx_graphics_disable(info); + + par->powered_down = 1; + return 0; +} + +int lx_powerup(struct fb_info *info) +{ + struct lxfb_par *par = info->par; + + if (!par->powered_down) + return 0; + + lx_restore_regs(par); + + par->powered_down = 0; + return 0; +} + +#endif diff --git a/drivers/video/geode/suspend_gx.c b/drivers/video/geode/suspend_gx.c new file mode 100644 index 00000000000..9aff32ef8bb --- /dev/null +++ b/drivers/video/geode/suspend_gx.c @@ -0,0 +1,267 @@ +/* + * Copyright (C) 2007 Advanced Micro Devices, Inc. + * Copyright (C) 2008 Andres Salomon <dilinger@debian.org> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +#include <linux/fb.h> +#include <asm/io.h> +#include <asm/msr.h> +#include <asm/geode.h> +#include <asm/delay.h> + +#include "gxfb.h" + +#ifdef CONFIG_PM + +static void gx_save_regs(struct gxfb_par *par) +{ + int i; + + /* wait for the BLT engine to stop being busy */ + do { + i = read_gp(par, GP_BLT_STATUS); + } while (i & (GP_BLT_STATUS_BLT_PENDING | GP_BLT_STATUS_BLT_BUSY)); + + /* save MSRs */ + rdmsrl(MSR_GX_MSR_PADSEL, par->msr.padsel); + rdmsrl(MSR_GLCP_DOTPLL, par->msr.dotpll); + + write_dc(par, DC_UNLOCK, DC_UNLOCK_UNLOCK); + + /* save registers */ + memcpy(par->gp, par->gp_regs, sizeof(par->gp)); + memcpy(par->dc, par->dc_regs, sizeof(par->dc)); + memcpy(par->vp, par->vid_regs, sizeof(par->vp)); + memcpy(par->fp, par->vid_regs + VP_FP_START, sizeof(par->fp)); + + /* save the palette */ + write_dc(par, DC_PAL_ADDRESS, 0); + for (i = 0; i < ARRAY_SIZE(par->pal); i++) + par->pal[i] = read_dc(par, DC_PAL_DATA); +} + +static void gx_set_dotpll(uint32_t dotpll_hi) +{ + uint32_t dotpll_lo; + int i; + + rdmsrl(MSR_GLCP_DOTPLL, dotpll_lo); + dotpll_lo |= MSR_GLCP_DOTPLL_DOTRESET; + dotpll_lo &= ~MSR_GLCP_DOTPLL_BYPASS; + wrmsr(MSR_GLCP_DOTPLL, dotpll_lo, dotpll_hi); + + /* wait for the PLL to lock */ + for (i = 0; i < 200; i++) { + rdmsrl(MSR_GLCP_DOTPLL, dotpll_lo); + if (dotpll_lo & MSR_GLCP_DOTPLL_LOCK) + break; + udelay(1); + } + + /* PLL set, unlock */ + dotpll_lo &= ~MSR_GLCP_DOTPLL_DOTRESET; + wrmsr(MSR_GLCP_DOTPLL, dotpll_lo, dotpll_hi); +} + +static void gx_restore_gfx_proc(struct gxfb_par *par) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(par->gp); i++) { + switch (i) { + case GP_VECTOR_MODE: + case GP_BLT_MODE: + case GP_BLT_STATUS: + case GP_HST_SRC: + /* don't restore these registers */ + break; + default: + write_gp(par, i, par->gp[i]); + } + } +} + +static void gx_restore_display_ctlr(struct gxfb_par *par) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(par->dc); i++) { + switch (i) { + case DC_UNLOCK: + /* unlock the DC; runs first */ + write_dc(par, DC_UNLOCK, DC_UNLOCK_UNLOCK); + break; + + case DC_GENERAL_CFG: + /* write without the enables */ + write_dc(par, i, par->dc[i] & ~(DC_GENERAL_CFG_VIDE | + DC_GENERAL_CFG_ICNE | + DC_GENERAL_CFG_CURE | + DC_GENERAL_CFG_DFLE)); + break; + + case DC_DISPLAY_CFG: + /* write without the enables */ + write_dc(par, i, par->dc[i] & ~(DC_DISPLAY_CFG_VDEN | + DC_DISPLAY_CFG_GDEN | + DC_DISPLAY_CFG_TGEN)); + break; + + case DC_RSVD_0: + case DC_RSVD_1: + case DC_RSVD_2: + case DC_RSVD_3: + case DC_RSVD_4: + case DC_LINE_CNT: + case DC_PAL_ADDRESS: + case DC_PAL_DATA: + case DC_DFIFO_DIAG: + case DC_CFIFO_DIAG: + case DC_RSVD_5: + /* don't restore these registers */ + break; + default: + write_dc(par, i, par->dc[i]); + } + } + + /* restore the palette */ + write_dc(par, DC_PAL_ADDRESS, 0); + for (i = 0; i < ARRAY_SIZE(par->pal); i++) + write_dc(par, DC_PAL_DATA, par->pal[i]); +} + +static void gx_restore_video_proc(struct gxfb_par *par) +{ + int i; + + wrmsrl(MSR_GX_MSR_PADSEL, par->msr.padsel); + + for (i = 0; i < ARRAY_SIZE(par->vp); i++) { + switch (i) { + case VP_VCFG: + /* don't enable video yet */ + write_vp(par, i, par->vp[i] & ~VP_VCFG_VID_EN); + break; + + case VP_DCFG: + /* don't enable CRT yet */ + write_vp(par, i, par->vp[i] & + ~(VP_DCFG_DAC_BL_EN | VP_DCFG_VSYNC_EN | + VP_DCFG_HSYNC_EN | VP_DCFG_CRT_EN)); + break; + + case VP_GAR: + case VP_GDR: + case VP_RSVD_0: + case VP_RSVD_1: + case VP_RSVD_2: + case VP_RSVD_3: + case VP_CRC32: + case VP_AWT: + case VP_VTM: + /* don't restore these registers */ + break; + default: + write_vp(par, i, par->vp[i]); + } + } +} + +static void gx_restore_regs(struct gxfb_par *par) +{ + int i; + + gx_set_dotpll((uint32_t) (par->msr.dotpll >> 32)); + gx_restore_gfx_proc(par); + gx_restore_display_ctlr(par); + gx_restore_video_proc(par); + + /* Flat Panel */ + for (i = 0; i < ARRAY_SIZE(par->fp); i++) { + if (i != FP_PM && i != FP_RSVD_0) + write_fp(par, i, par->fp[i]); + } +} + +static void gx_disable_graphics(struct gxfb_par *par) +{ + /* shut down the engine */ + write_vp(par, VP_VCFG, par->vp[VP_VCFG] & ~VP_VCFG_VID_EN); + write_vp(par, VP_DCFG, par->vp[VP_DCFG] & ~(VP_DCFG_DAC_BL_EN | + VP_DCFG_VSYNC_EN | VP_DCFG_HSYNC_EN | VP_DCFG_CRT_EN)); + + /* turn off the flat panel */ + write_fp(par, FP_PM, par->fp[FP_PM] & ~FP_PM_P); + + + /* turn off display */ + write_dc(par, DC_UNLOCK, DC_UNLOCK_UNLOCK); + write_dc(par, DC_GENERAL_CFG, par->dc[DC_GENERAL_CFG] & + ~(DC_GENERAL_CFG_VIDE | DC_GENERAL_CFG_ICNE | + DC_GENERAL_CFG_CURE | DC_GENERAL_CFG_DFLE)); + write_dc(par, DC_DISPLAY_CFG, par->dc[DC_DISPLAY_CFG] & + ~(DC_DISPLAY_CFG_VDEN | DC_DISPLAY_CFG_GDEN | + DC_DISPLAY_CFG_TGEN)); + write_dc(par, DC_UNLOCK, DC_UNLOCK_LOCK); +} + +static void gx_enable_graphics(struct gxfb_par *par) +{ + uint32_t fp; + + fp = read_fp(par, FP_PM); + if (par->fp[FP_PM] & FP_PM_P) { + /* power on the panel if not already power{ed,ing} on */ + if (!(fp & (FP_PM_PANEL_ON|FP_PM_PANEL_PWR_UP))) + write_fp(par, FP_PM, par->fp[FP_PM]); + } else { + /* power down the panel if not already power{ed,ing} down */ + if (!(fp & (FP_PM_PANEL_OFF|FP_PM_PANEL_PWR_DOWN))) + write_fp(par, FP_PM, par->fp[FP_PM]); + } + + /* turn everything on */ + write_vp(par, VP_VCFG, par->vp[VP_VCFG]); + write_vp(par, VP_DCFG, par->vp[VP_DCFG]); + write_dc(par, DC_DISPLAY_CFG, par->dc[DC_DISPLAY_CFG]); + /* do this last; it will enable the FIFO load */ + write_dc(par, DC_GENERAL_CFG, par->dc[DC_GENERAL_CFG]); + + /* lock the door behind us */ + write_dc(par, DC_UNLOCK, DC_UNLOCK_LOCK); +} + +int gx_powerdown(struct fb_info *info) +{ + struct gxfb_par *par = info->par; + + if (par->powered_down) + return 0; + + gx_save_regs(par); + gx_disable_graphics(par); + + par->powered_down = 1; + return 0; +} + +int gx_powerup(struct fb_info *info) +{ + struct gxfb_par *par = info->par; + + if (!par->powered_down) + return 0; + + gx_restore_regs(par); + gx_enable_graphics(par); + + par->powered_down = 0; + return 0; +} + +#endif diff --git a/drivers/video/geode/video_gx.c b/drivers/video/geode/video_gx.c index febf09c6349..b8d52a8360d 100644 --- a/drivers/video/geode/video_gx.c +++ b/drivers/video/geode/video_gx.c @@ -16,9 +16,9 @@ #include <asm/io.h> #include <asm/delay.h> #include <asm/msr.h> +#include <asm/geode.h> -#include "geodefb.h" -#include "video_gx.h" +#include "gxfb.h" /* @@ -117,7 +117,7 @@ static const struct gx_pll_entry gx_pll_table_14MHz[] = { { 4357, 0, 0x0000057D }, /* 229.5000 */ }; -static void gx_set_dclk_frequency(struct fb_info *info) +void gx_set_dclk_frequency(struct fb_info *info) { const struct gx_pll_entry *pll_table; int pll_table_len; @@ -178,110 +178,116 @@ static void gx_set_dclk_frequency(struct fb_info *info) static void gx_configure_tft(struct fb_info *info) { - struct geodefb_par *par = info->par; + struct gxfb_par *par = info->par; unsigned long val; unsigned long fp; /* Set up the DF pad select MSR */ - rdmsrl(GX_VP_MSR_PAD_SELECT, val); - val &= ~GX_VP_PAD_SELECT_MASK; - val |= GX_VP_PAD_SELECT_TFT; - wrmsrl(GX_VP_MSR_PAD_SELECT, val); + rdmsrl(MSR_GX_MSR_PADSEL, val); + val &= ~MSR_GX_MSR_PADSEL_MASK; + val |= MSR_GX_MSR_PADSEL_TFT; + wrmsrl(MSR_GX_MSR_PADSEL, val); /* Turn off the panel */ - fp = readl(par->vid_regs + GX_FP_PM); - fp &= ~GX_FP_PM_P; - writel(fp, par->vid_regs + GX_FP_PM); + fp = read_fp(par, FP_PM); + fp &= ~FP_PM_P; + write_fp(par, FP_PM, fp); /* Set timing 1 */ - fp = readl(par->vid_regs + GX_FP_PT1); - fp &= GX_FP_PT1_VSIZE_MASK; - fp |= info->var.yres << GX_FP_PT1_VSIZE_SHIFT; - writel(fp, par->vid_regs + GX_FP_PT1); + fp = read_fp(par, FP_PT1); + fp &= FP_PT1_VSIZE_MASK; + fp |= info->var.yres << FP_PT1_VSIZE_SHIFT; + write_fp(par, FP_PT1, fp); /* Timing 2 */ /* Set bits that are always on for TFT */ fp = 0x0F100000; - /* Add sync polarity */ + /* Configure sync polarity */ if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT)) - fp |= GX_FP_PT2_VSP; + fp |= FP_PT2_VSP; if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT)) - fp |= GX_FP_PT2_HSP; + fp |= FP_PT2_HSP; - writel(fp, par->vid_regs + GX_FP_PT2); + write_fp(par, FP_PT2, fp); /* Set the dither control */ - writel(0x70, par->vid_regs + GX_FP_DFC); + write_fp(par, FP_DFC, FP_DFC_NFI); /* Enable the FP data and power (in case the BIOS didn't) */ - fp = readl(par->vid_regs + GX_DCFG); - fp |= GX_DCFG_FP_PWR_EN | GX_DCFG_FP_DATA_EN; - writel(fp, par->vid_regs + GX_DCFG); + fp = read_vp(par, VP_DCFG); + fp |= VP_DCFG_FP_PWR_EN | VP_DCFG_FP_DATA_EN; + write_vp(par, VP_DCFG, fp); /* Unblank the panel */ - fp = readl(par->vid_regs + GX_FP_PM); - fp |= GX_FP_PM_P; - writel(fp, par->vid_regs + GX_FP_PM); + fp = read_fp(par, FP_PM); + fp |= FP_PM_P; + write_fp(par, FP_PM, fp); } -static void gx_configure_display(struct fb_info *info) +void gx_configure_display(struct fb_info *info) { - struct geodefb_par *par = info->par; + struct gxfb_par *par = info->par; u32 dcfg, misc; - /* Set up the MISC register */ - - misc = readl(par->vid_regs + GX_MISC); - - /* Power up the DAC */ - misc &= ~(GX_MISC_A_PWRDN | GX_MISC_DAC_PWRDN); - - /* Disable gamma correction */ - misc |= GX_MISC_GAM_EN; - - writel(misc, par->vid_regs + GX_MISC); - /* Write the display configuration */ - dcfg = readl(par->vid_regs + GX_DCFG); + dcfg = read_vp(par, VP_DCFG); /* Disable hsync and vsync */ - dcfg &= ~(GX_DCFG_VSYNC_EN | GX_DCFG_HSYNC_EN); - writel(dcfg, par->vid_regs + GX_DCFG); + dcfg &= ~(VP_DCFG_VSYNC_EN | VP_DCFG_HSYNC_EN); + write_vp(par, VP_DCFG, dcfg); /* Clear bits from existing mode. */ - dcfg &= ~(GX_DCFG_CRT_SYNC_SKW_MASK - | GX_DCFG_CRT_HSYNC_POL | GX_DCFG_CRT_VSYNC_POL - | GX_DCFG_VSYNC_EN | GX_DCFG_HSYNC_EN); + dcfg &= ~(VP_DCFG_CRT_SYNC_SKW + | VP_DCFG_CRT_HSYNC_POL | VP_DCFG_CRT_VSYNC_POL + | VP_DCFG_VSYNC_EN | VP_DCFG_HSYNC_EN); /* Set default sync skew. */ - dcfg |= GX_DCFG_CRT_SYNC_SKW_DFLT; + dcfg |= VP_DCFG_CRT_SYNC_SKW_DEFAULT; /* Enable hsync and vsync. */ - dcfg |= GX_DCFG_HSYNC_EN | GX_DCFG_VSYNC_EN; + dcfg |= VP_DCFG_HSYNC_EN | VP_DCFG_VSYNC_EN; - /* Sync polarities. */ - if (info->var.sync & FB_SYNC_HOR_HIGH_ACT) - dcfg |= GX_DCFG_CRT_HSYNC_POL; - if (info->var.sync & FB_SYNC_VERT_HIGH_ACT) - dcfg |= GX_DCFG_CRT_VSYNC_POL; + misc = read_vp(par, VP_MISC); + + /* Disable gamma correction */ + misc |= VP_MISC_GAM_EN; + + if (par->enable_crt) { + + /* Power up the CRT DACs */ + misc &= ~(VP_MISC_APWRDN | VP_MISC_DACPWRDN); + write_vp(par, VP_MISC, misc); + + /* Only change the sync polarities if we are running + * in CRT mode. The FP polarities will be handled in + * gxfb_configure_tft */ + if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT)) + dcfg |= VP_DCFG_CRT_HSYNC_POL; + if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT)) + dcfg |= VP_DCFG_CRT_VSYNC_POL; + } else { + /* Power down the CRT DACs if in FP mode */ + misc |= (VP_MISC_APWRDN | VP_MISC_DACPWRDN); + write_vp(par, VP_MISC, misc); + } /* Enable the display logic */ /* Set up the DACS to blank normally */ - dcfg |= GX_DCFG_CRT_EN | GX_DCFG_DAC_BL_EN; + dcfg |= VP_DCFG_CRT_EN | VP_DCFG_DAC_BL_EN; /* Enable the external DAC VREF? */ - writel(dcfg, par->vid_regs + GX_DCFG); + write_vp(par, VP_DCFG, dcfg); /* Set up the flat panel (if it is enabled) */ @@ -289,59 +295,55 @@ static void gx_configure_display(struct fb_info *info) gx_configure_tft(info); } -static int gx_blank_display(struct fb_info *info, int blank_mode) +int gx_blank_display(struct fb_info *info, int blank_mode) { - struct geodefb_par *par = info->par; + struct gxfb_par *par = info->par; u32 dcfg, fp_pm; - int blank, hsync, vsync; + int blank, hsync, vsync, crt; /* CRT power saving modes. */ switch (blank_mode) { case FB_BLANK_UNBLANK: - blank = 0; hsync = 1; vsync = 1; + blank = 0; hsync = 1; vsync = 1; crt = 1; break; case FB_BLANK_NORMAL: - blank = 1; hsync = 1; vsync = 1; + blank = 1; hsync = 1; vsync = 1; crt = 1; break; case FB_BLANK_VSYNC_SUSPEND: - blank = 1; hsync = 1; vsync = 0; + blank = 1; hsync = 1; vsync = 0; crt = 1; break; case FB_BLANK_HSYNC_SUSPEND: - blank = 1; hsync = 0; vsync = 1; + blank = 1; hsync = 0; vsync = 1; crt = 1; break; case FB_BLANK_POWERDOWN: - blank = 1; hsync = 0; vsync = 0; + blank = 1; hsync = 0; vsync = 0; crt = 0; break; default: return -EINVAL; } - dcfg = readl(par->vid_regs + GX_DCFG); - dcfg &= ~(GX_DCFG_DAC_BL_EN - | GX_DCFG_HSYNC_EN | GX_DCFG_VSYNC_EN); + dcfg = read_vp(par, VP_DCFG); + dcfg &= ~(VP_DCFG_DAC_BL_EN | VP_DCFG_HSYNC_EN | VP_DCFG_VSYNC_EN | + VP_DCFG_CRT_EN); if (!blank) - dcfg |= GX_DCFG_DAC_BL_EN; + dcfg |= VP_DCFG_DAC_BL_EN; if (hsync) - dcfg |= GX_DCFG_HSYNC_EN; + dcfg |= VP_DCFG_HSYNC_EN; if (vsync) - dcfg |= GX_DCFG_VSYNC_EN; - writel(dcfg, par->vid_regs + GX_DCFG); + dcfg |= VP_DCFG_VSYNC_EN; + if (crt) + dcfg |= VP_DCFG_CRT_EN; + write_vp(par, VP_DCFG, dcfg); /* Power on/off flat panel. */ if (par->enable_crt == 0) { - fp_pm = readl(par->vid_regs + GX_FP_PM); + fp_pm = read_fp(par, FP_PM); if (blank_mode == FB_BLANK_POWERDOWN) - fp_pm &= ~GX_FP_PM_P; + fp_pm &= ~FP_PM_P; else - fp_pm |= GX_FP_PM_P; - writel(fp_pm, par->vid_regs + GX_FP_PM); + fp_pm |= FP_PM_P; + write_fp(par, FP_PM, fp_pm); } return 0; } - -struct geode_vid_ops gx_vid_ops = { - .set_dclk = gx_set_dclk_frequency, - .configure_display = gx_configure_display, - .blank_display = gx_blank_display, -}; diff --git a/drivers/video/geode/video_gx.h b/drivers/video/geode/video_gx.h deleted file mode 100644 index ce28d8f382d..00000000000 --- a/drivers/video/geode/video_gx.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Geode GX video device - * - * Copyright (C) 2006 Arcom Control Systems 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. - */ -#ifndef __VIDEO_GX_H__ -#define __VIDEO_GX_H__ - -extern struct geode_vid_ops gx_vid_ops; - -/* GX Flatpanel control MSR */ -#define GX_VP_MSR_PAD_SELECT 0xC0002011 -#define GX_VP_PAD_SELECT_MASK 0x3FFFFFFF -#define GX_VP_PAD_SELECT_TFT 0x1FFFFFFF - -/* Geode GX video processor registers */ - -#define GX_DCFG 0x0008 -# define GX_DCFG_CRT_EN 0x00000001 -# define GX_DCFG_HSYNC_EN 0x00000002 -# define GX_DCFG_VSYNC_EN 0x00000004 -# define GX_DCFG_DAC_BL_EN 0x00000008 -# define GX_DCFG_FP_PWR_EN 0x00000040 -# define GX_DCFG_FP_DATA_EN 0x00000080 -# define GX_DCFG_CRT_HSYNC_POL 0x00000100 -# define GX_DCFG_CRT_VSYNC_POL 0x00000200 -# define GX_DCFG_CRT_SYNC_SKW_MASK 0x0001C000 -# define GX_DCFG_CRT_SYNC_SKW_DFLT 0x00010000 -# define GX_DCFG_VG_CK 0x00100000 -# define GX_DCFG_GV_GAM 0x00200000 -# define GX_DCFG_DAC_VREF 0x04000000 - -/* Geode GX MISC video configuration */ - -#define GX_MISC 0x50 -#define GX_MISC_GAM_EN 0x00000001 -#define GX_MISC_DAC_PWRDN 0x00000400 -#define GX_MISC_A_PWRDN 0x00000800 - -/* Geode GX flat panel display control registers */ - -#define GX_FP_PT1 0x0400 -#define GX_FP_PT1_VSIZE_MASK 0x7FF0000 -#define GX_FP_PT1_VSIZE_SHIFT 16 - -#define GX_FP_PT2 0x408 -#define GX_FP_PT2_VSP (1 << 23) -#define GX_FP_PT2_HSP (1 << 22) - -#define GX_FP_PM 0x410 -# define GX_FP_PM_P 0x01000000 - -#define GX_FP_DFC 0x418 - -/* Geode GX clock control MSRs */ - -#define MSR_GLCP_SYS_RSTPLL 0x4c000014 -# define MSR_GLCP_SYS_RSTPLL_DOTPREDIV2 (0x0000000000000002ull) -# define MSR_GLCP_SYS_RSTPLL_DOTPREMULT2 (0x0000000000000004ull) -# define MSR_GLCP_SYS_RSTPLL_DOTPOSTDIV3 (0x0000000000000008ull) - -#define MSR_GLCP_DOTPLL 0x4c000015 -# define MSR_GLCP_DOTPLL_DOTRESET (0x0000000000000001ull) -# define MSR_GLCP_DOTPLL_BYPASS (0x0000000000008000ull) -# define MSR_GLCP_DOTPLL_LOCK (0x0000000002000000ull) - -#endif /* !__VIDEO_GX_H__ */ diff --git a/drivers/video/gxt4500.c b/drivers/video/gxt4500.c index e92337bef50..564557792be 100644 --- a/drivers/video/gxt4500.c +++ b/drivers/video/gxt4500.c @@ -238,7 +238,7 @@ static int calc_pll(int period_ps, struct gxt4500_par *par) for (pdiv1 = 1; pdiv1 <= 8; ++pdiv1) { for (pdiv2 = 1; pdiv2 <= pdiv1; ++pdiv2) { postdiv = pdiv1 * pdiv2; - pll_period = (period_ps + postdiv - 1) / postdiv; + pll_period = DIV_ROUND_UP(period_ps, postdiv); /* keep pll in range 350..600 MHz */ if (pll_period < 1666 || pll_period > 2857) continue; diff --git a/drivers/video/hecubafb.c b/drivers/video/hecubafb.c index 94e0df8a6f6..0b4bffbe67c 100644 --- a/drivers/video/hecubafb.c +++ b/drivers/video/hecubafb.c @@ -1,5 +1,5 @@ /* - * linux/drivers/video/hecubafb.c -- FB driver for Hecuba controller + * linux/drivers/video/hecubafb.c -- FB driver for Hecuba/Apollo controller * * Copyright (C) 2006, Jaya Kumar * This work was sponsored by CIS(M) Sdn Bhd @@ -17,18 +17,13 @@ * values. There are other commands that the display is capable of, * beyond the 5 used here but they are more complex. * - * This driver is written to be used with the Hecuba display controller - * board, and tested with the EInk 800x600 display in 1 bit mode. - * The interface between Hecuba and the host is TTL based GPIO. The - * GPIO requirements are 8 writable data lines and 6 lines for control. - * Only 4 of the controls are actually used here but 6 for future use. - * The driver requires the IO addresses for data and control GPIO at - * load time. It is also possible to use this display with a standard - * PC parallel port. + * This driver is written to be used with the Hecuba display architecture. + * The actual display chip is called Apollo and the interface electronics + * it needs is called Hecuba. * - * General notes: - * - User must set hecubafb_enable=1 to enable it - * - User must set dio_addr=0xIOADDR cio_addr=0xIOADDR c2io_addr=0xIOADDR + * It is intended to be architecture independent. A board specific driver + * must be used to perform all the physical IO interactions. An example + * is provided as n411.c * */ @@ -47,34 +42,12 @@ #include <linux/list.h> #include <linux/uaccess.h> -/* Apollo controller specific defines */ -#define APOLLO_START_NEW_IMG 0xA0 -#define APOLLO_STOP_IMG_DATA 0xA1 -#define APOLLO_DISPLAY_IMG 0xA2 -#define APOLLO_ERASE_DISPLAY 0xA3 -#define APOLLO_INIT_DISPLAY 0xA4 - -/* Hecuba interface specific defines */ -/* WUP is inverted, CD is inverted, DS is inverted */ -#define HCB_NWUP_BIT 0x01 -#define HCB_NDS_BIT 0x02 -#define HCB_RW_BIT 0x04 -#define HCB_NCD_BIT 0x08 -#define HCB_ACK_BIT 0x80 +#include <video/hecubafb.h> /* Display specific information */ #define DPY_W 600 #define DPY_H 800 -struct hecubafb_par { - unsigned long dio_addr; - unsigned long cio_addr; - unsigned long c2io_addr; - unsigned char ctl; - struct fb_info *info; - unsigned int irq; -}; - static struct fb_fix_screeninfo hecubafb_fix __devinitdata = { .id = "hecubafb", .type = FB_TYPE_PACKED_PIXELS, @@ -82,6 +55,7 @@ static struct fb_fix_screeninfo hecubafb_fix __devinitdata = { .xpanstep = 0, .ypanstep = 0, .ywrapstep = 0, + .line_length = DPY_W, .accel = FB_ACCEL_NONE, }; @@ -94,136 +68,51 @@ static struct fb_var_screeninfo hecubafb_var __devinitdata = { .nonstd = 1, }; -static unsigned long dio_addr; -static unsigned long cio_addr; -static unsigned long c2io_addr; -static unsigned long splashval; -static unsigned int nosplash; -static unsigned int hecubafb_enable; -static unsigned int irq; - -static DECLARE_WAIT_QUEUE_HEAD(hecubafb_waitq); - -static void hcb_set_ctl(struct hecubafb_par *par) -{ - outb(par->ctl, par->cio_addr); -} - -static unsigned char hcb_get_ctl(struct hecubafb_par *par) -{ - return inb(par->c2io_addr); -} - -static void hcb_set_data(struct hecubafb_par *par, unsigned char value) -{ - outb(value, par->dio_addr); -} - -static int __devinit apollo_init_control(struct hecubafb_par *par) -{ - unsigned char ctl; - /* for init, we want the following setup to be set: - WUP = lo - ACK = hi - DS = hi - RW = hi - CD = lo - */ - - /* write WUP to lo, DS to hi, RW to hi, CD to lo */ - par->ctl = HCB_NWUP_BIT | HCB_RW_BIT | HCB_NCD_BIT ; - par->ctl &= ~HCB_NDS_BIT; - hcb_set_ctl(par); - - /* check ACK is not lo */ - ctl = hcb_get_ctl(par); - if ((ctl & HCB_ACK_BIT)) { - printk(KERN_ERR "Fail because ACK is already low\n"); - return -ENXIO; - } - - return 0; -} - -static void hcb_wait_for_ack(struct hecubafb_par *par) -{ - - int timeout; - unsigned char ctl; - - timeout=500; - do { - ctl = hcb_get_ctl(par); - if ((ctl & HCB_ACK_BIT)) - return; - udelay(1); - } while (timeout--); - printk(KERN_ERR "timed out waiting for ack\n"); -} - -static void hcb_wait_for_ack_clear(struct hecubafb_par *par) -{ - - int timeout; - unsigned char ctl; - - timeout=500; - do { - ctl = hcb_get_ctl(par); - if (!(ctl & HCB_ACK_BIT)) - return; - udelay(1); - } while (timeout--); - printk(KERN_ERR "timed out waiting for clear\n"); -} +/* main hecubafb functions */ static void apollo_send_data(struct hecubafb_par *par, unsigned char data) { /* set data */ - hcb_set_data(par, data); + par->board->set_data(par, data); /* set DS low */ - par->ctl |= HCB_NDS_BIT; - hcb_set_ctl(par); + par->board->set_ctl(par, HCB_DS_BIT, 0); - hcb_wait_for_ack(par); + /* wait for ack */ + par->board->wait_for_ack(par, 0); /* set DS hi */ - par->ctl &= ~(HCB_NDS_BIT); - hcb_set_ctl(par); + par->board->set_ctl(par, HCB_DS_BIT, 1); - hcb_wait_for_ack_clear(par); + /* wait for ack to clear */ + par->board->wait_for_ack(par, 1); } static void apollo_send_command(struct hecubafb_par *par, unsigned char data) { /* command so set CD to high */ - par->ctl &= ~(HCB_NCD_BIT); - hcb_set_ctl(par); + par->board->set_ctl(par, HCB_CD_BIT, 1); /* actually strobe with command */ apollo_send_data(par, data); /* clear CD back to low */ - par->ctl |= (HCB_NCD_BIT); - hcb_set_ctl(par); + par->board->set_ctl(par, HCB_CD_BIT, 0); } -/* main hecubafb functions */ - static void hecubafb_dpy_update(struct hecubafb_par *par) { int i; unsigned char *buf = (unsigned char __force *)par->info->screen_base; - apollo_send_command(par, 0xA0); + apollo_send_command(par, APOLLO_START_NEW_IMG); for (i=0; i < (DPY_W*DPY_H/8); i++) { apollo_send_data(par, *(buf++)); } - apollo_send_command(par, 0xA1); - apollo_send_command(par, 0xA2); + apollo_send_command(par, APOLLO_STOP_IMG_DATA); + apollo_send_command(par, APOLLO_DISPLAY_IMG); } /* this is called back from the deferred io workqueue */ @@ -270,41 +159,43 @@ static void hecubafb_imageblit(struct fb_info *info, static ssize_t hecubafb_write(struct fb_info *info, const char __user *buf, size_t count, loff_t *ppos) { - unsigned long p; - int err=-EINVAL; - struct hecubafb_par *par; - unsigned int xres; - unsigned int fbmemlength; + struct hecubafb_par *par = info->par; + unsigned long p = *ppos; + void *dst; + int err = 0; + unsigned long total_size; - p = *ppos; - par = info->par; - xres = info->var.xres; - fbmemlength = (xres * info->var.yres)/8; + if (info->state != FBINFO_STATE_RUNNING) + return -EPERM; - if (p > fbmemlength) - return -ENOSPC; + total_size = info->fix.smem_len; - err = 0; - if ((count + p) > fbmemlength) { - count = fbmemlength - p; - err = -ENOSPC; + if (p > total_size) + return -EFBIG; + + if (count > total_size) { + err = -EFBIG; + count = total_size; } - if (count) { - char *base_addr; + if (count + p > total_size) { + if (!err) + err = -ENOSPC; - base_addr = (char __force *)info->screen_base; - count -= copy_from_user(base_addr + p, buf, count); - *ppos += count; - err = -EFAULT; + count = total_size - p; } - hecubafb_dpy_update(par); + dst = (void __force *) (info->screen_base + p); + + if (copy_from_user(dst, buf, count)) + err = -EFAULT; - if (count) - return count; + if (!err) + *ppos += count; - return err; + hecubafb_dpy_update(par); + + return (err) ? err : count; } static struct fb_ops hecubafb_ops = { @@ -324,11 +215,21 @@ static struct fb_deferred_io hecubafb_defio = { static int __devinit hecubafb_probe(struct platform_device *dev) { struct fb_info *info; + struct hecuba_board *board; int retval = -ENOMEM; int videomemorysize; unsigned char *videomemory; struct hecubafb_par *par; + /* pick up board specific routines */ + board = dev->dev.platform_data; + if (!board) + return -EINVAL; + + /* try to count device specific driver, if can't, platform recalls */ + if (!try_module_get(board->owner)) + return -ENODEV; + videomemorysize = (DPY_W*DPY_H)/8; if (!(videomemory = vmalloc(videomemorysize))) @@ -338,9 +239,9 @@ static int __devinit hecubafb_probe(struct platform_device *dev) info = framebuffer_alloc(sizeof(struct hecubafb_par), &dev->dev); if (!info) - goto err; + goto err_fballoc; - info->screen_base = (char __iomem *) videomemory; + info->screen_base = (char __force __iomem *)videomemory; info->fbops = &hecubafb_ops; info->var = hecubafb_var; @@ -348,14 +249,10 @@ static int __devinit hecubafb_probe(struct platform_device *dev) info->fix.smem_len = videomemorysize; par = info->par; par->info = info; + par->board = board; + par->send_command = apollo_send_command; + par->send_data = apollo_send_data; - if (!dio_addr || !cio_addr || !c2io_addr) { - printk(KERN_WARNING "no IO addresses supplied\n"); - goto err1; - } - par->dio_addr = dio_addr; - par->cio_addr = cio_addr; - par->c2io_addr = c2io_addr; info->flags = FBINFO_FLAG_DEFAULT; info->fbdefio = &hecubafb_defio; @@ -363,7 +260,7 @@ static int __devinit hecubafb_probe(struct platform_device *dev) retval = register_framebuffer(info); if (retval < 0) - goto err1; + goto err_fbreg; platform_set_drvdata(dev, info); printk(KERN_INFO @@ -371,25 +268,16 @@ static int __devinit hecubafb_probe(struct platform_device *dev) info->node, videomemorysize >> 10); /* this inits the dpy */ - apollo_init_control(par); - - apollo_send_command(par, APOLLO_INIT_DISPLAY); - apollo_send_data(par, 0x81); - - /* have to wait while display resets */ - udelay(1000); - - /* if we were told to splash the screen, we just clear it */ - if (!nosplash) { - apollo_send_command(par, APOLLO_ERASE_DISPLAY); - apollo_send_data(par, splashval); - } + retval = par->board->init(par); + if (retval < 0) + goto err_fbreg; return 0; -err1: +err_fbreg: framebuffer_release(info); -err: +err_fballoc: vfree(videomemory); + module_put(board->owner); return retval; } @@ -398,9 +286,13 @@ static int __devexit hecubafb_remove(struct platform_device *dev) struct fb_info *info = platform_get_drvdata(dev); if (info) { + struct hecubafb_par *par = info->par; fb_deferred_io_cleanup(info); unregister_framebuffer(info); vfree((void __force *)info->screen_base); + if (par->board->remove) + par->board->remove(par); + module_put(par->board->owner); framebuffer_release(info); } return 0; @@ -410,62 +302,24 @@ static struct platform_driver hecubafb_driver = { .probe = hecubafb_probe, .remove = hecubafb_remove, .driver = { + .owner = THIS_MODULE, .name = "hecubafb", }, }; -static struct platform_device *hecubafb_device; - static int __init hecubafb_init(void) { - int ret; - - if (!hecubafb_enable) { - printk(KERN_ERR "Use hecubafb_enable to enable the device\n"); - return -ENXIO; - } - - ret = platform_driver_register(&hecubafb_driver); - if (!ret) { - hecubafb_device = platform_device_alloc("hecubafb", 0); - if (hecubafb_device) - ret = platform_device_add(hecubafb_device); - else - ret = -ENOMEM; - - if (ret) { - platform_device_put(hecubafb_device); - platform_driver_unregister(&hecubafb_driver); - } - } - return ret; - + return platform_driver_register(&hecubafb_driver); } static void __exit hecubafb_exit(void) { - platform_device_unregister(hecubafb_device); platform_driver_unregister(&hecubafb_driver); } -module_param(nosplash, uint, 0); -MODULE_PARM_DESC(nosplash, "Disable doing the splash screen"); -module_param(hecubafb_enable, uint, 0); -MODULE_PARM_DESC(hecubafb_enable, "Enable communication with Hecuba board"); -module_param(dio_addr, ulong, 0); -MODULE_PARM_DESC(dio_addr, "IO address for data, eg: 0x480"); -module_param(cio_addr, ulong, 0); -MODULE_PARM_DESC(cio_addr, "IO address for control, eg: 0x400"); -module_param(c2io_addr, ulong, 0); -MODULE_PARM_DESC(c2io_addr, "IO address for secondary control, eg: 0x408"); -module_param(splashval, ulong, 0); -MODULE_PARM_DESC(splashval, "Splash pattern: 0x00 is black, 0x01 is white"); -module_param(irq, uint, 0); -MODULE_PARM_DESC(irq, "IRQ for the Hecuba board"); - module_init(hecubafb_init); module_exit(hecubafb_exit); -MODULE_DESCRIPTION("fbdev driver for Hecuba board"); +MODULE_DESCRIPTION("fbdev driver for Hecuba/Apollo controller"); MODULE_AUTHOR("Jaya Kumar"); MODULE_LICENSE("GPL"); diff --git a/drivers/video/imsttfb.c b/drivers/video/imsttfb.c index 3ab91bf2157..15d50b9906c 100644 --- a/drivers/video/imsttfb.c +++ b/drivers/video/imsttfb.c @@ -1151,8 +1151,10 @@ imsttfb_load_cursor_image(struct imstt_par *par, int width, int height, __u8 fgc par->cmap_regs[TVPCRDAT] = 0xff; eieio(); } par->cmap_regs[TVPCADRW] = 0x00; eieio(); - for (x = 0; x < 12; x++) - par->cmap_regs[TVPCDATA] = fgc; eieio(); + for (x = 0; x < 12; x++) { + par->cmap_regs[TVPCDATA] = fgc; + eieio(); + } } return 1; } @@ -1476,7 +1478,7 @@ imsttfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) dp = pci_device_to_OF_node(pdev); if(dp) - printk(KERN_INFO "%s: OF name %s\n",__FUNCTION__, dp->name); + printk(KERN_INFO "%s: OF name %s\n",__func__, dp->name); else printk(KERN_ERR "imsttfb: no OF node for pci device\n"); #endif /* CONFIG_PPC_OF */ diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c index 11609552a38..94e4d3ac1a0 100644 --- a/drivers/video/imxfb.c +++ b/drivers/video/imxfb.c @@ -415,7 +415,7 @@ static void imxfb_setup_gpio(struct imxfb_info *fbi) static int imxfb_suspend(struct platform_device *dev, pm_message_t state) { struct imxfb_info *fbi = platform_get_drvdata(dev); - pr_debug("%s\n",__FUNCTION__); + pr_debug("%s\n",__func__); imxfb_disable_controller(fbi); return 0; @@ -424,7 +424,7 @@ static int imxfb_suspend(struct platform_device *dev, pm_message_t state) static int imxfb_resume(struct platform_device *dev) { struct imxfb_info *fbi = platform_get_drvdata(dev); - pr_debug("%s\n",__FUNCTION__); + pr_debug("%s\n",__func__); imxfb_enable_controller(fbi); return 0; @@ -440,7 +440,7 @@ static int __init imxfb_init_fbinfo(struct device *dev) struct fb_info *info = dev_get_drvdata(dev); struct imxfb_info *fbi = info->par; - pr_debug("%s\n",__FUNCTION__); + pr_debug("%s\n",__func__); info->pseudo_palette = kmalloc( sizeof(u32) * 16, GFP_KERNEL); if (!info->pseudo_palette) diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h index 83679617794..3325fbd68ab 100644 --- a/drivers/video/intelfb/intelfb.h +++ b/drivers/video/intelfb/intelfb.h @@ -12,9 +12,9 @@ #endif /*** Version/name ***/ -#define INTELFB_VERSION "0.9.4" +#define INTELFB_VERSION "0.9.5" #define INTELFB_MODULE_NAME "intelfb" -#define SUPPORTED_CHIPSETS "830M/845G/852GM/855GM/865G/915G/915GM/945G/945GM" +#define SUPPORTED_CHIPSETS "830M/845G/852GM/855GM/865G/915G/915GM/945G/945GM/965G/965GM" /*** Debug/feature defines ***/ @@ -58,6 +58,8 @@ #define PCI_DEVICE_ID_INTEL_915GM 0x2592 #define PCI_DEVICE_ID_INTEL_945G 0x2772 #define PCI_DEVICE_ID_INTEL_945GM 0x27A2 +#define PCI_DEVICE_ID_INTEL_965G 0x29A2 +#define PCI_DEVICE_ID_INTEL_965GM 0x2A02 /* Size of MMIO region */ #define INTEL_REG_SIZE 0x80000 @@ -158,6 +160,8 @@ enum intel_chips { INTEL_915GM, INTEL_945G, INTEL_945GM, + INTEL_965G, + INTEL_965GM, }; struct intelfb_hwstate { @@ -358,7 +362,9 @@ struct intelfb_info { #define IS_I9XX(dinfo) (((dinfo)->chipset == INTEL_915G) || \ ((dinfo)->chipset == INTEL_915GM) || \ ((dinfo)->chipset == INTEL_945G) || \ - ((dinfo)->chipset==INTEL_945GM)) + ((dinfo)->chipset == INTEL_945GM) || \ + ((dinfo)->chipset == INTEL_965G) || \ + ((dinfo)->chipset == INTEL_965GM)) #ifndef FBIO_WAITFORVSYNC #define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32) diff --git a/drivers/video/intelfb/intelfb_i2c.c b/drivers/video/intelfb/intelfb_i2c.c index 94c08bb5acf..ca95f09d8b4 100644 --- a/drivers/video/intelfb/intelfb_i2c.c +++ b/drivers/video/intelfb/intelfb_i2c.c @@ -169,6 +169,8 @@ void intelfb_create_i2c_busses(struct intelfb_info *dinfo) /* has some LVDS + tv-out */ case INTEL_945G: case INTEL_945GM: + case INTEL_965G: + case INTEL_965GM: /* SDVO ports have a single control bus - 2 devices */ dinfo->output[i].type = INTELFB_OUTPUT_SDVO; intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].i2c_bus, diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c index 481d58f7535..e44303f9bc5 100644 --- a/drivers/video/intelfb/intelfbdrv.c +++ b/drivers/video/intelfb/intelfbdrv.c @@ -2,7 +2,7 @@ * intelfb * * Linux framebuffer driver for Intel(R) 830M/845G/852GM/855GM/865G/915G/915GM/ - * 945G/945GM integrated graphics chips. + * 945G/945GM/965G/965GM integrated graphics chips. * * Copyright © 2002, 2003 David Dawes <dawes@xfree86.org> * 2004 Sylvain Meyer @@ -99,6 +99,9 @@ * Add vram option to reserve more memory than stolen by BIOS * Fix intelfbhw_pan_display typo * Add __initdata annotations + * + * 04/2008 - Version 0.9.5 + * Add support for 965G/965GM. (Maik Broemme <mbroemme@plusserver.de>) */ #include <linux/module.h> @@ -180,6 +183,8 @@ static struct pci_device_id intelfb_pci_table[] __devinitdata = { { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_915GM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_915GM }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_945G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_945G }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_945GM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_945GM }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_965G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_965G }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_965GM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_965GM }, { 0, } }; @@ -549,7 +554,10 @@ static int __devinit intelfb_pci_register(struct pci_dev *pdev, if ((ent->device == PCI_DEVICE_ID_INTEL_915G) || (ent->device == PCI_DEVICE_ID_INTEL_915GM) || (ent->device == PCI_DEVICE_ID_INTEL_945G) || - (ent->device == PCI_DEVICE_ID_INTEL_945GM)) { + (ent->device == PCI_DEVICE_ID_INTEL_945GM) || + (ent->device == PCI_DEVICE_ID_INTEL_965G) || + (ent->device == PCI_DEVICE_ID_INTEL_965GM)) { + aperture_bar = 2; mmio_bar = 0; } diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c index fa1fff55356..8e6d6a4db0a 100644 --- a/drivers/video/intelfb/intelfbhw.c +++ b/drivers/video/intelfb/intelfbhw.c @@ -143,6 +143,18 @@ int intelfbhw_get_chipset(struct pci_dev *pdev, struct intelfb_info *dinfo) dinfo->mobile = 1; dinfo->pll_index = PLLS_I9xx; return 0; + case PCI_DEVICE_ID_INTEL_965G: + dinfo->name = "Intel(R) 965G"; + dinfo->chipset = INTEL_965G; + dinfo->mobile = 0; + dinfo->pll_index = PLLS_I9xx; + return 0; + case PCI_DEVICE_ID_INTEL_965GM: + dinfo->name = "Intel(R) 965GM"; + dinfo->chipset = INTEL_965GM; + dinfo->mobile = 1; + dinfo->pll_index = PLLS_I9xx; + return 0; default: return 1; } @@ -174,7 +186,9 @@ int intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size, case PCI_DEVICE_ID_INTEL_915GM: case PCI_DEVICE_ID_INTEL_945G: case PCI_DEVICE_ID_INTEL_945GM: - /* 915 and 945 chipsets support a 256MB aperture. + case PCI_DEVICE_ID_INTEL_965G: + case PCI_DEVICE_ID_INTEL_965GM: + /* 915, 945 and 965 chipsets support a 256MB aperture. Aperture size is determined by inspected the base address of the aperture. */ if (pci_resource_start(pdev, 2) & 0x08000000) diff --git a/drivers/video/leo.c b/drivers/video/leo.c index 45b9a5d55de..f3160fc2979 100644 --- a/drivers/video/leo.c +++ b/drivers/video/leo.c @@ -614,7 +614,7 @@ static int __devinit leo_probe(struct of_device *op, const struct of_device_id * dev_set_drvdata(&op->dev, info); - printk("%s: leo at %lx:%lx\n", + printk(KERN_INFO "%s: leo at %lx:%lx\n", dp->full_name, par->which_io, par->physbase); diff --git a/drivers/video/matrox/matroxfb_DAC1064.c b/drivers/video/matrox/matroxfb_DAC1064.c index c4b570b4a4d..0ce3b0a8979 100644 --- a/drivers/video/matrox/matroxfb_DAC1064.c +++ b/drivers/video/matrox/matroxfb_DAC1064.c @@ -37,7 +37,7 @@ static void DAC1064_calcclock(CPMINFO unsigned int freq, unsigned int fmax, unsi unsigned int fvco; unsigned int p; - DBG(__FUNCTION__) + DBG(__func__) /* only for devices older than G450 */ @@ -83,7 +83,7 @@ static const unsigned char MGA1064_DAC[] = { static void DAC1064_setpclk(WPMINFO unsigned long fout) { unsigned int m, n, p; - DBG(__FUNCTION__) + DBG(__func__) DAC1064_calcclock(PMINFO fout, ACCESS_FBINFO(max_pixel_clock), &m, &n, &p); ACCESS_FBINFO(hw).DACclk[0] = m; @@ -95,7 +95,7 @@ static void DAC1064_setmclk(WPMINFO int oscinfo, unsigned long fmem) { u_int32_t mx; struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); - DBG(__FUNCTION__) + DBG(__func__) if (ACCESS_FBINFO(devflags.noinit)) { /* read MCLK and give up... */ @@ -338,7 +338,7 @@ void DAC1064_global_restore(WPMINFO2) { static int DAC1064_init_1(WPMINFO struct my_timming* m) { struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); - DBG(__FUNCTION__) + DBG(__func__) memcpy(hw->DACreg, MGA1064_DAC, sizeof(MGA1064_DAC_regs)); switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) { @@ -374,7 +374,7 @@ static int DAC1064_init_1(WPMINFO struct my_timming* m) { static int DAC1064_init_2(WPMINFO struct my_timming* m) { struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); - DBG(__FUNCTION__) + DBG(__func__) if (ACCESS_FBINFO(fbcon).var.bits_per_pixel > 16) { /* 256 entries */ int i; @@ -418,7 +418,7 @@ static void DAC1064_restore_1(WPMINFO2) { CRITFLAGS - DBG(__FUNCTION__) + DBG(__func__) CRITBEGIN @@ -448,7 +448,7 @@ static void DAC1064_restore_2(WPMINFO2) { unsigned int i; #endif - DBG(__FUNCTION__) + DBG(__func__) #ifdef DEBUG dprintk(KERN_DEBUG "DAC1064regs "); @@ -521,7 +521,7 @@ static struct matrox_altout g450out = { static int MGA1064_init(WPMINFO struct my_timming* m) { struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); - DBG(__FUNCTION__) + DBG(__func__) if (DAC1064_init_1(PMINFO m)) return 1; if (matroxfb_vgaHWinit(PMINFO m)) return 1; @@ -543,7 +543,7 @@ static int MGA1064_init(WPMINFO struct my_timming* m) { static int MGAG100_init(WPMINFO struct my_timming* m) { struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); - DBG(__FUNCTION__) + DBG(__func__) if (DAC1064_init_1(PMINFO m)) return 1; hw->MXoptionReg &= ~0x2000; @@ -565,7 +565,7 @@ static int MGAG100_init(WPMINFO struct my_timming* m) { #ifdef CONFIG_FB_MATROX_MYSTIQUE static void MGA1064_ramdac_init(WPMINFO2) { - DBG(__FUNCTION__) + DBG(__func__) /* ACCESS_FBINFO(features.DAC1064.vco_freq_min) = 120000; */ ACCESS_FBINFO(features.pll.vco_freq_min) = 62000; @@ -594,7 +594,7 @@ static void MGAG100_progPixClock(CPMINFO int flags, int m, int n, int p) { int selClk; int clk; - DBG(__FUNCTION__) + DBG(__func__) outDAC1064(PMINFO M1064_XPIXCLKCTRL, inDAC1064(PMINFO M1064_XPIXCLKCTRL) | M1064_XPIXCLKCTRL_DIS | M1064_XPIXCLKCTRL_PLL_UP); @@ -636,7 +636,7 @@ static void MGAG100_progPixClock(CPMINFO int flags, int m, int n, int p) { static void MGAG100_setPixClock(CPMINFO int flags, int freq) { unsigned int m, n, p; - DBG(__FUNCTION__) + DBG(__func__) DAC1064_calcclock(PMINFO freq, ACCESS_FBINFO(max_pixel_clock), &m, &n, &p); MGAG100_progPixClock(PMINFO flags, m, n, p); @@ -650,7 +650,7 @@ static int MGA1064_preinit(WPMINFO2) { 2048, 0}; struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); - DBG(__FUNCTION__) + DBG(__func__) /* ACCESS_FBINFO(capable.cfb4) = 0; ... preinitialized by 0 */ ACCESS_FBINFO(capable.text) = 1; @@ -683,7 +683,7 @@ static int MGA1064_preinit(WPMINFO2) { static void MGA1064_reset(WPMINFO2) { - DBG(__FUNCTION__); + DBG(__func__); MGA1064_ramdac_init(PMINFO2); } @@ -819,7 +819,7 @@ static int MGAG100_preinit(WPMINFO2) { u_int32_t q; #endif - DBG(__FUNCTION__) + DBG(__func__) /* there are some instabilities if in_div > 19 && vco < 61000 */ if (ACCESS_FBINFO(devflags.g450dac)) { @@ -956,7 +956,7 @@ static void MGAG100_reset(WPMINFO2) { u_int8_t b; struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); - DBG(__FUNCTION__) + DBG(__func__) { #ifdef G100_BROKEN_IBM_82351 @@ -1015,7 +1015,7 @@ static void MGA1064_restore(WPMINFO2) { CRITFLAGS - DBG(__FUNCTION__) + DBG(__func__) CRITBEGIN @@ -1041,7 +1041,7 @@ static void MGAG100_restore(WPMINFO2) { CRITFLAGS - DBG(__FUNCTION__) + DBG(__func__) CRITBEGIN diff --git a/drivers/video/matrox/matroxfb_Ti3026.c b/drivers/video/matrox/matroxfb_Ti3026.c index 9445cdb759b..13524821e24 100644 --- a/drivers/video/matrox/matroxfb_Ti3026.c +++ b/drivers/video/matrox/matroxfb_Ti3026.c @@ -283,7 +283,7 @@ static int Ti3026_calcclock(CPMINFO unsigned int freq, unsigned int fmax, int* i unsigned int fvco; unsigned int lin, lfeed, lpost; - DBG(__FUNCTION__) + DBG(__func__) fvco = PLL_calcclock(PMINFO freq, fmax, &lin, &lfeed, &lpost); fvco >>= (*post = lpost); @@ -297,7 +297,7 @@ static int Ti3026_setpclk(WPMINFO int clk) { unsigned int pixfeed, pixin, pixpost; struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); - DBG(__FUNCTION__) + DBG(__func__) f_pll = Ti3026_calcclock(PMINFO clk, ACCESS_FBINFO(max_pixel_clock), &pixin, &pixfeed, &pixpost); @@ -365,7 +365,7 @@ static int Ti3026_init(WPMINFO struct my_timming* m) { u_int8_t muxctrl = isInterleave(MINFO) ? TVP3026_XMUXCTRL_MEMORY_64BIT : TVP3026_XMUXCTRL_MEMORY_32BIT; struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); - DBG(__FUNCTION__) + DBG(__func__) memcpy(hw->DACreg, MGADACbpp32, sizeof(hw->DACreg)); switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) { @@ -440,7 +440,7 @@ static void ti3026_setMCLK(WPMINFO int fout){ unsigned int rfhcnt, mclk_ctl; int tmout; - DBG(__FUNCTION__) + DBG(__func__) f_pll = Ti3026_calcclock(PMINFO fout, ACCESS_FBINFO(max_pixel_clock), &mclk_n, &mclk_m, &mclk_p); @@ -534,7 +534,7 @@ static void ti3026_setMCLK(WPMINFO int fout){ static void ti3026_ramdac_init(WPMINFO2) { - DBG(__FUNCTION__) + DBG(__func__) ACCESS_FBINFO(features.pll.vco_freq_min) = 110000; ACCESS_FBINFO(features.pll.ref_freq) = 114545; @@ -554,7 +554,7 @@ static void Ti3026_restore(WPMINFO2) { struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); CRITFLAGS - DBG(__FUNCTION__) + DBG(__func__) #ifdef DEBUG dprintk(KERN_INFO "EXTVGA regs: "); @@ -662,7 +662,7 @@ static void Ti3026_restore(WPMINFO2) { static void Ti3026_reset(WPMINFO2) { - DBG(__FUNCTION__) + DBG(__func__) ti3026_ramdac_init(PMINFO2); } @@ -680,7 +680,7 @@ static int Ti3026_preinit(WPMINFO2) { 2048, 0}; struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); - DBG(__FUNCTION__) + DBG(__func__) ACCESS_FBINFO(millenium) = 1; ACCESS_FBINFO(milleniumII) = (ACCESS_FBINFO(pcidev)->device != PCI_DEVICE_ID_MATROX_MIL); diff --git a/drivers/video/matrox/matroxfb_accel.c b/drivers/video/matrox/matroxfb_accel.c index 3660d2673bd..9c3aeee1cc4 100644 --- a/drivers/video/matrox/matroxfb_accel.c +++ b/drivers/video/matrox/matroxfb_accel.c @@ -113,7 +113,7 @@ void matrox_cfbX_init(WPMINFO2) { u_int32_t mopmode; int accel; - DBG(__FUNCTION__) + DBG(__func__) mpitch = ACCESS_FBINFO(fbcon).var.xres_virtual; @@ -199,7 +199,7 @@ static void matrox_accel_bmove(WPMINFO int vxres, int sy, int sx, int dy, int dx int start, end; CRITFLAGS - DBG(__FUNCTION__) + DBG(__func__) CRITBEGIN @@ -235,7 +235,7 @@ static void matrox_accel_bmove_lin(WPMINFO int vxres, int sy, int sx, int dy, in int start, end; CRITFLAGS - DBG(__FUNCTION__) + DBG(__func__) CRITBEGIN @@ -287,7 +287,7 @@ static void matroxfb_accel_clear(WPMINFO u_int32_t color, int sy, int sx, int he int width) { CRITFLAGS - DBG(__FUNCTION__) + DBG(__func__) CRITBEGIN @@ -315,7 +315,7 @@ static void matroxfb_cfb4_clear(WPMINFO u_int32_t bgx, int sy, int sx, int heigh int whattodo; CRITFLAGS - DBG(__FUNCTION__) + DBG(__func__) CRITBEGIN @@ -388,7 +388,7 @@ static void matroxfb_1bpp_imageblit(WPMINFO u_int32_t fgx, u_int32_t bgx, int easy; CRITFLAGS - DBG_HEAVY(__FUNCTION__); + DBG_HEAVY(__func__); step = (width + 7) >> 3; charcell = height * step; @@ -469,7 +469,7 @@ static void matroxfb_1bpp_imageblit(WPMINFO u_int32_t fgx, u_int32_t bgx, static void matroxfb_imageblit(struct fb_info* info, const struct fb_image* image) { MINFO_FROM_INFO(info); - DBG_HEAVY(__FUNCTION__); + DBG_HEAVY(__func__); if (image->depth == 1) { u_int32_t fgx, bgx; diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c index b25972ac6ee..54e82f35353 100644 --- a/drivers/video/matrox/matroxfb_base.c +++ b/drivers/video/matrox/matroxfb_base.c @@ -312,7 +312,7 @@ static void matrox_pan_var(WPMINFO struct fb_var_screeninfo *var) { CRITFLAGS - DBG(__FUNCTION__) + DBG(__func__) if (ACCESS_FBINFO(dead)) return; @@ -392,7 +392,7 @@ static int matroxfb_open(struct fb_info *info, int user) { MINFO_FROM_INFO(info); - DBG_LOOP(__FUNCTION__) + DBG_LOOP(__func__) if (ACCESS_FBINFO(dead)) { return -ENXIO; @@ -408,7 +408,7 @@ static int matroxfb_release(struct fb_info *info, int user) { MINFO_FROM_INFO(info); - DBG_LOOP(__FUNCTION__) + DBG_LOOP(__func__) if (user) { if (0 == --ACCESS_FBINFO(userusecount)) { @@ -425,7 +425,7 @@ static int matroxfb_pan_display(struct fb_var_screeninfo *var, struct fb_info* info) { MINFO_FROM_INFO(info); - DBG(__FUNCTION__) + DBG(__func__) matrox_pan_var(PMINFO var); return 0; @@ -434,7 +434,7 @@ static int matroxfb_pan_display(struct fb_var_screeninfo *var, static int matroxfb_get_final_bppShift(CPMINFO int bpp) { int bppshft2; - DBG(__FUNCTION__) + DBG(__func__) bppshft2 = bpp; if (!bppshft2) { @@ -451,7 +451,7 @@ static int matroxfb_test_and_set_rounding(CPMINFO int xres, int bpp) { int over; int rounding; - DBG(__FUNCTION__) + DBG(__func__) switch (bpp) { case 0: return xres; @@ -482,7 +482,7 @@ static int matroxfb_pitch_adjust(CPMINFO int xres, int bpp) { const int* width; int xres_new; - DBG(__FUNCTION__) + DBG(__func__) if (!bpp) return xres; @@ -504,7 +504,7 @@ static int matroxfb_pitch_adjust(CPMINFO int xres, int bpp) { static int matroxfb_get_cmap_len(struct fb_var_screeninfo *var) { - DBG(__FUNCTION__) + DBG(__func__) switch (var->bits_per_pixel) { case 4: @@ -548,7 +548,7 @@ static int matroxfb_decode_var(CPMINFO struct fb_var_screeninfo *var, int *visua unsigned int vramlen; unsigned int memlen; - DBG(__FUNCTION__) + DBG(__func__) switch (bpp) { case 4: if (!ACCESS_FBINFO(capable.cfb4)) return -EINVAL; @@ -648,7 +648,7 @@ static int matroxfb_setcolreg(unsigned regno, unsigned red, unsigned green, struct matrox_fb_info* minfo = container_of(fb_info, struct matrox_fb_info, fbcon); #endif - DBG(__FUNCTION__) + DBG(__func__) /* * Set a single color register. The values supplied are @@ -707,7 +707,7 @@ static int matroxfb_setcolreg(unsigned regno, unsigned red, unsigned green, static void matroxfb_init_fix(WPMINFO2) { struct fb_fix_screeninfo *fix = &ACCESS_FBINFO(fbcon).fix; - DBG(__FUNCTION__) + DBG(__func__) strcpy(fix->id,"MATROX"); @@ -722,7 +722,7 @@ static void matroxfb_init_fix(WPMINFO2) static void matroxfb_update_fix(WPMINFO2) { struct fb_fix_screeninfo *fix = &ACCESS_FBINFO(fbcon).fix; - DBG(__FUNCTION__) + DBG(__func__) fix->smem_start = ACCESS_FBINFO(video.base) + ACCESS_FBINFO(curr.ydstorg.bytes); fix->smem_len = ACCESS_FBINFO(video.len_usable) - ACCESS_FBINFO(curr.ydstorg.bytes); @@ -753,7 +753,7 @@ static int matroxfb_set_par(struct fb_info *info) struct fb_var_screeninfo *var; MINFO_FROM_INFO(info); - DBG(__FUNCTION__) + DBG(__func__) if (ACCESS_FBINFO(dead)) { return -ENXIO; @@ -876,7 +876,7 @@ static int matroxfb_ioctl(struct fb_info *info, void __user *argp = (void __user *)arg; MINFO_FROM_INFO(info); - DBG(__FUNCTION__) + DBG(__func__) if (ACCESS_FBINFO(dead)) { return -ENXIO; @@ -1175,7 +1175,7 @@ static int matroxfb_blank(int blank, struct fb_info *info) CRITFLAGS MINFO_FROM_INFO(info); - DBG(__FUNCTION__) + DBG(__func__) if (ACCESS_FBINFO(dead)) return 1; @@ -1287,7 +1287,7 @@ static int matroxfb_getmemory(WPMINFO unsigned int maxSize, unsigned int *realSi unsigned char bytes[32]; unsigned char* tmp; - DBG(__FUNCTION__) + DBG(__func__) vm = ACCESS_FBINFO(video.vbase); maxSize &= ~0x1FFFFF; /* must be X*2MB (really it must be 2 or X*4MB) */ @@ -1593,7 +1593,7 @@ static int initMatrox2(WPMINFO struct board* b){ { }, }; - DBG(__FUNCTION__) + DBG(__func__) /* set default values... */ vesafb_defined.accel_flags = FB_ACCELF_TEXT; @@ -2006,7 +2006,7 @@ static int matroxfb_probe(struct pci_dev* pdev, const struct pci_device_id* dumm #ifndef CONFIG_FB_MATROX_MULTIHEAD static int registered = 0; #endif - DBG(__FUNCTION__) + DBG(__func__) svid = pdev->subsystem_vendor; sid = pdev->subsystem_device; @@ -2301,7 +2301,7 @@ static void __exit matrox_done(void) { static int __init matroxfb_setup(char *options) { char *this_opt; - DBG(__FUNCTION__) + DBG(__func__) if (!options || !*options) return 0; @@ -2444,7 +2444,7 @@ static int __init matroxfb_init(void) char *option = NULL; int err = 0; - DBG(__FUNCTION__) + DBG(__func__) if (fb_get_options("matroxfb", &option)) return -ENODEV; @@ -2556,7 +2556,7 @@ MODULE_PARM_DESC(cmode, "Specify the video depth that should be used (8bit defau int __init init_module(void){ - DBG(__FUNCTION__) + DBG(__func__) if (disabled) return -ENXIO; diff --git a/drivers/video/matrox/matroxfb_crtc2.c b/drivers/video/matrox/matroxfb_crtc2.c index a6ab5b6a58d..7ac4c5f6145 100644 --- a/drivers/video/matrox/matroxfb_crtc2.c +++ b/drivers/video/matrox/matroxfb_crtc2.c @@ -420,7 +420,7 @@ static int matroxfb_dh_ioctl(struct fb_info *info, #define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon)) MINFO_FROM(m2info->primary_dev); - DBG(__FUNCTION__) + DBG(__func__) switch (cmd) { case FBIOGET_VBLANK: diff --git a/drivers/video/matrox/matroxfb_maven.c b/drivers/video/matrox/matroxfb_maven.c index 0cd58f84fb4..89da27bd5c4 100644 --- a/drivers/video/matrox/matroxfb_maven.c +++ b/drivers/video/matrox/matroxfb_maven.c @@ -220,7 +220,7 @@ static int matroxfb_PLL_mavenclock(const struct matrox_pll_features2* pll, unsigned int scrlen; unsigned int fmax; - DBG(__FUNCTION__) + DBG(__func__) scrlen = htotal * (vtotal - 1); fwant = htotal * vtotal; diff --git a/drivers/video/matrox/matroxfb_misc.c b/drivers/video/matrox/matroxfb_misc.c index ab7fb50bc1d..5b5f072fc1a 100644 --- a/drivers/video/matrox/matroxfb_misc.c +++ b/drivers/video/matrox/matroxfb_misc.c @@ -90,13 +90,13 @@ #include <linux/matroxfb.h> void matroxfb_DAC_out(CPMINFO int reg, int val) { - DBG_REG(__FUNCTION__) + DBG_REG(__func__) mga_outb(M_RAMDAC_BASE+M_X_INDEX, reg); mga_outb(M_RAMDAC_BASE+M_X_DATAREG, val); } int matroxfb_DAC_in(CPMINFO int reg) { - DBG_REG(__FUNCTION__) + DBG_REG(__func__) mga_outb(M_RAMDAC_BASE+M_X_INDEX, reg); return mga_inb(M_RAMDAC_BASE+M_X_DATAREG); } @@ -104,7 +104,7 @@ int matroxfb_DAC_in(CPMINFO int reg) { void matroxfb_var2my(struct fb_var_screeninfo* var, struct my_timming* mt) { unsigned int pixclock = var->pixclock; - DBG(__FUNCTION__) + DBG(__func__) if (!pixclock) pixclock = 10000; /* 10ns = 100MHz */ mt->pixclock = 1000000000 / pixclock; @@ -131,7 +131,7 @@ int matroxfb_PLL_calcclock(const struct matrox_pll_features* pll, unsigned int f unsigned int fwant; unsigned int p; - DBG(__FUNCTION__) + DBG(__func__) fwant = freq; @@ -192,7 +192,7 @@ int matroxfb_vgaHWinit(WPMINFO struct my_timming* m) { int i; struct matrox_hw_state * const hw = &ACCESS_FBINFO(hw); - DBG(__FUNCTION__) + DBG(__func__) hw->SEQ[0] = 0x00; hw->SEQ[1] = 0x01; /* or 0x09 */ @@ -336,7 +336,7 @@ void matroxfb_vgaHWrestore(WPMINFO2) { struct matrox_hw_state * const hw = &ACCESS_FBINFO(hw); CRITFLAGS - DBG(__FUNCTION__) + DBG(__func__) dprintk(KERN_INFO "MiscOutReg: %02X\n", hw->MiscOutReg); dprintk(KERN_INFO "SEQ regs: "); @@ -522,8 +522,6 @@ static void parse_bios(unsigned char __iomem* vbios, struct matrox_bios* bd) { #endif } -#define get_u16(x) (le16_to_cpu(get_unaligned((__u16*)(x)))) -#define get_u32(x) (le32_to_cpu(get_unaligned((__u32*)(x)))) static int parse_pins1(WPMINFO const struct matrox_bios* bd) { unsigned int maxdac; @@ -532,11 +530,12 @@ static int parse_pins1(WPMINFO const struct matrox_bios* bd) { case 1: maxdac = 220000; break; default: maxdac = 240000; break; } - if (get_u16(bd->pins + 24)) { - maxdac = get_u16(bd->pins + 24) * 10; + if (get_unaligned_le16(bd->pins + 24)) { + maxdac = get_unaligned_le16(bd->pins + 24) * 10; } MINFO->limits.pixel.vcomax = maxdac; - MINFO->values.pll.system = get_u16(bd->pins + 28) ? get_u16(bd->pins + 28) * 10 : 50000; + MINFO->values.pll.system = get_unaligned_le16(bd->pins + 28) ? + get_unaligned_le16(bd->pins + 28) * 10 : 50000; /* ignore 4MB, 8MB, module clocks */ MINFO->features.pll.ref_freq = 14318; MINFO->values.reg.mctlwtst = 0x00030101; @@ -575,7 +574,8 @@ static void default_pins2(WPMINFO2) { static int parse_pins3(WPMINFO const struct matrox_bios* bd) { MINFO->limits.pixel.vcomax = MINFO->limits.system.vcomax = (bd->pins[36] == 0xFF) ? 230000 : ((bd->pins[36] + 100) * 1000); - MINFO->values.reg.mctlwtst = get_u32(bd->pins + 48) == 0xFFFFFFFF ? 0x01250A21 : get_u32(bd->pins + 48); + MINFO->values.reg.mctlwtst = get_unaligned_le32(bd->pins + 48) == 0xFFFFFFFF ? + 0x01250A21 : get_unaligned_le32(bd->pins + 48); /* memory config */ MINFO->values.reg.memrdbk = ((bd->pins[57] << 21) & 0x1E000000) | ((bd->pins[57] << 22) & 0x00C00000) | @@ -601,7 +601,7 @@ static void default_pins3(WPMINFO2) { static int parse_pins4(WPMINFO const struct matrox_bios* bd) { MINFO->limits.pixel.vcomax = (bd->pins[ 39] == 0xFF) ? 230000 : bd->pins[ 39] * 4000; MINFO->limits.system.vcomax = (bd->pins[ 38] == 0xFF) ? MINFO->limits.pixel.vcomax : bd->pins[ 38] * 4000; - MINFO->values.reg.mctlwtst = get_u32(bd->pins + 71); + MINFO->values.reg.mctlwtst = get_unaligned_le32(bd->pins + 71); MINFO->values.reg.memrdbk = ((bd->pins[87] << 21) & 0x1E000000) | ((bd->pins[87] << 22) & 0x00C00000) | ((bd->pins[86] << 1) & 0x000001E0) | @@ -609,7 +609,7 @@ static int parse_pins4(WPMINFO const struct matrox_bios* bd) { MINFO->values.reg.opt = ((bd->pins[53] << 15) & 0x00400000) | ((bd->pins[53] << 22) & 0x10000000) | ((bd->pins[53] << 7) & 0x00001C00); - MINFO->values.reg.opt3 = get_u32(bd->pins + 67); + MINFO->values.reg.opt3 = get_unaligned_le32(bd->pins + 67); MINFO->values.pll.system = (bd->pins[ 65] == 0xFF) ? 200000 : bd->pins[ 65] * 4000; MINFO->features.pll.ref_freq = (bd->pins[ 92] & 0x01) ? 14318 : 27000; return 0; @@ -640,12 +640,12 @@ static int parse_pins5(WPMINFO const struct matrox_bios* bd) { MINFO->limits.video.vcomin = (bd->pins[122] == 0xFF) ? MINFO->limits.system.vcomin : bd->pins[122] * mult; MINFO->values.pll.system = MINFO->values.pll.video = (bd->pins[ 92] == 0xFF) ? 284000 : bd->pins[ 92] * 4000; - MINFO->values.reg.opt = get_u32(bd->pins+ 48); - MINFO->values.reg.opt2 = get_u32(bd->pins+ 52); - MINFO->values.reg.opt3 = get_u32(bd->pins+ 94); - MINFO->values.reg.mctlwtst = get_u32(bd->pins+ 98); - MINFO->values.reg.memmisc = get_u32(bd->pins+102); - MINFO->values.reg.memrdbk = get_u32(bd->pins+106); + MINFO->values.reg.opt = get_unaligned_le32(bd->pins + 48); + MINFO->values.reg.opt2 = get_unaligned_le32(bd->pins + 52); + MINFO->values.reg.opt3 = get_unaligned_le32(bd->pins + 94); + MINFO->values.reg.mctlwtst = get_unaligned_le32(bd->pins + 98); + MINFO->values.reg.memmisc = get_unaligned_le32(bd->pins + 102); + MINFO->values.reg.memrdbk = get_unaligned_le32(bd->pins + 106); MINFO->features.pll.ref_freq = (bd->pins[110] & 0x01) ? 14318 : 27000; MINFO->values.memory.ddr = (bd->pins[114] & 0x60) == 0x20; MINFO->values.memory.dll = (bd->pins[115] & 0x02) != 0; diff --git a/drivers/video/metronomefb.c b/drivers/video/metronomefb.c index e9a89fd8275..cc4c038a1b3 100644 --- a/drivers/video/metronomefb.c +++ b/drivers/video/metronomefb.c @@ -13,12 +13,10 @@ * Corporation. http://support.eink.com/community * * This driver is written to be used with the Metronome display controller. - * It was tested with an E-Ink 800x600 Vizplex EPD on a Gumstix Connex board - * using the Lyre interface board. + * It is intended to be architecture independent. A board specific driver + * must be used to perform all the physical IO interactions. An example + * is provided as am200epd.c * - * General notes: - * - User must set metronomefb_enable=1 to enable it. - * - See Documentation/fb/metronomefb.txt for how metronome works. */ #include <linux/module.h> #include <linux/kernel.h> @@ -38,9 +36,11 @@ #include <linux/uaccess.h> #include <linux/irq.h> -#include <asm/arch/pxa-regs.h> +#include <video/metronomefb.h> + #include <asm/unaligned.h> + #define DEBUG 1 #ifdef DEBUG #define DPRINTK(f, a...) printk(KERN_DEBUG "%s: " f, __func__ , ## a) @@ -53,35 +53,6 @@ #define DPY_W 832 #define DPY_H 622 -struct metromem_desc { - u32 mFDADR0; - u32 mFSADR0; - u32 mFIDR0; - u32 mLDCMD0; -}; - -struct metromem_cmd { - u16 opcode; - u16 args[((64-2)/2)]; - u16 csum; -}; - -struct metronomefb_par { - unsigned char *metromem; - struct metromem_desc *metromem_desc; - struct metromem_cmd *metromem_cmd; - unsigned char *metromem_wfm; - unsigned char *metromem_img; - u16 *metromem_img_csum; - u16 *csum_table; - int metromemsize; - dma_addr_t metromem_dma; - dma_addr_t metromem_desc_dma; - struct fb_info *info; - wait_queue_head_t waitq; - u8 frame_count; -}; - /* frame differs from image. frame includes non-visible pixels */ struct epd_frame { int fw; /* frame width */ @@ -120,8 +91,7 @@ static struct fb_var_screeninfo metronomefb_var __devinitdata = { .transp = { 0, 0, 0 }, }; -static unsigned int metronomefb_enable; - +/* the waveform structure that is coming from userspace firmware */ struct waveform_hdr { u8 stuff[32]; @@ -236,8 +206,7 @@ static int load_waveform(u8 *mem, size_t size, u8 *metromem, int m, int t, } /* check waveform mode table address checksum */ - wmta = le32_to_cpu(get_unaligned((__le32 *) wfm_hdr->wmta)); - wmta &= 0x00FFFFFF; + wmta = get_unaligned_le32(wfm_hdr->wmta) & 0x00FFFFFF; cksum_idx = wmta + m*4 + 3; if (cksum_idx > size) return -EINVAL; @@ -249,8 +218,7 @@ static int load_waveform(u8 *mem, size_t size, u8 *metromem, int m, int t, } /* check waveform temperature table address checksum */ - tta = le32_to_cpu(get_unaligned((int *) (mem + wmta + m*4))); - tta &= 0x00FFFFFF; + tta = get_unaligned_le32(mem + wmta + m * 4) & 0x00FFFFFF; cksum_idx = tta + trn*4 + 3; if (cksum_idx > size) return -EINVAL; @@ -263,8 +231,7 @@ static int load_waveform(u8 *mem, size_t size, u8 *metromem, int m, int t, /* here we do the real work of putting the waveform into the metromem buffer. this does runlength decoding of the waveform */ - wfm_idx = le32_to_cpu(get_unaligned((__le32 *) (mem + tta + trn*4))); - wfm_idx &= 0x00FFFFFF; + wfm_idx = get_unaligned_le32(mem + tta + trn * 4) & 0x00FFFFFF; owfm_idx = wfm_idx; if (wfm_idx > size) return -EINVAL; @@ -301,165 +268,6 @@ static int load_waveform(u8 *mem, size_t size, u8 *metromem, int m, int t, return 0; } -/* register offsets for gpio control */ -#define LED_GPIO_PIN 51 -#define STDBY_GPIO_PIN 48 -#define RST_GPIO_PIN 49 -#define RDY_GPIO_PIN 32 -#define ERR_GPIO_PIN 17 -#define PCBPWR_GPIO_PIN 16 - -#define AF_SEL_GPIO_N 0x3 -#define GAFR0_U_OFFSET(pin) ((pin - 16) * 2) -#define GAFR1_L_OFFSET(pin) ((pin - 32) * 2) -#define GAFR1_U_OFFSET(pin) ((pin - 48) * 2) -#define GPDR1_OFFSET(pin) (pin - 32) -#define GPCR1_OFFSET(pin) (pin - 32) -#define GPSR1_OFFSET(pin) (pin - 32) -#define GPCR0_OFFSET(pin) (pin) -#define GPSR0_OFFSET(pin) (pin) - -static void metronome_set_gpio_output(int pin, int val) -{ - u8 index; - - index = pin >> 4; - - switch (index) { - case 1: - if (val) - GPSR0 |= (1 << GPSR0_OFFSET(pin)); - else - GPCR0 |= (1 << GPCR0_OFFSET(pin)); - break; - case 2: - break; - case 3: - if (val) - GPSR1 |= (1 << GPSR1_OFFSET(pin)); - else - GPCR1 |= (1 << GPCR1_OFFSET(pin)); - break; - default: - printk(KERN_ERR "unimplemented\n"); - } -} - -static void __devinit metronome_init_gpio_pin(int pin, int dir) -{ - u8 index; - /* dir 0 is output, 1 is input - - do 2 things here: - - set gpio alternate function to standard gpio - - set gpio direction to input or output */ - - index = pin >> 4; - switch (index) { - case 1: - GAFR0_U &= ~(AF_SEL_GPIO_N << GAFR0_U_OFFSET(pin)); - - if (dir) - GPDR0 &= ~(1 << pin); - else - GPDR0 |= (1 << pin); - break; - case 2: - GAFR1_L &= ~(AF_SEL_GPIO_N << GAFR1_L_OFFSET(pin)); - - if (dir) - GPDR1 &= ~(1 << GPDR1_OFFSET(pin)); - else - GPDR1 |= (1 << GPDR1_OFFSET(pin)); - break; - case 3: - GAFR1_U &= ~(AF_SEL_GPIO_N << GAFR1_U_OFFSET(pin)); - - if (dir) - GPDR1 &= ~(1 << GPDR1_OFFSET(pin)); - else - GPDR1 |= (1 << GPDR1_OFFSET(pin)); - break; - default: - printk(KERN_ERR "unimplemented\n"); - } -} - -static void __devinit metronome_init_gpio_regs(void) -{ - metronome_init_gpio_pin(LED_GPIO_PIN, 0); - metronome_set_gpio_output(LED_GPIO_PIN, 0); - - metronome_init_gpio_pin(STDBY_GPIO_PIN, 0); - metronome_set_gpio_output(STDBY_GPIO_PIN, 0); - - metronome_init_gpio_pin(RST_GPIO_PIN, 0); - metronome_set_gpio_output(RST_GPIO_PIN, 0); - - metronome_init_gpio_pin(RDY_GPIO_PIN, 1); - - metronome_init_gpio_pin(ERR_GPIO_PIN, 1); - - metronome_init_gpio_pin(PCBPWR_GPIO_PIN, 0); - metronome_set_gpio_output(PCBPWR_GPIO_PIN, 0); -} - -static void metronome_disable_lcd_controller(struct metronomefb_par *par) -{ - LCSR = 0xffffffff; /* Clear LCD Status Register */ - LCCR0 |= LCCR0_DIS; /* Disable LCD Controller */ - - /* we reset and just wait for things to settle */ - msleep(200); -} - -static void metronome_enable_lcd_controller(struct metronomefb_par *par) -{ - LCSR = 0xffffffff; - FDADR0 = par->metromem_desc_dma; - LCCR0 |= LCCR0_ENB; -} - -static void __devinit metronome_init_lcdc_regs(struct metronomefb_par *par) -{ - /* here we do: - - disable the lcd controller - - setup lcd control registers - - setup dma descriptor - - reenable lcd controller - */ - - /* disable the lcd controller */ - metronome_disable_lcd_controller(par); - - /* setup lcd control registers */ - LCCR0 = LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM | LCCR0_PAS - | LCCR0_QDM | LCCR0_BM | LCCR0_OUM; - - LCCR1 = (epd_frame_table[0].fw/2 - 1) /* pixels per line */ - | (27 << 10) /* hsync pulse width - 1 */ - | (33 << 16) /* eol pixel count */ - | (33 << 24); /* bol pixel count */ - - LCCR2 = (epd_frame_table[0].fh - 1) /* lines per panel */ - | (24 << 10) /* vsync pulse width - 1 */ - | (2 << 16) /* eof pixel count */ - | (0 << 24); /* bof pixel count */ - - LCCR3 = 2 /* pixel clock divisor */ - | (24 << 8) /* AC Bias pin freq */ - | LCCR3_16BPP /* BPP */ - | LCCR3_PCP; /* PCP falling edge */ - - /* setup dma descriptor */ - par->metromem_desc->mFDADR0 = par->metromem_desc_dma; - par->metromem_desc->mFSADR0 = par->metromem_dma; - par->metromem_desc->mFIDR0 = 0; - par->metromem_desc->mLDCMD0 = epd_frame_table[0].fw - * epd_frame_table[0].fh; - /* reenable lcd controller */ - metronome_enable_lcd_controller(par); -} - static int metronome_display_cmd(struct metronomefb_par *par) { int i; @@ -493,8 +301,7 @@ static int metronome_display_cmd(struct metronomefb_par *par) par->metromem_cmd->csum = cs; par->metromem_cmd->opcode = opcode; /* display cmd */ - i = wait_event_interruptible_timeout(par->waitq, (GPLR1 & 0x01), HZ); - return i; + return par->board->met_wait_event_intr(par); } static int __devinit metronome_powerup_cmd(struct metronomefb_par *par) @@ -518,13 +325,12 @@ static int __devinit metronome_powerup_cmd(struct metronomefb_par *par) par->metromem_cmd->csum = cs; msleep(1); - metronome_set_gpio_output(RST_GPIO_PIN, 1); + par->board->set_rst(par, 1); msleep(1); - metronome_set_gpio_output(STDBY_GPIO_PIN, 1); + par->board->set_stdby(par, 1); - i = wait_event_timeout(par->waitq, (GPLR1 & 0x01), HZ); - return i; + return par->board->met_wait_event(par); } static int __devinit metronome_config_cmd(struct metronomefb_par *par) @@ -569,8 +375,7 @@ static int __devinit metronome_config_cmd(struct metronomefb_par *par) par->metromem_cmd->csum = cs; par->metromem_cmd->opcode = 0xCC10; /* config cmd */ - i = wait_event_timeout(par->waitq, (GPLR1 & 0x01), HZ); - return i; + return par->board->met_wait_event(par); } static int __devinit metronome_init_cmd(struct metronomefb_par *par) @@ -596,16 +401,19 @@ static int __devinit metronome_init_cmd(struct metronomefb_par *par) par->metromem_cmd->csum = cs; par->metromem_cmd->opcode = 0xCC20; /* init cmd */ - i = wait_event_timeout(par->waitq, (GPLR1 & 0x01), HZ); - return i; + return par->board->met_wait_event(par); } static int __devinit metronome_init_regs(struct metronomefb_par *par) { int res; - metronome_init_gpio_regs(); - metronome_init_lcdc_regs(par); + par->board->init_gpio_regs(par); + + par->board->init_lcdc_regs(par); + + /* now that lcd is setup, setup dma descriptor */ + par->board->post_dma_setup(par); res = metronome_powerup_cmd(par); if (res) @@ -616,8 +424,6 @@ static int __devinit metronome_init_regs(struct metronomefb_par *par) return res; res = metronome_init_cmd(par); - if (res) - return res; return res; } @@ -632,7 +438,7 @@ static void metronomefb_dpy_update(struct metronomefb_par *par) cksum = calc_img_cksum((u16 *) par->metromem_img, (epd_frame_table[0].fw * DPY_H)/2); - *((u16 *) (par->metromem_img) + + *((u16 *)(par->metromem_img) + (epd_frame_table[0].fw * DPY_H)/2) = cksum; metronome_display_cmd(par); } @@ -641,8 +447,8 @@ static u16 metronomefb_dpy_update_page(struct metronomefb_par *par, int index) { int i; u16 csum = 0; - u16 *buf = (u16 __force *) (par->info->screen_base + index); - u16 *img = (u16 *) (par->metromem_img + index); + u16 *buf = (u16 __force *)(par->info->screen_base + index); + u16 *img = (u16 *)(par->metromem_img + index); /* swizzle from vm to metromem and recalc cksum at the same time*/ for (i = 0; i < PAGE_SIZE/2; i++) { @@ -678,7 +484,7 @@ static void metronomefb_fillrect(struct fb_info *info, { struct metronomefb_par *par = info->par; - cfb_fillrect(info, rect); + sys_fillrect(info, rect); metronomefb_dpy_update(par); } @@ -687,7 +493,7 @@ static void metronomefb_copyarea(struct fb_info *info, { struct metronomefb_par *par = info->par; - cfb_copyarea(info, area); + sys_copyarea(info, area); metronomefb_dpy_update(par); } @@ -696,7 +502,7 @@ static void metronomefb_imageblit(struct fb_info *info, { struct metronomefb_par *par = info->par; - cfb_imageblit(info, image); + sys_imageblit(info, image); metronomefb_dpy_update(par); } @@ -733,7 +539,7 @@ static ssize_t metronomefb_write(struct fb_info *info, const char __user *buf, count = total_size - p; } - dst = (void __force *) (info->screen_base + p); + dst = (void __force *)(info->screen_base + p); if (copy_from_user(dst, buf, count)) err = -EFAULT; @@ -759,18 +565,10 @@ static struct fb_deferred_io metronomefb_defio = { .deferred_io = metronomefb_dpy_deferred_io, }; -static irqreturn_t metronome_handle_irq(int irq, void *dev_id) -{ - struct fb_info *info = dev_id; - struct metronomefb_par *par = info->par; - - wake_up_interruptible(&par->waitq); - return IRQ_HANDLED; -} - static int __devinit metronomefb_probe(struct platform_device *dev) { struct fb_info *info; + struct metronome_board *board; int retval = -ENOMEM; int videomemorysize; unsigned char *videomemory; @@ -779,17 +577,26 @@ static int __devinit metronomefb_probe(struct platform_device *dev) int cmd_size, wfm_size, img_size, padding_size, totalsize; int i; + /* pick up board specific routines */ + board = dev->dev.platform_data; + if (!board) + return -EINVAL; + + /* try to count device specific driver, if can't, platform recalls */ + if (!try_module_get(board->owner)) + return -ENODEV; + /* we have two blocks of memory. info->screen_base which is vm, and is the fb used by apps. par->metromem which is physically contiguous memory and contains the display controller commands, waveform, processed image data and padding. this is the data pulled - by the pxa255's LCD controller and pushed to Metronome */ + by the device's LCD controller and pushed to Metronome */ videomemorysize = (DPY_W*DPY_H); videomemory = vmalloc(videomemorysize); if (!videomemory) - return retval; + return -ENOMEM; memset(videomemory, 0, videomemorysize); @@ -797,7 +604,7 @@ static int __devinit metronomefb_probe(struct platform_device *dev) if (!info) goto err_vfree; - info->screen_base = (char __iomem *) videomemory; + info->screen_base = (char __force __iomem *)videomemory; info->fbops = &metronomefb_ops; info->var = metronomefb_var; @@ -805,6 +612,7 @@ static int __devinit metronomefb_probe(struct platform_device *dev) info->fix.smem_len = videomemorysize; par = info->par; par->info = info; + par->board = board; init_waitqueue_head(&par->waitq); /* this table caches per page csum values. */ @@ -849,11 +657,10 @@ static int __devinit metronomefb_probe(struct platform_device *dev) par->metromem_desc_dma = par->metromem_dma + cmd_size + wfm_size + img_size + padding_size; - /* load the waveform in. assume mode 3, temp 31 for now */ - /* a) request the waveform file from userspace + /* load the waveform in. assume mode 3, temp 31 for now + a) request the waveform file from userspace b) process waveform and decode into metromem */ - - retval = request_firmware(&fw_entry, "waveform.wbf", &dev->dev); + retval = request_firmware(&fw_entry, "metronome.wbf", &dev->dev); if (retval < 0) { printk(KERN_ERR "metronomefb: couldn't get waveform\n"); goto err_dma_free; @@ -861,19 +668,14 @@ static int __devinit metronomefb_probe(struct platform_device *dev) retval = load_waveform((u8 *) fw_entry->data, fw_entry->size, par->metromem_wfm, 3, 31, &par->frame_count); + release_firmware(fw_entry); if (retval < 0) { printk(KERN_ERR "metronomefb: couldn't process waveform\n"); - goto err_ld_wfm; + goto err_dma_free; } - release_firmware(fw_entry); - retval = request_irq(IRQ_GPIO(RDY_GPIO_PIN), metronome_handle_irq, - IRQF_DISABLED, "Metronome", info); - if (retval) { - dev_err(&dev->dev, "request_irq failed: %d\n", retval); - goto err_ld_wfm; - } - set_irq_type(IRQ_GPIO(RDY_GPIO_PIN), IRQT_FALLING); + if (board->setup_irq(info)) + goto err_dma_free; retval = metronome_init_regs(par); if (retval < 0) @@ -913,9 +715,7 @@ err_cmap: err_fb_rel: framebuffer_release(info); err_free_irq: - free_irq(IRQ_GPIO(RDY_GPIO_PIN), info); -err_ld_wfm: - release_firmware(fw_entry); + board->free_irq(info); err_dma_free: dma_free_writecombine(&dev->dev, par->metromemsize, par->metromem, par->metromem_dma); @@ -923,6 +723,7 @@ err_csum_table: vfree(par->csum_table); err_vfree: vfree(videomemory); + module_put(board->owner); return retval; } @@ -939,7 +740,8 @@ static int __devexit metronomefb_remove(struct platform_device *dev) vfree(par->csum_table); unregister_framebuffer(info); vfree((void __force *)info->screen_base); - free_irq(IRQ_GPIO(RDY_GPIO_PIN), info); + par->board->free_irq(info); + module_put(par->board->owner); framebuffer_release(info); } return 0; @@ -949,48 +751,21 @@ static struct platform_driver metronomefb_driver = { .probe = metronomefb_probe, .remove = metronomefb_remove, .driver = { + .owner = THIS_MODULE, .name = "metronomefb", }, }; -static struct platform_device *metronomefb_device; - static int __init metronomefb_init(void) { - int ret; - - if (!metronomefb_enable) { - printk(KERN_ERR - "Use metronomefb_enable to enable the device\n"); - return -ENXIO; - } - - ret = platform_driver_register(&metronomefb_driver); - if (!ret) { - metronomefb_device = platform_device_alloc("metronomefb", 0); - if (metronomefb_device) - ret = platform_device_add(metronomefb_device); - else - ret = -ENOMEM; - - if (ret) { - platform_device_put(metronomefb_device); - platform_driver_unregister(&metronomefb_driver); - } - } - return ret; - + return platform_driver_register(&metronomefb_driver); } static void __exit metronomefb_exit(void) { - platform_device_unregister(metronomefb_device); platform_driver_unregister(&metronomefb_driver); } -module_param(metronomefb_enable, uint, 0); -MODULE_PARM_DESC(metronomefb_enable, "Enable communication with Metronome"); - module_init(metronomefb_init); module_exit(metronomefb_exit); diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c index 08d07255223..47356219158 100644 --- a/drivers/video/modedb.c +++ b/drivers/video/modedb.c @@ -22,7 +22,7 @@ ((v).xres == (x) && (v).yres == (y)) #ifdef DEBUG -#define DPRINTK(fmt, args...) printk("modedb %s: " fmt, __FUNCTION__ , ## args) +#define DPRINTK(fmt, args...) printk("modedb %s: " fmt, __func__ , ## args) #else #define DPRINTK(fmt, args...) #endif @@ -522,7 +522,7 @@ int fb_find_mode(struct fb_var_screeninfo *var, int res_specified = 0, bpp_specified = 0, refresh_specified = 0; unsigned int xres = 0, yres = 0, bpp = default_bpp, refresh = 0; int yres_specified = 0, cvt = 0, rb = 0, interlace = 0, margins = 0; - u32 best, diff; + u32 best, diff, tdiff; for (i = namelen-1; i >= 0; i--) { switch (name[i]) { @@ -651,19 +651,27 @@ done: return (refresh_specified) ? 2 : 1; } - diff = xres + yres; + diff = 2 * (xres + yres); best = -1; DPRINTK("Trying best-fit modes\n"); for (i = 0; i < dbsize; i++) { - if (xres <= db[i].xres && yres <= db[i].yres) { DPRINTK("Trying %ix%i\n", db[i].xres, db[i].yres); if (!fb_try_mode(var, info, &db[i], bpp)) { - if (diff > (db[i].xres - xres) + (db[i].yres - yres)) { - diff = (db[i].xres - xres) + (db[i].yres - yres); - best = i; - } + tdiff = abs(db[i].xres - xres) + + abs(db[i].yres - yres); + + /* + * Penalize modes with resolutions smaller + * than requested. + */ + if (xres > db[i].xres || yres > db[i].yres) + tdiff += xres + yres; + + if (diff > tdiff) { + diff = tdiff; + best = i; + } } - } } if (best != -1) { fb_try_mode(var, info, &db[best], bpp); diff --git a/drivers/video/n411.c b/drivers/video/n411.c new file mode 100644 index 00000000000..935830fea7b --- /dev/null +++ b/drivers/video/n411.c @@ -0,0 +1,202 @@ +/* + * linux/drivers/video/n411.c -- Platform device for N411 EPD kit + * + * Copyright (C) 2008, Jaya Kumar + * + * 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. + * + * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven. + * + * This driver is written to be used with the Hecuba display controller + * board, and tested with the EInk 800x600 display in 1 bit mode. + * The interface between Hecuba and the host is TTL based GPIO. The + * GPIO requirements are 8 writable data lines and 6 lines for control. + * Only 4 of the controls are actually used here but 6 for future use. + * The driver requires the IO addresses for data and control GPIO at + * load time. It is also possible to use this display with a standard + * PC parallel port. + * + * General notes: + * - User must set dio_addr=0xIOADDR cio_addr=0xIOADDR c2io_addr=0xIOADDR + * + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/list.h> +#include <linux/uaccess.h> +#include <linux/irq.h> + +#include <video/hecubafb.h> + +static unsigned long dio_addr; +static unsigned long cio_addr; +static unsigned long c2io_addr; +static unsigned long splashval; +static unsigned int nosplash; +static unsigned char ctl; + +static void n411_set_ctl(struct hecubafb_par *par, unsigned char bit, unsigned + char state) +{ + switch (bit) { + case HCB_CD_BIT: + if (state) + ctl &= ~(HCB_CD_BIT); + else + ctl |= HCB_CD_BIT; + break; + case HCB_DS_BIT: + if (state) + ctl &= ~(HCB_DS_BIT); + else + ctl |= HCB_DS_BIT; + break; + } + outb(ctl, cio_addr); +} + +static unsigned char n411_get_ctl(struct hecubafb_par *par) +{ + return inb(c2io_addr); +} + +static void n411_set_data(struct hecubafb_par *par, unsigned char value) +{ + outb(value, dio_addr); +} + +static void n411_wait_for_ack(struct hecubafb_par *par, int clear) +{ + int timeout; + unsigned char tmp; + + timeout = 500; + do { + tmp = n411_get_ctl(par); + if ((tmp & HCB_ACK_BIT) && (!clear)) + return; + else if (!(tmp & HCB_ACK_BIT) && (clear)) + return; + udelay(1); + } while (timeout--); + printk(KERN_ERR "timed out waiting for ack\n"); +} + +static int n411_init_control(struct hecubafb_par *par) +{ + unsigned char tmp; + /* for init, we want the following setup to be set: + WUP = lo + ACK = hi + DS = hi + RW = hi + CD = lo + */ + + /* write WUP to lo, DS to hi, RW to hi, CD to lo */ + ctl = HCB_WUP_BIT | HCB_RW_BIT | HCB_CD_BIT ; + n411_set_ctl(par, HCB_DS_BIT, 1); + + /* check ACK is not lo */ + tmp = n411_get_ctl(par); + if (tmp & HCB_ACK_BIT) { + printk(KERN_ERR "Fail because ACK is already low\n"); + return -ENXIO; + } + + return 0; +} + + +static int n411_init_board(struct hecubafb_par *par) +{ + int retval; + + retval = n411_init_control(par); + if (retval) + return retval; + + par->send_command(par, APOLLO_INIT_DISPLAY); + par->send_data(par, 0x81); + + /* have to wait while display resets */ + udelay(1000); + + /* if we were told to splash the screen, we just clear it */ + if (!nosplash) { + par->send_command(par, APOLLO_ERASE_DISPLAY); + par->send_data(par, splashval); + } + + return 0; +} + +static struct hecuba_board n411_board = { + .owner = THIS_MODULE, + .init = n411_init_board, + .set_ctl = n411_set_ctl, + .set_data = n411_set_data, + .wait_for_ack = n411_wait_for_ack, +}; + +static struct platform_device *n411_device; +static int __init n411_init(void) +{ + int ret; + if (!dio_addr || !cio_addr || !c2io_addr) { + printk(KERN_WARNING "no IO addresses supplied\n"); + return -EINVAL; + } + + /* request our platform independent driver */ + request_module("hecubafb"); + + n411_device = platform_device_alloc("hecubafb", -1); + if (!n411_device) + return -ENOMEM; + + platform_device_add_data(n411_device, &n411_board, sizeof(n411_board)); + + /* this _add binds hecubafb to n411. hecubafb refcounts n411 */ + ret = platform_device_add(n411_device); + + if (ret) + platform_device_put(n411_device); + + return ret; + +} + +static void __exit n411_exit(void) +{ + platform_device_unregister(n411_device); +} + +module_init(n411_init); +module_exit(n411_exit); + +module_param(nosplash, uint, 0); +MODULE_PARM_DESC(nosplash, "Disable doing the splash screen"); +module_param(dio_addr, ulong, 0); +MODULE_PARM_DESC(dio_addr, "IO address for data, eg: 0x480"); +module_param(cio_addr, ulong, 0); +MODULE_PARM_DESC(cio_addr, "IO address for control, eg: 0x400"); +module_param(c2io_addr, ulong, 0); +MODULE_PARM_DESC(c2io_addr, "IO address for secondary control, eg: 0x408"); +module_param(splashval, ulong, 0); +MODULE_PARM_DESC(splashval, "Splash pattern: 0x00 is black, 0x01 is white"); + +MODULE_DESCRIPTION("board driver for n411 hecuba/apollo epd kit"); +MODULE_AUTHOR("Jaya Kumar"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/video/nvidia/nv_hw.c b/drivers/video/nvidia/nv_hw.c index d1a10549f54..ed20a9871b3 100644 --- a/drivers/video/nvidia/nv_hw.c +++ b/drivers/video/nvidia/nv_hw.c @@ -129,7 +129,7 @@ typedef struct { int nvclk_khz; char mem_page_miss; char mem_latency; - int memory_type; + u32 memory_type; int memory_width; char enable_video; char gr_during_vid; @@ -719,7 +719,7 @@ static void nForceUpdateArbitrationSettings(unsigned VClk, memctrl >>= 16; if ((memctrl == 0x1A9) || (memctrl == 0x1AB) || (memctrl == 0x1ED)) { - int dimm[3]; + u32 dimm[3]; dev = pci_get_bus_and_slot(0, 2); pci_read_config_dword(dev, 0x40, &dimm[0]); diff --git a/drivers/video/nvidia/nv_setup.c b/drivers/video/nvidia/nv_setup.c index 82579d3a997..d9627b57eb4 100644 --- a/drivers/video/nvidia/nv_setup.c +++ b/drivers/video/nvidia/nv_setup.c @@ -265,12 +265,12 @@ static void nv10GetConfig(struct nvidia_par *par) dev = pci_get_bus_and_slot(0, 1); if ((par->Chipset & 0xffff) == 0x01a0) { - int amt = 0; + u32 amt; pci_read_config_dword(dev, 0x7c, &amt); par->RamAmountKBytes = (((amt >> 6) & 31) + 1) * 1024; } else if ((par->Chipset & 0xffff) == 0x01f0) { - int amt = 0; + u32 amt; pci_read_config_dword(dev, 0x84, &amt); par->RamAmountKBytes = (((amt >> 4) & 127) + 1) * 1024; diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c index 596652d2831..9dbb5a5a267 100644 --- a/drivers/video/nvidia/nvidia.c +++ b/drivers/video/nvidia/nvidia.c @@ -43,14 +43,14 @@ #define NVTRACE if (0) printk #endif -#define NVTRACE_ENTER(...) NVTRACE("%s START\n", __FUNCTION__) -#define NVTRACE_LEAVE(...) NVTRACE("%s END\n", __FUNCTION__) +#define NVTRACE_ENTER(...) NVTRACE("%s START\n", __func__) +#define NVTRACE_LEAVE(...) NVTRACE("%s END\n", __func__) #ifdef CONFIG_FB_NVIDIA_DEBUG #define assert(expr) \ if (!(expr)) { \ printk( "Assertion failed! %s,%s,%s,line=%d\n",\ - #expr,__FILE__,__FUNCTION__,__LINE__); \ + #expr,__FILE__,__func__,__LINE__); \ BUG(); \ } #else @@ -1559,7 +1559,6 @@ static int __devinit nvidiafb_init(void) module_init(nvidiafb_init); -#ifdef MODULE static void __exit nvidiafb_exit(void) { pci_unregister_driver(&nvidiafb_driver); @@ -1615,5 +1614,3 @@ MODULE_PARM_DESC(nomtrr, "Disables MTRR support (0 or 1=disabled) " MODULE_AUTHOR("Antonino Daplas"); MODULE_DESCRIPTION("Framebuffer driver for nVidia graphics chipset"); MODULE_LICENSE("GPL"); -#endif /* MODULE */ - diff --git a/drivers/video/offb.c b/drivers/video/offb.c index 452433d4697..d7b3dcc0dc4 100644 --- a/drivers/video/offb.c +++ b/drivers/video/offb.c @@ -248,7 +248,7 @@ static void __iomem *offb_map_reg(struct device_node *np, int index, static void __init offb_init_fb(const char *name, const char *full_name, int width, int height, int depth, int pitch, unsigned long address, - struct device_node *dp) + int foreign_endian, struct device_node *dp) { unsigned long res_size = pitch * height * (depth + 7) / 8; struct offb_par *par = &default_par; @@ -397,7 +397,7 @@ static void __init offb_init_fb(const char *name, const char *full_name, info->screen_base = ioremap(address, fix->smem_len); info->par = par; info->pseudo_palette = (void *) (info + 1); - info->flags = FBINFO_DEFAULT; + info->flags = FBINFO_DEFAULT | foreign_endian; fb_alloc_cmap(&info->cmap, 256, 0); @@ -424,6 +424,15 @@ static void __init offb_init_nodriver(struct device_node *dp, int no_real_node) u64 rstart, address = OF_BAD_ADDR; const u32 *pp, *addrp, *up; u64 asize; + int foreign_endian = 0; + +#ifdef __BIG_ENDIAN + if (of_get_property(dp, "little-endian", NULL)) + foreign_endian = FBINFO_FOREIGN_ENDIAN; +#else + if (of_get_property(dp, "big-endian", NULL)) + foreign_endian = FBINFO_FOREIGN_ENDIAN; +#endif pp = of_get_property(dp, "linux,bootx-depth", &len); if (pp == NULL) @@ -509,7 +518,7 @@ static void __init offb_init_nodriver(struct device_node *dp, int no_real_node) offb_init_fb(no_real_node ? "bootx" : dp->name, no_real_node ? "display" : dp->full_name, width, height, depth, pitch, address, - no_real_node ? NULL : dp); + foreign_endian, no_real_node ? NULL : dp); } } diff --git a/drivers/video/p9100.c b/drivers/video/p9100.c index 58496061142..c95874fe907 100644 --- a/drivers/video/p9100.c +++ b/drivers/video/p9100.c @@ -310,7 +310,7 @@ static int __devinit p9100_probe(struct of_device *op, const struct of_device_id dev_set_drvdata(&op->dev, info); - printk("%s: p9100 at %lx:%lx\n", + printk(KERN_INFO "%s: p9100 at %lx:%lx\n", dp->full_name, par->which_io, par->physbase); diff --git a/drivers/video/pm2fb.c b/drivers/video/pm2fb.c index 30181b59382..3f1ca2adda3 100644 --- a/drivers/video/pm2fb.c +++ b/drivers/video/pm2fb.c @@ -56,7 +56,7 @@ #undef PM2FB_MASTER_DEBUG #ifdef PM2FB_MASTER_DEBUG #define DPRINTK(a, b...) \ - printk(KERN_DEBUG "pm2fb: %s: " a, __FUNCTION__ , ## b) + printk(KERN_DEBUG "pm2fb: %s: " a, __func__ , ## b) #else #define DPRINTK(a, b...) #endif @@ -67,7 +67,7 @@ * Driver data */ static int hwcursor = 1; -static char *mode __devinitdata; +static char *mode_option __devinitdata; /* * The XFree GLINT driver will (I think to implement hardware cursor @@ -1680,17 +1680,19 @@ static int __devinit pm2fb_probe(struct pci_dev *pdev, info->pixmap.scan_align = 1; } - if (!mode) - mode = "640x480@60"; + if (!mode_option) + mode_option = "640x480@60"; - err = fb_find_mode(&info->var, info, mode, NULL, 0, NULL, 8); + err = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8); if (!err || err == 4) info->var = pm2fb_var; - if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) + retval = fb_alloc_cmap(&info->cmap, 256, 0); + if (retval < 0) goto err_exit_both; - if (register_framebuffer(info) < 0) + retval = register_framebuffer(info); + if (retval < 0) goto err_exit_all; printk(KERN_INFO "fb%d: %s frame buffer device, memory = %dK.\n", @@ -1797,7 +1799,7 @@ static int __init pm2fb_setup(char *options) else if (!strncmp(this_opt, "noaccel", 7)) noaccel = 1; else - mode = this_opt; + mode_option = this_opt; } return 0; } @@ -1833,8 +1835,10 @@ static void __exit pm2fb_exit(void) #ifdef MODULE module_exit(pm2fb_exit); -module_param(mode, charp, 0); -MODULE_PARM_DESC(mode, "Preferred video mode e.g. '648x480-8@60'"); +module_param(mode_option, charp, 0); +MODULE_PARM_DESC(mode_option, "Initial video mode e.g. '648x480-8@60'"); +module_param_named(mode, mode_option, charp, 0); +MODULE_PARM_DESC(mode, "Initial video mode e.g. '648x480-8@60' (deprecated)"); module_param(lowhsync, bool, 0); MODULE_PARM_DESC(lowhsync, "Force horizontal sync low regardless of mode"); module_param(lowvsync, bool, 0); diff --git a/drivers/video/pm3fb.c b/drivers/video/pm3fb.c index 5dba8cdd051..68089d1456c 100644 --- a/drivers/video/pm3fb.c +++ b/drivers/video/pm3fb.c @@ -45,7 +45,7 @@ #undef PM3FB_MASTER_DEBUG #ifdef PM3FB_MASTER_DEBUG #define DPRINTK(a, b...) \ - printk(KERN_DEBUG "pm3fb: %s: " a, __FUNCTION__ , ## b) + printk(KERN_DEBUG "pm3fb: %s: " a, __func__ , ## b) #else #define DPRINTK(a, b...) #endif @@ -1571,6 +1571,8 @@ module_exit(pm3fb_exit); #endif module_init(pm3fb_init); +module_param(mode_option, charp, 0); +MODULE_PARM_DESC(mode_option, "Initial video mode e.g. '648x480-8@60'"); module_param(noaccel, bool, 0); MODULE_PARM_DESC(noaccel, "Disable acceleration"); module_param(hwcursor, int, 0644); diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c index 5c47968e7f2..d94c57ffbdb 100644 --- a/drivers/video/riva/fbdev.c +++ b/drivers/video/riva/fbdev.c @@ -56,10 +56,6 @@ #include "rivafb.h" #include "nvreg.h" -#ifndef CONFIG_PCI /* sanity check */ -#error This driver requires PCI support. -#endif - /* version number of this driver */ #define RIVAFB_VERSION "0.9.5b" @@ -74,14 +70,14 @@ #define NVTRACE if(0) printk #endif -#define NVTRACE_ENTER(...) NVTRACE("%s START\n", __FUNCTION__) -#define NVTRACE_LEAVE(...) NVTRACE("%s END\n", __FUNCTION__) +#define NVTRACE_ENTER(...) NVTRACE("%s START\n", __func__) +#define NVTRACE_LEAVE(...) NVTRACE("%s END\n", __func__) #ifdef CONFIG_FB_RIVA_DEBUG #define assert(expr) \ if(!(expr)) { \ printk( "Assertion failed! %s,%s,%s,line=%d\n",\ - #expr,__FILE__,__FUNCTION__,__LINE__); \ + #expr,__FILE__,__func__,__LINE__); \ BUG(); \ } #else @@ -2213,14 +2209,12 @@ static int __devinit rivafb_init(void) module_init(rivafb_init); -#ifdef MODULE static void __exit rivafb_exit(void) { pci_unregister_driver(&rivafb_driver); } module_exit(rivafb_exit); -#endif /* MODULE */ module_param(noaccel, bool, 0); MODULE_PARM_DESC(noaccel, "bool: disable acceleration"); diff --git a/drivers/video/riva/nv_driver.c b/drivers/video/riva/nv_driver.c index a11026812d1..f3694cf17e5 100644 --- a/drivers/video/riva/nv_driver.c +++ b/drivers/video/riva/nv_driver.c @@ -41,11 +41,6 @@ #include "rivafb.h" #include "nvreg.h" - -#ifndef CONFIG_PCI /* sanity check */ -#error This driver requires PCI support. -#endif - #define PFX "rivafb: " static inline unsigned char MISCin(struct riva_par *par) @@ -163,7 +158,7 @@ unsigned long riva_get_memlen(struct riva_par *par) unsigned long memlen = 0; unsigned int chipset = par->Chipset; struct pci_dev* dev; - int amt; + u32 amt; switch (chip->Architecture) { case NV_ARCH_03: diff --git a/drivers/video/riva/riva_hw.c b/drivers/video/riva/riva_hw.c index 13307703a9f..78fdbf5178d 100644 --- a/drivers/video/riva/riva_hw.c +++ b/drivers/video/riva/riva_hw.c @@ -231,7 +231,7 @@ typedef struct { int nvclk_khz; char mem_page_miss; char mem_latency; - int memory_type; + u32 memory_type; int memory_width; char enable_video; char gr_during_vid; @@ -2107,7 +2107,7 @@ static void nv10GetConfig ) { struct pci_dev* dev; - int amt; + u32 amt; #ifdef __BIG_ENDIAN /* turn on big endian register access */ diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c index 71fa6edb5c4..13b38cbbe4c 100644 --- a/drivers/video/s3c2410fb.c +++ b/drivers/video/s3c2410fb.c @@ -430,9 +430,9 @@ static void s3c2410fb_activate_var(struct fb_info *info) struct fb_var_screeninfo *var = &info->var; int clkdiv = s3c2410fb_calc_pixclk(fbi, var->pixclock) / 2; - dprintk("%s: var->xres = %d\n", __FUNCTION__, var->xres); - dprintk("%s: var->yres = %d\n", __FUNCTION__, var->yres); - dprintk("%s: var->bpp = %d\n", __FUNCTION__, var->bits_per_pixel); + dprintk("%s: var->xres = %d\n", __func__, var->xres); + dprintk("%s: var->yres = %d\n", __func__, var->yres); + dprintk("%s: var->bpp = %d\n", __func__, var->bits_per_pixel); if (type == S3C2410_LCDCON1_TFT) { s3c2410fb_calculate_tft_lcd_regs(info, &fbi->regs); diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c index 7d53bc23b9c..2972f112dbe 100644 --- a/drivers/video/s3fb.c +++ b/drivers/video/s3fb.c @@ -132,10 +132,10 @@ static const struct svga_timing_regs s3_timing_regs = { /* Module parameters */ -static char *mode = "640x480-8@60"; +static char *mode_option __devinitdata = "640x480-8@60"; #ifdef CONFIG_MTRR -static int mtrr = 1; +static int mtrr __devinitdata = 1; #endif static int fasttext = 1; @@ -145,8 +145,10 @@ MODULE_AUTHOR("(c) 2006-2007 Ondrej Zajicek <santiago@crfreenet.org>"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("fbdev driver for S3 Trio/Virge"); -module_param(mode, charp, 0444); -MODULE_PARM_DESC(mode, "Default video mode ('640x480-8@60', etc)"); +module_param(mode_option, charp, 0444); +MODULE_PARM_DESC(mode_option, "Default video mode ('640x480-8@60', etc)"); +module_param_named(mode, mode_option, charp, 0444); +MODULE_PARM_DESC(mode, "Default video mode ('640x480-8@60', etc) (deprecated)"); #ifdef CONFIG_MTRR module_param(mtrr, int, 0444); @@ -886,7 +888,7 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i } /* Allocate and fill driver data structure */ - info = framebuffer_alloc(sizeof(struct s3fb_info), NULL); + info = framebuffer_alloc(sizeof(struct s3fb_info), &(dev->dev)); if (!info) { dev_err(&(dev->dev), "cannot allocate memory\n"); return -ENOMEM; @@ -901,13 +903,13 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i /* Prepare PCI device */ rc = pci_enable_device(dev); if (rc < 0) { - dev_err(&(dev->dev), "cannot enable PCI device\n"); + dev_err(info->dev, "cannot enable PCI device\n"); goto err_enable_device; } rc = pci_request_regions(dev, "s3fb"); if (rc < 0) { - dev_err(&(dev->dev), "cannot reserve framebuffer region\n"); + dev_err(info->dev, "cannot reserve framebuffer region\n"); goto err_request_regions; } @@ -919,7 +921,7 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i info->screen_base = pci_iomap(dev, 0, 0); if (! info->screen_base) { rc = -ENOMEM; - dev_err(&(dev->dev), "iomap for framebuffer failed\n"); + dev_err(info->dev, "iomap for framebuffer failed\n"); goto err_iomap; } @@ -960,22 +962,22 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i info->pseudo_palette = (void*) (par->pseudo_palette); /* Prepare startup mode */ - rc = fb_find_mode(&(info->var), info, mode, NULL, 0, NULL, 8); + rc = fb_find_mode(&(info->var), info, mode_option, NULL, 0, NULL, 8); if (! ((rc == 1) || (rc == 2))) { rc = -EINVAL; - dev_err(&(dev->dev), "mode %s not found\n", mode); + dev_err(info->dev, "mode %s not found\n", mode_option); goto err_find_mode; } rc = fb_alloc_cmap(&info->cmap, 256, 0); if (rc < 0) { - dev_err(&(dev->dev), "cannot allocate colormap\n"); + dev_err(info->dev, "cannot allocate colormap\n"); goto err_alloc_cmap; } rc = register_framebuffer(info); if (rc < 0) { - dev_err(&(dev->dev), "cannot register framebuffer\n"); + dev_err(info->dev, "cannot register framebuffer\n"); goto err_reg_fb; } @@ -1051,7 +1053,7 @@ static int s3_pci_suspend(struct pci_dev* dev, pm_message_t state) struct fb_info *info = pci_get_drvdata(dev); struct s3fb_info *par = info->par; - dev_info(&(dev->dev), "suspend\n"); + dev_info(info->dev, "suspend\n"); acquire_console_sem(); mutex_lock(&(par->open_lock)); @@ -1083,7 +1085,7 @@ static int s3_pci_resume(struct pci_dev* dev) struct s3fb_info *par = info->par; int err; - dev_info(&(dev->dev), "resume\n"); + dev_info(info->dev, "resume\n"); acquire_console_sem(); mutex_lock(&(par->open_lock)); @@ -1100,7 +1102,7 @@ static int s3_pci_resume(struct pci_dev* dev) if (err) { mutex_unlock(&(par->open_lock)); release_console_sem(); - dev_err(&(dev->dev), "error %d enabling device for resume\n", err); + dev_err(info->dev, "error %d enabling device for resume\n", err); return err; } pci_set_master(dev); @@ -1168,7 +1170,7 @@ static int __init s3fb_setup(char *options) else if (!strncmp(opt, "fasttext:", 9)) fasttext = simple_strtoul(opt + 9, NULL, 0); else - mode = opt; + mode_option = opt; } return 0; diff --git a/drivers/video/sa1100fb.h b/drivers/video/sa1100fb.h index 48066ef3af0..f465b27ed86 100644 --- a/drivers/video/sa1100fb.h +++ b/drivers/video/sa1100fb.h @@ -132,7 +132,7 @@ struct sa1100fb_info { * Debug macros */ #if DEBUG -# define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args) +# define DPRINTK(fmt, args...) printk("%s: " fmt, __func__ , ## args) #else # define DPRINTK(fmt, args...) #endif diff --git a/drivers/video/savage/savagefb-i2c.c b/drivers/video/savage/savagefb-i2c.c index 35c1ce62b21..783d4adffb9 100644 --- a/drivers/video/savage/savagefb-i2c.c +++ b/drivers/video/savage/savagefb-i2c.c @@ -140,7 +140,7 @@ static int savage_setup_i2c_bus(struct savagefb_i2c_chan *chan, chan->adapter.id = I2C_HW_B_SAVAGE; chan->adapter.algo_data = &chan->algo; chan->adapter.dev.parent = &chan->par->pcidev->dev; - chan->algo.udelay = 40; + chan->algo.udelay = 10; chan->algo.timeout = 20; chan->algo.data = chan; diff --git a/drivers/video/sis/sis.h b/drivers/video/sis/sis.h index 9b05da6268f..a14e8221103 100644 --- a/drivers/video/sis/sis.h +++ b/drivers/video/sis/sis.h @@ -55,7 +55,7 @@ #undef SISFBDEBUG #ifdef SISFBDEBUG -#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) +#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __func__ , ## args) #define TWDEBUG(x) printk(KERN_INFO x "\n"); #else #define DPRINTK(fmt, args...) diff --git a/drivers/video/sstfb.c b/drivers/video/sstfb.c index 97784f9c184..5b11a00f49b 100644 --- a/drivers/video/sstfb.c +++ b/drivers/video/sstfb.c @@ -1006,7 +1006,7 @@ static int sst_set_pll_att_ti(struct fb_info *info, break; default: dprintk("%s: wrong clock code '%d'\n", - __FUNCTION__, clock); + __func__, clock); return 0; } udelay(300); @@ -1048,7 +1048,7 @@ static int sst_set_pll_ics(struct fb_info *info, break; default: dprintk("%s: wrong clock code '%d'\n", - __FUNCTION__, clock); + __func__, clock); return 0; } udelay(300); @@ -1079,7 +1079,7 @@ static void sst_set_vidmod_att_ti(struct fb_info *info, const int bpp) sst_dac_write(DACREG_RMR, (cr0 & 0x0f) | DACREG_CR0_16BPP); break; default: - dprintk("%s: bad depth '%u'\n", __FUNCTION__, bpp); + dprintk("%s: bad depth '%u'\n", __func__, bpp); break; } } @@ -1093,7 +1093,7 @@ static void sst_set_vidmod_ics(struct fb_info *info, const int bpp) sst_dac_write(DACREG_ICS_CMD, DACREG_ICS_CMD_16BPP); break; default: - dprintk("%s: bad depth '%u'\n", __FUNCTION__, bpp); + dprintk("%s: bad depth '%u'\n", __func__, bpp); break; } } @@ -1133,7 +1133,7 @@ static int __devinit sst_detect_dactype(struct fb_info *info, struct sstfb_par * } if (!ret) return 0; - f_dprintk("%s found %s\n", __FUNCTION__, dacs[i].name); + f_dprintk("%s found %s\n", __func__, dacs[i].name); par->dac_sw = dacs[i]; return 1; } diff --git a/drivers/video/stifb.c b/drivers/video/stifb.c index f98be301140..598d35eff93 100644 --- a/drivers/video/stifb.c +++ b/drivers/video/stifb.c @@ -164,11 +164,11 @@ static int __initdata stifb_bpp_pref[MAX_STI_ROMS]; # define DEBUG_ON() debug_on=1 # define WRITE_BYTE(value,fb,reg) do { if (debug_on) \ printk(KERN_DEBUG "%30s: WRITE_BYTE(0x%06x) = 0x%02x (old=0x%02x)\n", \ - __FUNCTION__, reg, value, READ_BYTE(fb,reg)); \ + __func__, reg, value, READ_BYTE(fb,reg)); \ gsc_writeb((value),(fb)->info.fix.mmio_start + (reg)); } while (0) # define WRITE_WORD(value,fb,reg) do { if (debug_on) \ printk(KERN_DEBUG "%30s: WRITE_WORD(0x%06x) = 0x%08x (old=0x%08x)\n", \ - __FUNCTION__, reg, value, READ_WORD(fb,reg)); \ + __func__, reg, value, READ_WORD(fb,reg)); \ gsc_writel((value),(fb)->info.fix.mmio_start + (reg)); } while (0) #endif /* DEBUG_STIFB_REGS */ diff --git a/drivers/video/syscopyarea.c b/drivers/video/syscopyarea.c index 37af10ab8f5..a352d5f46bb 100644 --- a/drivers/video/syscopyarea.c +++ b/drivers/video/syscopyarea.c @@ -26,15 +26,15 @@ */ static void -bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src, - int src_idx, int bits, unsigned n) +bitcpy(struct fb_info *p, unsigned long *dst, int dst_idx, + const unsigned long *src, int src_idx, int bits, unsigned n) { unsigned long first, last; int const shift = dst_idx-src_idx; int left, right; - first = FB_SHIFT_HIGH(~0UL, dst_idx); - last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits)); + first = FB_SHIFT_HIGH(p, ~0UL, dst_idx); + last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits)); if (!shift) { /* Same alignment for source and dest */ @@ -167,8 +167,8 @@ bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src, */ static void -bitcpy_rev(unsigned long *dst, int dst_idx, const unsigned long *src, - int src_idx, int bits, unsigned n) +bitcpy_rev(struct fb_info *p, unsigned long *dst, int dst_idx, + const unsigned long *src, int src_idx, int bits, unsigned n) { unsigned long first, last; int shift; @@ -186,8 +186,8 @@ bitcpy_rev(unsigned long *dst, int dst_idx, const unsigned long *src, shift = dst_idx-src_idx; - first = FB_SHIFT_LOW(~0UL, bits - 1 - dst_idx); - last = ~(FB_SHIFT_LOW(~0UL, bits - 1 - ((dst_idx-n) % bits))); + first = FB_SHIFT_LOW(p, ~0UL, bits - 1 - dst_idx); + last = ~(FB_SHIFT_LOW(p, ~0UL, bits - 1 - ((dst_idx-n) % bits))); if (!shift) { /* Same alignment for source and dest */ @@ -353,7 +353,7 @@ void sys_copyarea(struct fb_info *p, const struct fb_copyarea *area) dst_idx &= (bytes - 1); src += src_idx >> (ffs(bits) - 1); src_idx &= (bytes - 1); - bitcpy_rev(dst, dst_idx, src, src_idx, bits, + bitcpy_rev(p, dst, dst_idx, src, src_idx, bits, width*p->var.bits_per_pixel); } } else { @@ -362,7 +362,7 @@ void sys_copyarea(struct fb_info *p, const struct fb_copyarea *area) dst_idx &= (bytes - 1); src += src_idx >> (ffs(bits) - 1); src_idx &= (bytes - 1); - bitcpy(dst, dst_idx, src, src_idx, bits, + bitcpy(p, dst, dst_idx, src, src_idx, bits, width*p->var.bits_per_pixel); dst_idx += bits_per_line; src_idx += bits_per_line; diff --git a/drivers/video/sysfillrect.c b/drivers/video/sysfillrect.c index a261e9e6a67..f94d6b6e29e 100644 --- a/drivers/video/sysfillrect.c +++ b/drivers/video/sysfillrect.c @@ -22,16 +22,16 @@ */ static void -bitfill_aligned(unsigned long *dst, int dst_idx, unsigned long pat, - unsigned n, int bits) +bitfill_aligned(struct fb_info *p, unsigned long *dst, int dst_idx, + unsigned long pat, unsigned n, int bits) { unsigned long first, last; if (!n) return; - first = FB_SHIFT_HIGH(~0UL, dst_idx); - last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits)); + first = FB_SHIFT_HIGH(p, ~0UL, dst_idx); + last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits)); if (dst_idx+n <= bits) { /* Single word */ @@ -78,16 +78,16 @@ bitfill_aligned(unsigned long *dst, int dst_idx, unsigned long pat, */ static void -bitfill_unaligned(unsigned long *dst, int dst_idx, unsigned long pat, - int left, int right, unsigned n, int bits) +bitfill_unaligned(struct fb_info *p, unsigned long *dst, int dst_idx, + unsigned long pat, int left, int right, unsigned n, int bits) { unsigned long first, last; if (!n) return; - first = FB_SHIFT_HIGH(~0UL, dst_idx); - last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits)); + first = FB_SHIFT_HIGH(p, ~0UL, dst_idx); + last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits)); if (dst_idx+n <= bits) { /* Single word */ @@ -132,8 +132,8 @@ bitfill_unaligned(unsigned long *dst, int dst_idx, unsigned long pat, * Aligned pattern invert using 32/64-bit memory accesses */ static void -bitfill_aligned_rev(unsigned long *dst, int dst_idx, unsigned long pat, - unsigned n, int bits) +bitfill_aligned_rev(struct fb_info *p, unsigned long *dst, int dst_idx, + unsigned long pat, unsigned n, int bits) { unsigned long val = pat; unsigned long first, last; @@ -141,8 +141,8 @@ bitfill_aligned_rev(unsigned long *dst, int dst_idx, unsigned long pat, if (!n) return; - first = FB_SHIFT_HIGH(~0UL, dst_idx); - last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits)); + first = FB_SHIFT_HIGH(p, ~0UL, dst_idx); + last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits)); if (dst_idx+n <= bits) { /* Single word */ @@ -188,16 +188,17 @@ bitfill_aligned_rev(unsigned long *dst, int dst_idx, unsigned long pat, */ static void -bitfill_unaligned_rev(unsigned long *dst, int dst_idx, unsigned long pat, - int left, int right, unsigned n, int bits) +bitfill_unaligned_rev(struct fb_info *p, unsigned long *dst, int dst_idx, + unsigned long pat, int left, int right, unsigned n, + int bits) { unsigned long first, last; if (!n) return; - first = FB_SHIFT_HIGH(~0UL, dst_idx); - last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits)); + first = FB_SHIFT_HIGH(p, ~0UL, dst_idx); + last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits)); if (dst_idx+n <= bits) { /* Single word */ @@ -267,9 +268,9 @@ void sys_fillrect(struct fb_info *p, const struct fb_fillrect *rect) if (p->fbops->fb_sync) p->fbops->fb_sync(p); if (!left) { - void (*fill_op32)(unsigned long *dst, int dst_idx, - unsigned long pat, unsigned n, int bits) = - NULL; + void (*fill_op32)(struct fb_info *p, unsigned long *dst, + int dst_idx, unsigned long pat, unsigned n, + int bits) = NULL; switch (rect->rop) { case ROP_XOR: @@ -287,16 +288,16 @@ void sys_fillrect(struct fb_info *p, const struct fb_fillrect *rect) while (height--) { dst += dst_idx >> (ffs(bits) - 1); dst_idx &= (bits - 1); - fill_op32(dst, dst_idx, pat, width*bpp, bits); + fill_op32(p, dst, dst_idx, pat, width*bpp, bits); dst_idx += p->fix.line_length*8; } } else { int right; int r; int rot = (left-dst_idx) % bpp; - void (*fill_op)(unsigned long *dst, int dst_idx, - unsigned long pat, int left, int right, - unsigned n, int bits) = NULL; + void (*fill_op)(struct fb_info *p, unsigned long *dst, + int dst_idx, unsigned long pat, int left, + int right, unsigned n, int bits) = NULL; /* rotate pattern to correct start position */ pat = pat << rot | pat >> (bpp-rot); @@ -318,7 +319,7 @@ void sys_fillrect(struct fb_info *p, const struct fb_fillrect *rect) while (height--) { dst += dst_idx >> (ffs(bits) - 1); dst_idx &= (bits - 1); - fill_op(dst, dst_idx, pat, left, right, + fill_op(p, dst, dst_idx, pat, left, right, width*bpp, bits); r = (p->fix.line_length*8) % bpp; pat = pat << (bpp-r) | pat >> r; diff --git a/drivers/video/sysimgblt.c b/drivers/video/sysimgblt.c index bd7e7e9d155..186c6f607be 100644 --- a/drivers/video/sysimgblt.c +++ b/drivers/video/sysimgblt.c @@ -18,35 +18,31 @@ #define DEBUG #ifdef DEBUG -#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt,__FUNCTION__,## args) +#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt,__func__,## args) #else #define DPRINTK(fmt, args...) #endif -static const u32 cfb_tab8[] = { -#if defined(__BIG_ENDIAN) +static const u32 cfb_tab8_be[] = { 0x00000000,0x000000ff,0x0000ff00,0x0000ffff, 0x00ff0000,0x00ff00ff,0x00ffff00,0x00ffffff, 0xff000000,0xff0000ff,0xff00ff00,0xff00ffff, 0xffff0000,0xffff00ff,0xffffff00,0xffffffff -#elif defined(__LITTLE_ENDIAN) +}; + +static const u32 cfb_tab8_le[] = { 0x00000000,0xff000000,0x00ff0000,0xffff0000, 0x0000ff00,0xff00ff00,0x00ffff00,0xffffff00, 0x000000ff,0xff0000ff,0x00ff00ff,0xffff00ff, 0x0000ffff,0xff00ffff,0x00ffffff,0xffffffff -#else -#error FIXME: No endianness?? -#endif }; -static const u32 cfb_tab16[] = { -#if defined(__BIG_ENDIAN) +static const u32 cfb_tab16_be[] = { 0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff -#elif defined(__LITTLE_ENDIAN) +}; + +static const u32 cfb_tab16_le[] = { 0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff -#else -#error FIXME: No endianness?? -#endif }; static const u32 cfb_tab32[] = { @@ -72,7 +68,7 @@ static void color_imageblit(const struct fb_image *image, struct fb_info *p, val = 0; if (start_index) { - u32 start_mask = ~(FB_SHIFT_HIGH(~(u32)0, + u32 start_mask = ~(FB_SHIFT_HIGH(p, ~(u32)0, start_index)); val = *dst & start_mask; shift = start_index; @@ -83,20 +79,20 @@ static void color_imageblit(const struct fb_image *image, struct fb_info *p, color = palette[*src]; else color = *src; - color <<= FB_LEFT_POS(bpp); - val |= FB_SHIFT_HIGH(color, shift); + color <<= FB_LEFT_POS(p, bpp); + val |= FB_SHIFT_HIGH(p, color, shift); if (shift >= null_bits) { *dst++ = val; val = (shift == null_bits) ? 0 : - FB_SHIFT_LOW(color, 32 - shift); + FB_SHIFT_LOW(p, color, 32 - shift); } shift += bpp; shift &= (32 - 1); src++; } if (shift) { - u32 end_mask = FB_SHIFT_HIGH(~(u32)0, shift); + u32 end_mask = FB_SHIFT_HIGH(p, ~(u32)0, shift); *dst &= end_mask; *dst |= val; @@ -125,8 +121,8 @@ static void slow_imageblit(const struct fb_image *image, struct fb_info *p, u32 i, j, l; dst2 = dst1; - fgcolor <<= FB_LEFT_POS(bpp); - bgcolor <<= FB_LEFT_POS(bpp); + fgcolor <<= FB_LEFT_POS(p, bpp); + bgcolor <<= FB_LEFT_POS(p, bpp); for (i = image->height; i--; ) { shift = val = 0; @@ -137,7 +133,8 @@ static void slow_imageblit(const struct fb_image *image, struct fb_info *p, /* write leading bits */ if (start_index) { - u32 start_mask = ~(FB_SHIFT_HIGH(~(u32)0,start_index)); + u32 start_mask = ~(FB_SHIFT_HIGH(p, ~(u32)0, + start_index)); val = *dst & start_mask; shift = start_index; } @@ -145,13 +142,13 @@ static void slow_imageblit(const struct fb_image *image, struct fb_info *p, while (j--) { l--; color = (*s & (1 << l)) ? fgcolor : bgcolor; - val |= FB_SHIFT_HIGH(color, shift); + val |= FB_SHIFT_HIGH(p, color, shift); /* Did the bitshift spill bits to the next long? */ if (shift >= null_bits) { *dst++ = val; val = (shift == null_bits) ? 0 : - FB_SHIFT_LOW(color,32 - shift); + FB_SHIFT_LOW(p, color, 32 - shift); } shift += bpp; shift &= (32 - 1); @@ -160,7 +157,7 @@ static void slow_imageblit(const struct fb_image *image, struct fb_info *p, /* write trailing bits */ if (shift) { - u32 end_mask = FB_SHIFT_HIGH(~(u32)0, shift); + u32 end_mask = FB_SHIFT_HIGH(p, ~(u32)0, shift); *dst &= end_mask; *dst |= val; @@ -199,10 +196,10 @@ static void fast_imageblit(const struct fb_image *image, struct fb_info *p, switch (bpp) { case 8: - tab = cfb_tab8; + tab = fb_be_math(p) ? cfb_tab8_be : cfb_tab8_le; break; case 16: - tab = cfb_tab16; + tab = fb_be_math(p) ? cfb_tab16_be : cfb_tab16_le; break; case 32: default: diff --git a/drivers/video/tcx.c b/drivers/video/tcx.c index e5a9ddb3c8b..a7177430577 100644 --- a/drivers/video/tcx.c +++ b/drivers/video/tcx.c @@ -419,7 +419,7 @@ static int __devinit tcx_init_one(struct of_device *op) par->mmap_map[6].size = SBUS_MMAP_EMPTY; } - par->physbase = 0; + par->physbase = op->resource[0].start; par->which_io = op->resource[0].flags & IORESOURCE_BITS; for (i = 0; i < TCX_MMAP_ENTRIES; i++) { @@ -470,10 +470,10 @@ static int __devinit tcx_init_one(struct of_device *op) dev_set_drvdata(&op->dev, info); - printk("%s: TCX at %lx:%lx, %s\n", + printk(KERN_INFO "%s: TCX at %lx:%lx, %s\n", dp->full_name, par->which_io, - op->resource[0].start, + par->physbase, par->lowdepth ? "8-bit only" : "24-bit depth"); return 0; @@ -527,7 +527,7 @@ static struct of_platform_driver tcx_driver = { .remove = __devexit_p(tcx_remove), }; -int __init tcx_init(void) +static int __init tcx_init(void) { if (fb_get_options("tcxfb", NULL)) return -ENODEV; @@ -535,7 +535,7 @@ int __init tcx_init(void) return of_register_driver(&tcx_driver, &of_bus_type); } -void __exit tcx_exit(void) +static void __exit tcx_exit(void) { of_unregister_driver(&tcx_driver); } diff --git a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c index 71e179ea5f9..ea9f19d2559 100644 --- a/drivers/video/tdfxfb.c +++ b/drivers/video/tdfxfb.c @@ -70,7 +70,7 @@ #include <video/tdfx.h> -#define DPRINTK(a, b...) pr_debug("fb: %s: " a, __FUNCTION__ , ## b) +#define DPRINTK(a, b...) pr_debug("fb: %s: " a, __func__ , ## b) #ifdef CONFIG_MTRR #include <asm/mtrr.h> diff --git a/drivers/video/tridentfb.c b/drivers/video/tridentfb.c index 0a4e07d43d2..bd54cd0de39 100644 --- a/drivers/video/tridentfb.c +++ b/drivers/video/tridentfb.c @@ -58,7 +58,7 @@ static int displaytype; /* defaults which are normally overriden by user values */ /* video mode */ -static char *mode = "640x480"; +static char *mode_option __devinitdata = "640x480"; static int bpp = 8; static int noaccel; @@ -73,7 +73,10 @@ static int memsize; static int memdiff; static int nativex; -module_param(mode, charp, 0); +module_param(mode_option, charp, 0); +MODULE_PARM_DESC(mode_option, "Initial video mode e.g. '648x480-8@60'"); +module_param_named(mode, mode_option, charp, 0); +MODULE_PARM_DESC(mode, "Initial video mode e.g. '648x480-8@60' (deprecated)"); module_param(bpp, int, 0); module_param(center, int, 0); module_param(stretch, int, 0); @@ -1297,7 +1300,8 @@ static int __devinit trident_pci_probe(struct pci_dev * dev, #endif fb_info.pseudo_palette = pseudo_pal; - if (!fb_find_mode(&default_var, &fb_info, mode, NULL, 0, NULL, bpp)) { + if (!fb_find_mode(&default_var, &fb_info, + mode_option, NULL, 0, NULL, bpp)) { err = -EINVAL; goto out_unmap2; } @@ -1385,7 +1389,7 @@ static struct pci_driver tridentfb_pci_driver = { * video=trident:800x600,bpp=16,noaccel */ #ifndef MODULE -static int tridentfb_setup(char *options) +static int __init tridentfb_setup(char *options) { char *opt; if (!options || !*options) @@ -1412,7 +1416,7 @@ static int tridentfb_setup(char *options) else if (!strncmp(opt, "nativex=", 8)) nativex = simple_strtoul(opt + 8, NULL, 0); else - mode = opt; + mode_option = opt; } return 0; } diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c index 93361656316..cdbb56edb6c 100644 --- a/drivers/video/uvesafb.c +++ b/drivers/video/uvesafb.c @@ -181,7 +181,8 @@ static int uvesafb_exec(struct uvesafb_ktask *task) /* If all slots are taken -- bail out. */ if (uvfb_tasks[seq]) { mutex_unlock(&uvfb_lock); - return -EBUSY; + err = -EBUSY; + goto out; } /* Save a pointer to the kernel part of the task struct. */ @@ -205,7 +206,6 @@ static int uvesafb_exec(struct uvesafb_ktask *task) err = cn_netlink_send(m, 0, gfp_any()); } } - kfree(m); if (!err && !(task->t.flags & TF_EXIT)) err = !wait_for_completion_timeout(task->done, @@ -218,7 +218,8 @@ static int uvesafb_exec(struct uvesafb_ktask *task) seq++; if (seq >= UVESAFB_TASKS_MAX) seq = 0; - +out: + kfree(m); return err; } @@ -885,7 +886,7 @@ static int __devinit uvesafb_vbe_init_mode(struct fb_info *info) } /* fb_find_mode() failed */ - if (i == 0 || i >= 3) { + if (i == 0) { info->var.xres = 640; info->var.yres = 480; mode = (struct fb_videomode *) diff --git a/drivers/video/vermilion/vermilion.c b/drivers/video/vermilion/vermilion.c index 2aa71eb67c2..c18f1884b55 100644 --- a/drivers/video/vermilion/vermilion.c +++ b/drivers/video/vermilion/vermilion.c @@ -112,8 +112,9 @@ static int vmlfb_alloc_vram_area(struct vram_area *va, unsigned max_order, /* * It seems like __get_free_pages only ups the usage count - * of the first page. This doesn't work with nopage mapping, so - * up the usage count once more. + * of the first page. This doesn't work with fault mapping, so + * up the usage count once more (XXX: should use split_page or + * compound page). */ memset((void *)va->logical, 0x00, va->size); diff --git a/drivers/video/vt8623fb.c b/drivers/video/vt8623fb.c index 4c3a63308df..536ab11623f 100644 --- a/drivers/video/vt8623fb.c +++ b/drivers/video/vt8623fb.c @@ -100,7 +100,7 @@ static struct svga_timing_regs vt8623_timing_regs = { /* Module parameters */ -static char *mode = "640x480-8@60"; +static char *mode_option = "640x480-8@60"; #ifdef CONFIG_MTRR static int mtrr = 1; @@ -110,8 +110,10 @@ MODULE_AUTHOR("(c) 2006 Ondrej Zajicek <santiago@crfreenet.org>"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("fbdev driver for integrated graphics core in VIA VT8623 [CLE266]"); -module_param(mode, charp, 0644); -MODULE_PARM_DESC(mode, "Default video mode ('640x480-8@60', etc)"); +module_param(mode_option, charp, 0644); +MODULE_PARM_DESC(mode_option, "Default video mode ('640x480-8@60', etc)"); +module_param_named(mode, mode_option, charp, 0); +MODULE_PARM_DESC(mode, "Default video mode e.g. '648x480-8@60' (deprecated)"); #ifdef CONFIG_MTRR module_param(mtrr, int, 0444); @@ -434,6 +436,10 @@ static int vt8623fb_set_par(struct fb_info *info) svga_wcrt_multi(vt8623_offset_regs, offset_value); svga_wseq_multi(vt8623_fetch_count_regs, fetch_value); + /* Clear H/V Skew */ + svga_wcrt_mask(0x03, 0x00, 0x60); + svga_wcrt_mask(0x05, 0x00, 0x60); + if (info->var.vmode & FB_VMODE_DOUBLE) svga_wcrt_mask(0x09, 0x80, 0x80); else @@ -655,7 +661,7 @@ static int __devinit vt8623_pci_probe(struct pci_dev *dev, const struct pci_devi } /* Allocate and fill driver data structure */ - info = framebuffer_alloc(sizeof(struct vt8623fb_info), NULL); + info = framebuffer_alloc(sizeof(struct vt8623fb_info), &(dev->dev)); if (! info) { dev_err(&(dev->dev), "cannot allocate memory\n"); return -ENOMEM; @@ -671,13 +677,13 @@ static int __devinit vt8623_pci_probe(struct pci_dev *dev, const struct pci_devi rc = pci_enable_device(dev); if (rc < 0) { - dev_err(&(dev->dev), "cannot enable PCI device\n"); + dev_err(info->dev, "cannot enable PCI device\n"); goto err_enable_device; } rc = pci_request_regions(dev, "vt8623fb"); if (rc < 0) { - dev_err(&(dev->dev), "cannot reserve framebuffer region\n"); + dev_err(info->dev, "cannot reserve framebuffer region\n"); goto err_request_regions; } @@ -690,14 +696,14 @@ static int __devinit vt8623_pci_probe(struct pci_dev *dev, const struct pci_devi info->screen_base = pci_iomap(dev, 0, 0); if (! info->screen_base) { rc = -ENOMEM; - dev_err(&(dev->dev), "iomap for framebuffer failed\n"); + dev_err(info->dev, "iomap for framebuffer failed\n"); goto err_iomap_1; } par->mmio_base = pci_iomap(dev, 1, 0); if (! par->mmio_base) { rc = -ENOMEM; - dev_err(&(dev->dev), "iomap for MMIO failed\n"); + dev_err(info->dev, "iomap for MMIO failed\n"); goto err_iomap_2; } @@ -708,7 +714,7 @@ static int __devinit vt8623_pci_probe(struct pci_dev *dev, const struct pci_devi if ((16 <= memsize1) && (memsize1 <= 64) && (memsize1 == memsize2)) info->screen_size = memsize1 << 20; else { - dev_err(&(dev->dev), "memory size detection failed (%x %x), suppose 16 MB\n", memsize1, memsize2); + dev_err(info->dev, "memory size detection failed (%x %x), suppose 16 MB\n", memsize1, memsize2); info->screen_size = 16 << 20; } @@ -722,22 +728,22 @@ static int __devinit vt8623_pci_probe(struct pci_dev *dev, const struct pci_devi /* Prepare startup mode */ - rc = fb_find_mode(&(info->var), info, mode, NULL, 0, NULL, 8); + rc = fb_find_mode(&(info->var), info, mode_option, NULL, 0, NULL, 8); if (! ((rc == 1) || (rc == 2))) { rc = -EINVAL; - dev_err(&(dev->dev), "mode %s not found\n", mode); + dev_err(info->dev, "mode %s not found\n", mode_option); goto err_find_mode; } rc = fb_alloc_cmap(&info->cmap, 256, 0); if (rc < 0) { - dev_err(&(dev->dev), "cannot allocate colormap\n"); + dev_err(info->dev, "cannot allocate colormap\n"); goto err_alloc_cmap; } rc = register_framebuffer(info); if (rc < 0) { - dev_err(&(dev->dev), "cannot register framebugger\n"); + dev_err(info->dev, "cannot register framebugger\n"); goto err_reg_fb; } @@ -811,7 +817,7 @@ static int vt8623_pci_suspend(struct pci_dev* dev, pm_message_t state) struct fb_info *info = pci_get_drvdata(dev); struct vt8623fb_info *par = info->par; - dev_info(&(dev->dev), "suspend\n"); + dev_info(info->dev, "suspend\n"); acquire_console_sem(); mutex_lock(&(par->open_lock)); @@ -842,7 +848,7 @@ static int vt8623_pci_resume(struct pci_dev* dev) struct fb_info *info = pci_get_drvdata(dev); struct vt8623fb_info *par = info->par; - dev_info(&(dev->dev), "resume\n"); + dev_info(info->dev, "resume\n"); acquire_console_sem(); mutex_lock(&(par->open_lock)); @@ -913,7 +919,7 @@ static int __init vt8623fb_init(void) return -ENODEV; if (option && *option) - mode = option; + mode_option = option; #endif pr_debug("vt8623fb: initializing\n"); diff --git a/drivers/video/w100fb.c b/drivers/video/w100fb.c index 003c49a490e..30469bf906e 100644 --- a/drivers/video/w100fb.c +++ b/drivers/video/w100fb.c @@ -765,8 +765,10 @@ int __init w100fb_probe(struct platform_device *pdev) printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, info->fix.id); return 0; out: - fb_dealloc_cmap(&info->cmap); - kfree(info->pseudo_palette); + if (info) { + fb_dealloc_cmap(&info->cmap); + kfree(info->pseudo_palette); + } if (remapped_fbuf != NULL) iounmap(remapped_fbuf); if (remapped_regs != NULL) diff --git a/drivers/zorro/proc.c b/drivers/zorro/proc.c index 2ce4cebc31d..099b6fb5b5c 100644 --- a/drivers/zorro/proc.c +++ b/drivers/zorro/proc.c @@ -13,6 +13,7 @@ #include <linux/types.h> #include <linux/zorro.h> #include <linux/proc_fs.h> +#include <linux/seq_file.h> #include <linux/init.h> #include <linux/smp_lock.h> #include <asm/uaccess.h> @@ -76,36 +77,58 @@ proc_bus_zorro_read(struct file *file, char __user *buf, size_t nbytes, loff_t * } static const struct file_operations proc_bus_zorro_operations = { + .owner = THIS_MODULE, .llseek = proc_bus_zorro_lseek, .read = proc_bus_zorro_read, }; -static int -get_zorro_dev_info(char *buf, char **start, off_t pos, int count) +static void * zorro_seq_start(struct seq_file *m, loff_t *pos) { - u_int slot; - off_t at = 0; - int len, cnt; - - for (slot = cnt = 0; slot < zorro_num_autocon && count > cnt; slot++) { - struct zorro_dev *z = &zorro_autocon[slot]; - len = sprintf(buf, "%02x\t%08x\t%08lx\t%08lx\t%02x\n", slot, - z->id, (unsigned long)zorro_resource_start(z), - (unsigned long)zorro_resource_len(z), - z->rom.er_Type); - at += len; - if (at >= pos) { - if (!*start) { - *start = buf + (pos - (at - len)); - cnt = at - pos; - } else - cnt += len; - buf += len; - } - } - return (count > cnt) ? cnt : count; + return (*pos < zorro_num_autocon) ? pos : NULL; +} + +static void * zorro_seq_next(struct seq_file *m, void *v, loff_t *pos) +{ + (*pos)++; + return (*pos < zorro_num_autocon) ? pos : NULL; +} + +static void zorro_seq_stop(struct seq_file *m, void *v) +{ +} + +static int zorro_seq_show(struct seq_file *m, void *v) +{ + u_int slot = *(loff_t *)v; + struct zorro_dev *z = &zorro_autocon[slot]; + + seq_printf(m, "%02x\t%08x\t%08lx\t%08lx\t%02x\n", slot, z->id, + (unsigned long)zorro_resource_start(z), + (unsigned long)zorro_resource_len(z), + z->rom.er_Type); + return 0; +} + +static const struct seq_operations zorro_devices_seq_ops = { + .start = zorro_seq_start, + .next = zorro_seq_next, + .stop = zorro_seq_stop, + .show = zorro_seq_show, +}; + +static int zorro_devices_proc_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &zorro_devices_seq_ops); } +static const struct file_operations zorro_devices_proc_fops = { + .owner = THIS_MODULE, + .open = zorro_devices_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + static struct proc_dir_entry *proc_bus_zorro_dir; static int __init zorro_proc_attach_device(u_int slot) @@ -114,11 +137,11 @@ static int __init zorro_proc_attach_device(u_int slot) char name[4]; sprintf(name, "%02x", slot); - entry = create_proc_entry(name, 0, proc_bus_zorro_dir); + entry = proc_create_data(name, 0, proc_bus_zorro_dir, + &proc_bus_zorro_operations, + &zorro_autocon[slot]); if (!entry) return -ENOMEM; - entry->proc_fops = &proc_bus_zorro_operations; - entry->data = &zorro_autocon[slot]; entry->size = sizeof(struct zorro_dev); return 0; } @@ -128,9 +151,9 @@ static int __init zorro_proc_init(void) u_int slot; if (MACH_IS_AMIGA && AMIGAHW_PRESENT(ZORRO)) { - proc_bus_zorro_dir = proc_mkdir("zorro", proc_bus); - create_proc_info_entry("devices", 0, proc_bus_zorro_dir, - get_zorro_dev_info); + proc_bus_zorro_dir = proc_mkdir("bus/zorro", NULL); + proc_create("devices", 0, proc_bus_zorro_dir, + &zorro_devices_proc_fops); for (slot = 0; slot < zorro_num_autocon; slot++) zorro_proc_attach_device(slot); } |