diff options
Diffstat (limited to 'drivers')
118 files changed, 8795 insertions, 1804 deletions
diff --git a/drivers/block/viodasd.c b/drivers/block/viodasd.c index f63e07bd9f9c..b0df4f5ab97a 100644 --- a/drivers/block/viodasd.c +++ b/drivers/block/viodasd.c | |||
@@ -747,7 +747,7 @@ static int viodasd_remove(struct vio_dev *vdev) | |||
747 | * support. | 747 | * support. |
748 | */ | 748 | */ |
749 | static struct vio_device_id viodasd_device_table[] __devinitdata = { | 749 | static struct vio_device_id viodasd_device_table[] __devinitdata = { |
750 | { "viodasd", "" }, | 750 | { "block", "IBM,iSeries-viodasd" }, |
751 | { "", "" } | 751 | { "", "" } |
752 | }; | 752 | }; |
753 | MODULE_DEVICE_TABLE(vio, viodasd_device_table); | 753 | MODULE_DEVICE_TABLE(vio, viodasd_device_table); |
diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c index c0f817ba7adb..af6b3bfd169b 100644 --- a/drivers/cdrom/viocd.c +++ b/drivers/cdrom/viocd.c | |||
@@ -731,7 +731,7 @@ static int viocd_remove(struct vio_dev *vdev) | |||
731 | * support. | 731 | * support. |
732 | */ | 732 | */ |
733 | static struct vio_device_id viocd_device_table[] __devinitdata = { | 733 | static struct vio_device_id viocd_device_table[] __devinitdata = { |
734 | { "viocd", "" }, | 734 | { "block", "IBM,iSeries-viocd" }, |
735 | { "", "" } | 735 | { "", "" } |
736 | }; | 736 | }; |
737 | MODULE_DEVICE_TABLE(vio, viocd_device_table); | 737 | MODULE_DEVICE_TABLE(vio, viocd_device_table); |
diff --git a/drivers/char/agp/Kconfig b/drivers/char/agp/Kconfig index 7c88c060a9e6..46685a540772 100644 --- a/drivers/char/agp/Kconfig +++ b/drivers/char/agp/Kconfig | |||
@@ -1,7 +1,6 @@ | |||
1 | config AGP | 1 | config AGP |
2 | tristate "/dev/agpgart (AGP Support)" if !GART_IOMMU | 2 | tristate "/dev/agpgart (AGP Support)" |
3 | depends on ALPHA || IA64 || PPC || X86 | 3 | depends on ALPHA || IA64 || PPC || X86 |
4 | default y if GART_IOMMU | ||
5 | ---help--- | 4 | ---help--- |
6 | AGP (Accelerated Graphics Port) is a bus system mainly used to | 5 | AGP (Accelerated Graphics Port) is a bus system mainly used to |
7 | connect graphics cards to the rest of the system. | 6 | connect graphics cards to the rest of the system. |
diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index 2b6a56b2bf35..a5c6a9d7ff08 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c | |||
@@ -553,7 +553,6 @@ static int hvc_chars_in_buffer(struct tty_struct *tty) | |||
553 | 553 | ||
554 | #define HVC_POLL_READ 0x00000001 | 554 | #define HVC_POLL_READ 0x00000001 |
555 | #define HVC_POLL_WRITE 0x00000002 | 555 | #define HVC_POLL_WRITE 0x00000002 |
556 | #define HVC_POLL_QUICK 0x00000004 | ||
557 | 556 | ||
558 | static int hvc_poll(struct hvc_struct *hp) | 557 | static int hvc_poll(struct hvc_struct *hp) |
559 | { | 558 | { |
@@ -568,6 +567,7 @@ static int hvc_poll(struct hvc_struct *hp) | |||
568 | /* Push pending writes */ | 567 | /* Push pending writes */ |
569 | if (hp->n_outbuf > 0) | 568 | if (hp->n_outbuf > 0) |
570 | hvc_push(hp); | 569 | hvc_push(hp); |
570 | |||
571 | /* Reschedule us if still some write pending */ | 571 | /* Reschedule us if still some write pending */ |
572 | if (hp->n_outbuf > 0) | 572 | if (hp->n_outbuf > 0) |
573 | poll_mask |= HVC_POLL_WRITE; | 573 | poll_mask |= HVC_POLL_WRITE; |
@@ -680,7 +680,7 @@ int khvcd(void *unused) | |||
680 | poll_mask |= HVC_POLL_READ; | 680 | poll_mask |= HVC_POLL_READ; |
681 | if (hvc_kicked) | 681 | if (hvc_kicked) |
682 | continue; | 682 | continue; |
683 | if (poll_mask & HVC_POLL_QUICK) { | 683 | if (poll_mask & HVC_POLL_WRITE) { |
684 | yield(); | 684 | yield(); |
685 | continue; | 685 | continue; |
686 | } | 686 | } |
diff --git a/drivers/char/hvc_rtas.c b/drivers/char/hvc_rtas.c index 83364ea63cba..57106e02fd2e 100644 --- a/drivers/char/hvc_rtas.c +++ b/drivers/char/hvc_rtas.c | |||
@@ -41,37 +41,28 @@ | |||
41 | #define hvc_rtas_cookie 0x67781e15 | 41 | #define hvc_rtas_cookie 0x67781e15 |
42 | struct hvc_struct *hvc_rtas_dev; | 42 | struct hvc_struct *hvc_rtas_dev; |
43 | 43 | ||
44 | #define RTASCONS_PUT_ATTEMPTS 16 | ||
45 | |||
46 | static int rtascons_put_char_token = RTAS_UNKNOWN_SERVICE; | 44 | static int rtascons_put_char_token = RTAS_UNKNOWN_SERVICE; |
47 | static int rtascons_get_char_token = RTAS_UNKNOWN_SERVICE; | 45 | static int rtascons_get_char_token = RTAS_UNKNOWN_SERVICE; |
48 | static int rtascons_put_delay = 100; | ||
49 | module_param_named(put_delay, rtascons_put_delay, int, 0644); | ||
50 | 46 | ||
51 | static inline int hvc_rtas_write_console(uint32_t vtermno, const char *buf, int count) | 47 | static inline int hvc_rtas_write_console(uint32_t vtermno, const char *buf, |
48 | int count) | ||
52 | { | 49 | { |
53 | int done; | 50 | int i; |
54 | 51 | ||
55 | /* if there is more than one character to be displayed, wait a bit */ | 52 | for (i = 0; i < count; i++) { |
56 | for (done = 0; done < count; done++) { | 53 | if (rtas_call(rtascons_put_char_token, 1, 1, NULL, buf[i])) |
57 | int result; | ||
58 | result = rtas_call(rtascons_put_char_token, 1, 1, NULL, buf[done]); | ||
59 | if (result) | ||
60 | break; | 54 | break; |
61 | } | 55 | } |
62 | /* the calling routine expects to receive the number of bytes sent */ | 56 | |
63 | return done; | 57 | return i; |
64 | } | 58 | } |
65 | 59 | ||
66 | static int hvc_rtas_read_console(uint32_t vtermno, char *buf, int count) | 60 | static int hvc_rtas_read_console(uint32_t vtermno, char *buf, int count) |
67 | { | 61 | { |
68 | int i; | 62 | int i, c; |
69 | 63 | ||
70 | for (i = 0; i < count; i++) { | 64 | for (i = 0; i < count; i++) { |
71 | int c, err; | 65 | if (rtas_call(rtascons_get_char_token, 0, 2, &c)) |
72 | |||
73 | err = rtas_call(rtascons_get_char_token, 0, 2, &c); | ||
74 | if (err) | ||
75 | break; | 66 | break; |
76 | 67 | ||
77 | buf[i] = c; | 68 | buf[i] = c; |
@@ -106,7 +97,9 @@ static int hvc_rtas_init(void) | |||
106 | hp = hvc_alloc(hvc_rtas_cookie, NO_IRQ, &hvc_rtas_get_put_ops); | 97 | hp = hvc_alloc(hvc_rtas_cookie, NO_IRQ, &hvc_rtas_get_put_ops); |
107 | if (IS_ERR(hp)) | 98 | if (IS_ERR(hp)) |
108 | return PTR_ERR(hp); | 99 | return PTR_ERR(hp); |
100 | |||
109 | hvc_rtas_dev = hp; | 101 | hvc_rtas_dev = hp; |
102 | |||
110 | return 0; | 103 | return 0; |
111 | } | 104 | } |
112 | module_init(hvc_rtas_init); | 105 | module_init(hvc_rtas_init); |
@@ -114,8 +107,8 @@ module_init(hvc_rtas_init); | |||
114 | /* This will tear down the tty portion of the driver */ | 107 | /* This will tear down the tty portion of the driver */ |
115 | static void __exit hvc_rtas_exit(void) | 108 | static void __exit hvc_rtas_exit(void) |
116 | { | 109 | { |
117 | /* Really the fun isn't over until the worker thread breaks down and the | 110 | /* Really the fun isn't over until the worker thread breaks down and |
118 | * tty cleans up */ | 111 | * the tty cleans up */ |
119 | if (hvc_rtas_dev) | 112 | if (hvc_rtas_dev) |
120 | hvc_remove(hvc_rtas_dev); | 113 | hvc_remove(hvc_rtas_dev); |
121 | } | 114 | } |
@@ -127,12 +120,14 @@ static int hvc_rtas_console_init(void) | |||
127 | rtascons_put_char_token = rtas_token("put-term-char"); | 120 | rtascons_put_char_token = rtas_token("put-term-char"); |
128 | if (rtascons_put_char_token == RTAS_UNKNOWN_SERVICE) | 121 | if (rtascons_put_char_token == RTAS_UNKNOWN_SERVICE) |
129 | return -EIO; | 122 | return -EIO; |
123 | |||
130 | rtascons_get_char_token = rtas_token("get-term-char"); | 124 | rtascons_get_char_token = rtas_token("get-term-char"); |
131 | if (rtascons_get_char_token == RTAS_UNKNOWN_SERVICE) | 125 | if (rtascons_get_char_token == RTAS_UNKNOWN_SERVICE) |
132 | return -EIO; | 126 | return -EIO; |
133 | 127 | ||
134 | hvc_instantiate(hvc_rtas_cookie, 0, &hvc_rtas_get_put_ops ); | 128 | hvc_instantiate(hvc_rtas_cookie, 0, &hvc_rtas_get_put_ops); |
135 | add_preferred_console("hvc", 0, NULL); | 129 | add_preferred_console("hvc", 0, NULL); |
130 | |||
136 | return 0; | 131 | return 0; |
137 | } | 132 | } |
138 | console_initcall(hvc_rtas_console_init); | 133 | console_initcall(hvc_rtas_console_init); |
diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c index a9522189fc9e..a0370ed752ce 100644 --- a/drivers/char/hvsi.c +++ b/drivers/char/hvsi.c | |||
@@ -1179,7 +1179,7 @@ static int __init hvsi_init(void) | |||
1179 | if (tty_register_driver(hvsi_driver)) | 1179 | if (tty_register_driver(hvsi_driver)) |
1180 | panic("Couldn't register hvsi console driver\n"); | 1180 | panic("Couldn't register hvsi console driver\n"); |
1181 | 1181 | ||
1182 | printk(KERN_INFO "HVSI: registered %i devices\n", hvsi_count); | 1182 | printk(KERN_DEBUG "HVSI: registered %i devices\n", hvsi_count); |
1183 | 1183 | ||
1184 | return 0; | 1184 | return 0; |
1185 | } | 1185 | } |
diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c index 60aabdb4a046..11c7e9de5958 100644 --- a/drivers/char/viotape.c +++ b/drivers/char/viotape.c | |||
@@ -989,7 +989,7 @@ static int viotape_remove(struct vio_dev *vdev) | |||
989 | * support. | 989 | * support. |
990 | */ | 990 | */ |
991 | static struct vio_device_id viotape_device_table[] __devinitdata = { | 991 | static struct vio_device_id viotape_device_table[] __devinitdata = { |
992 | { "viotape", "" }, | 992 | { "byte", "IBM,iSeries-viotape" }, |
993 | { "", "" } | 993 | { "", "" } |
994 | }; | 994 | }; |
995 | MODULE_DEVICE_TABLE(vio, viotape_device_table); | 995 | MODULE_DEVICE_TABLE(vio, viotape_device_table); |
diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c index e07a35487bde..8878a154ed43 100644 --- a/drivers/cpufreq/cpufreq_conservative.c +++ b/drivers/cpufreq/cpufreq_conservative.c | |||
@@ -72,6 +72,14 @@ static DEFINE_PER_CPU(struct cpu_dbs_info_s, cpu_dbs_info); | |||
72 | 72 | ||
73 | static unsigned int dbs_enable; /* number of CPUs using this policy */ | 73 | static unsigned int dbs_enable; /* number of CPUs using this policy */ |
74 | 74 | ||
75 | /* | ||
76 | * DEADLOCK ALERT! There is a ordering requirement between cpu_hotplug | ||
77 | * lock and dbs_mutex. cpu_hotplug lock should always be held before | ||
78 | * dbs_mutex. If any function that can potentially take cpu_hotplug lock | ||
79 | * (like __cpufreq_driver_target()) is being called with dbs_mutex taken, then | ||
80 | * cpu_hotplug lock should be taken before that. Note that cpu_hotplug lock | ||
81 | * is recursive for the same process. -Venki | ||
82 | */ | ||
75 | static DEFINE_MUTEX (dbs_mutex); | 83 | static DEFINE_MUTEX (dbs_mutex); |
76 | static DECLARE_WORK (dbs_work, do_dbs_timer, NULL); | 84 | static DECLARE_WORK (dbs_work, do_dbs_timer, NULL); |
77 | 85 | ||
@@ -414,12 +422,14 @@ static void dbs_check_cpu(int cpu) | |||
414 | static void do_dbs_timer(void *data) | 422 | static void do_dbs_timer(void *data) |
415 | { | 423 | { |
416 | int i; | 424 | int i; |
425 | lock_cpu_hotplug(); | ||
417 | mutex_lock(&dbs_mutex); | 426 | mutex_lock(&dbs_mutex); |
418 | for_each_online_cpu(i) | 427 | for_each_online_cpu(i) |
419 | dbs_check_cpu(i); | 428 | dbs_check_cpu(i); |
420 | schedule_delayed_work(&dbs_work, | 429 | schedule_delayed_work(&dbs_work, |
421 | usecs_to_jiffies(dbs_tuners_ins.sampling_rate)); | 430 | usecs_to_jiffies(dbs_tuners_ins.sampling_rate)); |
422 | mutex_unlock(&dbs_mutex); | 431 | mutex_unlock(&dbs_mutex); |
432 | unlock_cpu_hotplug(); | ||
423 | } | 433 | } |
424 | 434 | ||
425 | static inline void dbs_timer_init(void) | 435 | static inline void dbs_timer_init(void) |
@@ -514,6 +524,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy, | |||
514 | break; | 524 | break; |
515 | 525 | ||
516 | case CPUFREQ_GOV_LIMITS: | 526 | case CPUFREQ_GOV_LIMITS: |
527 | lock_cpu_hotplug(); | ||
517 | mutex_lock(&dbs_mutex); | 528 | mutex_lock(&dbs_mutex); |
518 | if (policy->max < this_dbs_info->cur_policy->cur) | 529 | if (policy->max < this_dbs_info->cur_policy->cur) |
519 | __cpufreq_driver_target( | 530 | __cpufreq_driver_target( |
@@ -524,6 +535,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy, | |||
524 | this_dbs_info->cur_policy, | 535 | this_dbs_info->cur_policy, |
525 | policy->min, CPUFREQ_RELATION_L); | 536 | policy->min, CPUFREQ_RELATION_L); |
526 | mutex_unlock(&dbs_mutex); | 537 | mutex_unlock(&dbs_mutex); |
538 | unlock_cpu_hotplug(); | ||
527 | break; | 539 | break; |
528 | } | 540 | } |
529 | return 0; | 541 | return 0; |
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index 3e6ffcaa5af4..4d308410b60e 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c | |||
@@ -71,6 +71,14 @@ static DEFINE_PER_CPU(struct cpu_dbs_info_s, cpu_dbs_info); | |||
71 | 71 | ||
72 | static unsigned int dbs_enable; /* number of CPUs using this policy */ | 72 | static unsigned int dbs_enable; /* number of CPUs using this policy */ |
73 | 73 | ||
74 | /* | ||
75 | * DEADLOCK ALERT! There is a ordering requirement between cpu_hotplug | ||
76 | * lock and dbs_mutex. cpu_hotplug lock should always be held before | ||
77 | * dbs_mutex. If any function that can potentially take cpu_hotplug lock | ||
78 | * (like __cpufreq_driver_target()) is being called with dbs_mutex taken, then | ||
79 | * cpu_hotplug lock should be taken before that. Note that cpu_hotplug lock | ||
80 | * is recursive for the same process. -Venki | ||
81 | */ | ||
74 | static DEFINE_MUTEX (dbs_mutex); | 82 | static DEFINE_MUTEX (dbs_mutex); |
75 | static DECLARE_WORK (dbs_work, do_dbs_timer, NULL); | 83 | static DECLARE_WORK (dbs_work, do_dbs_timer, NULL); |
76 | 84 | ||
@@ -363,12 +371,14 @@ static void dbs_check_cpu(int cpu) | |||
363 | static void do_dbs_timer(void *data) | 371 | static void do_dbs_timer(void *data) |
364 | { | 372 | { |
365 | int i; | 373 | int i; |
374 | lock_cpu_hotplug(); | ||
366 | mutex_lock(&dbs_mutex); | 375 | mutex_lock(&dbs_mutex); |
367 | for_each_online_cpu(i) | 376 | for_each_online_cpu(i) |
368 | dbs_check_cpu(i); | 377 | dbs_check_cpu(i); |
369 | queue_delayed_work(dbs_workq, &dbs_work, | 378 | queue_delayed_work(dbs_workq, &dbs_work, |
370 | usecs_to_jiffies(dbs_tuners_ins.sampling_rate)); | 379 | usecs_to_jiffies(dbs_tuners_ins.sampling_rate)); |
371 | mutex_unlock(&dbs_mutex); | 380 | mutex_unlock(&dbs_mutex); |
381 | unlock_cpu_hotplug(); | ||
372 | } | 382 | } |
373 | 383 | ||
374 | static inline void dbs_timer_init(void) | 384 | static inline void dbs_timer_init(void) |
@@ -469,6 +479,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy, | |||
469 | break; | 479 | break; |
470 | 480 | ||
471 | case CPUFREQ_GOV_LIMITS: | 481 | case CPUFREQ_GOV_LIMITS: |
482 | lock_cpu_hotplug(); | ||
472 | mutex_lock(&dbs_mutex); | 483 | mutex_lock(&dbs_mutex); |
473 | if (policy->max < this_dbs_info->cur_policy->cur) | 484 | if (policy->max < this_dbs_info->cur_policy->cur) |
474 | __cpufreq_driver_target( | 485 | __cpufreq_driver_target( |
@@ -479,6 +490,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy, | |||
479 | this_dbs_info->cur_policy, | 490 | this_dbs_info->cur_policy, |
480 | policy->min, CPUFREQ_RELATION_L); | 491 | policy->min, CPUFREQ_RELATION_L); |
481 | mutex_unlock(&dbs_mutex); | 492 | mutex_unlock(&dbs_mutex); |
493 | unlock_cpu_hotplug(); | ||
482 | break; | 494 | break; |
483 | } | 495 | } |
484 | return 0; | 496 | return 0; |
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 99cdc612d2c6..0e31a0c496e8 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig | |||
@@ -1,5 +1,5 @@ | |||
1 | # | 1 | # |
2 | # I2C Sensor chip drivers configuration | 2 | # Hardware monitoring chip drivers configuration |
3 | # | 3 | # |
4 | 4 | ||
5 | menu "Hardware Monitoring support" | 5 | menu "Hardware Monitoring support" |
@@ -16,6 +16,10 @@ config HWMON | |||
16 | should say Y here and also to the specific driver(s) for your | 16 | should say Y here and also to the specific driver(s) for your |
17 | sensors chip(s) below. | 17 | sensors chip(s) below. |
18 | 18 | ||
19 | To find out which specific driver(s) you need, use the | ||
20 | sensors-detect script from the lm_sensors package. Read | ||
21 | <file:Documentation/hwmon/userspace-tools> for details. | ||
22 | |||
19 | This support can also be built as a module. If so, the module | 23 | This support can also be built as a module. If so, the module |
20 | will be called hwmon. | 24 | will be called hwmon. |
21 | 25 | ||
@@ -23,6 +27,18 @@ config HWMON_VID | |||
23 | tristate | 27 | tristate |
24 | default n | 28 | default n |
25 | 29 | ||
30 | config SENSORS_ABITUGURU | ||
31 | tristate "Abit uGuru" | ||
32 | depends on HWMON && EXPERIMENTAL | ||
33 | help | ||
34 | If you say yes here you get support for the Abit uGuru chips | ||
35 | sensor part. The voltage and frequency control parts of the Abit | ||
36 | uGuru are not supported. The Abit uGuru chip can be found on Abit | ||
37 | uGuru featuring motherboards (most modern Abit motherboards). | ||
38 | |||
39 | This driver can also be built as a module. If so, the module | ||
40 | will be called abituguru. | ||
41 | |||
26 | config SENSORS_ADM1021 | 42 | config SENSORS_ADM1021 |
27 | tristate "Analog Devices ADM1021 and compatibles" | 43 | tristate "Analog Devices ADM1021 and compatibles" |
28 | depends on HWMON && I2C | 44 | depends on HWMON && I2C |
@@ -188,6 +204,16 @@ config SENSORS_LM63 | |||
188 | This driver can also be built as a module. If so, the module | 204 | This driver can also be built as a module. If so, the module |
189 | will be called lm63. | 205 | will be called lm63. |
190 | 206 | ||
207 | config SENSORS_LM70 | ||
208 | tristate "National Semiconductor LM70" | ||
209 | depends on HWMON && SPI_MASTER && EXPERIMENTAL | ||
210 | help | ||
211 | If you say yes here you get support for the National Semiconductor | ||
212 | LM70 digital temperature sensor chip. | ||
213 | |||
214 | This driver can also be built as a module. If so, the module | ||
215 | will be called lm70. | ||
216 | |||
191 | config SENSORS_LM75 | 217 | config SENSORS_LM75 |
192 | tristate "National Semiconductor LM75 and compatibles" | 218 | tristate "National Semiconductor LM75 and compatibles" |
193 | depends on HWMON && I2C | 219 | depends on HWMON && I2C |
@@ -236,11 +262,11 @@ config SENSORS_LM80 | |||
236 | will be called lm80. | 262 | will be called lm80. |
237 | 263 | ||
238 | config SENSORS_LM83 | 264 | config SENSORS_LM83 |
239 | tristate "National Semiconductor LM83" | 265 | tristate "National Semiconductor LM83 and compatibles" |
240 | depends on HWMON && I2C | 266 | depends on HWMON && I2C |
241 | help | 267 | help |
242 | If you say yes here you get support for National Semiconductor | 268 | If you say yes here you get support for National Semiconductor |
243 | LM83 sensor chips. | 269 | LM82 and LM83 sensor chips. |
244 | 270 | ||
245 | This driver can also be built as a module. If so, the module | 271 | This driver can also be built as a module. If so, the module |
246 | will be called lm83. | 272 | will be called lm83. |
@@ -333,11 +359,32 @@ config SENSORS_SMSC47M1 | |||
333 | help | 359 | help |
334 | If you say yes here you get support for the integrated fan | 360 | If you say yes here you get support for the integrated fan |
335 | monitoring and control capabilities of the SMSC LPC47B27x, | 361 | monitoring and control capabilities of the SMSC LPC47B27x, |
336 | LPC47M10x, LPC47M13x, LPC47M14x, LPC47M15x and LPC47M192 chips. | 362 | LPC47M10x, LPC47M13x, LPC47M14x, LPC47M15x, LPC47M192 and |
363 | LPC47M997 chips. | ||
364 | |||
365 | The temperature and voltage sensor features of the LPC47M192 | ||
366 | and LPC47M997 are supported by another driver, select also | ||
367 | "SMSC LPC47M192 and compatibles" below for those. | ||
337 | 368 | ||
338 | This driver can also be built as a module. If so, the module | 369 | This driver can also be built as a module. If so, the module |
339 | will be called smsc47m1. | 370 | will be called smsc47m1. |
340 | 371 | ||
372 | config SENSORS_SMSC47M192 | ||
373 | tristate "SMSC LPC47M192 and compatibles" | ||
374 | depends on HWMON && I2C && EXPERIMENTAL | ||
375 | select HWMON_VID | ||
376 | help | ||
377 | If you say yes here you get support for the temperature and | ||
378 | voltage sensors of the SMSC LPC47M192 and LPC47M997 chips. | ||
379 | |||
380 | The fan monitoring and control capabilities of these chips | ||
381 | are supported by another driver, select | ||
382 | "SMSC LPC47M10x and compatibles" above. You need both drivers | ||
383 | if you want fan control and voltage/temperature sensor support. | ||
384 | |||
385 | This driver can also be built as a module. If so, the module | ||
386 | will be called smsc47m192. | ||
387 | |||
341 | config SENSORS_SMSC47B397 | 388 | config SENSORS_SMSC47B397 |
342 | tristate "SMSC LPC47B397-NC" | 389 | tristate "SMSC LPC47B397-NC" |
343 | depends on HWMON && I2C && EXPERIMENTAL | 390 | depends on HWMON && I2C && EXPERIMENTAL |
@@ -385,6 +432,16 @@ config SENSORS_W83781D | |||
385 | This driver can also be built as a module. If so, the module | 432 | This driver can also be built as a module. If so, the module |
386 | will be called w83781d. | 433 | will be called w83781d. |
387 | 434 | ||
435 | config SENSORS_W83791D | ||
436 | tristate "Winbond W83791D" | ||
437 | depends on HWMON && I2C && EXPERIMENTAL | ||
438 | select HWMON_VID | ||
439 | help | ||
440 | If you say yes here you get support for the Winbond W83791D chip. | ||
441 | |||
442 | This driver can also be built as a module. If so, the module | ||
443 | will be called w83791d. | ||
444 | |||
388 | config SENSORS_W83792D | 445 | config SENSORS_W83792D |
389 | tristate "Winbond W83792D" | 446 | tristate "Winbond W83792D" |
390 | depends on HWMON && I2C && EXPERIMENTAL | 447 | depends on HWMON && I2C && EXPERIMENTAL |
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index fbdb8d911a72..31415843a91a 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile | |||
@@ -10,7 +10,9 @@ obj-$(CONFIG_SENSORS_ASB100) += asb100.o | |||
10 | obj-$(CONFIG_SENSORS_W83627HF) += w83627hf.o | 10 | obj-$(CONFIG_SENSORS_W83627HF) += w83627hf.o |
11 | obj-$(CONFIG_SENSORS_W83792D) += w83792d.o | 11 | obj-$(CONFIG_SENSORS_W83792D) += w83792d.o |
12 | obj-$(CONFIG_SENSORS_W83781D) += w83781d.o | 12 | obj-$(CONFIG_SENSORS_W83781D) += w83781d.o |
13 | obj-$(CONFIG_SENSORS_W83791D) += w83791d.o | ||
13 | 14 | ||
15 | obj-$(CONFIG_SENSORS_ABITUGURU) += abituguru.o | ||
14 | obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o | 16 | obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o |
15 | obj-$(CONFIG_SENSORS_ADM1025) += adm1025.o | 17 | obj-$(CONFIG_SENSORS_ADM1025) += adm1025.o |
16 | obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o | 18 | obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o |
@@ -26,6 +28,7 @@ obj-$(CONFIG_SENSORS_GL520SM) += gl520sm.o | |||
26 | obj-$(CONFIG_SENSORS_HDAPS) += hdaps.o | 28 | obj-$(CONFIG_SENSORS_HDAPS) += hdaps.o |
27 | obj-$(CONFIG_SENSORS_IT87) += it87.o | 29 | obj-$(CONFIG_SENSORS_IT87) += it87.o |
28 | obj-$(CONFIG_SENSORS_LM63) += lm63.o | 30 | obj-$(CONFIG_SENSORS_LM63) += lm63.o |
31 | obj-$(CONFIG_SENSORS_LM70) += lm70.o | ||
29 | obj-$(CONFIG_SENSORS_LM75) += lm75.o | 32 | obj-$(CONFIG_SENSORS_LM75) += lm75.o |
30 | obj-$(CONFIG_SENSORS_LM77) += lm77.o | 33 | obj-$(CONFIG_SENSORS_LM77) += lm77.o |
31 | obj-$(CONFIG_SENSORS_LM78) += lm78.o | 34 | obj-$(CONFIG_SENSORS_LM78) += lm78.o |
@@ -40,6 +43,7 @@ obj-$(CONFIG_SENSORS_PC87360) += pc87360.o | |||
40 | obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o | 43 | obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o |
41 | obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o | 44 | obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o |
42 | obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o | 45 | obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o |
46 | obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o | ||
43 | obj-$(CONFIG_SENSORS_VIA686A) += via686a.o | 47 | obj-$(CONFIG_SENSORS_VIA686A) += via686a.o |
44 | obj-$(CONFIG_SENSORS_VT8231) += vt8231.o | 48 | obj-$(CONFIG_SENSORS_VT8231) += vt8231.o |
45 | obj-$(CONFIG_SENSORS_W83627EHF) += w83627ehf.o | 49 | obj-$(CONFIG_SENSORS_W83627EHF) += w83627ehf.o |
diff --git a/drivers/hwmon/abituguru.c b/drivers/hwmon/abituguru.c new file mode 100644 index 000000000000..59122cc0a50a --- /dev/null +++ b/drivers/hwmon/abituguru.c | |||
@@ -0,0 +1,1415 @@ | |||
1 | /* | ||
2 | abituguru.c Copyright (c) 2005-2006 Hans de Goede <j.w.r.degoede@hhs.nl> | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2 of the License, or | ||
7 | (at your option) any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program; if not, write to the Free Software | ||
16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
17 | */ | ||
18 | /* | ||
19 | This driver supports the sensor part of the custom Abit uGuru chip found | ||
20 | on Abit uGuru motherboards. Note: because of lack of specs the CPU / RAM / | ||
21 | etc voltage & frequency control is not supported! | ||
22 | */ | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/slab.h> | ||
26 | #include <linux/jiffies.h> | ||
27 | #include <linux/mutex.h> | ||
28 | #include <linux/err.h> | ||
29 | #include <linux/platform_device.h> | ||
30 | #include <linux/hwmon.h> | ||
31 | #include <linux/hwmon-sysfs.h> | ||
32 | #include <asm/io.h> | ||
33 | |||
34 | /* Banks */ | ||
35 | #define ABIT_UGURU_ALARM_BANK 0x20 /* 1x 3 bytes */ | ||
36 | #define ABIT_UGURU_SENSOR_BANK1 0x21 /* 16x volt and temp */ | ||
37 | #define ABIT_UGURU_FAN_PWM 0x24 /* 3x 5 bytes */ | ||
38 | #define ABIT_UGURU_SENSOR_BANK2 0x26 /* fans */ | ||
39 | /* max nr of sensors in bank1, a bank1 sensor can be in, temp or nc */ | ||
40 | #define ABIT_UGURU_MAX_BANK1_SENSORS 16 | ||
41 | /* Warning if you increase one of the 2 MAX defines below to 10 or higher you | ||
42 | should adjust the belonging _NAMES_LENGTH macro for the 2 digit number! */ | ||
43 | /* max nr of sensors in bank2, currently mb's with max 6 fans are known */ | ||
44 | #define ABIT_UGURU_MAX_BANK2_SENSORS 6 | ||
45 | /* max nr of pwm outputs, currently mb's with max 5 pwm outputs are known */ | ||
46 | #define ABIT_UGURU_MAX_PWMS 5 | ||
47 | /* uGuru sensor bank 1 flags */ /* Alarm if: */ | ||
48 | #define ABIT_UGURU_TEMP_HIGH_ALARM_ENABLE 0x01 /* temp over warn */ | ||
49 | #define ABIT_UGURU_VOLT_HIGH_ALARM_ENABLE 0x02 /* volt over max */ | ||
50 | #define ABIT_UGURU_VOLT_LOW_ALARM_ENABLE 0x04 /* volt under min */ | ||
51 | #define ABIT_UGURU_TEMP_HIGH_ALARM_FLAG 0x10 /* temp is over warn */ | ||
52 | #define ABIT_UGURU_VOLT_HIGH_ALARM_FLAG 0x20 /* volt is over max */ | ||
53 | #define ABIT_UGURU_VOLT_LOW_ALARM_FLAG 0x40 /* volt is under min */ | ||
54 | /* uGuru sensor bank 2 flags */ /* Alarm if: */ | ||
55 | #define ABIT_UGURU_FAN_LOW_ALARM_ENABLE 0x01 /* fan under min */ | ||
56 | /* uGuru sensor bank common flags */ | ||
57 | #define ABIT_UGURU_BEEP_ENABLE 0x08 /* beep if alarm */ | ||
58 | #define ABIT_UGURU_SHUTDOWN_ENABLE 0x80 /* shutdown if alarm */ | ||
59 | /* uGuru fan PWM (speed control) flags */ | ||
60 | #define ABIT_UGURU_FAN_PWM_ENABLE 0x80 /* enable speed control */ | ||
61 | /* Values used for conversion */ | ||
62 | #define ABIT_UGURU_FAN_MAX 15300 /* RPM */ | ||
63 | /* Bank1 sensor types */ | ||
64 | #define ABIT_UGURU_IN_SENSOR 0 | ||
65 | #define ABIT_UGURU_TEMP_SENSOR 1 | ||
66 | #define ABIT_UGURU_NC 2 | ||
67 | /* Timeouts / Retries, if these turn out to need a lot of fiddling we could | ||
68 | convert them to params. */ | ||
69 | /* 250 was determined by trial and error, 200 works most of the time, but not | ||
70 | always. I assume this is cpu-speed independent, since the ISA-bus and not | ||
71 | the CPU should be the bottleneck. Note that 250 sometimes is still not | ||
72 | enough (only reported on AN7 mb) this is handled by a higher layer. */ | ||
73 | #define ABIT_UGURU_WAIT_TIMEOUT 250 | ||
74 | /* Normally all expected status in abituguru_ready, are reported after the | ||
75 | first read, but sometimes not and we need to poll, 5 polls was not enough | ||
76 | 50 sofar is. */ | ||
77 | #define ABIT_UGURU_READY_TIMEOUT 50 | ||
78 | /* Maximum 3 retries on timedout reads/writes, delay 200 ms before retrying */ | ||
79 | #define ABIT_UGURU_MAX_RETRIES 3 | ||
80 | #define ABIT_UGURU_RETRY_DELAY (HZ/5) | ||
81 | /* Maximum 2 timeouts in abituguru_update_device, iow 3 in a row is an error */ | ||
82 | #define ABIT_UGURU_MAX_TIMEOUTS 2 | ||
83 | /* utility macros */ | ||
84 | #define ABIT_UGURU_NAME "abituguru" | ||
85 | #define ABIT_UGURU_DEBUG(level, format, arg...) \ | ||
86 | if (level <= verbose) \ | ||
87 | printk(KERN_DEBUG ABIT_UGURU_NAME ": " format , ## arg) | ||
88 | /* Macros to help calculate the sysfs_names array length */ | ||
89 | /* sum of strlen of: in??_input\0, in??_{min,max}\0, in??_{min,max}_alarm\0, | ||
90 | in??_{min,max}_alarm_enable\0, in??_beep\0, in??_shutdown\0 */ | ||
91 | #define ABITUGURU_IN_NAMES_LENGTH (11 + 2 * 9 + 2 * 15 + 2 * 22 + 10 + 14) | ||
92 | /* sum of strlen of: temp??_input\0, temp??_max\0, temp??_crit\0, | ||
93 | temp??_alarm\0, temp??_alarm_enable\0, temp??_beep\0, temp??_shutdown\0 */ | ||
94 | #define ABITUGURU_TEMP_NAMES_LENGTH (13 + 11 + 12 + 13 + 20 + 12 + 16) | ||
95 | /* sum of strlen of: fan?_input\0, fan?_min\0, fan?_alarm\0, | ||
96 | fan?_alarm_enable\0, fan?_beep\0, fan?_shutdown\0 */ | ||
97 | #define ABITUGURU_FAN_NAMES_LENGTH (11 + 9 + 11 + 18 + 10 + 14) | ||
98 | /* sum of strlen of: pwm?_enable\0, pwm?_auto_channels_temp\0, | ||
99 | pwm?_auto_point{1,2}_pwm\0, pwm?_auto_point{1,2}_temp\0 */ | ||
100 | #define ABITUGURU_PWM_NAMES_LENGTH (12 + 24 + 2 * 21 + 2 * 22) | ||
101 | /* IN_NAMES_LENGTH > TEMP_NAMES_LENGTH so assume all bank1 sensors are in */ | ||
102 | #define ABITUGURU_SYSFS_NAMES_LENGTH ( \ | ||
103 | ABIT_UGURU_MAX_BANK1_SENSORS * ABITUGURU_IN_NAMES_LENGTH + \ | ||
104 | ABIT_UGURU_MAX_BANK2_SENSORS * ABITUGURU_FAN_NAMES_LENGTH + \ | ||
105 | ABIT_UGURU_MAX_PWMS * ABITUGURU_PWM_NAMES_LENGTH) | ||
106 | |||
107 | /* All the macros below are named identical to the oguru and oguru2 programs | ||
108 | reverse engineered by Olle Sandberg, hence the names might not be 100% | ||
109 | logical. I could come up with better names, but I prefer keeping the names | ||
110 | identical so that this driver can be compared with his work more easily. */ | ||
111 | /* Two i/o-ports are used by uGuru */ | ||
112 | #define ABIT_UGURU_BASE 0x00E0 | ||
113 | /* Used to tell uGuru what to read and to read the actual data */ | ||
114 | #define ABIT_UGURU_CMD 0x00 | ||
115 | /* Mostly used to check if uGuru is busy */ | ||
116 | #define ABIT_UGURU_DATA 0x04 | ||
117 | #define ABIT_UGURU_REGION_LENGTH 5 | ||
118 | /* uGuru status' */ | ||
119 | #define ABIT_UGURU_STATUS_WRITE 0x00 /* Ready to be written */ | ||
120 | #define ABIT_UGURU_STATUS_READ 0x01 /* Ready to be read */ | ||
121 | #define ABIT_UGURU_STATUS_INPUT 0x08 /* More input */ | ||
122 | #define ABIT_UGURU_STATUS_READY 0x09 /* Ready to be written */ | ||
123 | |||
124 | /* Constants */ | ||
125 | /* in (Volt) sensors go up to 3494 mV, temp to 255000 millidegrees Celsius */ | ||
126 | static const int abituguru_bank1_max_value[2] = { 3494, 255000 }; | ||
127 | /* Min / Max allowed values for sensor2 (fan) alarm threshold, these values | ||
128 | correspond to 300-3000 RPM */ | ||
129 | static const u8 abituguru_bank2_min_threshold = 5; | ||
130 | static const u8 abituguru_bank2_max_threshold = 50; | ||
131 | /* Register 0 is a bitfield, 1 and 2 are pwm settings (255 = 100%), 3 and 4 | ||
132 | are temperature trip points. */ | ||
133 | static const int abituguru_pwm_settings_multiplier[5] = { 0, 1, 1, 1000, 1000 }; | ||
134 | /* Min / Max allowed values for pwm_settings. Note: pwm1 (CPU fan) is a | ||
135 | special case the minium allowed pwm% setting for this is 30% (77) on | ||
136 | some MB's this special case is handled in the code! */ | ||
137 | static const u8 abituguru_pwm_min[5] = { 0, 170, 170, 25, 25 }; | ||
138 | static const u8 abituguru_pwm_max[5] = { 0, 255, 255, 75, 75 }; | ||
139 | |||
140 | |||
141 | /* Insmod parameters */ | ||
142 | static int force; | ||
143 | module_param(force, bool, 0); | ||
144 | MODULE_PARM_DESC(force, "Set to one to force detection."); | ||
145 | static int fan_sensors; | ||
146 | module_param(fan_sensors, int, 0); | ||
147 | MODULE_PARM_DESC(fan_sensors, "Number of fan sensors on the uGuru " | ||
148 | "(0 = autodetect)"); | ||
149 | static int pwms; | ||
150 | module_param(pwms, int, 0); | ||
151 | MODULE_PARM_DESC(pwms, "Number of PWMs on the uGuru " | ||
152 | "(0 = autodetect)"); | ||
153 | |||
154 | /* Default verbose is 2, since this driver is still in the testing phase */ | ||
155 | static int verbose = 2; | ||
156 | module_param(verbose, int, 0644); | ||
157 | MODULE_PARM_DESC(verbose, "How verbose should the driver be? (0-3):\n" | ||
158 | " 0 normal output\n" | ||
159 | " 1 + verbose error reporting\n" | ||
160 | " 2 + sensors type probing info\n" | ||
161 | " 3 + retryable error reporting"); | ||
162 | |||
163 | |||
164 | /* For the Abit uGuru, we need to keep some data in memory. | ||
165 | The structure is dynamically allocated, at the same time when a new | ||
166 | abituguru device is allocated. */ | ||
167 | struct abituguru_data { | ||
168 | struct class_device *class_dev; /* hwmon registered device */ | ||
169 | struct mutex update_lock; /* protect access to data and uGuru */ | ||
170 | unsigned long last_updated; /* In jiffies */ | ||
171 | unsigned short addr; /* uguru base address */ | ||
172 | char uguru_ready; /* is the uguru in ready state? */ | ||
173 | unsigned char update_timeouts; /* number of update timeouts since last | ||
174 | successful update */ | ||
175 | |||
176 | /* The sysfs attr and their names are generated automatically, for bank1 | ||
177 | we cannot use a predefined array because we don't know beforehand | ||
178 | of a sensor is a volt or a temp sensor, for bank2 and the pwms its | ||
179 | easier todo things the same way. For in sensors we have 9 (temp 7) | ||
180 | sysfs entries per sensor, for bank2 and pwms 6. */ | ||
181 | struct sensor_device_attribute_2 sysfs_attr[ | ||
182 | ABIT_UGURU_MAX_BANK1_SENSORS * 9 + | ||
183 | ABIT_UGURU_MAX_BANK2_SENSORS * 6 + ABIT_UGURU_MAX_PWMS * 6]; | ||
184 | /* Buffer to store the dynamically generated sysfs names */ | ||
185 | char sysfs_names[ABITUGURU_SYSFS_NAMES_LENGTH]; | ||
186 | |||
187 | /* Bank 1 data */ | ||
188 | /* number of and addresses of [0] in, [1] temp sensors */ | ||
189 | u8 bank1_sensors[2]; | ||
190 | u8 bank1_address[2][ABIT_UGURU_MAX_BANK1_SENSORS]; | ||
191 | u8 bank1_value[ABIT_UGURU_MAX_BANK1_SENSORS]; | ||
192 | /* This array holds 3 entries per sensor for the bank 1 sensor settings | ||
193 | (flags, min, max for voltage / flags, warn, shutdown for temp). */ | ||
194 | u8 bank1_settings[ABIT_UGURU_MAX_BANK1_SENSORS][3]; | ||
195 | /* Maximum value for each sensor used for scaling in mV/millidegrees | ||
196 | Celsius. */ | ||
197 | int bank1_max_value[ABIT_UGURU_MAX_BANK1_SENSORS]; | ||
198 | |||
199 | /* Bank 2 data, ABIT_UGURU_MAX_BANK2_SENSORS entries for bank2 */ | ||
200 | u8 bank2_sensors; /* actual number of bank2 sensors found */ | ||
201 | u8 bank2_value[ABIT_UGURU_MAX_BANK2_SENSORS]; | ||
202 | u8 bank2_settings[ABIT_UGURU_MAX_BANK2_SENSORS][2]; /* flags, min */ | ||
203 | |||
204 | /* Alarms 2 bytes for bank1, 1 byte for bank2 */ | ||
205 | u8 alarms[3]; | ||
206 | |||
207 | /* Fan PWM (speed control) 5 bytes per PWM */ | ||
208 | u8 pwms; /* actual number of pwms found */ | ||
209 | u8 pwm_settings[ABIT_UGURU_MAX_PWMS][5]; | ||
210 | }; | ||
211 | |||
212 | /* wait till the uguru is in the specified state */ | ||
213 | static int abituguru_wait(struct abituguru_data *data, u8 state) | ||
214 | { | ||
215 | int timeout = ABIT_UGURU_WAIT_TIMEOUT; | ||
216 | |||
217 | while (inb_p(data->addr + ABIT_UGURU_DATA) != state) { | ||
218 | timeout--; | ||
219 | if (timeout == 0) | ||
220 | return -EBUSY; | ||
221 | } | ||
222 | return 0; | ||
223 | } | ||
224 | |||
225 | /* Put the uguru in ready for input state */ | ||
226 | static int abituguru_ready(struct abituguru_data *data) | ||
227 | { | ||
228 | int timeout = ABIT_UGURU_READY_TIMEOUT; | ||
229 | |||
230 | if (data->uguru_ready) | ||
231 | return 0; | ||
232 | |||
233 | /* Reset? / Prepare for next read/write cycle */ | ||
234 | outb(0x00, data->addr + ABIT_UGURU_DATA); | ||
235 | |||
236 | /* Wait till the uguru is ready */ | ||
237 | if (abituguru_wait(data, ABIT_UGURU_STATUS_READY)) { | ||
238 | ABIT_UGURU_DEBUG(1, | ||
239 | "timeout exceeded waiting for ready state\n"); | ||
240 | return -EIO; | ||
241 | } | ||
242 | |||
243 | /* Cmd port MUST be read now and should contain 0xAC */ | ||
244 | while (inb_p(data->addr + ABIT_UGURU_CMD) != 0xAC) { | ||
245 | timeout--; | ||
246 | if (timeout == 0) { | ||
247 | ABIT_UGURU_DEBUG(1, | ||
248 | "CMD reg does not hold 0xAC after ready command\n"); | ||
249 | return -EIO; | ||
250 | } | ||
251 | } | ||
252 | |||
253 | /* After this the ABIT_UGURU_DATA port should contain | ||
254 | ABIT_UGURU_STATUS_INPUT */ | ||
255 | timeout = ABIT_UGURU_READY_TIMEOUT; | ||
256 | while (inb_p(data->addr + ABIT_UGURU_DATA) != ABIT_UGURU_STATUS_INPUT) { | ||
257 | timeout--; | ||
258 | if (timeout == 0) { | ||
259 | ABIT_UGURU_DEBUG(1, | ||
260 | "state != more input after ready command\n"); | ||
261 | return -EIO; | ||
262 | } | ||
263 | } | ||
264 | |||
265 | data->uguru_ready = 1; | ||
266 | return 0; | ||
267 | } | ||
268 | |||
269 | /* Send the bank and then sensor address to the uGuru for the next read/write | ||
270 | cycle. This function gets called as the first part of a read/write by | ||
271 | abituguru_read and abituguru_write. This function should never be | ||
272 | called by any other function. */ | ||
273 | static int abituguru_send_address(struct abituguru_data *data, | ||
274 | u8 bank_addr, u8 sensor_addr, int retries) | ||
275 | { | ||
276 | /* assume the caller does error handling itself if it has not requested | ||
277 | any retries, and thus be quiet. */ | ||
278 | int report_errors = retries; | ||
279 | |||
280 | for (;;) { | ||
281 | /* Make sure the uguru is ready and then send the bank address, | ||
282 | after this the uguru is no longer "ready". */ | ||
283 | if (abituguru_ready(data) != 0) | ||
284 | return -EIO; | ||
285 | outb(bank_addr, data->addr + ABIT_UGURU_DATA); | ||
286 | data->uguru_ready = 0; | ||
287 | |||
288 | /* Wait till the uguru is ABIT_UGURU_STATUS_INPUT state again | ||
289 | and send the sensor addr */ | ||
290 | if (abituguru_wait(data, ABIT_UGURU_STATUS_INPUT)) { | ||
291 | if (retries) { | ||
292 | ABIT_UGURU_DEBUG(3, "timeout exceeded " | ||
293 | "waiting for more input state, %d " | ||
294 | "tries remaining\n", retries); | ||
295 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
296 | schedule_timeout(ABIT_UGURU_RETRY_DELAY); | ||
297 | retries--; | ||
298 | continue; | ||
299 | } | ||
300 | if (report_errors) | ||
301 | ABIT_UGURU_DEBUG(1, "timeout exceeded " | ||
302 | "waiting for more input state " | ||
303 | "(bank: %d)\n", (int)bank_addr); | ||
304 | return -EBUSY; | ||
305 | } | ||
306 | outb(sensor_addr, data->addr + ABIT_UGURU_CMD); | ||
307 | return 0; | ||
308 | } | ||
309 | } | ||
310 | |||
311 | /* Read count bytes from sensor sensor_addr in bank bank_addr and store the | ||
312 | result in buf, retry the send address part of the read retries times. */ | ||
313 | static int abituguru_read(struct abituguru_data *data, | ||
314 | u8 bank_addr, u8 sensor_addr, u8 *buf, int count, int retries) | ||
315 | { | ||
316 | int i; | ||
317 | |||
318 | /* Send the address */ | ||
319 | i = abituguru_send_address(data, bank_addr, sensor_addr, retries); | ||
320 | if (i) | ||
321 | return i; | ||
322 | |||
323 | /* And read the data */ | ||
324 | for (i = 0; i < count; i++) { | ||
325 | if (abituguru_wait(data, ABIT_UGURU_STATUS_READ)) { | ||
326 | ABIT_UGURU_DEBUG(1, "timeout exceeded waiting for " | ||
327 | "read state (bank: %d, sensor: %d)\n", | ||
328 | (int)bank_addr, (int)sensor_addr); | ||
329 | break; | ||
330 | } | ||
331 | buf[i] = inb(data->addr + ABIT_UGURU_CMD); | ||
332 | } | ||
333 | |||
334 | /* Last put the chip back in ready state */ | ||
335 | abituguru_ready(data); | ||
336 | |||
337 | return i; | ||
338 | } | ||
339 | |||
340 | /* Write count bytes from buf to sensor sensor_addr in bank bank_addr, the send | ||
341 | address part of the write is always retried ABIT_UGURU_MAX_RETRIES times. */ | ||
342 | static int abituguru_write(struct abituguru_data *data, | ||
343 | u8 bank_addr, u8 sensor_addr, u8 *buf, int count) | ||
344 | { | ||
345 | int i; | ||
346 | |||
347 | /* Send the address */ | ||
348 | i = abituguru_send_address(data, bank_addr, sensor_addr, | ||
349 | ABIT_UGURU_MAX_RETRIES); | ||
350 | if (i) | ||
351 | return i; | ||
352 | |||
353 | /* And write the data */ | ||
354 | for (i = 0; i < count; i++) { | ||
355 | if (abituguru_wait(data, ABIT_UGURU_STATUS_WRITE)) { | ||
356 | ABIT_UGURU_DEBUG(1, "timeout exceeded waiting for " | ||
357 | "write state (bank: %d, sensor: %d)\n", | ||
358 | (int)bank_addr, (int)sensor_addr); | ||
359 | break; | ||
360 | } | ||
361 | outb(buf[i], data->addr + ABIT_UGURU_CMD); | ||
362 | } | ||
363 | |||
364 | /* Now we need to wait till the chip is ready to be read again, | ||
365 | don't ask why */ | ||
366 | if (abituguru_wait(data, ABIT_UGURU_STATUS_READ)) { | ||
367 | ABIT_UGURU_DEBUG(1, "timeout exceeded waiting for read state " | ||
368 | "after write (bank: %d, sensor: %d)\n", (int)bank_addr, | ||
369 | (int)sensor_addr); | ||
370 | return -EIO; | ||
371 | } | ||
372 | |||
373 | /* Cmd port MUST be read now and should contain 0xAC */ | ||
374 | if (inb_p(data->addr + ABIT_UGURU_CMD) != 0xAC) { | ||
375 | ABIT_UGURU_DEBUG(1, "CMD reg does not hold 0xAC after write " | ||
376 | "(bank: %d, sensor: %d)\n", (int)bank_addr, | ||
377 | (int)sensor_addr); | ||
378 | return -EIO; | ||
379 | } | ||
380 | |||
381 | /* Last put the chip back in ready state */ | ||
382 | abituguru_ready(data); | ||
383 | |||
384 | return i; | ||
385 | } | ||
386 | |||
387 | /* Detect sensor type. Temp and Volt sensors are enabled with | ||
388 | different masks and will ignore enable masks not meant for them. | ||
389 | This enables us to test what kind of sensor we're dealing with. | ||
390 | By setting the alarm thresholds so that we will always get an | ||
391 | alarm for sensor type X and then enabling the sensor as sensor type | ||
392 | X, if we then get an alarm it is a sensor of type X. */ | ||
393 | static int __devinit | ||
394 | abituguru_detect_bank1_sensor_type(struct abituguru_data *data, | ||
395 | u8 sensor_addr) | ||
396 | { | ||
397 | u8 val, buf[3]; | ||
398 | int ret = ABIT_UGURU_NC; | ||
399 | |||
400 | /* First read the sensor and the current settings */ | ||
401 | if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK1, sensor_addr, &val, | ||
402 | 1, ABIT_UGURU_MAX_RETRIES) != 1) | ||
403 | return -ENODEV; | ||
404 | |||
405 | /* Test val is sane / usable for sensor type detection. */ | ||
406 | if ((val < 10u) || (val > 240u)) { | ||
407 | printk(KERN_WARNING ABIT_UGURU_NAME | ||
408 | ": bank1-sensor: %d reading (%d) too close to limits, " | ||
409 | "unable to determine sensor type, skipping sensor\n", | ||
410 | (int)sensor_addr, (int)val); | ||
411 | /* assume no sensor is there for sensors for which we can't | ||
412 | determine the sensor type because their reading is too close | ||
413 | to their limits, this usually means no sensor is there. */ | ||
414 | return ABIT_UGURU_NC; | ||
415 | } | ||
416 | |||
417 | ABIT_UGURU_DEBUG(2, "testing bank1 sensor %d\n", (int)sensor_addr); | ||
418 | /* Volt sensor test, enable volt low alarm, set min value ridicously | ||
419 | high. If its a volt sensor this should always give us an alarm. */ | ||
420 | buf[0] = ABIT_UGURU_VOLT_LOW_ALARM_ENABLE; | ||
421 | buf[1] = 245; | ||
422 | buf[2] = 250; | ||
423 | if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2, sensor_addr, | ||
424 | buf, 3) != 3) | ||
425 | return -ENODEV; | ||
426 | /* Now we need 20 ms to give the uguru time to read the sensors | ||
427 | and raise a voltage alarm */ | ||
428 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
429 | schedule_timeout(HZ/50); | ||
430 | /* Check for alarm and check the alarm is a volt low alarm. */ | ||
431 | if (abituguru_read(data, ABIT_UGURU_ALARM_BANK, 0, buf, 3, | ||
432 | ABIT_UGURU_MAX_RETRIES) != 3) | ||
433 | return -ENODEV; | ||
434 | if (buf[sensor_addr/8] & (0x01 << (sensor_addr % 8))) { | ||
435 | if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK1 + 1, | ||
436 | sensor_addr, buf, 3, | ||
437 | ABIT_UGURU_MAX_RETRIES) != 3) | ||
438 | return -ENODEV; | ||
439 | if (buf[0] & ABIT_UGURU_VOLT_LOW_ALARM_FLAG) { | ||
440 | /* Restore original settings */ | ||
441 | if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2, | ||
442 | sensor_addr, | ||
443 | data->bank1_settings[sensor_addr], | ||
444 | 3) != 3) | ||
445 | return -ENODEV; | ||
446 | ABIT_UGURU_DEBUG(2, " found volt sensor\n"); | ||
447 | return ABIT_UGURU_IN_SENSOR; | ||
448 | } else | ||
449 | ABIT_UGURU_DEBUG(2, " alarm raised during volt " | ||
450 | "sensor test, but volt low flag not set\n"); | ||
451 | } else | ||
452 | ABIT_UGURU_DEBUG(2, " alarm not raised during volt sensor " | ||
453 | "test\n"); | ||
454 | |||
455 | /* Temp sensor test, enable sensor as a temp sensor, set beep value | ||
456 | ridicously low (but not too low, otherwise uguru ignores it). | ||
457 | If its a temp sensor this should always give us an alarm. */ | ||
458 | buf[0] = ABIT_UGURU_TEMP_HIGH_ALARM_ENABLE; | ||
459 | buf[1] = 5; | ||
460 | buf[2] = 10; | ||
461 | if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2, sensor_addr, | ||
462 | buf, 3) != 3) | ||
463 | return -ENODEV; | ||
464 | /* Now we need 50 ms to give the uguru time to read the sensors | ||
465 | and raise a temp alarm */ | ||
466 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
467 | schedule_timeout(HZ/20); | ||
468 | /* Check for alarm and check the alarm is a temp high alarm. */ | ||
469 | if (abituguru_read(data, ABIT_UGURU_ALARM_BANK, 0, buf, 3, | ||
470 | ABIT_UGURU_MAX_RETRIES) != 3) | ||
471 | return -ENODEV; | ||
472 | if (buf[sensor_addr/8] & (0x01 << (sensor_addr % 8))) { | ||
473 | if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK1 + 1, | ||
474 | sensor_addr, buf, 3, | ||
475 | ABIT_UGURU_MAX_RETRIES) != 3) | ||
476 | return -ENODEV; | ||
477 | if (buf[0] & ABIT_UGURU_TEMP_HIGH_ALARM_FLAG) { | ||
478 | ret = ABIT_UGURU_TEMP_SENSOR; | ||
479 | ABIT_UGURU_DEBUG(2, " found temp sensor\n"); | ||
480 | } else | ||
481 | ABIT_UGURU_DEBUG(2, " alarm raised during temp " | ||
482 | "sensor test, but temp high flag not set\n"); | ||
483 | } else | ||
484 | ABIT_UGURU_DEBUG(2, " alarm not raised during temp sensor " | ||
485 | "test\n"); | ||
486 | |||
487 | /* Restore original settings */ | ||
488 | if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2, sensor_addr, | ||
489 | data->bank1_settings[sensor_addr], 3) != 3) | ||
490 | return -ENODEV; | ||
491 | |||
492 | return ret; | ||
493 | } | ||
494 | |||
495 | /* These functions try to find out how many sensors there are in bank2 and how | ||
496 | many pwms there are. The purpose of this is to make sure that we don't give | ||
497 | the user the possibility to change settings for non-existent sensors / pwm. | ||
498 | The uGuru will happily read / write whatever memory happens to be after the | ||
499 | memory storing the PWM settings when reading/writing to a PWM which is not | ||
500 | there. Notice even if we detect a PWM which doesn't exist we normally won't | ||
501 | write to it, unless the user tries to change the settings. | ||
502 | |||
503 | Although the uGuru allows reading (settings) from non existing bank2 | ||
504 | sensors, my version of the uGuru does seem to stop writing to them, the | ||
505 | write function above aborts in this case with: | ||
506 | "CMD reg does not hold 0xAC after write" | ||
507 | |||
508 | Notice these 2 tests are non destructive iow read-only tests, otherwise | ||
509 | they would defeat their purpose. Although for the bank2_sensors detection a | ||
510 | read/write test would be feasible because of the reaction above, I've | ||
511 | however opted to stay on the safe side. */ | ||
512 | static void __devinit | ||
513 | abituguru_detect_no_bank2_sensors(struct abituguru_data *data) | ||
514 | { | ||
515 | int i; | ||
516 | |||
517 | if (fan_sensors) { | ||
518 | data->bank2_sensors = fan_sensors; | ||
519 | ABIT_UGURU_DEBUG(2, "assuming %d fan sensors because of " | ||
520 | "\"fan_sensors\" module param\n", | ||
521 | (int)data->bank2_sensors); | ||
522 | return; | ||
523 | } | ||
524 | |||
525 | ABIT_UGURU_DEBUG(2, "detecting number of fan sensors\n"); | ||
526 | for (i = 0; i < ABIT_UGURU_MAX_BANK2_SENSORS; i++) { | ||
527 | /* 0x89 are the known used bits: | ||
528 | -0x80 enable shutdown | ||
529 | -0x08 enable beep | ||
530 | -0x01 enable alarm | ||
531 | All other bits should be 0, but on some motherboards | ||
532 | 0x40 (bit 6) is also high for some of the fans?? */ | ||
533 | if (data->bank2_settings[i][0] & ~0xC9) { | ||
534 | ABIT_UGURU_DEBUG(2, " bank2 sensor %d does not seem " | ||
535 | "to be a fan sensor: settings[0] = %02X\n", | ||
536 | i, (unsigned int)data->bank2_settings[i][0]); | ||
537 | break; | ||
538 | } | ||
539 | |||
540 | /* check if the threshold is within the allowed range */ | ||
541 | if (data->bank2_settings[i][1] < | ||
542 | abituguru_bank2_min_threshold) { | ||
543 | ABIT_UGURU_DEBUG(2, " bank2 sensor %d does not seem " | ||
544 | "to be a fan sensor: the threshold (%d) is " | ||
545 | "below the minimum (%d)\n", i, | ||
546 | (int)data->bank2_settings[i][1], | ||
547 | (int)abituguru_bank2_min_threshold); | ||
548 | break; | ||
549 | } | ||
550 | if (data->bank2_settings[i][1] > | ||
551 | abituguru_bank2_max_threshold) { | ||
552 | ABIT_UGURU_DEBUG(2, " bank2 sensor %d does not seem " | ||
553 | "to be a fan sensor: the threshold (%d) is " | ||
554 | "above the maximum (%d)\n", i, | ||
555 | (int)data->bank2_settings[i][1], | ||
556 | (int)abituguru_bank2_max_threshold); | ||
557 | break; | ||
558 | } | ||
559 | } | ||
560 | |||
561 | data->bank2_sensors = i; | ||
562 | ABIT_UGURU_DEBUG(2, " found: %d fan sensors\n", | ||
563 | (int)data->bank2_sensors); | ||
564 | } | ||
565 | |||
566 | static void __devinit | ||
567 | abituguru_detect_no_pwms(struct abituguru_data *data) | ||
568 | { | ||
569 | int i, j; | ||
570 | |||
571 | if (pwms) { | ||
572 | data->pwms = pwms; | ||
573 | ABIT_UGURU_DEBUG(2, "assuming %d PWM outputs because of " | ||
574 | "\"pwms\" module param\n", (int)data->pwms); | ||
575 | return; | ||
576 | } | ||
577 | |||
578 | ABIT_UGURU_DEBUG(2, "detecting number of PWM outputs\n"); | ||
579 | for (i = 0; i < ABIT_UGURU_MAX_PWMS; i++) { | ||
580 | /* 0x80 is the enable bit and the low | ||
581 | nibble is which temp sensor to use, | ||
582 | the other bits should be 0 */ | ||
583 | if (data->pwm_settings[i][0] & ~0x8F) { | ||
584 | ABIT_UGURU_DEBUG(2, " pwm channel %d does not seem " | ||
585 | "to be a pwm channel: settings[0] = %02X\n", | ||
586 | i, (unsigned int)data->pwm_settings[i][0]); | ||
587 | break; | ||
588 | } | ||
589 | |||
590 | /* the low nibble must correspond to one of the temp sensors | ||
591 | we've found */ | ||
592 | for (j = 0; j < data->bank1_sensors[ABIT_UGURU_TEMP_SENSOR]; | ||
593 | j++) { | ||
594 | if (data->bank1_address[ABIT_UGURU_TEMP_SENSOR][j] == | ||
595 | (data->pwm_settings[i][0] & 0x0F)) | ||
596 | break; | ||
597 | } | ||
598 | if (j == data->bank1_sensors[ABIT_UGURU_TEMP_SENSOR]) { | ||
599 | ABIT_UGURU_DEBUG(2, " pwm channel %d does not seem " | ||
600 | "to be a pwm channel: %d is not a valid temp " | ||
601 | "sensor address\n", i, | ||
602 | data->pwm_settings[i][0] & 0x0F); | ||
603 | break; | ||
604 | } | ||
605 | |||
606 | /* check if all other settings are within the allowed range */ | ||
607 | for (j = 1; j < 5; j++) { | ||
608 | u8 min; | ||
609 | /* special case pwm1 min pwm% */ | ||
610 | if ((i == 0) && ((j == 1) || (j == 2))) | ||
611 | min = 77; | ||
612 | else | ||
613 | min = abituguru_pwm_min[j]; | ||
614 | if (data->pwm_settings[i][j] < min) { | ||
615 | ABIT_UGURU_DEBUG(2, " pwm channel %d does " | ||
616 | "not seem to be a pwm channel: " | ||
617 | "setting %d (%d) is below the minimum " | ||
618 | "value (%d)\n", i, j, | ||
619 | (int)data->pwm_settings[i][j], | ||
620 | (int)min); | ||
621 | goto abituguru_detect_no_pwms_exit; | ||
622 | } | ||
623 | if (data->pwm_settings[i][j] > abituguru_pwm_max[j]) { | ||
624 | ABIT_UGURU_DEBUG(2, " pwm channel %d does " | ||
625 | "not seem to be a pwm channel: " | ||
626 | "setting %d (%d) is above the maximum " | ||
627 | "value (%d)\n", i, j, | ||
628 | (int)data->pwm_settings[i][j], | ||
629 | (int)abituguru_pwm_max[j]); | ||
630 | goto abituguru_detect_no_pwms_exit; | ||
631 | } | ||
632 | } | ||
633 | |||
634 | /* check that min temp < max temp and min pwm < max pwm */ | ||
635 | if (data->pwm_settings[i][1] >= data->pwm_settings[i][2]) { | ||
636 | ABIT_UGURU_DEBUG(2, " pwm channel %d does not seem " | ||
637 | "to be a pwm channel: min pwm (%d) >= " | ||
638 | "max pwm (%d)\n", i, | ||
639 | (int)data->pwm_settings[i][1], | ||
640 | (int)data->pwm_settings[i][2]); | ||
641 | break; | ||
642 | } | ||
643 | if (data->pwm_settings[i][3] >= data->pwm_settings[i][4]) { | ||
644 | ABIT_UGURU_DEBUG(2, " pwm channel %d does not seem " | ||
645 | "to be a pwm channel: min temp (%d) >= " | ||
646 | "max temp (%d)\n", i, | ||
647 | (int)data->pwm_settings[i][3], | ||
648 | (int)data->pwm_settings[i][4]); | ||
649 | break; | ||
650 | } | ||
651 | } | ||
652 | |||
653 | abituguru_detect_no_pwms_exit: | ||
654 | data->pwms = i; | ||
655 | ABIT_UGURU_DEBUG(2, " found: %d PWM outputs\n", (int)data->pwms); | ||
656 | } | ||
657 | |||
658 | /* Following are the sysfs callback functions. These functions expect: | ||
659 | sensor_device_attribute_2->index: sensor address/offset in the bank | ||
660 | sensor_device_attribute_2->nr: register offset, bitmask or NA. */ | ||
661 | static struct abituguru_data *abituguru_update_device(struct device *dev); | ||
662 | |||
663 | static ssize_t show_bank1_value(struct device *dev, | ||
664 | struct device_attribute *devattr, char *buf) | ||
665 | { | ||
666 | struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); | ||
667 | struct abituguru_data *data = abituguru_update_device(dev); | ||
668 | if (!data) | ||
669 | return -EIO; | ||
670 | return sprintf(buf, "%d\n", (data->bank1_value[attr->index] * | ||
671 | data->bank1_max_value[attr->index] + 128) / 255); | ||
672 | } | ||
673 | |||
674 | static ssize_t show_bank1_setting(struct device *dev, | ||
675 | struct device_attribute *devattr, char *buf) | ||
676 | { | ||
677 | struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); | ||
678 | struct abituguru_data *data = dev_get_drvdata(dev); | ||
679 | return sprintf(buf, "%d\n", | ||
680 | (data->bank1_settings[attr->index][attr->nr] * | ||
681 | data->bank1_max_value[attr->index] + 128) / 255); | ||
682 | } | ||
683 | |||
684 | static ssize_t show_bank2_value(struct device *dev, | ||
685 | struct device_attribute *devattr, char *buf) | ||
686 | { | ||
687 | struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); | ||
688 | struct abituguru_data *data = abituguru_update_device(dev); | ||
689 | if (!data) | ||
690 | return -EIO; | ||
691 | return sprintf(buf, "%d\n", (data->bank2_value[attr->index] * | ||
692 | ABIT_UGURU_FAN_MAX + 128) / 255); | ||
693 | } | ||
694 | |||
695 | static ssize_t show_bank2_setting(struct device *dev, | ||
696 | struct device_attribute *devattr, char *buf) | ||
697 | { | ||
698 | struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); | ||
699 | struct abituguru_data *data = dev_get_drvdata(dev); | ||
700 | return sprintf(buf, "%d\n", | ||
701 | (data->bank2_settings[attr->index][attr->nr] * | ||
702 | ABIT_UGURU_FAN_MAX + 128) / 255); | ||
703 | } | ||
704 | |||
705 | static ssize_t store_bank1_setting(struct device *dev, struct device_attribute | ||
706 | *devattr, const char *buf, size_t count) | ||
707 | { | ||
708 | struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); | ||
709 | struct abituguru_data *data = dev_get_drvdata(dev); | ||
710 | u8 val = (simple_strtoul(buf, NULL, 10) * 255 + | ||
711 | data->bank1_max_value[attr->index]/2) / | ||
712 | data->bank1_max_value[attr->index]; | ||
713 | ssize_t ret = count; | ||
714 | |||
715 | mutex_lock(&data->update_lock); | ||
716 | if (data->bank1_settings[attr->index][attr->nr] != val) { | ||
717 | u8 orig_val = data->bank1_settings[attr->index][attr->nr]; | ||
718 | data->bank1_settings[attr->index][attr->nr] = val; | ||
719 | if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2, | ||
720 | attr->index, data->bank1_settings[attr->index], | ||
721 | 3) <= attr->nr) { | ||
722 | data->bank1_settings[attr->index][attr->nr] = orig_val; | ||
723 | ret = -EIO; | ||
724 | } | ||
725 | } | ||
726 | mutex_unlock(&data->update_lock); | ||
727 | return ret; | ||
728 | } | ||
729 | |||
730 | static ssize_t store_bank2_setting(struct device *dev, struct device_attribute | ||
731 | *devattr, const char *buf, size_t count) | ||
732 | { | ||
733 | struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); | ||
734 | struct abituguru_data *data = dev_get_drvdata(dev); | ||
735 | u8 val = (simple_strtoul(buf, NULL, 10)*255 + ABIT_UGURU_FAN_MAX/2) / | ||
736 | ABIT_UGURU_FAN_MAX; | ||
737 | ssize_t ret = count; | ||
738 | |||
739 | /* this check can be done before taking the lock */ | ||
740 | if ((val < abituguru_bank2_min_threshold) || | ||
741 | (val > abituguru_bank2_max_threshold)) | ||
742 | return -EINVAL; | ||
743 | |||
744 | mutex_lock(&data->update_lock); | ||
745 | if (data->bank2_settings[attr->index][attr->nr] != val) { | ||
746 | u8 orig_val = data->bank2_settings[attr->index][attr->nr]; | ||
747 | data->bank2_settings[attr->index][attr->nr] = val; | ||
748 | if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK2 + 2, | ||
749 | attr->index, data->bank2_settings[attr->index], | ||
750 | 2) <= attr->nr) { | ||
751 | data->bank2_settings[attr->index][attr->nr] = orig_val; | ||
752 | ret = -EIO; | ||
753 | } | ||
754 | } | ||
755 | mutex_unlock(&data->update_lock); | ||
756 | return ret; | ||
757 | } | ||
758 | |||
759 | static ssize_t show_bank1_alarm(struct device *dev, | ||
760 | struct device_attribute *devattr, char *buf) | ||
761 | { | ||
762 | struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); | ||
763 | struct abituguru_data *data = abituguru_update_device(dev); | ||
764 | if (!data) | ||
765 | return -EIO; | ||
766 | /* See if the alarm bit for this sensor is set, and if the | ||
767 | alarm matches the type of alarm we're looking for (for volt | ||
768 | it can be either low or high). The type is stored in a few | ||
769 | readonly bits in the settings part of the relevant sensor. | ||
770 | The bitmask of the type is passed to us in attr->nr. */ | ||
771 | if ((data->alarms[attr->index / 8] & (0x01 << (attr->index % 8))) && | ||
772 | (data->bank1_settings[attr->index][0] & attr->nr)) | ||
773 | return sprintf(buf, "1\n"); | ||
774 | else | ||
775 | return sprintf(buf, "0\n"); | ||
776 | } | ||
777 | |||
778 | static ssize_t show_bank2_alarm(struct device *dev, | ||
779 | struct device_attribute *devattr, char *buf) | ||
780 | { | ||
781 | struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); | ||
782 | struct abituguru_data *data = abituguru_update_device(dev); | ||
783 | if (!data) | ||
784 | return -EIO; | ||
785 | if (data->alarms[2] & (0x01 << attr->index)) | ||
786 | return sprintf(buf, "1\n"); | ||
787 | else | ||
788 | return sprintf(buf, "0\n"); | ||
789 | } | ||
790 | |||
791 | static ssize_t show_bank1_mask(struct device *dev, | ||
792 | struct device_attribute *devattr, char *buf) | ||
793 | { | ||
794 | struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); | ||
795 | struct abituguru_data *data = dev_get_drvdata(dev); | ||
796 | if (data->bank1_settings[attr->index][0] & attr->nr) | ||
797 | return sprintf(buf, "1\n"); | ||
798 | else | ||
799 | return sprintf(buf, "0\n"); | ||
800 | } | ||
801 | |||
802 | static ssize_t show_bank2_mask(struct device *dev, | ||
803 | struct device_attribute *devattr, char *buf) | ||
804 | { | ||
805 | struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); | ||
806 | struct abituguru_data *data = dev_get_drvdata(dev); | ||
807 | if (data->bank2_settings[attr->index][0] & attr->nr) | ||
808 | return sprintf(buf, "1\n"); | ||
809 | else | ||
810 | return sprintf(buf, "0\n"); | ||
811 | } | ||
812 | |||
813 | static ssize_t store_bank1_mask(struct device *dev, | ||
814 | struct device_attribute *devattr, const char *buf, size_t count) | ||
815 | { | ||
816 | struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); | ||
817 | struct abituguru_data *data = dev_get_drvdata(dev); | ||
818 | int mask = simple_strtoul(buf, NULL, 10); | ||
819 | ssize_t ret = count; | ||
820 | u8 orig_val; | ||
821 | |||
822 | mutex_lock(&data->update_lock); | ||
823 | orig_val = data->bank1_settings[attr->index][0]; | ||
824 | |||
825 | if (mask) | ||
826 | data->bank1_settings[attr->index][0] |= attr->nr; | ||
827 | else | ||
828 | data->bank1_settings[attr->index][0] &= ~attr->nr; | ||
829 | |||
830 | if ((data->bank1_settings[attr->index][0] != orig_val) && | ||
831 | (abituguru_write(data, | ||
832 | ABIT_UGURU_SENSOR_BANK1 + 2, attr->index, | ||
833 | data->bank1_settings[attr->index], 3) < 1)) { | ||
834 | data->bank1_settings[attr->index][0] = orig_val; | ||
835 | ret = -EIO; | ||
836 | } | ||
837 | mutex_unlock(&data->update_lock); | ||
838 | return ret; | ||
839 | } | ||
840 | |||
841 | static ssize_t store_bank2_mask(struct device *dev, | ||
842 | struct device_attribute *devattr, const char *buf, size_t count) | ||
843 | { | ||
844 | struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); | ||
845 | struct abituguru_data *data = dev_get_drvdata(dev); | ||
846 | int mask = simple_strtoul(buf, NULL, 10); | ||
847 | ssize_t ret = count; | ||
848 | u8 orig_val; | ||
849 | |||
850 | mutex_lock(&data->update_lock); | ||
851 | orig_val = data->bank2_settings[attr->index][0]; | ||
852 | |||
853 | if (mask) | ||
854 | data->bank2_settings[attr->index][0] |= attr->nr; | ||
855 | else | ||
856 | data->bank2_settings[attr->index][0] &= ~attr->nr; | ||
857 | |||
858 | if ((data->bank2_settings[attr->index][0] != orig_val) && | ||
859 | (abituguru_write(data, | ||
860 | ABIT_UGURU_SENSOR_BANK2 + 2, attr->index, | ||
861 | data->bank2_settings[attr->index], 2) < 1)) { | ||
862 | data->bank2_settings[attr->index][0] = orig_val; | ||
863 | ret = -EIO; | ||
864 | } | ||
865 | mutex_unlock(&data->update_lock); | ||
866 | return ret; | ||
867 | } | ||
868 | |||
869 | /* Fan PWM (speed control) */ | ||
870 | static ssize_t show_pwm_setting(struct device *dev, | ||
871 | struct device_attribute *devattr, char *buf) | ||
872 | { | ||
873 | struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); | ||
874 | struct abituguru_data *data = dev_get_drvdata(dev); | ||
875 | return sprintf(buf, "%d\n", data->pwm_settings[attr->index][attr->nr] * | ||
876 | abituguru_pwm_settings_multiplier[attr->nr]); | ||
877 | } | ||
878 | |||
879 | static ssize_t store_pwm_setting(struct device *dev, struct device_attribute | ||
880 | *devattr, const char *buf, size_t count) | ||
881 | { | ||
882 | struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); | ||
883 | struct abituguru_data *data = dev_get_drvdata(dev); | ||
884 | u8 min, val = (simple_strtoul(buf, NULL, 10) + | ||
885 | abituguru_pwm_settings_multiplier[attr->nr]/2) / | ||
886 | abituguru_pwm_settings_multiplier[attr->nr]; | ||
887 | ssize_t ret = count; | ||
888 | |||
889 | /* special case pwm1 min pwm% */ | ||
890 | if ((attr->index == 0) && ((attr->nr == 1) || (attr->nr == 2))) | ||
891 | min = 77; | ||
892 | else | ||
893 | min = abituguru_pwm_min[attr->nr]; | ||
894 | |||
895 | /* this check can be done before taking the lock */ | ||
896 | if ((val < min) || (val > abituguru_pwm_max[attr->nr])) | ||
897 | return -EINVAL; | ||
898 | |||
899 | mutex_lock(&data->update_lock); | ||
900 | /* this check needs to be done after taking the lock */ | ||
901 | if ((attr->nr & 1) && | ||
902 | (val >= data->pwm_settings[attr->index][attr->nr + 1])) | ||
903 | ret = -EINVAL; | ||
904 | else if (!(attr->nr & 1) && | ||
905 | (val <= data->pwm_settings[attr->index][attr->nr - 1])) | ||
906 | ret = -EINVAL; | ||
907 | else if (data->pwm_settings[attr->index][attr->nr] != val) { | ||
908 | u8 orig_val = data->pwm_settings[attr->index][attr->nr]; | ||
909 | data->pwm_settings[attr->index][attr->nr] = val; | ||
910 | if (abituguru_write(data, ABIT_UGURU_FAN_PWM + 1, | ||
911 | attr->index, data->pwm_settings[attr->index], | ||
912 | 5) <= attr->nr) { | ||
913 | data->pwm_settings[attr->index][attr->nr] = | ||
914 | orig_val; | ||
915 | ret = -EIO; | ||
916 | } | ||
917 | } | ||
918 | mutex_unlock(&data->update_lock); | ||
919 | return ret; | ||
920 | } | ||
921 | |||
922 | static ssize_t show_pwm_sensor(struct device *dev, | ||
923 | struct device_attribute *devattr, char *buf) | ||
924 | { | ||
925 | struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); | ||
926 | struct abituguru_data *data = dev_get_drvdata(dev); | ||
927 | int i; | ||
928 | /* We need to walk to the temp sensor addresses to find what | ||
929 | the userspace id of the configured temp sensor is. */ | ||
930 | for (i = 0; i < data->bank1_sensors[ABIT_UGURU_TEMP_SENSOR]; i++) | ||
931 | if (data->bank1_address[ABIT_UGURU_TEMP_SENSOR][i] == | ||
932 | (data->pwm_settings[attr->index][0] & 0x0F)) | ||
933 | return sprintf(buf, "%d\n", i+1); | ||
934 | |||
935 | return -ENXIO; | ||
936 | } | ||
937 | |||
938 | static ssize_t store_pwm_sensor(struct device *dev, struct device_attribute | ||
939 | *devattr, const char *buf, size_t count) | ||
940 | { | ||
941 | struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); | ||
942 | struct abituguru_data *data = dev_get_drvdata(dev); | ||
943 | unsigned long val = simple_strtoul(buf, NULL, 10) - 1; | ||
944 | ssize_t ret = count; | ||
945 | |||
946 | mutex_lock(&data->update_lock); | ||
947 | if (val < data->bank1_sensors[ABIT_UGURU_TEMP_SENSOR]) { | ||
948 | u8 orig_val = data->pwm_settings[attr->index][0]; | ||
949 | u8 address = data->bank1_address[ABIT_UGURU_TEMP_SENSOR][val]; | ||
950 | data->pwm_settings[attr->index][0] &= 0xF0; | ||
951 | data->pwm_settings[attr->index][0] |= address; | ||
952 | if (data->pwm_settings[attr->index][0] != orig_val) { | ||
953 | if (abituguru_write(data, ABIT_UGURU_FAN_PWM + 1, | ||
954 | attr->index, | ||
955 | data->pwm_settings[attr->index], | ||
956 | 5) < 1) { | ||
957 | data->pwm_settings[attr->index][0] = orig_val; | ||
958 | ret = -EIO; | ||
959 | } | ||
960 | } | ||
961 | } | ||
962 | else | ||
963 | ret = -EINVAL; | ||
964 | mutex_unlock(&data->update_lock); | ||
965 | return ret; | ||
966 | } | ||
967 | |||
968 | static ssize_t show_pwm_enable(struct device *dev, | ||
969 | struct device_attribute *devattr, char *buf) | ||
970 | { | ||
971 | struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); | ||
972 | struct abituguru_data *data = dev_get_drvdata(dev); | ||
973 | int res = 0; | ||
974 | if (data->pwm_settings[attr->index][0] & ABIT_UGURU_FAN_PWM_ENABLE) | ||
975 | res = 2; | ||
976 | return sprintf(buf, "%d\n", res); | ||
977 | } | ||
978 | |||
979 | static ssize_t store_pwm_enable(struct device *dev, struct device_attribute | ||
980 | *devattr, const char *buf, size_t count) | ||
981 | { | ||
982 | struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); | ||
983 | struct abituguru_data *data = dev_get_drvdata(dev); | ||
984 | u8 orig_val, user_val = simple_strtoul(buf, NULL, 10); | ||
985 | ssize_t ret = count; | ||
986 | |||
987 | mutex_lock(&data->update_lock); | ||
988 | orig_val = data->pwm_settings[attr->index][0]; | ||
989 | switch (user_val) { | ||
990 | case 0: | ||
991 | data->pwm_settings[attr->index][0] &= | ||
992 | ~ABIT_UGURU_FAN_PWM_ENABLE; | ||
993 | break; | ||
994 | case 2: | ||
995 | data->pwm_settings[attr->index][0] |= | ||
996 | ABIT_UGURU_FAN_PWM_ENABLE; | ||
997 | break; | ||
998 | default: | ||
999 | ret = -EINVAL; | ||
1000 | } | ||
1001 | if ((data->pwm_settings[attr->index][0] != orig_val) && | ||
1002 | (abituguru_write(data, ABIT_UGURU_FAN_PWM + 1, | ||
1003 | attr->index, data->pwm_settings[attr->index], | ||
1004 | 5) < 1)) { | ||
1005 | data->pwm_settings[attr->index][0] = orig_val; | ||
1006 | ret = -EIO; | ||
1007 | } | ||
1008 | mutex_unlock(&data->update_lock); | ||
1009 | return ret; | ||
1010 | } | ||
1011 | |||
1012 | static ssize_t show_name(struct device *dev, | ||
1013 | struct device_attribute *devattr, char *buf) | ||
1014 | { | ||
1015 | return sprintf(buf, "%s\n", ABIT_UGURU_NAME); | ||
1016 | } | ||
1017 | |||
1018 | /* Sysfs attr templates, the real entries are generated automatically. */ | ||
1019 | static const | ||
1020 | struct sensor_device_attribute_2 abituguru_sysfs_bank1_templ[2][9] = { | ||
1021 | { | ||
1022 | SENSOR_ATTR_2(in%d_input, 0444, show_bank1_value, NULL, 0, 0), | ||
1023 | SENSOR_ATTR_2(in%d_min, 0644, show_bank1_setting, | ||
1024 | store_bank1_setting, 1, 0), | ||
1025 | SENSOR_ATTR_2(in%d_min_alarm, 0444, show_bank1_alarm, NULL, | ||
1026 | ABIT_UGURU_VOLT_LOW_ALARM_FLAG, 0), | ||
1027 | SENSOR_ATTR_2(in%d_max, 0644, show_bank1_setting, | ||
1028 | store_bank1_setting, 2, 0), | ||
1029 | SENSOR_ATTR_2(in%d_max_alarm, 0444, show_bank1_alarm, NULL, | ||
1030 | ABIT_UGURU_VOLT_HIGH_ALARM_FLAG, 0), | ||
1031 | SENSOR_ATTR_2(in%d_beep, 0644, show_bank1_mask, | ||
1032 | store_bank1_mask, ABIT_UGURU_BEEP_ENABLE, 0), | ||
1033 | SENSOR_ATTR_2(in%d_shutdown, 0644, show_bank1_mask, | ||
1034 | store_bank1_mask, ABIT_UGURU_SHUTDOWN_ENABLE, 0), | ||
1035 | SENSOR_ATTR_2(in%d_min_alarm_enable, 0644, show_bank1_mask, | ||
1036 | store_bank1_mask, ABIT_UGURU_VOLT_LOW_ALARM_ENABLE, 0), | ||
1037 | SENSOR_ATTR_2(in%d_max_alarm_enable, 0644, show_bank1_mask, | ||
1038 | store_bank1_mask, ABIT_UGURU_VOLT_HIGH_ALARM_ENABLE, 0), | ||
1039 | }, { | ||
1040 | SENSOR_ATTR_2(temp%d_input, 0444, show_bank1_value, NULL, 0, 0), | ||
1041 | SENSOR_ATTR_2(temp%d_alarm, 0444, show_bank1_alarm, NULL, | ||
1042 | ABIT_UGURU_TEMP_HIGH_ALARM_FLAG, 0), | ||
1043 | SENSOR_ATTR_2(temp%d_max, 0644, show_bank1_setting, | ||
1044 | store_bank1_setting, 1, 0), | ||
1045 | SENSOR_ATTR_2(temp%d_crit, 0644, show_bank1_setting, | ||
1046 | store_bank1_setting, 2, 0), | ||
1047 | SENSOR_ATTR_2(temp%d_beep, 0644, show_bank1_mask, | ||
1048 | store_bank1_mask, ABIT_UGURU_BEEP_ENABLE, 0), | ||
1049 | SENSOR_ATTR_2(temp%d_shutdown, 0644, show_bank1_mask, | ||
1050 | store_bank1_mask, ABIT_UGURU_SHUTDOWN_ENABLE, 0), | ||
1051 | SENSOR_ATTR_2(temp%d_alarm_enable, 0644, show_bank1_mask, | ||
1052 | store_bank1_mask, ABIT_UGURU_TEMP_HIGH_ALARM_ENABLE, 0), | ||
1053 | } | ||
1054 | }; | ||
1055 | |||
1056 | static const struct sensor_device_attribute_2 abituguru_sysfs_fan_templ[6] = { | ||
1057 | SENSOR_ATTR_2(fan%d_input, 0444, show_bank2_value, NULL, 0, 0), | ||
1058 | SENSOR_ATTR_2(fan%d_alarm, 0444, show_bank2_alarm, NULL, 0, 0), | ||
1059 | SENSOR_ATTR_2(fan%d_min, 0644, show_bank2_setting, | ||
1060 | store_bank2_setting, 1, 0), | ||
1061 | SENSOR_ATTR_2(fan%d_beep, 0644, show_bank2_mask, | ||
1062 | store_bank2_mask, ABIT_UGURU_BEEP_ENABLE, 0), | ||
1063 | SENSOR_ATTR_2(fan%d_shutdown, 0644, show_bank2_mask, | ||
1064 | store_bank2_mask, ABIT_UGURU_SHUTDOWN_ENABLE, 0), | ||
1065 | SENSOR_ATTR_2(fan%d_alarm_enable, 0644, show_bank2_mask, | ||
1066 | store_bank2_mask, ABIT_UGURU_FAN_LOW_ALARM_ENABLE, 0), | ||
1067 | }; | ||
1068 | |||
1069 | static const struct sensor_device_attribute_2 abituguru_sysfs_pwm_templ[6] = { | ||
1070 | SENSOR_ATTR_2(pwm%d_enable, 0644, show_pwm_enable, | ||
1071 | store_pwm_enable, 0, 0), | ||
1072 | SENSOR_ATTR_2(pwm%d_auto_channels_temp, 0644, show_pwm_sensor, | ||
1073 | store_pwm_sensor, 0, 0), | ||
1074 | SENSOR_ATTR_2(pwm%d_auto_point1_pwm, 0644, show_pwm_setting, | ||
1075 | store_pwm_setting, 1, 0), | ||
1076 | SENSOR_ATTR_2(pwm%d_auto_point2_pwm, 0644, show_pwm_setting, | ||
1077 | store_pwm_setting, 2, 0), | ||
1078 | SENSOR_ATTR_2(pwm%d_auto_point1_temp, 0644, show_pwm_setting, | ||
1079 | store_pwm_setting, 3, 0), | ||
1080 | SENSOR_ATTR_2(pwm%d_auto_point2_temp, 0644, show_pwm_setting, | ||
1081 | store_pwm_setting, 4, 0), | ||
1082 | }; | ||
1083 | |||
1084 | static struct sensor_device_attribute_2 abituguru_sysfs_attr[] = { | ||
1085 | SENSOR_ATTR_2(name, 0444, show_name, NULL, 0, 0), | ||
1086 | }; | ||
1087 | |||
1088 | static int __devinit abituguru_probe(struct platform_device *pdev) | ||
1089 | { | ||
1090 | struct abituguru_data *data; | ||
1091 | int i, j, used, sysfs_names_free, sysfs_attr_i, res = -ENODEV; | ||
1092 | char *sysfs_filename; | ||
1093 | |||
1094 | /* El weirdo probe order, to keep the sysfs order identical to the | ||
1095 | BIOS and window-appliction listing order. */ | ||
1096 | const u8 probe_order[ABIT_UGURU_MAX_BANK1_SENSORS] = { | ||
1097 | 0x00, 0x01, 0x03, 0x04, 0x0A, 0x08, 0x0E, 0x02, | ||
1098 | 0x09, 0x06, 0x05, 0x0B, 0x0F, 0x0D, 0x07, 0x0C }; | ||
1099 | |||
1100 | if (!(data = kzalloc(sizeof(struct abituguru_data), GFP_KERNEL))) | ||
1101 | return -ENOMEM; | ||
1102 | |||
1103 | data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start; | ||
1104 | mutex_init(&data->update_lock); | ||
1105 | platform_set_drvdata(pdev, data); | ||
1106 | |||
1107 | /* See if the uGuru is ready */ | ||
1108 | if (inb_p(data->addr + ABIT_UGURU_DATA) == ABIT_UGURU_STATUS_INPUT) | ||
1109 | data->uguru_ready = 1; | ||
1110 | |||
1111 | /* Completely read the uGuru this has 2 purposes: | ||
1112 | - testread / see if one really is there. | ||
1113 | - make an in memory copy of all the uguru settings for future use. */ | ||
1114 | if (abituguru_read(data, ABIT_UGURU_ALARM_BANK, 0, | ||
1115 | data->alarms, 3, ABIT_UGURU_MAX_RETRIES) != 3) | ||
1116 | goto abituguru_probe_error; | ||
1117 | |||
1118 | for (i = 0; i < ABIT_UGURU_MAX_BANK1_SENSORS; i++) { | ||
1119 | if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK1, i, | ||
1120 | &data->bank1_value[i], 1, | ||
1121 | ABIT_UGURU_MAX_RETRIES) != 1) | ||
1122 | goto abituguru_probe_error; | ||
1123 | if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK1+1, i, | ||
1124 | data->bank1_settings[i], 3, | ||
1125 | ABIT_UGURU_MAX_RETRIES) != 3) | ||
1126 | goto abituguru_probe_error; | ||
1127 | } | ||
1128 | /* Note: We don't know how many bank2 sensors / pwms there really are, | ||
1129 | but in order to "detect" this we need to read the maximum amount | ||
1130 | anyways. If we read sensors/pwms not there we'll just read crap | ||
1131 | this can't hurt. We need the detection because we don't want | ||
1132 | unwanted writes, which will hurt! */ | ||
1133 | for (i = 0; i < ABIT_UGURU_MAX_BANK2_SENSORS; i++) { | ||
1134 | if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK2, i, | ||
1135 | &data->bank2_value[i], 1, | ||
1136 | ABIT_UGURU_MAX_RETRIES) != 1) | ||
1137 | goto abituguru_probe_error; | ||
1138 | if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK2+1, i, | ||
1139 | data->bank2_settings[i], 2, | ||
1140 | ABIT_UGURU_MAX_RETRIES) != 2) | ||
1141 | goto abituguru_probe_error; | ||
1142 | } | ||
1143 | for (i = 0; i < ABIT_UGURU_MAX_PWMS; i++) { | ||
1144 | if (abituguru_read(data, ABIT_UGURU_FAN_PWM, i, | ||
1145 | data->pwm_settings[i], 5, | ||
1146 | ABIT_UGURU_MAX_RETRIES) != 5) | ||
1147 | goto abituguru_probe_error; | ||
1148 | } | ||
1149 | data->last_updated = jiffies; | ||
1150 | |||
1151 | /* Detect sensor types and fill the sysfs attr for bank1 */ | ||
1152 | sysfs_attr_i = 0; | ||
1153 | sysfs_filename = data->sysfs_names; | ||
1154 | sysfs_names_free = ABITUGURU_SYSFS_NAMES_LENGTH; | ||
1155 | for (i = 0; i < ABIT_UGURU_MAX_BANK1_SENSORS; i++) { | ||
1156 | res = abituguru_detect_bank1_sensor_type(data, probe_order[i]); | ||
1157 | if (res < 0) | ||
1158 | goto abituguru_probe_error; | ||
1159 | if (res == ABIT_UGURU_NC) | ||
1160 | continue; | ||
1161 | |||
1162 | /* res 1 (temp) sensors have 7 sysfs entries, 0 (in) 9 */ | ||
1163 | for (j = 0; j < (res ? 7 : 9); j++) { | ||
1164 | used = snprintf(sysfs_filename, sysfs_names_free, | ||
1165 | abituguru_sysfs_bank1_templ[res][j].dev_attr. | ||
1166 | attr.name, data->bank1_sensors[res] + res) | ||
1167 | + 1; | ||
1168 | data->sysfs_attr[sysfs_attr_i] = | ||
1169 | abituguru_sysfs_bank1_templ[res][j]; | ||
1170 | data->sysfs_attr[sysfs_attr_i].dev_attr.attr.name = | ||
1171 | sysfs_filename; | ||
1172 | data->sysfs_attr[sysfs_attr_i].index = probe_order[i]; | ||
1173 | sysfs_filename += used; | ||
1174 | sysfs_names_free -= used; | ||
1175 | sysfs_attr_i++; | ||
1176 | } | ||
1177 | data->bank1_max_value[probe_order[i]] = | ||
1178 | abituguru_bank1_max_value[res]; | ||
1179 | data->bank1_address[res][data->bank1_sensors[res]] = | ||
1180 | probe_order[i]; | ||
1181 | data->bank1_sensors[res]++; | ||
1182 | } | ||
1183 | /* Detect number of sensors and fill the sysfs attr for bank2 (fans) */ | ||
1184 | abituguru_detect_no_bank2_sensors(data); | ||
1185 | for (i = 0; i < data->bank2_sensors; i++) { | ||
1186 | for (j = 0; j < ARRAY_SIZE(abituguru_sysfs_fan_templ); j++) { | ||
1187 | used = snprintf(sysfs_filename, sysfs_names_free, | ||
1188 | abituguru_sysfs_fan_templ[j].dev_attr.attr.name, | ||
1189 | i + 1) + 1; | ||
1190 | data->sysfs_attr[sysfs_attr_i] = | ||
1191 | abituguru_sysfs_fan_templ[j]; | ||
1192 | data->sysfs_attr[sysfs_attr_i].dev_attr.attr.name = | ||
1193 | sysfs_filename; | ||
1194 | data->sysfs_attr[sysfs_attr_i].index = i; | ||
1195 | sysfs_filename += used; | ||
1196 | sysfs_names_free -= used; | ||
1197 | sysfs_attr_i++; | ||
1198 | } | ||
1199 | } | ||
1200 | /* Detect number of sensors and fill the sysfs attr for pwms */ | ||
1201 | abituguru_detect_no_pwms(data); | ||
1202 | for (i = 0; i < data->pwms; i++) { | ||
1203 | for (j = 0; j < ARRAY_SIZE(abituguru_sysfs_pwm_templ); j++) { | ||
1204 | used = snprintf(sysfs_filename, sysfs_names_free, | ||
1205 | abituguru_sysfs_pwm_templ[j].dev_attr.attr.name, | ||
1206 | i + 1) + 1; | ||
1207 | data->sysfs_attr[sysfs_attr_i] = | ||
1208 | abituguru_sysfs_pwm_templ[j]; | ||
1209 | data->sysfs_attr[sysfs_attr_i].dev_attr.attr.name = | ||
1210 | sysfs_filename; | ||
1211 | data->sysfs_attr[sysfs_attr_i].index = i; | ||
1212 | sysfs_filename += used; | ||
1213 | sysfs_names_free -= used; | ||
1214 | sysfs_attr_i++; | ||
1215 | } | ||
1216 | } | ||
1217 | /* Fail safe check, this should never happen! */ | ||
1218 | if (sysfs_names_free < 0) { | ||
1219 | printk(KERN_ERR ABIT_UGURU_NAME ": Fatal error ran out of " | ||
1220 | "space for sysfs attr names. This should never " | ||
1221 | "happen please report to the abituguru maintainer " | ||
1222 | "(see MAINTAINERS)\n"); | ||
1223 | res = -ENAMETOOLONG; | ||
1224 | goto abituguru_probe_error; | ||
1225 | } | ||
1226 | printk(KERN_INFO ABIT_UGURU_NAME ": found Abit uGuru\n"); | ||
1227 | |||
1228 | /* Register sysfs hooks */ | ||
1229 | data->class_dev = hwmon_device_register(&pdev->dev); | ||
1230 | if (IS_ERR(data->class_dev)) { | ||
1231 | res = PTR_ERR(data->class_dev); | ||
1232 | goto abituguru_probe_error; | ||
1233 | } | ||
1234 | for (i = 0; i < sysfs_attr_i; i++) | ||
1235 | device_create_file(&pdev->dev, &data->sysfs_attr[i].dev_attr); | ||
1236 | for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++) | ||
1237 | device_create_file(&pdev->dev, | ||
1238 | &abituguru_sysfs_attr[i].dev_attr); | ||
1239 | |||
1240 | return 0; | ||
1241 | |||
1242 | abituguru_probe_error: | ||
1243 | kfree(data); | ||
1244 | return res; | ||
1245 | } | ||
1246 | |||
1247 | static int __devexit abituguru_remove(struct platform_device *pdev) | ||
1248 | { | ||
1249 | struct abituguru_data *data = platform_get_drvdata(pdev); | ||
1250 | |||
1251 | platform_set_drvdata(pdev, NULL); | ||
1252 | hwmon_device_unregister(data->class_dev); | ||
1253 | kfree(data); | ||
1254 | |||
1255 | return 0; | ||
1256 | } | ||
1257 | |||
1258 | static struct abituguru_data *abituguru_update_device(struct device *dev) | ||
1259 | { | ||
1260 | int i, err; | ||
1261 | struct abituguru_data *data = dev_get_drvdata(dev); | ||
1262 | /* fake a complete successful read if no update necessary. */ | ||
1263 | char success = 1; | ||
1264 | |||
1265 | mutex_lock(&data->update_lock); | ||
1266 | if (time_after(jiffies, data->last_updated + HZ)) { | ||
1267 | success = 0; | ||
1268 | if ((err = abituguru_read(data, ABIT_UGURU_ALARM_BANK, 0, | ||
1269 | data->alarms, 3, 0)) != 3) | ||
1270 | goto LEAVE_UPDATE; | ||
1271 | for (i = 0; i < ABIT_UGURU_MAX_BANK1_SENSORS; i++) { | ||
1272 | if ((err = abituguru_read(data, | ||
1273 | ABIT_UGURU_SENSOR_BANK1, i, | ||
1274 | &data->bank1_value[i], 1, 0)) != 1) | ||
1275 | goto LEAVE_UPDATE; | ||
1276 | if ((err = abituguru_read(data, | ||
1277 | ABIT_UGURU_SENSOR_BANK1 + 1, i, | ||
1278 | data->bank1_settings[i], 3, 0)) != 3) | ||
1279 | goto LEAVE_UPDATE; | ||
1280 | } | ||
1281 | for (i = 0; i < data->bank2_sensors; i++) | ||
1282 | if ((err = abituguru_read(data, | ||
1283 | ABIT_UGURU_SENSOR_BANK2, i, | ||
1284 | &data->bank2_value[i], 1, 0)) != 1) | ||
1285 | goto LEAVE_UPDATE; | ||
1286 | /* success! */ | ||
1287 | success = 1; | ||
1288 | data->update_timeouts = 0; | ||
1289 | LEAVE_UPDATE: | ||
1290 | /* handle timeout condition */ | ||
1291 | if (err == -EBUSY) { | ||
1292 | /* No overflow please */ | ||
1293 | if (data->update_timeouts < 255u) | ||
1294 | data->update_timeouts++; | ||
1295 | if (data->update_timeouts <= ABIT_UGURU_MAX_TIMEOUTS) { | ||
1296 | ABIT_UGURU_DEBUG(3, "timeout exceeded, will " | ||
1297 | "try again next update\n"); | ||
1298 | /* Just a timeout, fake a successful read */ | ||
1299 | success = 1; | ||
1300 | } else | ||
1301 | ABIT_UGURU_DEBUG(1, "timeout exceeded %d " | ||
1302 | "times waiting for more input state\n", | ||
1303 | (int)data->update_timeouts); | ||
1304 | } | ||
1305 | /* On success set last_updated */ | ||
1306 | if (success) | ||
1307 | data->last_updated = jiffies; | ||
1308 | } | ||
1309 | mutex_unlock(&data->update_lock); | ||
1310 | |||
1311 | if (success) | ||
1312 | return data; | ||
1313 | else | ||
1314 | return NULL; | ||
1315 | } | ||
1316 | |||
1317 | static struct platform_driver abituguru_driver = { | ||
1318 | .driver = { | ||
1319 | .owner = THIS_MODULE, | ||
1320 | .name = ABIT_UGURU_NAME, | ||
1321 | }, | ||
1322 | .probe = abituguru_probe, | ||
1323 | .remove = __devexit_p(abituguru_remove), | ||
1324 | }; | ||
1325 | |||
1326 | static int __init abituguru_detect(void) | ||
1327 | { | ||
1328 | /* See if there is an uguru there. After a reboot uGuru will hold 0x00 | ||
1329 | at DATA and 0xAC, when this driver has already been loaded once | ||
1330 | DATA will hold 0x08. For most uGuru's CMD will hold 0xAC in either | ||
1331 | scenario but some will hold 0x00. | ||
1332 | Some uGuru's initally hold 0x09 at DATA and will only hold 0x08 | ||
1333 | after reading CMD first, so CMD must be read first! */ | ||
1334 | u8 cmd_val = inb_p(ABIT_UGURU_BASE + ABIT_UGURU_CMD); | ||
1335 | u8 data_val = inb_p(ABIT_UGURU_BASE + ABIT_UGURU_DATA); | ||
1336 | if (((data_val == 0x00) || (data_val == 0x08)) && | ||
1337 | ((cmd_val == 0x00) || (cmd_val == 0xAC))) | ||
1338 | return ABIT_UGURU_BASE; | ||
1339 | |||
1340 | ABIT_UGURU_DEBUG(2, "no Abit uGuru found, data = 0x%02X, cmd = " | ||
1341 | "0x%02X\n", (unsigned int)data_val, (unsigned int)cmd_val); | ||
1342 | |||
1343 | if (force) { | ||
1344 | printk(KERN_INFO ABIT_UGURU_NAME ": Assuming Abit uGuru is " | ||
1345 | "present because of \"force\" parameter\n"); | ||
1346 | return ABIT_UGURU_BASE; | ||
1347 | } | ||
1348 | |||
1349 | /* No uGuru found */ | ||
1350 | return -ENODEV; | ||
1351 | } | ||
1352 | |||
1353 | static struct platform_device *abituguru_pdev; | ||
1354 | |||
1355 | static int __init abituguru_init(void) | ||
1356 | { | ||
1357 | int address, err; | ||
1358 | struct resource res = { .flags = IORESOURCE_IO }; | ||
1359 | |||
1360 | address = abituguru_detect(); | ||
1361 | if (address < 0) | ||
1362 | return address; | ||
1363 | |||
1364 | err = platform_driver_register(&abituguru_driver); | ||
1365 | if (err) | ||
1366 | goto exit; | ||
1367 | |||
1368 | abituguru_pdev = platform_device_alloc(ABIT_UGURU_NAME, address); | ||
1369 | if (!abituguru_pdev) { | ||
1370 | printk(KERN_ERR ABIT_UGURU_NAME | ||
1371 | ": Device allocation failed\n"); | ||
1372 | err = -ENOMEM; | ||
1373 | goto exit_driver_unregister; | ||
1374 | } | ||
1375 | |||
1376 | res.start = address; | ||
1377 | res.end = address + ABIT_UGURU_REGION_LENGTH - 1; | ||
1378 | res.name = ABIT_UGURU_NAME; | ||
1379 | |||
1380 | err = platform_device_add_resources(abituguru_pdev, &res, 1); | ||
1381 | if (err) { | ||
1382 | printk(KERN_ERR ABIT_UGURU_NAME | ||
1383 | ": Device resource addition failed (%d)\n", err); | ||
1384 | goto exit_device_put; | ||
1385 | } | ||
1386 | |||
1387 | err = platform_device_add(abituguru_pdev); | ||
1388 | if (err) { | ||
1389 | printk(KERN_ERR ABIT_UGURU_NAME | ||
1390 | ": Device addition failed (%d)\n", err); | ||
1391 | goto exit_device_put; | ||
1392 | } | ||
1393 | |||
1394 | return 0; | ||
1395 | |||
1396 | exit_device_put: | ||
1397 | platform_device_put(abituguru_pdev); | ||
1398 | exit_driver_unregister: | ||
1399 | platform_driver_unregister(&abituguru_driver); | ||
1400 | exit: | ||
1401 | return err; | ||
1402 | } | ||
1403 | |||
1404 | static void __exit abituguru_exit(void) | ||
1405 | { | ||
1406 | platform_device_unregister(abituguru_pdev); | ||
1407 | platform_driver_unregister(&abituguru_driver); | ||
1408 | } | ||
1409 | |||
1410 | MODULE_AUTHOR("Hans de Goede <j.w.r.degoede@hhs.nl>"); | ||
1411 | MODULE_DESCRIPTION("Abit uGuru Sensor device"); | ||
1412 | MODULE_LICENSE("GPL"); | ||
1413 | |||
1414 | module_init(abituguru_init); | ||
1415 | module_exit(abituguru_exit); | ||
diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c index 885465df6e6a..fd72440faf76 100644 --- a/drivers/hwmon/f71805f.c +++ b/drivers/hwmon/f71805f.c | |||
@@ -99,10 +99,6 @@ superio_exit(int base) | |||
99 | #define ADDR_REG_OFFSET 0 | 99 | #define ADDR_REG_OFFSET 0 |
100 | #define DATA_REG_OFFSET 1 | 100 | #define DATA_REG_OFFSET 1 |
101 | 101 | ||
102 | static struct resource f71805f_resource __initdata = { | ||
103 | .flags = IORESOURCE_IO, | ||
104 | }; | ||
105 | |||
106 | /* | 102 | /* |
107 | * Registers | 103 | * Registers |
108 | */ | 104 | */ |
@@ -782,6 +778,11 @@ static struct platform_driver f71805f_driver = { | |||
782 | 778 | ||
783 | static int __init f71805f_device_add(unsigned short address) | 779 | static int __init f71805f_device_add(unsigned short address) |
784 | { | 780 | { |
781 | struct resource res = { | ||
782 | .start = address, | ||
783 | .end = address + REGION_LENGTH - 1, | ||
784 | .flags = IORESOURCE_IO, | ||
785 | }; | ||
785 | int err; | 786 | int err; |
786 | 787 | ||
787 | pdev = platform_device_alloc(DRVNAME, address); | 788 | pdev = platform_device_alloc(DRVNAME, address); |
@@ -791,10 +792,8 @@ static int __init f71805f_device_add(unsigned short address) | |||
791 | goto exit; | 792 | goto exit; |
792 | } | 793 | } |
793 | 794 | ||
794 | f71805f_resource.start = address; | 795 | res.name = pdev->name; |
795 | f71805f_resource.end = address + REGION_LENGTH - 1; | 796 | err = platform_device_add_resources(pdev, &res, 1); |
796 | f71805f_resource.name = pdev->name; | ||
797 | err = platform_device_add_resources(pdev, &f71805f_resource, 1); | ||
798 | if (err) { | 797 | if (err) { |
799 | printk(KERN_ERR DRVNAME ": Device resource addition failed " | 798 | printk(KERN_ERR DRVNAME ": Device resource addition failed " |
800 | "(%d)\n", err); | 799 | "(%d)\n", err); |
diff --git a/drivers/hwmon/hdaps.c b/drivers/hwmon/hdaps.c index 1659f6c41458..42b632889dd8 100644 --- a/drivers/hwmon/hdaps.c +++ b/drivers/hwmon/hdaps.c | |||
@@ -41,7 +41,7 @@ | |||
41 | #define HDAPS_PORT_STATE 0x1611 /* device state */ | 41 | #define HDAPS_PORT_STATE 0x1611 /* device state */ |
42 | #define HDAPS_PORT_YPOS 0x1612 /* y-axis position */ | 42 | #define HDAPS_PORT_YPOS 0x1612 /* y-axis position */ |
43 | #define HDAPS_PORT_XPOS 0x1614 /* x-axis position */ | 43 | #define HDAPS_PORT_XPOS 0x1614 /* x-axis position */ |
44 | #define HDAPS_PORT_TEMP1 0x1616 /* device temperature, in celcius */ | 44 | #define HDAPS_PORT_TEMP1 0x1616 /* device temperature, in Celsius */ |
45 | #define HDAPS_PORT_YVAR 0x1617 /* y-axis variance (what is this?) */ | 45 | #define HDAPS_PORT_YVAR 0x1617 /* y-axis variance (what is this?) */ |
46 | #define HDAPS_PORT_XVAR 0x1619 /* x-axis variance (what is this?) */ | 46 | #define HDAPS_PORT_XVAR 0x1619 /* x-axis variance (what is this?) */ |
47 | #define HDAPS_PORT_TEMP2 0x161b /* device temperature (again?) */ | 47 | #define HDAPS_PORT_TEMP2 0x161b /* device temperature (again?) */ |
@@ -522,13 +522,15 @@ static int __init hdaps_init(void) | |||
522 | { | 522 | { |
523 | int ret; | 523 | int ret; |
524 | 524 | ||
525 | /* Note that DMI_MATCH(...,"ThinkPad T42") will match "ThinkPad T42p" */ | 525 | /* Note that HDAPS_DMI_MATCH_NORMAL("ThinkPad T42") would match |
526 | "ThinkPad T42p", so the order of the entries matters */ | ||
526 | struct dmi_system_id hdaps_whitelist[] = { | 527 | struct dmi_system_id hdaps_whitelist[] = { |
527 | HDAPS_DMI_MATCH_NORMAL("ThinkPad H"), | 528 | HDAPS_DMI_MATCH_NORMAL("ThinkPad H"), |
528 | HDAPS_DMI_MATCH_INVERT("ThinkPad R50p"), | 529 | HDAPS_DMI_MATCH_INVERT("ThinkPad R50p"), |
529 | HDAPS_DMI_MATCH_NORMAL("ThinkPad R50"), | 530 | HDAPS_DMI_MATCH_NORMAL("ThinkPad R50"), |
530 | HDAPS_DMI_MATCH_NORMAL("ThinkPad R51"), | 531 | HDAPS_DMI_MATCH_NORMAL("ThinkPad R51"), |
531 | HDAPS_DMI_MATCH_NORMAL("ThinkPad R52"), | 532 | HDAPS_DMI_MATCH_NORMAL("ThinkPad R52"), |
533 | HDAPS_DMI_MATCH_NORMAL("ThinkPad H"), /* R52 (1846AQG) */ | ||
532 | HDAPS_DMI_MATCH_INVERT("ThinkPad T41p"), | 534 | HDAPS_DMI_MATCH_INVERT("ThinkPad T41p"), |
533 | HDAPS_DMI_MATCH_NORMAL("ThinkPad T41"), | 535 | HDAPS_DMI_MATCH_NORMAL("ThinkPad T41"), |
534 | HDAPS_DMI_MATCH_INVERT("ThinkPad T42p"), | 536 | HDAPS_DMI_MATCH_INVERT("ThinkPad T42p"), |
@@ -536,9 +538,9 @@ static int __init hdaps_init(void) | |||
536 | HDAPS_DMI_MATCH_NORMAL("ThinkPad T43"), | 538 | HDAPS_DMI_MATCH_NORMAL("ThinkPad T43"), |
537 | HDAPS_DMI_MATCH_LENOVO("ThinkPad T60p"), | 539 | HDAPS_DMI_MATCH_LENOVO("ThinkPad T60p"), |
538 | HDAPS_DMI_MATCH_NORMAL("ThinkPad X40"), | 540 | HDAPS_DMI_MATCH_NORMAL("ThinkPad X40"), |
539 | HDAPS_DMI_MATCH_NORMAL("ThinkPad X41 Tablet"), | ||
540 | HDAPS_DMI_MATCH_NORMAL("ThinkPad X41"), | 541 | HDAPS_DMI_MATCH_NORMAL("ThinkPad X41"), |
541 | HDAPS_DMI_MATCH_LENOVO("ThinkPad X60"), | 542 | HDAPS_DMI_MATCH_LENOVO("ThinkPad X60"), |
543 | HDAPS_DMI_MATCH_NORMAL("ThinkPad Z60m"), | ||
542 | { .ident = NULL } | 544 | { .ident = NULL } |
543 | }; | 545 | }; |
544 | 546 | ||
diff --git a/drivers/hwmon/hwmon-vid.c b/drivers/hwmon/hwmon-vid.c index a74a44f16f51..a6764ff00803 100644 --- a/drivers/hwmon/hwmon-vid.c +++ b/drivers/hwmon/hwmon-vid.c | |||
@@ -58,11 +58,20 @@ | |||
58 | doesn't seem to be any named specification for these. The conversion | 58 | doesn't seem to be any named specification for these. The conversion |
59 | tables are detailed directly in the various Pentium M datasheets: | 59 | tables are detailed directly in the various Pentium M datasheets: |
60 | http://www.intel.com/design/intarch/pentiumm/docs_pentiumm.htm | 60 | http://www.intel.com/design/intarch/pentiumm/docs_pentiumm.htm |
61 | |||
62 | The 14 specification corresponds to Intel Core series. There | ||
63 | doesn't seem to be any named specification for these. The conversion | ||
64 | tables are detailed directly in the various Pentium Core datasheets: | ||
65 | http://www.intel.com/design/mobile/datashts/309221.htm | ||
66 | |||
67 | The 110 (VRM 11) specification corresponds to Intel Conroe based series. | ||
68 | http://www.intel.com/design/processor/applnots/313214.htm | ||
61 | */ | 69 | */ |
62 | 70 | ||
63 | /* vrm is the VRM/VRD document version multiplied by 10. | 71 | /* vrm is the VRM/VRD document version multiplied by 10. |
64 | val is the 4-, 5- or 6-bit VID code. | 72 | val is the 4-bit or more VID code. |
65 | Returned value is in mV to avoid floating point in the kernel. */ | 73 | Returned value is in mV to avoid floating point in the kernel. |
74 | Some VID have some bits in uV scale, this is rounded to mV */ | ||
66 | int vid_from_reg(int val, u8 vrm) | 75 | int vid_from_reg(int val, u8 vrm) |
67 | { | 76 | { |
68 | int vid; | 77 | int vid; |
@@ -70,26 +79,36 @@ int vid_from_reg(int val, u8 vrm) | |||
70 | switch(vrm) { | 79 | switch(vrm) { |
71 | 80 | ||
72 | case 100: /* VRD 10.0 */ | 81 | case 100: /* VRD 10.0 */ |
82 | /* compute in uV, round to mV */ | ||
83 | val &= 0x3f; | ||
73 | if((val & 0x1f) == 0x1f) | 84 | if((val & 0x1f) == 0x1f) |
74 | return 0; | 85 | return 0; |
75 | if((val & 0x1f) <= 0x09 || val == 0x0a) | 86 | if((val & 0x1f) <= 0x09 || val == 0x0a) |
76 | vid = 10875 - (val & 0x1f) * 250; | 87 | vid = 1087500 - (val & 0x1f) * 25000; |
77 | else | 88 | else |
78 | vid = 18625 - (val & 0x1f) * 250; | 89 | vid = 1862500 - (val & 0x1f) * 25000; |
79 | if(val & 0x20) | 90 | if(val & 0x20) |
80 | vid -= 125; | 91 | vid -= 12500; |
81 | vid /= 10; /* only return 3 dec. places for now */ | 92 | return((vid + 500) / 1000); |
82 | return vid; | ||
83 | 93 | ||
94 | case 110: /* Intel Conroe */ | ||
95 | /* compute in uV, round to mV */ | ||
96 | val &= 0xff; | ||
97 | if(((val & 0x7e) == 0xfe) || (!(val & 0x7e))) | ||
98 | return 0; | ||
99 | return((1600000 - (val - 2) * 6250 + 500) / 1000); | ||
84 | case 24: /* Opteron processor */ | 100 | case 24: /* Opteron processor */ |
101 | val &= 0x1f; | ||
85 | return(val == 0x1f ? 0 : 1550 - val * 25); | 102 | return(val == 0x1f ? 0 : 1550 - val * 25); |
86 | 103 | ||
87 | case 91: /* VRM 9.1 */ | 104 | case 91: /* VRM 9.1 */ |
88 | case 90: /* VRM 9.0 */ | 105 | case 90: /* VRM 9.0 */ |
106 | val &= 0x1f; | ||
89 | return(val == 0x1f ? 0 : | 107 | return(val == 0x1f ? 0 : |
90 | 1850 - val * 25); | 108 | 1850 - val * 25); |
91 | 109 | ||
92 | case 85: /* VRM 8.5 */ | 110 | case 85: /* VRM 8.5 */ |
111 | val &= 0x1f; | ||
93 | return((val & 0x10 ? 25 : 0) + | 112 | return((val & 0x10 ? 25 : 0) + |
94 | ((val & 0x0f) > 0x04 ? 2050 : 1250) - | 113 | ((val & 0x0f) > 0x04 ? 2050 : 1250) - |
95 | ((val & 0x0f) * 50)); | 114 | ((val & 0x0f) * 50)); |
@@ -98,14 +117,21 @@ int vid_from_reg(int val, u8 vrm) | |||
98 | val &= 0x0f; | 117 | val &= 0x0f; |
99 | /* fall through */ | 118 | /* fall through */ |
100 | case 82: /* VRM 8.2 */ | 119 | case 82: /* VRM 8.2 */ |
120 | val &= 0x1f; | ||
101 | return(val == 0x1f ? 0 : | 121 | return(val == 0x1f ? 0 : |
102 | val & 0x10 ? 5100 - (val) * 100 : | 122 | val & 0x10 ? 5100 - (val) * 100 : |
103 | 2050 - (val) * 50); | 123 | 2050 - (val) * 50); |
104 | case 17: /* Intel IMVP-II */ | 124 | case 17: /* Intel IMVP-II */ |
125 | val &= 0x1f; | ||
105 | return(val & 0x10 ? 975 - (val & 0xF) * 25 : | 126 | return(val & 0x10 ? 975 - (val & 0xF) * 25 : |
106 | 1750 - val * 50); | 127 | 1750 - val * 50); |
107 | case 13: | 128 | case 13: |
108 | return(1708 - (val & 0x3f) * 16); | 129 | val &= 0x3f; |
130 | return(1708 - val * 16); | ||
131 | case 14: /* Intel Core */ | ||
132 | /* compute in uV, round to mV */ | ||
133 | val &= 0x7f; | ||
134 | return(val > 0x77 ? 0 : (1500000 - (val * 12500) + 500) / 1000); | ||
109 | default: /* report 0 for unknown */ | 135 | default: /* report 0 for unknown */ |
110 | printk(KERN_INFO "hwmon-vid: requested unknown VRM version\n"); | 136 | printk(KERN_INFO "hwmon-vid: requested unknown VRM version\n"); |
111 | return 0; | 137 | return 0; |
@@ -138,6 +164,8 @@ static struct vrm_model vrm_models[] = { | |||
138 | {X86_VENDOR_INTEL, 0x6, 0x9, ANY, 13}, /* Pentium M (130 nm) */ | 164 | {X86_VENDOR_INTEL, 0x6, 0x9, ANY, 13}, /* Pentium M (130 nm) */ |
139 | {X86_VENDOR_INTEL, 0x6, 0xB, ANY, 85}, /* Tualatin */ | 165 | {X86_VENDOR_INTEL, 0x6, 0xB, ANY, 85}, /* Tualatin */ |
140 | {X86_VENDOR_INTEL, 0x6, 0xD, ANY, 13}, /* Pentium M (90 nm) */ | 166 | {X86_VENDOR_INTEL, 0x6, 0xD, ANY, 13}, /* Pentium M (90 nm) */ |
167 | {X86_VENDOR_INTEL, 0x6, 0xE, ANY, 14}, /* Intel Core (65 nm) */ | ||
168 | {X86_VENDOR_INTEL, 0x6, 0xF, ANY, 110}, /* Intel Conroe */ | ||
141 | {X86_VENDOR_INTEL, 0x6, ANY, ANY, 82}, /* any P6 */ | 169 | {X86_VENDOR_INTEL, 0x6, ANY, ANY, 82}, /* any P6 */ |
142 | {X86_VENDOR_INTEL, 0x7, ANY, ANY, 0}, /* Itanium */ | 170 | {X86_VENDOR_INTEL, 0x7, ANY, ANY, 0}, /* Itanium */ |
143 | {X86_VENDOR_INTEL, 0xF, 0x0, ANY, 90}, /* P4 */ | 171 | {X86_VENDOR_INTEL, 0xF, 0x0, ANY, 90}, /* P4 */ |
diff --git a/drivers/hwmon/lm70.c b/drivers/hwmon/lm70.c new file mode 100644 index 000000000000..6ba84731b9cd --- /dev/null +++ b/drivers/hwmon/lm70.c | |||
@@ -0,0 +1,165 @@ | |||
1 | /* | ||
2 | * lm70.c | ||
3 | * | ||
4 | * The LM70 is a temperature sensor chip from National Semiconductor (NS). | ||
5 | * Copyright (C) 2006 Kaiwan N Billimoria <kaiwan@designergraphix.com> | ||
6 | * | ||
7 | * The LM70 communicates with a host processor via an SPI/Microwire Bus | ||
8 | * interface. The complete datasheet is available at National's website | ||
9 | * here: | ||
10 | * http://www.national.com/pf/LM/LM70.html | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #include <linux/init.h> | ||
28 | #include <linux/module.h> | ||
29 | #include <linux/kernel.h> | ||
30 | #include <linux/device.h> | ||
31 | #include <linux/err.h> | ||
32 | #include <linux/sysfs.h> | ||
33 | #include <linux/hwmon.h> | ||
34 | #include <linux/spi/spi.h> | ||
35 | #include <asm/semaphore.h> | ||
36 | |||
37 | #define DRVNAME "lm70" | ||
38 | |||
39 | struct lm70 { | ||
40 | struct class_device *cdev; | ||
41 | struct semaphore sem; | ||
42 | }; | ||
43 | |||
44 | /* sysfs hook function */ | ||
45 | static ssize_t lm70_sense_temp(struct device *dev, | ||
46 | struct device_attribute *attr, char *buf) | ||
47 | { | ||
48 | struct spi_device *spi = to_spi_device(dev); | ||
49 | int status, val; | ||
50 | u8 rxbuf[2]; | ||
51 | s16 raw=0; | ||
52 | struct lm70 *p_lm70 = dev_get_drvdata(&spi->dev); | ||
53 | |||
54 | if (down_interruptible(&p_lm70->sem)) | ||
55 | return -ERESTARTSYS; | ||
56 | |||
57 | /* | ||
58 | * spi_read() requires a DMA-safe buffer; so we use | ||
59 | * spi_write_then_read(), transmitting 0 bytes. | ||
60 | */ | ||
61 | status = spi_write_then_read(spi, NULL, 0, &rxbuf[0], 2); | ||
62 | if (status < 0) { | ||
63 | printk(KERN_WARNING | ||
64 | "spi_write_then_read failed with status %d\n", status); | ||
65 | goto out; | ||
66 | } | ||
67 | dev_dbg(dev, "rxbuf[1] : 0x%x rxbuf[0] : 0x%x\n", rxbuf[1], rxbuf[0]); | ||
68 | |||
69 | raw = (rxbuf[1] << 8) + rxbuf[0]; | ||
70 | dev_dbg(dev, "raw=0x%x\n", raw); | ||
71 | |||
72 | /* | ||
73 | * The "raw" temperature read into rxbuf[] is a 16-bit signed 2's | ||
74 | * complement value. Only the MSB 11 bits (1 sign + 10 temperature | ||
75 | * bits) are meaningful; the LSB 5 bits are to be discarded. | ||
76 | * See the datasheet. | ||
77 | * | ||
78 | * Further, each bit represents 0.25 degrees Celsius; so, multiply | ||
79 | * by 0.25. Also multiply by 1000 to represent in millidegrees | ||
80 | * Celsius. | ||
81 | * So it's equivalent to multiplying by 0.25 * 1000 = 250. | ||
82 | */ | ||
83 | val = ((int)raw/32) * 250; | ||
84 | status = sprintf(buf, "%+d\n", val); /* millidegrees Celsius */ | ||
85 | out: | ||
86 | up(&p_lm70->sem); | ||
87 | return status; | ||
88 | } | ||
89 | |||
90 | static DEVICE_ATTR(temp1_input, S_IRUGO, lm70_sense_temp, NULL); | ||
91 | |||
92 | /*----------------------------------------------------------------------*/ | ||
93 | |||
94 | static int __devinit lm70_probe(struct spi_device *spi) | ||
95 | { | ||
96 | struct lm70 *p_lm70; | ||
97 | int status; | ||
98 | |||
99 | p_lm70 = kzalloc(sizeof *p_lm70, GFP_KERNEL); | ||
100 | if (!p_lm70) | ||
101 | return -ENOMEM; | ||
102 | |||
103 | init_MUTEX(&p_lm70->sem); | ||
104 | |||
105 | /* sysfs hook */ | ||
106 | p_lm70->cdev = hwmon_device_register(&spi->dev); | ||
107 | if (IS_ERR(p_lm70->cdev)) { | ||
108 | dev_dbg(&spi->dev, "hwmon_device_register failed.\n"); | ||
109 | status = PTR_ERR(p_lm70->cdev); | ||
110 | goto out_dev_reg_failed; | ||
111 | } | ||
112 | dev_set_drvdata(&spi->dev, p_lm70); | ||
113 | |||
114 | if ((status = device_create_file(&spi->dev, &dev_attr_temp1_input))) { | ||
115 | dev_dbg(&spi->dev, "device_create_file failure.\n"); | ||
116 | goto out_dev_create_file_failed; | ||
117 | } | ||
118 | |||
119 | return 0; | ||
120 | |||
121 | out_dev_create_file_failed: | ||
122 | hwmon_device_unregister(p_lm70->cdev); | ||
123 | out_dev_reg_failed: | ||
124 | dev_set_drvdata(&spi->dev, NULL); | ||
125 | kfree(p_lm70); | ||
126 | return status; | ||
127 | } | ||
128 | |||
129 | static int __exit lm70_remove(struct spi_device *spi) | ||
130 | { | ||
131 | struct lm70 *p_lm70 = dev_get_drvdata(&spi->dev); | ||
132 | |||
133 | device_remove_file(&spi->dev, &dev_attr_temp1_input); | ||
134 | hwmon_device_unregister(p_lm70->cdev); | ||
135 | dev_set_drvdata(&spi->dev, NULL); | ||
136 | kfree(p_lm70); | ||
137 | |||
138 | return 0; | ||
139 | } | ||
140 | |||
141 | static struct spi_driver lm70_driver = { | ||
142 | .driver = { | ||
143 | .name = "lm70", | ||
144 | .owner = THIS_MODULE, | ||
145 | }, | ||
146 | .probe = lm70_probe, | ||
147 | .remove = __devexit_p(lm70_remove), | ||
148 | }; | ||
149 | |||
150 | static int __init init_lm70(void) | ||
151 | { | ||
152 | return spi_register_driver(&lm70_driver); | ||
153 | } | ||
154 | |||
155 | static void __exit cleanup_lm70(void) | ||
156 | { | ||
157 | spi_unregister_driver(&lm70_driver); | ||
158 | } | ||
159 | |||
160 | module_init(init_lm70); | ||
161 | module_exit(cleanup_lm70); | ||
162 | |||
163 | MODULE_AUTHOR("Kaiwan N Billimoria"); | ||
164 | MODULE_DESCRIPTION("National Semiconductor LM70 Linux driver"); | ||
165 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/hwmon/lm83.c b/drivers/hwmon/lm83.c index aac4ec2bf694..2137d7879df6 100644 --- a/drivers/hwmon/lm83.c +++ b/drivers/hwmon/lm83.c | |||
@@ -12,6 +12,10 @@ | |||
12 | * Since the datasheet omits to give the chip stepping code, I give it | 12 | * Since the datasheet omits to give the chip stepping code, I give it |
13 | * here: 0x03 (at register 0xff). | 13 | * here: 0x03 (at register 0xff). |
14 | * | 14 | * |
15 | * Also supports the LM82 temp sensor, which is basically a stripped down | ||
16 | * model of the LM83. Datasheet is here: | ||
17 | * http://www.national.com/pf/LM/LM82.html | ||
18 | * | ||
15 | * This program is free software; you can redistribute it and/or modify | 19 | * This program is free software; you can redistribute it and/or modify |
16 | * it under the terms of the GNU General Public License as published by | 20 | * it under the terms of the GNU General Public License as published by |
17 | * the Free Software Foundation; either version 2 of the License, or | 21 | * the Free Software Foundation; either version 2 of the License, or |
@@ -52,7 +56,7 @@ static unsigned short normal_i2c[] = { 0x18, 0x19, 0x1a, | |||
52 | * Insmod parameters | 56 | * Insmod parameters |
53 | */ | 57 | */ |
54 | 58 | ||
55 | I2C_CLIENT_INSMOD_1(lm83); | 59 | I2C_CLIENT_INSMOD_2(lm83, lm82); |
56 | 60 | ||
57 | /* | 61 | /* |
58 | * The LM83 registers | 62 | * The LM83 registers |
@@ -283,6 +287,9 @@ static int lm83_detect(struct i2c_adapter *adapter, int address, int kind) | |||
283 | if (man_id == 0x01) { /* National Semiconductor */ | 287 | if (man_id == 0x01) { /* National Semiconductor */ |
284 | if (chip_id == 0x03) { | 288 | if (chip_id == 0x03) { |
285 | kind = lm83; | 289 | kind = lm83; |
290 | } else | ||
291 | if (chip_id == 0x01) { | ||
292 | kind = lm82; | ||
286 | } | 293 | } |
287 | } | 294 | } |
288 | 295 | ||
@@ -296,6 +303,9 @@ static int lm83_detect(struct i2c_adapter *adapter, int address, int kind) | |||
296 | 303 | ||
297 | if (kind == lm83) { | 304 | if (kind == lm83) { |
298 | name = "lm83"; | 305 | name = "lm83"; |
306 | } else | ||
307 | if (kind == lm82) { | ||
308 | name = "lm82"; | ||
299 | } | 309 | } |
300 | 310 | ||
301 | /* We can fill in the remaining client fields */ | 311 | /* We can fill in the remaining client fields */ |
@@ -319,32 +329,46 @@ static int lm83_detect(struct i2c_adapter *adapter, int address, int kind) | |||
319 | goto exit_detach; | 329 | goto exit_detach; |
320 | } | 330 | } |
321 | 331 | ||
332 | /* | ||
333 | * The LM82 can only monitor one external diode which is | ||
334 | * at the same register as the LM83 temp3 entry - so we | ||
335 | * declare 1 and 3 common, and then 2 and 4 only for the LM83. | ||
336 | */ | ||
337 | |||
322 | device_create_file(&new_client->dev, | 338 | device_create_file(&new_client->dev, |
323 | &sensor_dev_attr_temp1_input.dev_attr); | 339 | &sensor_dev_attr_temp1_input.dev_attr); |
324 | device_create_file(&new_client->dev, | 340 | device_create_file(&new_client->dev, |
325 | &sensor_dev_attr_temp2_input.dev_attr); | ||
326 | device_create_file(&new_client->dev, | ||
327 | &sensor_dev_attr_temp3_input.dev_attr); | 341 | &sensor_dev_attr_temp3_input.dev_attr); |
328 | device_create_file(&new_client->dev, | 342 | |
329 | &sensor_dev_attr_temp4_input.dev_attr); | ||
330 | device_create_file(&new_client->dev, | 343 | device_create_file(&new_client->dev, |
331 | &sensor_dev_attr_temp1_max.dev_attr); | 344 | &sensor_dev_attr_temp1_max.dev_attr); |
332 | device_create_file(&new_client->dev, | 345 | device_create_file(&new_client->dev, |
333 | &sensor_dev_attr_temp2_max.dev_attr); | ||
334 | device_create_file(&new_client->dev, | ||
335 | &sensor_dev_attr_temp3_max.dev_attr); | 346 | &sensor_dev_attr_temp3_max.dev_attr); |
336 | device_create_file(&new_client->dev, | 347 | |
337 | &sensor_dev_attr_temp4_max.dev_attr); | ||
338 | device_create_file(&new_client->dev, | 348 | device_create_file(&new_client->dev, |
339 | &sensor_dev_attr_temp1_crit.dev_attr); | 349 | &sensor_dev_attr_temp1_crit.dev_attr); |
340 | device_create_file(&new_client->dev, | 350 | device_create_file(&new_client->dev, |
341 | &sensor_dev_attr_temp2_crit.dev_attr); | ||
342 | device_create_file(&new_client->dev, | ||
343 | &sensor_dev_attr_temp3_crit.dev_attr); | 351 | &sensor_dev_attr_temp3_crit.dev_attr); |
344 | device_create_file(&new_client->dev, | 352 | |
345 | &sensor_dev_attr_temp4_crit.dev_attr); | ||
346 | device_create_file(&new_client->dev, &dev_attr_alarms); | 353 | device_create_file(&new_client->dev, &dev_attr_alarms); |
347 | 354 | ||
355 | if (kind == lm83) { | ||
356 | device_create_file(&new_client->dev, | ||
357 | &sensor_dev_attr_temp2_input.dev_attr); | ||
358 | device_create_file(&new_client->dev, | ||
359 | &sensor_dev_attr_temp4_input.dev_attr); | ||
360 | |||
361 | device_create_file(&new_client->dev, | ||
362 | &sensor_dev_attr_temp2_max.dev_attr); | ||
363 | device_create_file(&new_client->dev, | ||
364 | &sensor_dev_attr_temp4_max.dev_attr); | ||
365 | |||
366 | device_create_file(&new_client->dev, | ||
367 | &sensor_dev_attr_temp2_crit.dev_attr); | ||
368 | device_create_file(&new_client->dev, | ||
369 | &sensor_dev_attr_temp4_crit.dev_attr); | ||
370 | } | ||
371 | |||
348 | return 0; | 372 | return 0; |
349 | 373 | ||
350 | exit_detach: | 374 | exit_detach: |
diff --git a/drivers/hwmon/smsc47m192.c b/drivers/hwmon/smsc47m192.c new file mode 100644 index 000000000000..bdc4570acf9a --- /dev/null +++ b/drivers/hwmon/smsc47m192.c | |||
@@ -0,0 +1,648 @@ | |||
1 | /* | ||
2 | smsc47m192.c - Support for hardware monitoring block of | ||
3 | SMSC LPC47M192 and LPC47M997 Super I/O chips | ||
4 | |||
5 | Copyright (C) 2006 Hartmut Rick <linux@rick.claranet.de> | ||
6 | |||
7 | Derived from lm78.c and other chip drivers. | ||
8 | |||
9 | This program is free software; you can redistribute it and/or modify | ||
10 | it under the terms of the GNU General Public License as published by | ||
11 | the Free Software Foundation; either version 2 of the License, or | ||
12 | (at your option) any later version. | ||
13 | |||
14 | This program is distributed in the hope that it will be useful, | ||
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | GNU General Public License for more details. | ||
18 | |||
19 | You should have received a copy of the GNU General Public License | ||
20 | along with this program; if not, write to the Free Software | ||
21 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
22 | */ | ||
23 | |||
24 | #include <linux/module.h> | ||
25 | #include <linux/init.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/jiffies.h> | ||
28 | #include <linux/i2c.h> | ||
29 | #include <linux/hwmon.h> | ||
30 | #include <linux/hwmon-sysfs.h> | ||
31 | #include <linux/hwmon-vid.h> | ||
32 | #include <linux/err.h> | ||
33 | |||
34 | /* Addresses to scan */ | ||
35 | static unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END }; | ||
36 | |||
37 | /* Insmod parameters */ | ||
38 | I2C_CLIENT_INSMOD_1(smsc47m192); | ||
39 | |||
40 | /* SMSC47M192 registers */ | ||
41 | #define SMSC47M192_REG_IN(nr) ((nr)<6 ? (0x20 + (nr)) : \ | ||
42 | (0x50 + (nr) - 6)) | ||
43 | #define SMSC47M192_REG_IN_MAX(nr) ((nr)<6 ? (0x2b + (nr) * 2) : \ | ||
44 | (0x54 + (((nr) - 6) * 2))) | ||
45 | #define SMSC47M192_REG_IN_MIN(nr) ((nr)<6 ? (0x2c + (nr) * 2) : \ | ||
46 | (0x55 + (((nr) - 6) * 2))) | ||
47 | static u8 SMSC47M192_REG_TEMP[3] = { 0x27, 0x26, 0x52 }; | ||
48 | static u8 SMSC47M192_REG_TEMP_MAX[3] = { 0x39, 0x37, 0x58 }; | ||
49 | static u8 SMSC47M192_REG_TEMP_MIN[3] = { 0x3A, 0x38, 0x59 }; | ||
50 | #define SMSC47M192_REG_TEMP_OFFSET(nr) ((nr)==2 ? 0x1e : 0x1f) | ||
51 | #define SMSC47M192_REG_ALARM1 0x41 | ||
52 | #define SMSC47M192_REG_ALARM2 0x42 | ||
53 | #define SMSC47M192_REG_VID 0x47 | ||
54 | #define SMSC47M192_REG_VID4 0x49 | ||
55 | #define SMSC47M192_REG_CONFIG 0x40 | ||
56 | #define SMSC47M192_REG_SFR 0x4f | ||
57 | #define SMSC47M192_REG_COMPANY_ID 0x3e | ||
58 | #define SMSC47M192_REG_VERSION 0x3f | ||
59 | |||
60 | /* generalised scaling with integer rounding */ | ||
61 | static inline int SCALE(long val, int mul, int div) | ||
62 | { | ||
63 | if (val < 0) | ||
64 | return (val * mul - div / 2) / div; | ||
65 | else | ||
66 | return (val * mul + div / 2) / div; | ||
67 | } | ||
68 | |||
69 | /* Conversions */ | ||
70 | |||
71 | /* smsc47m192 internally scales voltage measurements */ | ||
72 | static const u16 nom_mv[] = { 2500, 2250, 3300, 5000, 12000, 3300, 1500, 1800 }; | ||
73 | |||
74 | static inline unsigned int IN_FROM_REG(u8 reg, int n) | ||
75 | { | ||
76 | return SCALE(reg, nom_mv[n], 192); | ||
77 | } | ||
78 | |||
79 | static inline u8 IN_TO_REG(unsigned long val, int n) | ||
80 | { | ||
81 | return SENSORS_LIMIT(SCALE(val, 192, nom_mv[n]), 0, 255); | ||
82 | } | ||
83 | |||
84 | /* TEMP: 0.001 degC units (-128C to +127C) | ||
85 | REG: 1C/bit, two's complement */ | ||
86 | static inline s8 TEMP_TO_REG(int val) | ||
87 | { | ||
88 | return SENSORS_LIMIT(SCALE(val, 1, 1000), -128000, 127000); | ||
89 | } | ||
90 | |||
91 | static inline int TEMP_FROM_REG(s8 val) | ||
92 | { | ||
93 | return val * 1000; | ||
94 | } | ||
95 | |||
96 | struct smsc47m192_data { | ||
97 | struct i2c_client client; | ||
98 | struct class_device *class_dev; | ||
99 | struct semaphore update_lock; | ||
100 | char valid; /* !=0 if following fields are valid */ | ||
101 | unsigned long last_updated; /* In jiffies */ | ||
102 | |||
103 | u8 in[8]; /* Register value */ | ||
104 | u8 in_max[8]; /* Register value */ | ||
105 | u8 in_min[8]; /* Register value */ | ||
106 | s8 temp[3]; /* Register value */ | ||
107 | s8 temp_max[3]; /* Register value */ | ||
108 | s8 temp_min[3]; /* Register value */ | ||
109 | s8 temp_offset[3]; /* Register value */ | ||
110 | u16 alarms; /* Register encoding, combined */ | ||
111 | u8 vid; /* Register encoding, combined */ | ||
112 | u8 vrm; | ||
113 | }; | ||
114 | |||
115 | static int smsc47m192_attach_adapter(struct i2c_adapter *adapter); | ||
116 | static int smsc47m192_detect(struct i2c_adapter *adapter, int address, | ||
117 | int kind); | ||
118 | static int smsc47m192_detach_client(struct i2c_client *client); | ||
119 | static struct smsc47m192_data *smsc47m192_update_device(struct device *dev); | ||
120 | |||
121 | static struct i2c_driver smsc47m192_driver = { | ||
122 | .driver = { | ||
123 | .name = "smsc47m192", | ||
124 | }, | ||
125 | .attach_adapter = smsc47m192_attach_adapter, | ||
126 | .detach_client = smsc47m192_detach_client, | ||
127 | }; | ||
128 | |||
129 | /* Voltages */ | ||
130 | static ssize_t show_in(struct device *dev, struct device_attribute *attr, | ||
131 | char *buf) | ||
132 | { | ||
133 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | ||
134 | int nr = sensor_attr->index; | ||
135 | struct smsc47m192_data *data = smsc47m192_update_device(dev); | ||
136 | return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr], nr)); | ||
137 | } | ||
138 | |||
139 | static ssize_t show_in_min(struct device *dev, struct device_attribute *attr, | ||
140 | char *buf) | ||
141 | { | ||
142 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | ||
143 | int nr = sensor_attr->index; | ||
144 | struct smsc47m192_data *data = smsc47m192_update_device(dev); | ||
145 | return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr], nr)); | ||
146 | } | ||
147 | |||
148 | static ssize_t show_in_max(struct device *dev, struct device_attribute *attr, | ||
149 | char *buf) | ||
150 | { | ||
151 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | ||
152 | int nr = sensor_attr->index; | ||
153 | struct smsc47m192_data *data = smsc47m192_update_device(dev); | ||
154 | return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr], nr)); | ||
155 | } | ||
156 | |||
157 | static ssize_t set_in_min(struct device *dev, struct device_attribute *attr, | ||
158 | const char *buf, size_t count) | ||
159 | { | ||
160 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | ||
161 | int nr = sensor_attr->index; | ||
162 | struct i2c_client *client = to_i2c_client(dev); | ||
163 | struct smsc47m192_data *data = i2c_get_clientdata(client); | ||
164 | unsigned long val = simple_strtoul(buf, NULL, 10); | ||
165 | |||
166 | down(&data->update_lock); | ||
167 | data->in_min[nr] = IN_TO_REG(val, nr); | ||
168 | i2c_smbus_write_byte_data(client, SMSC47M192_REG_IN_MIN(nr), | ||
169 | data->in_min[nr]); | ||
170 | up(&data->update_lock); | ||
171 | return count; | ||
172 | } | ||
173 | |||
174 | static ssize_t set_in_max(struct device *dev, struct device_attribute *attr, | ||
175 | const char *buf, size_t count) | ||
176 | { | ||
177 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | ||
178 | int nr = sensor_attr->index; | ||
179 | struct i2c_client *client = to_i2c_client(dev); | ||
180 | struct smsc47m192_data *data = i2c_get_clientdata(client); | ||
181 | unsigned long val = simple_strtoul(buf, NULL, 10); | ||
182 | |||
183 | down(&data->update_lock); | ||
184 | data->in_max[nr] = IN_TO_REG(val, nr); | ||
185 | i2c_smbus_write_byte_data(client, SMSC47M192_REG_IN_MAX(nr), | ||
186 | data->in_max[nr]); | ||
187 | up(&data->update_lock); | ||
188 | return count; | ||
189 | } | ||
190 | |||
191 | #define show_in_offset(offset) \ | ||
192 | static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \ | ||
193 | show_in, NULL, offset); \ | ||
194 | static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ | ||
195 | show_in_min, set_in_min, offset); \ | ||
196 | static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ | ||
197 | show_in_max, set_in_max, offset); | ||
198 | |||
199 | show_in_offset(0) | ||
200 | show_in_offset(1) | ||
201 | show_in_offset(2) | ||
202 | show_in_offset(3) | ||
203 | show_in_offset(4) | ||
204 | show_in_offset(5) | ||
205 | show_in_offset(6) | ||
206 | show_in_offset(7) | ||
207 | |||
208 | /* Temperatures */ | ||
209 | static ssize_t show_temp(struct device *dev, struct device_attribute *attr, | ||
210 | char *buf) | ||
211 | { | ||
212 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | ||
213 | int nr = sensor_attr->index; | ||
214 | struct smsc47m192_data *data = smsc47m192_update_device(dev); | ||
215 | return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr])); | ||
216 | } | ||
217 | |||
218 | static ssize_t show_temp_min(struct device *dev, struct device_attribute *attr, | ||
219 | char *buf) | ||
220 | { | ||
221 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | ||
222 | int nr = sensor_attr->index; | ||
223 | struct smsc47m192_data *data = smsc47m192_update_device(dev); | ||
224 | return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[nr])); | ||
225 | } | ||
226 | |||
227 | static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr, | ||
228 | char *buf) | ||
229 | { | ||
230 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | ||
231 | int nr = sensor_attr->index; | ||
232 | struct smsc47m192_data *data = smsc47m192_update_device(dev); | ||
233 | return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[nr])); | ||
234 | } | ||
235 | |||
236 | static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr, | ||
237 | const char *buf, size_t count) | ||
238 | { | ||
239 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | ||
240 | int nr = sensor_attr->index; | ||
241 | struct i2c_client *client = to_i2c_client(dev); | ||
242 | struct smsc47m192_data *data = i2c_get_clientdata(client); | ||
243 | long val = simple_strtol(buf, NULL, 10); | ||
244 | |||
245 | down(&data->update_lock); | ||
246 | data->temp_min[nr] = TEMP_TO_REG(val); | ||
247 | i2c_smbus_write_byte_data(client, SMSC47M192_REG_TEMP_MIN[nr], | ||
248 | data->temp_min[nr]); | ||
249 | up(&data->update_lock); | ||
250 | return count; | ||
251 | } | ||
252 | |||
253 | static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, | ||
254 | const char *buf, size_t count) | ||
255 | { | ||
256 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | ||
257 | int nr = sensor_attr->index; | ||
258 | struct i2c_client *client = to_i2c_client(dev); | ||
259 | struct smsc47m192_data *data = i2c_get_clientdata(client); | ||
260 | long val = simple_strtol(buf, NULL, 10); | ||
261 | |||
262 | down(&data->update_lock); | ||
263 | data->temp_max[nr] = TEMP_TO_REG(val); | ||
264 | i2c_smbus_write_byte_data(client, SMSC47M192_REG_TEMP_MAX[nr], | ||
265 | data->temp_max[nr]); | ||
266 | up(&data->update_lock); | ||
267 | return count; | ||
268 | } | ||
269 | |||
270 | static ssize_t show_temp_offset(struct device *dev, struct device_attribute | ||
271 | *attr, char *buf) | ||
272 | { | ||
273 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | ||
274 | int nr = sensor_attr->index; | ||
275 | struct smsc47m192_data *data = smsc47m192_update_device(dev); | ||
276 | return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_offset[nr])); | ||
277 | } | ||
278 | |||
279 | static ssize_t set_temp_offset(struct device *dev, struct device_attribute | ||
280 | *attr, const char *buf, size_t count) | ||
281 | { | ||
282 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | ||
283 | int nr = sensor_attr->index; | ||
284 | struct i2c_client *client = to_i2c_client(dev); | ||
285 | struct smsc47m192_data *data = i2c_get_clientdata(client); | ||
286 | u8 sfr = i2c_smbus_read_byte_data(client, SMSC47M192_REG_SFR); | ||
287 | long val = simple_strtol(buf, NULL, 10); | ||
288 | |||
289 | down(&data->update_lock); | ||
290 | data->temp_offset[nr] = TEMP_TO_REG(val); | ||
291 | if (nr>1) | ||
292 | i2c_smbus_write_byte_data(client, | ||
293 | SMSC47M192_REG_TEMP_OFFSET(nr), data->temp_offset[nr]); | ||
294 | else if (data->temp_offset[nr] != 0) { | ||
295 | /* offset[0] and offset[1] share the same register, | ||
296 | SFR bit 4 activates offset[0] */ | ||
297 | i2c_smbus_write_byte_data(client, SMSC47M192_REG_SFR, | ||
298 | (sfr & 0xef) | (nr==0 ? 0x10 : 0)); | ||
299 | data->temp_offset[1-nr] = 0; | ||
300 | i2c_smbus_write_byte_data(client, | ||
301 | SMSC47M192_REG_TEMP_OFFSET(nr), data->temp_offset[nr]); | ||
302 | } else if ((sfr & 0x10) == (nr==0 ? 0x10 : 0)) | ||
303 | i2c_smbus_write_byte_data(client, | ||
304 | SMSC47M192_REG_TEMP_OFFSET(nr), 0); | ||
305 | up(&data->update_lock); | ||
306 | return count; | ||
307 | } | ||
308 | |||
309 | #define show_temp_index(index) \ | ||
310 | static SENSOR_DEVICE_ATTR(temp##index##_input, S_IRUGO, \ | ||
311 | show_temp, NULL, index-1); \ | ||
312 | static SENSOR_DEVICE_ATTR(temp##index##_min, S_IRUGO | S_IWUSR, \ | ||
313 | show_temp_min, set_temp_min, index-1); \ | ||
314 | static SENSOR_DEVICE_ATTR(temp##index##_max, S_IRUGO | S_IWUSR, \ | ||
315 | show_temp_max, set_temp_max, index-1); \ | ||
316 | static SENSOR_DEVICE_ATTR(temp##index##_offset, S_IRUGO | S_IWUSR, \ | ||
317 | show_temp_offset, set_temp_offset, index-1); | ||
318 | |||
319 | show_temp_index(1) | ||
320 | show_temp_index(2) | ||
321 | show_temp_index(3) | ||
322 | |||
323 | /* VID */ | ||
324 | static ssize_t show_vid(struct device *dev, struct device_attribute *attr, | ||
325 | char *buf) | ||
326 | { | ||
327 | struct smsc47m192_data *data = smsc47m192_update_device(dev); | ||
328 | return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm)); | ||
329 | } | ||
330 | static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); | ||
331 | |||
332 | static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, | ||
333 | char *buf) | ||
334 | { | ||
335 | struct smsc47m192_data *data = smsc47m192_update_device(dev); | ||
336 | return sprintf(buf, "%d\n", data->vrm); | ||
337 | } | ||
338 | |||
339 | static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, | ||
340 | const char *buf, size_t count) | ||
341 | { | ||
342 | struct i2c_client *client = to_i2c_client(dev); | ||
343 | struct smsc47m192_data *data = i2c_get_clientdata(client); | ||
344 | data->vrm = simple_strtoul(buf, NULL, 10); | ||
345 | return count; | ||
346 | } | ||
347 | static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm); | ||
348 | |||
349 | /* Alarms */ | ||
350 | static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, | ||
351 | char *buf) | ||
352 | { | ||
353 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | ||
354 | int nr = sensor_attr->index; | ||
355 | struct smsc47m192_data *data = smsc47m192_update_device(dev); | ||
356 | return sprintf(buf, "%u\n", (data->alarms & nr) ? 1 : 0); | ||
357 | } | ||
358 | |||
359 | static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 0x0010); | ||
360 | static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 0x0020); | ||
361 | static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 0x0040); | ||
362 | static SENSOR_DEVICE_ATTR(temp2_input_fault, S_IRUGO, show_alarm, NULL, 0x4000); | ||
363 | static SENSOR_DEVICE_ATTR(temp3_input_fault, S_IRUGO, show_alarm, NULL, 0x8000); | ||
364 | static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0x0001); | ||
365 | static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 0x0002); | ||
366 | static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 0x0004); | ||
367 | static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 0x0008); | ||
368 | static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 0x0100); | ||
369 | static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 0x0200); | ||
370 | static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 0x0400); | ||
371 | static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 0x0800); | ||
372 | |||
373 | /* This function is called when: | ||
374 | * smsc47m192_driver is inserted (when this module is loaded), for each | ||
375 | available adapter | ||
376 | * when a new adapter is inserted (and smsc47m192_driver is still present) */ | ||
377 | static int smsc47m192_attach_adapter(struct i2c_adapter *adapter) | ||
378 | { | ||
379 | if (!(adapter->class & I2C_CLASS_HWMON)) | ||
380 | return 0; | ||
381 | return i2c_probe(adapter, &addr_data, smsc47m192_detect); | ||
382 | } | ||
383 | |||
384 | static void smsc47m192_init_client(struct i2c_client *client) | ||
385 | { | ||
386 | int i; | ||
387 | u8 config = i2c_smbus_read_byte_data(client, SMSC47M192_REG_CONFIG); | ||
388 | u8 sfr = i2c_smbus_read_byte_data(client, SMSC47M192_REG_SFR); | ||
389 | |||
390 | /* select cycle mode (pause 1 sec between updates) */ | ||
391 | i2c_smbus_write_byte_data(client, SMSC47M192_REG_SFR, | ||
392 | (sfr & 0xfd) | 0x02); | ||
393 | if (!(config & 0x01)) { | ||
394 | /* initialize alarm limits */ | ||
395 | for (i=0; i<8; i++) { | ||
396 | i2c_smbus_write_byte_data(client, | ||
397 | SMSC47M192_REG_IN_MIN(i), 0); | ||
398 | i2c_smbus_write_byte_data(client, | ||
399 | SMSC47M192_REG_IN_MAX(i), 0xff); | ||
400 | } | ||
401 | for (i=0; i<3; i++) { | ||
402 | i2c_smbus_write_byte_data(client, | ||
403 | SMSC47M192_REG_TEMP_MIN[i], 0x80); | ||
404 | i2c_smbus_write_byte_data(client, | ||
405 | SMSC47M192_REG_TEMP_MAX[i], 0x7f); | ||
406 | } | ||
407 | |||
408 | /* start monitoring */ | ||
409 | i2c_smbus_write_byte_data(client, SMSC47M192_REG_CONFIG, | ||
410 | (config & 0xf7) | 0x01); | ||
411 | } | ||
412 | } | ||
413 | |||
414 | /* This function is called by i2c_probe */ | ||
415 | static int smsc47m192_detect(struct i2c_adapter *adapter, int address, | ||
416 | int kind) | ||
417 | { | ||
418 | struct i2c_client *client; | ||
419 | struct smsc47m192_data *data; | ||
420 | int err = 0; | ||
421 | int version, config; | ||
422 | |||
423 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | ||
424 | goto exit; | ||
425 | |||
426 | if (!(data = kzalloc(sizeof(struct smsc47m192_data), GFP_KERNEL))) { | ||
427 | err = -ENOMEM; | ||
428 | goto exit; | ||
429 | } | ||
430 | |||
431 | client = &data->client; | ||
432 | i2c_set_clientdata(client, data); | ||
433 | client->addr = address; | ||
434 | client->adapter = adapter; | ||
435 | client->driver = &smsc47m192_driver; | ||
436 | |||
437 | if (kind == 0) | ||
438 | kind = smsc47m192; | ||
439 | |||
440 | /* Detection criteria from sensors_detect script */ | ||
441 | if (kind < 0) { | ||
442 | if (i2c_smbus_read_byte_data(client, | ||
443 | SMSC47M192_REG_COMPANY_ID) == 0x55 | ||
444 | && ((version = i2c_smbus_read_byte_data(client, | ||
445 | SMSC47M192_REG_VERSION)) & 0xf0) == 0x20 | ||
446 | && (i2c_smbus_read_byte_data(client, | ||
447 | SMSC47M192_REG_VID) & 0x70) == 0x00 | ||
448 | && (i2c_smbus_read_byte_data(client, | ||
449 | SMSC47M192_REG_VID4) & 0xfe) == 0x80) { | ||
450 | dev_info(&adapter->dev, | ||
451 | "found SMSC47M192 or SMSC47M997, " | ||
452 | "version 2, stepping A%d\n", version & 0x0f); | ||
453 | } else { | ||
454 | dev_dbg(&adapter->dev, | ||
455 | "SMSC47M192 detection failed at 0x%02x\n", | ||
456 | address); | ||
457 | goto exit_free; | ||
458 | } | ||
459 | } | ||
460 | |||
461 | /* Fill in the remaining client fields and put into the global list */ | ||
462 | strlcpy(client->name, "smsc47m192", I2C_NAME_SIZE); | ||
463 | data->vrm = vid_which_vrm(); | ||
464 | init_MUTEX(&data->update_lock); | ||
465 | |||
466 | /* Tell the I2C layer a new client has arrived */ | ||
467 | if ((err = i2c_attach_client(client))) | ||
468 | goto exit_free; | ||
469 | |||
470 | /* Initialize the SMSC47M192 chip */ | ||
471 | smsc47m192_init_client(client); | ||
472 | |||
473 | /* Register sysfs hooks */ | ||
474 | data->class_dev = hwmon_device_register(&client->dev); | ||
475 | if (IS_ERR(data->class_dev)) { | ||
476 | err = PTR_ERR(data->class_dev); | ||
477 | goto exit_detach; | ||
478 | } | ||
479 | |||
480 | device_create_file(&client->dev, &sensor_dev_attr_in0_input.dev_attr); | ||
481 | device_create_file(&client->dev, &sensor_dev_attr_in0_min.dev_attr); | ||
482 | device_create_file(&client->dev, &sensor_dev_attr_in0_max.dev_attr); | ||
483 | device_create_file(&client->dev, &sensor_dev_attr_in0_alarm.dev_attr); | ||
484 | device_create_file(&client->dev, &sensor_dev_attr_in1_input.dev_attr); | ||
485 | device_create_file(&client->dev, &sensor_dev_attr_in1_min.dev_attr); | ||
486 | device_create_file(&client->dev, &sensor_dev_attr_in1_max.dev_attr); | ||
487 | device_create_file(&client->dev, &sensor_dev_attr_in1_alarm.dev_attr); | ||
488 | device_create_file(&client->dev, &sensor_dev_attr_in2_input.dev_attr); | ||
489 | device_create_file(&client->dev, &sensor_dev_attr_in2_min.dev_attr); | ||
490 | device_create_file(&client->dev, &sensor_dev_attr_in2_max.dev_attr); | ||
491 | device_create_file(&client->dev, &sensor_dev_attr_in2_alarm.dev_attr); | ||
492 | device_create_file(&client->dev, &sensor_dev_attr_in3_input.dev_attr); | ||
493 | device_create_file(&client->dev, &sensor_dev_attr_in3_min.dev_attr); | ||
494 | device_create_file(&client->dev, &sensor_dev_attr_in3_max.dev_attr); | ||
495 | device_create_file(&client->dev, &sensor_dev_attr_in3_alarm.dev_attr); | ||
496 | |||
497 | /* Pin 110 is either in4 (+12V) or VID4 */ | ||
498 | config = i2c_smbus_read_byte_data(client, SMSC47M192_REG_CONFIG); | ||
499 | if (!(config & 0x20)) { | ||
500 | device_create_file(&client->dev, | ||
501 | &sensor_dev_attr_in4_input.dev_attr); | ||
502 | device_create_file(&client->dev, | ||
503 | &sensor_dev_attr_in4_min.dev_attr); | ||
504 | device_create_file(&client->dev, | ||
505 | &sensor_dev_attr_in4_max.dev_attr); | ||
506 | device_create_file(&client->dev, | ||
507 | &sensor_dev_attr_in4_alarm.dev_attr); | ||
508 | } | ||
509 | device_create_file(&client->dev, &sensor_dev_attr_in5_input.dev_attr); | ||
510 | device_create_file(&client->dev, &sensor_dev_attr_in5_min.dev_attr); | ||
511 | device_create_file(&client->dev, &sensor_dev_attr_in5_max.dev_attr); | ||
512 | device_create_file(&client->dev, &sensor_dev_attr_in5_alarm.dev_attr); | ||
513 | device_create_file(&client->dev, &sensor_dev_attr_in6_input.dev_attr); | ||
514 | device_create_file(&client->dev, &sensor_dev_attr_in6_min.dev_attr); | ||
515 | device_create_file(&client->dev, &sensor_dev_attr_in6_max.dev_attr); | ||
516 | device_create_file(&client->dev, &sensor_dev_attr_in6_alarm.dev_attr); | ||
517 | device_create_file(&client->dev, &sensor_dev_attr_in7_input.dev_attr); | ||
518 | device_create_file(&client->dev, &sensor_dev_attr_in7_min.dev_attr); | ||
519 | device_create_file(&client->dev, &sensor_dev_attr_in7_max.dev_attr); | ||
520 | device_create_file(&client->dev, &sensor_dev_attr_in7_alarm.dev_attr); | ||
521 | device_create_file(&client->dev, &sensor_dev_attr_temp1_input.dev_attr); | ||
522 | device_create_file(&client->dev, &sensor_dev_attr_temp1_max.dev_attr); | ||
523 | device_create_file(&client->dev, &sensor_dev_attr_temp1_min.dev_attr); | ||
524 | device_create_file(&client->dev, | ||
525 | &sensor_dev_attr_temp1_offset.dev_attr); | ||
526 | device_create_file(&client->dev, &sensor_dev_attr_temp1_alarm.dev_attr); | ||
527 | device_create_file(&client->dev, &sensor_dev_attr_temp2_input.dev_attr); | ||
528 | device_create_file(&client->dev, &sensor_dev_attr_temp2_max.dev_attr); | ||
529 | device_create_file(&client->dev, &sensor_dev_attr_temp2_min.dev_attr); | ||
530 | device_create_file(&client->dev, | ||
531 | &sensor_dev_attr_temp2_offset.dev_attr); | ||
532 | device_create_file(&client->dev, &sensor_dev_attr_temp2_alarm.dev_attr); | ||
533 | device_create_file(&client->dev, | ||
534 | &sensor_dev_attr_temp2_input_fault.dev_attr); | ||
535 | device_create_file(&client->dev, &sensor_dev_attr_temp3_input.dev_attr); | ||
536 | device_create_file(&client->dev, &sensor_dev_attr_temp3_max.dev_attr); | ||
537 | device_create_file(&client->dev, &sensor_dev_attr_temp3_min.dev_attr); | ||
538 | device_create_file(&client->dev, | ||
539 | &sensor_dev_attr_temp3_offset.dev_attr); | ||
540 | device_create_file(&client->dev, &sensor_dev_attr_temp3_alarm.dev_attr); | ||
541 | device_create_file(&client->dev, | ||
542 | &sensor_dev_attr_temp3_input_fault.dev_attr); | ||
543 | device_create_file(&client->dev, &dev_attr_cpu0_vid); | ||
544 | device_create_file(&client->dev, &dev_attr_vrm); | ||
545 | |||
546 | return 0; | ||
547 | |||
548 | exit_detach: | ||
549 | i2c_detach_client(client); | ||
550 | exit_free: | ||
551 | kfree(data); | ||
552 | exit: | ||
553 | return err; | ||
554 | } | ||
555 | |||
556 | static int smsc47m192_detach_client(struct i2c_client *client) | ||
557 | { | ||
558 | struct smsc47m192_data *data = i2c_get_clientdata(client); | ||
559 | int err; | ||
560 | |||
561 | hwmon_device_unregister(data->class_dev); | ||
562 | |||
563 | if ((err = i2c_detach_client(client))) | ||
564 | return err; | ||
565 | |||
566 | kfree(data); | ||
567 | |||
568 | return 0; | ||
569 | } | ||
570 | |||
571 | static struct smsc47m192_data *smsc47m192_update_device(struct device *dev) | ||
572 | { | ||
573 | struct i2c_client *client = to_i2c_client(dev); | ||
574 | struct smsc47m192_data *data = i2c_get_clientdata(client); | ||
575 | int i, config; | ||
576 | |||
577 | down(&data->update_lock); | ||
578 | |||
579 | if (time_after(jiffies, data->last_updated + HZ + HZ / 2) | ||
580 | || !data->valid) { | ||
581 | u8 sfr = i2c_smbus_read_byte_data(client, SMSC47M192_REG_SFR); | ||
582 | |||
583 | dev_dbg(&client->dev, "Starting smsc47m192 update\n"); | ||
584 | |||
585 | for (i = 0; i <= 7; i++) { | ||
586 | data->in[i] = i2c_smbus_read_byte_data(client, | ||
587 | SMSC47M192_REG_IN(i)); | ||
588 | data->in_min[i] = i2c_smbus_read_byte_data(client, | ||
589 | SMSC47M192_REG_IN_MIN(i)); | ||
590 | data->in_max[i] = i2c_smbus_read_byte_data(client, | ||
591 | SMSC47M192_REG_IN_MAX(i)); | ||
592 | } | ||
593 | for (i = 0; i < 3; i++) { | ||
594 | data->temp[i] = i2c_smbus_read_byte_data(client, | ||
595 | SMSC47M192_REG_TEMP[i]); | ||
596 | data->temp_max[i] = i2c_smbus_read_byte_data(client, | ||
597 | SMSC47M192_REG_TEMP_MAX[i]); | ||
598 | data->temp_min[i] = i2c_smbus_read_byte_data(client, | ||
599 | SMSC47M192_REG_TEMP_MIN[i]); | ||
600 | } | ||
601 | for (i = 1; i < 3; i++) | ||
602 | data->temp_offset[i] = i2c_smbus_read_byte_data(client, | ||
603 | SMSC47M192_REG_TEMP_OFFSET(i)); | ||
604 | /* first offset is temp_offset[0] if SFR bit 4 is set, | ||
605 | temp_offset[1] otherwise */ | ||
606 | if (sfr & 0x10) { | ||
607 | data->temp_offset[0] = data->temp_offset[1]; | ||
608 | data->temp_offset[1] = 0; | ||
609 | } else | ||
610 | data->temp_offset[0] = 0; | ||
611 | |||
612 | data->vid = i2c_smbus_read_byte_data(client, SMSC47M192_REG_VID) | ||
613 | & 0x0f; | ||
614 | config = i2c_smbus_read_byte_data(client, | ||
615 | SMSC47M192_REG_CONFIG); | ||
616 | if (config & 0x20) | ||
617 | data->vid |= (i2c_smbus_read_byte_data(client, | ||
618 | SMSC47M192_REG_VID4) & 0x01) << 4; | ||
619 | data->alarms = i2c_smbus_read_byte_data(client, | ||
620 | SMSC47M192_REG_ALARM1) | | ||
621 | (i2c_smbus_read_byte_data(client, | ||
622 | SMSC47M192_REG_ALARM2) << 8); | ||
623 | |||
624 | data->last_updated = jiffies; | ||
625 | data->valid = 1; | ||
626 | } | ||
627 | |||
628 | up(&data->update_lock); | ||
629 | |||
630 | return data; | ||
631 | } | ||
632 | |||
633 | static int __init smsc47m192_init(void) | ||
634 | { | ||
635 | return i2c_add_driver(&smsc47m192_driver); | ||
636 | } | ||
637 | |||
638 | static void __exit smsc47m192_exit(void) | ||
639 | { | ||
640 | i2c_del_driver(&smsc47m192_driver); | ||
641 | } | ||
642 | |||
643 | MODULE_AUTHOR("Hartmut Rick <linux@rick.claranet.de>"); | ||
644 | MODULE_DESCRIPTION("SMSC47M192 driver"); | ||
645 | MODULE_LICENSE("GPL"); | ||
646 | |||
647 | module_init(smsc47m192_init); | ||
648 | module_exit(smsc47m192_exit); | ||
diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index b6bd5685fd38..40301bc6ce18 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c | |||
@@ -30,10 +30,7 @@ | |||
30 | Supports the following chips: | 30 | Supports the following chips: |
31 | 31 | ||
32 | Chip #vin #fan #pwm #temp chip_id man_id | 32 | Chip #vin #fan #pwm #temp chip_id man_id |
33 | w83627ehf - 5 - 3 0x88 0x5ca3 | 33 | w83627ehf 10 5 - 3 0x88 0x5ca3 |
34 | |||
35 | This is a preliminary version of the driver, only supporting the | ||
36 | fan and temperature inputs. The chip does much more than that. | ||
37 | */ | 34 | */ |
38 | 35 | ||
39 | #include <linux/module.h> | 36 | #include <linux/module.h> |
@@ -121,6 +118,14 @@ superio_exit(void) | |||
121 | static const u16 W83627EHF_REG_FAN[] = { 0x28, 0x29, 0x2a, 0x3f, 0x553 }; | 118 | static const u16 W83627EHF_REG_FAN[] = { 0x28, 0x29, 0x2a, 0x3f, 0x553 }; |
122 | static const u16 W83627EHF_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d, 0x3e, 0x55c }; | 119 | static const u16 W83627EHF_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d, 0x3e, 0x55c }; |
123 | 120 | ||
121 | /* The W83627EHF registers for nr=7,8,9 are in bank 5 */ | ||
122 | #define W83627EHF_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \ | ||
123 | (0x554 + (((nr) - 7) * 2))) | ||
124 | #define W83627EHF_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \ | ||
125 | (0x555 + (((nr) - 7) * 2))) | ||
126 | #define W83627EHF_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \ | ||
127 | (0x550 + (nr) - 7)) | ||
128 | |||
124 | #define W83627EHF_REG_TEMP1 0x27 | 129 | #define W83627EHF_REG_TEMP1 0x27 |
125 | #define W83627EHF_REG_TEMP1_HYST 0x3a | 130 | #define W83627EHF_REG_TEMP1_HYST 0x3a |
126 | #define W83627EHF_REG_TEMP1_OVER 0x39 | 131 | #define W83627EHF_REG_TEMP1_OVER 0x39 |
@@ -136,6 +141,10 @@ static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0x152, 0x252 }; | |||
136 | #define W83627EHF_REG_DIODE 0x59 | 141 | #define W83627EHF_REG_DIODE 0x59 |
137 | #define W83627EHF_REG_SMI_OVT 0x4C | 142 | #define W83627EHF_REG_SMI_OVT 0x4C |
138 | 143 | ||
144 | #define W83627EHF_REG_ALARM1 0x459 | ||
145 | #define W83627EHF_REG_ALARM2 0x45A | ||
146 | #define W83627EHF_REG_ALARM3 0x45B | ||
147 | |||
139 | /* | 148 | /* |
140 | * Conversions | 149 | * Conversions |
141 | */ | 150 | */ |
@@ -172,6 +181,20 @@ temp1_to_reg(int temp) | |||
172 | return (temp + 500) / 1000; | 181 | return (temp + 500) / 1000; |
173 | } | 182 | } |
174 | 183 | ||
184 | /* Some of analog inputs have internal scaling (2x), 8mV is ADC LSB */ | ||
185 | |||
186 | static u8 scale_in[10] = { 8, 8, 16, 16, 8, 8, 8, 16, 16, 8 }; | ||
187 | |||
188 | static inline long in_from_reg(u8 reg, u8 nr) | ||
189 | { | ||
190 | return reg * scale_in[nr]; | ||
191 | } | ||
192 | |||
193 | static inline u8 in_to_reg(u32 val, u8 nr) | ||
194 | { | ||
195 | return SENSORS_LIMIT(((val + (scale_in[nr] / 2)) / scale_in[nr]), 0, 255); | ||
196 | } | ||
197 | |||
175 | /* | 198 | /* |
176 | * Data structures and manipulation thereof | 199 | * Data structures and manipulation thereof |
177 | */ | 200 | */ |
@@ -186,6 +209,9 @@ struct w83627ehf_data { | |||
186 | unsigned long last_updated; /* In jiffies */ | 209 | unsigned long last_updated; /* In jiffies */ |
187 | 210 | ||
188 | /* Register values */ | 211 | /* Register values */ |
212 | u8 in[10]; /* Register value */ | ||
213 | u8 in_max[10]; /* Register value */ | ||
214 | u8 in_min[10]; /* Register value */ | ||
189 | u8 fan[5]; | 215 | u8 fan[5]; |
190 | u8 fan_min[5]; | 216 | u8 fan_min[5]; |
191 | u8 fan_div[5]; | 217 | u8 fan_div[5]; |
@@ -196,6 +222,7 @@ struct w83627ehf_data { | |||
196 | s16 temp[2]; | 222 | s16 temp[2]; |
197 | s16 temp_max[2]; | 223 | s16 temp_max[2]; |
198 | s16 temp_max_hyst[2]; | 224 | s16 temp_max_hyst[2]; |
225 | u32 alarms; | ||
199 | }; | 226 | }; |
200 | 227 | ||
201 | static inline int is_word_sized(u16 reg) | 228 | static inline int is_word_sized(u16 reg) |
@@ -349,6 +376,16 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev) | |||
349 | data->fan_div[3] |= (i >> 5) & 0x04; | 376 | data->fan_div[3] |= (i >> 5) & 0x04; |
350 | } | 377 | } |
351 | 378 | ||
379 | /* Measured voltages and limits */ | ||
380 | for (i = 0; i < 10; i++) { | ||
381 | data->in[i] = w83627ehf_read_value(client, | ||
382 | W83627EHF_REG_IN(i)); | ||
383 | data->in_min[i] = w83627ehf_read_value(client, | ||
384 | W83627EHF_REG_IN_MIN(i)); | ||
385 | data->in_max[i] = w83627ehf_read_value(client, | ||
386 | W83627EHF_REG_IN_MAX(i)); | ||
387 | } | ||
388 | |||
352 | /* Measured fan speeds and limits */ | 389 | /* Measured fan speeds and limits */ |
353 | for (i = 0; i < 5; i++) { | 390 | for (i = 0; i < 5; i++) { |
354 | if (!(data->has_fan & (1 << i))) | 391 | if (!(data->has_fan & (1 << i))) |
@@ -395,6 +432,13 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev) | |||
395 | W83627EHF_REG_TEMP_HYST[i]); | 432 | W83627EHF_REG_TEMP_HYST[i]); |
396 | } | 433 | } |
397 | 434 | ||
435 | data->alarms = w83627ehf_read_value(client, | ||
436 | W83627EHF_REG_ALARM1) | | ||
437 | (w83627ehf_read_value(client, | ||
438 | W83627EHF_REG_ALARM2) << 8) | | ||
439 | (w83627ehf_read_value(client, | ||
440 | W83627EHF_REG_ALARM3) << 16); | ||
441 | |||
398 | data->last_updated = jiffies; | 442 | data->last_updated = jiffies; |
399 | data->valid = 1; | 443 | data->valid = 1; |
400 | } | 444 | } |
@@ -406,6 +450,109 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev) | |||
406 | /* | 450 | /* |
407 | * Sysfs callback functions | 451 | * Sysfs callback functions |
408 | */ | 452 | */ |
453 | #define show_in_reg(reg) \ | ||
454 | static ssize_t \ | ||
455 | show_##reg(struct device *dev, struct device_attribute *attr, \ | ||
456 | char *buf) \ | ||
457 | { \ | ||
458 | struct w83627ehf_data *data = w83627ehf_update_device(dev); \ | ||
459 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \ | ||
460 | int nr = sensor_attr->index; \ | ||
461 | return sprintf(buf, "%ld\n", in_from_reg(data->reg[nr], nr)); \ | ||
462 | } | ||
463 | show_in_reg(in) | ||
464 | show_in_reg(in_min) | ||
465 | show_in_reg(in_max) | ||
466 | |||
467 | #define store_in_reg(REG, reg) \ | ||
468 | static ssize_t \ | ||
469 | store_in_##reg (struct device *dev, struct device_attribute *attr, \ | ||
470 | const char *buf, size_t count) \ | ||
471 | { \ | ||
472 | struct i2c_client *client = to_i2c_client(dev); \ | ||
473 | struct w83627ehf_data *data = i2c_get_clientdata(client); \ | ||
474 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \ | ||
475 | int nr = sensor_attr->index; \ | ||
476 | u32 val = simple_strtoul(buf, NULL, 10); \ | ||
477 | \ | ||
478 | mutex_lock(&data->update_lock); \ | ||
479 | data->in_##reg[nr] = in_to_reg(val, nr); \ | ||
480 | w83627ehf_write_value(client, W83627EHF_REG_IN_##REG(nr), \ | ||
481 | data->in_##reg[nr]); \ | ||
482 | mutex_unlock(&data->update_lock); \ | ||
483 | return count; \ | ||
484 | } | ||
485 | |||
486 | store_in_reg(MIN, min) | ||
487 | store_in_reg(MAX, max) | ||
488 | |||
489 | static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, char *buf) | ||
490 | { | ||
491 | struct w83627ehf_data *data = w83627ehf_update_device(dev); | ||
492 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | ||
493 | int nr = sensor_attr->index; | ||
494 | return sprintf(buf, "%u\n", (data->alarms >> nr) & 0x01); | ||
495 | } | ||
496 | |||
497 | static struct sensor_device_attribute sda_in_input[] = { | ||
498 | SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0), | ||
499 | SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1), | ||
500 | SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2), | ||
501 | SENSOR_ATTR(in3_input, S_IRUGO, show_in, NULL, 3), | ||
502 | SENSOR_ATTR(in4_input, S_IRUGO, show_in, NULL, 4), | ||
503 | SENSOR_ATTR(in5_input, S_IRUGO, show_in, NULL, 5), | ||
504 | SENSOR_ATTR(in6_input, S_IRUGO, show_in, NULL, 6), | ||
505 | SENSOR_ATTR(in7_input, S_IRUGO, show_in, NULL, 7), | ||
506 | SENSOR_ATTR(in8_input, S_IRUGO, show_in, NULL, 8), | ||
507 | SENSOR_ATTR(in9_input, S_IRUGO, show_in, NULL, 9), | ||
508 | }; | ||
509 | |||
510 | static struct sensor_device_attribute sda_in_alarm[] = { | ||
511 | SENSOR_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0), | ||
512 | SENSOR_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1), | ||
513 | SENSOR_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2), | ||
514 | SENSOR_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3), | ||
515 | SENSOR_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8), | ||
516 | SENSOR_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 21), | ||
517 | SENSOR_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 20), | ||
518 | SENSOR_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 16), | ||
519 | SENSOR_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 17), | ||
520 | SENSOR_ATTR(in9_alarm, S_IRUGO, show_alarm, NULL, 19), | ||
521 | }; | ||
522 | |||
523 | static struct sensor_device_attribute sda_in_min[] = { | ||
524 | SENSOR_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 0), | ||
525 | SENSOR_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 1), | ||
526 | SENSOR_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 2), | ||
527 | SENSOR_ATTR(in3_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 3), | ||
528 | SENSOR_ATTR(in4_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 4), | ||
529 | SENSOR_ATTR(in5_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 5), | ||
530 | SENSOR_ATTR(in6_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 6), | ||
531 | SENSOR_ATTR(in7_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 7), | ||
532 | SENSOR_ATTR(in8_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 8), | ||
533 | SENSOR_ATTR(in9_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 9), | ||
534 | }; | ||
535 | |||
536 | static struct sensor_device_attribute sda_in_max[] = { | ||
537 | SENSOR_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 0), | ||
538 | SENSOR_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 1), | ||
539 | SENSOR_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 2), | ||
540 | SENSOR_ATTR(in3_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 3), | ||
541 | SENSOR_ATTR(in4_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 4), | ||
542 | SENSOR_ATTR(in5_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 5), | ||
543 | SENSOR_ATTR(in6_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 6), | ||
544 | SENSOR_ATTR(in7_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 7), | ||
545 | SENSOR_ATTR(in8_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 8), | ||
546 | SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 9), | ||
547 | }; | ||
548 | |||
549 | static void device_create_file_in(struct device *dev, int i) | ||
550 | { | ||
551 | device_create_file(dev, &sda_in_input[i].dev_attr); | ||
552 | device_create_file(dev, &sda_in_alarm[i].dev_attr); | ||
553 | device_create_file(dev, &sda_in_min[i].dev_attr); | ||
554 | device_create_file(dev, &sda_in_max[i].dev_attr); | ||
555 | } | ||
409 | 556 | ||
410 | #define show_fan_reg(reg) \ | 557 | #define show_fan_reg(reg) \ |
411 | static ssize_t \ | 558 | static ssize_t \ |
@@ -505,6 +652,14 @@ static struct sensor_device_attribute sda_fan_input[] = { | |||
505 | SENSOR_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 4), | 652 | SENSOR_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 4), |
506 | }; | 653 | }; |
507 | 654 | ||
655 | static struct sensor_device_attribute sda_fan_alarm[] = { | ||
656 | SENSOR_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6), | ||
657 | SENSOR_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7), | ||
658 | SENSOR_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11), | ||
659 | SENSOR_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 10), | ||
660 | SENSOR_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 23), | ||
661 | }; | ||
662 | |||
508 | static struct sensor_device_attribute sda_fan_min[] = { | 663 | static struct sensor_device_attribute sda_fan_min[] = { |
509 | SENSOR_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min, | 664 | SENSOR_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min, |
510 | store_fan_min, 0), | 665 | store_fan_min, 0), |
@@ -529,6 +684,7 @@ static struct sensor_device_attribute sda_fan_div[] = { | |||
529 | static void device_create_file_fan(struct device *dev, int i) | 684 | static void device_create_file_fan(struct device *dev, int i) |
530 | { | 685 | { |
531 | device_create_file(dev, &sda_fan_input[i].dev_attr); | 686 | device_create_file(dev, &sda_fan_input[i].dev_attr); |
687 | device_create_file(dev, &sda_fan_alarm[i].dev_attr); | ||
532 | device_create_file(dev, &sda_fan_div[i].dev_attr); | 688 | device_create_file(dev, &sda_fan_div[i].dev_attr); |
533 | device_create_file(dev, &sda_fan_min[i].dev_attr); | 689 | device_create_file(dev, &sda_fan_min[i].dev_attr); |
534 | } | 690 | } |
@@ -616,6 +772,9 @@ static struct sensor_device_attribute sda_temp[] = { | |||
616 | store_temp_max_hyst, 0), | 772 | store_temp_max_hyst, 0), |
617 | SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst, | 773 | SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst, |
618 | store_temp_max_hyst, 1), | 774 | store_temp_max_hyst, 1), |
775 | SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4), | ||
776 | SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5), | ||
777 | SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13), | ||
619 | }; | 778 | }; |
620 | 779 | ||
621 | /* | 780 | /* |
@@ -705,6 +864,9 @@ static int w83627ehf_detect(struct i2c_adapter *adapter) | |||
705 | goto exit_detach; | 864 | goto exit_detach; |
706 | } | 865 | } |
707 | 866 | ||
867 | for (i = 0; i < 10; i++) | ||
868 | device_create_file_in(dev, i); | ||
869 | |||
708 | for (i = 0; i < 5; i++) { | 870 | for (i = 0; i < 5; i++) { |
709 | if (data->has_fan & (1 << i)) | 871 | if (data->has_fan & (1 << i)) |
710 | device_create_file_fan(dev, i); | 872 | device_create_file_fan(dev, i); |
diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c new file mode 100644 index 000000000000..eec43abd57fb --- /dev/null +++ b/drivers/hwmon/w83791d.c | |||
@@ -0,0 +1,1255 @@ | |||
1 | /* | ||
2 | w83791d.c - Part of lm_sensors, Linux kernel modules for hardware | ||
3 | monitoring | ||
4 | |||
5 | Copyright (C) 2006 Charles Spirakis <bezaur@gmail.com> | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2 of the License, or | ||
10 | (at your option) any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; if not, write to the Free Software | ||
19 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | ||
21 | |||
22 | /* | ||
23 | Supports following chips: | ||
24 | |||
25 | Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA | ||
26 | w83791d 10 5 3 3 0x71 0x5ca3 yes no | ||
27 | |||
28 | The w83791d chip appears to be part way between the 83781d and the | ||
29 | 83792d. Thus, this file is derived from both the w83792d.c and | ||
30 | w83781d.c files, but its output is more along the lines of the | ||
31 | 83781d (which means there are no changes to the user-mode sensors | ||
32 | program which treats the 83791d as an 83781d). | ||
33 | */ | ||
34 | |||
35 | #include <linux/config.h> | ||
36 | #include <linux/module.h> | ||
37 | #include <linux/init.h> | ||
38 | #include <linux/slab.h> | ||
39 | #include <linux/i2c.h> | ||
40 | #include <linux/hwmon.h> | ||
41 | #include <linux/hwmon-vid.h> | ||
42 | #include <linux/hwmon-sysfs.h> | ||
43 | #include <linux/err.h> | ||
44 | #include <linux/mutex.h> | ||
45 | |||
46 | #define NUMBER_OF_VIN 10 | ||
47 | #define NUMBER_OF_FANIN 5 | ||
48 | #define NUMBER_OF_TEMPIN 3 | ||
49 | |||
50 | /* Addresses to scan */ | ||
51 | static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END }; | ||
52 | |||
53 | /* Insmod parameters */ | ||
54 | I2C_CLIENT_INSMOD_1(w83791d); | ||
55 | I2C_CLIENT_MODULE_PARM(force_subclients, "List of subclient addresses: " | ||
56 | "{bus, clientaddr, subclientaddr1, subclientaddr2}"); | ||
57 | |||
58 | static int reset; | ||
59 | module_param(reset, bool, 0); | ||
60 | MODULE_PARM_DESC(reset, "Set to one to force a hardware chip reset"); | ||
61 | |||
62 | static int init; | ||
63 | module_param(init, bool, 0); | ||
64 | MODULE_PARM_DESC(init, "Set to one to force extra software initialization"); | ||
65 | |||
66 | /* The W83791D registers */ | ||
67 | static const u8 W83791D_REG_IN[NUMBER_OF_VIN] = { | ||
68 | 0x20, /* VCOREA in DataSheet */ | ||
69 | 0x21, /* VINR0 in DataSheet */ | ||
70 | 0x22, /* +3.3VIN in DataSheet */ | ||
71 | 0x23, /* VDD5V in DataSheet */ | ||
72 | 0x24, /* +12VIN in DataSheet */ | ||
73 | 0x25, /* -12VIN in DataSheet */ | ||
74 | 0x26, /* -5VIN in DataSheet */ | ||
75 | 0xB0, /* 5VSB in DataSheet */ | ||
76 | 0xB1, /* VBAT in DataSheet */ | ||
77 | 0xB2 /* VINR1 in DataSheet */ | ||
78 | }; | ||
79 | |||
80 | static const u8 W83791D_REG_IN_MAX[NUMBER_OF_VIN] = { | ||
81 | 0x2B, /* VCOREA High Limit in DataSheet */ | ||
82 | 0x2D, /* VINR0 High Limit in DataSheet */ | ||
83 | 0x2F, /* +3.3VIN High Limit in DataSheet */ | ||
84 | 0x31, /* VDD5V High Limit in DataSheet */ | ||
85 | 0x33, /* +12VIN High Limit in DataSheet */ | ||
86 | 0x35, /* -12VIN High Limit in DataSheet */ | ||
87 | 0x37, /* -5VIN High Limit in DataSheet */ | ||
88 | 0xB4, /* 5VSB High Limit in DataSheet */ | ||
89 | 0xB6, /* VBAT High Limit in DataSheet */ | ||
90 | 0xB8 /* VINR1 High Limit in DataSheet */ | ||
91 | }; | ||
92 | static const u8 W83791D_REG_IN_MIN[NUMBER_OF_VIN] = { | ||
93 | 0x2C, /* VCOREA Low Limit in DataSheet */ | ||
94 | 0x2E, /* VINR0 Low Limit in DataSheet */ | ||
95 | 0x30, /* +3.3VIN Low Limit in DataSheet */ | ||
96 | 0x32, /* VDD5V Low Limit in DataSheet */ | ||
97 | 0x34, /* +12VIN Low Limit in DataSheet */ | ||
98 | 0x36, /* -12VIN Low Limit in DataSheet */ | ||
99 | 0x38, /* -5VIN Low Limit in DataSheet */ | ||
100 | 0xB5, /* 5VSB Low Limit in DataSheet */ | ||
101 | 0xB7, /* VBAT Low Limit in DataSheet */ | ||
102 | 0xB9 /* VINR1 Low Limit in DataSheet */ | ||
103 | }; | ||
104 | static const u8 W83791D_REG_FAN[NUMBER_OF_FANIN] = { | ||
105 | 0x28, /* FAN 1 Count in DataSheet */ | ||
106 | 0x29, /* FAN 2 Count in DataSheet */ | ||
107 | 0x2A, /* FAN 3 Count in DataSheet */ | ||
108 | 0xBA, /* FAN 4 Count in DataSheet */ | ||
109 | 0xBB, /* FAN 5 Count in DataSheet */ | ||
110 | }; | ||
111 | static const u8 W83791D_REG_FAN_MIN[NUMBER_OF_FANIN] = { | ||
112 | 0x3B, /* FAN 1 Count Low Limit in DataSheet */ | ||
113 | 0x3C, /* FAN 2 Count Low Limit in DataSheet */ | ||
114 | 0x3D, /* FAN 3 Count Low Limit in DataSheet */ | ||
115 | 0xBC, /* FAN 4 Count Low Limit in DataSheet */ | ||
116 | 0xBD, /* FAN 5 Count Low Limit in DataSheet */ | ||
117 | }; | ||
118 | |||
119 | static const u8 W83791D_REG_FAN_CFG[2] = { | ||
120 | 0x84, /* FAN 1/2 configuration */ | ||
121 | 0x95, /* FAN 3 configuration */ | ||
122 | }; | ||
123 | |||
124 | static const u8 W83791D_REG_FAN_DIV[3] = { | ||
125 | 0x47, /* contains FAN1 and FAN2 Divisor */ | ||
126 | 0x4b, /* contains FAN3 Divisor */ | ||
127 | 0x5C, /* contains FAN4 and FAN5 Divisor */ | ||
128 | }; | ||
129 | |||
130 | #define W83791D_REG_BANK 0x4E | ||
131 | #define W83791D_REG_TEMP2_CONFIG 0xC2 | ||
132 | #define W83791D_REG_TEMP3_CONFIG 0xCA | ||
133 | |||
134 | static const u8 W83791D_REG_TEMP1[3] = { | ||
135 | 0x27, /* TEMP 1 in DataSheet */ | ||
136 | 0x39, /* TEMP 1 Over in DataSheet */ | ||
137 | 0x3A, /* TEMP 1 Hyst in DataSheet */ | ||
138 | }; | ||
139 | |||
140 | static const u8 W83791D_REG_TEMP_ADD[2][6] = { | ||
141 | {0xC0, /* TEMP 2 in DataSheet */ | ||
142 | 0xC1, /* TEMP 2(0.5 deg) in DataSheet */ | ||
143 | 0xC5, /* TEMP 2 Over High part in DataSheet */ | ||
144 | 0xC6, /* TEMP 2 Over Low part in DataSheet */ | ||
145 | 0xC3, /* TEMP 2 Thyst High part in DataSheet */ | ||
146 | 0xC4}, /* TEMP 2 Thyst Low part in DataSheet */ | ||
147 | {0xC8, /* TEMP 3 in DataSheet */ | ||
148 | 0xC9, /* TEMP 3(0.5 deg) in DataSheet */ | ||
149 | 0xCD, /* TEMP 3 Over High part in DataSheet */ | ||
150 | 0xCE, /* TEMP 3 Over Low part in DataSheet */ | ||
151 | 0xCB, /* TEMP 3 Thyst High part in DataSheet */ | ||
152 | 0xCC} /* TEMP 3 Thyst Low part in DataSheet */ | ||
153 | }; | ||
154 | |||
155 | #define W83791D_REG_BEEP_CONFIG 0x4D | ||
156 | |||
157 | static const u8 W83791D_REG_BEEP_CTRL[3] = { | ||
158 | 0x56, /* BEEP Control Register 1 */ | ||
159 | 0x57, /* BEEP Control Register 2 */ | ||
160 | 0xA3, /* BEEP Control Register 3 */ | ||
161 | }; | ||
162 | |||
163 | #define W83791D_REG_CONFIG 0x40 | ||
164 | #define W83791D_REG_VID_FANDIV 0x47 | ||
165 | #define W83791D_REG_DID_VID4 0x49 | ||
166 | #define W83791D_REG_WCHIPID 0x58 | ||
167 | #define W83791D_REG_CHIPMAN 0x4F | ||
168 | #define W83791D_REG_PIN 0x4B | ||
169 | #define W83791D_REG_I2C_SUBADDR 0x4A | ||
170 | |||
171 | #define W83791D_REG_ALARM1 0xA9 /* realtime status register1 */ | ||
172 | #define W83791D_REG_ALARM2 0xAA /* realtime status register2 */ | ||
173 | #define W83791D_REG_ALARM3 0xAB /* realtime status register3 */ | ||
174 | |||
175 | #define W83791D_REG_VBAT 0x5D | ||
176 | #define W83791D_REG_I2C_ADDR 0x48 | ||
177 | |||
178 | /* The SMBus locks itself. The Winbond W83791D has a bank select register | ||
179 | (index 0x4e), but the driver only accesses registers in bank 0. Since | ||
180 | we don't switch banks, we don't need any special code to handle | ||
181 | locking access between bank switches */ | ||
182 | static inline int w83791d_read(struct i2c_client *client, u8 reg) | ||
183 | { | ||
184 | return i2c_smbus_read_byte_data(client, reg); | ||
185 | } | ||
186 | |||
187 | static inline int w83791d_write(struct i2c_client *client, u8 reg, u8 value) | ||
188 | { | ||
189 | return i2c_smbus_write_byte_data(client, reg, value); | ||
190 | } | ||
191 | |||
192 | /* The analog voltage inputs have 16mV LSB. Since the sysfs output is | ||
193 | in mV as would be measured on the chip input pin, need to just | ||
194 | multiply/divide by 16 to translate from/to register values. */ | ||
195 | #define IN_TO_REG(val) (SENSORS_LIMIT((((val) + 8) / 16), 0, 255)) | ||
196 | #define IN_FROM_REG(val) ((val) * 16) | ||
197 | |||
198 | static u8 fan_to_reg(long rpm, int div) | ||
199 | { | ||
200 | if (rpm == 0) | ||
201 | return 255; | ||
202 | rpm = SENSORS_LIMIT(rpm, 1, 1000000); | ||
203 | return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254); | ||
204 | } | ||
205 | |||
206 | #define FAN_FROM_REG(val,div) ((val) == 0 ? -1 : \ | ||
207 | ((val) == 255 ? 0 : \ | ||
208 | 1350000 / ((val) * (div)))) | ||
209 | |||
210 | /* for temp1 which is 8-bit resolution, LSB = 1 degree Celsius */ | ||
211 | #define TEMP1_FROM_REG(val) ((val) * 1000) | ||
212 | #define TEMP1_TO_REG(val) ((val) <= -128000 ? -128 : \ | ||
213 | (val) >= 127000 ? 127 : \ | ||
214 | (val) < 0 ? ((val) - 500) / 1000 : \ | ||
215 | ((val) + 500) / 1000) | ||
216 | |||
217 | /* for temp2 and temp3 which are 9-bit resolution, LSB = 0.5 degree Celsius | ||
218 | Assumes the top 8 bits are the integral amount and the bottom 8 bits | ||
219 | are the fractional amount. Since we only have 0.5 degree resolution, | ||
220 | the bottom 7 bits will always be zero */ | ||
221 | #define TEMP23_FROM_REG(val) ((val) / 128 * 500) | ||
222 | #define TEMP23_TO_REG(val) ((val) <= -128000 ? 0x8000 : \ | ||
223 | (val) >= 127500 ? 0x7F80 : \ | ||
224 | (val) < 0 ? ((val) - 250) / 500 * 128 : \ | ||
225 | ((val) + 250) / 500 * 128) | ||
226 | |||
227 | |||
228 | #define BEEP_MASK_TO_REG(val) ((val) & 0xffffff) | ||
229 | #define BEEP_MASK_FROM_REG(val) ((val) & 0xffffff) | ||
230 | |||
231 | #define DIV_FROM_REG(val) (1 << (val)) | ||
232 | |||
233 | static u8 div_to_reg(int nr, long val) | ||
234 | { | ||
235 | int i; | ||
236 | int max; | ||
237 | |||
238 | /* first three fan's divisor max out at 8, rest max out at 128 */ | ||
239 | max = (nr < 3) ? 8 : 128; | ||
240 | val = SENSORS_LIMIT(val, 1, max) >> 1; | ||
241 | for (i = 0; i < 7; i++) { | ||
242 | if (val == 0) | ||
243 | break; | ||
244 | val >>= 1; | ||
245 | } | ||
246 | return (u8) i; | ||
247 | } | ||
248 | |||
249 | struct w83791d_data { | ||
250 | struct i2c_client client; | ||
251 | struct class_device *class_dev; | ||
252 | struct mutex update_lock; | ||
253 | |||
254 | char valid; /* !=0 if following fields are valid */ | ||
255 | unsigned long last_updated; /* In jiffies */ | ||
256 | |||
257 | /* array of 2 pointers to subclients */ | ||
258 | struct i2c_client *lm75[2]; | ||
259 | |||
260 | /* volts */ | ||
261 | u8 in[NUMBER_OF_VIN]; /* Register value */ | ||
262 | u8 in_max[NUMBER_OF_VIN]; /* Register value */ | ||
263 | u8 in_min[NUMBER_OF_VIN]; /* Register value */ | ||
264 | |||
265 | /* fans */ | ||
266 | u8 fan[NUMBER_OF_FANIN]; /* Register value */ | ||
267 | u8 fan_min[NUMBER_OF_FANIN]; /* Register value */ | ||
268 | u8 fan_div[NUMBER_OF_FANIN]; /* Register encoding, shifted right */ | ||
269 | |||
270 | /* Temperature sensors */ | ||
271 | |||
272 | s8 temp1[3]; /* current, over, thyst */ | ||
273 | s16 temp_add[2][3]; /* fixed point value. Top 8 bits are the | ||
274 | integral part, bottom 8 bits are the | ||
275 | fractional part. We only use the top | ||
276 | 9 bits as the resolution is only | ||
277 | to the 0.5 degree C... | ||
278 | two sensors with three values | ||
279 | (cur, over, hyst) */ | ||
280 | |||
281 | /* Misc */ | ||
282 | u32 alarms; /* realtime status register encoding,combined */ | ||
283 | u8 beep_enable; /* Global beep enable */ | ||
284 | u32 beep_mask; /* Mask off specific beeps */ | ||
285 | u8 vid; /* Register encoding, combined */ | ||
286 | u8 vrm; /* hwmon-vid */ | ||
287 | }; | ||
288 | |||
289 | static int w83791d_attach_adapter(struct i2c_adapter *adapter); | ||
290 | static int w83791d_detect(struct i2c_adapter *adapter, int address, int kind); | ||
291 | static int w83791d_detach_client(struct i2c_client *client); | ||
292 | |||
293 | static int w83791d_read(struct i2c_client *client, u8 register); | ||
294 | static int w83791d_write(struct i2c_client *client, u8 register, u8 value); | ||
295 | static struct w83791d_data *w83791d_update_device(struct device *dev); | ||
296 | |||
297 | #ifdef DEBUG | ||
298 | static void w83791d_print_debug(struct w83791d_data *data, struct device *dev); | ||
299 | #endif | ||
300 | |||
301 | static void w83791d_init_client(struct i2c_client *client); | ||
302 | |||
303 | static struct i2c_driver w83791d_driver = { | ||
304 | .driver = { | ||
305 | .name = "w83791d", | ||
306 | }, | ||
307 | .attach_adapter = w83791d_attach_adapter, | ||
308 | .detach_client = w83791d_detach_client, | ||
309 | }; | ||
310 | |||
311 | /* following are the sysfs callback functions */ | ||
312 | #define show_in_reg(reg) \ | ||
313 | static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \ | ||
314 | char *buf) \ | ||
315 | { \ | ||
316 | struct sensor_device_attribute *sensor_attr = \ | ||
317 | to_sensor_dev_attr(attr); \ | ||
318 | struct w83791d_data *data = w83791d_update_device(dev); \ | ||
319 | int nr = sensor_attr->index; \ | ||
320 | return sprintf(buf,"%d\n", IN_FROM_REG(data->reg[nr])); \ | ||
321 | } | ||
322 | |||
323 | show_in_reg(in); | ||
324 | show_in_reg(in_min); | ||
325 | show_in_reg(in_max); | ||
326 | |||
327 | #define store_in_reg(REG, reg) \ | ||
328 | static ssize_t store_in_##reg(struct device *dev, \ | ||
329 | struct device_attribute *attr, \ | ||
330 | const char *buf, size_t count) \ | ||
331 | { \ | ||
332 | struct sensor_device_attribute *sensor_attr = \ | ||
333 | to_sensor_dev_attr(attr); \ | ||
334 | struct i2c_client *client = to_i2c_client(dev); \ | ||
335 | struct w83791d_data *data = i2c_get_clientdata(client); \ | ||
336 | unsigned long val = simple_strtoul(buf, NULL, 10); \ | ||
337 | int nr = sensor_attr->index; \ | ||
338 | \ | ||
339 | mutex_lock(&data->update_lock); \ | ||
340 | data->in_##reg[nr] = IN_TO_REG(val); \ | ||
341 | w83791d_write(client, W83791D_REG_IN_##REG[nr], data->in_##reg[nr]); \ | ||
342 | mutex_unlock(&data->update_lock); \ | ||
343 | \ | ||
344 | return count; \ | ||
345 | } | ||
346 | store_in_reg(MIN, min); | ||
347 | store_in_reg(MAX, max); | ||
348 | |||
349 | static struct sensor_device_attribute sda_in_input[] = { | ||
350 | SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0), | ||
351 | SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1), | ||
352 | SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2), | ||
353 | SENSOR_ATTR(in3_input, S_IRUGO, show_in, NULL, 3), | ||
354 | SENSOR_ATTR(in4_input, S_IRUGO, show_in, NULL, 4), | ||
355 | SENSOR_ATTR(in5_input, S_IRUGO, show_in, NULL, 5), | ||
356 | SENSOR_ATTR(in6_input, S_IRUGO, show_in, NULL, 6), | ||
357 | SENSOR_ATTR(in7_input, S_IRUGO, show_in, NULL, 7), | ||
358 | SENSOR_ATTR(in8_input, S_IRUGO, show_in, NULL, 8), | ||
359 | SENSOR_ATTR(in9_input, S_IRUGO, show_in, NULL, 9), | ||
360 | }; | ||
361 | |||
362 | static struct sensor_device_attribute sda_in_min[] = { | ||
363 | SENSOR_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 0), | ||
364 | SENSOR_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 1), | ||
365 | SENSOR_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 2), | ||
366 | SENSOR_ATTR(in3_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 3), | ||
367 | SENSOR_ATTR(in4_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 4), | ||
368 | SENSOR_ATTR(in5_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 5), | ||
369 | SENSOR_ATTR(in6_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 6), | ||
370 | SENSOR_ATTR(in7_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 7), | ||
371 | SENSOR_ATTR(in8_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 8), | ||
372 | SENSOR_ATTR(in9_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 9), | ||
373 | }; | ||
374 | |||
375 | static struct sensor_device_attribute sda_in_max[] = { | ||
376 | SENSOR_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 0), | ||
377 | SENSOR_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 1), | ||
378 | SENSOR_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 2), | ||
379 | SENSOR_ATTR(in3_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 3), | ||
380 | SENSOR_ATTR(in4_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 4), | ||
381 | SENSOR_ATTR(in5_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 5), | ||
382 | SENSOR_ATTR(in6_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 6), | ||
383 | SENSOR_ATTR(in7_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 7), | ||
384 | SENSOR_ATTR(in8_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 8), | ||
385 | SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 9), | ||
386 | }; | ||
387 | |||
388 | #define show_fan_reg(reg) \ | ||
389 | static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \ | ||
390 | char *buf) \ | ||
391 | { \ | ||
392 | struct sensor_device_attribute *sensor_attr = \ | ||
393 | to_sensor_dev_attr(attr); \ | ||
394 | struct w83791d_data *data = w83791d_update_device(dev); \ | ||
395 | int nr = sensor_attr->index; \ | ||
396 | return sprintf(buf,"%d\n", \ | ||
397 | FAN_FROM_REG(data->reg[nr], DIV_FROM_REG(data->fan_div[nr]))); \ | ||
398 | } | ||
399 | |||
400 | show_fan_reg(fan); | ||
401 | show_fan_reg(fan_min); | ||
402 | |||
403 | static ssize_t store_fan_min(struct device *dev, struct device_attribute *attr, | ||
404 | const char *buf, size_t count) | ||
405 | { | ||
406 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | ||
407 | struct i2c_client *client = to_i2c_client(dev); | ||
408 | struct w83791d_data *data = i2c_get_clientdata(client); | ||
409 | unsigned long val = simple_strtoul(buf, NULL, 10); | ||
410 | int nr = sensor_attr->index; | ||
411 | |||
412 | mutex_lock(&data->update_lock); | ||
413 | data->fan_min[nr] = fan_to_reg(val, DIV_FROM_REG(data->fan_div[nr])); | ||
414 | w83791d_write(client, W83791D_REG_FAN_MIN[nr], data->fan_min[nr]); | ||
415 | mutex_unlock(&data->update_lock); | ||
416 | |||
417 | return count; | ||
418 | } | ||
419 | |||
420 | static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr, | ||
421 | char *buf) | ||
422 | { | ||
423 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | ||
424 | int nr = sensor_attr->index; | ||
425 | struct w83791d_data *data = w83791d_update_device(dev); | ||
426 | return sprintf(buf, "%u\n", DIV_FROM_REG(data->fan_div[nr])); | ||
427 | } | ||
428 | |||
429 | /* Note: we save and restore the fan minimum here, because its value is | ||
430 | determined in part by the fan divisor. This follows the principle of | ||
431 | least suprise; the user doesn't expect the fan minimum to change just | ||
432 | because the divisor changed. */ | ||
433 | static ssize_t store_fan_div(struct device *dev, struct device_attribute *attr, | ||
434 | const char *buf, size_t count) | ||
435 | { | ||
436 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | ||
437 | struct i2c_client *client = to_i2c_client(dev); | ||
438 | struct w83791d_data *data = i2c_get_clientdata(client); | ||
439 | int nr = sensor_attr->index; | ||
440 | unsigned long min; | ||
441 | u8 tmp_fan_div; | ||
442 | u8 fan_div_reg; | ||
443 | int indx = 0; | ||
444 | u8 keep_mask = 0; | ||
445 | u8 new_shift = 0; | ||
446 | |||
447 | /* Save fan_min */ | ||
448 | min = FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])); | ||
449 | |||
450 | mutex_lock(&data->update_lock); | ||
451 | data->fan_div[nr] = div_to_reg(nr, simple_strtoul(buf, NULL, 10)); | ||
452 | |||
453 | switch (nr) { | ||
454 | case 0: | ||
455 | indx = 0; | ||
456 | keep_mask = 0xcf; | ||
457 | new_shift = 4; | ||
458 | break; | ||
459 | case 1: | ||
460 | indx = 0; | ||
461 | keep_mask = 0x3f; | ||
462 | new_shift = 6; | ||
463 | break; | ||
464 | case 2: | ||
465 | indx = 1; | ||
466 | keep_mask = 0x3f; | ||
467 | new_shift = 6; | ||
468 | break; | ||
469 | case 3: | ||
470 | indx = 2; | ||
471 | keep_mask = 0xf8; | ||
472 | new_shift = 0; | ||
473 | break; | ||
474 | case 4: | ||
475 | indx = 2; | ||
476 | keep_mask = 0x8f; | ||
477 | new_shift = 4; | ||
478 | break; | ||
479 | #ifdef DEBUG | ||
480 | default: | ||
481 | dev_warn(dev, "store_fan_div: Unexpected nr seen: %d\n", nr); | ||
482 | count = -EINVAL; | ||
483 | goto err_exit; | ||
484 | #endif | ||
485 | } | ||
486 | |||
487 | fan_div_reg = w83791d_read(client, W83791D_REG_FAN_DIV[indx]) | ||
488 | & keep_mask; | ||
489 | tmp_fan_div = (data->fan_div[nr] << new_shift) & ~keep_mask; | ||
490 | |||
491 | w83791d_write(client, W83791D_REG_FAN_DIV[indx], | ||
492 | fan_div_reg | tmp_fan_div); | ||
493 | |||
494 | /* Restore fan_min */ | ||
495 | data->fan_min[nr] = fan_to_reg(min, DIV_FROM_REG(data->fan_div[nr])); | ||
496 | w83791d_write(client, W83791D_REG_FAN_MIN[nr], data->fan_min[nr]); | ||
497 | |||
498 | #ifdef DEBUG | ||
499 | err_exit: | ||
500 | #endif | ||
501 | mutex_unlock(&data->update_lock); | ||
502 | |||
503 | return count; | ||
504 | } | ||
505 | |||
506 | static struct sensor_device_attribute sda_fan_input[] = { | ||
507 | SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0), | ||
508 | SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1), | ||
509 | SENSOR_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2), | ||
510 | SENSOR_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3), | ||
511 | SENSOR_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 4), | ||
512 | }; | ||
513 | |||
514 | static struct sensor_device_attribute sda_fan_min[] = { | ||
515 | SENSOR_ATTR(fan1_min, S_IWUSR | S_IRUGO, | ||
516 | show_fan_min, store_fan_min, 0), | ||
517 | SENSOR_ATTR(fan2_min, S_IWUSR | S_IRUGO, | ||
518 | show_fan_min, store_fan_min, 1), | ||
519 | SENSOR_ATTR(fan3_min, S_IWUSR | S_IRUGO, | ||
520 | show_fan_min, store_fan_min, 2), | ||
521 | SENSOR_ATTR(fan4_min, S_IWUSR | S_IRUGO, | ||
522 | show_fan_min, store_fan_min, 3), | ||
523 | SENSOR_ATTR(fan5_min, S_IWUSR | S_IRUGO, | ||
524 | show_fan_min, store_fan_min, 4), | ||
525 | }; | ||
526 | |||
527 | static struct sensor_device_attribute sda_fan_div[] = { | ||
528 | SENSOR_ATTR(fan1_div, S_IWUSR | S_IRUGO, | ||
529 | show_fan_div, store_fan_div, 0), | ||
530 | SENSOR_ATTR(fan2_div, S_IWUSR | S_IRUGO, | ||
531 | show_fan_div, store_fan_div, 1), | ||
532 | SENSOR_ATTR(fan3_div, S_IWUSR | S_IRUGO, | ||
533 | show_fan_div, store_fan_div, 2), | ||
534 | SENSOR_ATTR(fan4_div, S_IWUSR | S_IRUGO, | ||
535 | show_fan_div, store_fan_div, 3), | ||
536 | SENSOR_ATTR(fan5_div, S_IWUSR | S_IRUGO, | ||
537 | show_fan_div, store_fan_div, 4), | ||
538 | }; | ||
539 | |||
540 | /* read/write the temperature1, includes measured value and limits */ | ||
541 | static ssize_t show_temp1(struct device *dev, struct device_attribute *devattr, | ||
542 | char *buf) | ||
543 | { | ||
544 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
545 | struct w83791d_data *data = w83791d_update_device(dev); | ||
546 | return sprintf(buf, "%d\n", TEMP1_FROM_REG(data->temp1[attr->index])); | ||
547 | } | ||
548 | |||
549 | static ssize_t store_temp1(struct device *dev, struct device_attribute *devattr, | ||
550 | const char *buf, size_t count) | ||
551 | { | ||
552 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
553 | struct i2c_client *client = to_i2c_client(dev); | ||
554 | struct w83791d_data *data = i2c_get_clientdata(client); | ||
555 | long val = simple_strtol(buf, NULL, 10); | ||
556 | int nr = attr->index; | ||
557 | |||
558 | mutex_lock(&data->update_lock); | ||
559 | data->temp1[nr] = TEMP1_TO_REG(val); | ||
560 | w83791d_write(client, W83791D_REG_TEMP1[nr], data->temp1[nr]); | ||
561 | mutex_unlock(&data->update_lock); | ||
562 | return count; | ||
563 | } | ||
564 | |||
565 | /* read/write temperature2-3, includes measured value and limits */ | ||
566 | static ssize_t show_temp23(struct device *dev, struct device_attribute *devattr, | ||
567 | char *buf) | ||
568 | { | ||
569 | struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); | ||
570 | struct w83791d_data *data = w83791d_update_device(dev); | ||
571 | int nr = attr->nr; | ||
572 | int index = attr->index; | ||
573 | return sprintf(buf, "%d\n", TEMP23_FROM_REG(data->temp_add[nr][index])); | ||
574 | } | ||
575 | |||
576 | static ssize_t store_temp23(struct device *dev, | ||
577 | struct device_attribute *devattr, | ||
578 | const char *buf, size_t count) | ||
579 | { | ||
580 | struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); | ||
581 | struct i2c_client *client = to_i2c_client(dev); | ||
582 | struct w83791d_data *data = i2c_get_clientdata(client); | ||
583 | long val = simple_strtol(buf, NULL, 10); | ||
584 | int nr = attr->nr; | ||
585 | int index = attr->index; | ||
586 | |||
587 | mutex_lock(&data->update_lock); | ||
588 | data->temp_add[nr][index] = TEMP23_TO_REG(val); | ||
589 | w83791d_write(client, W83791D_REG_TEMP_ADD[nr][index * 2], | ||
590 | data->temp_add[nr][index] >> 8); | ||
591 | w83791d_write(client, W83791D_REG_TEMP_ADD[nr][index * 2 + 1], | ||
592 | data->temp_add[nr][index] & 0x80); | ||
593 | mutex_unlock(&data->update_lock); | ||
594 | |||
595 | return count; | ||
596 | } | ||
597 | |||
598 | static struct sensor_device_attribute_2 sda_temp_input[] = { | ||
599 | SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp1, NULL, 0, 0), | ||
600 | SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp23, NULL, 0, 0), | ||
601 | SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp23, NULL, 1, 0), | ||
602 | }; | ||
603 | |||
604 | static struct sensor_device_attribute_2 sda_temp_max[] = { | ||
605 | SENSOR_ATTR_2(temp1_max, S_IRUGO | S_IWUSR, | ||
606 | show_temp1, store_temp1, 0, 1), | ||
607 | SENSOR_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, | ||
608 | show_temp23, store_temp23, 0, 1), | ||
609 | SENSOR_ATTR_2(temp3_max, S_IRUGO | S_IWUSR, | ||
610 | show_temp23, store_temp23, 1, 1), | ||
611 | }; | ||
612 | |||
613 | static struct sensor_device_attribute_2 sda_temp_max_hyst[] = { | ||
614 | SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO | S_IWUSR, | ||
615 | show_temp1, store_temp1, 0, 2), | ||
616 | SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO | S_IWUSR, | ||
617 | show_temp23, store_temp23, 0, 2), | ||
618 | SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO | S_IWUSR, | ||
619 | show_temp23, store_temp23, 1, 2), | ||
620 | }; | ||
621 | |||
622 | |||
623 | /* get reatime status of all sensors items: voltage, temp, fan */ | ||
624 | static ssize_t show_alarms_reg(struct device *dev, | ||
625 | struct device_attribute *attr, char *buf) | ||
626 | { | ||
627 | struct w83791d_data *data = w83791d_update_device(dev); | ||
628 | return sprintf(buf, "%u\n", data->alarms); | ||
629 | } | ||
630 | |||
631 | static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL); | ||
632 | |||
633 | /* Beep control */ | ||
634 | |||
635 | #define GLOBAL_BEEP_ENABLE_SHIFT 15 | ||
636 | #define GLOBAL_BEEP_ENABLE_MASK (1 << GLOBAL_BEEP_ENABLE_SHIFT) | ||
637 | |||
638 | static ssize_t show_beep_enable(struct device *dev, | ||
639 | struct device_attribute *attr, char *buf) | ||
640 | { | ||
641 | struct w83791d_data *data = w83791d_update_device(dev); | ||
642 | return sprintf(buf, "%d\n", data->beep_enable); | ||
643 | } | ||
644 | |||
645 | static ssize_t show_beep_mask(struct device *dev, | ||
646 | struct device_attribute *attr, char *buf) | ||
647 | { | ||
648 | struct w83791d_data *data = w83791d_update_device(dev); | ||
649 | return sprintf(buf, "%d\n", BEEP_MASK_FROM_REG(data->beep_mask)); | ||
650 | } | ||
651 | |||
652 | |||
653 | static ssize_t store_beep_mask(struct device *dev, | ||
654 | struct device_attribute *attr, | ||
655 | const char *buf, size_t count) | ||
656 | { | ||
657 | struct i2c_client *client = to_i2c_client(dev); | ||
658 | struct w83791d_data *data = i2c_get_clientdata(client); | ||
659 | long val = simple_strtol(buf, NULL, 10); | ||
660 | int i; | ||
661 | |||
662 | mutex_lock(&data->update_lock); | ||
663 | |||
664 | /* The beep_enable state overrides any enabling request from | ||
665 | the masks */ | ||
666 | data->beep_mask = BEEP_MASK_TO_REG(val) & ~GLOBAL_BEEP_ENABLE_MASK; | ||
667 | data->beep_mask |= (data->beep_enable << GLOBAL_BEEP_ENABLE_SHIFT); | ||
668 | |||
669 | val = data->beep_mask; | ||
670 | |||
671 | for (i = 0; i < 3; i++) { | ||
672 | w83791d_write(client, W83791D_REG_BEEP_CTRL[i], (val & 0xff)); | ||
673 | val >>= 8; | ||
674 | } | ||
675 | |||
676 | mutex_unlock(&data->update_lock); | ||
677 | |||
678 | return count; | ||
679 | } | ||
680 | |||
681 | static ssize_t store_beep_enable(struct device *dev, | ||
682 | struct device_attribute *attr, | ||
683 | const char *buf, size_t count) | ||
684 | { | ||
685 | struct i2c_client *client = to_i2c_client(dev); | ||
686 | struct w83791d_data *data = i2c_get_clientdata(client); | ||
687 | long val = simple_strtol(buf, NULL, 10); | ||
688 | |||
689 | mutex_lock(&data->update_lock); | ||
690 | |||
691 | data->beep_enable = val ? 1 : 0; | ||
692 | |||
693 | /* Keep the full mask value in sync with the current enable */ | ||
694 | data->beep_mask &= ~GLOBAL_BEEP_ENABLE_MASK; | ||
695 | data->beep_mask |= (data->beep_enable << GLOBAL_BEEP_ENABLE_SHIFT); | ||
696 | |||
697 | /* The global control is in the second beep control register | ||
698 | so only need to update that register */ | ||
699 | val = (data->beep_mask >> 8) & 0xff; | ||
700 | |||
701 | w83791d_write(client, W83791D_REG_BEEP_CTRL[1], val); | ||
702 | |||
703 | mutex_unlock(&data->update_lock); | ||
704 | |||
705 | return count; | ||
706 | } | ||
707 | |||
708 | static struct sensor_device_attribute sda_beep_ctrl[] = { | ||
709 | SENSOR_ATTR(beep_enable, S_IRUGO | S_IWUSR, | ||
710 | show_beep_enable, store_beep_enable, 0), | ||
711 | SENSOR_ATTR(beep_mask, S_IRUGO | S_IWUSR, | ||
712 | show_beep_mask, store_beep_mask, 1) | ||
713 | }; | ||
714 | |||
715 | /* cpu voltage regulation information */ | ||
716 | static ssize_t show_vid_reg(struct device *dev, | ||
717 | struct device_attribute *attr, char *buf) | ||
718 | { | ||
719 | struct w83791d_data *data = w83791d_update_device(dev); | ||
720 | return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm)); | ||
721 | } | ||
722 | |||
723 | static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); | ||
724 | |||
725 | static ssize_t show_vrm_reg(struct device *dev, | ||
726 | struct device_attribute *attr, char *buf) | ||
727 | { | ||
728 | struct w83791d_data *data = w83791d_update_device(dev); | ||
729 | return sprintf(buf, "%d\n", data->vrm); | ||
730 | } | ||
731 | |||
732 | static ssize_t store_vrm_reg(struct device *dev, | ||
733 | struct device_attribute *attr, | ||
734 | const char *buf, size_t count) | ||
735 | { | ||
736 | struct i2c_client *client = to_i2c_client(dev); | ||
737 | struct w83791d_data *data = i2c_get_clientdata(client); | ||
738 | unsigned long val = simple_strtoul(buf, NULL, 10); | ||
739 | |||
740 | /* No lock needed as vrm is internal to the driver | ||
741 | (not read from a chip register) and so is not | ||
742 | updated in w83791d_update_device() */ | ||
743 | data->vrm = val; | ||
744 | |||
745 | return count; | ||
746 | } | ||
747 | |||
748 | static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg); | ||
749 | |||
750 | /* This function is called when: | ||
751 | * w83791d_driver is inserted (when this module is loaded), for each | ||
752 | available adapter | ||
753 | * when a new adapter is inserted (and w83791d_driver is still present) */ | ||
754 | static int w83791d_attach_adapter(struct i2c_adapter *adapter) | ||
755 | { | ||
756 | if (!(adapter->class & I2C_CLASS_HWMON)) | ||
757 | return 0; | ||
758 | return i2c_probe(adapter, &addr_data, w83791d_detect); | ||
759 | } | ||
760 | |||
761 | |||
762 | static int w83791d_create_subclient(struct i2c_adapter *adapter, | ||
763 | struct i2c_client *client, int addr, | ||
764 | struct i2c_client **sub_cli) | ||
765 | { | ||
766 | int err; | ||
767 | struct i2c_client *sub_client; | ||
768 | |||
769 | (*sub_cli) = sub_client = | ||
770 | kzalloc(sizeof(struct i2c_client), GFP_KERNEL); | ||
771 | if (!(sub_client)) { | ||
772 | return -ENOMEM; | ||
773 | } | ||
774 | sub_client->addr = 0x48 + addr; | ||
775 | i2c_set_clientdata(sub_client, NULL); | ||
776 | sub_client->adapter = adapter; | ||
777 | sub_client->driver = &w83791d_driver; | ||
778 | strlcpy(sub_client->name, "w83791d subclient", I2C_NAME_SIZE); | ||
779 | if ((err = i2c_attach_client(sub_client))) { | ||
780 | dev_err(&client->dev, "subclient registration " | ||
781 | "at address 0x%x failed\n", sub_client->addr); | ||
782 | kfree(sub_client); | ||
783 | return err; | ||
784 | } | ||
785 | return 0; | ||
786 | } | ||
787 | |||
788 | |||
789 | static int w83791d_detect_subclients(struct i2c_adapter *adapter, int address, | ||
790 | int kind, struct i2c_client *client) | ||
791 | { | ||
792 | struct w83791d_data *data = i2c_get_clientdata(client); | ||
793 | int i, id, err; | ||
794 | u8 val; | ||
795 | |||
796 | id = i2c_adapter_id(adapter); | ||
797 | if (force_subclients[0] == id && force_subclients[1] == address) { | ||
798 | for (i = 2; i <= 3; i++) { | ||
799 | if (force_subclients[i] < 0x48 || | ||
800 | force_subclients[i] > 0x4f) { | ||
801 | dev_err(&client->dev, | ||
802 | "invalid subclient " | ||
803 | "address %d; must be 0x48-0x4f\n", | ||
804 | force_subclients[i]); | ||
805 | err = -ENODEV; | ||
806 | goto error_sc_0; | ||
807 | } | ||
808 | } | ||
809 | w83791d_write(client, W83791D_REG_I2C_SUBADDR, | ||
810 | (force_subclients[2] & 0x07) | | ||
811 | ((force_subclients[3] & 0x07) << 4)); | ||
812 | } | ||
813 | |||
814 | val = w83791d_read(client, W83791D_REG_I2C_SUBADDR); | ||
815 | if (!(val & 0x08)) { | ||
816 | err = w83791d_create_subclient(adapter, client, | ||
817 | val & 0x7, &data->lm75[0]); | ||
818 | if (err < 0) | ||
819 | goto error_sc_0; | ||
820 | } | ||
821 | if (!(val & 0x80)) { | ||
822 | if ((data->lm75[0] != NULL) && | ||
823 | ((val & 0x7) == ((val >> 4) & 0x7))) { | ||
824 | dev_err(&client->dev, | ||
825 | "duplicate addresses 0x%x, " | ||
826 | "use force_subclient\n", | ||
827 | data->lm75[0]->addr); | ||
828 | err = -ENODEV; | ||
829 | goto error_sc_1; | ||
830 | } | ||
831 | err = w83791d_create_subclient(adapter, client, | ||
832 | (val >> 4) & 0x7, &data->lm75[1]); | ||
833 | if (err < 0) | ||
834 | goto error_sc_1; | ||
835 | } | ||
836 | |||
837 | return 0; | ||
838 | |||
839 | /* Undo inits in case of errors */ | ||
840 | |||
841 | error_sc_1: | ||
842 | if (data->lm75[0] != NULL) { | ||
843 | i2c_detach_client(data->lm75[0]); | ||
844 | kfree(data->lm75[0]); | ||
845 | } | ||
846 | error_sc_0: | ||
847 | return err; | ||
848 | } | ||
849 | |||
850 | |||
851 | static int w83791d_detect(struct i2c_adapter *adapter, int address, int kind) | ||
852 | { | ||
853 | struct i2c_client *client; | ||
854 | struct device *dev; | ||
855 | struct w83791d_data *data; | ||
856 | int i, val1, val2; | ||
857 | int err = 0; | ||
858 | const char *client_name = ""; | ||
859 | |||
860 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { | ||
861 | goto error0; | ||
862 | } | ||
863 | |||
864 | /* OK. For now, we presume we have a valid client. We now create the | ||
865 | client structure, even though we cannot fill it completely yet. | ||
866 | But it allows us to access w83791d_{read,write}_value. */ | ||
867 | if (!(data = kzalloc(sizeof(struct w83791d_data), GFP_KERNEL))) { | ||
868 | err = -ENOMEM; | ||
869 | goto error0; | ||
870 | } | ||
871 | |||
872 | client = &data->client; | ||
873 | dev = &client->dev; | ||
874 | i2c_set_clientdata(client, data); | ||
875 | client->addr = address; | ||
876 | client->adapter = adapter; | ||
877 | client->driver = &w83791d_driver; | ||
878 | mutex_init(&data->update_lock); | ||
879 | |||
880 | /* Now, we do the remaining detection. */ | ||
881 | |||
882 | /* The w83791d may be stuck in some other bank than bank 0. This may | ||
883 | make reading other information impossible. Specify a force=... | ||
884 | parameter, and the Winbond will be reset to the right bank. */ | ||
885 | if (kind < 0) { | ||
886 | if (w83791d_read(client, W83791D_REG_CONFIG) & 0x80) { | ||
887 | dev_dbg(dev, "Detection failed at step 1\n"); | ||
888 | goto error1; | ||
889 | } | ||
890 | val1 = w83791d_read(client, W83791D_REG_BANK); | ||
891 | val2 = w83791d_read(client, W83791D_REG_CHIPMAN); | ||
892 | /* Check for Winbond ID if in bank 0 */ | ||
893 | if (!(val1 & 0x07)) { | ||
894 | /* yes it is Bank0 */ | ||
895 | if (((!(val1 & 0x80)) && (val2 != 0xa3)) || | ||
896 | ((val1 & 0x80) && (val2 != 0x5c))) { | ||
897 | dev_dbg(dev, "Detection failed at step 2\n"); | ||
898 | goto error1; | ||
899 | } | ||
900 | } | ||
901 | /* If Winbond chip, address of chip and W83791D_REG_I2C_ADDR | ||
902 | should match */ | ||
903 | if (w83791d_read(client, W83791D_REG_I2C_ADDR) != address) { | ||
904 | dev_dbg(dev, "Detection failed at step 3\n"); | ||
905 | goto error1; | ||
906 | } | ||
907 | } | ||
908 | |||
909 | /* We either have a force parameter or we have reason to | ||
910 | believe it is a Winbond chip. Either way, we want bank 0 and | ||
911 | Vendor ID high byte */ | ||
912 | val1 = w83791d_read(client, W83791D_REG_BANK) & 0x78; | ||
913 | w83791d_write(client, W83791D_REG_BANK, val1 | 0x80); | ||
914 | |||
915 | /* Verify it is a Winbond w83791d */ | ||
916 | if (kind <= 0) { | ||
917 | /* get vendor ID */ | ||
918 | val2 = w83791d_read(client, W83791D_REG_CHIPMAN); | ||
919 | if (val2 != 0x5c) { /* the vendor is NOT Winbond */ | ||
920 | dev_dbg(dev, "Detection failed at step 4\n"); | ||
921 | goto error1; | ||
922 | } | ||
923 | val1 = w83791d_read(client, W83791D_REG_WCHIPID); | ||
924 | if (val1 == 0x71) { | ||
925 | kind = w83791d; | ||
926 | } else { | ||
927 | if (kind == 0) | ||
928 | dev_warn(dev, | ||
929 | "w83791d: Ignoring 'force' parameter " | ||
930 | "for unknown chip at adapter %d, " | ||
931 | "address 0x%02x\n", | ||
932 | i2c_adapter_id(adapter), address); | ||
933 | goto error1; | ||
934 | } | ||
935 | } | ||
936 | |||
937 | if (kind == w83791d) { | ||
938 | client_name = "w83791d"; | ||
939 | } else { | ||
940 | dev_err(dev, "w83791d: Internal error: unknown kind (%d)?!?", | ||
941 | kind); | ||
942 | goto error1; | ||
943 | } | ||
944 | |||
945 | #ifdef DEBUG | ||
946 | val1 = w83791d_read(client, W83791D_REG_DID_VID4); | ||
947 | dev_dbg(dev, "Device ID version: %d.%d (0x%02x)\n", | ||
948 | (val1 >> 5) & 0x07, (val1 >> 1) & 0x0f, val1); | ||
949 | #endif | ||
950 | |||
951 | /* Fill in the remaining client fields and put into the global list */ | ||
952 | strlcpy(client->name, client_name, I2C_NAME_SIZE); | ||
953 | |||
954 | /* Tell the I2C layer a new client has arrived */ | ||
955 | if ((err = i2c_attach_client(client))) | ||
956 | goto error1; | ||
957 | |||
958 | if ((err = w83791d_detect_subclients(adapter, address, kind, client))) | ||
959 | goto error2; | ||
960 | |||
961 | /* Initialize the chip */ | ||
962 | w83791d_init_client(client); | ||
963 | |||
964 | /* If the fan_div is changed, make sure there is a rational | ||
965 | fan_min in place */ | ||
966 | for (i = 0; i < NUMBER_OF_FANIN; i++) { | ||
967 | data->fan_min[i] = w83791d_read(client, W83791D_REG_FAN_MIN[i]); | ||
968 | } | ||
969 | |||
970 | /* Register sysfs hooks */ | ||
971 | data->class_dev = hwmon_device_register(dev); | ||
972 | if (IS_ERR(data->class_dev)) { | ||
973 | err = PTR_ERR(data->class_dev); | ||
974 | goto error3; | ||
975 | } | ||
976 | |||
977 | for (i = 0; i < NUMBER_OF_VIN; i++) { | ||
978 | device_create_file(dev, &sda_in_input[i].dev_attr); | ||
979 | device_create_file(dev, &sda_in_min[i].dev_attr); | ||
980 | device_create_file(dev, &sda_in_max[i].dev_attr); | ||
981 | } | ||
982 | |||
983 | for (i = 0; i < NUMBER_OF_FANIN; i++) { | ||
984 | device_create_file(dev, &sda_fan_input[i].dev_attr); | ||
985 | device_create_file(dev, &sda_fan_div[i].dev_attr); | ||
986 | device_create_file(dev, &sda_fan_min[i].dev_attr); | ||
987 | } | ||
988 | |||
989 | for (i = 0; i < NUMBER_OF_TEMPIN; i++) { | ||
990 | device_create_file(dev, &sda_temp_input[i].dev_attr); | ||
991 | device_create_file(dev, &sda_temp_max[i].dev_attr); | ||
992 | device_create_file(dev, &sda_temp_max_hyst[i].dev_attr); | ||
993 | } | ||
994 | |||
995 | device_create_file(dev, &dev_attr_alarms); | ||
996 | |||
997 | for (i = 0; i < ARRAY_SIZE(sda_beep_ctrl); i++) { | ||
998 | device_create_file(dev, &sda_beep_ctrl[i].dev_attr); | ||
999 | } | ||
1000 | |||
1001 | device_create_file(dev, &dev_attr_cpu0_vid); | ||
1002 | device_create_file(dev, &dev_attr_vrm); | ||
1003 | |||
1004 | return 0; | ||
1005 | |||
1006 | error3: | ||
1007 | if (data->lm75[0] != NULL) { | ||
1008 | i2c_detach_client(data->lm75[0]); | ||
1009 | kfree(data->lm75[0]); | ||
1010 | } | ||
1011 | if (data->lm75[1] != NULL) { | ||
1012 | i2c_detach_client(data->lm75[1]); | ||
1013 | kfree(data->lm75[1]); | ||
1014 | } | ||
1015 | error2: | ||
1016 | i2c_detach_client(client); | ||
1017 | error1: | ||
1018 | kfree(data); | ||
1019 | error0: | ||
1020 | return err; | ||
1021 | } | ||
1022 | |||
1023 | static int w83791d_detach_client(struct i2c_client *client) | ||
1024 | { | ||
1025 | struct w83791d_data *data = i2c_get_clientdata(client); | ||
1026 | int err; | ||
1027 | |||
1028 | /* main client */ | ||
1029 | if (data) | ||
1030 | hwmon_device_unregister(data->class_dev); | ||
1031 | |||
1032 | if ((err = i2c_detach_client(client))) | ||
1033 | return err; | ||
1034 | |||
1035 | /* main client */ | ||
1036 | if (data) | ||
1037 | kfree(data); | ||
1038 | /* subclient */ | ||
1039 | else | ||
1040 | kfree(client); | ||
1041 | |||
1042 | return 0; | ||
1043 | } | ||
1044 | |||
1045 | static void w83791d_init_client(struct i2c_client *client) | ||
1046 | { | ||
1047 | struct w83791d_data *data = i2c_get_clientdata(client); | ||
1048 | u8 tmp; | ||
1049 | u8 old_beep; | ||
1050 | |||
1051 | /* The difference between reset and init is that reset | ||
1052 | does a hard reset of the chip via index 0x40, bit 7, | ||
1053 | but init simply forces certain registers to have "sane" | ||
1054 | values. The hope is that the BIOS has done the right | ||
1055 | thing (which is why the default is reset=0, init=0), | ||
1056 | but if not, reset is the hard hammer and init | ||
1057 | is the soft mallet both of which are trying to whack | ||
1058 | things into place... | ||
1059 | NOTE: The data sheet makes a distinction between | ||
1060 | "power on defaults" and "reset by MR". As far as I can tell, | ||
1061 | the hard reset puts everything into a power-on state so I'm | ||
1062 | not sure what "reset by MR" means or how it can happen. | ||
1063 | */ | ||
1064 | if (reset || init) { | ||
1065 | /* keep some BIOS settings when we... */ | ||
1066 | old_beep = w83791d_read(client, W83791D_REG_BEEP_CONFIG); | ||
1067 | |||
1068 | if (reset) { | ||
1069 | /* ... reset the chip and ... */ | ||
1070 | w83791d_write(client, W83791D_REG_CONFIG, 0x80); | ||
1071 | } | ||
1072 | |||
1073 | /* ... disable power-on abnormal beep */ | ||
1074 | w83791d_write(client, W83791D_REG_BEEP_CONFIG, old_beep | 0x80); | ||
1075 | |||
1076 | /* disable the global beep (not done by hard reset) */ | ||
1077 | tmp = w83791d_read(client, W83791D_REG_BEEP_CTRL[1]); | ||
1078 | w83791d_write(client, W83791D_REG_BEEP_CTRL[1], tmp & 0xef); | ||
1079 | |||
1080 | if (init) { | ||
1081 | /* Make sure monitoring is turned on for add-ons */ | ||
1082 | tmp = w83791d_read(client, W83791D_REG_TEMP2_CONFIG); | ||
1083 | if (tmp & 1) { | ||
1084 | w83791d_write(client, W83791D_REG_TEMP2_CONFIG, | ||
1085 | tmp & 0xfe); | ||
1086 | } | ||
1087 | |||
1088 | tmp = w83791d_read(client, W83791D_REG_TEMP3_CONFIG); | ||
1089 | if (tmp & 1) { | ||
1090 | w83791d_write(client, W83791D_REG_TEMP3_CONFIG, | ||
1091 | tmp & 0xfe); | ||
1092 | } | ||
1093 | |||
1094 | /* Start monitoring */ | ||
1095 | tmp = w83791d_read(client, W83791D_REG_CONFIG) & 0xf7; | ||
1096 | w83791d_write(client, W83791D_REG_CONFIG, tmp | 0x01); | ||
1097 | } | ||
1098 | } | ||
1099 | |||
1100 | data->vrm = vid_which_vrm(); | ||
1101 | } | ||
1102 | |||
1103 | static struct w83791d_data *w83791d_update_device(struct device *dev) | ||
1104 | { | ||
1105 | struct i2c_client *client = to_i2c_client(dev); | ||
1106 | struct w83791d_data *data = i2c_get_clientdata(client); | ||
1107 | int i, j; | ||
1108 | u8 reg_array_tmp[3]; | ||
1109 | |||
1110 | mutex_lock(&data->update_lock); | ||
1111 | |||
1112 | if (time_after(jiffies, data->last_updated + (HZ * 3)) | ||
1113 | || !data->valid) { | ||
1114 | dev_dbg(dev, "Starting w83791d device update\n"); | ||
1115 | |||
1116 | /* Update the voltages measured value and limits */ | ||
1117 | for (i = 0; i < NUMBER_OF_VIN; i++) { | ||
1118 | data->in[i] = w83791d_read(client, | ||
1119 | W83791D_REG_IN[i]); | ||
1120 | data->in_max[i] = w83791d_read(client, | ||
1121 | W83791D_REG_IN_MAX[i]); | ||
1122 | data->in_min[i] = w83791d_read(client, | ||
1123 | W83791D_REG_IN_MIN[i]); | ||
1124 | } | ||
1125 | |||
1126 | /* Update the fan counts and limits */ | ||
1127 | for (i = 0; i < NUMBER_OF_FANIN; i++) { | ||
1128 | /* Update the Fan measured value and limits */ | ||
1129 | data->fan[i] = w83791d_read(client, | ||
1130 | W83791D_REG_FAN[i]); | ||
1131 | data->fan_min[i] = w83791d_read(client, | ||
1132 | W83791D_REG_FAN_MIN[i]); | ||
1133 | } | ||
1134 | |||
1135 | /* Update the fan divisor */ | ||
1136 | for (i = 0; i < 3; i++) { | ||
1137 | reg_array_tmp[i] = w83791d_read(client, | ||
1138 | W83791D_REG_FAN_DIV[i]); | ||
1139 | } | ||
1140 | data->fan_div[0] = (reg_array_tmp[0] >> 4) & 0x03; | ||
1141 | data->fan_div[1] = (reg_array_tmp[0] >> 6) & 0x03; | ||
1142 | data->fan_div[2] = (reg_array_tmp[1] >> 6) & 0x03; | ||
1143 | data->fan_div[3] = reg_array_tmp[2] & 0x07; | ||
1144 | data->fan_div[4] = (reg_array_tmp[2] >> 4) & 0x07; | ||
1145 | |||
1146 | /* Update the first temperature sensor */ | ||
1147 | for (i = 0; i < 3; i++) { | ||
1148 | data->temp1[i] = w83791d_read(client, | ||
1149 | W83791D_REG_TEMP1[i]); | ||
1150 | } | ||
1151 | |||
1152 | /* Update the rest of the temperature sensors */ | ||
1153 | for (i = 0; i < 2; i++) { | ||
1154 | for (j = 0; j < 3; j++) { | ||
1155 | data->temp_add[i][j] = | ||
1156 | (w83791d_read(client, | ||
1157 | W83791D_REG_TEMP_ADD[i][j * 2]) << 8) | | ||
1158 | w83791d_read(client, | ||
1159 | W83791D_REG_TEMP_ADD[i][j * 2 + 1]); | ||
1160 | } | ||
1161 | } | ||
1162 | |||
1163 | /* Update the realtime status */ | ||
1164 | data->alarms = | ||
1165 | w83791d_read(client, W83791D_REG_ALARM1) + | ||
1166 | (w83791d_read(client, W83791D_REG_ALARM2) << 8) + | ||
1167 | (w83791d_read(client, W83791D_REG_ALARM3) << 16); | ||
1168 | |||
1169 | /* Update the beep configuration information */ | ||
1170 | data->beep_mask = | ||
1171 | w83791d_read(client, W83791D_REG_BEEP_CTRL[0]) + | ||
1172 | (w83791d_read(client, W83791D_REG_BEEP_CTRL[1]) << 8) + | ||
1173 | (w83791d_read(client, W83791D_REG_BEEP_CTRL[2]) << 16); | ||
1174 | |||
1175 | data->beep_enable = | ||
1176 | (data->beep_mask >> GLOBAL_BEEP_ENABLE_SHIFT) & 0x01; | ||
1177 | |||
1178 | /* Update the cpu voltage information */ | ||
1179 | i = w83791d_read(client, W83791D_REG_VID_FANDIV); | ||
1180 | data->vid = i & 0x0f; | ||
1181 | data->vid |= (w83791d_read(client, W83791D_REG_DID_VID4) & 0x01) | ||
1182 | << 4; | ||
1183 | |||
1184 | data->last_updated = jiffies; | ||
1185 | data->valid = 1; | ||
1186 | } | ||
1187 | |||
1188 | mutex_unlock(&data->update_lock); | ||
1189 | |||
1190 | #ifdef DEBUG | ||
1191 | w83791d_print_debug(data, dev); | ||
1192 | #endif | ||
1193 | |||
1194 | return data; | ||
1195 | } | ||
1196 | |||
1197 | #ifdef DEBUG | ||
1198 | static void w83791d_print_debug(struct w83791d_data *data, struct device *dev) | ||
1199 | { | ||
1200 | int i = 0, j = 0; | ||
1201 | |||
1202 | dev_dbg(dev, "======Start of w83791d debug values======\n"); | ||
1203 | dev_dbg(dev, "%d set of Voltages: ===>\n", NUMBER_OF_VIN); | ||
1204 | for (i = 0; i < NUMBER_OF_VIN; i++) { | ||
1205 | dev_dbg(dev, "vin[%d] is: 0x%02x\n", i, data->in[i]); | ||
1206 | dev_dbg(dev, "vin[%d] min is: 0x%02x\n", i, data->in_min[i]); | ||
1207 | dev_dbg(dev, "vin[%d] max is: 0x%02x\n", i, data->in_max[i]); | ||
1208 | } | ||
1209 | dev_dbg(dev, "%d set of Fan Counts/Divisors: ===>\n", NUMBER_OF_FANIN); | ||
1210 | for (i = 0; i < NUMBER_OF_FANIN; i++) { | ||
1211 | dev_dbg(dev, "fan[%d] is: 0x%02x\n", i, data->fan[i]); | ||
1212 | dev_dbg(dev, "fan[%d] min is: 0x%02x\n", i, data->fan_min[i]); | ||
1213 | dev_dbg(dev, "fan_div[%d] is: 0x%02x\n", i, data->fan_div[i]); | ||
1214 | } | ||
1215 | |||
1216 | /* temperature math is signed, but only print out the | ||
1217 | bits that matter */ | ||
1218 | dev_dbg(dev, "%d set of Temperatures: ===>\n", NUMBER_OF_TEMPIN); | ||
1219 | for (i = 0; i < 3; i++) { | ||
1220 | dev_dbg(dev, "temp1[%d] is: 0x%02x\n", i, (u8) data->temp1[i]); | ||
1221 | } | ||
1222 | for (i = 0; i < 2; i++) { | ||
1223 | for (j = 0; j < 3; j++) { | ||
1224 | dev_dbg(dev, "temp_add[%d][%d] is: 0x%04x\n", i, j, | ||
1225 | (u16) data->temp_add[i][j]); | ||
1226 | } | ||
1227 | } | ||
1228 | |||
1229 | dev_dbg(dev, "Misc Information: ===>\n"); | ||
1230 | dev_dbg(dev, "alarm is: 0x%08x\n", data->alarms); | ||
1231 | dev_dbg(dev, "beep_mask is: 0x%08x\n", data->beep_mask); | ||
1232 | dev_dbg(dev, "beep_enable is: %d\n", data->beep_enable); | ||
1233 | dev_dbg(dev, "vid is: 0x%02x\n", data->vid); | ||
1234 | dev_dbg(dev, "vrm is: 0x%02x\n", data->vrm); | ||
1235 | dev_dbg(dev, "=======End of w83791d debug values========\n"); | ||
1236 | dev_dbg(dev, "\n"); | ||
1237 | } | ||
1238 | #endif | ||
1239 | |||
1240 | static int __init sensors_w83791d_init(void) | ||
1241 | { | ||
1242 | return i2c_add_driver(&w83791d_driver); | ||
1243 | } | ||
1244 | |||
1245 | static void __exit sensors_w83791d_exit(void) | ||
1246 | { | ||
1247 | i2c_del_driver(&w83791d_driver); | ||
1248 | } | ||
1249 | |||
1250 | MODULE_AUTHOR("Charles Spirakis <bezaur@gmail.com>"); | ||
1251 | MODULE_DESCRIPTION("W83791D driver"); | ||
1252 | MODULE_LICENSE("GPL"); | ||
1253 | |||
1254 | module_init(sensors_w83791d_init); | ||
1255 | module_exit(sensors_w83791d_exit); | ||
diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c index 958602e28412..4ef884c216e2 100644 --- a/drivers/hwmon/w83792d.c +++ b/drivers/hwmon/w83792d.c | |||
@@ -250,8 +250,6 @@ FAN_TO_REG(long rpm, int div) | |||
250 | : (val)) / 1000, 0, 0xff)) | 250 | : (val)) / 1000, 0, 0xff)) |
251 | #define TEMP_ADD_TO_REG_LOW(val) ((val%1000) ? 0x80 : 0x00) | 251 | #define TEMP_ADD_TO_REG_LOW(val) ((val%1000) ? 0x80 : 0x00) |
252 | 252 | ||
253 | #define PWM_FROM_REG(val) (val) | ||
254 | #define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255)) | ||
255 | #define DIV_FROM_REG(val) (1 << (val)) | 253 | #define DIV_FROM_REG(val) (1 << (val)) |
256 | 254 | ||
257 | static inline u8 | 255 | static inline u8 |
@@ -291,7 +289,6 @@ struct w83792d_data { | |||
291 | u8 pwm[7]; /* We only consider the first 3 set of pwm, | 289 | u8 pwm[7]; /* We only consider the first 3 set of pwm, |
292 | although 792 chip has 7 set of pwm. */ | 290 | although 792 chip has 7 set of pwm. */ |
293 | u8 pwmenable[3]; | 291 | u8 pwmenable[3]; |
294 | u8 pwm_mode[7]; /* indicates PWM or DC mode: 1->PWM; 0->DC */ | ||
295 | u32 alarms; /* realtime status register encoding,combined */ | 292 | u32 alarms; /* realtime status register encoding,combined */ |
296 | u8 chassis; /* Chassis status */ | 293 | u8 chassis; /* Chassis status */ |
297 | u8 chassis_clear; /* CLR_CHS, clear chassis intrusion detection */ | 294 | u8 chassis_clear; /* CLR_CHS, clear chassis intrusion detection */ |
@@ -375,8 +372,10 @@ static ssize_t store_in_##reg (struct device *dev, \ | |||
375 | u32 val; \ | 372 | u32 val; \ |
376 | \ | 373 | \ |
377 | val = simple_strtoul(buf, NULL, 10); \ | 374 | val = simple_strtoul(buf, NULL, 10); \ |
375 | mutex_lock(&data->update_lock); \ | ||
378 | data->in_##reg[nr] = SENSORS_LIMIT(IN_TO_REG(nr, val)/4, 0, 255); \ | 376 | data->in_##reg[nr] = SENSORS_LIMIT(IN_TO_REG(nr, val)/4, 0, 255); \ |
379 | w83792d_write_value(client, W83792D_REG_IN_##REG[nr], data->in_##reg[nr]); \ | 377 | w83792d_write_value(client, W83792D_REG_IN_##REG[nr], data->in_##reg[nr]); \ |
378 | mutex_unlock(&data->update_lock); \ | ||
380 | \ | 379 | \ |
381 | return count; \ | 380 | return count; \ |
382 | } | 381 | } |
@@ -443,9 +442,11 @@ store_fan_min(struct device *dev, struct device_attribute *attr, | |||
443 | u32 val; | 442 | u32 val; |
444 | 443 | ||
445 | val = simple_strtoul(buf, NULL, 10); | 444 | val = simple_strtoul(buf, NULL, 10); |
445 | mutex_lock(&data->update_lock); | ||
446 | data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); | 446 | data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); |
447 | w83792d_write_value(client, W83792D_REG_FAN_MIN[nr], | 447 | w83792d_write_value(client, W83792D_REG_FAN_MIN[nr], |
448 | data->fan_min[nr]); | 448 | data->fan_min[nr]); |
449 | mutex_unlock(&data->update_lock); | ||
449 | 450 | ||
450 | return count; | 451 | return count; |
451 | } | 452 | } |
@@ -478,6 +479,7 @@ store_fan_div(struct device *dev, struct device_attribute *attr, | |||
478 | u8 tmp_fan_div; | 479 | u8 tmp_fan_div; |
479 | 480 | ||
480 | /* Save fan_min */ | 481 | /* Save fan_min */ |
482 | mutex_lock(&data->update_lock); | ||
481 | min = FAN_FROM_REG(data->fan_min[nr], | 483 | min = FAN_FROM_REG(data->fan_min[nr], |
482 | DIV_FROM_REG(data->fan_div[nr])); | 484 | DIV_FROM_REG(data->fan_div[nr])); |
483 | 485 | ||
@@ -493,6 +495,7 @@ store_fan_div(struct device *dev, struct device_attribute *attr, | |||
493 | /* Restore fan_min */ | 495 | /* Restore fan_min */ |
494 | data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); | 496 | data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); |
495 | w83792d_write_value(client, W83792D_REG_FAN_MIN[nr], data->fan_min[nr]); | 497 | w83792d_write_value(client, W83792D_REG_FAN_MIN[nr], data->fan_min[nr]); |
498 | mutex_unlock(&data->update_lock); | ||
496 | 499 | ||
497 | return count; | 500 | return count; |
498 | } | 501 | } |
@@ -547,10 +550,11 @@ static ssize_t store_temp1(struct device *dev, struct device_attribute *attr, | |||
547 | s32 val; | 550 | s32 val; |
548 | 551 | ||
549 | val = simple_strtol(buf, NULL, 10); | 552 | val = simple_strtol(buf, NULL, 10); |
550 | 553 | mutex_lock(&data->update_lock); | |
551 | data->temp1[nr] = TEMP1_TO_REG(val); | 554 | data->temp1[nr] = TEMP1_TO_REG(val); |
552 | w83792d_write_value(client, W83792D_REG_TEMP1[nr], | 555 | w83792d_write_value(client, W83792D_REG_TEMP1[nr], |
553 | data->temp1[nr]); | 556 | data->temp1[nr]); |
557 | mutex_unlock(&data->update_lock); | ||
554 | 558 | ||
555 | return count; | 559 | return count; |
556 | } | 560 | } |
@@ -580,13 +584,14 @@ static ssize_t store_temp23(struct device *dev, struct device_attribute *attr, | |||
580 | s32 val; | 584 | s32 val; |
581 | 585 | ||
582 | val = simple_strtol(buf, NULL, 10); | 586 | val = simple_strtol(buf, NULL, 10); |
583 | 587 | mutex_lock(&data->update_lock); | |
584 | data->temp_add[nr][index] = TEMP_ADD_TO_REG_HIGH(val); | 588 | data->temp_add[nr][index] = TEMP_ADD_TO_REG_HIGH(val); |
585 | data->temp_add[nr][index+1] = TEMP_ADD_TO_REG_LOW(val); | 589 | data->temp_add[nr][index+1] = TEMP_ADD_TO_REG_LOW(val); |
586 | w83792d_write_value(client, W83792D_REG_TEMP_ADD[nr][index], | 590 | w83792d_write_value(client, W83792D_REG_TEMP_ADD[nr][index], |
587 | data->temp_add[nr][index]); | 591 | data->temp_add[nr][index]); |
588 | w83792d_write_value(client, W83792D_REG_TEMP_ADD[nr][index+1], | 592 | w83792d_write_value(client, W83792D_REG_TEMP_ADD[nr][index+1], |
589 | data->temp_add[nr][index+1]); | 593 | data->temp_add[nr][index+1]); |
594 | mutex_unlock(&data->update_lock); | ||
590 | 595 | ||
591 | return count; | 596 | return count; |
592 | } | 597 | } |
@@ -627,7 +632,7 @@ show_pwm(struct device *dev, struct device_attribute *attr, | |||
627 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | 632 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); |
628 | int nr = sensor_attr->index; | 633 | int nr = sensor_attr->index; |
629 | struct w83792d_data *data = w83792d_update_device(dev); | 634 | struct w83792d_data *data = w83792d_update_device(dev); |
630 | return sprintf(buf, "%ld\n", (long) PWM_FROM_REG(data->pwm[nr-1])); | 635 | return sprintf(buf, "%d\n", (data->pwm[nr] & 0x0f) << 4); |
631 | } | 636 | } |
632 | 637 | ||
633 | static ssize_t | 638 | static ssize_t |
@@ -659,14 +664,16 @@ store_pwm(struct device *dev, struct device_attribute *attr, | |||
659 | const char *buf, size_t count) | 664 | const char *buf, size_t count) |
660 | { | 665 | { |
661 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | 666 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); |
662 | int nr = sensor_attr->index - 1; | 667 | int nr = sensor_attr->index; |
663 | struct i2c_client *client = to_i2c_client(dev); | 668 | struct i2c_client *client = to_i2c_client(dev); |
664 | struct w83792d_data *data = i2c_get_clientdata(client); | 669 | struct w83792d_data *data = i2c_get_clientdata(client); |
665 | u32 val; | 670 | u8 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 0, 255) >> 4; |
666 | 671 | ||
667 | val = simple_strtoul(buf, NULL, 10); | 672 | mutex_lock(&data->update_lock); |
668 | data->pwm[nr] = PWM_TO_REG(val); | 673 | val |= w83792d_read_value(client, W83792D_REG_PWM[nr]) & 0xf0; |
674 | data->pwm[nr] = val; | ||
669 | w83792d_write_value(client, W83792D_REG_PWM[nr], data->pwm[nr]); | 675 | w83792d_write_value(client, W83792D_REG_PWM[nr], data->pwm[nr]); |
676 | mutex_unlock(&data->update_lock); | ||
670 | 677 | ||
671 | return count; | 678 | return count; |
672 | } | 679 | } |
@@ -683,6 +690,10 @@ store_pwmenable(struct device *dev, struct device_attribute *attr, | |||
683 | u8 fan_cfg_tmp, cfg1_tmp, cfg2_tmp, cfg3_tmp, cfg4_tmp; | 690 | u8 fan_cfg_tmp, cfg1_tmp, cfg2_tmp, cfg3_tmp, cfg4_tmp; |
684 | 691 | ||
685 | val = simple_strtoul(buf, NULL, 10); | 692 | val = simple_strtoul(buf, NULL, 10); |
693 | if (val < 1 || val > 3) | ||
694 | return -EINVAL; | ||
695 | |||
696 | mutex_lock(&data->update_lock); | ||
686 | switch (val) { | 697 | switch (val) { |
687 | case 1: | 698 | case 1: |
688 | data->pwmenable[nr] = 0; /* manual mode */ | 699 | data->pwmenable[nr] = 0; /* manual mode */ |
@@ -693,8 +704,6 @@ store_pwmenable(struct device *dev, struct device_attribute *attr, | |||
693 | case 3: | 704 | case 3: |
694 | data->pwmenable[nr] = 1; /* thermal cruise/Smart Fan I */ | 705 | data->pwmenable[nr] = 1; /* thermal cruise/Smart Fan I */ |
695 | break; | 706 | break; |
696 | default: | ||
697 | return -EINVAL; | ||
698 | } | 707 | } |
699 | cfg1_tmp = data->pwmenable[0]; | 708 | cfg1_tmp = data->pwmenable[0]; |
700 | cfg2_tmp = (data->pwmenable[1]) << 2; | 709 | cfg2_tmp = (data->pwmenable[1]) << 2; |
@@ -702,14 +711,15 @@ store_pwmenable(struct device *dev, struct device_attribute *attr, | |||
702 | cfg4_tmp = w83792d_read_value(client,W83792D_REG_FAN_CFG) & 0xc0; | 711 | cfg4_tmp = w83792d_read_value(client,W83792D_REG_FAN_CFG) & 0xc0; |
703 | fan_cfg_tmp = ((cfg4_tmp | cfg3_tmp) | cfg2_tmp) | cfg1_tmp; | 712 | fan_cfg_tmp = ((cfg4_tmp | cfg3_tmp) | cfg2_tmp) | cfg1_tmp; |
704 | w83792d_write_value(client, W83792D_REG_FAN_CFG, fan_cfg_tmp); | 713 | w83792d_write_value(client, W83792D_REG_FAN_CFG, fan_cfg_tmp); |
714 | mutex_unlock(&data->update_lock); | ||
705 | 715 | ||
706 | return count; | 716 | return count; |
707 | } | 717 | } |
708 | 718 | ||
709 | static struct sensor_device_attribute sda_pwm[] = { | 719 | static struct sensor_device_attribute sda_pwm[] = { |
710 | SENSOR_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1), | 720 | SENSOR_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0), |
711 | SENSOR_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2), | 721 | SENSOR_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1), |
712 | SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 3), | 722 | SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2), |
713 | }; | 723 | }; |
714 | static struct sensor_device_attribute sda_pwm_enable[] = { | 724 | static struct sensor_device_attribute sda_pwm_enable[] = { |
715 | SENSOR_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, | 725 | SENSOR_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, |
@@ -728,7 +738,7 @@ show_pwm_mode(struct device *dev, struct device_attribute *attr, | |||
728 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | 738 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); |
729 | int nr = sensor_attr->index; | 739 | int nr = sensor_attr->index; |
730 | struct w83792d_data *data = w83792d_update_device(dev); | 740 | struct w83792d_data *data = w83792d_update_device(dev); |
731 | return sprintf(buf, "%d\n", data->pwm_mode[nr-1]); | 741 | return sprintf(buf, "%d\n", data->pwm[nr] >> 7); |
732 | } | 742 | } |
733 | 743 | ||
734 | static ssize_t | 744 | static ssize_t |
@@ -736,29 +746,35 @@ store_pwm_mode(struct device *dev, struct device_attribute *attr, | |||
736 | const char *buf, size_t count) | 746 | const char *buf, size_t count) |
737 | { | 747 | { |
738 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | 748 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); |
739 | int nr = sensor_attr->index - 1; | 749 | int nr = sensor_attr->index; |
740 | struct i2c_client *client = to_i2c_client(dev); | 750 | struct i2c_client *client = to_i2c_client(dev); |
741 | struct w83792d_data *data = i2c_get_clientdata(client); | 751 | struct w83792d_data *data = i2c_get_clientdata(client); |
742 | u32 val; | 752 | u32 val; |
743 | u8 pwm_mode_mask = 0; | ||
744 | 753 | ||
745 | val = simple_strtoul(buf, NULL, 10); | 754 | val = simple_strtoul(buf, NULL, 10); |
746 | data->pwm_mode[nr] = SENSORS_LIMIT(val, 0, 1); | 755 | if (val != 0 && val != 1) |
747 | pwm_mode_mask = w83792d_read_value(client, | 756 | return -EINVAL; |
748 | W83792D_REG_PWM[nr]) & 0x7f; | 757 | |
749 | w83792d_write_value(client, W83792D_REG_PWM[nr], | 758 | mutex_lock(&data->update_lock); |
750 | ((data->pwm_mode[nr]) << 7) | pwm_mode_mask); | 759 | data->pwm[nr] = w83792d_read_value(client, W83792D_REG_PWM[nr]); |
760 | if (val) { /* PWM mode */ | ||
761 | data->pwm[nr] |= 0x80; | ||
762 | } else { /* DC mode */ | ||
763 | data->pwm[nr] &= 0x7f; | ||
764 | } | ||
765 | w83792d_write_value(client, W83792D_REG_PWM[nr], data->pwm[nr]); | ||
766 | mutex_unlock(&data->update_lock); | ||
751 | 767 | ||
752 | return count; | 768 | return count; |
753 | } | 769 | } |
754 | 770 | ||
755 | static struct sensor_device_attribute sda_pwm_mode[] = { | 771 | static struct sensor_device_attribute sda_pwm_mode[] = { |
756 | SENSOR_ATTR(pwm1_mode, S_IWUSR | S_IRUGO, | 772 | SENSOR_ATTR(pwm1_mode, S_IWUSR | S_IRUGO, |
757 | show_pwm_mode, store_pwm_mode, 1), | 773 | show_pwm_mode, store_pwm_mode, 0), |
758 | SENSOR_ATTR(pwm2_mode, S_IWUSR | S_IRUGO, | 774 | SENSOR_ATTR(pwm2_mode, S_IWUSR | S_IRUGO, |
759 | show_pwm_mode, store_pwm_mode, 2), | 775 | show_pwm_mode, store_pwm_mode, 1), |
760 | SENSOR_ATTR(pwm3_mode, S_IWUSR | S_IRUGO, | 776 | SENSOR_ATTR(pwm3_mode, S_IWUSR | S_IRUGO, |
761 | show_pwm_mode, store_pwm_mode, 3), | 777 | show_pwm_mode, store_pwm_mode, 2), |
762 | }; | 778 | }; |
763 | 779 | ||
764 | 780 | ||
@@ -789,12 +805,13 @@ store_chassis_clear(struct device *dev, struct device_attribute *attr, | |||
789 | u8 temp1 = 0, temp2 = 0; | 805 | u8 temp1 = 0, temp2 = 0; |
790 | 806 | ||
791 | val = simple_strtoul(buf, NULL, 10); | 807 | val = simple_strtoul(buf, NULL, 10); |
792 | 808 | mutex_lock(&data->update_lock); | |
793 | data->chassis_clear = SENSORS_LIMIT(val, 0 ,1); | 809 | data->chassis_clear = SENSORS_LIMIT(val, 0 ,1); |
794 | temp1 = ((data->chassis_clear) << 7) & 0x80; | 810 | temp1 = ((data->chassis_clear) << 7) & 0x80; |
795 | temp2 = w83792d_read_value(client, | 811 | temp2 = w83792d_read_value(client, |
796 | W83792D_REG_CHASSIS_CLR) & 0x7f; | 812 | W83792D_REG_CHASSIS_CLR) & 0x7f; |
797 | w83792d_write_value(client, W83792D_REG_CHASSIS_CLR, temp1 | temp2); | 813 | w83792d_write_value(client, W83792D_REG_CHASSIS_CLR, temp1 | temp2); |
814 | mutex_unlock(&data->update_lock); | ||
798 | 815 | ||
799 | return count; | 816 | return count; |
800 | } | 817 | } |
@@ -827,10 +844,12 @@ store_thermal_cruise(struct device *dev, struct device_attribute *attr, | |||
827 | val = simple_strtoul(buf, NULL, 10); | 844 | val = simple_strtoul(buf, NULL, 10); |
828 | target_tmp = val; | 845 | target_tmp = val; |
829 | target_tmp = target_tmp & 0x7f; | 846 | target_tmp = target_tmp & 0x7f; |
847 | mutex_lock(&data->update_lock); | ||
830 | target_mask = w83792d_read_value(client, W83792D_REG_THERMAL[nr]) & 0x80; | 848 | target_mask = w83792d_read_value(client, W83792D_REG_THERMAL[nr]) & 0x80; |
831 | data->thermal_cruise[nr] = SENSORS_LIMIT(target_tmp, 0, 255); | 849 | data->thermal_cruise[nr] = SENSORS_LIMIT(target_tmp, 0, 255); |
832 | w83792d_write_value(client, W83792D_REG_THERMAL[nr], | 850 | w83792d_write_value(client, W83792D_REG_THERMAL[nr], |
833 | (data->thermal_cruise[nr]) | target_mask); | 851 | (data->thermal_cruise[nr]) | target_mask); |
852 | mutex_unlock(&data->update_lock); | ||
834 | 853 | ||
835 | return count; | 854 | return count; |
836 | } | 855 | } |
@@ -867,6 +886,7 @@ store_tolerance(struct device *dev, struct device_attribute *attr, | |||
867 | u8 tol_tmp, tol_mask; | 886 | u8 tol_tmp, tol_mask; |
868 | 887 | ||
869 | val = simple_strtoul(buf, NULL, 10); | 888 | val = simple_strtoul(buf, NULL, 10); |
889 | mutex_lock(&data->update_lock); | ||
870 | tol_mask = w83792d_read_value(client, | 890 | tol_mask = w83792d_read_value(client, |
871 | W83792D_REG_TOLERANCE[nr]) & ((nr == 1) ? 0x0f : 0xf0); | 891 | W83792D_REG_TOLERANCE[nr]) & ((nr == 1) ? 0x0f : 0xf0); |
872 | tol_tmp = SENSORS_LIMIT(val, 0, 15); | 892 | tol_tmp = SENSORS_LIMIT(val, 0, 15); |
@@ -877,6 +897,7 @@ store_tolerance(struct device *dev, struct device_attribute *attr, | |||
877 | } | 897 | } |
878 | w83792d_write_value(client, W83792D_REG_TOLERANCE[nr], | 898 | w83792d_write_value(client, W83792D_REG_TOLERANCE[nr], |
879 | tol_mask | tol_tmp); | 899 | tol_mask | tol_tmp); |
900 | mutex_unlock(&data->update_lock); | ||
880 | 901 | ||
881 | return count; | 902 | return count; |
882 | } | 903 | } |
@@ -915,11 +936,13 @@ store_sf2_point(struct device *dev, struct device_attribute *attr, | |||
915 | u8 mask_tmp = 0; | 936 | u8 mask_tmp = 0; |
916 | 937 | ||
917 | val = simple_strtoul(buf, NULL, 10); | 938 | val = simple_strtoul(buf, NULL, 10); |
939 | mutex_lock(&data->update_lock); | ||
918 | data->sf2_points[index][nr] = SENSORS_LIMIT(val, 0, 127); | 940 | data->sf2_points[index][nr] = SENSORS_LIMIT(val, 0, 127); |
919 | mask_tmp = w83792d_read_value(client, | 941 | mask_tmp = w83792d_read_value(client, |
920 | W83792D_REG_POINTS[index][nr]) & 0x80; | 942 | W83792D_REG_POINTS[index][nr]) & 0x80; |
921 | w83792d_write_value(client, W83792D_REG_POINTS[index][nr], | 943 | w83792d_write_value(client, W83792D_REG_POINTS[index][nr], |
922 | mask_tmp|data->sf2_points[index][nr]); | 944 | mask_tmp|data->sf2_points[index][nr]); |
945 | mutex_unlock(&data->update_lock); | ||
923 | 946 | ||
924 | return count; | 947 | return count; |
925 | } | 948 | } |
@@ -979,6 +1002,7 @@ store_sf2_level(struct device *dev, struct device_attribute *attr, | |||
979 | u8 mask_tmp=0, level_tmp=0; | 1002 | u8 mask_tmp=0, level_tmp=0; |
980 | 1003 | ||
981 | val = simple_strtoul(buf, NULL, 10); | 1004 | val = simple_strtoul(buf, NULL, 10); |
1005 | mutex_lock(&data->update_lock); | ||
982 | data->sf2_levels[index][nr] = SENSORS_LIMIT((val * 15) / 100, 0, 15); | 1006 | data->sf2_levels[index][nr] = SENSORS_LIMIT((val * 15) / 100, 0, 15); |
983 | mask_tmp = w83792d_read_value(client, W83792D_REG_LEVELS[index][nr]) | 1007 | mask_tmp = w83792d_read_value(client, W83792D_REG_LEVELS[index][nr]) |
984 | & ((nr==3) ? 0xf0 : 0x0f); | 1008 | & ((nr==3) ? 0xf0 : 0x0f); |
@@ -988,6 +1012,7 @@ store_sf2_level(struct device *dev, struct device_attribute *attr, | |||
988 | level_tmp = data->sf2_levels[index][nr] << 4; | 1012 | level_tmp = data->sf2_levels[index][nr] << 4; |
989 | } | 1013 | } |
990 | w83792d_write_value(client, W83792D_REG_LEVELS[index][nr], level_tmp | mask_tmp); | 1014 | w83792d_write_value(client, W83792D_REG_LEVELS[index][nr], level_tmp | mask_tmp); |
1015 | mutex_unlock(&data->update_lock); | ||
991 | 1016 | ||
992 | return count; | 1017 | return count; |
993 | } | 1018 | } |
@@ -1373,7 +1398,7 @@ static struct w83792d_data *w83792d_update_device(struct device *dev) | |||
1373 | struct i2c_client *client = to_i2c_client(dev); | 1398 | struct i2c_client *client = to_i2c_client(dev); |
1374 | struct w83792d_data *data = i2c_get_clientdata(client); | 1399 | struct w83792d_data *data = i2c_get_clientdata(client); |
1375 | int i, j; | 1400 | int i, j; |
1376 | u8 reg_array_tmp[4], pwm_array_tmp[7], reg_tmp; | 1401 | u8 reg_array_tmp[4], reg_tmp; |
1377 | 1402 | ||
1378 | mutex_lock(&data->update_lock); | 1403 | mutex_lock(&data->update_lock); |
1379 | 1404 | ||
@@ -1402,10 +1427,8 @@ static struct w83792d_data *w83792d_update_device(struct device *dev) | |||
1402 | data->fan_min[i] = w83792d_read_value(client, | 1427 | data->fan_min[i] = w83792d_read_value(client, |
1403 | W83792D_REG_FAN_MIN[i]); | 1428 | W83792D_REG_FAN_MIN[i]); |
1404 | /* Update the PWM/DC Value and PWM/DC flag */ | 1429 | /* Update the PWM/DC Value and PWM/DC flag */ |
1405 | pwm_array_tmp[i] = w83792d_read_value(client, | 1430 | data->pwm[i] = w83792d_read_value(client, |
1406 | W83792D_REG_PWM[i]); | 1431 | W83792D_REG_PWM[i]); |
1407 | data->pwm[i] = pwm_array_tmp[i] & 0x0f; | ||
1408 | data->pwm_mode[i] = pwm_array_tmp[i] >> 7; | ||
1409 | } | 1432 | } |
1410 | 1433 | ||
1411 | reg_tmp = w83792d_read_value(client, W83792D_REG_FAN_CFG); | 1434 | reg_tmp = w83792d_read_value(client, W83792D_REG_FAN_CFG); |
@@ -1513,7 +1536,6 @@ static void w83792d_print_debug(struct w83792d_data *data, struct device *dev) | |||
1513 | dev_dbg(dev, "fan[%d] is: 0x%x\n", i, data->fan[i]); | 1536 | dev_dbg(dev, "fan[%d] is: 0x%x\n", i, data->fan[i]); |
1514 | dev_dbg(dev, "fan[%d] min is: 0x%x\n", i, data->fan_min[i]); | 1537 | dev_dbg(dev, "fan[%d] min is: 0x%x\n", i, data->fan_min[i]); |
1515 | dev_dbg(dev, "pwm[%d] is: 0x%x\n", i, data->pwm[i]); | 1538 | dev_dbg(dev, "pwm[%d] is: 0x%x\n", i, data->pwm[i]); |
1516 | dev_dbg(dev, "pwm_mode[%d] is: 0x%x\n", i, data->pwm_mode[i]); | ||
1517 | } | 1539 | } |
1518 | dev_dbg(dev, "3 set of Temperatures: =====>\n"); | 1540 | dev_dbg(dev, "3 set of Temperatures: =====>\n"); |
1519 | for (i=0; i<3; i++) { | 1541 | for (i=0; i<3; i++) { |
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index d6d44946a283..884320e70403 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig | |||
@@ -163,7 +163,7 @@ config I2C_PXA_SLAVE | |||
163 | I2C bus. | 163 | I2C bus. |
164 | 164 | ||
165 | config I2C_PIIX4 | 165 | config I2C_PIIX4 |
166 | tristate "Intel PIIX4" | 166 | tristate "Intel PIIX4 and compatible (ATI/Serverworks/Broadcom/SMSC)" |
167 | depends on I2C && PCI | 167 | depends on I2C && PCI |
168 | help | 168 | help |
169 | If you say yes to this option, support will be included for the Intel | 169 | If you say yes to this option, support will be included for the Intel |
@@ -172,6 +172,9 @@ config I2C_PIIX4 | |||
172 | of Broadcom): | 172 | of Broadcom): |
173 | Intel PIIX4 | 173 | Intel PIIX4 |
174 | Intel 440MX | 174 | Intel 440MX |
175 | ATI IXP200 | ||
176 | ATI IXP300 | ||
177 | ATI IXP400 | ||
175 | Serverworks OSB4 | 178 | Serverworks OSB4 |
176 | Serverworks CSB5 | 179 | Serverworks CSB5 |
177 | Serverworks CSB6 | 180 | Serverworks CSB6 |
@@ -252,12 +255,12 @@ config I2C_POWERMAC | |||
252 | will be called i2c-powermac. | 255 | will be called i2c-powermac. |
253 | 256 | ||
254 | config I2C_MPC | 257 | config I2C_MPC |
255 | tristate "MPC107/824x/85xx/52xx" | 258 | tristate "MPC107/824x/85xx/52xx/86xx" |
256 | depends on I2C && PPC32 | 259 | depends on I2C && PPC32 |
257 | help | 260 | help |
258 | If you say yes to this option, support will be included for the | 261 | If you say yes to this option, support will be included for the |
259 | built-in I2C interface on the MPC107/Tsi107/MPC8240/MPC8245 and | 262 | built-in I2C interface on the MPC107/Tsi107/MPC8240/MPC8245 and |
260 | MPC85xx family processors. The driver may also work on 52xx | 263 | MPC85xx/MPC8641 family processors. The driver may also work on 52xx |
261 | family processors, though interrupts are known not to work. | 264 | family processors, though interrupts are known not to work. |
262 | 265 | ||
263 | This driver can also be built as a module. If so, the module | 266 | This driver can also be built as a module. If so, the module |
@@ -273,6 +276,17 @@ config I2C_NFORCE2 | |||
273 | This driver can also be built as a module. If so, the module | 276 | This driver can also be built as a module. If so, the module |
274 | will be called i2c-nforce2. | 277 | will be called i2c-nforce2. |
275 | 278 | ||
279 | config I2C_OCORES | ||
280 | tristate "OpenCores I2C Controller" | ||
281 | depends on I2C && EXPERIMENTAL | ||
282 | help | ||
283 | If you say yes to this option, support will be included for the | ||
284 | OpenCores I2C controller. For details see | ||
285 | http://www.opencores.org/projects.cgi/web/i2c/overview | ||
286 | |||
287 | This driver can also be built as a module. If so, the module | ||
288 | will be called i2c-ocores. | ||
289 | |||
276 | config I2C_PARPORT | 290 | config I2C_PARPORT |
277 | tristate "Parallel port adapter" | 291 | tristate "Parallel port adapter" |
278 | depends on I2C && PARPORT | 292 | depends on I2C && PARPORT |
@@ -500,6 +514,7 @@ config I2C_PCA_ISA | |||
500 | tristate "PCA9564 on an ISA bus" | 514 | tristate "PCA9564 on an ISA bus" |
501 | depends on I2C | 515 | depends on I2C |
502 | select I2C_ALGOPCA | 516 | select I2C_ALGOPCA |
517 | default n | ||
503 | help | 518 | help |
504 | This driver supports ISA boards using the Philips PCA 9564 | 519 | This driver supports ISA boards using the Philips PCA 9564 |
505 | Parallel bus to I2C bus controller | 520 | Parallel bus to I2C bus controller |
@@ -507,6 +522,11 @@ config I2C_PCA_ISA | |||
507 | This driver can also be built as a module. If so, the module | 522 | This driver can also be built as a module. If so, the module |
508 | will be called i2c-pca-isa. | 523 | will be called i2c-pca-isa. |
509 | 524 | ||
525 | This device is almost undetectable and using this driver on a | ||
526 | system which doesn't have this device will result in long | ||
527 | delays when I2C/SMBus chip drivers are loaded (e.g. at boot | ||
528 | time). If unsure, say N. | ||
529 | |||
510 | config I2C_MV64XXX | 530 | config I2C_MV64XXX |
511 | tristate "Marvell mv64xxx I2C Controller" | 531 | tristate "Marvell mv64xxx I2C Controller" |
512 | depends on I2C && MV64X60 && EXPERIMENTAL | 532 | depends on I2C && MV64X60 && EXPERIMENTAL |
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index b44831dff683..ac56df53155b 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile | |||
@@ -23,6 +23,7 @@ obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o | |||
23 | obj-$(CONFIG_I2C_MPC) += i2c-mpc.o | 23 | obj-$(CONFIG_I2C_MPC) += i2c-mpc.o |
24 | obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o | 24 | obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o |
25 | obj-$(CONFIG_I2C_NFORCE2) += i2c-nforce2.o | 25 | obj-$(CONFIG_I2C_NFORCE2) += i2c-nforce2.o |
26 | obj-$(CONFIG_I2C_OCORES) += i2c-ocores.o | ||
26 | obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o | 27 | obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o |
27 | obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o | 28 | obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o |
28 | obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o | 29 | obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o |
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index dfca74933625..3e0d04d5a800 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | i801.c - Part of lm_sensors, Linux kernel modules for hardware | 2 | i2c-i801.c - Part of lm_sensors, Linux kernel modules for hardware |
3 | monitoring | 3 | monitoring |
4 | Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl>, | 4 | Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl>, |
5 | Philip Edelbrock <phil@netroedge.com>, and Mark D. Studebaker | 5 | Philip Edelbrock <phil@netroedge.com>, and Mark D. Studebaker |
@@ -36,7 +36,7 @@ | |||
36 | This driver supports several versions of Intel's I/O Controller Hubs (ICH). | 36 | This driver supports several versions of Intel's I/O Controller Hubs (ICH). |
37 | For SMBus support, they are similar to the PIIX4 and are part | 37 | For SMBus support, they are similar to the PIIX4 and are part |
38 | of Intel's '810' and other chipsets. | 38 | of Intel's '810' and other chipsets. |
39 | See the doc/busses/i2c-i801 file for details. | 39 | See the file Documentation/i2c/busses/i2c-i801 for details. |
40 | I2C Block Read and Process Call are not supported. | 40 | I2C Block Read and Process Call are not supported. |
41 | */ | 41 | */ |
42 | 42 | ||
@@ -66,9 +66,8 @@ | |||
66 | #define SMBAUXCTL (13 + i801_smba) /* ICH4 only */ | 66 | #define SMBAUXCTL (13 + i801_smba) /* ICH4 only */ |
67 | 67 | ||
68 | /* PCI Address Constants */ | 68 | /* PCI Address Constants */ |
69 | #define SMBBA 0x020 | 69 | #define SMBBAR 4 |
70 | #define SMBHSTCFG 0x040 | 70 | #define SMBHSTCFG 0x040 |
71 | #define SMBREV 0x008 | ||
72 | 71 | ||
73 | /* Host configuration bits for SMBHSTCFG */ | 72 | /* Host configuration bits for SMBHSTCFG */ |
74 | #define SMBHSTCFG_HST_EN 1 | 73 | #define SMBHSTCFG_HST_EN 1 |
@@ -92,92 +91,16 @@ | |||
92 | #define I801_START 0x40 | 91 | #define I801_START 0x40 |
93 | #define I801_PEC_EN 0x80 /* ICH4 only */ | 92 | #define I801_PEC_EN 0x80 /* ICH4 only */ |
94 | 93 | ||
95 | /* insmod parameters */ | ||
96 | |||
97 | /* If force_addr is set to anything different from 0, we forcibly enable | ||
98 | the I801 at the given address. VERY DANGEROUS! */ | ||
99 | static u16 force_addr; | ||
100 | module_param(force_addr, ushort, 0); | ||
101 | MODULE_PARM_DESC(force_addr, | ||
102 | "Forcibly enable the I801 at the given address. " | ||
103 | "EXTREMELY DANGEROUS!"); | ||
104 | 94 | ||
105 | static int i801_transaction(void); | 95 | static int i801_transaction(void); |
106 | static int i801_block_transaction(union i2c_smbus_data *data, char read_write, | 96 | static int i801_block_transaction(union i2c_smbus_data *data, char read_write, |
107 | int command, int hwpec); | 97 | int command, int hwpec); |
108 | 98 | ||
109 | static unsigned short i801_smba; | 99 | static unsigned long i801_smba; |
110 | static struct pci_driver i801_driver; | 100 | static struct pci_driver i801_driver; |
111 | static struct pci_dev *I801_dev; | 101 | static struct pci_dev *I801_dev; |
112 | static int isich4; | 102 | static int isich4; |
113 | 103 | ||
114 | static int i801_setup(struct pci_dev *dev) | ||
115 | { | ||
116 | int error_return = 0; | ||
117 | unsigned char temp; | ||
118 | |||
119 | /* Note: we keep on searching until we have found 'function 3' */ | ||
120 | if(PCI_FUNC(dev->devfn) != 3) | ||
121 | return -ENODEV; | ||
122 | |||
123 | I801_dev = dev; | ||
124 | if ((dev->device == PCI_DEVICE_ID_INTEL_82801DB_3) || | ||
125 | (dev->device == PCI_DEVICE_ID_INTEL_82801EB_3) || | ||
126 | (dev->device == PCI_DEVICE_ID_INTEL_ESB_4)) | ||
127 | isich4 = 1; | ||
128 | else | ||
129 | isich4 = 0; | ||
130 | |||
131 | /* Determine the address of the SMBus areas */ | ||
132 | if (force_addr) { | ||
133 | i801_smba = force_addr & 0xfff0; | ||
134 | } else { | ||
135 | pci_read_config_word(I801_dev, SMBBA, &i801_smba); | ||
136 | i801_smba &= 0xfff0; | ||
137 | if(i801_smba == 0) { | ||
138 | dev_err(&dev->dev, "SMB base address uninitialized " | ||
139 | "- upgrade BIOS or use force_addr=0xaddr\n"); | ||
140 | return -ENODEV; | ||
141 | } | ||
142 | } | ||
143 | |||
144 | if (!request_region(i801_smba, (isich4 ? 16 : 8), i801_driver.name)) { | ||
145 | dev_err(&dev->dev, "I801_smb region 0x%x already in use!\n", | ||
146 | i801_smba); | ||
147 | error_return = -EBUSY; | ||
148 | goto END; | ||
149 | } | ||
150 | |||
151 | pci_read_config_byte(I801_dev, SMBHSTCFG, &temp); | ||
152 | temp &= ~SMBHSTCFG_I2C_EN; /* SMBus timing */ | ||
153 | pci_write_config_byte(I801_dev, SMBHSTCFG, temp); | ||
154 | |||
155 | /* If force_addr is set, we program the new address here. Just to make | ||
156 | sure, we disable the device first. */ | ||
157 | if (force_addr) { | ||
158 | pci_write_config_byte(I801_dev, SMBHSTCFG, temp & 0xfe); | ||
159 | pci_write_config_word(I801_dev, SMBBA, i801_smba); | ||
160 | pci_write_config_byte(I801_dev, SMBHSTCFG, temp | 0x01); | ||
161 | dev_warn(&dev->dev, "WARNING: I801 SMBus interface set to " | ||
162 | "new address %04x!\n", i801_smba); | ||
163 | } else if ((temp & 1) == 0) { | ||
164 | pci_write_config_byte(I801_dev, SMBHSTCFG, temp | 1); | ||
165 | dev_warn(&dev->dev, "enabling SMBus device\n"); | ||
166 | } | ||
167 | |||
168 | if (temp & 0x02) | ||
169 | dev_dbg(&dev->dev, "I801 using Interrupt SMI# for SMBus.\n"); | ||
170 | else | ||
171 | dev_dbg(&dev->dev, "I801 using PCI Interrupt for SMBus.\n"); | ||
172 | |||
173 | pci_read_config_byte(I801_dev, SMBREV, &temp); | ||
174 | dev_dbg(&dev->dev, "SMBREV = 0x%X\n", temp); | ||
175 | dev_dbg(&dev->dev, "I801_smba = 0x%X\n", i801_smba); | ||
176 | |||
177 | END: | ||
178 | return error_return; | ||
179 | } | ||
180 | |||
181 | static int i801_transaction(void) | 104 | static int i801_transaction(void) |
182 | { | 105 | { |
183 | int temp; | 106 | int temp; |
@@ -334,8 +257,8 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write, | |||
334 | /* We will always wait for a fraction of a second! */ | 257 | /* We will always wait for a fraction of a second! */ |
335 | timeout = 0; | 258 | timeout = 0; |
336 | do { | 259 | do { |
337 | temp = inb_p(SMBHSTSTS); | ||
338 | msleep(1); | 260 | msleep(1); |
261 | temp = inb_p(SMBHSTSTS); | ||
339 | } | 262 | } |
340 | while ((!(temp & 0x80)) | 263 | while ((!(temp & 0x80)) |
341 | && (timeout++ < MAX_TIMEOUT)); | 264 | && (timeout++ < MAX_TIMEOUT)); |
@@ -393,8 +316,8 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write, | |||
393 | /* wait for INTR bit as advised by Intel */ | 316 | /* wait for INTR bit as advised by Intel */ |
394 | timeout = 0; | 317 | timeout = 0; |
395 | do { | 318 | do { |
396 | temp = inb_p(SMBHSTSTS); | ||
397 | msleep(1); | 319 | msleep(1); |
320 | temp = inb_p(SMBHSTSTS); | ||
398 | } while ((!(temp & 0x02)) | 321 | } while ((!(temp & 0x02)) |
399 | && (timeout++ < MAX_TIMEOUT)); | 322 | && (timeout++ < MAX_TIMEOUT)); |
400 | 323 | ||
@@ -541,25 +464,76 @@ MODULE_DEVICE_TABLE (pci, i801_ids); | |||
541 | 464 | ||
542 | static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id *id) | 465 | static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id *id) |
543 | { | 466 | { |
467 | unsigned char temp; | ||
468 | int err; | ||
469 | |||
470 | I801_dev = dev; | ||
471 | if ((dev->device == PCI_DEVICE_ID_INTEL_82801DB_3) || | ||
472 | (dev->device == PCI_DEVICE_ID_INTEL_82801EB_3) || | ||
473 | (dev->device == PCI_DEVICE_ID_INTEL_ESB_4)) | ||
474 | isich4 = 1; | ||
475 | else | ||
476 | isich4 = 0; | ||
477 | |||
478 | err = pci_enable_device(dev); | ||
479 | if (err) { | ||
480 | dev_err(&dev->dev, "Failed to enable SMBus PCI device (%d)\n", | ||
481 | err); | ||
482 | goto exit; | ||
483 | } | ||
484 | |||
485 | /* Determine the address of the SMBus area */ | ||
486 | i801_smba = pci_resource_start(dev, SMBBAR); | ||
487 | if (!i801_smba) { | ||
488 | dev_err(&dev->dev, "SMBus base address uninitialized, " | ||
489 | "upgrade BIOS\n"); | ||
490 | err = -ENODEV; | ||
491 | goto exit_disable; | ||
492 | } | ||
493 | |||
494 | err = pci_request_region(dev, SMBBAR, i801_driver.name); | ||
495 | if (err) { | ||
496 | dev_err(&dev->dev, "Failed to request SMBus region " | ||
497 | "0x%lx-0x%lx\n", i801_smba, | ||
498 | pci_resource_end(dev, SMBBAR)); | ||
499 | goto exit_disable; | ||
500 | } | ||
544 | 501 | ||
545 | if (i801_setup(dev)) { | 502 | pci_read_config_byte(I801_dev, SMBHSTCFG, &temp); |
546 | dev_warn(&dev->dev, | 503 | temp &= ~SMBHSTCFG_I2C_EN; /* SMBus timing */ |
547 | "I801 not detected, module not inserted.\n"); | 504 | if (!(temp & SMBHSTCFG_HST_EN)) { |
548 | return -ENODEV; | 505 | dev_info(&dev->dev, "Enabling SMBus device\n"); |
506 | temp |= SMBHSTCFG_HST_EN; | ||
549 | } | 507 | } |
508 | pci_write_config_byte(I801_dev, SMBHSTCFG, temp); | ||
509 | |||
510 | if (temp & SMBHSTCFG_SMB_SMI_EN) | ||
511 | dev_dbg(&dev->dev, "SMBus using interrupt SMI#\n"); | ||
512 | else | ||
513 | dev_dbg(&dev->dev, "SMBus using PCI Interrupt\n"); | ||
550 | 514 | ||
551 | /* set up the driverfs linkage to our parent device */ | 515 | /* set up the driverfs linkage to our parent device */ |
552 | i801_adapter.dev.parent = &dev->dev; | 516 | i801_adapter.dev.parent = &dev->dev; |
553 | 517 | ||
554 | snprintf(i801_adapter.name, I2C_NAME_SIZE, | 518 | snprintf(i801_adapter.name, I2C_NAME_SIZE, |
555 | "SMBus I801 adapter at %04x", i801_smba); | 519 | "SMBus I801 adapter at %04lx", i801_smba); |
556 | return i2c_add_adapter(&i801_adapter); | 520 | err = i2c_add_adapter(&i801_adapter); |
521 | if (err) { | ||
522 | dev_err(&dev->dev, "Failed to add SMBus adapter\n"); | ||
523 | goto exit_disable; | ||
524 | } | ||
525 | |||
526 | exit_disable: | ||
527 | pci_disable_device(dev); | ||
528 | exit: | ||
529 | return err; | ||
557 | } | 530 | } |
558 | 531 | ||
559 | static void __devexit i801_remove(struct pci_dev *dev) | 532 | static void __devexit i801_remove(struct pci_dev *dev) |
560 | { | 533 | { |
561 | i2c_del_adapter(&i801_adapter); | 534 | i2c_del_adapter(&i801_adapter); |
562 | release_region(i801_smba, (isich4 ? 16 : 8)); | 535 | pci_release_region(dev, SMBBAR); |
536 | pci_disable_device(dev); | ||
563 | } | 537 | } |
564 | 538 | ||
565 | static struct pci_driver i801_driver = { | 539 | static struct pci_driver i801_driver = { |
diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c index 2d80eb26f688..604b49e22df1 100644 --- a/drivers/i2c/busses/i2c-nforce2.c +++ b/drivers/i2c/busses/i2c-nforce2.c | |||
@@ -31,6 +31,8 @@ | |||
31 | nForce3 250Gb MCP 00E4 | 31 | nForce3 250Gb MCP 00E4 |
32 | nForce4 MCP 0052 | 32 | nForce4 MCP 0052 |
33 | nForce4 MCP-04 0034 | 33 | nForce4 MCP-04 0034 |
34 | nForce4 MCP51 0264 | ||
35 | nForce4 MCP55 0368 | ||
34 | 36 | ||
35 | This driver supports the 2 SMBuses that are included in the MCP of the | 37 | This driver supports the 2 SMBuses that are included in the MCP of the |
36 | nForce2/3/4 chipsets. | 38 | nForce2/3/4 chipsets. |
@@ -64,6 +66,7 @@ struct nforce2_smbus { | |||
64 | 66 | ||
65 | /* | 67 | /* |
66 | * nVidia nForce2 SMBus control register definitions | 68 | * nVidia nForce2 SMBus control register definitions |
69 | * (Newer incarnations use standard BARs 4 and 5 instead) | ||
67 | */ | 70 | */ |
68 | #define NFORCE_PCI_SMB1 0x50 | 71 | #define NFORCE_PCI_SMB1 0x50 |
69 | #define NFORCE_PCI_SMB2 0x54 | 72 | #define NFORCE_PCI_SMB2 0x54 |
@@ -259,6 +262,8 @@ static struct pci_device_id nforce2_ids[] = { | |||
259 | { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SMBUS) }, | 262 | { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SMBUS) }, |
260 | { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE4_SMBUS) }, | 263 | { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE4_SMBUS) }, |
261 | { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SMBUS) }, | 264 | { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SMBUS) }, |
265 | { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS) }, | ||
266 | { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS) }, | ||
262 | { 0 } | 267 | { 0 } |
263 | }; | 268 | }; |
264 | 269 | ||
@@ -266,19 +271,29 @@ static struct pci_device_id nforce2_ids[] = { | |||
266 | MODULE_DEVICE_TABLE (pci, nforce2_ids); | 271 | MODULE_DEVICE_TABLE (pci, nforce2_ids); |
267 | 272 | ||
268 | 273 | ||
269 | static int __devinit nforce2_probe_smb (struct pci_dev *dev, int reg, | 274 | static int __devinit nforce2_probe_smb (struct pci_dev *dev, int bar, |
270 | struct nforce2_smbus *smbus, char *name) | 275 | int alt_reg, struct nforce2_smbus *smbus, const char *name) |
271 | { | 276 | { |
272 | u16 iobase; | ||
273 | int error; | 277 | int error; |
274 | 278 | ||
275 | if (pci_read_config_word(dev, reg, &iobase) != PCIBIOS_SUCCESSFUL) { | 279 | smbus->base = pci_resource_start(dev, bar); |
276 | dev_err(&smbus->adapter.dev, "Error reading PCI config for %s\n", name); | 280 | if (smbus->base) { |
277 | return -1; | 281 | smbus->size = pci_resource_len(dev, bar); |
282 | } else { | ||
283 | /* Older incarnations of the device used non-standard BARs */ | ||
284 | u16 iobase; | ||
285 | |||
286 | if (pci_read_config_word(dev, alt_reg, &iobase) | ||
287 | != PCIBIOS_SUCCESSFUL) { | ||
288 | dev_err(&dev->dev, "Error reading PCI config for %s\n", | ||
289 | name); | ||
290 | return -1; | ||
291 | } | ||
292 | |||
293 | smbus->base = iobase & PCI_BASE_ADDRESS_IO_MASK; | ||
294 | smbus->size = 8; | ||
278 | } | 295 | } |
279 | smbus->dev = dev; | 296 | smbus->dev = dev; |
280 | smbus->base = iobase & 0xfffc; | ||
281 | smbus->size = 8; | ||
282 | 297 | ||
283 | if (!request_region(smbus->base, smbus->size, nforce2_driver.name)) { | 298 | if (!request_region(smbus->base, smbus->size, nforce2_driver.name)) { |
284 | dev_err(&smbus->adapter.dev, "Error requesting region %02x .. %02X for %s\n", | 299 | dev_err(&smbus->adapter.dev, "Error requesting region %02x .. %02X for %s\n", |
@@ -313,12 +328,13 @@ static int __devinit nforce2_probe(struct pci_dev *dev, const struct pci_device_ | |||
313 | pci_set_drvdata(dev, smbuses); | 328 | pci_set_drvdata(dev, smbuses); |
314 | 329 | ||
315 | /* SMBus adapter 1 */ | 330 | /* SMBus adapter 1 */ |
316 | res1 = nforce2_probe_smb (dev, NFORCE_PCI_SMB1, &smbuses[0], "SMB1"); | 331 | res1 = nforce2_probe_smb(dev, 4, NFORCE_PCI_SMB1, &smbuses[0], "SMB1"); |
317 | if (res1 < 0) { | 332 | if (res1 < 0) { |
318 | dev_err(&dev->dev, "Error probing SMB1.\n"); | 333 | dev_err(&dev->dev, "Error probing SMB1.\n"); |
319 | smbuses[0].base = 0; /* to have a check value */ | 334 | smbuses[0].base = 0; /* to have a check value */ |
320 | } | 335 | } |
321 | res2 = nforce2_probe_smb (dev, NFORCE_PCI_SMB2, &smbuses[1], "SMB2"); | 336 | /* SMBus adapter 2 */ |
337 | res2 = nforce2_probe_smb(dev, 5, NFORCE_PCI_SMB2, &smbuses[1], "SMB2"); | ||
322 | if (res2 < 0) { | 338 | if (res2 < 0) { |
323 | dev_err(&dev->dev, "Error probing SMB2.\n"); | 339 | dev_err(&dev->dev, "Error probing SMB2.\n"); |
324 | smbuses[1].base = 0; /* to have a check value */ | 340 | smbuses[1].base = 0; /* to have a check value */ |
diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c new file mode 100644 index 000000000000..592824087c49 --- /dev/null +++ b/drivers/i2c/busses/i2c-ocores.c | |||
@@ -0,0 +1,341 @@ | |||
1 | /* | ||
2 | * i2c-ocores.c: I2C bus driver for OpenCores I2C controller | ||
3 | * (http://www.opencores.org/projects.cgi/web/i2c/overview). | ||
4 | * | ||
5 | * Peter Korsgaard <jacmet@sunsite.dk> | ||
6 | * | ||
7 | * This file is licensed under the terms of the GNU General Public License | ||
8 | * version 2. This program is licensed "as is" without any warranty of any | ||
9 | * kind, whether express or implied. | ||
10 | */ | ||
11 | |||
12 | #include <linux/config.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/sched.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/errno.h> | ||
18 | #include <linux/platform_device.h> | ||
19 | #include <linux/i2c.h> | ||
20 | #include <linux/interrupt.h> | ||
21 | #include <linux/wait.h> | ||
22 | #include <linux/i2c-ocores.h> | ||
23 | #include <asm/io.h> | ||
24 | |||
25 | struct ocores_i2c { | ||
26 | void __iomem *base; | ||
27 | int regstep; | ||
28 | wait_queue_head_t wait; | ||
29 | struct i2c_adapter adap; | ||
30 | struct i2c_msg *msg; | ||
31 | int pos; | ||
32 | int nmsgs; | ||
33 | int state; /* see STATE_ */ | ||
34 | }; | ||
35 | |||
36 | /* registers */ | ||
37 | #define OCI2C_PRELOW 0 | ||
38 | #define OCI2C_PREHIGH 1 | ||
39 | #define OCI2C_CONTROL 2 | ||
40 | #define OCI2C_DATA 3 | ||
41 | #define OCI2C_CMD 4 /* write only */ | ||
42 | #define OCI2C_STATUS 4 /* read only, same address as OCI2C_CMD */ | ||
43 | |||
44 | #define OCI2C_CTRL_IEN 0x40 | ||
45 | #define OCI2C_CTRL_EN 0x80 | ||
46 | |||
47 | #define OCI2C_CMD_START 0x91 | ||
48 | #define OCI2C_CMD_STOP 0x41 | ||
49 | #define OCI2C_CMD_READ 0x21 | ||
50 | #define OCI2C_CMD_WRITE 0x11 | ||
51 | #define OCI2C_CMD_READ_ACK 0x21 | ||
52 | #define OCI2C_CMD_READ_NACK 0x29 | ||
53 | #define OCI2C_CMD_IACK 0x01 | ||
54 | |||
55 | #define OCI2C_STAT_IF 0x01 | ||
56 | #define OCI2C_STAT_TIP 0x02 | ||
57 | #define OCI2C_STAT_ARBLOST 0x20 | ||
58 | #define OCI2C_STAT_BUSY 0x40 | ||
59 | #define OCI2C_STAT_NACK 0x80 | ||
60 | |||
61 | #define STATE_DONE 0 | ||
62 | #define STATE_START 1 | ||
63 | #define STATE_WRITE 2 | ||
64 | #define STATE_READ 3 | ||
65 | #define STATE_ERROR 4 | ||
66 | |||
67 | static inline void oc_setreg(struct ocores_i2c *i2c, int reg, u8 value) | ||
68 | { | ||
69 | iowrite8(value, i2c->base + reg * i2c->regstep); | ||
70 | } | ||
71 | |||
72 | static inline u8 oc_getreg(struct ocores_i2c *i2c, int reg) | ||
73 | { | ||
74 | return ioread8(i2c->base + reg * i2c->regstep); | ||
75 | } | ||
76 | |||
77 | static void ocores_process(struct ocores_i2c *i2c) | ||
78 | { | ||
79 | struct i2c_msg *msg = i2c->msg; | ||
80 | u8 stat = oc_getreg(i2c, OCI2C_STATUS); | ||
81 | |||
82 | if ((i2c->state == STATE_DONE) || (i2c->state == STATE_ERROR)) { | ||
83 | /* stop has been sent */ | ||
84 | oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK); | ||
85 | wake_up(&i2c->wait); | ||
86 | return; | ||
87 | } | ||
88 | |||
89 | /* error? */ | ||
90 | if (stat & OCI2C_STAT_ARBLOST) { | ||
91 | i2c->state = STATE_ERROR; | ||
92 | oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP); | ||
93 | return; | ||
94 | } | ||
95 | |||
96 | if ((i2c->state == STATE_START) || (i2c->state == STATE_WRITE)) { | ||
97 | i2c->state = | ||
98 | (msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE; | ||
99 | |||
100 | if (stat & OCI2C_STAT_NACK) { | ||
101 | i2c->state = STATE_ERROR; | ||
102 | oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP); | ||
103 | return; | ||
104 | } | ||
105 | } else | ||
106 | msg->buf[i2c->pos++] = oc_getreg(i2c, OCI2C_DATA); | ||
107 | |||
108 | /* end of msg? */ | ||
109 | if (i2c->pos == msg->len) { | ||
110 | i2c->nmsgs--; | ||
111 | i2c->msg++; | ||
112 | i2c->pos = 0; | ||
113 | msg = i2c->msg; | ||
114 | |||
115 | if (i2c->nmsgs) { /* end? */ | ||
116 | /* send start? */ | ||
117 | if (!(msg->flags & I2C_M_NOSTART)) { | ||
118 | u8 addr = (msg->addr << 1); | ||
119 | |||
120 | if (msg->flags & I2C_M_RD) | ||
121 | addr |= 1; | ||
122 | |||
123 | i2c->state = STATE_START; | ||
124 | |||
125 | oc_setreg(i2c, OCI2C_DATA, addr); | ||
126 | oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START); | ||
127 | return; | ||
128 | } else | ||
129 | i2c->state = (msg->flags & I2C_M_RD) | ||
130 | ? STATE_READ : STATE_WRITE; | ||
131 | } else { | ||
132 | i2c->state = STATE_DONE; | ||
133 | oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP); | ||
134 | return; | ||
135 | } | ||
136 | } | ||
137 | |||
138 | if (i2c->state == STATE_READ) { | ||
139 | oc_setreg(i2c, OCI2C_CMD, i2c->pos == (msg->len-1) ? | ||
140 | OCI2C_CMD_READ_NACK : OCI2C_CMD_READ_ACK); | ||
141 | } else { | ||
142 | oc_setreg(i2c, OCI2C_DATA, msg->buf[i2c->pos++]); | ||
143 | oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_WRITE); | ||
144 | } | ||
145 | } | ||
146 | |||
147 | static irqreturn_t ocores_isr(int irq, void *dev_id, struct pt_regs *regs) | ||
148 | { | ||
149 | struct ocores_i2c *i2c = dev_id; | ||
150 | |||
151 | ocores_process(i2c); | ||
152 | |||
153 | return IRQ_HANDLED; | ||
154 | } | ||
155 | |||
156 | static int ocores_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) | ||
157 | { | ||
158 | struct ocores_i2c *i2c = i2c_get_adapdata(adap); | ||
159 | |||
160 | i2c->msg = msgs; | ||
161 | i2c->pos = 0; | ||
162 | i2c->nmsgs = num; | ||
163 | i2c->state = STATE_START; | ||
164 | |||
165 | oc_setreg(i2c, OCI2C_DATA, | ||
166 | (i2c->msg->addr << 1) | | ||
167 | ((i2c->msg->flags & I2C_M_RD) ? 1:0)); | ||
168 | |||
169 | oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START); | ||
170 | |||
171 | if (wait_event_timeout(i2c->wait, (i2c->state == STATE_ERROR) || | ||
172 | (i2c->state == STATE_DONE), HZ)) | ||
173 | return (i2c->state == STATE_DONE) ? num : -EIO; | ||
174 | else | ||
175 | return -ETIMEDOUT; | ||
176 | } | ||
177 | |||
178 | static void ocores_init(struct ocores_i2c *i2c, | ||
179 | struct ocores_i2c_platform_data *pdata) | ||
180 | { | ||
181 | int prescale; | ||
182 | u8 ctrl = oc_getreg(i2c, OCI2C_CONTROL); | ||
183 | |||
184 | /* make sure the device is disabled */ | ||
185 | oc_setreg(i2c, OCI2C_CONTROL, ctrl & ~(OCI2C_CTRL_EN|OCI2C_CTRL_IEN)); | ||
186 | |||
187 | prescale = (pdata->clock_khz / (5*100)) - 1; | ||
188 | oc_setreg(i2c, OCI2C_PRELOW, prescale & 0xff); | ||
189 | oc_setreg(i2c, OCI2C_PREHIGH, prescale >> 8); | ||
190 | |||
191 | /* Init the device */ | ||
192 | oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK); | ||
193 | oc_setreg(i2c, OCI2C_CONTROL, ctrl | OCI2C_CTRL_IEN | OCI2C_CTRL_EN); | ||
194 | } | ||
195 | |||
196 | |||
197 | static u32 ocores_func(struct i2c_adapter *adap) | ||
198 | { | ||
199 | return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; | ||
200 | } | ||
201 | |||
202 | static struct i2c_algorithm ocores_algorithm = { | ||
203 | .master_xfer = ocores_xfer, | ||
204 | .functionality = ocores_func, | ||
205 | }; | ||
206 | |||
207 | static struct i2c_adapter ocores_adapter = { | ||
208 | .owner = THIS_MODULE, | ||
209 | .name = "i2c-ocores", | ||
210 | .class = I2C_CLASS_HWMON, | ||
211 | .algo = &ocores_algorithm, | ||
212 | }; | ||
213 | |||
214 | |||
215 | static int __devinit ocores_i2c_probe(struct platform_device *pdev) | ||
216 | { | ||
217 | struct ocores_i2c *i2c; | ||
218 | struct ocores_i2c_platform_data *pdata; | ||
219 | struct resource *res, *res2; | ||
220 | int ret; | ||
221 | |||
222 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
223 | if (!res) | ||
224 | return -ENODEV; | ||
225 | |||
226 | res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | ||
227 | if (!res2) | ||
228 | return -ENODEV; | ||
229 | |||
230 | pdata = (struct ocores_i2c_platform_data*) pdev->dev.platform_data; | ||
231 | if (!pdata) | ||
232 | return -ENODEV; | ||
233 | |||
234 | i2c = kzalloc(sizeof(*i2c), GFP_KERNEL); | ||
235 | if (!i2c) | ||
236 | return -ENOMEM; | ||
237 | |||
238 | if (!request_mem_region(res->start, res->end - res->start + 1, | ||
239 | pdev->name)) { | ||
240 | dev_err(&pdev->dev, "Memory region busy\n"); | ||
241 | ret = -EBUSY; | ||
242 | goto request_mem_failed; | ||
243 | } | ||
244 | |||
245 | i2c->base = ioremap(res->start, res->end - res->start + 1); | ||
246 | if (!i2c->base) { | ||
247 | dev_err(&pdev->dev, "Unable to map registers\n"); | ||
248 | ret = -EIO; | ||
249 | goto map_failed; | ||
250 | } | ||
251 | |||
252 | i2c->regstep = pdata->regstep; | ||
253 | ocores_init(i2c, pdata); | ||
254 | |||
255 | init_waitqueue_head(&i2c->wait); | ||
256 | ret = request_irq(res2->start, ocores_isr, 0, pdev->name, i2c); | ||
257 | if (ret) { | ||
258 | dev_err(&pdev->dev, "Cannot claim IRQ\n"); | ||
259 | goto request_irq_failed; | ||
260 | } | ||
261 | |||
262 | /* hook up driver to tree */ | ||
263 | platform_set_drvdata(pdev, i2c); | ||
264 | i2c->adap = ocores_adapter; | ||
265 | i2c_set_adapdata(&i2c->adap, i2c); | ||
266 | i2c->adap.dev.parent = &pdev->dev; | ||
267 | |||
268 | /* add i2c adapter to i2c tree */ | ||
269 | ret = i2c_add_adapter(&i2c->adap); | ||
270 | if (ret) { | ||
271 | dev_err(&pdev->dev, "Failed to add adapter\n"); | ||
272 | goto add_adapter_failed; | ||
273 | } | ||
274 | |||
275 | return 0; | ||
276 | |||
277 | add_adapter_failed: | ||
278 | free_irq(res2->start, i2c); | ||
279 | request_irq_failed: | ||
280 | iounmap(i2c->base); | ||
281 | map_failed: | ||
282 | release_mem_region(res->start, res->end - res->start + 1); | ||
283 | request_mem_failed: | ||
284 | kfree(i2c); | ||
285 | |||
286 | return ret; | ||
287 | } | ||
288 | |||
289 | static int __devexit ocores_i2c_remove(struct platform_device* pdev) | ||
290 | { | ||
291 | struct ocores_i2c *i2c = platform_get_drvdata(pdev); | ||
292 | struct resource *res; | ||
293 | |||
294 | /* disable i2c logic */ | ||
295 | oc_setreg(i2c, OCI2C_CONTROL, oc_getreg(i2c, OCI2C_CONTROL) | ||
296 | & ~(OCI2C_CTRL_EN|OCI2C_CTRL_IEN)); | ||
297 | |||
298 | /* remove adapter & data */ | ||
299 | i2c_del_adapter(&i2c->adap); | ||
300 | platform_set_drvdata(pdev, NULL); | ||
301 | |||
302 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | ||
303 | if (res) | ||
304 | free_irq(res->start, i2c); | ||
305 | |||
306 | iounmap(i2c->base); | ||
307 | |||
308 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
309 | if (res) | ||
310 | release_mem_region(res->start, res->end - res->start + 1); | ||
311 | |||
312 | kfree(i2c); | ||
313 | |||
314 | return 0; | ||
315 | } | ||
316 | |||
317 | static struct platform_driver ocores_i2c_driver = { | ||
318 | .probe = ocores_i2c_probe, | ||
319 | .remove = __devexit_p(ocores_i2c_remove), | ||
320 | .driver = { | ||
321 | .owner = THIS_MODULE, | ||
322 | .name = "ocores-i2c", | ||
323 | }, | ||
324 | }; | ||
325 | |||
326 | static int __init ocores_i2c_init(void) | ||
327 | { | ||
328 | return platform_driver_register(&ocores_i2c_driver); | ||
329 | } | ||
330 | |||
331 | static void __exit ocores_i2c_exit(void) | ||
332 | { | ||
333 | platform_driver_unregister(&ocores_i2c_driver); | ||
334 | } | ||
335 | |||
336 | module_init(ocores_i2c_init); | ||
337 | module_exit(ocores_i2c_exit); | ||
338 | |||
339 | MODULE_AUTHOR("Peter Korsgaard <jacmet@sunsite.dk>"); | ||
340 | MODULE_DESCRIPTION("OpenCores I2C bus driver"); | ||
341 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index d9c7c00e71f9..8f2f65b793b9 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c | |||
@@ -102,13 +102,6 @@ MODULE_PARM_DESC(force_addr, | |||
102 | "Forcibly enable the PIIX4 at the given address. " | 102 | "Forcibly enable the PIIX4 at the given address. " |
103 | "EXTREMELY DANGEROUS!"); | 103 | "EXTREMELY DANGEROUS!"); |
104 | 104 | ||
105 | /* If fix_hstcfg is set to anything different from 0, we reset one of the | ||
106 | registers to be a valid value. */ | ||
107 | static int fix_hstcfg; | ||
108 | module_param (fix_hstcfg, int, 0); | ||
109 | MODULE_PARM_DESC(fix_hstcfg, | ||
110 | "Fix config register. Needed on some boards (Force CPCI735)."); | ||
111 | |||
112 | static int piix4_transaction(void); | 105 | static int piix4_transaction(void); |
113 | 106 | ||
114 | static unsigned short piix4_smba; | 107 | static unsigned short piix4_smba; |
@@ -137,7 +130,7 @@ static int __devinit piix4_setup(struct pci_dev *PIIX4_dev, | |||
137 | /* Don't access SMBus on IBM systems which get corrupted eeproms */ | 130 | /* Don't access SMBus on IBM systems which get corrupted eeproms */ |
138 | if (dmi_check_system(piix4_dmi_table) && | 131 | if (dmi_check_system(piix4_dmi_table) && |
139 | PIIX4_dev->vendor == PCI_VENDOR_ID_INTEL) { | 132 | PIIX4_dev->vendor == PCI_VENDOR_ID_INTEL) { |
140 | dev_err(&PIIX4_dev->dev, "IBM Laptop detected; this module " | 133 | dev_err(&PIIX4_dev->dev, "IBM system detected; this module " |
141 | "may corrupt your serial eeprom! Refusing to load " | 134 | "may corrupt your serial eeprom! Refusing to load " |
142 | "module!\n"); | 135 | "module!\n"); |
143 | return -EPERM; | 136 | return -EPERM; |
@@ -166,22 +159,6 @@ static int __devinit piix4_setup(struct pci_dev *PIIX4_dev, | |||
166 | 159 | ||
167 | pci_read_config_byte(PIIX4_dev, SMBHSTCFG, &temp); | 160 | pci_read_config_byte(PIIX4_dev, SMBHSTCFG, &temp); |
168 | 161 | ||
169 | /* Some BIOS will set up the chipset incorrectly and leave a register | ||
170 | in an undefined state (causing I2C to act very strangely). */ | ||
171 | if (temp & 0x02) { | ||
172 | if (fix_hstcfg) { | ||
173 | dev_info(&PIIX4_dev->dev, "Working around buggy BIOS " | ||
174 | "(I2C)\n"); | ||
175 | temp &= 0xfd; | ||
176 | pci_write_config_byte(PIIX4_dev, SMBHSTCFG, temp); | ||
177 | } else { | ||
178 | dev_info(&PIIX4_dev->dev, "Unusual config register " | ||
179 | "value\n"); | ||
180 | dev_info(&PIIX4_dev->dev, "Try using fix_hstcfg=1 if " | ||
181 | "you experience problems\n"); | ||
182 | } | ||
183 | } | ||
184 | |||
185 | /* If force_addr is set, we program the new address here. Just to make | 162 | /* If force_addr is set, we program the new address here. Just to make |
186 | sure, we disable the PIIX4 first. */ | 163 | sure, we disable the PIIX4 first. */ |
187 | if (force_addr) { | 164 | if (force_addr) { |
@@ -214,7 +191,7 @@ static int __devinit piix4_setup(struct pci_dev *PIIX4_dev, | |||
214 | } | 191 | } |
215 | } | 192 | } |
216 | 193 | ||
217 | if ((temp & 0x0E) == 8) | 194 | if (((temp & 0x0E) == 8) || ((temp & 0x0E) == 2)) |
218 | dev_dbg(&PIIX4_dev->dev, "Using Interrupt 9 for SMBus.\n"); | 195 | dev_dbg(&PIIX4_dev->dev, "Using Interrupt 9 for SMBus.\n"); |
219 | else if ((temp & 0x0E) == 0) | 196 | else if ((temp & 0x0E) == 0) |
220 | dev_dbg(&PIIX4_dev->dev, "Using Interrupt SMI# for SMBus.\n"); | 197 | dev_dbg(&PIIX4_dev->dev, "Using Interrupt SMI# for SMBus.\n"); |
@@ -413,6 +390,12 @@ static struct i2c_adapter piix4_adapter = { | |||
413 | static struct pci_device_id piix4_ids[] = { | 390 | static struct pci_device_id piix4_ids[] = { |
414 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3), | 391 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3), |
415 | .driver_data = 3 }, | 392 | .driver_data = 3 }, |
393 | { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP200_SMBUS), | ||
394 | .driver_data = 0 }, | ||
395 | { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP300_SMBUS), | ||
396 | .driver_data = 0 }, | ||
397 | { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS), | ||
398 | .driver_data = 0 }, | ||
416 | { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4), | 399 | { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4), |
417 | .driver_data = 0 }, | 400 | .driver_data = 0 }, |
418 | { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5), | 401 | { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5), |
diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c index 766cc969c4d0..22a3eda04166 100644 --- a/drivers/i2c/busses/scx200_acb.c +++ b/drivers/i2c/busses/scx200_acb.c | |||
@@ -33,7 +33,6 @@ | |||
33 | #include <linux/delay.h> | 33 | #include <linux/delay.h> |
34 | #include <linux/mutex.h> | 34 | #include <linux/mutex.h> |
35 | #include <asm/io.h> | 35 | #include <asm/io.h> |
36 | #include <asm/msr.h> | ||
37 | 36 | ||
38 | #include <linux/scx200.h> | 37 | #include <linux/scx200.h> |
39 | 38 | ||
@@ -85,6 +84,10 @@ struct scx200_acb_iface { | |||
85 | u8 *ptr; | 84 | u8 *ptr; |
86 | char needs_reset; | 85 | char needs_reset; |
87 | unsigned len; | 86 | unsigned len; |
87 | |||
88 | /* PCI device info */ | ||
89 | struct pci_dev *pdev; | ||
90 | int bar; | ||
88 | }; | 91 | }; |
89 | 92 | ||
90 | /* Register Definitions */ | 93 | /* Register Definitions */ |
@@ -381,7 +384,7 @@ static struct i2c_algorithm scx200_acb_algorithm = { | |||
381 | static struct scx200_acb_iface *scx200_acb_list; | 384 | static struct scx200_acb_iface *scx200_acb_list; |
382 | static DECLARE_MUTEX(scx200_acb_list_mutex); | 385 | static DECLARE_MUTEX(scx200_acb_list_mutex); |
383 | 386 | ||
384 | static int scx200_acb_probe(struct scx200_acb_iface *iface) | 387 | static __init int scx200_acb_probe(struct scx200_acb_iface *iface) |
385 | { | 388 | { |
386 | u8 val; | 389 | u8 val; |
387 | 390 | ||
@@ -417,17 +420,16 @@ static int scx200_acb_probe(struct scx200_acb_iface *iface) | |||
417 | return 0; | 420 | return 0; |
418 | } | 421 | } |
419 | 422 | ||
420 | static int __init scx200_acb_create(const char *text, int base, int index) | 423 | static __init struct scx200_acb_iface *scx200_create_iface(const char *text, |
424 | int index) | ||
421 | { | 425 | { |
422 | struct scx200_acb_iface *iface; | 426 | struct scx200_acb_iface *iface; |
423 | struct i2c_adapter *adapter; | 427 | struct i2c_adapter *adapter; |
424 | int rc; | ||
425 | 428 | ||
426 | iface = kzalloc(sizeof(*iface), GFP_KERNEL); | 429 | iface = kzalloc(sizeof(*iface), GFP_KERNEL); |
427 | if (!iface) { | 430 | if (!iface) { |
428 | printk(KERN_ERR NAME ": can't allocate memory\n"); | 431 | printk(KERN_ERR NAME ": can't allocate memory\n"); |
429 | rc = -ENOMEM; | 432 | return NULL; |
430 | goto errout; | ||
431 | } | 433 | } |
432 | 434 | ||
433 | adapter = &iface->adapter; | 435 | adapter = &iface->adapter; |
@@ -440,26 +442,27 @@ static int __init scx200_acb_create(const char *text, int base, int index) | |||
440 | 442 | ||
441 | mutex_init(&iface->mutex); | 443 | mutex_init(&iface->mutex); |
442 | 444 | ||
443 | if (!request_region(base, 8, adapter->name)) { | 445 | return iface; |
444 | printk(KERN_ERR NAME ": can't allocate io 0x%x-0x%x\n", | 446 | } |
445 | base, base + 8-1); | 447 | |
446 | rc = -EBUSY; | 448 | static int __init scx200_acb_create(struct scx200_acb_iface *iface) |
447 | goto errout_free; | 449 | { |
448 | } | 450 | struct i2c_adapter *adapter; |
449 | iface->base = base; | 451 | int rc; |
452 | |||
453 | adapter = &iface->adapter; | ||
450 | 454 | ||
451 | rc = scx200_acb_probe(iface); | 455 | rc = scx200_acb_probe(iface); |
452 | if (rc) { | 456 | if (rc) { |
453 | printk(KERN_WARNING NAME ": probe failed\n"); | 457 | printk(KERN_WARNING NAME ": probe failed\n"); |
454 | goto errout_release; | 458 | return rc; |
455 | } | 459 | } |
456 | 460 | ||
457 | scx200_acb_reset(iface); | 461 | scx200_acb_reset(iface); |
458 | 462 | ||
459 | if (i2c_add_adapter(adapter) < 0) { | 463 | if (i2c_add_adapter(adapter) < 0) { |
460 | printk(KERN_ERR NAME ": failed to register\n"); | 464 | printk(KERN_ERR NAME ": failed to register\n"); |
461 | rc = -ENODEV; | 465 | return -ENODEV; |
462 | goto errout_release; | ||
463 | } | 466 | } |
464 | 467 | ||
465 | down(&scx200_acb_list_mutex); | 468 | down(&scx200_acb_list_mutex); |
@@ -468,64 +471,148 @@ static int __init scx200_acb_create(const char *text, int base, int index) | |||
468 | up(&scx200_acb_list_mutex); | 471 | up(&scx200_acb_list_mutex); |
469 | 472 | ||
470 | return 0; | 473 | return 0; |
474 | } | ||
471 | 475 | ||
472 | errout_release: | 476 | static __init int scx200_create_pci(const char *text, struct pci_dev *pdev, |
473 | release_region(iface->base, 8); | 477 | int bar) |
478 | { | ||
479 | struct scx200_acb_iface *iface; | ||
480 | int rc; | ||
481 | |||
482 | iface = scx200_create_iface(text, 0); | ||
483 | |||
484 | if (iface == NULL) | ||
485 | return -ENOMEM; | ||
486 | |||
487 | iface->pdev = pdev; | ||
488 | iface->bar = bar; | ||
489 | |||
490 | pci_enable_device_bars(iface->pdev, 1 << iface->bar); | ||
491 | |||
492 | rc = pci_request_region(iface->pdev, iface->bar, iface->adapter.name); | ||
493 | |||
494 | if (rc != 0) { | ||
495 | printk(KERN_ERR NAME ": can't allocate PCI BAR %d\n", | ||
496 | iface->bar); | ||
497 | goto errout_free; | ||
498 | } | ||
499 | |||
500 | iface->base = pci_resource_start(iface->pdev, iface->bar); | ||
501 | rc = scx200_acb_create(iface); | ||
502 | |||
503 | if (rc == 0) | ||
504 | return 0; | ||
505 | |||
506 | pci_release_region(iface->pdev, iface->bar); | ||
507 | pci_dev_put(iface->pdev); | ||
474 | errout_free: | 508 | errout_free: |
475 | kfree(iface); | 509 | kfree(iface); |
476 | errout: | ||
477 | return rc; | 510 | return rc; |
478 | } | 511 | } |
479 | 512 | ||
480 | static struct pci_device_id scx200[] = { | 513 | static int __init scx200_create_isa(const char *text, unsigned long base, |
481 | { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE) }, | 514 | int index) |
482 | { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE) }, | 515 | { |
483 | { }, | 516 | struct scx200_acb_iface *iface; |
484 | }; | 517 | int rc; |
518 | |||
519 | iface = scx200_create_iface(text, index); | ||
520 | |||
521 | if (iface == NULL) | ||
522 | return -ENOMEM; | ||
523 | |||
524 | if (request_region(base, 8, iface->adapter.name) == 0) { | ||
525 | printk(KERN_ERR NAME ": can't allocate io 0x%lx-0x%lx\n", | ||
526 | base, base + 8 - 1); | ||
527 | rc = -EBUSY; | ||
528 | goto errout_free; | ||
529 | } | ||
530 | |||
531 | iface->base = base; | ||
532 | rc = scx200_acb_create(iface); | ||
533 | |||
534 | if (rc == 0) | ||
535 | return 0; | ||
485 | 536 | ||
486 | static struct pci_device_id divil_pci[] = { | 537 | release_region(base, 8); |
487 | { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA) }, | 538 | errout_free: |
488 | { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) }, | 539 | kfree(iface); |
489 | { } /* NULL entry */ | 540 | return rc; |
541 | } | ||
542 | |||
543 | /* Driver data is an index into the scx200_data array that indicates | ||
544 | * the name and the BAR where the I/O address resource is located. ISA | ||
545 | * devices are flagged with a bar value of -1 */ | ||
546 | |||
547 | static struct pci_device_id scx200_pci[] = { | ||
548 | { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE), | ||
549 | .driver_data = 0 }, | ||
550 | { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE), | ||
551 | .driver_data = 0 }, | ||
552 | { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA), | ||
553 | .driver_data = 1 }, | ||
554 | { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA), | ||
555 | .driver_data = 2 } | ||
490 | }; | 556 | }; |
491 | 557 | ||
492 | #define MSR_LBAR_SMB 0x5140000B | 558 | static struct { |
559 | const char *name; | ||
560 | int bar; | ||
561 | } scx200_data[] = { | ||
562 | { "SCx200", -1 }, | ||
563 | { "CS5535", 0 }, | ||
564 | { "CS5536", 0 } | ||
565 | }; | ||
493 | 566 | ||
494 | static __init int scx200_add_cs553x(void) | 567 | static __init int scx200_scan_pci(void) |
495 | { | 568 | { |
496 | u32 low, hi; | 569 | int data, dev; |
497 | u32 smb_base; | 570 | int rc = -ENODEV; |
498 | 571 | struct pci_dev *pdev; | |
499 | /* Grab & reserve the SMB I/O range */ | 572 | |
500 | rdmsr(MSR_LBAR_SMB, low, hi); | 573 | for(dev = 0; dev < ARRAY_SIZE(scx200_pci); dev++) { |
574 | pdev = pci_get_device(scx200_pci[dev].vendor, | ||
575 | scx200_pci[dev].device, NULL); | ||
576 | |||
577 | if (pdev == NULL) | ||
578 | continue; | ||
579 | |||
580 | data = scx200_pci[dev].driver_data; | ||
581 | |||
582 | /* if .bar is greater or equal to zero, this is a | ||
583 | * PCI device - otherwise, we assume | ||
584 | that the ports are ISA based | ||
585 | */ | ||
586 | |||
587 | if (scx200_data[data].bar >= 0) | ||
588 | rc = scx200_create_pci(scx200_data[data].name, pdev, | ||
589 | scx200_data[data].bar); | ||
590 | else { | ||
591 | int i; | ||
592 | |||
593 | for (i = 0; i < MAX_DEVICES; ++i) { | ||
594 | if (base[i] == 0) | ||
595 | continue; | ||
596 | |||
597 | rc = scx200_create_isa(scx200_data[data].name, | ||
598 | base[i], | ||
599 | i); | ||
600 | } | ||
601 | } | ||
501 | 602 | ||
502 | /* Check the IO mask and whether SMB is enabled */ | 603 | break; |
503 | if (hi != 0x0000F001) { | ||
504 | printk(KERN_WARNING NAME ": SMBus not enabled\n"); | ||
505 | return -ENODEV; | ||
506 | } | 604 | } |
507 | 605 | ||
508 | /* SMBus IO size is 8 bytes */ | 606 | return rc; |
509 | smb_base = low & 0x0000FFF8; | ||
510 | |||
511 | return scx200_acb_create("CS5535", smb_base, 0); | ||
512 | } | 607 | } |
513 | 608 | ||
514 | static int __init scx200_acb_init(void) | 609 | static int __init scx200_acb_init(void) |
515 | { | 610 | { |
516 | int i; | 611 | int rc; |
517 | int rc = -ENODEV; | ||
518 | 612 | ||
519 | pr_debug(NAME ": NatSemi SCx200 ACCESS.bus Driver\n"); | 613 | pr_debug(NAME ": NatSemi SCx200 ACCESS.bus Driver\n"); |
520 | 614 | ||
521 | /* Verify that this really is a SCx200 processor */ | 615 | rc = scx200_scan_pci(); |
522 | if (pci_dev_present(scx200)) { | ||
523 | for (i = 0; i < MAX_DEVICES; ++i) { | ||
524 | if (base[i] > 0) | ||
525 | rc = scx200_acb_create("SCx200", base[i], i); | ||
526 | } | ||
527 | } else if (pci_dev_present(divil_pci)) | ||
528 | rc = scx200_add_cs553x(); | ||
529 | 616 | ||
530 | /* If at least one bus was created, init must succeed */ | 617 | /* If at least one bus was created, init must succeed */ |
531 | if (scx200_acb_list) | 618 | if (scx200_acb_list) |
@@ -543,7 +630,14 @@ static void __exit scx200_acb_cleanup(void) | |||
543 | up(&scx200_acb_list_mutex); | 630 | up(&scx200_acb_list_mutex); |
544 | 631 | ||
545 | i2c_del_adapter(&iface->adapter); | 632 | i2c_del_adapter(&iface->adapter); |
546 | release_region(iface->base, 8); | 633 | |
634 | if (iface->pdev) { | ||
635 | pci_release_region(iface->pdev, iface->bar); | ||
636 | pci_dev_put(iface->pdev); | ||
637 | } | ||
638 | else | ||
639 | release_region(iface->base, 8); | ||
640 | |||
547 | kfree(iface); | 641 | kfree(iface); |
548 | down(&scx200_acb_list_mutex); | 642 | down(&scx200_acb_list_mutex); |
549 | } | 643 | } |
diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index 7aa5c38f0855..87ee3ce58618 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig | |||
@@ -39,6 +39,7 @@ config SENSORS_EEPROM | |||
39 | config SENSORS_PCF8574 | 39 | config SENSORS_PCF8574 |
40 | tristate "Philips PCF8574 and PCF8574A" | 40 | tristate "Philips PCF8574 and PCF8574A" |
41 | depends on I2C && EXPERIMENTAL | 41 | depends on I2C && EXPERIMENTAL |
42 | default n | ||
42 | help | 43 | help |
43 | If you say yes here you get support for Philips PCF8574 and | 44 | If you say yes here you get support for Philips PCF8574 and |
44 | PCF8574A chips. | 45 | PCF8574A chips. |
@@ -46,6 +47,9 @@ config SENSORS_PCF8574 | |||
46 | This driver can also be built as a module. If so, the module | 47 | This driver can also be built as a module. If so, the module |
47 | will be called pcf8574. | 48 | will be called pcf8574. |
48 | 49 | ||
50 | These devices are hard to detect and rarely found on mainstream | ||
51 | hardware. If unsure, say N. | ||
52 | |||
49 | config SENSORS_PCA9539 | 53 | config SENSORS_PCA9539 |
50 | tristate "Philips PCA9539 16-bit I/O port" | 54 | tristate "Philips PCA9539 16-bit I/O port" |
51 | depends on I2C && EXPERIMENTAL | 55 | depends on I2C && EXPERIMENTAL |
@@ -59,12 +63,16 @@ config SENSORS_PCA9539 | |||
59 | config SENSORS_PCF8591 | 63 | config SENSORS_PCF8591 |
60 | tristate "Philips PCF8591" | 64 | tristate "Philips PCF8591" |
61 | depends on I2C && EXPERIMENTAL | 65 | depends on I2C && EXPERIMENTAL |
66 | default n | ||
62 | help | 67 | help |
63 | If you say yes here you get support for Philips PCF8591 chips. | 68 | If you say yes here you get support for Philips PCF8591 chips. |
64 | 69 | ||
65 | This driver can also be built as a module. If so, the module | 70 | This driver can also be built as a module. If so, the module |
66 | will be called pcf8591. | 71 | will be called pcf8591. |
67 | 72 | ||
73 | These devices are hard to detect and rarely found on mainstream | ||
74 | hardware. If unsure, say N. | ||
75 | |||
68 | config ISP1301_OMAP | 76 | config ISP1301_OMAP |
69 | tristate "Philips ISP1301 with OMAP OTG" | 77 | tristate "Philips ISP1301 with OMAP OTG" |
70 | depends on I2C && ARCH_OMAP_OTG | 78 | depends on I2C && ARCH_OMAP_OTG |
diff --git a/drivers/i2c/chips/m41t00.c b/drivers/i2c/chips/m41t00.c index 99ab4ec34390..2dd0a34d9472 100644 --- a/drivers/i2c/chips/m41t00.c +++ b/drivers/i2c/chips/m41t00.c | |||
@@ -1,11 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/i2c/chips/m41t00.c | 2 | * I2C client/driver for the ST M41T00 family of i2c rtc chips. |
3 | * | ||
4 | * I2C client/driver for the ST M41T00 Real-Time Clock chip. | ||
5 | * | 3 | * |
6 | * Author: Mark A. Greer <mgreer@mvista.com> | 4 | * Author: Mark A. Greer <mgreer@mvista.com> |
7 | * | 5 | * |
8 | * 2005 (c) MontaVista Software, Inc. This file is licensed under | 6 | * 2005, 2006 (c) MontaVista Software, Inc. This file is licensed under |
9 | * the terms of the GNU General Public License version 2. This program | 7 | * the terms of the GNU General Public License version 2. This program |
10 | * is licensed "as is" without any warranty of any kind, whether express | 8 | * is licensed "as is" without any warranty of any kind, whether express |
11 | * or implied. | 9 | * or implied. |
@@ -13,9 +11,6 @@ | |||
13 | /* | 11 | /* |
14 | * This i2c client/driver wedges between the drivers/char/genrtc.c RTC | 12 | * This i2c client/driver wedges between the drivers/char/genrtc.c RTC |
15 | * interface and the SMBus interface of the i2c subsystem. | 13 | * interface and the SMBus interface of the i2c subsystem. |
16 | * It would be more efficient to use i2c msgs/i2c_transfer directly but, as | ||
17 | * recommened in .../Documentation/i2c/writing-clients section | ||
18 | * "Sending and receiving", using SMBus level communication is preferred. | ||
19 | */ | 14 | */ |
20 | 15 | ||
21 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
@@ -24,56 +19,110 @@ | |||
24 | #include <linux/i2c.h> | 19 | #include <linux/i2c.h> |
25 | #include <linux/rtc.h> | 20 | #include <linux/rtc.h> |
26 | #include <linux/bcd.h> | 21 | #include <linux/bcd.h> |
27 | #include <linux/mutex.h> | ||
28 | #include <linux/workqueue.h> | 22 | #include <linux/workqueue.h> |
29 | 23 | #include <linux/platform_device.h> | |
24 | #include <linux/m41t00.h> | ||
30 | #include <asm/time.h> | 25 | #include <asm/time.h> |
31 | #include <asm/rtc.h> | 26 | #include <asm/rtc.h> |
32 | 27 | ||
33 | #define M41T00_DRV_NAME "m41t00" | ||
34 | |||
35 | static DEFINE_MUTEX(m41t00_mutex); | ||
36 | |||
37 | static struct i2c_driver m41t00_driver; | 28 | static struct i2c_driver m41t00_driver; |
38 | static struct i2c_client *save_client; | 29 | static struct i2c_client *save_client; |
39 | 30 | ||
40 | static unsigned short ignore[] = { I2C_CLIENT_END }; | 31 | static unsigned short ignore[] = { I2C_CLIENT_END }; |
41 | static unsigned short normal_addr[] = { 0x68, I2C_CLIENT_END }; | 32 | static unsigned short normal_addr[] = { I2C_CLIENT_END, I2C_CLIENT_END }; |
42 | 33 | ||
43 | static struct i2c_client_address_data addr_data = { | 34 | static struct i2c_client_address_data addr_data = { |
44 | .normal_i2c = normal_addr, | 35 | .normal_i2c = normal_addr, |
45 | .probe = ignore, | 36 | .probe = ignore, |
46 | .ignore = ignore, | 37 | .ignore = ignore, |
38 | }; | ||
39 | |||
40 | struct m41t00_chip_info { | ||
41 | u8 type; | ||
42 | char *name; | ||
43 | u8 read_limit; | ||
44 | u8 sec; /* Offsets for chip regs */ | ||
45 | u8 min; | ||
46 | u8 hour; | ||
47 | u8 day; | ||
48 | u8 mon; | ||
49 | u8 year; | ||
50 | u8 alarm_mon; | ||
51 | u8 alarm_hour; | ||
52 | u8 sqw; | ||
53 | u8 sqw_freq; | ||
47 | }; | 54 | }; |
48 | 55 | ||
56 | static struct m41t00_chip_info m41t00_chip_info_tbl[] = { | ||
57 | { | ||
58 | .type = M41T00_TYPE_M41T00, | ||
59 | .name = "m41t00", | ||
60 | .read_limit = 5, | ||
61 | .sec = 0, | ||
62 | .min = 1, | ||
63 | .hour = 2, | ||
64 | .day = 4, | ||
65 | .mon = 5, | ||
66 | .year = 6, | ||
67 | }, | ||
68 | { | ||
69 | .type = M41T00_TYPE_M41T81, | ||
70 | .name = "m41t81", | ||
71 | .read_limit = 1, | ||
72 | .sec = 1, | ||
73 | .min = 2, | ||
74 | .hour = 3, | ||
75 | .day = 5, | ||
76 | .mon = 6, | ||
77 | .year = 7, | ||
78 | .alarm_mon = 0xa, | ||
79 | .alarm_hour = 0xc, | ||
80 | .sqw = 0x13, | ||
81 | }, | ||
82 | { | ||
83 | .type = M41T00_TYPE_M41T85, | ||
84 | .name = "m41t85", | ||
85 | .read_limit = 1, | ||
86 | .sec = 1, | ||
87 | .min = 2, | ||
88 | .hour = 3, | ||
89 | .day = 5, | ||
90 | .mon = 6, | ||
91 | .year = 7, | ||
92 | .alarm_mon = 0xa, | ||
93 | .alarm_hour = 0xc, | ||
94 | .sqw = 0x13, | ||
95 | }, | ||
96 | }; | ||
97 | static struct m41t00_chip_info *m41t00_chip; | ||
98 | |||
49 | ulong | 99 | ulong |
50 | m41t00_get_rtc_time(void) | 100 | m41t00_get_rtc_time(void) |
51 | { | 101 | { |
52 | s32 sec, min, hour, day, mon, year; | 102 | s32 sec, min, hour, day, mon, year; |
53 | s32 sec1, min1, hour1, day1, mon1, year1; | 103 | s32 sec1, min1, hour1, day1, mon1, year1; |
54 | ulong limit = 10; | 104 | u8 reads = 0; |
105 | u8 buf[8], msgbuf[1] = { 0 }; /* offset into rtc's regs */ | ||
106 | struct i2c_msg msgs[] = { | ||
107 | { | ||
108 | .addr = save_client->addr, | ||
109 | .flags = 0, | ||
110 | .len = 1, | ||
111 | .buf = msgbuf, | ||
112 | }, | ||
113 | { | ||
114 | .addr = save_client->addr, | ||
115 | .flags = I2C_M_RD, | ||
116 | .len = 8, | ||
117 | .buf = buf, | ||
118 | }, | ||
119 | }; | ||
55 | 120 | ||
56 | sec = min = hour = day = mon = year = 0; | 121 | sec = min = hour = day = mon = year = 0; |
57 | sec1 = min1 = hour1 = day1 = mon1 = year1 = 0; | ||
58 | 122 | ||
59 | mutex_lock(&m41t00_mutex); | ||
60 | do { | 123 | do { |
61 | if (((sec = i2c_smbus_read_byte_data(save_client, 0)) >= 0) | 124 | if (i2c_transfer(save_client->adapter, msgs, 2) < 0) |
62 | && ((min = i2c_smbus_read_byte_data(save_client, 1)) | 125 | goto read_err; |
63 | >= 0) | ||
64 | && ((hour = i2c_smbus_read_byte_data(save_client, 2)) | ||
65 | >= 0) | ||
66 | && ((day = i2c_smbus_read_byte_data(save_client, 4)) | ||
67 | >= 0) | ||
68 | && ((mon = i2c_smbus_read_byte_data(save_client, 5)) | ||
69 | >= 0) | ||
70 | && ((year = i2c_smbus_read_byte_data(save_client, 6)) | ||
71 | >= 0) | ||
72 | && ((sec == sec1) && (min == min1) && (hour == hour1) | ||
73 | && (day == day1) && (mon == mon1) | ||
74 | && (year == year1))) | ||
75 | |||
76 | break; | ||
77 | 126 | ||
78 | sec1 = sec; | 127 | sec1 = sec; |
79 | min1 = min; | 128 | min1 = min; |
@@ -81,69 +130,88 @@ m41t00_get_rtc_time(void) | |||
81 | day1 = day; | 130 | day1 = day; |
82 | mon1 = mon; | 131 | mon1 = mon; |
83 | year1 = year; | 132 | year1 = year; |
84 | } while (--limit > 0); | ||
85 | mutex_unlock(&m41t00_mutex); | ||
86 | |||
87 | if (limit == 0) { | ||
88 | dev_warn(&save_client->dev, | ||
89 | "m41t00: can't read rtc chip\n"); | ||
90 | sec = min = hour = day = mon = year = 0; | ||
91 | } | ||
92 | |||
93 | sec &= 0x7f; | ||
94 | min &= 0x7f; | ||
95 | hour &= 0x3f; | ||
96 | day &= 0x3f; | ||
97 | mon &= 0x1f; | ||
98 | year &= 0xff; | ||
99 | 133 | ||
100 | BCD_TO_BIN(sec); | 134 | sec = buf[m41t00_chip->sec] & 0x7f; |
101 | BCD_TO_BIN(min); | 135 | min = buf[m41t00_chip->min] & 0x7f; |
102 | BCD_TO_BIN(hour); | 136 | hour = buf[m41t00_chip->hour] & 0x3f; |
103 | BCD_TO_BIN(day); | 137 | day = buf[m41t00_chip->day] & 0x3f; |
104 | BCD_TO_BIN(mon); | 138 | mon = buf[m41t00_chip->mon] & 0x1f; |
105 | BCD_TO_BIN(year); | 139 | year = buf[m41t00_chip->year]; |
140 | } while ((++reads < m41t00_chip->read_limit) && ((sec != sec1) | ||
141 | || (min != min1) || (hour != hour1) || (day != day1) | ||
142 | || (mon != mon1) || (year != year1))); | ||
143 | |||
144 | if ((m41t00_chip->read_limit > 1) && ((sec != sec1) || (min != min1) | ||
145 | || (hour != hour1) || (day != day1) || (mon != mon1) | ||
146 | || (year != year1))) | ||
147 | goto read_err; | ||
148 | |||
149 | sec = BCD2BIN(sec); | ||
150 | min = BCD2BIN(min); | ||
151 | hour = BCD2BIN(hour); | ||
152 | day = BCD2BIN(day); | ||
153 | mon = BCD2BIN(mon); | ||
154 | year = BCD2BIN(year); | ||
106 | 155 | ||
107 | year += 1900; | 156 | year += 1900; |
108 | if (year < 1970) | 157 | if (year < 1970) |
109 | year += 100; | 158 | year += 100; |
110 | 159 | ||
111 | return mktime(year, mon, day, hour, min, sec); | 160 | return mktime(year, mon, day, hour, min, sec); |
161 | |||
162 | read_err: | ||
163 | dev_err(&save_client->dev, "m41t00_get_rtc_time: Read error\n"); | ||
164 | return 0; | ||
112 | } | 165 | } |
166 | EXPORT_SYMBOL_GPL(m41t00_get_rtc_time); | ||
113 | 167 | ||
114 | static void | 168 | static void |
115 | m41t00_set(void *arg) | 169 | m41t00_set(void *arg) |
116 | { | 170 | { |
117 | struct rtc_time tm; | 171 | struct rtc_time tm; |
118 | ulong nowtime = *(ulong *)arg; | 172 | int nowtime = *(int *)arg; |
173 | s32 sec, min, hour, day, mon, year; | ||
174 | u8 wbuf[9], *buf = &wbuf[1], msgbuf[1] = { 0 }; | ||
175 | struct i2c_msg msgs[] = { | ||
176 | { | ||
177 | .addr = save_client->addr, | ||
178 | .flags = 0, | ||
179 | .len = 1, | ||
180 | .buf = msgbuf, | ||
181 | }, | ||
182 | { | ||
183 | .addr = save_client->addr, | ||
184 | .flags = I2C_M_RD, | ||
185 | .len = 8, | ||
186 | .buf = buf, | ||
187 | }, | ||
188 | }; | ||
119 | 189 | ||
120 | to_tm(nowtime, &tm); | 190 | to_tm(nowtime, &tm); |
121 | tm.tm_year = (tm.tm_year - 1900) % 100; | 191 | tm.tm_year = (tm.tm_year - 1900) % 100; |
122 | 192 | ||
123 | BIN_TO_BCD(tm.tm_sec); | 193 | sec = BIN2BCD(tm.tm_sec); |
124 | BIN_TO_BCD(tm.tm_min); | 194 | min = BIN2BCD(tm.tm_min); |
125 | BIN_TO_BCD(tm.tm_hour); | 195 | hour = BIN2BCD(tm.tm_hour); |
126 | BIN_TO_BCD(tm.tm_mon); | 196 | day = BIN2BCD(tm.tm_mday); |
127 | BIN_TO_BCD(tm.tm_mday); | 197 | mon = BIN2BCD(tm.tm_mon); |
128 | BIN_TO_BCD(tm.tm_year); | 198 | year = BIN2BCD(tm.tm_year); |
129 | 199 | ||
130 | mutex_lock(&m41t00_mutex); | 200 | /* Read reg values into buf[0..7]/wbuf[1..8] */ |
131 | if ((i2c_smbus_write_byte_data(save_client, 0, tm.tm_sec & 0x7f) < 0) | 201 | if (i2c_transfer(save_client->adapter, msgs, 2) < 0) { |
132 | || (i2c_smbus_write_byte_data(save_client, 1, tm.tm_min & 0x7f) | 202 | dev_err(&save_client->dev, "m41t00_set: Read error\n"); |
133 | < 0) | 203 | return; |
134 | || (i2c_smbus_write_byte_data(save_client, 2, tm.tm_hour & 0x3f) | 204 | } |
135 | < 0) | 205 | |
136 | || (i2c_smbus_write_byte_data(save_client, 4, tm.tm_mday & 0x3f) | 206 | wbuf[0] = 0; /* offset into rtc's regs */ |
137 | < 0) | 207 | buf[m41t00_chip->sec] = (buf[m41t00_chip->sec] & ~0x7f) | (sec & 0x7f); |
138 | || (i2c_smbus_write_byte_data(save_client, 5, tm.tm_mon & 0x1f) | 208 | buf[m41t00_chip->min] = (buf[m41t00_chip->min] & ~0x7f) | (min & 0x7f); |
139 | < 0) | 209 | buf[m41t00_chip->hour] = (buf[m41t00_chip->hour] & ~0x3f) | (hour& 0x3f); |
140 | || (i2c_smbus_write_byte_data(save_client, 6, tm.tm_year & 0xff) | 210 | buf[m41t00_chip->day] = (buf[m41t00_chip->day] & ~0x3f) | (day & 0x3f); |
141 | < 0)) | 211 | buf[m41t00_chip->mon] = (buf[m41t00_chip->mon] & ~0x1f) | (mon & 0x1f); |
142 | 212 | ||
143 | dev_warn(&save_client->dev,"m41t00: can't write to rtc chip\n"); | 213 | if (i2c_master_send(save_client, wbuf, 9) < 0) |
144 | 214 | dev_err(&save_client->dev, "m41t00_set: Write error\n"); | |
145 | mutex_unlock(&m41t00_mutex); | ||
146 | return; | ||
147 | } | 215 | } |
148 | 216 | ||
149 | static ulong new_time; | 217 | static ulong new_time; |
@@ -162,6 +230,48 @@ m41t00_set_rtc_time(ulong nowtime) | |||
162 | 230 | ||
163 | return 0; | 231 | return 0; |
164 | } | 232 | } |
233 | EXPORT_SYMBOL_GPL(m41t00_set_rtc_time); | ||
234 | |||
235 | /* | ||
236 | ***************************************************************************** | ||
237 | * | ||
238 | * platform_data Driver Interface | ||
239 | * | ||
240 | ***************************************************************************** | ||
241 | */ | ||
242 | static int __init | ||
243 | m41t00_platform_probe(struct platform_device *pdev) | ||
244 | { | ||
245 | struct m41t00_platform_data *pdata; | ||
246 | int i; | ||
247 | |||
248 | if (pdev && (pdata = pdev->dev.platform_data)) { | ||
249 | normal_addr[0] = pdata->i2c_addr; | ||
250 | |||
251 | for (i=0; i<ARRAY_SIZE(m41t00_chip_info_tbl); i++) | ||
252 | if (m41t00_chip_info_tbl[i].type == pdata->type) { | ||
253 | m41t00_chip = &m41t00_chip_info_tbl[i]; | ||
254 | m41t00_chip->sqw_freq = pdata->sqw_freq; | ||
255 | return 0; | ||
256 | } | ||
257 | } | ||
258 | return -ENODEV; | ||
259 | } | ||
260 | |||
261 | static int __exit | ||
262 | m41t00_platform_remove(struct platform_device *pdev) | ||
263 | { | ||
264 | return 0; | ||
265 | } | ||
266 | |||
267 | static struct platform_driver m41t00_platform_driver = { | ||
268 | .probe = m41t00_platform_probe, | ||
269 | .remove = m41t00_platform_remove, | ||
270 | .driver = { | ||
271 | .owner = THIS_MODULE, | ||
272 | .name = M41T00_DRV_NAME, | ||
273 | }, | ||
274 | }; | ||
165 | 275 | ||
166 | /* | 276 | /* |
167 | ***************************************************************************** | 277 | ***************************************************************************** |
@@ -176,23 +286,71 @@ m41t00_probe(struct i2c_adapter *adap, int addr, int kind) | |||
176 | struct i2c_client *client; | 286 | struct i2c_client *client; |
177 | int rc; | 287 | int rc; |
178 | 288 | ||
289 | if (!i2c_check_functionality(adap, I2C_FUNC_I2C | ||
290 | | I2C_FUNC_SMBUS_BYTE_DATA)) | ||
291 | return 0; | ||
292 | |||
179 | client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); | 293 | client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); |
180 | if (!client) | 294 | if (!client) |
181 | return -ENOMEM; | 295 | return -ENOMEM; |
182 | 296 | ||
183 | strncpy(client->name, M41T00_DRV_NAME, I2C_NAME_SIZE); | 297 | strlcpy(client->name, m41t00_chip->name, I2C_NAME_SIZE); |
184 | client->addr = addr; | 298 | client->addr = addr; |
185 | client->adapter = adap; | 299 | client->adapter = adap; |
186 | client->driver = &m41t00_driver; | 300 | client->driver = &m41t00_driver; |
187 | 301 | ||
188 | if ((rc = i2c_attach_client(client)) != 0) { | 302 | if ((rc = i2c_attach_client(client))) |
189 | kfree(client); | 303 | goto attach_err; |
190 | return rc; | 304 | |
305 | if (m41t00_chip->type != M41T00_TYPE_M41T00) { | ||
306 | /* If asked, disable SQW, set SQW frequency & re-enable */ | ||
307 | if (m41t00_chip->sqw_freq) | ||
308 | if (((rc = i2c_smbus_read_byte_data(client, | ||
309 | m41t00_chip->alarm_mon)) < 0) | ||
310 | || ((rc = i2c_smbus_write_byte_data(client, | ||
311 | m41t00_chip->alarm_mon, rc & ~0x40)) <0) | ||
312 | || ((rc = i2c_smbus_write_byte_data(client, | ||
313 | m41t00_chip->sqw, | ||
314 | m41t00_chip->sqw_freq)) < 0) | ||
315 | || ((rc = i2c_smbus_write_byte_data(client, | ||
316 | m41t00_chip->alarm_mon, rc | 0x40)) <0)) | ||
317 | goto sqw_err; | ||
318 | |||
319 | /* Make sure HT (Halt Update) bit is cleared */ | ||
320 | if ((rc = i2c_smbus_read_byte_data(client, | ||
321 | m41t00_chip->alarm_hour)) < 0) | ||
322 | goto ht_err; | ||
323 | |||
324 | if (rc & 0x40) | ||
325 | if ((rc = i2c_smbus_write_byte_data(client, | ||
326 | m41t00_chip->alarm_hour, rc & ~0x40))<0) | ||
327 | goto ht_err; | ||
191 | } | 328 | } |
192 | 329 | ||
193 | m41t00_wq = create_singlethread_workqueue("m41t00"); | 330 | /* Make sure ST (stop) bit is cleared */ |
331 | if ((rc = i2c_smbus_read_byte_data(client, m41t00_chip->sec)) < 0) | ||
332 | goto st_err; | ||
333 | |||
334 | if (rc & 0x80) | ||
335 | if ((rc = i2c_smbus_write_byte_data(client, m41t00_chip->sec, | ||
336 | rc & ~0x80)) < 0) | ||
337 | goto st_err; | ||
338 | |||
339 | m41t00_wq = create_singlethread_workqueue(m41t00_chip->name); | ||
194 | save_client = client; | 340 | save_client = client; |
195 | return 0; | 341 | return 0; |
342 | |||
343 | st_err: | ||
344 | dev_err(&client->dev, "m41t00_probe: Can't clear ST bit\n"); | ||
345 | goto attach_err; | ||
346 | ht_err: | ||
347 | dev_err(&client->dev, "m41t00_probe: Can't clear HT bit\n"); | ||
348 | goto attach_err; | ||
349 | sqw_err: | ||
350 | dev_err(&client->dev, "m41t00_probe: Can't set SQW Frequency\n"); | ||
351 | attach_err: | ||
352 | kfree(client); | ||
353 | return rc; | ||
196 | } | 354 | } |
197 | 355 | ||
198 | static int | 356 | static int |
@@ -204,7 +362,7 @@ m41t00_attach(struct i2c_adapter *adap) | |||
204 | static int | 362 | static int |
205 | m41t00_detach(struct i2c_client *client) | 363 | m41t00_detach(struct i2c_client *client) |
206 | { | 364 | { |
207 | int rc; | 365 | int rc; |
208 | 366 | ||
209 | if ((rc = i2c_detach_client(client)) == 0) { | 367 | if ((rc = i2c_detach_client(client)) == 0) { |
210 | kfree(client); | 368 | kfree(client); |
@@ -225,14 +383,18 @@ static struct i2c_driver m41t00_driver = { | |||
225 | static int __init | 383 | static int __init |
226 | m41t00_init(void) | 384 | m41t00_init(void) |
227 | { | 385 | { |
228 | return i2c_add_driver(&m41t00_driver); | 386 | int rc; |
387 | |||
388 | if (!(rc = platform_driver_register(&m41t00_platform_driver))) | ||
389 | rc = i2c_add_driver(&m41t00_driver); | ||
390 | return rc; | ||
229 | } | 391 | } |
230 | 392 | ||
231 | static void __exit | 393 | static void __exit |
232 | m41t00_exit(void) | 394 | m41t00_exit(void) |
233 | { | 395 | { |
234 | i2c_del_driver(&m41t00_driver); | 396 | i2c_del_driver(&m41t00_driver); |
235 | return; | 397 | platform_driver_unregister(&m41t00_platform_driver); |
236 | } | 398 | } |
237 | 399 | ||
238 | module_init(m41t00_init); | 400 | module_init(m41t00_init); |
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 45e2cdf54736..a45155f799d4 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c | |||
@@ -916,7 +916,7 @@ s32 i2c_smbus_write_word_data(struct i2c_client *client, u8 command, u16 value) | |||
916 | } | 916 | } |
917 | 917 | ||
918 | s32 i2c_smbus_write_block_data(struct i2c_client *client, u8 command, | 918 | s32 i2c_smbus_write_block_data(struct i2c_client *client, u8 command, |
919 | u8 length, u8 *values) | 919 | u8 length, const u8 *values) |
920 | { | 920 | { |
921 | union i2c_smbus_data data; | 921 | union i2c_smbus_data data; |
922 | 922 | ||
@@ -944,7 +944,7 @@ s32 i2c_smbus_read_i2c_block_data(struct i2c_client *client, u8 command, u8 *val | |||
944 | } | 944 | } |
945 | 945 | ||
946 | s32 i2c_smbus_write_i2c_block_data(struct i2c_client *client, u8 command, | 946 | s32 i2c_smbus_write_i2c_block_data(struct i2c_client *client, u8 command, |
947 | u8 length, u8 *values) | 947 | u8 length, const u8 *values) |
948 | { | 948 | { |
949 | union i2c_smbus_data data; | 949 | union i2c_smbus_data data; |
950 | 950 | ||
diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index ed7eed388bae..58ccddd5c237 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c | |||
@@ -426,10 +426,7 @@ static int i2cdev_attach_adapter(struct i2c_adapter *adap) | |||
426 | 426 | ||
427 | /* register this i2c device with the driver core */ | 427 | /* register this i2c device with the driver core */ |
428 | i2c_dev->adap = adap; | 428 | i2c_dev->adap = adap; |
429 | if (adap->dev.parent == &platform_bus) | 429 | dev = &adap->dev; |
430 | dev = &adap->dev; | ||
431 | else | ||
432 | dev = adap->dev.parent; | ||
433 | i2c_dev->class_dev = class_device_create(i2c_dev_class, NULL, | 430 | i2c_dev->class_dev = class_device_create(i2c_dev_class, NULL, |
434 | MKDEV(I2C_MAJOR, i2c_dev->minor), | 431 | MKDEV(I2C_MAJOR, i2c_dev->minor), |
435 | dev, "i2c-%d", i2c_dev->minor); | 432 | dev, "i2c-%d", i2c_dev->minor); |
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index 0b5ff553e39a..c63d4e7984be 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c | |||
@@ -2268,7 +2268,7 @@ static int powerbook_sleep_grackle(void) | |||
2268 | _set_L2CR(save_l2cr); | 2268 | _set_L2CR(save_l2cr); |
2269 | 2269 | ||
2270 | /* Restore userland MMU context */ | 2270 | /* Restore userland MMU context */ |
2271 | set_context(current->active_mm->context, current->active_mm->pgd); | 2271 | set_context(current->active_mm->context.id, current->active_mm->pgd); |
2272 | 2272 | ||
2273 | /* Power things up */ | 2273 | /* Power things up */ |
2274 | pmu_unlock(); | 2274 | pmu_unlock(); |
@@ -2366,7 +2366,7 @@ powerbook_sleep_Core99(void) | |||
2366 | _set_L3CR(save_l3cr); | 2366 | _set_L3CR(save_l3cr); |
2367 | 2367 | ||
2368 | /* Restore userland MMU context */ | 2368 | /* Restore userland MMU context */ |
2369 | set_context(current->active_mm->context, current->active_mm->pgd); | 2369 | set_context(current->active_mm->context.id, current->active_mm->pgd); |
2370 | 2370 | ||
2371 | /* Tell PMU we are ready */ | 2371 | /* Tell PMU we are ready */ |
2372 | pmu_unlock(); | 2372 | pmu_unlock(); |
diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index 46d8c01437e9..a26077a175ad 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c | |||
@@ -401,6 +401,11 @@ static void cp_clean_rings (struct cp_private *cp); | |||
401 | #ifdef CONFIG_NET_POLL_CONTROLLER | 401 | #ifdef CONFIG_NET_POLL_CONTROLLER |
402 | static void cp_poll_controller(struct net_device *dev); | 402 | static void cp_poll_controller(struct net_device *dev); |
403 | #endif | 403 | #endif |
404 | static int cp_get_eeprom_len(struct net_device *dev); | ||
405 | static int cp_get_eeprom(struct net_device *dev, | ||
406 | struct ethtool_eeprom *eeprom, u8 *data); | ||
407 | static int cp_set_eeprom(struct net_device *dev, | ||
408 | struct ethtool_eeprom *eeprom, u8 *data); | ||
404 | 409 | ||
405 | static struct pci_device_id cp_pci_tbl[] = { | 410 | static struct pci_device_id cp_pci_tbl[] = { |
406 | { PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8139, | 411 | { PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8139, |
@@ -1577,6 +1582,9 @@ static struct ethtool_ops cp_ethtool_ops = { | |||
1577 | .get_strings = cp_get_strings, | 1582 | .get_strings = cp_get_strings, |
1578 | .get_ethtool_stats = cp_get_ethtool_stats, | 1583 | .get_ethtool_stats = cp_get_ethtool_stats, |
1579 | .get_perm_addr = ethtool_op_get_perm_addr, | 1584 | .get_perm_addr = ethtool_op_get_perm_addr, |
1585 | .get_eeprom_len = cp_get_eeprom_len, | ||
1586 | .get_eeprom = cp_get_eeprom, | ||
1587 | .set_eeprom = cp_set_eeprom, | ||
1580 | }; | 1588 | }; |
1581 | 1589 | ||
1582 | static int cp_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) | 1590 | static int cp_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) |
@@ -1612,24 +1620,32 @@ static int cp_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) | |||
1612 | #define eeprom_delay() readl(ee_addr) | 1620 | #define eeprom_delay() readl(ee_addr) |
1613 | 1621 | ||
1614 | /* The EEPROM commands include the alway-set leading bit. */ | 1622 | /* The EEPROM commands include the alway-set leading bit. */ |
1623 | #define EE_EXTEND_CMD (4) | ||
1615 | #define EE_WRITE_CMD (5) | 1624 | #define EE_WRITE_CMD (5) |
1616 | #define EE_READ_CMD (6) | 1625 | #define EE_READ_CMD (6) |
1617 | #define EE_ERASE_CMD (7) | 1626 | #define EE_ERASE_CMD (7) |
1618 | 1627 | ||
1619 | static int read_eeprom (void __iomem *ioaddr, int location, int addr_len) | 1628 | #define EE_EWDS_ADDR (0) |
1620 | { | 1629 | #define EE_WRAL_ADDR (1) |
1621 | int i; | 1630 | #define EE_ERAL_ADDR (2) |
1622 | unsigned retval = 0; | 1631 | #define EE_EWEN_ADDR (3) |
1623 | void __iomem *ee_addr = ioaddr + Cfg9346; | 1632 | |
1624 | int read_cmd = location | (EE_READ_CMD << addr_len); | 1633 | #define CP_EEPROM_MAGIC PCI_DEVICE_ID_REALTEK_8139 |
1625 | 1634 | ||
1635 | static void eeprom_cmd_start(void __iomem *ee_addr) | ||
1636 | { | ||
1626 | writeb (EE_ENB & ~EE_CS, ee_addr); | 1637 | writeb (EE_ENB & ~EE_CS, ee_addr); |
1627 | writeb (EE_ENB, ee_addr); | 1638 | writeb (EE_ENB, ee_addr); |
1628 | eeprom_delay (); | 1639 | eeprom_delay (); |
1640 | } | ||
1629 | 1641 | ||
1630 | /* Shift the read command bits out. */ | 1642 | static void eeprom_cmd(void __iomem *ee_addr, int cmd, int cmd_len) |
1631 | for (i = 4 + addr_len; i >= 0; i--) { | 1643 | { |
1632 | int dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; | 1644 | int i; |
1645 | |||
1646 | /* Shift the command bits out. */ | ||
1647 | for (i = cmd_len - 1; i >= 0; i--) { | ||
1648 | int dataval = (cmd & (1 << i)) ? EE_DATA_WRITE : 0; | ||
1633 | writeb (EE_ENB | dataval, ee_addr); | 1649 | writeb (EE_ENB | dataval, ee_addr); |
1634 | eeprom_delay (); | 1650 | eeprom_delay (); |
1635 | writeb (EE_ENB | dataval | EE_SHIFT_CLK, ee_addr); | 1651 | writeb (EE_ENB | dataval | EE_SHIFT_CLK, ee_addr); |
@@ -1637,6 +1653,33 @@ static int read_eeprom (void __iomem *ioaddr, int location, int addr_len) | |||
1637 | } | 1653 | } |
1638 | writeb (EE_ENB, ee_addr); | 1654 | writeb (EE_ENB, ee_addr); |
1639 | eeprom_delay (); | 1655 | eeprom_delay (); |
1656 | } | ||
1657 | |||
1658 | static void eeprom_cmd_end(void __iomem *ee_addr) | ||
1659 | { | ||
1660 | writeb (~EE_CS, ee_addr); | ||
1661 | eeprom_delay (); | ||
1662 | } | ||
1663 | |||
1664 | static void eeprom_extend_cmd(void __iomem *ee_addr, int extend_cmd, | ||
1665 | int addr_len) | ||
1666 | { | ||
1667 | int cmd = (EE_EXTEND_CMD << addr_len) | (extend_cmd << (addr_len - 2)); | ||
1668 | |||
1669 | eeprom_cmd_start(ee_addr); | ||
1670 | eeprom_cmd(ee_addr, cmd, 3 + addr_len); | ||
1671 | eeprom_cmd_end(ee_addr); | ||
1672 | } | ||
1673 | |||
1674 | static u16 read_eeprom (void __iomem *ioaddr, int location, int addr_len) | ||
1675 | { | ||
1676 | int i; | ||
1677 | u16 retval = 0; | ||
1678 | void __iomem *ee_addr = ioaddr + Cfg9346; | ||
1679 | int read_cmd = location | (EE_READ_CMD << addr_len); | ||
1680 | |||
1681 | eeprom_cmd_start(ee_addr); | ||
1682 | eeprom_cmd(ee_addr, read_cmd, 3 + addr_len); | ||
1640 | 1683 | ||
1641 | for (i = 16; i > 0; i--) { | 1684 | for (i = 16; i > 0; i--) { |
1642 | writeb (EE_ENB | EE_SHIFT_CLK, ee_addr); | 1685 | writeb (EE_ENB | EE_SHIFT_CLK, ee_addr); |
@@ -1648,13 +1691,125 @@ static int read_eeprom (void __iomem *ioaddr, int location, int addr_len) | |||
1648 | eeprom_delay (); | 1691 | eeprom_delay (); |
1649 | } | 1692 | } |
1650 | 1693 | ||
1651 | /* Terminate the EEPROM access. */ | 1694 | eeprom_cmd_end(ee_addr); |
1652 | writeb (~EE_CS, ee_addr); | ||
1653 | eeprom_delay (); | ||
1654 | 1695 | ||
1655 | return retval; | 1696 | return retval; |
1656 | } | 1697 | } |
1657 | 1698 | ||
1699 | static void write_eeprom(void __iomem *ioaddr, int location, u16 val, | ||
1700 | int addr_len) | ||
1701 | { | ||
1702 | int i; | ||
1703 | void __iomem *ee_addr = ioaddr + Cfg9346; | ||
1704 | int write_cmd = location | (EE_WRITE_CMD << addr_len); | ||
1705 | |||
1706 | eeprom_extend_cmd(ee_addr, EE_EWEN_ADDR, addr_len); | ||
1707 | |||
1708 | eeprom_cmd_start(ee_addr); | ||
1709 | eeprom_cmd(ee_addr, write_cmd, 3 + addr_len); | ||
1710 | eeprom_cmd(ee_addr, val, 16); | ||
1711 | eeprom_cmd_end(ee_addr); | ||
1712 | |||
1713 | eeprom_cmd_start(ee_addr); | ||
1714 | for (i = 0; i < 20000; i++) | ||
1715 | if (readb(ee_addr) & EE_DATA_READ) | ||
1716 | break; | ||
1717 | eeprom_cmd_end(ee_addr); | ||
1718 | |||
1719 | eeprom_extend_cmd(ee_addr, EE_EWDS_ADDR, addr_len); | ||
1720 | } | ||
1721 | |||
1722 | static int cp_get_eeprom_len(struct net_device *dev) | ||
1723 | { | ||
1724 | struct cp_private *cp = netdev_priv(dev); | ||
1725 | int size; | ||
1726 | |||
1727 | spin_lock_irq(&cp->lock); | ||
1728 | size = read_eeprom(cp->regs, 0, 8) == 0x8129 ? 256 : 128; | ||
1729 | spin_unlock_irq(&cp->lock); | ||
1730 | |||
1731 | return size; | ||
1732 | } | ||
1733 | |||
1734 | static int cp_get_eeprom(struct net_device *dev, | ||
1735 | struct ethtool_eeprom *eeprom, u8 *data) | ||
1736 | { | ||
1737 | struct cp_private *cp = netdev_priv(dev); | ||
1738 | unsigned int addr_len; | ||
1739 | u16 val; | ||
1740 | u32 offset = eeprom->offset >> 1; | ||
1741 | u32 len = eeprom->len; | ||
1742 | u32 i = 0; | ||
1743 | |||
1744 | eeprom->magic = CP_EEPROM_MAGIC; | ||
1745 | |||
1746 | spin_lock_irq(&cp->lock); | ||
1747 | |||
1748 | addr_len = read_eeprom(cp->regs, 0, 8) == 0x8129 ? 8 : 6; | ||
1749 | |||
1750 | if (eeprom->offset & 1) { | ||
1751 | val = read_eeprom(cp->regs, offset, addr_len); | ||
1752 | data[i++] = (u8)(val >> 8); | ||
1753 | offset++; | ||
1754 | } | ||
1755 | |||
1756 | while (i < len - 1) { | ||
1757 | val = read_eeprom(cp->regs, offset, addr_len); | ||
1758 | data[i++] = (u8)val; | ||
1759 | data[i++] = (u8)(val >> 8); | ||
1760 | offset++; | ||
1761 | } | ||
1762 | |||
1763 | if (i < len) { | ||
1764 | val = read_eeprom(cp->regs, offset, addr_len); | ||
1765 | data[i] = (u8)val; | ||
1766 | } | ||
1767 | |||
1768 | spin_unlock_irq(&cp->lock); | ||
1769 | return 0; | ||
1770 | } | ||
1771 | |||
1772 | static int cp_set_eeprom(struct net_device *dev, | ||
1773 | struct ethtool_eeprom *eeprom, u8 *data) | ||
1774 | { | ||
1775 | struct cp_private *cp = netdev_priv(dev); | ||
1776 | unsigned int addr_len; | ||
1777 | u16 val; | ||
1778 | u32 offset = eeprom->offset >> 1; | ||
1779 | u32 len = eeprom->len; | ||
1780 | u32 i = 0; | ||
1781 | |||
1782 | if (eeprom->magic != CP_EEPROM_MAGIC) | ||
1783 | return -EINVAL; | ||
1784 | |||
1785 | spin_lock_irq(&cp->lock); | ||
1786 | |||
1787 | addr_len = read_eeprom(cp->regs, 0, 8) == 0x8129 ? 8 : 6; | ||
1788 | |||
1789 | if (eeprom->offset & 1) { | ||
1790 | val = read_eeprom(cp->regs, offset, addr_len) & 0xff; | ||
1791 | val |= (u16)data[i++] << 8; | ||
1792 | write_eeprom(cp->regs, offset, val, addr_len); | ||
1793 | offset++; | ||
1794 | } | ||
1795 | |||
1796 | while (i < len - 1) { | ||
1797 | val = (u16)data[i++]; | ||
1798 | val |= (u16)data[i++] << 8; | ||
1799 | write_eeprom(cp->regs, offset, val, addr_len); | ||
1800 | offset++; | ||
1801 | } | ||
1802 | |||
1803 | if (i < len) { | ||
1804 | val = read_eeprom(cp->regs, offset, addr_len) & 0xff00; | ||
1805 | val |= (u16)data[i]; | ||
1806 | write_eeprom(cp->regs, offset, val, addr_len); | ||
1807 | } | ||
1808 | |||
1809 | spin_unlock_irq(&cp->lock); | ||
1810 | return 0; | ||
1811 | } | ||
1812 | |||
1658 | /* Put the board into D3cold state and wait for WakeUp signal */ | 1813 | /* Put the board into D3cold state and wait for WakeUp signal */ |
1659 | static void cp_set_d3_state (struct cp_private *cp) | 1814 | static void cp_set_d3_state (struct cp_private *cp) |
1660 | { | 1815 | { |
diff --git a/drivers/net/8390.c b/drivers/net/8390.c index f87027420081..86be96af9c8f 100644 --- a/drivers/net/8390.c +++ b/drivers/net/8390.c | |||
@@ -275,12 +275,14 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
275 | struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); | 275 | struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); |
276 | int send_length = skb->len, output_page; | 276 | int send_length = skb->len, output_page; |
277 | unsigned long flags; | 277 | unsigned long flags; |
278 | char buf[ETH_ZLEN]; | ||
279 | char *data = skb->data; | ||
278 | 280 | ||
279 | if (skb->len < ETH_ZLEN) { | 281 | if (skb->len < ETH_ZLEN) { |
280 | skb = skb_padto(skb, ETH_ZLEN); | 282 | memset(buf, 0, ETH_ZLEN); /* more efficient than doing just the needed bits */ |
281 | if (skb == NULL) | 283 | memcpy(buf, data, skb->len); |
282 | return 0; | ||
283 | send_length = ETH_ZLEN; | 284 | send_length = ETH_ZLEN; |
285 | data = buf; | ||
284 | } | 286 | } |
285 | 287 | ||
286 | /* Mask interrupts from the ethercard. | 288 | /* Mask interrupts from the ethercard. |
@@ -347,7 +349,7 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
347 | * trigger the send later, upon receiving a Tx done interrupt. | 349 | * trigger the send later, upon receiving a Tx done interrupt. |
348 | */ | 350 | */ |
349 | 351 | ||
350 | ei_block_output(dev, send_length, skb->data, output_page); | 352 | ei_block_output(dev, send_length, data, output_page); |
351 | 353 | ||
352 | if (! ei_local->txing) | 354 | if (! ei_local->txing) |
353 | { | 355 | { |
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 0c6b45a11d15..39189903e355 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig | |||
@@ -854,6 +854,17 @@ config SMC9194 | |||
854 | <file:Documentation/networking/net-modules.txt>. The module | 854 | <file:Documentation/networking/net-modules.txt>. The module |
855 | will be called smc9194. | 855 | will be called smc9194. |
856 | 856 | ||
857 | config NET_NETX | ||
858 | tristate "NetX Ethernet support" | ||
859 | select MII | ||
860 | depends on NET_ETHERNET && ARCH_NETX | ||
861 | help | ||
862 | This is support for the Hilscher netX builtin Ethernet ports | ||
863 | |||
864 | To compile this driver as a module, choose M here and read | ||
865 | <file:Documentation/networking/net-modules.txt>. The module | ||
866 | will be called netx-eth. | ||
867 | |||
857 | config DM9000 | 868 | config DM9000 |
858 | tristate "DM9000 support" | 869 | tristate "DM9000 support" |
859 | depends on (ARM || MIPS) && NET_ETHERNET | 870 | depends on (ARM || MIPS) && NET_ETHERNET |
@@ -1376,8 +1387,8 @@ config APRICOT | |||
1376 | called apricot. | 1387 | called apricot. |
1377 | 1388 | ||
1378 | config B44 | 1389 | config B44 |
1379 | tristate "Broadcom 4400 ethernet support (EXPERIMENTAL)" | 1390 | tristate "Broadcom 4400 ethernet support" |
1380 | depends on NET_PCI && PCI && EXPERIMENTAL | 1391 | depends on NET_PCI && PCI |
1381 | select MII | 1392 | select MII |
1382 | help | 1393 | help |
1383 | If you have a network (Ethernet) controller of this type, say Y and | 1394 | If you have a network (Ethernet) controller of this type, say Y and |
@@ -2190,7 +2201,7 @@ config BNX2 | |||
2190 | 2201 | ||
2191 | config SPIDER_NET | 2202 | config SPIDER_NET |
2192 | tristate "Spider Gigabit Ethernet driver" | 2203 | tristate "Spider Gigabit Ethernet driver" |
2193 | depends on PCI && PPC_CELL | 2204 | depends on PCI && PPC_IBM_CELL_BLADE |
2194 | select FW_LOADER | 2205 | select FW_LOADER |
2195 | help | 2206 | help |
2196 | This driver supports the Gigabit Ethernet chips present on the | 2207 | This driver supports the Gigabit Ethernet chips present on the |
@@ -2198,11 +2209,11 @@ config SPIDER_NET | |||
2198 | 2209 | ||
2199 | config GIANFAR | 2210 | config GIANFAR |
2200 | tristate "Gianfar Ethernet" | 2211 | tristate "Gianfar Ethernet" |
2201 | depends on 85xx || 83xx | 2212 | depends on 85xx || 83xx || PPC_86xx |
2202 | select PHYLIB | 2213 | select PHYLIB |
2203 | help | 2214 | help |
2204 | This driver supports the Gigabit TSEC on the MPC85xx | 2215 | This driver supports the Gigabit TSEC on the MPC83xx, MPC85xx, |
2205 | family of chips, and the FEC on the 8540 | 2216 | and MPC86xx family of chips, and the FEC on the 8540. |
2206 | 2217 | ||
2207 | config GFAR_NAPI | 2218 | config GFAR_NAPI |
2208 | bool "NAPI Support" | 2219 | bool "NAPI Support" |
diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 1eced3287507..c91e95126f78 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile | |||
@@ -187,6 +187,7 @@ obj-$(CONFIG_MACSONIC) += macsonic.o | |||
187 | obj-$(CONFIG_MACMACE) += macmace.o | 187 | obj-$(CONFIG_MACMACE) += macmace.o |
188 | obj-$(CONFIG_MAC89x0) += mac89x0.o | 188 | obj-$(CONFIG_MAC89x0) += mac89x0.o |
189 | obj-$(CONFIG_TUN) += tun.o | 189 | obj-$(CONFIG_TUN) += tun.o |
190 | obj-$(CONFIG_NET_NETX) += netx-eth.o | ||
190 | obj-$(CONFIG_DL2K) += dl2k.o | 191 | obj-$(CONFIG_DL2K) += dl2k.o |
191 | obj-$(CONFIG_R8169) += r8169.o | 192 | obj-$(CONFIG_R8169) += r8169.o |
192 | obj-$(CONFIG_AMD8111_ETH) += amd8111e.o | 193 | obj-$(CONFIG_AMD8111_ETH) += amd8111e.o |
diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c index 5503dc8a66e4..613005a0285d 100644 --- a/drivers/net/arm/at91_ether.c +++ b/drivers/net/arm/at91_ether.c | |||
@@ -43,7 +43,9 @@ | |||
43 | #define DRV_VERSION "1.0" | 43 | #define DRV_VERSION "1.0" |
44 | 44 | ||
45 | static struct net_device *at91_dev; | 45 | static struct net_device *at91_dev; |
46 | static struct clk *ether_clk; | 46 | |
47 | static struct timer_list check_timer; | ||
48 | #define LINK_POLL_INTERVAL (HZ) | ||
47 | 49 | ||
48 | /* ..................................................................... */ | 50 | /* ..................................................................... */ |
49 | 51 | ||
@@ -143,7 +145,7 @@ static void read_phy(unsigned char phy_addr, unsigned char address, unsigned int | |||
143 | * MAC accordingly. | 145 | * MAC accordingly. |
144 | * If no link or auto-negotiation is busy, then no changes are made. | 146 | * If no link or auto-negotiation is busy, then no changes are made. |
145 | */ | 147 | */ |
146 | static void update_linkspeed(struct net_device *dev) | 148 | static void update_linkspeed(struct net_device *dev, int silent) |
147 | { | 149 | { |
148 | struct at91_private *lp = (struct at91_private *) dev->priv; | 150 | struct at91_private *lp = (struct at91_private *) dev->priv; |
149 | unsigned int bmsr, bmcr, lpa, mac_cfg; | 151 | unsigned int bmsr, bmcr, lpa, mac_cfg; |
@@ -151,7 +153,8 @@ static void update_linkspeed(struct net_device *dev) | |||
151 | 153 | ||
152 | if (!mii_link_ok(&lp->mii)) { /* no link */ | 154 | if (!mii_link_ok(&lp->mii)) { /* no link */ |
153 | netif_carrier_off(dev); | 155 | netif_carrier_off(dev); |
154 | printk(KERN_INFO "%s: Link down.\n", dev->name); | 156 | if (!silent) |
157 | printk(KERN_INFO "%s: Link down.\n", dev->name); | ||
155 | return; | 158 | return; |
156 | } | 159 | } |
157 | 160 | ||
@@ -186,7 +189,8 @@ static void update_linkspeed(struct net_device *dev) | |||
186 | } | 189 | } |
187 | at91_emac_write(AT91_EMAC_CFG, mac_cfg); | 190 | at91_emac_write(AT91_EMAC_CFG, mac_cfg); |
188 | 191 | ||
189 | printk(KERN_INFO "%s: Link now %i-%s\n", dev->name, speed, (duplex == DUPLEX_FULL) ? "FullDuplex" : "HalfDuplex"); | 192 | if (!silent) |
193 | printk(KERN_INFO "%s: Link now %i-%s\n", dev->name, speed, (duplex == DUPLEX_FULL) ? "FullDuplex" : "HalfDuplex"); | ||
190 | netif_carrier_on(dev); | 194 | netif_carrier_on(dev); |
191 | } | 195 | } |
192 | 196 | ||
@@ -226,7 +230,7 @@ static irqreturn_t at91ether_phy_interrupt(int irq, void *dev_id, struct pt_regs | |||
226 | goto done; | 230 | goto done; |
227 | } | 231 | } |
228 | 232 | ||
229 | update_linkspeed(dev); | 233 | update_linkspeed(dev, 0); |
230 | 234 | ||
231 | done: | 235 | done: |
232 | disable_mdi(); | 236 | disable_mdi(); |
@@ -243,14 +247,17 @@ static void enable_phyirq(struct net_device *dev) | |||
243 | unsigned int dsintr, irq_number; | 247 | unsigned int dsintr, irq_number; |
244 | int status; | 248 | int status; |
245 | 249 | ||
246 | if (lp->phy_type == MII_RTL8201_ID) /* RTL8201 does not have an interrupt */ | 250 | irq_number = lp->board_data.phy_irq_pin; |
247 | return; | 251 | if (!irq_number) { |
248 | if (lp->phy_type == MII_DP83847_ID) /* DP83847 does not have an interrupt */ | 252 | /* |
249 | return; | 253 | * PHY doesn't have an IRQ pin (RTL8201, DP83847, AC101L), |
250 | if (lp->phy_type == MII_AC101L_ID) /* AC101L interrupt not supported yet */ | 254 | * or board does not have it connected. |
255 | */ | ||
256 | check_timer.expires = jiffies + LINK_POLL_INTERVAL; | ||
257 | add_timer(&check_timer); | ||
251 | return; | 258 | return; |
259 | } | ||
252 | 260 | ||
253 | irq_number = lp->board_data.phy_irq_pin; | ||
254 | status = request_irq(irq_number, at91ether_phy_interrupt, 0, dev->name, dev); | 261 | status = request_irq(irq_number, at91ether_phy_interrupt, 0, dev->name, dev); |
255 | if (status) { | 262 | if (status) { |
256 | printk(KERN_ERR "at91_ether: PHY IRQ %d request failed - status %d!\n", irq_number, status); | 263 | printk(KERN_ERR "at91_ether: PHY IRQ %d request failed - status %d!\n", irq_number, status); |
@@ -292,12 +299,11 @@ static void disable_phyirq(struct net_device *dev) | |||
292 | unsigned int dsintr; | 299 | unsigned int dsintr; |
293 | unsigned int irq_number; | 300 | unsigned int irq_number; |
294 | 301 | ||
295 | if (lp->phy_type == MII_RTL8201_ID) /* RTL8201 does not have an interrupt */ | 302 | irq_number = lp->board_data.phy_irq_pin; |
296 | return; | 303 | if (!irq_number) { |
297 | if (lp->phy_type == MII_DP83847_ID) /* DP83847 does not have an interrupt */ | 304 | del_timer_sync(&check_timer); |
298 | return; | ||
299 | if (lp->phy_type == MII_AC101L_ID) /* AC101L interrupt not supported yet */ | ||
300 | return; | 305 | return; |
306 | } | ||
301 | 307 | ||
302 | spin_lock_irq(&lp->lock); | 308 | spin_lock_irq(&lp->lock); |
303 | enable_mdi(); | 309 | enable_mdi(); |
@@ -326,7 +332,6 @@ static void disable_phyirq(struct net_device *dev) | |||
326 | disable_mdi(); | 332 | disable_mdi(); |
327 | spin_unlock_irq(&lp->lock); | 333 | spin_unlock_irq(&lp->lock); |
328 | 334 | ||
329 | irq_number = lp->board_data.phy_irq_pin; | ||
330 | free_irq(irq_number, dev); /* Free interrupt handler */ | 335 | free_irq(irq_number, dev); /* Free interrupt handler */ |
331 | } | 336 | } |
332 | 337 | ||
@@ -355,6 +360,18 @@ static void reset_phy(struct net_device *dev) | |||
355 | } | 360 | } |
356 | #endif | 361 | #endif |
357 | 362 | ||
363 | static void at91ether_check_link(unsigned long dev_id) | ||
364 | { | ||
365 | struct net_device *dev = (struct net_device *) dev_id; | ||
366 | |||
367 | enable_mdi(); | ||
368 | update_linkspeed(dev, 1); | ||
369 | disable_mdi(); | ||
370 | |||
371 | check_timer.expires = jiffies + LINK_POLL_INTERVAL; | ||
372 | add_timer(&check_timer); | ||
373 | } | ||
374 | |||
358 | /* ......................... ADDRESS MANAGEMENT ........................ */ | 375 | /* ......................... ADDRESS MANAGEMENT ........................ */ |
359 | 376 | ||
360 | /* | 377 | /* |
@@ -501,7 +518,7 @@ static int hash_get_index(__u8 *addr) | |||
501 | hash_index |= (bitval << j); | 518 | hash_index |= (bitval << j); |
502 | } | 519 | } |
503 | 520 | ||
504 | return hash_index; | 521 | return hash_index; |
505 | } | 522 | } |
506 | 523 | ||
507 | /* | 524 | /* |
@@ -557,10 +574,8 @@ static void at91ether_set_rx_mode(struct net_device *dev) | |||
557 | at91_emac_write(AT91_EMAC_CFG, cfg); | 574 | at91_emac_write(AT91_EMAC_CFG, cfg); |
558 | } | 575 | } |
559 | 576 | ||
560 | |||
561 | /* ......................... ETHTOOL SUPPORT ........................... */ | 577 | /* ......................... ETHTOOL SUPPORT ........................... */ |
562 | 578 | ||
563 | |||
564 | static int mdio_read(struct net_device *dev, int phy_id, int location) | 579 | static int mdio_read(struct net_device *dev, int phy_id, int location) |
565 | { | 580 | { |
566 | unsigned int value; | 581 | unsigned int value; |
@@ -642,6 +657,22 @@ static struct ethtool_ops at91ether_ethtool_ops = { | |||
642 | .get_link = ethtool_op_get_link, | 657 | .get_link = ethtool_op_get_link, |
643 | }; | 658 | }; |
644 | 659 | ||
660 | static int at91ether_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) | ||
661 | { | ||
662 | struct at91_private *lp = (struct at91_private *) dev->priv; | ||
663 | int res; | ||
664 | |||
665 | if (!netif_running(dev)) | ||
666 | return -EINVAL; | ||
667 | |||
668 | spin_lock_irq(&lp->lock); | ||
669 | enable_mdi(); | ||
670 | res = generic_mii_ioctl(&lp->mii, if_mii(rq), cmd, NULL); | ||
671 | disable_mdi(); | ||
672 | spin_unlock_irq(&lp->lock); | ||
673 | |||
674 | return res; | ||
675 | } | ||
645 | 676 | ||
646 | /* ................................ MAC ................................ */ | 677 | /* ................................ MAC ................................ */ |
647 | 678 | ||
@@ -685,10 +716,10 @@ static int at91ether_open(struct net_device *dev) | |||
685 | struct at91_private *lp = (struct at91_private *) dev->priv; | 716 | struct at91_private *lp = (struct at91_private *) dev->priv; |
686 | unsigned long ctl; | 717 | unsigned long ctl; |
687 | 718 | ||
688 | if (!is_valid_ether_addr(dev->dev_addr)) | 719 | if (!is_valid_ether_addr(dev->dev_addr)) |
689 | return -EADDRNOTAVAIL; | 720 | return -EADDRNOTAVAIL; |
690 | 721 | ||
691 | clk_enable(ether_clk); /* Re-enable Peripheral clock */ | 722 | clk_enable(lp->ether_clk); /* Re-enable Peripheral clock */ |
692 | 723 | ||
693 | /* Clear internal statistics */ | 724 | /* Clear internal statistics */ |
694 | ctl = at91_emac_read(AT91_EMAC_CTL); | 725 | ctl = at91_emac_read(AT91_EMAC_CTL); |
@@ -708,7 +739,7 @@ static int at91ether_open(struct net_device *dev) | |||
708 | /* Determine current link speed */ | 739 | /* Determine current link speed */ |
709 | spin_lock_irq(&lp->lock); | 740 | spin_lock_irq(&lp->lock); |
710 | enable_mdi(); | 741 | enable_mdi(); |
711 | update_linkspeed(dev); | 742 | update_linkspeed(dev, 0); |
712 | disable_mdi(); | 743 | disable_mdi(); |
713 | spin_unlock_irq(&lp->lock); | 744 | spin_unlock_irq(&lp->lock); |
714 | 745 | ||
@@ -722,6 +753,7 @@ static int at91ether_open(struct net_device *dev) | |||
722 | */ | 753 | */ |
723 | static int at91ether_close(struct net_device *dev) | 754 | static int at91ether_close(struct net_device *dev) |
724 | { | 755 | { |
756 | struct at91_private *lp = (struct at91_private *) dev->priv; | ||
725 | unsigned long ctl; | 757 | unsigned long ctl; |
726 | 758 | ||
727 | /* Disable Receiver and Transmitter */ | 759 | /* Disable Receiver and Transmitter */ |
@@ -738,7 +770,7 @@ static int at91ether_close(struct net_device *dev) | |||
738 | 770 | ||
739 | netif_stop_queue(dev); | 771 | netif_stop_queue(dev); |
740 | 772 | ||
741 | clk_disable(ether_clk); /* Disable Peripheral clock */ | 773 | clk_disable(lp->ether_clk); /* Disable Peripheral clock */ |
742 | 774 | ||
743 | return 0; | 775 | return 0; |
744 | } | 776 | } |
@@ -870,7 +902,7 @@ static irqreturn_t at91ether_interrupt(int irq, void *dev_id, struct pt_regs *re | |||
870 | if (intstatus & AT91_EMAC_RCOM) /* Receive complete */ | 902 | if (intstatus & AT91_EMAC_RCOM) /* Receive complete */ |
871 | at91ether_rx(dev); | 903 | at91ether_rx(dev); |
872 | 904 | ||
873 | if (intstatus & AT91_EMAC_TCOM) { /* Transmit complete */ | 905 | if (intstatus & AT91_EMAC_TCOM) { /* Transmit complete */ |
874 | /* The TCOM bit is set even if the transmission failed. */ | 906 | /* The TCOM bit is set even if the transmission failed. */ |
875 | if (intstatus & (AT91_EMAC_TUND | AT91_EMAC_RTRY)) | 907 | if (intstatus & (AT91_EMAC_TUND | AT91_EMAC_RTRY)) |
876 | lp->stats.tx_errors += 1; | 908 | lp->stats.tx_errors += 1; |
@@ -899,7 +931,8 @@ static irqreturn_t at91ether_interrupt(int irq, void *dev_id, struct pt_regs *re | |||
899 | /* | 931 | /* |
900 | * Initialize the ethernet interface | 932 | * Initialize the ethernet interface |
901 | */ | 933 | */ |
902 | static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_address, struct platform_device *pdev) | 934 | static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_address, |
935 | struct platform_device *pdev, struct clk *ether_clk) | ||
903 | { | 936 | { |
904 | struct at91_eth_data *board_data = pdev->dev.platform_data; | 937 | struct at91_eth_data *board_data = pdev->dev.platform_data; |
905 | struct net_device *dev; | 938 | struct net_device *dev; |
@@ -933,6 +966,7 @@ static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_add | |||
933 | return -ENOMEM; | 966 | return -ENOMEM; |
934 | } | 967 | } |
935 | lp->board_data = *board_data; | 968 | lp->board_data = *board_data; |
969 | lp->ether_clk = ether_clk; | ||
936 | platform_set_drvdata(pdev, dev); | 970 | platform_set_drvdata(pdev, dev); |
937 | 971 | ||
938 | spin_lock_init(&lp->lock); | 972 | spin_lock_init(&lp->lock); |
@@ -945,6 +979,7 @@ static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_add | |||
945 | dev->set_multicast_list = at91ether_set_rx_mode; | 979 | dev->set_multicast_list = at91ether_set_rx_mode; |
946 | dev->set_mac_address = set_mac_address; | 980 | dev->set_mac_address = set_mac_address; |
947 | dev->ethtool_ops = &at91ether_ethtool_ops; | 981 | dev->ethtool_ops = &at91ether_ethtool_ops; |
982 | dev->do_ioctl = at91ether_ioctl; | ||
948 | 983 | ||
949 | SET_NETDEV_DEV(dev, &pdev->dev); | 984 | SET_NETDEV_DEV(dev, &pdev->dev); |
950 | 985 | ||
@@ -975,6 +1010,9 @@ static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_add | |||
975 | lp->mii.dev = dev; /* Support for ethtool */ | 1010 | lp->mii.dev = dev; /* Support for ethtool */ |
976 | lp->mii.mdio_read = mdio_read; | 1011 | lp->mii.mdio_read = mdio_read; |
977 | lp->mii.mdio_write = mdio_write; | 1012 | lp->mii.mdio_write = mdio_write; |
1013 | lp->mii.phy_id = phy_address; | ||
1014 | lp->mii.phy_id_mask = 0x1f; | ||
1015 | lp->mii.reg_num_mask = 0x1f; | ||
978 | 1016 | ||
979 | lp->phy_type = phy_type; /* Type of PHY connected */ | 1017 | lp->phy_type = phy_type; /* Type of PHY connected */ |
980 | lp->phy_address = phy_address; /* MDI address of PHY */ | 1018 | lp->phy_address = phy_address; /* MDI address of PHY */ |
@@ -992,11 +1030,18 @@ static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_add | |||
992 | /* Determine current link speed */ | 1030 | /* Determine current link speed */ |
993 | spin_lock_irq(&lp->lock); | 1031 | spin_lock_irq(&lp->lock); |
994 | enable_mdi(); | 1032 | enable_mdi(); |
995 | update_linkspeed(dev); | 1033 | update_linkspeed(dev, 0); |
996 | disable_mdi(); | 1034 | disable_mdi(); |
997 | spin_unlock_irq(&lp->lock); | 1035 | spin_unlock_irq(&lp->lock); |
998 | netif_carrier_off(dev); /* will be enabled in open() */ | 1036 | netif_carrier_off(dev); /* will be enabled in open() */ |
999 | 1037 | ||
1038 | /* If board has no PHY IRQ, use a timer to poll the PHY */ | ||
1039 | if (!lp->board_data.phy_irq_pin) { | ||
1040 | init_timer(&check_timer); | ||
1041 | check_timer.data = (unsigned long)dev; | ||
1042 | check_timer.function = at91ether_check_link; | ||
1043 | } | ||
1044 | |||
1000 | /* Display ethernet banner */ | 1045 | /* Display ethernet banner */ |
1001 | printk(KERN_INFO "%s: AT91 ethernet at 0x%08x int=%d %s%s (%02x:%02x:%02x:%02x:%02x:%02x)\n", | 1046 | printk(KERN_INFO "%s: AT91 ethernet at 0x%08x int=%d %s%s (%02x:%02x:%02x:%02x:%02x:%02x)\n", |
1002 | dev->name, (uint) dev->base_addr, dev->irq, | 1047 | dev->name, (uint) dev->base_addr, dev->irq, |
@@ -1005,7 +1050,7 @@ static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_add | |||
1005 | dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], | 1050 | dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], |
1006 | dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); | 1051 | dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); |
1007 | if ((phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) | 1052 | if ((phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) |
1008 | printk(KERN_INFO "%s: Davicom 9196 PHY %s\n", dev->name, (lp->phy_media == PORT_FIBRE) ? "(Fiber)" : "(Copper)"); | 1053 | printk(KERN_INFO "%s: Davicom 9161 PHY %s\n", dev->name, (lp->phy_media == PORT_FIBRE) ? "(Fiber)" : "(Copper)"); |
1009 | else if (phy_type == MII_LXT971A_ID) | 1054 | else if (phy_type == MII_LXT971A_ID) |
1010 | printk(KERN_INFO "%s: Intel LXT971A PHY\n", dev->name); | 1055 | printk(KERN_INFO "%s: Intel LXT971A PHY\n", dev->name); |
1011 | else if (phy_type == MII_RTL8201_ID) | 1056 | else if (phy_type == MII_RTL8201_ID) |
@@ -1031,9 +1076,10 @@ static int __init at91ether_probe(struct platform_device *pdev) | |||
1031 | int detected = -1; | 1076 | int detected = -1; |
1032 | unsigned long phy_id; | 1077 | unsigned long phy_id; |
1033 | unsigned short phy_address = 0; | 1078 | unsigned short phy_address = 0; |
1079 | struct clk *ether_clk; | ||
1034 | 1080 | ||
1035 | ether_clk = clk_get(&pdev->dev, "ether_clk"); | 1081 | ether_clk = clk_get(&pdev->dev, "ether_clk"); |
1036 | if (!ether_clk) { | 1082 | if (IS_ERR(ether_clk)) { |
1037 | printk(KERN_ERR "at91_ether: no clock defined\n"); | 1083 | printk(KERN_ERR "at91_ether: no clock defined\n"); |
1038 | return -ENODEV; | 1084 | return -ENODEV; |
1039 | } | 1085 | } |
@@ -1056,7 +1102,7 @@ static int __init at91ether_probe(struct platform_device *pdev) | |||
1056 | case MII_DP83847_ID: /* National Semiconductor DP83847: */ | 1102 | case MII_DP83847_ID: /* National Semiconductor DP83847: */ |
1057 | case MII_AC101L_ID: /* Altima AC101L: PHY_ID1 = 0x22, PHY_ID2 = 0x5520 */ | 1103 | case MII_AC101L_ID: /* Altima AC101L: PHY_ID1 = 0x22, PHY_ID2 = 0x5520 */ |
1058 | case MII_KS8721_ID: /* Micrel KS8721: PHY_ID1 = 0x22, PHY_ID2 = 0x1610 */ | 1104 | case MII_KS8721_ID: /* Micrel KS8721: PHY_ID1 = 0x22, PHY_ID2 = 0x1610 */ |
1059 | detected = at91ether_setup(phy_id, phy_address, pdev); | 1105 | detected = at91ether_setup(phy_id, phy_address, pdev, ether_clk); |
1060 | break; | 1106 | break; |
1061 | } | 1107 | } |
1062 | 1108 | ||
@@ -1075,17 +1121,61 @@ static int __devexit at91ether_remove(struct platform_device *pdev) | |||
1075 | unregister_netdev(at91_dev); | 1121 | unregister_netdev(at91_dev); |
1076 | free_irq(at91_dev->irq, at91_dev); | 1122 | free_irq(at91_dev->irq, at91_dev); |
1077 | dma_free_coherent(NULL, sizeof(struct recv_desc_bufs), lp->dlist, (dma_addr_t)lp->dlist_phys); | 1123 | dma_free_coherent(NULL, sizeof(struct recv_desc_bufs), lp->dlist, (dma_addr_t)lp->dlist_phys); |
1078 | clk_put(ether_clk); | 1124 | clk_put(lp->ether_clk); |
1079 | 1125 | ||
1080 | free_netdev(at91_dev); | 1126 | free_netdev(at91_dev); |
1081 | at91_dev = NULL; | 1127 | at91_dev = NULL; |
1082 | return 0; | 1128 | return 0; |
1083 | } | 1129 | } |
1084 | 1130 | ||
1131 | #ifdef CONFIG_PM | ||
1132 | |||
1133 | static int at91ether_suspend(struct platform_device *pdev, pm_message_t mesg) | ||
1134 | { | ||
1135 | struct at91_private *lp = (struct at91_private *) at91_dev->priv; | ||
1136 | struct net_device *net_dev = platform_get_drvdata(pdev); | ||
1137 | int phy_irq = lp->board_data.phy_irq_pin; | ||
1138 | |||
1139 | if (netif_running(net_dev)) { | ||
1140 | if (phy_irq) | ||
1141 | disable_irq(phy_irq); | ||
1142 | |||
1143 | netif_stop_queue(net_dev); | ||
1144 | netif_device_detach(net_dev); | ||
1145 | |||
1146 | clk_disable(lp->ether_clk); | ||
1147 | } | ||
1148 | return 0; | ||
1149 | } | ||
1150 | |||
1151 | static int at91ether_resume(struct platform_device *pdev) | ||
1152 | { | ||
1153 | struct at91_private *lp = (struct at91_private *) at91_dev->priv; | ||
1154 | struct net_device *net_dev = platform_get_drvdata(pdev); | ||
1155 | int phy_irq = lp->board_data.phy_irq_pin; | ||
1156 | |||
1157 | if (netif_running(net_dev)) { | ||
1158 | clk_enable(lp->ether_clk); | ||
1159 | |||
1160 | netif_device_attach(net_dev); | ||
1161 | netif_start_queue(net_dev); | ||
1162 | |||
1163 | if (phy_irq) | ||
1164 | enable_irq(phy_irq); | ||
1165 | } | ||
1166 | return 0; | ||
1167 | } | ||
1168 | |||
1169 | #else | ||
1170 | #define at91ether_suspend NULL | ||
1171 | #define at91ether_resume NULL | ||
1172 | #endif | ||
1173 | |||
1085 | static struct platform_driver at91ether_driver = { | 1174 | static struct platform_driver at91ether_driver = { |
1086 | .probe = at91ether_probe, | 1175 | .probe = at91ether_probe, |
1087 | .remove = __devexit_p(at91ether_remove), | 1176 | .remove = __devexit_p(at91ether_remove), |
1088 | /* FIXME: support suspend and resume */ | 1177 | .suspend = at91ether_suspend, |
1178 | .resume = at91ether_resume, | ||
1089 | .driver = { | 1179 | .driver = { |
1090 | .name = DRV_NAME, | 1180 | .name = DRV_NAME, |
1091 | .owner = THIS_MODULE, | 1181 | .owner = THIS_MODULE, |
diff --git a/drivers/net/arm/at91_ether.h b/drivers/net/arm/at91_ether.h index 9885735c9c8a..d1e72e02be3a 100644 --- a/drivers/net/arm/at91_ether.h +++ b/drivers/net/arm/at91_ether.h | |||
@@ -80,6 +80,7 @@ struct at91_private | |||
80 | struct net_device_stats stats; | 80 | struct net_device_stats stats; |
81 | struct mii_if_info mii; /* ethtool support */ | 81 | struct mii_if_info mii; /* ethtool support */ |
82 | struct at91_eth_data board_data; /* board-specific configuration */ | 82 | struct at91_eth_data board_data; /* board-specific configuration */ |
83 | struct clk *ether_clk; /* clock */ | ||
83 | 84 | ||
84 | /* PHY */ | 85 | /* PHY */ |
85 | unsigned long phy_type; /* type of PHY (PHY_ID) */ | 86 | unsigned long phy_type; /* type of PHY (PHY_ID) */ |
diff --git a/drivers/net/b44.c b/drivers/net/b44.c index d8233e0b7899..a7e4ba5a580f 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c | |||
@@ -29,8 +29,8 @@ | |||
29 | 29 | ||
30 | #define DRV_MODULE_NAME "b44" | 30 | #define DRV_MODULE_NAME "b44" |
31 | #define PFX DRV_MODULE_NAME ": " | 31 | #define PFX DRV_MODULE_NAME ": " |
32 | #define DRV_MODULE_VERSION "1.00" | 32 | #define DRV_MODULE_VERSION "1.01" |
33 | #define DRV_MODULE_RELDATE "Apr 7, 2006" | 33 | #define DRV_MODULE_RELDATE "Jun 16, 2006" |
34 | 34 | ||
35 | #define B44_DEF_MSG_ENABLE \ | 35 | #define B44_DEF_MSG_ENABLE \ |
36 | (NETIF_MSG_DRV | \ | 36 | (NETIF_MSG_DRV | \ |
@@ -75,6 +75,15 @@ | |||
75 | /* minimum number of free TX descriptors required to wake up TX process */ | 75 | /* minimum number of free TX descriptors required to wake up TX process */ |
76 | #define B44_TX_WAKEUP_THRESH (B44_TX_RING_SIZE / 4) | 76 | #define B44_TX_WAKEUP_THRESH (B44_TX_RING_SIZE / 4) |
77 | 77 | ||
78 | /* b44 internal pattern match filter info */ | ||
79 | #define B44_PATTERN_BASE 0x400 | ||
80 | #define B44_PATTERN_SIZE 0x80 | ||
81 | #define B44_PMASK_BASE 0x600 | ||
82 | #define B44_PMASK_SIZE 0x10 | ||
83 | #define B44_MAX_PATTERNS 16 | ||
84 | #define B44_ETHIPV6UDP_HLEN 62 | ||
85 | #define B44_ETHIPV4UDP_HLEN 42 | ||
86 | |||
78 | static char version[] __devinitdata = | 87 | static char version[] __devinitdata = |
79 | DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; | 88 | DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; |
80 | 89 | ||
@@ -101,7 +110,7 @@ MODULE_DEVICE_TABLE(pci, b44_pci_tbl); | |||
101 | 110 | ||
102 | static void b44_halt(struct b44 *); | 111 | static void b44_halt(struct b44 *); |
103 | static void b44_init_rings(struct b44 *); | 112 | static void b44_init_rings(struct b44 *); |
104 | static void b44_init_hw(struct b44 *); | 113 | static void b44_init_hw(struct b44 *, int); |
105 | 114 | ||
106 | static int dma_desc_align_mask; | 115 | static int dma_desc_align_mask; |
107 | static int dma_desc_sync_size; | 116 | static int dma_desc_sync_size; |
@@ -873,7 +882,7 @@ static int b44_poll(struct net_device *netdev, int *budget) | |||
873 | spin_lock_irq(&bp->lock); | 882 | spin_lock_irq(&bp->lock); |
874 | b44_halt(bp); | 883 | b44_halt(bp); |
875 | b44_init_rings(bp); | 884 | b44_init_rings(bp); |
876 | b44_init_hw(bp); | 885 | b44_init_hw(bp, 1); |
877 | netif_wake_queue(bp->dev); | 886 | netif_wake_queue(bp->dev); |
878 | spin_unlock_irq(&bp->lock); | 887 | spin_unlock_irq(&bp->lock); |
879 | done = 1; | 888 | done = 1; |
@@ -942,7 +951,7 @@ static void b44_tx_timeout(struct net_device *dev) | |||
942 | 951 | ||
943 | b44_halt(bp); | 952 | b44_halt(bp); |
944 | b44_init_rings(bp); | 953 | b44_init_rings(bp); |
945 | b44_init_hw(bp); | 954 | b44_init_hw(bp, 1); |
946 | 955 | ||
947 | spin_unlock_irq(&bp->lock); | 956 | spin_unlock_irq(&bp->lock); |
948 | 957 | ||
@@ -1059,7 +1068,7 @@ static int b44_change_mtu(struct net_device *dev, int new_mtu) | |||
1059 | b44_halt(bp); | 1068 | b44_halt(bp); |
1060 | dev->mtu = new_mtu; | 1069 | dev->mtu = new_mtu; |
1061 | b44_init_rings(bp); | 1070 | b44_init_rings(bp); |
1062 | b44_init_hw(bp); | 1071 | b44_init_hw(bp, 1); |
1063 | spin_unlock_irq(&bp->lock); | 1072 | spin_unlock_irq(&bp->lock); |
1064 | 1073 | ||
1065 | b44_enable_ints(bp); | 1074 | b44_enable_ints(bp); |
@@ -1356,13 +1365,15 @@ static int b44_set_mac_addr(struct net_device *dev, void *p) | |||
1356 | * packet processing. Invoked with bp->lock held. | 1365 | * packet processing. Invoked with bp->lock held. |
1357 | */ | 1366 | */ |
1358 | static void __b44_set_rx_mode(struct net_device *); | 1367 | static void __b44_set_rx_mode(struct net_device *); |
1359 | static void b44_init_hw(struct b44 *bp) | 1368 | static void b44_init_hw(struct b44 *bp, int full_reset) |
1360 | { | 1369 | { |
1361 | u32 val; | 1370 | u32 val; |
1362 | 1371 | ||
1363 | b44_chip_reset(bp); | 1372 | b44_chip_reset(bp); |
1364 | b44_phy_reset(bp); | 1373 | if (full_reset) { |
1365 | b44_setup_phy(bp); | 1374 | b44_phy_reset(bp); |
1375 | b44_setup_phy(bp); | ||
1376 | } | ||
1366 | 1377 | ||
1367 | /* Enable CRC32, set proper LED modes and power on PHY */ | 1378 | /* Enable CRC32, set proper LED modes and power on PHY */ |
1368 | bw32(bp, B44_MAC_CTRL, MAC_CTRL_CRC32_ENAB | MAC_CTRL_PHY_LEDCTRL); | 1379 | bw32(bp, B44_MAC_CTRL, MAC_CTRL_CRC32_ENAB | MAC_CTRL_PHY_LEDCTRL); |
@@ -1376,16 +1387,21 @@ static void b44_init_hw(struct b44 *bp) | |||
1376 | bw32(bp, B44_TXMAXLEN, bp->dev->mtu + ETH_HLEN + 8 + RX_HEADER_LEN); | 1387 | bw32(bp, B44_TXMAXLEN, bp->dev->mtu + ETH_HLEN + 8 + RX_HEADER_LEN); |
1377 | 1388 | ||
1378 | bw32(bp, B44_TX_WMARK, 56); /* XXX magic */ | 1389 | bw32(bp, B44_TX_WMARK, 56); /* XXX magic */ |
1379 | bw32(bp, B44_DMATX_CTRL, DMATX_CTRL_ENABLE); | 1390 | if (full_reset) { |
1380 | bw32(bp, B44_DMATX_ADDR, bp->tx_ring_dma + bp->dma_offset); | 1391 | bw32(bp, B44_DMATX_CTRL, DMATX_CTRL_ENABLE); |
1381 | bw32(bp, B44_DMARX_CTRL, (DMARX_CTRL_ENABLE | | 1392 | bw32(bp, B44_DMATX_ADDR, bp->tx_ring_dma + bp->dma_offset); |
1382 | (bp->rx_offset << DMARX_CTRL_ROSHIFT))); | 1393 | bw32(bp, B44_DMARX_CTRL, (DMARX_CTRL_ENABLE | |
1383 | bw32(bp, B44_DMARX_ADDR, bp->rx_ring_dma + bp->dma_offset); | 1394 | (bp->rx_offset << DMARX_CTRL_ROSHIFT))); |
1395 | bw32(bp, B44_DMARX_ADDR, bp->rx_ring_dma + bp->dma_offset); | ||
1384 | 1396 | ||
1385 | bw32(bp, B44_DMARX_PTR, bp->rx_pending); | 1397 | bw32(bp, B44_DMARX_PTR, bp->rx_pending); |
1386 | bp->rx_prod = bp->rx_pending; | 1398 | bp->rx_prod = bp->rx_pending; |
1387 | 1399 | ||
1388 | bw32(bp, B44_MIB_CTRL, MIB_CTRL_CLR_ON_READ); | 1400 | bw32(bp, B44_MIB_CTRL, MIB_CTRL_CLR_ON_READ); |
1401 | } else { | ||
1402 | bw32(bp, B44_DMARX_CTRL, (DMARX_CTRL_ENABLE | | ||
1403 | (bp->rx_offset << DMARX_CTRL_ROSHIFT))); | ||
1404 | } | ||
1389 | 1405 | ||
1390 | val = br32(bp, B44_ENET_CTRL); | 1406 | val = br32(bp, B44_ENET_CTRL); |
1391 | bw32(bp, B44_ENET_CTRL, (val | ENET_CTRL_ENABLE)); | 1407 | bw32(bp, B44_ENET_CTRL, (val | ENET_CTRL_ENABLE)); |
@@ -1401,7 +1417,7 @@ static int b44_open(struct net_device *dev) | |||
1401 | goto out; | 1417 | goto out; |
1402 | 1418 | ||
1403 | b44_init_rings(bp); | 1419 | b44_init_rings(bp); |
1404 | b44_init_hw(bp); | 1420 | b44_init_hw(bp, 1); |
1405 | 1421 | ||
1406 | b44_check_phy(bp); | 1422 | b44_check_phy(bp); |
1407 | 1423 | ||
@@ -1450,6 +1466,140 @@ static void b44_poll_controller(struct net_device *dev) | |||
1450 | } | 1466 | } |
1451 | #endif | 1467 | #endif |
1452 | 1468 | ||
1469 | static void bwfilter_table(struct b44 *bp, u8 *pp, u32 bytes, u32 table_offset) | ||
1470 | { | ||
1471 | u32 i; | ||
1472 | u32 *pattern = (u32 *) pp; | ||
1473 | |||
1474 | for (i = 0; i < bytes; i += sizeof(u32)) { | ||
1475 | bw32(bp, B44_FILT_ADDR, table_offset + i); | ||
1476 | bw32(bp, B44_FILT_DATA, pattern[i / sizeof(u32)]); | ||
1477 | } | ||
1478 | } | ||
1479 | |||
1480 | static int b44_magic_pattern(u8 *macaddr, u8 *ppattern, u8 *pmask, int offset) | ||
1481 | { | ||
1482 | int magicsync = 6; | ||
1483 | int k, j, len = offset; | ||
1484 | int ethaddr_bytes = ETH_ALEN; | ||
1485 | |||
1486 | memset(ppattern + offset, 0xff, magicsync); | ||
1487 | for (j = 0; j < magicsync; j++) | ||
1488 | set_bit(len++, (unsigned long *) pmask); | ||
1489 | |||
1490 | for (j = 0; j < B44_MAX_PATTERNS; j++) { | ||
1491 | if ((B44_PATTERN_SIZE - len) >= ETH_ALEN) | ||
1492 | ethaddr_bytes = ETH_ALEN; | ||
1493 | else | ||
1494 | ethaddr_bytes = B44_PATTERN_SIZE - len; | ||
1495 | if (ethaddr_bytes <=0) | ||
1496 | break; | ||
1497 | for (k = 0; k< ethaddr_bytes; k++) { | ||
1498 | ppattern[offset + magicsync + | ||
1499 | (j * ETH_ALEN) + k] = macaddr[k]; | ||
1500 | len++; | ||
1501 | set_bit(len, (unsigned long *) pmask); | ||
1502 | } | ||
1503 | } | ||
1504 | return len - 1; | ||
1505 | } | ||
1506 | |||
1507 | /* Setup magic packet patterns in the b44 WOL | ||
1508 | * pattern matching filter. | ||
1509 | */ | ||
1510 | static void b44_setup_pseudo_magicp(struct b44 *bp) | ||
1511 | { | ||
1512 | |||
1513 | u32 val; | ||
1514 | int plen0, plen1, plen2; | ||
1515 | u8 *pwol_pattern; | ||
1516 | u8 pwol_mask[B44_PMASK_SIZE]; | ||
1517 | |||
1518 | pwol_pattern = kmalloc(B44_PATTERN_SIZE, GFP_KERNEL); | ||
1519 | if (!pwol_pattern) { | ||
1520 | printk(KERN_ERR PFX "Memory not available for WOL\n"); | ||
1521 | return; | ||
1522 | } | ||
1523 | |||
1524 | /* Ipv4 magic packet pattern - pattern 0.*/ | ||
1525 | memset(pwol_pattern, 0, B44_PATTERN_SIZE); | ||
1526 | memset(pwol_mask, 0, B44_PMASK_SIZE); | ||
1527 | plen0 = b44_magic_pattern(bp->dev->dev_addr, pwol_pattern, pwol_mask, | ||
1528 | B44_ETHIPV4UDP_HLEN); | ||
1529 | |||
1530 | bwfilter_table(bp, pwol_pattern, B44_PATTERN_SIZE, B44_PATTERN_BASE); | ||
1531 | bwfilter_table(bp, pwol_mask, B44_PMASK_SIZE, B44_PMASK_BASE); | ||
1532 | |||
1533 | /* Raw ethernet II magic packet pattern - pattern 1 */ | ||
1534 | memset(pwol_pattern, 0, B44_PATTERN_SIZE); | ||
1535 | memset(pwol_mask, 0, B44_PMASK_SIZE); | ||
1536 | plen1 = b44_magic_pattern(bp->dev->dev_addr, pwol_pattern, pwol_mask, | ||
1537 | ETH_HLEN); | ||
1538 | |||
1539 | bwfilter_table(bp, pwol_pattern, B44_PATTERN_SIZE, | ||
1540 | B44_PATTERN_BASE + B44_PATTERN_SIZE); | ||
1541 | bwfilter_table(bp, pwol_mask, B44_PMASK_SIZE, | ||
1542 | B44_PMASK_BASE + B44_PMASK_SIZE); | ||
1543 | |||
1544 | /* Ipv6 magic packet pattern - pattern 2 */ | ||
1545 | memset(pwol_pattern, 0, B44_PATTERN_SIZE); | ||
1546 | memset(pwol_mask, 0, B44_PMASK_SIZE); | ||
1547 | plen2 = b44_magic_pattern(bp->dev->dev_addr, pwol_pattern, pwol_mask, | ||
1548 | B44_ETHIPV6UDP_HLEN); | ||
1549 | |||
1550 | bwfilter_table(bp, pwol_pattern, B44_PATTERN_SIZE, | ||
1551 | B44_PATTERN_BASE + B44_PATTERN_SIZE + B44_PATTERN_SIZE); | ||
1552 | bwfilter_table(bp, pwol_mask, B44_PMASK_SIZE, | ||
1553 | B44_PMASK_BASE + B44_PMASK_SIZE + B44_PMASK_SIZE); | ||
1554 | |||
1555 | kfree(pwol_pattern); | ||
1556 | |||
1557 | /* set these pattern's lengths: one less than each real length */ | ||
1558 | val = plen0 | (plen1 << 8) | (plen2 << 16) | WKUP_LEN_ENABLE_THREE; | ||
1559 | bw32(bp, B44_WKUP_LEN, val); | ||
1560 | |||
1561 | /* enable wakeup pattern matching */ | ||
1562 | val = br32(bp, B44_DEVCTRL); | ||
1563 | bw32(bp, B44_DEVCTRL, val | DEVCTRL_PFE); | ||
1564 | |||
1565 | } | ||
1566 | |||
1567 | static void b44_setup_wol(struct b44 *bp) | ||
1568 | { | ||
1569 | u32 val; | ||
1570 | u16 pmval; | ||
1571 | |||
1572 | bw32(bp, B44_RXCONFIG, RXCONFIG_ALLMULTI); | ||
1573 | |||
1574 | if (bp->flags & B44_FLAG_B0_ANDLATER) { | ||
1575 | |||
1576 | bw32(bp, B44_WKUP_LEN, WKUP_LEN_DISABLE); | ||
1577 | |||
1578 | val = bp->dev->dev_addr[2] << 24 | | ||
1579 | bp->dev->dev_addr[3] << 16 | | ||
1580 | bp->dev->dev_addr[4] << 8 | | ||
1581 | bp->dev->dev_addr[5]; | ||
1582 | bw32(bp, B44_ADDR_LO, val); | ||
1583 | |||
1584 | val = bp->dev->dev_addr[0] << 8 | | ||
1585 | bp->dev->dev_addr[1]; | ||
1586 | bw32(bp, B44_ADDR_HI, val); | ||
1587 | |||
1588 | val = br32(bp, B44_DEVCTRL); | ||
1589 | bw32(bp, B44_DEVCTRL, val | DEVCTRL_MPM | DEVCTRL_PFE); | ||
1590 | |||
1591 | } else { | ||
1592 | b44_setup_pseudo_magicp(bp); | ||
1593 | } | ||
1594 | |||
1595 | val = br32(bp, B44_SBTMSLOW); | ||
1596 | bw32(bp, B44_SBTMSLOW, val | SBTMSLOW_PE); | ||
1597 | |||
1598 | pci_read_config_word(bp->pdev, SSB_PMCSR, &pmval); | ||
1599 | pci_write_config_word(bp->pdev, SSB_PMCSR, pmval | SSB_PE); | ||
1600 | |||
1601 | } | ||
1602 | |||
1453 | static int b44_close(struct net_device *dev) | 1603 | static int b44_close(struct net_device *dev) |
1454 | { | 1604 | { |
1455 | struct b44 *bp = netdev_priv(dev); | 1605 | struct b44 *bp = netdev_priv(dev); |
@@ -1475,6 +1625,11 @@ static int b44_close(struct net_device *dev) | |||
1475 | 1625 | ||
1476 | netif_poll_enable(dev); | 1626 | netif_poll_enable(dev); |
1477 | 1627 | ||
1628 | if (bp->flags & B44_FLAG_WOL_ENABLE) { | ||
1629 | b44_init_hw(bp, 0); | ||
1630 | b44_setup_wol(bp); | ||
1631 | } | ||
1632 | |||
1478 | b44_free_consistent(bp); | 1633 | b44_free_consistent(bp); |
1479 | 1634 | ||
1480 | return 0; | 1635 | return 0; |
@@ -1620,8 +1775,6 @@ static int b44_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) | |||
1620 | { | 1775 | { |
1621 | struct b44 *bp = netdev_priv(dev); | 1776 | struct b44 *bp = netdev_priv(dev); |
1622 | 1777 | ||
1623 | if (!netif_running(dev)) | ||
1624 | return -EAGAIN; | ||
1625 | cmd->supported = (SUPPORTED_Autoneg); | 1778 | cmd->supported = (SUPPORTED_Autoneg); |
1626 | cmd->supported |= (SUPPORTED_100baseT_Half | | 1779 | cmd->supported |= (SUPPORTED_100baseT_Half | |
1627 | SUPPORTED_100baseT_Full | | 1780 | SUPPORTED_100baseT_Full | |
@@ -1649,6 +1802,12 @@ static int b44_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) | |||
1649 | XCVR_INTERNAL : XCVR_EXTERNAL; | 1802 | XCVR_INTERNAL : XCVR_EXTERNAL; |
1650 | cmd->autoneg = (bp->flags & B44_FLAG_FORCE_LINK) ? | 1803 | cmd->autoneg = (bp->flags & B44_FLAG_FORCE_LINK) ? |
1651 | AUTONEG_DISABLE : AUTONEG_ENABLE; | 1804 | AUTONEG_DISABLE : AUTONEG_ENABLE; |
1805 | if (cmd->autoneg == AUTONEG_ENABLE) | ||
1806 | cmd->advertising |= ADVERTISED_Autoneg; | ||
1807 | if (!netif_running(dev)){ | ||
1808 | cmd->speed = 0; | ||
1809 | cmd->duplex = 0xff; | ||
1810 | } | ||
1652 | cmd->maxtxpkt = 0; | 1811 | cmd->maxtxpkt = 0; |
1653 | cmd->maxrxpkt = 0; | 1812 | cmd->maxrxpkt = 0; |
1654 | return 0; | 1813 | return 0; |
@@ -1658,9 +1817,6 @@ static int b44_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) | |||
1658 | { | 1817 | { |
1659 | struct b44 *bp = netdev_priv(dev); | 1818 | struct b44 *bp = netdev_priv(dev); |
1660 | 1819 | ||
1661 | if (!netif_running(dev)) | ||
1662 | return -EAGAIN; | ||
1663 | |||
1664 | /* We do not support gigabit. */ | 1820 | /* We do not support gigabit. */ |
1665 | if (cmd->autoneg == AUTONEG_ENABLE) { | 1821 | if (cmd->autoneg == AUTONEG_ENABLE) { |
1666 | if (cmd->advertising & | 1822 | if (cmd->advertising & |
@@ -1677,28 +1833,39 @@ static int b44_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) | |||
1677 | spin_lock_irq(&bp->lock); | 1833 | spin_lock_irq(&bp->lock); |
1678 | 1834 | ||
1679 | if (cmd->autoneg == AUTONEG_ENABLE) { | 1835 | if (cmd->autoneg == AUTONEG_ENABLE) { |
1680 | bp->flags &= ~B44_FLAG_FORCE_LINK; | 1836 | bp->flags &= ~(B44_FLAG_FORCE_LINK | |
1681 | bp->flags &= ~(B44_FLAG_ADV_10HALF | | 1837 | B44_FLAG_100_BASE_T | |
1838 | B44_FLAG_FULL_DUPLEX | | ||
1839 | B44_FLAG_ADV_10HALF | | ||
1682 | B44_FLAG_ADV_10FULL | | 1840 | B44_FLAG_ADV_10FULL | |
1683 | B44_FLAG_ADV_100HALF | | 1841 | B44_FLAG_ADV_100HALF | |
1684 | B44_FLAG_ADV_100FULL); | 1842 | B44_FLAG_ADV_100FULL); |
1685 | if (cmd->advertising & ADVERTISE_10HALF) | 1843 | if (cmd->advertising == 0) { |
1686 | bp->flags |= B44_FLAG_ADV_10HALF; | 1844 | bp->flags |= (B44_FLAG_ADV_10HALF | |
1687 | if (cmd->advertising & ADVERTISE_10FULL) | 1845 | B44_FLAG_ADV_10FULL | |
1688 | bp->flags |= B44_FLAG_ADV_10FULL; | 1846 | B44_FLAG_ADV_100HALF | |
1689 | if (cmd->advertising & ADVERTISE_100HALF) | 1847 | B44_FLAG_ADV_100FULL); |
1690 | bp->flags |= B44_FLAG_ADV_100HALF; | 1848 | } else { |
1691 | if (cmd->advertising & ADVERTISE_100FULL) | 1849 | if (cmd->advertising & ADVERTISED_10baseT_Half) |
1692 | bp->flags |= B44_FLAG_ADV_100FULL; | 1850 | bp->flags |= B44_FLAG_ADV_10HALF; |
1851 | if (cmd->advertising & ADVERTISED_10baseT_Full) | ||
1852 | bp->flags |= B44_FLAG_ADV_10FULL; | ||
1853 | if (cmd->advertising & ADVERTISED_100baseT_Half) | ||
1854 | bp->flags |= B44_FLAG_ADV_100HALF; | ||
1855 | if (cmd->advertising & ADVERTISED_100baseT_Full) | ||
1856 | bp->flags |= B44_FLAG_ADV_100FULL; | ||
1857 | } | ||
1693 | } else { | 1858 | } else { |
1694 | bp->flags |= B44_FLAG_FORCE_LINK; | 1859 | bp->flags |= B44_FLAG_FORCE_LINK; |
1860 | bp->flags &= ~(B44_FLAG_100_BASE_T | B44_FLAG_FULL_DUPLEX); | ||
1695 | if (cmd->speed == SPEED_100) | 1861 | if (cmd->speed == SPEED_100) |
1696 | bp->flags |= B44_FLAG_100_BASE_T; | 1862 | bp->flags |= B44_FLAG_100_BASE_T; |
1697 | if (cmd->duplex == DUPLEX_FULL) | 1863 | if (cmd->duplex == DUPLEX_FULL) |
1698 | bp->flags |= B44_FLAG_FULL_DUPLEX; | 1864 | bp->flags |= B44_FLAG_FULL_DUPLEX; |
1699 | } | 1865 | } |
1700 | 1866 | ||
1701 | b44_setup_phy(bp); | 1867 | if (netif_running(dev)) |
1868 | b44_setup_phy(bp); | ||
1702 | 1869 | ||
1703 | spin_unlock_irq(&bp->lock); | 1870 | spin_unlock_irq(&bp->lock); |
1704 | 1871 | ||
@@ -1734,7 +1901,7 @@ static int b44_set_ringparam(struct net_device *dev, | |||
1734 | 1901 | ||
1735 | b44_halt(bp); | 1902 | b44_halt(bp); |
1736 | b44_init_rings(bp); | 1903 | b44_init_rings(bp); |
1737 | b44_init_hw(bp); | 1904 | b44_init_hw(bp, 1); |
1738 | netif_wake_queue(bp->dev); | 1905 | netif_wake_queue(bp->dev); |
1739 | spin_unlock_irq(&bp->lock); | 1906 | spin_unlock_irq(&bp->lock); |
1740 | 1907 | ||
@@ -1777,7 +1944,7 @@ static int b44_set_pauseparam(struct net_device *dev, | |||
1777 | if (bp->flags & B44_FLAG_PAUSE_AUTO) { | 1944 | if (bp->flags & B44_FLAG_PAUSE_AUTO) { |
1778 | b44_halt(bp); | 1945 | b44_halt(bp); |
1779 | b44_init_rings(bp); | 1946 | b44_init_rings(bp); |
1780 | b44_init_hw(bp); | 1947 | b44_init_hw(bp, 1); |
1781 | } else { | 1948 | } else { |
1782 | __b44_set_flow_ctrl(bp, bp->flags); | 1949 | __b44_set_flow_ctrl(bp, bp->flags); |
1783 | } | 1950 | } |
@@ -1819,12 +1986,40 @@ static void b44_get_ethtool_stats(struct net_device *dev, | |||
1819 | spin_unlock_irq(&bp->lock); | 1986 | spin_unlock_irq(&bp->lock); |
1820 | } | 1987 | } |
1821 | 1988 | ||
1989 | static void b44_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) | ||
1990 | { | ||
1991 | struct b44 *bp = netdev_priv(dev); | ||
1992 | |||
1993 | wol->supported = WAKE_MAGIC; | ||
1994 | if (bp->flags & B44_FLAG_WOL_ENABLE) | ||
1995 | wol->wolopts = WAKE_MAGIC; | ||
1996 | else | ||
1997 | wol->wolopts = 0; | ||
1998 | memset(&wol->sopass, 0, sizeof(wol->sopass)); | ||
1999 | } | ||
2000 | |||
2001 | static int b44_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) | ||
2002 | { | ||
2003 | struct b44 *bp = netdev_priv(dev); | ||
2004 | |||
2005 | spin_lock_irq(&bp->lock); | ||
2006 | if (wol->wolopts & WAKE_MAGIC) | ||
2007 | bp->flags |= B44_FLAG_WOL_ENABLE; | ||
2008 | else | ||
2009 | bp->flags &= ~B44_FLAG_WOL_ENABLE; | ||
2010 | spin_unlock_irq(&bp->lock); | ||
2011 | |||
2012 | return 0; | ||
2013 | } | ||
2014 | |||
1822 | static struct ethtool_ops b44_ethtool_ops = { | 2015 | static struct ethtool_ops b44_ethtool_ops = { |
1823 | .get_drvinfo = b44_get_drvinfo, | 2016 | .get_drvinfo = b44_get_drvinfo, |
1824 | .get_settings = b44_get_settings, | 2017 | .get_settings = b44_get_settings, |
1825 | .set_settings = b44_set_settings, | 2018 | .set_settings = b44_set_settings, |
1826 | .nway_reset = b44_nway_reset, | 2019 | .nway_reset = b44_nway_reset, |
1827 | .get_link = ethtool_op_get_link, | 2020 | .get_link = ethtool_op_get_link, |
2021 | .get_wol = b44_get_wol, | ||
2022 | .set_wol = b44_set_wol, | ||
1828 | .get_ringparam = b44_get_ringparam, | 2023 | .get_ringparam = b44_get_ringparam, |
1829 | .set_ringparam = b44_set_ringparam, | 2024 | .set_ringparam = b44_set_ringparam, |
1830 | .get_pauseparam = b44_get_pauseparam, | 2025 | .get_pauseparam = b44_get_pauseparam, |
@@ -1903,6 +2098,10 @@ static int __devinit b44_get_invariants(struct b44 *bp) | |||
1903 | /* XXX - really required? | 2098 | /* XXX - really required? |
1904 | bp->flags |= B44_FLAG_BUGGY_TXPTR; | 2099 | bp->flags |= B44_FLAG_BUGGY_TXPTR; |
1905 | */ | 2100 | */ |
2101 | |||
2102 | if (ssb_get_core_rev(bp) >= 7) | ||
2103 | bp->flags |= B44_FLAG_B0_ANDLATER; | ||
2104 | |||
1906 | out: | 2105 | out: |
1907 | return err; | 2106 | return err; |
1908 | } | 2107 | } |
@@ -2103,6 +2302,10 @@ static int b44_suspend(struct pci_dev *pdev, pm_message_t state) | |||
2103 | spin_unlock_irq(&bp->lock); | 2302 | spin_unlock_irq(&bp->lock); |
2104 | 2303 | ||
2105 | free_irq(dev->irq, dev); | 2304 | free_irq(dev->irq, dev); |
2305 | if (bp->flags & B44_FLAG_WOL_ENABLE) { | ||
2306 | b44_init_hw(bp, 0); | ||
2307 | b44_setup_wol(bp); | ||
2308 | } | ||
2106 | pci_disable_device(pdev); | 2309 | pci_disable_device(pdev); |
2107 | return 0; | 2310 | return 0; |
2108 | } | 2311 | } |
@@ -2125,7 +2328,7 @@ static int b44_resume(struct pci_dev *pdev) | |||
2125 | spin_lock_irq(&bp->lock); | 2328 | spin_lock_irq(&bp->lock); |
2126 | 2329 | ||
2127 | b44_init_rings(bp); | 2330 | b44_init_rings(bp); |
2128 | b44_init_hw(bp); | 2331 | b44_init_hw(bp, 1); |
2129 | netif_device_attach(bp->dev); | 2332 | netif_device_attach(bp->dev); |
2130 | spin_unlock_irq(&bp->lock); | 2333 | spin_unlock_irq(&bp->lock); |
2131 | 2334 | ||
diff --git a/drivers/net/b44.h b/drivers/net/b44.h index b178662978f3..4944507fad23 100644 --- a/drivers/net/b44.h +++ b/drivers/net/b44.h | |||
@@ -24,6 +24,9 @@ | |||
24 | #define WKUP_LEN_P3_MASK 0x7f000000 /* Pattern 3 */ | 24 | #define WKUP_LEN_P3_MASK 0x7f000000 /* Pattern 3 */ |
25 | #define WKUP_LEN_P3_SHIFT 24 | 25 | #define WKUP_LEN_P3_SHIFT 24 |
26 | #define WKUP_LEN_D3 0x80000000 | 26 | #define WKUP_LEN_D3 0x80000000 |
27 | #define WKUP_LEN_DISABLE 0x80808080 | ||
28 | #define WKUP_LEN_ENABLE_TWO 0x80800000 | ||
29 | #define WKUP_LEN_ENABLE_THREE 0x80000000 | ||
27 | #define B44_ISTAT 0x0020UL /* Interrupt Status */ | 30 | #define B44_ISTAT 0x0020UL /* Interrupt Status */ |
28 | #define ISTAT_LS 0x00000020 /* Link Change (B0 only) */ | 31 | #define ISTAT_LS 0x00000020 /* Link Change (B0 only) */ |
29 | #define ISTAT_PME 0x00000040 /* Power Management Event */ | 32 | #define ISTAT_PME 0x00000040 /* Power Management Event */ |
@@ -264,6 +267,8 @@ | |||
264 | #define SBIDHIGH_VC_SHIFT 16 | 267 | #define SBIDHIGH_VC_SHIFT 16 |
265 | 268 | ||
266 | /* SSB PCI config space registers. */ | 269 | /* SSB PCI config space registers. */ |
270 | #define SSB_PMCSR 0x44 | ||
271 | #define SSB_PE 0x100 | ||
267 | #define SSB_BAR0_WIN 0x80 | 272 | #define SSB_BAR0_WIN 0x80 |
268 | #define SSB_BAR1_WIN 0x84 | 273 | #define SSB_BAR1_WIN 0x84 |
269 | #define SSB_SPROM_CONTROL 0x88 | 274 | #define SSB_SPROM_CONTROL 0x88 |
@@ -420,6 +425,7 @@ struct b44 { | |||
420 | 425 | ||
421 | u32 dma_offset; | 426 | u32 dma_offset; |
422 | u32 flags; | 427 | u32 flags; |
428 | #define B44_FLAG_B0_ANDLATER 0x00000001 | ||
423 | #define B44_FLAG_BUGGY_TXPTR 0x00000002 | 429 | #define B44_FLAG_BUGGY_TXPTR 0x00000002 |
424 | #define B44_FLAG_REORDER_BUG 0x00000004 | 430 | #define B44_FLAG_REORDER_BUG 0x00000004 |
425 | #define B44_FLAG_PAUSE_AUTO 0x00008000 | 431 | #define B44_FLAG_PAUSE_AUTO 0x00008000 |
@@ -435,6 +441,7 @@ struct b44 { | |||
435 | #define B44_FLAG_INTERNAL_PHY 0x10000000 | 441 | #define B44_FLAG_INTERNAL_PHY 0x10000000 |
436 | #define B44_FLAG_RX_RING_HACK 0x20000000 | 442 | #define B44_FLAG_RX_RING_HACK 0x20000000 |
437 | #define B44_FLAG_TX_RING_HACK 0x40000000 | 443 | #define B44_FLAG_TX_RING_HACK 0x40000000 |
444 | #define B44_FLAG_WOL_ENABLE 0x80000000 | ||
438 | 445 | ||
439 | u32 rx_offset; | 446 | u32 rx_offset; |
440 | 447 | ||
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 62b38a4494b8..191383d461d7 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c | |||
@@ -2076,7 +2076,7 @@ static void nv_set_multicast(struct net_device *dev) | |||
2076 | spin_unlock_irq(&np->lock); | 2076 | spin_unlock_irq(&np->lock); |
2077 | } | 2077 | } |
2078 | 2078 | ||
2079 | void nv_update_pause(struct net_device *dev, u32 pause_flags) | 2079 | static void nv_update_pause(struct net_device *dev, u32 pause_flags) |
2080 | { | 2080 | { |
2081 | struct fe_priv *np = netdev_priv(dev); | 2081 | struct fe_priv *np = netdev_priv(dev); |
2082 | u8 __iomem *base = get_hwbase(dev); | 2082 | u8 __iomem *base = get_hwbase(dev); |
diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 666346f6469e..4c2e7279ba34 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c | |||
@@ -61,7 +61,7 @@ | |||
61 | #undef DEBUG | 61 | #undef DEBUG |
62 | 62 | ||
63 | #define ibmveth_printk(fmt, args...) \ | 63 | #define ibmveth_printk(fmt, args...) \ |
64 | printk(KERN_INFO "%s: " fmt, __FILE__, ## args) | 64 | printk(KERN_DEBUG "%s: " fmt, __FILE__, ## args) |
65 | 65 | ||
66 | #define ibmveth_error_printk(fmt, args...) \ | 66 | #define ibmveth_error_printk(fmt, args...) \ |
67 | printk(KERN_ERR "(%s:%3.3d ua:%x) ERROR: " fmt, __FILE__, __LINE__ , adapter->vdev->unit_address, ## args) | 67 | printk(KERN_ERR "(%s:%3.3d ua:%x) ERROR: " fmt, __FILE__, __LINE__ , adapter->vdev->unit_address, ## args) |
diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c index ae71ed57c12d..e76e6e7be0b1 100644 --- a/drivers/net/ioc3-eth.c +++ b/drivers/net/ioc3-eth.c | |||
@@ -145,7 +145,7 @@ static inline struct sk_buff * ioc3_alloc_skb(unsigned long length, | |||
145 | static inline unsigned long ioc3_map(void *ptr, unsigned long vdev) | 145 | static inline unsigned long ioc3_map(void *ptr, unsigned long vdev) |
146 | { | 146 | { |
147 | #ifdef CONFIG_SGI_IP27 | 147 | #ifdef CONFIG_SGI_IP27 |
148 | vdev <<= 58; /* Shift to PCI64_ATTR_VIRTUAL */ | 148 | vdev <<= 57; /* Shift to PCI64_ATTR_VIRTUAL */ |
149 | 149 | ||
150 | return vdev | (0xaUL << PCI64_ATTR_TARG_SHFT) | PCI64_ATTR_PREF | | 150 | return vdev | (0xaUL << PCI64_ATTR_TARG_SHFT) | PCI64_ATTR_PREF | |
151 | ((unsigned long)ptr & TO_PHYS_MASK); | 151 | ((unsigned long)ptr & TO_PHYS_MASK); |
diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c index f0f04be989d6..93394d76587a 100644 --- a/drivers/net/iseries_veth.c +++ b/drivers/net/iseries_veth.c | |||
@@ -69,6 +69,7 @@ | |||
69 | #include <linux/delay.h> | 69 | #include <linux/delay.h> |
70 | #include <linux/mm.h> | 70 | #include <linux/mm.h> |
71 | #include <linux/ethtool.h> | 71 | #include <linux/ethtool.h> |
72 | #include <linux/if_ether.h> | ||
72 | 73 | ||
73 | #include <asm/abs_addr.h> | 74 | #include <asm/abs_addr.h> |
74 | #include <asm/iseries/mf.h> | 75 | #include <asm/iseries/mf.h> |
@@ -1035,11 +1036,22 @@ static struct ethtool_ops ops = { | |||
1035 | .get_link = veth_get_link, | 1036 | .get_link = veth_get_link, |
1036 | }; | 1037 | }; |
1037 | 1038 | ||
1038 | static struct net_device * __init veth_probe_one(int vlan, struct device *vdev) | 1039 | static struct net_device * __init veth_probe_one(int vlan, |
1040 | struct vio_dev *vio_dev) | ||
1039 | { | 1041 | { |
1040 | struct net_device *dev; | 1042 | struct net_device *dev; |
1041 | struct veth_port *port; | 1043 | struct veth_port *port; |
1044 | struct device *vdev = &vio_dev->dev; | ||
1042 | int i, rc; | 1045 | int i, rc; |
1046 | const unsigned char *mac_addr; | ||
1047 | |||
1048 | mac_addr = vio_get_attribute(vio_dev, "local-mac-address", NULL); | ||
1049 | if (mac_addr == NULL) | ||
1050 | mac_addr = vio_get_attribute(vio_dev, "mac-address", NULL); | ||
1051 | if (mac_addr == NULL) { | ||
1052 | veth_error("Unable to fetch MAC address from device tree.\n"); | ||
1053 | return NULL; | ||
1054 | } | ||
1043 | 1055 | ||
1044 | dev = alloc_etherdev(sizeof (struct veth_port)); | 1056 | dev = alloc_etherdev(sizeof (struct veth_port)); |
1045 | if (! dev) { | 1057 | if (! dev) { |
@@ -1064,16 +1076,11 @@ static struct net_device * __init veth_probe_one(int vlan, struct device *vdev) | |||
1064 | } | 1076 | } |
1065 | port->dev = vdev; | 1077 | port->dev = vdev; |
1066 | 1078 | ||
1067 | dev->dev_addr[0] = 0x02; | 1079 | memcpy(dev->dev_addr, mac_addr, ETH_ALEN); |
1068 | dev->dev_addr[1] = 0x01; | ||
1069 | dev->dev_addr[2] = 0xff; | ||
1070 | dev->dev_addr[3] = vlan; | ||
1071 | dev->dev_addr[4] = 0xff; | ||
1072 | dev->dev_addr[5] = this_lp; | ||
1073 | 1080 | ||
1074 | dev->mtu = VETH_MAX_MTU; | 1081 | dev->mtu = VETH_MAX_MTU; |
1075 | 1082 | ||
1076 | memcpy(&port->mac_addr, dev->dev_addr, 6); | 1083 | memcpy(&port->mac_addr, mac_addr, ETH_ALEN); |
1077 | 1084 | ||
1078 | dev->open = veth_open; | 1085 | dev->open = veth_open; |
1079 | dev->hard_start_xmit = veth_start_xmit; | 1086 | dev->hard_start_xmit = veth_start_xmit; |
@@ -1608,7 +1615,7 @@ static int veth_probe(struct vio_dev *vdev, const struct vio_device_id *id) | |||
1608 | struct net_device *dev; | 1615 | struct net_device *dev; |
1609 | struct veth_port *port; | 1616 | struct veth_port *port; |
1610 | 1617 | ||
1611 | dev = veth_probe_one(i, &vdev->dev); | 1618 | dev = veth_probe_one(i, vdev); |
1612 | if (dev == NULL) { | 1619 | if (dev == NULL) { |
1613 | veth_remove(vdev); | 1620 | veth_remove(vdev); |
1614 | return 1; | 1621 | return 1; |
@@ -1641,7 +1648,7 @@ static int veth_probe(struct vio_dev *vdev, const struct vio_device_id *id) | |||
1641 | * support. | 1648 | * support. |
1642 | */ | 1649 | */ |
1643 | static struct vio_device_id veth_device_table[] __devinitdata = { | 1650 | static struct vio_device_id veth_device_table[] __devinitdata = { |
1644 | { "vlan", "" }, | 1651 | { "network", "IBM,iSeries-l-lan" }, |
1645 | { "", "" } | 1652 | { "", "" } |
1646 | }; | 1653 | }; |
1647 | MODULE_DEVICE_TABLE(vio, veth_device_table); | 1654 | MODULE_DEVICE_TABLE(vio, veth_device_table); |
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index e1feb58bd661..5a74f63618bc 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c | |||
@@ -2120,7 +2120,7 @@ abort_linearize: | |||
2120 | goto drop; | 2120 | goto drop; |
2121 | } | 2121 | } |
2122 | 2122 | ||
2123 | if (skb_linearize(skb, GFP_ATOMIC)) | 2123 | if (skb_linearize(skb)) |
2124 | goto drop; | 2124 | goto drop; |
2125 | 2125 | ||
2126 | mgp->tx_linearized++; | 2126 | mgp->tx_linearized++; |
@@ -2251,12 +2251,6 @@ static void myri10ge_enable_ecrc(struct myri10ge_priv *mgp) | |||
2251 | } | 2251 | } |
2252 | 2252 | ||
2253 | cap = pci_find_ext_capability(bridge, PCI_EXT_CAP_ID_ERR); | 2253 | cap = pci_find_ext_capability(bridge, PCI_EXT_CAP_ID_ERR); |
2254 | /* nvidia ext cap is not always linked in ext cap chain */ | ||
2255 | if (!cap | ||
2256 | && bridge->vendor == PCI_VENDOR_ID_NVIDIA | ||
2257 | && bridge->device == PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_PCIE) | ||
2258 | cap = 0x160; | ||
2259 | |||
2260 | if (!cap) | 2254 | if (!cap) |
2261 | return; | 2255 | return; |
2262 | 2256 | ||
@@ -2732,8 +2726,6 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
2732 | /* Save configuration space to be restored if the | 2726 | /* Save configuration space to be restored if the |
2733 | * nic resets due to a parity error */ | 2727 | * nic resets due to a parity error */ |
2734 | myri10ge_save_state(mgp); | 2728 | myri10ge_save_state(mgp); |
2735 | /* Restore state immediately since pci_save_msi_state disables MSI */ | ||
2736 | myri10ge_restore_state(mgp); | ||
2737 | 2729 | ||
2738 | /* Setup the watchdog timer */ | 2730 | /* Setup the watchdog timer */ |
2739 | setup_timer(&mgp->watchdog_timer, myri10ge_watchdog_timer, | 2731 | setup_timer(&mgp->watchdog_timer, myri10ge_watchdog_timer, |
diff --git a/drivers/net/netx-eth.c b/drivers/net/netx-eth.c new file mode 100644 index 000000000000..b92430c4e3ac --- /dev/null +++ b/drivers/net/netx-eth.c | |||
@@ -0,0 +1,516 @@ | |||
1 | /* | ||
2 | * drivers/net/netx-eth.c | ||
3 | * | ||
4 | * Copyright (c) 2005 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 | ||
8 | * as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | #include <linux/config.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/delay.h> | ||
25 | |||
26 | #include <linux/netdevice.h> | ||
27 | #include <linux/platform_device.h> | ||
28 | #include <linux/etherdevice.h> | ||
29 | #include <linux/skbuff.h> | ||
30 | #include <linux/mii.h> | ||
31 | |||
32 | #include <asm/io.h> | ||
33 | #include <asm/hardware.h> | ||
34 | #include <asm/arch/hardware.h> | ||
35 | #include <asm/arch/netx-regs.h> | ||
36 | #include <asm/arch/pfifo.h> | ||
37 | #include <asm/arch/xc.h> | ||
38 | #include <asm/arch/eth.h> | ||
39 | |||
40 | /* XC Fifo Offsets */ | ||
41 | #define EMPTY_PTR_FIFO(xcno) (0 + ((xcno) << 3)) /* Index of the empty pointer FIFO */ | ||
42 | #define IND_FIFO_PORT_HI(xcno) (1 + ((xcno) << 3)) /* Index of the FIFO where received */ | ||
43 | /* Data packages are indicated by XC */ | ||
44 | #define IND_FIFO_PORT_LO(xcno) (2 + ((xcno) << 3)) /* Index of the FIFO where received */ | ||
45 | /* Data packages are indicated by XC */ | ||
46 | #define REQ_FIFO_PORT_HI(xcno) (3 + ((xcno) << 3)) /* Index of the FIFO where Data packages */ | ||
47 | /* have to be indicated by ARM which */ | ||
48 | /* shall be sent */ | ||
49 | #define REQ_FIFO_PORT_LO(xcno) (4 + ((xcno) << 3)) /* Index of the FIFO where Data packages */ | ||
50 | /* have to be indicated by ARM which shall */ | ||
51 | /* be sent */ | ||
52 | #define CON_FIFO_PORT_HI(xcno) (5 + ((xcno) << 3)) /* Index of the FIFO where sent Data packages */ | ||
53 | /* are confirmed */ | ||
54 | #define CON_FIFO_PORT_LO(xcno) (6 + ((xcno) << 3)) /* Index of the FIFO where sent Data */ | ||
55 | /* packages are confirmed */ | ||
56 | #define PFIFO_MASK(xcno) (0x7f << (xcno*8)) | ||
57 | |||
58 | #define FIFO_PTR_FRAMELEN_SHIFT 0 | ||
59 | #define FIFO_PTR_FRAMELEN_MASK (0x7ff << 0) | ||
60 | #define FIFO_PTR_FRAMELEN(len) (((len) << 0) & FIFO_PTR_FRAMELEN_MASK) | ||
61 | #define FIFO_PTR_TIMETRIG (1<<11) | ||
62 | #define FIFO_PTR_MULTI_REQ | ||
63 | #define FIFO_PTR_ORIGIN (1<<14) | ||
64 | #define FIFO_PTR_VLAN (1<<15) | ||
65 | #define FIFO_PTR_FRAMENO_SHIFT 16 | ||
66 | #define FIFO_PTR_FRAMENO_MASK (0x3f << 16) | ||
67 | #define FIFO_PTR_FRAMENO(no) (((no) << 16) & FIFO_PTR_FRAMENO_MASK) | ||
68 | #define FIFO_PTR_SEGMENT_SHIFT 22 | ||
69 | #define FIFO_PTR_SEGMENT_MASK (0xf << 22) | ||
70 | #define FIFO_PTR_SEGMENT(seg) (((seg) & 0xf) << 22) | ||
71 | #define FIFO_PTR_ERROR_SHIFT 28 | ||
72 | #define FIFO_PTR_ERROR_MASK (0xf << 28) | ||
73 | |||
74 | #define ISR_LINK_STATUS_CHANGE (1<<4) | ||
75 | #define ISR_IND_LO (1<<3) | ||
76 | #define ISR_CON_LO (1<<2) | ||
77 | #define ISR_IND_HI (1<<1) | ||
78 | #define ISR_CON_HI (1<<0) | ||
79 | |||
80 | #define ETH_MAC_LOCAL_CONFIG 0x1560 | ||
81 | #define ETH_MAC_4321 0x1564 | ||
82 | #define ETH_MAC_65 0x1568 | ||
83 | |||
84 | #define MAC_TRAFFIC_CLASS_ARRANGEMENT_SHIFT 16 | ||
85 | #define MAC_TRAFFIC_CLASS_ARRANGEMENT_MASK (0xf<<MAC_TRAFFIC_CLASS_ARRANGEMENT_SHIFT) | ||
86 | #define MAC_TRAFFIC_CLASS_ARRANGEMENT(x) (((x)<<MAC_TRAFFIC_CLASS_ARRANGEMENT_SHIFT) & MAC_TRAFFIC_CLASS_ARRANGEMENT_MASK) | ||
87 | #define LOCAL_CONFIG_LINK_STATUS_IRQ_EN (1<<24) | ||
88 | #define LOCAL_CONFIG_CON_LO_IRQ_EN (1<<23) | ||
89 | #define LOCAL_CONFIG_CON_HI_IRQ_EN (1<<22) | ||
90 | #define LOCAL_CONFIG_IND_LO_IRQ_EN (1<<21) | ||
91 | #define LOCAL_CONFIG_IND_HI_IRQ_EN (1<<20) | ||
92 | |||
93 | #define CARDNAME "netx-eth" | ||
94 | |||
95 | /* LSB must be zero */ | ||
96 | #define INTERNAL_PHY_ADR 0x1c | ||
97 | |||
98 | struct netx_eth_priv { | ||
99 | void __iomem *sram_base, *xpec_base, *xmac_base; | ||
100 | int id; | ||
101 | struct net_device_stats stats; | ||
102 | struct mii_if_info mii; | ||
103 | u32 msg_enable; | ||
104 | struct xc *xc; | ||
105 | spinlock_t lock; | ||
106 | }; | ||
107 | |||
108 | static void netx_eth_set_multicast_list(struct net_device *ndev) | ||
109 | { | ||
110 | /* implement me */ | ||
111 | } | ||
112 | |||
113 | static int | ||
114 | netx_eth_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev) | ||
115 | { | ||
116 | struct netx_eth_priv *priv = netdev_priv(ndev); | ||
117 | unsigned char *buf = skb->data; | ||
118 | unsigned int len = skb->len; | ||
119 | |||
120 | spin_lock_irq(&priv->lock); | ||
121 | memcpy_toio(priv->sram_base + 1560, (void *)buf, len); | ||
122 | if (len < 60) { | ||
123 | memset_io(priv->sram_base + 1560 + len, 0, 60 - len); | ||
124 | len = 60; | ||
125 | } | ||
126 | |||
127 | pfifo_push(REQ_FIFO_PORT_LO(priv->id), | ||
128 | FIFO_PTR_SEGMENT(priv->id) | | ||
129 | FIFO_PTR_FRAMENO(1) | | ||
130 | FIFO_PTR_FRAMELEN(len)); | ||
131 | |||
132 | ndev->trans_start = jiffies; | ||
133 | priv->stats.tx_packets++; | ||
134 | priv->stats.tx_bytes += skb->len; | ||
135 | |||
136 | netif_stop_queue(ndev); | ||
137 | spin_unlock_irq(&priv->lock); | ||
138 | dev_kfree_skb(skb); | ||
139 | |||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | static void netx_eth_receive(struct net_device *ndev) | ||
144 | { | ||
145 | struct netx_eth_priv *priv = netdev_priv(ndev); | ||
146 | unsigned int val, frameno, seg, len; | ||
147 | unsigned char *data; | ||
148 | struct sk_buff *skb; | ||
149 | |||
150 | val = pfifo_pop(IND_FIFO_PORT_LO(priv->id)); | ||
151 | |||
152 | frameno = (val & FIFO_PTR_FRAMENO_MASK) >> FIFO_PTR_FRAMENO_SHIFT; | ||
153 | seg = (val & FIFO_PTR_SEGMENT_MASK) >> FIFO_PTR_SEGMENT_SHIFT; | ||
154 | len = (val & FIFO_PTR_FRAMELEN_MASK) >> FIFO_PTR_FRAMELEN_SHIFT; | ||
155 | |||
156 | skb = dev_alloc_skb(len); | ||
157 | if (unlikely(skb == NULL)) { | ||
158 | printk(KERN_NOTICE "%s: Low memory, packet dropped.\n", | ||
159 | ndev->name); | ||
160 | priv->stats.rx_dropped++; | ||
161 | return; | ||
162 | } | ||
163 | |||
164 | data = skb_put(skb, len); | ||
165 | |||
166 | memcpy_fromio(data, priv->sram_base + frameno * 1560, len); | ||
167 | |||
168 | pfifo_push(EMPTY_PTR_FIFO(priv->id), | ||
169 | FIFO_PTR_SEGMENT(seg) | FIFO_PTR_FRAMENO(frameno)); | ||
170 | |||
171 | ndev->last_rx = jiffies; | ||
172 | skb->dev = ndev; | ||
173 | skb->protocol = eth_type_trans(skb, ndev); | ||
174 | netif_rx(skb); | ||
175 | priv->stats.rx_packets++; | ||
176 | priv->stats.rx_bytes += len; | ||
177 | } | ||
178 | |||
179 | static irqreturn_t | ||
180 | netx_eth_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
181 | { | ||
182 | struct net_device *ndev = dev_id; | ||
183 | struct netx_eth_priv *priv = netdev_priv(ndev); | ||
184 | int status; | ||
185 | unsigned long flags; | ||
186 | |||
187 | spin_lock_irqsave(&priv->lock, flags); | ||
188 | |||
189 | status = readl(NETX_PFIFO_XPEC_ISR(priv->id)); | ||
190 | while (status) { | ||
191 | int fill_level; | ||
192 | writel(status, NETX_PFIFO_XPEC_ISR(priv->id)); | ||
193 | |||
194 | if ((status & ISR_CON_HI) || (status & ISR_IND_HI)) | ||
195 | printk("%s: unexpected status: 0x%08x\n", | ||
196 | __FUNCTION__, status); | ||
197 | |||
198 | fill_level = | ||
199 | readl(NETX_PFIFO_FILL_LEVEL(IND_FIFO_PORT_LO(priv->id))); | ||
200 | while (fill_level--) | ||
201 | netx_eth_receive(ndev); | ||
202 | |||
203 | if (status & ISR_CON_LO) | ||
204 | netif_wake_queue(ndev); | ||
205 | |||
206 | if (status & ISR_LINK_STATUS_CHANGE) | ||
207 | mii_check_media(&priv->mii, netif_msg_link(priv), 1); | ||
208 | |||
209 | status = readl(NETX_PFIFO_XPEC_ISR(priv->id)); | ||
210 | } | ||
211 | spin_unlock_irqrestore(&priv->lock, flags); | ||
212 | return IRQ_HANDLED; | ||
213 | } | ||
214 | |||
215 | static struct net_device_stats *netx_eth_query_statistics(struct net_device *ndev) | ||
216 | { | ||
217 | struct netx_eth_priv *priv = netdev_priv(ndev); | ||
218 | return &priv->stats; | ||
219 | } | ||
220 | |||
221 | static int netx_eth_open(struct net_device *ndev) | ||
222 | { | ||
223 | struct netx_eth_priv *priv = netdev_priv(ndev); | ||
224 | |||
225 | if (request_irq | ||
226 | (ndev->irq, &netx_eth_interrupt, SA_SHIRQ, ndev->name, ndev)) | ||
227 | return -EAGAIN; | ||
228 | |||
229 | writel(ndev->dev_addr[0] | | ||
230 | ndev->dev_addr[1]<<8 | | ||
231 | ndev->dev_addr[2]<<16 | | ||
232 | ndev->dev_addr[3]<<24, | ||
233 | priv->xpec_base + NETX_XPEC_RAM_START_OFS + ETH_MAC_4321); | ||
234 | writel(ndev->dev_addr[4] | | ||
235 | ndev->dev_addr[5]<<8, | ||
236 | priv->xpec_base + NETX_XPEC_RAM_START_OFS + ETH_MAC_65); | ||
237 | |||
238 | writel(LOCAL_CONFIG_LINK_STATUS_IRQ_EN | | ||
239 | LOCAL_CONFIG_CON_LO_IRQ_EN | | ||
240 | LOCAL_CONFIG_CON_HI_IRQ_EN | | ||
241 | LOCAL_CONFIG_IND_LO_IRQ_EN | | ||
242 | LOCAL_CONFIG_IND_HI_IRQ_EN, | ||
243 | priv->xpec_base + NETX_XPEC_RAM_START_OFS + | ||
244 | ETH_MAC_LOCAL_CONFIG); | ||
245 | |||
246 | mii_check_media(&priv->mii, netif_msg_link(priv), 1); | ||
247 | netif_start_queue(ndev); | ||
248 | |||
249 | return 0; | ||
250 | } | ||
251 | |||
252 | static int netx_eth_close(struct net_device *ndev) | ||
253 | { | ||
254 | struct netx_eth_priv *priv = netdev_priv(ndev); | ||
255 | |||
256 | netif_stop_queue(ndev); | ||
257 | |||
258 | writel(0, | ||
259 | priv->xpec_base + NETX_XPEC_RAM_START_OFS + ETH_MAC_LOCAL_CONFIG); | ||
260 | |||
261 | free_irq(ndev->irq, ndev); | ||
262 | |||
263 | return 0; | ||
264 | } | ||
265 | |||
266 | static void netx_eth_timeout(struct net_device *ndev) | ||
267 | { | ||
268 | struct netx_eth_priv *priv = netdev_priv(ndev); | ||
269 | int i; | ||
270 | |||
271 | printk(KERN_ERR "%s: transmit timed out, resetting\n", ndev->name); | ||
272 | |||
273 | spin_lock_irq(&priv->lock); | ||
274 | |||
275 | xc_reset(priv->xc); | ||
276 | xc_start(priv->xc); | ||
277 | |||
278 | for (i=2; i<=18; i++) | ||
279 | pfifo_push(EMPTY_PTR_FIFO(priv->id), | ||
280 | FIFO_PTR_FRAMENO(i) | FIFO_PTR_SEGMENT(priv->id)); | ||
281 | |||
282 | spin_unlock_irq(&priv->lock); | ||
283 | |||
284 | netif_wake_queue(ndev); | ||
285 | } | ||
286 | |||
287 | static int | ||
288 | netx_eth_phy_read(struct net_device *ndev, int phy_id, int reg) | ||
289 | { | ||
290 | unsigned int val; | ||
291 | |||
292 | val = MIIMU_SNRDY | MIIMU_PREAMBLE | MIIMU_PHYADDR(phy_id) | | ||
293 | MIIMU_REGADDR(reg) | MIIMU_PHY_NRES; | ||
294 | |||
295 | writel(val, NETX_MIIMU); | ||
296 | while (readl(NETX_MIIMU) & MIIMU_SNRDY); | ||
297 | |||
298 | return readl(NETX_MIIMU) >> 16; | ||
299 | |||
300 | } | ||
301 | |||
302 | static void | ||
303 | netx_eth_phy_write(struct net_device *ndev, int phy_id, int reg, int value) | ||
304 | { | ||
305 | unsigned int val; | ||
306 | |||
307 | val = MIIMU_SNRDY | MIIMU_PREAMBLE | MIIMU_PHYADDR(phy_id) | | ||
308 | MIIMU_REGADDR(reg) | MIIMU_PHY_NRES | MIIMU_OPMODE_WRITE | | ||
309 | MIIMU_DATA(value); | ||
310 | |||
311 | writel(val, NETX_MIIMU); | ||
312 | while (readl(NETX_MIIMU) & MIIMU_SNRDY); | ||
313 | } | ||
314 | |||
315 | static int netx_eth_enable(struct net_device *ndev) | ||
316 | { | ||
317 | struct netx_eth_priv *priv = netdev_priv(ndev); | ||
318 | unsigned int mac4321, mac65; | ||
319 | int running, i; | ||
320 | |||
321 | ether_setup(ndev); | ||
322 | |||
323 | ndev->open = netx_eth_open; | ||
324 | ndev->stop = netx_eth_close; | ||
325 | ndev->hard_start_xmit = netx_eth_hard_start_xmit; | ||
326 | ndev->tx_timeout = netx_eth_timeout; | ||
327 | ndev->watchdog_timeo = msecs_to_jiffies(5000); | ||
328 | ndev->get_stats = netx_eth_query_statistics; | ||
329 | ndev->set_multicast_list = netx_eth_set_multicast_list; | ||
330 | |||
331 | priv->msg_enable = NETIF_MSG_LINK; | ||
332 | priv->mii.phy_id_mask = 0x1f; | ||
333 | priv->mii.reg_num_mask = 0x1f; | ||
334 | priv->mii.force_media = 0; | ||
335 | priv->mii.full_duplex = 0; | ||
336 | priv->mii.dev = ndev; | ||
337 | priv->mii.mdio_read = netx_eth_phy_read; | ||
338 | priv->mii.mdio_write = netx_eth_phy_write; | ||
339 | priv->mii.phy_id = INTERNAL_PHY_ADR + priv->id; | ||
340 | |||
341 | running = xc_running(priv->xc); | ||
342 | xc_stop(priv->xc); | ||
343 | |||
344 | /* if the xc engine is already running, assume the bootloader has | ||
345 | * loaded the firmware for us | ||
346 | */ | ||
347 | if (running) { | ||
348 | /* get Node Address from hardware */ | ||
349 | mac4321 = readl(priv->xpec_base + | ||
350 | NETX_XPEC_RAM_START_OFS + ETH_MAC_4321); | ||
351 | mac65 = readl(priv->xpec_base + | ||
352 | NETX_XPEC_RAM_START_OFS + ETH_MAC_65); | ||
353 | |||
354 | ndev->dev_addr[0] = mac4321 & 0xff; | ||
355 | ndev->dev_addr[1] = (mac4321 >> 8) & 0xff; | ||
356 | ndev->dev_addr[2] = (mac4321 >> 16) & 0xff; | ||
357 | ndev->dev_addr[3] = (mac4321 >> 24) & 0xff; | ||
358 | ndev->dev_addr[4] = mac65 & 0xff; | ||
359 | ndev->dev_addr[5] = (mac65 >> 8) & 0xff; | ||
360 | } else { | ||
361 | if (xc_request_firmware(priv->xc)) { | ||
362 | printk(CARDNAME ": requesting firmware failed\n"); | ||
363 | return -ENODEV; | ||
364 | } | ||
365 | } | ||
366 | |||
367 | xc_reset(priv->xc); | ||
368 | xc_start(priv->xc); | ||
369 | |||
370 | if (!is_valid_ether_addr(ndev->dev_addr)) | ||
371 | printk("%s: Invalid ethernet MAC address. Please " | ||
372 | "set using ifconfig\n", ndev->name); | ||
373 | |||
374 | for (i=2; i<=18; i++) | ||
375 | pfifo_push(EMPTY_PTR_FIFO(priv->id), | ||
376 | FIFO_PTR_FRAMENO(i) | FIFO_PTR_SEGMENT(priv->id)); | ||
377 | |||
378 | return register_netdev(ndev); | ||
379 | |||
380 | } | ||
381 | |||
382 | static int netx_eth_drv_probe(struct platform_device *pdev) | ||
383 | { | ||
384 | struct netx_eth_priv *priv; | ||
385 | struct net_device *ndev; | ||
386 | struct netxeth_platform_data *pdata; | ||
387 | int ret; | ||
388 | |||
389 | ndev = alloc_etherdev(sizeof (struct netx_eth_priv)); | ||
390 | if (!ndev) { | ||
391 | printk("%s: could not allocate device.\n", CARDNAME); | ||
392 | ret = -ENOMEM; | ||
393 | goto exit; | ||
394 | } | ||
395 | SET_MODULE_OWNER(ndev); | ||
396 | SET_NETDEV_DEV(ndev, &pdev->dev); | ||
397 | |||
398 | platform_set_drvdata(pdev, ndev); | ||
399 | |||
400 | priv = netdev_priv(ndev); | ||
401 | |||
402 | pdata = (struct netxeth_platform_data *)pdev->dev.platform_data; | ||
403 | priv->xc = request_xc(pdata->xcno, &pdev->dev); | ||
404 | if (!priv->xc) { | ||
405 | dev_err(&pdev->dev, "unable to request xc engine\n"); | ||
406 | ret = -ENODEV; | ||
407 | goto exit_free_netdev; | ||
408 | } | ||
409 | |||
410 | ndev->irq = priv->xc->irq; | ||
411 | priv->id = pdev->id; | ||
412 | priv->xpec_base = priv->xc->xpec_base; | ||
413 | priv->xmac_base = priv->xc->xmac_base; | ||
414 | priv->sram_base = priv->xc->sram_base; | ||
415 | |||
416 | ret = pfifo_request(PFIFO_MASK(priv->id)); | ||
417 | if (ret) { | ||
418 | printk("unable to request PFIFO\n"); | ||
419 | goto exit_free_xc; | ||
420 | } | ||
421 | |||
422 | ret = netx_eth_enable(ndev); | ||
423 | if (ret) | ||
424 | goto exit_free_pfifo; | ||
425 | |||
426 | return 0; | ||
427 | exit_free_pfifo: | ||
428 | pfifo_free(PFIFO_MASK(priv->id)); | ||
429 | exit_free_xc: | ||
430 | free_xc(priv->xc); | ||
431 | exit_free_netdev: | ||
432 | platform_set_drvdata(pdev, NULL); | ||
433 | free_netdev(ndev); | ||
434 | exit: | ||
435 | return ret; | ||
436 | } | ||
437 | |||
438 | static int netx_eth_drv_remove(struct platform_device *pdev) | ||
439 | { | ||
440 | struct net_device *ndev = dev_get_drvdata(&pdev->dev); | ||
441 | struct netx_eth_priv *priv = netdev_priv(ndev); | ||
442 | |||
443 | platform_set_drvdata(pdev, NULL); | ||
444 | |||
445 | unregister_netdev(ndev); | ||
446 | xc_stop(priv->xc); | ||
447 | free_xc(priv->xc); | ||
448 | free_netdev(ndev); | ||
449 | pfifo_free(PFIFO_MASK(priv->id)); | ||
450 | |||
451 | return 0; | ||
452 | } | ||
453 | |||
454 | static int netx_eth_drv_suspend(struct platform_device *pdev, pm_message_t state) | ||
455 | { | ||
456 | dev_err(&pdev->dev, "suspend not implemented\n"); | ||
457 | return 0; | ||
458 | } | ||
459 | |||
460 | static int netx_eth_drv_resume(struct platform_device *pdev) | ||
461 | { | ||
462 | dev_err(&pdev->dev, "resume not implemented\n"); | ||
463 | return 0; | ||
464 | } | ||
465 | |||
466 | static struct platform_driver netx_eth_driver = { | ||
467 | .probe = netx_eth_drv_probe, | ||
468 | .remove = netx_eth_drv_remove, | ||
469 | .suspend = netx_eth_drv_suspend, | ||
470 | .resume = netx_eth_drv_resume, | ||
471 | .driver = { | ||
472 | .name = CARDNAME, | ||
473 | .owner = THIS_MODULE, | ||
474 | }, | ||
475 | }; | ||
476 | |||
477 | static int __init netx_eth_init(void) | ||
478 | { | ||
479 | unsigned int phy_control, val; | ||
480 | |||
481 | printk("NetX Ethernet driver\n"); | ||
482 | |||
483 | phy_control = PHY_CONTROL_PHY_ADDRESS(INTERNAL_PHY_ADR>>1) | | ||
484 | PHY_CONTROL_PHY1_MODE(PHY_MODE_ALL) | | ||
485 | PHY_CONTROL_PHY1_AUTOMDIX | | ||
486 | PHY_CONTROL_PHY1_EN | | ||
487 | PHY_CONTROL_PHY0_MODE(PHY_MODE_ALL) | | ||
488 | PHY_CONTROL_PHY0_AUTOMDIX | | ||
489 | PHY_CONTROL_PHY0_EN | | ||
490 | PHY_CONTROL_CLK_XLATIN; | ||
491 | |||
492 | val = readl(NETX_SYSTEM_IOC_ACCESS_KEY); | ||
493 | writel(val, NETX_SYSTEM_IOC_ACCESS_KEY); | ||
494 | |||
495 | writel(phy_control | PHY_CONTROL_RESET, NETX_SYSTEM_PHY_CONTROL); | ||
496 | udelay(100); | ||
497 | |||
498 | val = readl(NETX_SYSTEM_IOC_ACCESS_KEY); | ||
499 | writel(val, NETX_SYSTEM_IOC_ACCESS_KEY); | ||
500 | |||
501 | writel(phy_control, NETX_SYSTEM_PHY_CONTROL); | ||
502 | |||
503 | return platform_driver_register(&netx_eth_driver); | ||
504 | } | ||
505 | |||
506 | static void __exit netx_eth_cleanup(void) | ||
507 | { | ||
508 | platform_driver_unregister(&netx_eth_driver); | ||
509 | } | ||
510 | |||
511 | module_init(netx_eth_init); | ||
512 | module_exit(netx_eth_cleanup); | ||
513 | |||
514 | MODULE_AUTHOR("Sascha Hauer, Pengutronix"); | ||
515 | MODULE_LICENSE("GPL"); | ||
516 | |||
diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index 71f45056a70c..e80d1e3aec68 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c | |||
@@ -1359,7 +1359,7 @@ do_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1359 | kio_addr_t ioaddr = dev->base_addr; | 1359 | kio_addr_t ioaddr = dev->base_addr; |
1360 | int okay; | 1360 | int okay; |
1361 | unsigned freespace; | 1361 | unsigned freespace; |
1362 | unsigned pktlen = skb? skb->len : 0; | 1362 | unsigned pktlen = skb->len; |
1363 | 1363 | ||
1364 | DEBUG(1, "do_start_xmit(skb=%p, dev=%p) len=%u\n", | 1364 | DEBUG(1, "do_start_xmit(skb=%p, dev=%p) len=%u\n", |
1365 | skb, dev, pktlen); | 1365 | skb, dev, pktlen); |
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index cda3e53d6917..2ba6d3a40e2e 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig | |||
@@ -44,6 +44,11 @@ config CICADA_PHY | |||
44 | depends on PHYLIB | 44 | depends on PHYLIB |
45 | ---help--- | 45 | ---help--- |
46 | Currently supports the cis8204 | 46 | Currently supports the cis8204 |
47 | config VITESSE_PHY | ||
48 | tristate "Drivers for the Vitesse PHYs" | ||
49 | depends on PHYLIB | ||
50 | ---help--- | ||
51 | Currently supports the vsc8244 | ||
47 | 52 | ||
48 | config SMSC_PHY | 53 | config SMSC_PHY |
49 | tristate "Drivers for SMSC PHYs" | 54 | tristate "Drivers for SMSC PHYs" |
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index d9614134cc06..a00e61942525 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile | |||
@@ -9,3 +9,4 @@ obj-$(CONFIG_CICADA_PHY) += cicada.o | |||
9 | obj-$(CONFIG_LXT_PHY) += lxt.o | 9 | obj-$(CONFIG_LXT_PHY) += lxt.o |
10 | obj-$(CONFIG_QSEMI_PHY) += qsemi.o | 10 | obj-$(CONFIG_QSEMI_PHY) += qsemi.o |
11 | obj-$(CONFIG_SMSC_PHY) += smsc.o | 11 | obj-$(CONFIG_SMSC_PHY) += smsc.o |
12 | obj-$(CONFIG_VITESSE_PHY) += vitesse.o | ||
diff --git a/drivers/net/phy/vitesse.c b/drivers/net/phy/vitesse.c new file mode 100644 index 000000000000..ffd215d9a9be --- /dev/null +++ b/drivers/net/phy/vitesse.c | |||
@@ -0,0 +1,112 @@ | |||
1 | /* | ||
2 | * Driver for Vitesse PHYs | ||
3 | * | ||
4 | * Author: Kriston Carson | ||
5 | * | ||
6 | * Copyright (c) 2005 Freescale Semiconductor, Inc. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #include <linux/config.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/mii.h> | ||
19 | #include <linux/ethtool.h> | ||
20 | #include <linux/phy.h> | ||
21 | |||
22 | /* Vitesse Extended Control Register 1 */ | ||
23 | #define MII_VSC8244_EXT_CON1 0x17 | ||
24 | #define MII_VSC8244_EXTCON1_INIT 0x0000 | ||
25 | |||
26 | /* Vitesse Interrupt Mask Register */ | ||
27 | #define MII_VSC8244_IMASK 0x19 | ||
28 | #define MII_VSC8244_IMASK_IEN 0x8000 | ||
29 | #define MII_VSC8244_IMASK_SPEED 0x4000 | ||
30 | #define MII_VSC8244_IMASK_LINK 0x2000 | ||
31 | #define MII_VSC8244_IMASK_DUPLEX 0x1000 | ||
32 | #define MII_VSC8244_IMASK_MASK 0xf000 | ||
33 | |||
34 | /* Vitesse Interrupt Status Register */ | ||
35 | #define MII_VSC8244_ISTAT 0x1a | ||
36 | #define MII_VSC8244_ISTAT_STATUS 0x8000 | ||
37 | #define MII_VSC8244_ISTAT_SPEED 0x4000 | ||
38 | #define MII_VSC8244_ISTAT_LINK 0x2000 | ||
39 | #define MII_VSC8244_ISTAT_DUPLEX 0x1000 | ||
40 | |||
41 | /* Vitesse Auxiliary Control/Status Register */ | ||
42 | #define MII_VSC8244_AUX_CONSTAT 0x1c | ||
43 | #define MII_VSC8244_AUXCONSTAT_INIT 0x0004 | ||
44 | #define MII_VSC8244_AUXCONSTAT_DUPLEX 0x0020 | ||
45 | #define MII_VSC8244_AUXCONSTAT_SPEED 0x0018 | ||
46 | #define MII_VSC8244_AUXCONSTAT_GBIT 0x0010 | ||
47 | #define MII_VSC8244_AUXCONSTAT_100 0x0008 | ||
48 | |||
49 | MODULE_DESCRIPTION("Vitesse PHY driver"); | ||
50 | MODULE_AUTHOR("Kriston Carson"); | ||
51 | MODULE_LICENSE("GPL"); | ||
52 | |||
53 | static int vsc824x_config_init(struct phy_device *phydev) | ||
54 | { | ||
55 | int err; | ||
56 | |||
57 | err = phy_write(phydev, MII_VSC8244_AUX_CONSTAT, | ||
58 | MII_VSC8244_AUXCONSTAT_INIT); | ||
59 | if (err < 0) | ||
60 | return err; | ||
61 | |||
62 | err = phy_write(phydev, MII_VSC8244_EXT_CON1, | ||
63 | MII_VSC8244_EXTCON1_INIT); | ||
64 | return err; | ||
65 | } | ||
66 | |||
67 | static int vsc824x_ack_interrupt(struct phy_device *phydev) | ||
68 | { | ||
69 | int err = phy_read(phydev, MII_VSC8244_ISTAT); | ||
70 | |||
71 | return (err < 0) ? err : 0; | ||
72 | } | ||
73 | |||
74 | static int vsc824x_config_intr(struct phy_device *phydev) | ||
75 | { | ||
76 | int err; | ||
77 | |||
78 | if (phydev->interrupts == PHY_INTERRUPT_ENABLED) | ||
79 | err = phy_write(phydev, MII_VSC8244_IMASK, | ||
80 | MII_VSC8244_IMASK_MASK); | ||
81 | else | ||
82 | err = phy_write(phydev, MII_VSC8244_IMASK, 0); | ||
83 | return err; | ||
84 | } | ||
85 | |||
86 | /* Vitesse 824x */ | ||
87 | static struct phy_driver vsc8244_driver = { | ||
88 | .phy_id = 0x000fc6c2, | ||
89 | .name = "Vitesse VSC8244", | ||
90 | .phy_id_mask = 0x000fffc0, | ||
91 | .features = PHY_GBIT_FEATURES, | ||
92 | .flags = PHY_HAS_INTERRUPT, | ||
93 | .config_init = &vsc824x_config_init, | ||
94 | .config_aneg = &genphy_config_aneg, | ||
95 | .read_status = &genphy_read_status, | ||
96 | .ack_interrupt = &vsc824x_ack_interrupt, | ||
97 | .config_intr = &vsc824x_config_intr, | ||
98 | .driver = { .owner = THIS_MODULE,}, | ||
99 | }; | ||
100 | |||
101 | static int __init vsc8244_init(void) | ||
102 | { | ||
103 | return phy_driver_register(&vsc8244_driver); | ||
104 | } | ||
105 | |||
106 | static void __exit vsc8244_exit(void) | ||
107 | { | ||
108 | phy_driver_unregister(&vsc8244_driver); | ||
109 | } | ||
110 | |||
111 | module_init(vsc8244_init); | ||
112 | module_exit(vsc8244_exit); | ||
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index cac9fdd2e1d5..11daed495b97 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c | |||
@@ -2627,6 +2627,50 @@ no_rx: | |||
2627 | #endif | 2627 | #endif |
2628 | 2628 | ||
2629 | /** | 2629 | /** |
2630 | * s2io_netpoll - Rx interrupt service handler for netpoll support | ||
2631 | * @dev : pointer to the device structure. | ||
2632 | * Description: | ||
2633 | * Polling 'interrupt' - used by things like netconsole to send skbs | ||
2634 | * without having to re-enable interrupts. It's not called while | ||
2635 | * the interrupt routine is executing. | ||
2636 | */ | ||
2637 | |||
2638 | #ifdef CONFIG_NET_POLL_CONTROLLER | ||
2639 | static void s2io_netpoll(struct net_device *dev) | ||
2640 | { | ||
2641 | nic_t *nic = dev->priv; | ||
2642 | mac_info_t *mac_control; | ||
2643 | struct config_param *config; | ||
2644 | XENA_dev_config_t __iomem *bar0 = nic->bar0; | ||
2645 | u64 val64; | ||
2646 | int i; | ||
2647 | |||
2648 | disable_irq(dev->irq); | ||
2649 | |||
2650 | atomic_inc(&nic->isr_cnt); | ||
2651 | mac_control = &nic->mac_control; | ||
2652 | config = &nic->config; | ||
2653 | |||
2654 | val64 = readq(&bar0->rx_traffic_int); | ||
2655 | writeq(val64, &bar0->rx_traffic_int); | ||
2656 | |||
2657 | for (i = 0; i < config->rx_ring_num; i++) | ||
2658 | rx_intr_handler(&mac_control->rings[i]); | ||
2659 | |||
2660 | for (i = 0; i < config->rx_ring_num; i++) { | ||
2661 | if (fill_rx_buffers(nic, i) == -ENOMEM) { | ||
2662 | DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name); | ||
2663 | DBG_PRINT(ERR_DBG, " in Rx Netpoll!!\n"); | ||
2664 | break; | ||
2665 | } | ||
2666 | } | ||
2667 | atomic_dec(&nic->isr_cnt); | ||
2668 | enable_irq(dev->irq); | ||
2669 | return; | ||
2670 | } | ||
2671 | #endif | ||
2672 | |||
2673 | /** | ||
2630 | * rx_intr_handler - Rx interrupt handler | 2674 | * rx_intr_handler - Rx interrupt handler |
2631 | * @nic: device private variable. | 2675 | * @nic: device private variable. |
2632 | * Description: | 2676 | * Description: |
@@ -6967,6 +7011,10 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) | |||
6967 | dev->weight = 32; | 7011 | dev->weight = 32; |
6968 | #endif | 7012 | #endif |
6969 | 7013 | ||
7014 | #ifdef CONFIG_NET_POLL_CONTROLLER | ||
7015 | dev->poll_controller = s2io_netpoll; | ||
7016 | #endif | ||
7017 | |||
6970 | dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; | 7018 | dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; |
6971 | if (sp->high_dma_flag == TRUE) | 7019 | if (sp->high_dma_flag == TRUE) |
6972 | dev->features |= NETIF_F_HIGHDMA; | 7020 | dev->features |= NETIF_F_HIGHDMA; |
diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index 61eec46cb111..f13b2a195c70 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c | |||
@@ -94,11 +94,13 @@ | |||
94 | Version LK1.10 (Philippe De Muyter phdm@macqel.be): | 94 | Version LK1.10 (Philippe De Muyter phdm@macqel.be): |
95 | - Make 'unblock interface after Tx underrun' work | 95 | - Make 'unblock interface after Tx underrun' work |
96 | 96 | ||
97 | Version LK1.11 (Pedro Alejandro Lopez-Valencia palopezv at gmail.com): | ||
98 | - Add support for IC Plus Corporation IP100A chipset | ||
97 | */ | 99 | */ |
98 | 100 | ||
99 | #define DRV_NAME "sundance" | 101 | #define DRV_NAME "sundance" |
100 | #define DRV_VERSION "1.01+LK1.10" | 102 | #define DRV_VERSION "1.01+LK1.11" |
101 | #define DRV_RELDATE "28-Oct-2005" | 103 | #define DRV_RELDATE "14-Jun-2006" |
102 | 104 | ||
103 | 105 | ||
104 | /* The user-configurable values. | 106 | /* The user-configurable values. |
@@ -287,6 +289,7 @@ static struct pci_device_id sundance_pci_tbl[] = { | |||
287 | {0x1186, 0x1002, 0x1186, 0x1040, 0, 0, 3}, | 289 | {0x1186, 0x1002, 0x1186, 0x1040, 0, 0, 3}, |
288 | {0x1186, 0x1002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4}, | 290 | {0x1186, 0x1002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4}, |
289 | {0x13F0, 0x0201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5}, | 291 | {0x13F0, 0x0201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5}, |
292 | {0x13F0, 0x0200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6}, | ||
290 | {0,} | 293 | {0,} |
291 | }; | 294 | }; |
292 | MODULE_DEVICE_TABLE(pci, sundance_pci_tbl); | 295 | MODULE_DEVICE_TABLE(pci, sundance_pci_tbl); |
@@ -305,6 +308,7 @@ static const struct pci_id_info pci_id_tbl[] = { | |||
305 | {"D-Link DFE-530TXS FAST Ethernet Adapter"}, | 308 | {"D-Link DFE-530TXS FAST Ethernet Adapter"}, |
306 | {"D-Link DL10050-based FAST Ethernet Adapter"}, | 309 | {"D-Link DL10050-based FAST Ethernet Adapter"}, |
307 | {"Sundance Technology Alta"}, | 310 | {"Sundance Technology Alta"}, |
311 | {"IC Plus Corporation IP100A FAST Ethernet Adapter"}, | ||
308 | {NULL,}, /* 0 terminated list. */ | 312 | {NULL,}, /* 0 terminated list. */ |
309 | }; | 313 | }; |
310 | 314 | ||
diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c index 23032a7bc0a9..c3cb8d26cfe3 100644 --- a/drivers/net/tokenring/olympic.c +++ b/drivers/net/tokenring/olympic.c | |||
@@ -217,7 +217,7 @@ static int __devinit olympic_probe(struct pci_dev *pdev, const struct pci_device | |||
217 | dev = alloc_trdev(sizeof(struct olympic_private)) ; | 217 | dev = alloc_trdev(sizeof(struct olympic_private)) ; |
218 | if (!dev) { | 218 | if (!dev) { |
219 | i = -ENOMEM; | 219 | i = -ENOMEM; |
220 | goto op_free_dev; | 220 | goto op_release_dev; |
221 | } | 221 | } |
222 | 222 | ||
223 | olympic_priv = dev->priv ; | 223 | olympic_priv = dev->priv ; |
@@ -282,8 +282,8 @@ op_free_iomap: | |||
282 | if (olympic_priv->olympic_lap) | 282 | if (olympic_priv->olympic_lap) |
283 | iounmap(olympic_priv->olympic_lap); | 283 | iounmap(olympic_priv->olympic_lap); |
284 | 284 | ||
285 | op_free_dev: | ||
286 | free_netdev(dev); | 285 | free_netdev(dev); |
286 | op_release_dev: | ||
287 | pci_release_regions(pdev); | 287 | pci_release_regions(pdev); |
288 | 288 | ||
289 | op_disable_dev: | 289 | op_disable_dev: |
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index 2eb6b5f9ba0d..09e05fe40c38 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c | |||
@@ -248,6 +248,7 @@ static void velocity_free_rd_ring(struct velocity_info *vptr); | |||
248 | static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_info *); | 248 | static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_info *); |
249 | static int velocity_soft_reset(struct velocity_info *vptr); | 249 | static int velocity_soft_reset(struct velocity_info *vptr); |
250 | static void mii_init(struct velocity_info *vptr, u32 mii_status); | 250 | static void mii_init(struct velocity_info *vptr, u32 mii_status); |
251 | static u32 velocity_get_link(struct net_device *dev); | ||
251 | static u32 velocity_get_opt_media_mode(struct velocity_info *vptr); | 252 | static u32 velocity_get_opt_media_mode(struct velocity_info *vptr); |
252 | static void velocity_print_link_status(struct velocity_info *vptr); | 253 | static void velocity_print_link_status(struct velocity_info *vptr); |
253 | static void safe_disable_mii_autopoll(struct mac_regs __iomem * regs); | 254 | static void safe_disable_mii_autopoll(struct mac_regs __iomem * regs); |
@@ -798,6 +799,9 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi | |||
798 | if (ret < 0) | 799 | if (ret < 0) |
799 | goto err_iounmap; | 800 | goto err_iounmap; |
800 | 801 | ||
802 | if (velocity_get_link(dev)) | ||
803 | netif_carrier_off(dev); | ||
804 | |||
801 | velocity_print_info(vptr); | 805 | velocity_print_info(vptr); |
802 | pci_set_drvdata(pdev, dev); | 806 | pci_set_drvdata(pdev, dev); |
803 | 807 | ||
@@ -1653,8 +1657,10 @@ static void velocity_error(struct velocity_info *vptr, int status) | |||
1653 | 1657 | ||
1654 | if (linked) { | 1658 | if (linked) { |
1655 | vptr->mii_status &= ~VELOCITY_LINK_FAIL; | 1659 | vptr->mii_status &= ~VELOCITY_LINK_FAIL; |
1660 | netif_carrier_on(vptr->dev); | ||
1656 | } else { | 1661 | } else { |
1657 | vptr->mii_status |= VELOCITY_LINK_FAIL; | 1662 | vptr->mii_status |= VELOCITY_LINK_FAIL; |
1663 | netif_carrier_off(vptr->dev); | ||
1658 | } | 1664 | } |
1659 | 1665 | ||
1660 | velocity_print_link_status(vptr); | 1666 | velocity_print_link_status(vptr); |
diff --git a/drivers/net/wan/c101.c b/drivers/net/wan/c101.c index 43d854ace233..b60ef02db7b0 100644 --- a/drivers/net/wan/c101.c +++ b/drivers/net/wan/c101.c | |||
@@ -326,21 +326,21 @@ static int __init c101_run(unsigned long irq, unsigned long winbase) | |||
326 | if (request_irq(irq, sca_intr, 0, devname, card)) { | 326 | if (request_irq(irq, sca_intr, 0, devname, card)) { |
327 | printk(KERN_ERR "c101: could not allocate IRQ\n"); | 327 | printk(KERN_ERR "c101: could not allocate IRQ\n"); |
328 | c101_destroy_card(card); | 328 | c101_destroy_card(card); |
329 | return(-EBUSY); | 329 | return -EBUSY; |
330 | } | 330 | } |
331 | card->irq = irq; | 331 | card->irq = irq; |
332 | 332 | ||
333 | if (!request_mem_region(winbase, C101_MAPPED_RAM_SIZE, devname)) { | 333 | if (!request_mem_region(winbase, C101_MAPPED_RAM_SIZE, devname)) { |
334 | printk(KERN_ERR "c101: could not request RAM window\n"); | 334 | printk(KERN_ERR "c101: could not request RAM window\n"); |
335 | c101_destroy_card(card); | 335 | c101_destroy_card(card); |
336 | return(-EBUSY); | 336 | return -EBUSY; |
337 | } | 337 | } |
338 | card->phy_winbase = winbase; | 338 | card->phy_winbase = winbase; |
339 | card->win0base = ioremap(winbase, C101_MAPPED_RAM_SIZE); | 339 | card->win0base = ioremap(winbase, C101_MAPPED_RAM_SIZE); |
340 | if (!card->win0base) { | 340 | if (!card->win0base) { |
341 | printk(KERN_ERR "c101: could not map I/O address\n"); | 341 | printk(KERN_ERR "c101: could not map I/O address\n"); |
342 | c101_destroy_card(card); | 342 | c101_destroy_card(card); |
343 | return -EBUSY; | 343 | return -EFAULT; |
344 | } | 344 | } |
345 | 345 | ||
346 | card->tx_ring_buffers = TX_RING_BUFFERS; | 346 | card->tx_ring_buffers = TX_RING_BUFFERS; |
diff --git a/drivers/net/wan/hdlc_generic.c b/drivers/net/wan/hdlc_generic.c index 46cef8f92133..57f9538b8fb5 100644 --- a/drivers/net/wan/hdlc_generic.c +++ b/drivers/net/wan/hdlc_generic.c | |||
@@ -259,7 +259,7 @@ int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | |||
259 | } | 259 | } |
260 | } | 260 | } |
261 | 261 | ||
262 | static void hdlc_setup(struct net_device *dev) | 262 | void hdlc_setup(struct net_device *dev) |
263 | { | 263 | { |
264 | hdlc_device *hdlc = dev_to_hdlc(dev); | 264 | hdlc_device *hdlc = dev_to_hdlc(dev); |
265 | 265 | ||
@@ -288,26 +288,6 @@ struct net_device *alloc_hdlcdev(void *priv) | |||
288 | return dev; | 288 | return dev; |
289 | } | 289 | } |
290 | 290 | ||
291 | int register_hdlc_device(struct net_device *dev) | ||
292 | { | ||
293 | int result = dev_alloc_name(dev, "hdlc%d"); | ||
294 | if (result < 0) | ||
295 | return result; | ||
296 | |||
297 | result = register_netdev(dev); | ||
298 | if (result != 0) | ||
299 | return -EIO; | ||
300 | |||
301 | #if 0 | ||
302 | if (netif_carrier_ok(dev)) | ||
303 | netif_carrier_off(dev); /* no carrier until DCD goes up */ | ||
304 | #endif | ||
305 | |||
306 | return 0; | ||
307 | } | ||
308 | |||
309 | |||
310 | |||
311 | void unregister_hdlc_device(struct net_device *dev) | 291 | void unregister_hdlc_device(struct net_device *dev) |
312 | { | 292 | { |
313 | rtnl_lock(); | 293 | rtnl_lock(); |
@@ -326,8 +306,8 @@ EXPORT_SYMBOL(hdlc_open); | |||
326 | EXPORT_SYMBOL(hdlc_close); | 306 | EXPORT_SYMBOL(hdlc_close); |
327 | EXPORT_SYMBOL(hdlc_set_carrier); | 307 | EXPORT_SYMBOL(hdlc_set_carrier); |
328 | EXPORT_SYMBOL(hdlc_ioctl); | 308 | EXPORT_SYMBOL(hdlc_ioctl); |
309 | EXPORT_SYMBOL(hdlc_setup); | ||
329 | EXPORT_SYMBOL(alloc_hdlcdev); | 310 | EXPORT_SYMBOL(alloc_hdlcdev); |
330 | EXPORT_SYMBOL(register_hdlc_device); | ||
331 | EXPORT_SYMBOL(unregister_hdlc_device); | 311 | EXPORT_SYMBOL(unregister_hdlc_device); |
332 | 312 | ||
333 | static struct packet_type hdlc_packet_type = { | 313 | static struct packet_type hdlc_packet_type = { |
diff --git a/drivers/net/wan/n2.c b/drivers/net/wan/n2.c index cd32751b64eb..b7d88db89a5c 100644 --- a/drivers/net/wan/n2.c +++ b/drivers/net/wan/n2.c | |||
@@ -387,6 +387,11 @@ static int __init n2_run(unsigned long io, unsigned long irq, | |||
387 | } | 387 | } |
388 | card->phy_winbase = winbase; | 388 | card->phy_winbase = winbase; |
389 | card->winbase = ioremap(winbase, USE_WINDOWSIZE); | 389 | card->winbase = ioremap(winbase, USE_WINDOWSIZE); |
390 | if (!card->winbase) { | ||
391 | printk(KERN_ERR "n2: ioremap() failed\n"); | ||
392 | n2_destroy_card(card); | ||
393 | return -EFAULT; | ||
394 | } | ||
390 | 395 | ||
391 | outb(0, io + N2_PCR); | 396 | outb(0, io + N2_PCR); |
392 | outb(winbase >> 12, io + N2_BAR); | 397 | outb(winbase >> 12, io + N2_BAR); |
diff --git a/drivers/net/wan/pci200syn.c b/drivers/net/wan/pci200syn.c index f485a97844cc..670e8bd2245c 100644 --- a/drivers/net/wan/pci200syn.c +++ b/drivers/net/wan/pci200syn.c | |||
@@ -354,6 +354,7 @@ static int __devinit pci200_pci_init_one(struct pci_dev *pdev, | |||
354 | card->rambase == NULL) { | 354 | card->rambase == NULL) { |
355 | printk(KERN_ERR "pci200syn: ioremap() failed\n"); | 355 | printk(KERN_ERR "pci200syn: ioremap() failed\n"); |
356 | pci200_pci_remove_one(pdev); | 356 | pci200_pci_remove_one(pdev); |
357 | return -EFAULT; | ||
357 | } | 358 | } |
358 | 359 | ||
359 | /* Reset PLX */ | 360 | /* Reset PLX */ |
diff --git a/drivers/net/wan/wanxl.c b/drivers/net/wan/wanxl.c index 29a756dd979b..437e0e938e38 100644 --- a/drivers/net/wan/wanxl.c +++ b/drivers/net/wan/wanxl.c | |||
@@ -634,7 +634,13 @@ static int __devinit wanxl_pci_init_one(struct pci_dev *pdev, | |||
634 | 634 | ||
635 | /* set up PLX mapping */ | 635 | /* set up PLX mapping */ |
636 | plx_phy = pci_resource_start(pdev, 0); | 636 | plx_phy = pci_resource_start(pdev, 0); |
637 | |||
637 | card->plx = ioremap_nocache(plx_phy, 0x70); | 638 | card->plx = ioremap_nocache(plx_phy, 0x70); |
639 | if (!card->plx) { | ||
640 | printk(KERN_ERR "wanxl: ioremap() failed\n"); | ||
641 | wanxl_pci_remove_one(pdev); | ||
642 | return -EFAULT; | ||
643 | } | ||
638 | 644 | ||
639 | #if RESET_WHILE_LOADING | 645 | #if RESET_WHILE_LOADING |
640 | wanxl_reset(card); | 646 | wanxl_reset(card); |
@@ -700,6 +706,12 @@ static int __devinit wanxl_pci_init_one(struct pci_dev *pdev, | |||
700 | } | 706 | } |
701 | 707 | ||
702 | mem = ioremap_nocache(mem_phy, PDM_OFFSET + sizeof(firmware)); | 708 | mem = ioremap_nocache(mem_phy, PDM_OFFSET + sizeof(firmware)); |
709 | if (!mem) { | ||
710 | printk(KERN_ERR "wanxl: ioremap() failed\n"); | ||
711 | wanxl_pci_remove_one(pdev); | ||
712 | return -EFAULT; | ||
713 | } | ||
714 | |||
703 | for (i = 0; i < sizeof(firmware); i += 4) | 715 | for (i = 0; i < sizeof(firmware); i += 4) |
704 | writel(htonl(*(u32*)(firmware + i)), mem + PDM_OFFSET + i); | 716 | writel(htonl(*(u32*)(firmware + i)), mem + PDM_OFFSET + i); |
705 | 717 | ||
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index e66fdb1f3cfd..d8f917c21ea4 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h | |||
@@ -636,6 +636,17 @@ struct bcm43xx_key { | |||
636 | u8 algorithm; | 636 | u8 algorithm; |
637 | }; | 637 | }; |
638 | 638 | ||
639 | /* Driver initialization status. */ | ||
640 | enum { | ||
641 | BCM43xx_STAT_UNINIT, /* Uninitialized. */ | ||
642 | BCM43xx_STAT_INITIALIZING, /* init_board() in progress. */ | ||
643 | BCM43xx_STAT_INITIALIZED, /* Fully operational. */ | ||
644 | BCM43xx_STAT_SHUTTINGDOWN, /* free_board() in progress. */ | ||
645 | BCM43xx_STAT_RESTARTING, /* controller_restart() called. */ | ||
646 | }; | ||
647 | #define bcm43xx_status(bcm) atomic_read(&(bcm)->init_status) | ||
648 | #define bcm43xx_set_status(bcm, stat) atomic_set(&(bcm)->init_status, (stat)) | ||
649 | |||
639 | struct bcm43xx_private { | 650 | struct bcm43xx_private { |
640 | struct ieee80211_device *ieee; | 651 | struct ieee80211_device *ieee; |
641 | struct ieee80211softmac_device *softmac; | 652 | struct ieee80211softmac_device *softmac; |
@@ -646,18 +657,17 @@ struct bcm43xx_private { | |||
646 | 657 | ||
647 | void __iomem *mmio_addr; | 658 | void __iomem *mmio_addr; |
648 | 659 | ||
649 | /* Do not use the lock directly. Use the bcm43xx_lock* helper | 660 | /* Locking, see "theory of locking" text below. */ |
650 | * functions, to be MMIO-safe. */ | 661 | spinlock_t irq_lock; |
651 | spinlock_t _lock; | 662 | struct mutex mutex; |
652 | 663 | ||
653 | /* Driver status flags. */ | 664 | /* Driver initialization status BCM43xx_STAT_*** */ |
654 | u32 initialized:1, /* init_board() succeed */ | 665 | atomic_t init_status; |
655 | was_initialized:1, /* for PCI suspend/resume. */ | 666 | |
656 | shutting_down:1, /* free_board() in progress */ | 667 | u16 was_initialized:1, /* for PCI suspend/resume. */ |
657 | __using_pio:1, /* Internal, use bcm43xx_using_pio(). */ | 668 | __using_pio:1, /* Internal, use bcm43xx_using_pio(). */ |
658 | bad_frames_preempt:1, /* Use "Bad Frames Preemption" (default off) */ | 669 | bad_frames_preempt:1, /* Use "Bad Frames Preemption" (default off) */ |
659 | reg124_set_0x4:1, /* Some variable to keep track of IRQ stuff. */ | 670 | reg124_set_0x4:1, /* Some variable to keep track of IRQ stuff. */ |
660 | powersaving:1, /* TRUE if we are in PowerSaving mode. FALSE otherwise. */ | ||
661 | short_preamble:1, /* TRUE, if short preamble is enabled. */ | 671 | short_preamble:1, /* TRUE, if short preamble is enabled. */ |
662 | firmware_norelease:1; /* Do not release the firmware. Used on suspend. */ | 672 | firmware_norelease:1; /* Do not release the firmware. Used on suspend. */ |
663 | 673 | ||
@@ -721,7 +731,7 @@ struct bcm43xx_private { | |||
721 | struct tasklet_struct isr_tasklet; | 731 | struct tasklet_struct isr_tasklet; |
722 | 732 | ||
723 | /* Periodic tasks */ | 733 | /* Periodic tasks */ |
724 | struct timer_list periodic_tasks; | 734 | struct work_struct periodic_work; |
725 | unsigned int periodic_state; | 735 | unsigned int periodic_state; |
726 | 736 | ||
727 | struct work_struct restart_work; | 737 | struct work_struct restart_work; |
@@ -746,21 +756,55 @@ struct bcm43xx_private { | |||
746 | #endif | 756 | #endif |
747 | }; | 757 | }; |
748 | 758 | ||
749 | /* bcm43xx_(un)lock() protect struct bcm43xx_private. | 759 | |
750 | * Note that _NO_ MMIO writes are allowed. If you want to | 760 | /* *** THEORY OF LOCKING *** |
751 | * write to the device through MMIO in the critical section, use | 761 | * |
752 | * the *_mmio lock functions. | 762 | * We have two different locks in the bcm43xx driver. |
753 | * MMIO read-access is allowed, though. | 763 | * => bcm->mutex: General sleeping mutex. Protects struct bcm43xx_private |
754 | */ | 764 | * and the device registers. |
755 | #define bcm43xx_lock(bcm, flags) spin_lock_irqsave(&(bcm)->_lock, flags) | 765 | * => bcm->irq_lock: IRQ spinlock. Protects against IRQ handler concurrency. |
756 | #define bcm43xx_unlock(bcm, flags) spin_unlock_irqrestore(&(bcm)->_lock, flags) | 766 | * |
757 | /* bcm43xx_(un)lock_mmio() protect struct bcm43xx_private and MMIO. | 767 | * We have three types of helper function pairs to utilize these locks. |
758 | * MMIO write-access to the device is allowed. | 768 | * (Always use the helper functions.) |
759 | * All MMIO writes are flushed on unlock, so it is guaranteed to not | 769 | * 1) bcm43xx_{un}lock_noirq(): |
760 | * interfere with other threads writing MMIO registers. | 770 | * Takes bcm->mutex. Does _not_ protect against IRQ concurrency, |
771 | * so it is almost always unsafe, if device IRQs are enabled. | ||
772 | * So only use this, if device IRQs are masked. | ||
773 | * Locking may sleep. | ||
774 | * You can sleep within the critical section. | ||
775 | * 2) bcm43xx_{un}lock_irqonly(): | ||
776 | * Takes bcm->irq_lock. Does _not_ protect against | ||
777 | * bcm43xx_lock_noirq() critical sections. | ||
778 | * Does only protect against the IRQ handler path and other | ||
779 | * irqonly() critical sections. | ||
780 | * Locking does not sleep. | ||
781 | * You must not sleep within the critical section. | ||
782 | * 3) bcm43xx_{un}lock_irqsafe(): | ||
783 | * This is the cummulative lock and takes both, mutex and irq_lock. | ||
784 | * Protects against noirq() and irqonly() critical sections (and | ||
785 | * the IRQ handler path). | ||
786 | * Locking may sleep. | ||
787 | * You must not sleep within the critical section. | ||
761 | */ | 788 | */ |
762 | #define bcm43xx_lock_mmio(bcm, flags) bcm43xx_lock(bcm, flags) | 789 | |
763 | #define bcm43xx_unlock_mmio(bcm, flags) do { mmiowb(); bcm43xx_unlock(bcm, flags); } while (0) | 790 | /* Lock type 1 */ |
791 | #define bcm43xx_lock_noirq(bcm) mutex_lock(&(bcm)->mutex) | ||
792 | #define bcm43xx_unlock_noirq(bcm) mutex_unlock(&(bcm)->mutex) | ||
793 | /* Lock type 2 */ | ||
794 | #define bcm43xx_lock_irqonly(bcm, flags) \ | ||
795 | spin_lock_irqsave(&(bcm)->irq_lock, flags) | ||
796 | #define bcm43xx_unlock_irqonly(bcm, flags) \ | ||
797 | spin_unlock_irqrestore(&(bcm)->irq_lock, flags) | ||
798 | /* Lock type 3 */ | ||
799 | #define bcm43xx_lock_irqsafe(bcm, flags) do { \ | ||
800 | bcm43xx_lock_noirq(bcm); \ | ||
801 | bcm43xx_lock_irqonly(bcm, flags); \ | ||
802 | } while (0) | ||
803 | #define bcm43xx_unlock_irqsafe(bcm, flags) do { \ | ||
804 | bcm43xx_unlock_irqonly(bcm, flags); \ | ||
805 | bcm43xx_unlock_noirq(bcm); \ | ||
806 | } while (0) | ||
807 | |||
764 | 808 | ||
765 | static inline | 809 | static inline |
766 | struct bcm43xx_private * bcm43xx_priv(struct net_device *dev) | 810 | struct bcm43xx_private * bcm43xx_priv(struct net_device *dev) |
@@ -843,16 +887,6 @@ struct bcm43xx_radioinfo * bcm43xx_current_radio(struct bcm43xx_private *bcm) | |||
843 | return &(bcm->core_80211_ext[bcm->current_80211_core_idx].radio); | 887 | return &(bcm->core_80211_ext[bcm->current_80211_core_idx].radio); |
844 | } | 888 | } |
845 | 889 | ||
846 | /* Are we running in init_board() context? */ | ||
847 | static inline | ||
848 | int bcm43xx_is_initializing(struct bcm43xx_private *bcm) | ||
849 | { | ||
850 | if (bcm->initialized) | ||
851 | return 0; | ||
852 | if (bcm->shutting_down) | ||
853 | return 0; | ||
854 | return 1; | ||
855 | } | ||
856 | 890 | ||
857 | static inline | 891 | static inline |
858 | struct bcm43xx_lopair * bcm43xx_get_lopair(struct bcm43xx_phyinfo *phy, | 892 | struct bcm43xx_lopair * bcm43xx_get_lopair(struct bcm43xx_phyinfo *phy, |
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c index 7497fb16076e..ce2e40b29b4f 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c | |||
@@ -77,8 +77,8 @@ static ssize_t devinfo_read_file(struct file *file, char __user *userbuf, | |||
77 | 77 | ||
78 | down(&big_buffer_sem); | 78 | down(&big_buffer_sem); |
79 | 79 | ||
80 | bcm43xx_lock_mmio(bcm, flags); | 80 | bcm43xx_lock_irqsafe(bcm, flags); |
81 | if (!bcm->initialized) { | 81 | if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) { |
82 | fappend("Board not initialized.\n"); | 82 | fappend("Board not initialized.\n"); |
83 | goto out; | 83 | goto out; |
84 | } | 84 | } |
@@ -121,7 +121,7 @@ static ssize_t devinfo_read_file(struct file *file, char __user *userbuf, | |||
121 | fappend("\n"); | 121 | fappend("\n"); |
122 | 122 | ||
123 | out: | 123 | out: |
124 | bcm43xx_unlock_mmio(bcm, flags); | 124 | bcm43xx_unlock_irqsafe(bcm, flags); |
125 | res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); | 125 | res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); |
126 | up(&big_buffer_sem); | 126 | up(&big_buffer_sem); |
127 | return res; | 127 | return res; |
@@ -159,8 +159,8 @@ static ssize_t spromdump_read_file(struct file *file, char __user *userbuf, | |||
159 | unsigned long flags; | 159 | unsigned long flags; |
160 | 160 | ||
161 | down(&big_buffer_sem); | 161 | down(&big_buffer_sem); |
162 | bcm43xx_lock_mmio(bcm, flags); | 162 | bcm43xx_lock_irqsafe(bcm, flags); |
163 | if (!bcm->initialized) { | 163 | if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) { |
164 | fappend("Board not initialized.\n"); | 164 | fappend("Board not initialized.\n"); |
165 | goto out; | 165 | goto out; |
166 | } | 166 | } |
@@ -169,7 +169,7 @@ static ssize_t spromdump_read_file(struct file *file, char __user *userbuf, | |||
169 | fappend("boardflags: 0x%04x\n", bcm->sprom.boardflags); | 169 | fappend("boardflags: 0x%04x\n", bcm->sprom.boardflags); |
170 | 170 | ||
171 | out: | 171 | out: |
172 | bcm43xx_unlock_mmio(bcm, flags); | 172 | bcm43xx_unlock_irqsafe(bcm, flags); |
173 | res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); | 173 | res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); |
174 | up(&big_buffer_sem); | 174 | up(&big_buffer_sem); |
175 | return res; | 175 | return res; |
@@ -188,8 +188,8 @@ static ssize_t tsf_read_file(struct file *file, char __user *userbuf, | |||
188 | u64 tsf; | 188 | u64 tsf; |
189 | 189 | ||
190 | down(&big_buffer_sem); | 190 | down(&big_buffer_sem); |
191 | bcm43xx_lock_mmio(bcm, flags); | 191 | bcm43xx_lock_irqsafe(bcm, flags); |
192 | if (!bcm->initialized) { | 192 | if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) { |
193 | fappend("Board not initialized.\n"); | 193 | fappend("Board not initialized.\n"); |
194 | goto out; | 194 | goto out; |
195 | } | 195 | } |
@@ -199,7 +199,7 @@ static ssize_t tsf_read_file(struct file *file, char __user *userbuf, | |||
199 | (unsigned int)(tsf & 0xFFFFFFFFULL)); | 199 | (unsigned int)(tsf & 0xFFFFFFFFULL)); |
200 | 200 | ||
201 | out: | 201 | out: |
202 | bcm43xx_unlock_mmio(bcm, flags); | 202 | bcm43xx_unlock_irqsafe(bcm, flags); |
203 | res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); | 203 | res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); |
204 | up(&big_buffer_sem); | 204 | up(&big_buffer_sem); |
205 | return res; | 205 | return res; |
@@ -221,8 +221,8 @@ static ssize_t tsf_write_file(struct file *file, const char __user *user_buf, | |||
221 | res = -EFAULT; | 221 | res = -EFAULT; |
222 | goto out_up; | 222 | goto out_up; |
223 | } | 223 | } |
224 | bcm43xx_lock_mmio(bcm, flags); | 224 | bcm43xx_lock_irqsafe(bcm, flags); |
225 | if (!bcm->initialized) { | 225 | if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) { |
226 | printk(KERN_INFO PFX "debugfs: Board not initialized.\n"); | 226 | printk(KERN_INFO PFX "debugfs: Board not initialized.\n"); |
227 | res = -EFAULT; | 227 | res = -EFAULT; |
228 | goto out_unlock; | 228 | goto out_unlock; |
@@ -233,10 +233,11 @@ static ssize_t tsf_write_file(struct file *file, const char __user *user_buf, | |||
233 | goto out_unlock; | 233 | goto out_unlock; |
234 | } | 234 | } |
235 | bcm43xx_tsf_write(bcm, tsf); | 235 | bcm43xx_tsf_write(bcm, tsf); |
236 | mmiowb(); | ||
236 | res = buf_size; | 237 | res = buf_size; |
237 | 238 | ||
238 | out_unlock: | 239 | out_unlock: |
239 | bcm43xx_unlock_mmio(bcm, flags); | 240 | bcm43xx_unlock_irqsafe(bcm, flags); |
240 | out_up: | 241 | out_up: |
241 | up(&big_buffer_sem); | 242 | up(&big_buffer_sem); |
242 | return res; | 243 | return res; |
@@ -257,7 +258,7 @@ static ssize_t txstat_read_file(struct file *file, char __user *userbuf, | |||
257 | int i, cnt, j = 0; | 258 | int i, cnt, j = 0; |
258 | 259 | ||
259 | down(&big_buffer_sem); | 260 | down(&big_buffer_sem); |
260 | bcm43xx_lock(bcm, flags); | 261 | bcm43xx_lock_irqsafe(bcm, flags); |
261 | 262 | ||
262 | fappend("Last %d logged xmitstatus blobs (Latest first):\n\n", | 263 | fappend("Last %d logged xmitstatus blobs (Latest first):\n\n", |
263 | BCM43xx_NR_LOGGED_XMITSTATUS); | 264 | BCM43xx_NR_LOGGED_XMITSTATUS); |
@@ -293,14 +294,14 @@ static ssize_t txstat_read_file(struct file *file, char __user *userbuf, | |||
293 | i = BCM43xx_NR_LOGGED_XMITSTATUS - 1; | 294 | i = BCM43xx_NR_LOGGED_XMITSTATUS - 1; |
294 | } | 295 | } |
295 | 296 | ||
296 | bcm43xx_unlock(bcm, flags); | 297 | bcm43xx_unlock_irqsafe(bcm, flags); |
297 | res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); | 298 | res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); |
298 | bcm43xx_lock(bcm, flags); | 299 | bcm43xx_lock_irqsafe(bcm, flags); |
299 | if (*ppos == pos) { | 300 | if (*ppos == pos) { |
300 | /* Done. Drop the copied data. */ | 301 | /* Done. Drop the copied data. */ |
301 | e->xmitstatus_printing = 0; | 302 | e->xmitstatus_printing = 0; |
302 | } | 303 | } |
303 | bcm43xx_unlock(bcm, flags); | 304 | bcm43xx_unlock_irqsafe(bcm, flags); |
304 | up(&big_buffer_sem); | 305 | up(&big_buffer_sem); |
305 | return res; | 306 | return res; |
306 | } | 307 | } |
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c index 4b2c02c0b31e..ec80692d638a 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c | |||
@@ -51,12 +51,12 @@ static void bcm43xx_led_blink(unsigned long d) | |||
51 | struct bcm43xx_private *bcm = led->bcm; | 51 | struct bcm43xx_private *bcm = led->bcm; |
52 | unsigned long flags; | 52 | unsigned long flags; |
53 | 53 | ||
54 | bcm43xx_lock_mmio(bcm, flags); | 54 | bcm43xx_lock_irqonly(bcm, flags); |
55 | if (led->blink_interval) { | 55 | if (led->blink_interval) { |
56 | bcm43xx_led_changestate(led); | 56 | bcm43xx_led_changestate(led); |
57 | mod_timer(&led->blink_timer, jiffies + led->blink_interval); | 57 | mod_timer(&led->blink_timer, jiffies + led->blink_interval); |
58 | } | 58 | } |
59 | bcm43xx_unlock_mmio(bcm, flags); | 59 | bcm43xx_unlock_irqonly(bcm, flags); |
60 | } | 60 | } |
61 | 61 | ||
62 | static void bcm43xx_led_blink_start(struct bcm43xx_led *led, | 62 | static void bcm43xx_led_blink_start(struct bcm43xx_led *led, |
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 736dde96c4a3..085d7857fe31 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c | |||
@@ -498,20 +498,31 @@ static inline u32 bcm43xx_interrupt_disable(struct bcm43xx_private *bcm, u32 mas | |||
498 | return old_mask; | 498 | return old_mask; |
499 | } | 499 | } |
500 | 500 | ||
501 | /* Synchronize IRQ top- and bottom-half. | ||
502 | * IRQs must be masked before calling this. | ||
503 | * This must not be called with the irq_lock held. | ||
504 | */ | ||
505 | static void bcm43xx_synchronize_irq(struct bcm43xx_private *bcm) | ||
506 | { | ||
507 | synchronize_irq(bcm->irq); | ||
508 | tasklet_disable(&bcm->isr_tasklet); | ||
509 | } | ||
510 | |||
501 | /* Make sure we don't receive more data from the device. */ | 511 | /* Make sure we don't receive more data from the device. */ |
502 | static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm, u32 *oldstate) | 512 | static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm, u32 *oldstate) |
503 | { | 513 | { |
504 | u32 old; | ||
505 | unsigned long flags; | 514 | unsigned long flags; |
515 | u32 old; | ||
506 | 516 | ||
507 | bcm43xx_lock_mmio(bcm, flags); | 517 | bcm43xx_lock_irqonly(bcm, flags); |
508 | if (bcm43xx_is_initializing(bcm) || bcm->shutting_down) { | 518 | if (unlikely(bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)) { |
509 | bcm43xx_unlock_mmio(bcm, flags); | 519 | bcm43xx_unlock_irqonly(bcm, flags); |
510 | return -EBUSY; | 520 | return -EBUSY; |
511 | } | 521 | } |
512 | old = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); | 522 | old = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); |
513 | tasklet_disable(&bcm->isr_tasklet); | 523 | bcm43xx_unlock_irqonly(bcm, flags); |
514 | bcm43xx_unlock_mmio(bcm, flags); | 524 | bcm43xx_synchronize_irq(bcm); |
525 | |||
515 | if (oldstate) | 526 | if (oldstate) |
516 | *oldstate = old; | 527 | *oldstate = old; |
517 | 528 | ||
@@ -1389,7 +1400,7 @@ void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy) | |||
1389 | bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA4_BASE); | 1400 | bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA4_BASE); |
1390 | #endif | 1401 | #endif |
1391 | } | 1402 | } |
1392 | if (bcm->shutting_down) { | 1403 | if (bcm43xx_status(bcm) == BCM43xx_STAT_SHUTTINGDOWN) { |
1393 | bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, | 1404 | bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, |
1394 | bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) | 1405 | bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) |
1395 | & ~(BCM43xx_SBF_MAC_ENABLED | 0x00000002)); | 1406 | & ~(BCM43xx_SBF_MAC_ENABLED | 0x00000002)); |
@@ -1709,7 +1720,7 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm) | |||
1709 | # define bcmirq_handled(irq) do { /* nothing */ } while (0) | 1720 | # define bcmirq_handled(irq) do { /* nothing */ } while (0) |
1710 | #endif /* CONFIG_BCM43XX_DEBUG*/ | 1721 | #endif /* CONFIG_BCM43XX_DEBUG*/ |
1711 | 1722 | ||
1712 | bcm43xx_lock_mmio(bcm, flags); | 1723 | bcm43xx_lock_irqonly(bcm, flags); |
1713 | reason = bcm->irq_reason; | 1724 | reason = bcm->irq_reason; |
1714 | dma_reason[0] = bcm->dma_reason[0]; | 1725 | dma_reason[0] = bcm->dma_reason[0]; |
1715 | dma_reason[1] = bcm->dma_reason[1]; | 1726 | dma_reason[1] = bcm->dma_reason[1]; |
@@ -1734,7 +1745,8 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm) | |||
1734 | dma_reason[0], dma_reason[1], | 1745 | dma_reason[0], dma_reason[1], |
1735 | dma_reason[2], dma_reason[3]); | 1746 | dma_reason[2], dma_reason[3]); |
1736 | bcm43xx_controller_restart(bcm, "DMA error"); | 1747 | bcm43xx_controller_restart(bcm, "DMA error"); |
1737 | bcm43xx_unlock_mmio(bcm, flags); | 1748 | mmiowb(); |
1749 | bcm43xx_unlock_irqonly(bcm, flags); | ||
1738 | return; | 1750 | return; |
1739 | } | 1751 | } |
1740 | if (unlikely((dma_reason[0] & BCM43xx_DMAIRQ_NONFATALMASK) | | 1752 | if (unlikely((dma_reason[0] & BCM43xx_DMAIRQ_NONFATALMASK) | |
@@ -1821,7 +1833,8 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm) | |||
1821 | if (!modparam_noleds) | 1833 | if (!modparam_noleds) |
1822 | bcm43xx_leds_update(bcm, activity); | 1834 | bcm43xx_leds_update(bcm, activity); |
1823 | bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate); | 1835 | bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate); |
1824 | bcm43xx_unlock_mmio(bcm, flags); | 1836 | mmiowb(); |
1837 | bcm43xx_unlock_irqonly(bcm, flags); | ||
1825 | } | 1838 | } |
1826 | 1839 | ||
1827 | static void pio_irq_workaround(struct bcm43xx_private *bcm, | 1840 | static void pio_irq_workaround(struct bcm43xx_private *bcm, |
@@ -1870,7 +1883,7 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_re | |||
1870 | if (!bcm) | 1883 | if (!bcm) |
1871 | return IRQ_NONE; | 1884 | return IRQ_NONE; |
1872 | 1885 | ||
1873 | spin_lock(&bcm->_lock); | 1886 | spin_lock(&bcm->irq_lock); |
1874 | 1887 | ||
1875 | reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); | 1888 | reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); |
1876 | if (reason == 0xffffffff) { | 1889 | if (reason == 0xffffffff) { |
@@ -1899,7 +1912,7 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_re | |||
1899 | * completely, but some careful work is needed to fix this. I think it | 1912 | * completely, but some careful work is needed to fix this. I think it |
1900 | * is best to stay with this cheap workaround for now... . | 1913 | * is best to stay with this cheap workaround for now... . |
1901 | */ | 1914 | */ |
1902 | if (likely(bcm->initialized)) { | 1915 | if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)) { |
1903 | /* disable all IRQs. They are enabled again in the bottom half. */ | 1916 | /* disable all IRQs. They are enabled again in the bottom half. */ |
1904 | bcm->irq_savedstate = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); | 1917 | bcm->irq_savedstate = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); |
1905 | /* save the reason code and call our bottom half. */ | 1918 | /* save the reason code and call our bottom half. */ |
@@ -1909,7 +1922,7 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_re | |||
1909 | 1922 | ||
1910 | out: | 1923 | out: |
1911 | mmiowb(); | 1924 | mmiowb(); |
1912 | spin_unlock(&bcm->_lock); | 1925 | spin_unlock(&bcm->irq_lock); |
1913 | 1926 | ||
1914 | return ret; | 1927 | return ret; |
1915 | } | 1928 | } |
@@ -2133,6 +2146,13 @@ out: | |||
2133 | return err; | 2146 | return err; |
2134 | } | 2147 | } |
2135 | 2148 | ||
2149 | #ifdef CONFIG_BCM947XX | ||
2150 | static struct pci_device_id bcm43xx_47xx_ids[] = { | ||
2151 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4324) }, | ||
2152 | { 0 } | ||
2153 | }; | ||
2154 | #endif | ||
2155 | |||
2136 | static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm) | 2156 | static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm) |
2137 | { | 2157 | { |
2138 | int res; | 2158 | int res; |
@@ -2142,11 +2162,15 @@ static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm) | |||
2142 | bcm->irq = bcm->pci_dev->irq; | 2162 | bcm->irq = bcm->pci_dev->irq; |
2143 | #ifdef CONFIG_BCM947XX | 2163 | #ifdef CONFIG_BCM947XX |
2144 | if (bcm->pci_dev->bus->number == 0) { | 2164 | if (bcm->pci_dev->bus->number == 0) { |
2145 | struct pci_dev *d = NULL; | 2165 | struct pci_dev *d; |
2146 | /* FIXME: we will probably need more device IDs here... */ | 2166 | struct pci_device_id *id; |
2147 | d = pci_find_device(PCI_VENDOR_ID_BROADCOM, 0x4324, NULL); | 2167 | for (id = bcm43xx_47xx_ids; id->vendor; id++) { |
2148 | if (d != NULL) { | 2168 | d = pci_get_device(id->vendor, id->device, NULL); |
2149 | bcm->irq = d->irq; | 2169 | if (d != NULL) { |
2170 | bcm->irq = d->irq; | ||
2171 | pci_dev_put(d); | ||
2172 | break; | ||
2173 | } | ||
2150 | } | 2174 | } |
2151 | } | 2175 | } |
2152 | #endif | 2176 | #endif |
@@ -3106,15 +3130,10 @@ static void bcm43xx_periodic_every15sec(struct bcm43xx_private *bcm) | |||
3106 | //TODO for APHY (temperature?) | 3130 | //TODO for APHY (temperature?) |
3107 | } | 3131 | } |
3108 | 3132 | ||
3109 | static void bcm43xx_periodic_task_handler(unsigned long d) | 3133 | static void do_periodic_work(struct bcm43xx_private *bcm) |
3110 | { | 3134 | { |
3111 | struct bcm43xx_private *bcm = (struct bcm43xx_private *)d; | ||
3112 | unsigned long flags; | ||
3113 | unsigned int state; | 3135 | unsigned int state; |
3114 | 3136 | ||
3115 | bcm43xx_lock_mmio(bcm, flags); | ||
3116 | |||
3117 | assert(bcm->initialized); | ||
3118 | state = bcm->periodic_state; | 3137 | state = bcm->periodic_state; |
3119 | if (state % 8 == 0) | 3138 | if (state % 8 == 0) |
3120 | bcm43xx_periodic_every120sec(bcm); | 3139 | bcm43xx_periodic_every120sec(bcm); |
@@ -3122,29 +3141,93 @@ static void bcm43xx_periodic_task_handler(unsigned long d) | |||
3122 | bcm43xx_periodic_every60sec(bcm); | 3141 | bcm43xx_periodic_every60sec(bcm); |
3123 | if (state % 2 == 0) | 3142 | if (state % 2 == 0) |
3124 | bcm43xx_periodic_every30sec(bcm); | 3143 | bcm43xx_periodic_every30sec(bcm); |
3125 | bcm43xx_periodic_every15sec(bcm); | 3144 | if (state % 1 == 0) |
3145 | bcm43xx_periodic_every15sec(bcm); | ||
3126 | bcm->periodic_state = state + 1; | 3146 | bcm->periodic_state = state + 1; |
3127 | 3147 | ||
3128 | mod_timer(&bcm->periodic_tasks, jiffies + (HZ * 15)); | 3148 | schedule_delayed_work(&bcm->periodic_work, HZ * 15); |
3149 | } | ||
3150 | |||
3151 | /* Estimate a "Badness" value based on the periodic work | ||
3152 | * state-machine state. "Badness" is worse (bigger), if the | ||
3153 | * periodic work will take longer. | ||
3154 | */ | ||
3155 | static int estimate_periodic_work_badness(unsigned int state) | ||
3156 | { | ||
3157 | int badness = 0; | ||
3158 | |||
3159 | if (state % 8 == 0) /* every 120 sec */ | ||
3160 | badness += 10; | ||
3161 | if (state % 4 == 0) /* every 60 sec */ | ||
3162 | badness += 5; | ||
3163 | if (state % 2 == 0) /* every 30 sec */ | ||
3164 | badness += 1; | ||
3165 | if (state % 1 == 0) /* every 15 sec */ | ||
3166 | badness += 1; | ||
3129 | 3167 | ||
3130 | bcm43xx_unlock_mmio(bcm, flags); | 3168 | #define BADNESS_LIMIT 4 |
3169 | return badness; | ||
3170 | } | ||
3171 | |||
3172 | static void bcm43xx_periodic_work_handler(void *d) | ||
3173 | { | ||
3174 | struct bcm43xx_private *bcm = d; | ||
3175 | unsigned long flags; | ||
3176 | u32 savedirqs = 0; | ||
3177 | int badness; | ||
3178 | |||
3179 | badness = estimate_periodic_work_badness(bcm->periodic_state); | ||
3180 | if (badness > BADNESS_LIMIT) { | ||
3181 | /* Periodic work will take a long time, so we want it to | ||
3182 | * be preemtible. | ||
3183 | */ | ||
3184 | bcm43xx_lock_irqonly(bcm, flags); | ||
3185 | netif_stop_queue(bcm->net_dev); | ||
3186 | if (bcm43xx_using_pio(bcm)) | ||
3187 | bcm43xx_pio_freeze_txqueues(bcm); | ||
3188 | savedirqs = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); | ||
3189 | bcm43xx_unlock_irqonly(bcm, flags); | ||
3190 | bcm43xx_lock_noirq(bcm); | ||
3191 | bcm43xx_synchronize_irq(bcm); | ||
3192 | } else { | ||
3193 | /* Periodic work should take short time, so we want low | ||
3194 | * locking overhead. | ||
3195 | */ | ||
3196 | bcm43xx_lock_irqsafe(bcm, flags); | ||
3197 | } | ||
3198 | |||
3199 | do_periodic_work(bcm); | ||
3200 | |||
3201 | if (badness > BADNESS_LIMIT) { | ||
3202 | bcm43xx_lock_irqonly(bcm, flags); | ||
3203 | if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)) { | ||
3204 | tasklet_enable(&bcm->isr_tasklet); | ||
3205 | bcm43xx_interrupt_enable(bcm, savedirqs); | ||
3206 | if (bcm43xx_using_pio(bcm)) | ||
3207 | bcm43xx_pio_thaw_txqueues(bcm); | ||
3208 | } | ||
3209 | netif_wake_queue(bcm->net_dev); | ||
3210 | mmiowb(); | ||
3211 | bcm43xx_unlock_irqonly(bcm, flags); | ||
3212 | bcm43xx_unlock_noirq(bcm); | ||
3213 | } else { | ||
3214 | mmiowb(); | ||
3215 | bcm43xx_unlock_irqsafe(bcm, flags); | ||
3216 | } | ||
3131 | } | 3217 | } |
3132 | 3218 | ||
3133 | static void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm) | 3219 | static void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm) |
3134 | { | 3220 | { |
3135 | del_timer_sync(&bcm->periodic_tasks); | 3221 | cancel_rearming_delayed_work(&bcm->periodic_work); |
3136 | } | 3222 | } |
3137 | 3223 | ||
3138 | static void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm) | 3224 | static void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm) |
3139 | { | 3225 | { |
3140 | struct timer_list *timer = &(bcm->periodic_tasks); | 3226 | struct work_struct *work = &(bcm->periodic_work); |
3141 | 3227 | ||
3142 | assert(bcm->initialized); | 3228 | assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED); |
3143 | setup_timer(timer, | 3229 | INIT_WORK(work, bcm43xx_periodic_work_handler, bcm); |
3144 | bcm43xx_periodic_task_handler, | 3230 | schedule_work(work); |
3145 | (unsigned long)bcm); | ||
3146 | timer->expires = jiffies; | ||
3147 | add_timer(timer); | ||
3148 | } | 3231 | } |
3149 | 3232 | ||
3150 | static void bcm43xx_security_init(struct bcm43xx_private *bcm) | 3233 | static void bcm43xx_security_init(struct bcm43xx_private *bcm) |
@@ -3158,16 +3241,12 @@ static void bcm43xx_security_init(struct bcm43xx_private *bcm) | |||
3158 | static void bcm43xx_free_board(struct bcm43xx_private *bcm) | 3241 | static void bcm43xx_free_board(struct bcm43xx_private *bcm) |
3159 | { | 3242 | { |
3160 | int i, err; | 3243 | int i, err; |
3161 | unsigned long flags; | ||
3162 | 3244 | ||
3245 | bcm43xx_lock_noirq(bcm); | ||
3163 | bcm43xx_sysfs_unregister(bcm); | 3246 | bcm43xx_sysfs_unregister(bcm); |
3164 | |||
3165 | bcm43xx_periodic_tasks_delete(bcm); | 3247 | bcm43xx_periodic_tasks_delete(bcm); |
3166 | 3248 | ||
3167 | bcm43xx_lock(bcm, flags); | 3249 | bcm43xx_set_status(bcm, BCM43xx_STAT_SHUTTINGDOWN); |
3168 | bcm->initialized = 0; | ||
3169 | bcm->shutting_down = 1; | ||
3170 | bcm43xx_unlock(bcm, flags); | ||
3171 | 3250 | ||
3172 | for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { | 3251 | for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { |
3173 | if (!bcm->core_80211[i].available) | 3252 | if (!bcm->core_80211[i].available) |
@@ -3182,23 +3261,19 @@ static void bcm43xx_free_board(struct bcm43xx_private *bcm) | |||
3182 | 3261 | ||
3183 | bcm43xx_pctl_set_crystal(bcm, 0); | 3262 | bcm43xx_pctl_set_crystal(bcm, 0); |
3184 | 3263 | ||
3185 | bcm43xx_lock(bcm, flags); | 3264 | bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT); |
3186 | bcm->shutting_down = 0; | 3265 | bcm43xx_unlock_noirq(bcm); |
3187 | bcm43xx_unlock(bcm, flags); | ||
3188 | } | 3266 | } |
3189 | 3267 | ||
3190 | static int bcm43xx_init_board(struct bcm43xx_private *bcm) | 3268 | static int bcm43xx_init_board(struct bcm43xx_private *bcm) |
3191 | { | 3269 | { |
3192 | int i, err; | 3270 | int i, err; |
3193 | int connect_phy; | 3271 | int connect_phy; |
3194 | unsigned long flags; | ||
3195 | 3272 | ||
3196 | might_sleep(); | 3273 | might_sleep(); |
3197 | 3274 | ||
3198 | bcm43xx_lock(bcm, flags); | 3275 | bcm43xx_lock_noirq(bcm); |
3199 | bcm->initialized = 0; | 3276 | bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZING); |
3200 | bcm->shutting_down = 0; | ||
3201 | bcm43xx_unlock(bcm, flags); | ||
3202 | 3277 | ||
3203 | err = bcm43xx_pctl_set_crystal(bcm, 1); | 3278 | err = bcm43xx_pctl_set_crystal(bcm, 1); |
3204 | if (err) | 3279 | if (err) |
@@ -3265,9 +3340,7 @@ static int bcm43xx_init_board(struct bcm43xx_private *bcm) | |||
3265 | } | 3340 | } |
3266 | 3341 | ||
3267 | /* Initialization of the board is done. Flag it as such. */ | 3342 | /* Initialization of the board is done. Flag it as such. */ |
3268 | bcm43xx_lock(bcm, flags); | 3343 | bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZED); |
3269 | bcm->initialized = 1; | ||
3270 | bcm43xx_unlock(bcm, flags); | ||
3271 | 3344 | ||
3272 | bcm43xx_periodic_tasks_setup(bcm); | 3345 | bcm43xx_periodic_tasks_setup(bcm); |
3273 | bcm43xx_sysfs_register(bcm); | 3346 | bcm43xx_sysfs_register(bcm); |
@@ -3278,6 +3351,8 @@ static int bcm43xx_init_board(struct bcm43xx_private *bcm) | |||
3278 | 3351 | ||
3279 | assert(err == 0); | 3352 | assert(err == 0); |
3280 | out: | 3353 | out: |
3354 | bcm43xx_unlock_noirq(bcm); | ||
3355 | |||
3281 | return err; | 3356 | return err; |
3282 | 3357 | ||
3283 | err_80211_unwind: | 3358 | err_80211_unwind: |
@@ -3534,8 +3609,8 @@ static void bcm43xx_ieee80211_set_chan(struct net_device *net_dev, | |||
3534 | struct bcm43xx_radioinfo *radio; | 3609 | struct bcm43xx_radioinfo *radio; |
3535 | unsigned long flags; | 3610 | unsigned long flags; |
3536 | 3611 | ||
3537 | bcm43xx_lock_mmio(bcm, flags); | 3612 | bcm43xx_lock_irqsafe(bcm, flags); |
3538 | if (bcm->initialized) { | 3613 | if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) { |
3539 | bcm43xx_mac_suspend(bcm); | 3614 | bcm43xx_mac_suspend(bcm); |
3540 | bcm43xx_radio_selectchannel(bcm, channel, 0); | 3615 | bcm43xx_radio_selectchannel(bcm, channel, 0); |
3541 | bcm43xx_mac_enable(bcm); | 3616 | bcm43xx_mac_enable(bcm); |
@@ -3543,7 +3618,7 @@ static void bcm43xx_ieee80211_set_chan(struct net_device *net_dev, | |||
3543 | radio = bcm43xx_current_radio(bcm); | 3618 | radio = bcm43xx_current_radio(bcm); |
3544 | radio->initial_channel = channel; | 3619 | radio->initial_channel = channel; |
3545 | } | 3620 | } |
3546 | bcm43xx_unlock_mmio(bcm, flags); | 3621 | bcm43xx_unlock_irqsafe(bcm, flags); |
3547 | } | 3622 | } |
3548 | 3623 | ||
3549 | /* set_security() callback in struct ieee80211_device */ | 3624 | /* set_security() callback in struct ieee80211_device */ |
@@ -3557,7 +3632,7 @@ static void bcm43xx_ieee80211_set_security(struct net_device *net_dev, | |||
3557 | 3632 | ||
3558 | dprintk(KERN_INFO PFX "set security called"); | 3633 | dprintk(KERN_INFO PFX "set security called"); |
3559 | 3634 | ||
3560 | bcm43xx_lock_mmio(bcm, flags); | 3635 | bcm43xx_lock_irqsafe(bcm, flags); |
3561 | 3636 | ||
3562 | for (keyidx = 0; keyidx<WEP_KEYS; keyidx++) | 3637 | for (keyidx = 0; keyidx<WEP_KEYS; keyidx++) |
3563 | if (sec->flags & (1<<keyidx)) { | 3638 | if (sec->flags & (1<<keyidx)) { |
@@ -3587,7 +3662,8 @@ static void bcm43xx_ieee80211_set_security(struct net_device *net_dev, | |||
3587 | dprintk(", .encrypt = %d", sec->encrypt); | 3662 | dprintk(", .encrypt = %d", sec->encrypt); |
3588 | } | 3663 | } |
3589 | dprintk("\n"); | 3664 | dprintk("\n"); |
3590 | if (bcm->initialized && !bcm->ieee->host_encrypt) { | 3665 | if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED && |
3666 | !bcm->ieee->host_encrypt) { | ||
3591 | if (secinfo->enabled) { | 3667 | if (secinfo->enabled) { |
3592 | /* upload WEP keys to hardware */ | 3668 | /* upload WEP keys to hardware */ |
3593 | char null_address[6] = { 0 }; | 3669 | char null_address[6] = { 0 }; |
@@ -3621,7 +3697,7 @@ static void bcm43xx_ieee80211_set_security(struct net_device *net_dev, | |||
3621 | } else | 3697 | } else |
3622 | bcm43xx_clear_keys(bcm); | 3698 | bcm43xx_clear_keys(bcm); |
3623 | } | 3699 | } |
3624 | bcm43xx_unlock_mmio(bcm, flags); | 3700 | bcm43xx_unlock_irqsafe(bcm, flags); |
3625 | } | 3701 | } |
3626 | 3702 | ||
3627 | /* hard_start_xmit() callback in struct ieee80211_device */ | 3703 | /* hard_start_xmit() callback in struct ieee80211_device */ |
@@ -3633,10 +3709,10 @@ static int bcm43xx_ieee80211_hard_start_xmit(struct ieee80211_txb *txb, | |||
3633 | int err = -ENODEV; | 3709 | int err = -ENODEV; |
3634 | unsigned long flags; | 3710 | unsigned long flags; |
3635 | 3711 | ||
3636 | bcm43xx_lock_mmio(bcm, flags); | 3712 | bcm43xx_lock_irqonly(bcm, flags); |
3637 | if (likely(bcm->initialized)) | 3713 | if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)) |
3638 | err = bcm43xx_tx(bcm, txb); | 3714 | err = bcm43xx_tx(bcm, txb); |
3639 | bcm43xx_unlock_mmio(bcm, flags); | 3715 | bcm43xx_unlock_irqonly(bcm, flags); |
3640 | 3716 | ||
3641 | return err; | 3717 | return err; |
3642 | } | 3718 | } |
@@ -3651,9 +3727,9 @@ static void bcm43xx_net_tx_timeout(struct net_device *net_dev) | |||
3651 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); | 3727 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); |
3652 | unsigned long flags; | 3728 | unsigned long flags; |
3653 | 3729 | ||
3654 | bcm43xx_lock_mmio(bcm, flags); | 3730 | bcm43xx_lock_irqonly(bcm, flags); |
3655 | bcm43xx_controller_restart(bcm, "TX timeout"); | 3731 | bcm43xx_controller_restart(bcm, "TX timeout"); |
3656 | bcm43xx_unlock_mmio(bcm, flags); | 3732 | bcm43xx_unlock_irqonly(bcm, flags); |
3657 | } | 3733 | } |
3658 | 3734 | ||
3659 | #ifdef CONFIG_NET_POLL_CONTROLLER | 3735 | #ifdef CONFIG_NET_POLL_CONTROLLER |
@@ -3678,9 +3754,11 @@ static int bcm43xx_net_open(struct net_device *net_dev) | |||
3678 | static int bcm43xx_net_stop(struct net_device *net_dev) | 3754 | static int bcm43xx_net_stop(struct net_device *net_dev) |
3679 | { | 3755 | { |
3680 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); | 3756 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); |
3757 | int err; | ||
3681 | 3758 | ||
3682 | ieee80211softmac_stop(net_dev); | 3759 | ieee80211softmac_stop(net_dev); |
3683 | bcm43xx_disable_interrupts_sync(bcm, NULL); | 3760 | err = bcm43xx_disable_interrupts_sync(bcm, NULL); |
3761 | assert(!err); | ||
3684 | bcm43xx_free_board(bcm); | 3762 | bcm43xx_free_board(bcm); |
3685 | 3763 | ||
3686 | return 0; | 3764 | return 0; |
@@ -3692,6 +3770,7 @@ static int bcm43xx_init_private(struct bcm43xx_private *bcm, | |||
3692 | { | 3770 | { |
3693 | int err; | 3771 | int err; |
3694 | 3772 | ||
3773 | bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT); | ||
3695 | bcm->ieee = netdev_priv(net_dev); | 3774 | bcm->ieee = netdev_priv(net_dev); |
3696 | bcm->softmac = ieee80211_priv(net_dev); | 3775 | bcm->softmac = ieee80211_priv(net_dev); |
3697 | bcm->softmac->set_channel = bcm43xx_ieee80211_set_chan; | 3776 | bcm->softmac->set_channel = bcm43xx_ieee80211_set_chan; |
@@ -3700,7 +3779,8 @@ static int bcm43xx_init_private(struct bcm43xx_private *bcm, | |||
3700 | bcm->pci_dev = pci_dev; | 3779 | bcm->pci_dev = pci_dev; |
3701 | bcm->net_dev = net_dev; | 3780 | bcm->net_dev = net_dev; |
3702 | bcm->bad_frames_preempt = modparam_bad_frames_preempt; | 3781 | bcm->bad_frames_preempt = modparam_bad_frames_preempt; |
3703 | spin_lock_init(&bcm->_lock); | 3782 | spin_lock_init(&bcm->irq_lock); |
3783 | mutex_init(&bcm->mutex); | ||
3704 | tasklet_init(&bcm->isr_tasklet, | 3784 | tasklet_init(&bcm->isr_tasklet, |
3705 | (void (*)(unsigned long))bcm43xx_interrupt_tasklet, | 3785 | (void (*)(unsigned long))bcm43xx_interrupt_tasklet, |
3706 | (unsigned long)bcm); | 3786 | (unsigned long)bcm); |
@@ -3831,7 +3911,7 @@ static void bcm43xx_chip_reset(void *_bcm) | |||
3831 | struct net_device *net_dev = bcm->net_dev; | 3911 | struct net_device *net_dev = bcm->net_dev; |
3832 | struct pci_dev *pci_dev = bcm->pci_dev; | 3912 | struct pci_dev *pci_dev = bcm->pci_dev; |
3833 | int err; | 3913 | int err; |
3834 | int was_initialized = bcm->initialized; | 3914 | int was_initialized = (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED); |
3835 | 3915 | ||
3836 | netif_stop_queue(bcm->net_dev); | 3916 | netif_stop_queue(bcm->net_dev); |
3837 | tasklet_disable(&bcm->isr_tasklet); | 3917 | tasklet_disable(&bcm->isr_tasklet); |
@@ -3866,6 +3946,7 @@ failure: | |||
3866 | */ | 3946 | */ |
3867 | void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason) | 3947 | void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason) |
3868 | { | 3948 | { |
3949 | bcm43xx_set_status(bcm, BCM43xx_STAT_RESTARTING); | ||
3869 | bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); | 3950 | bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); |
3870 | bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */ | 3951 | bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */ |
3871 | printk(KERN_ERR PFX "Controller RESET (%s) ...\n", reason); | 3952 | printk(KERN_ERR PFX "Controller RESET (%s) ...\n", reason); |
@@ -3884,11 +3965,11 @@ static int bcm43xx_suspend(struct pci_dev *pdev, pm_message_t state) | |||
3884 | 3965 | ||
3885 | dprintk(KERN_INFO PFX "Suspending...\n"); | 3966 | dprintk(KERN_INFO PFX "Suspending...\n"); |
3886 | 3967 | ||
3887 | bcm43xx_lock(bcm, flags); | 3968 | bcm43xx_lock_irqsafe(bcm, flags); |
3888 | bcm->was_initialized = bcm->initialized; | 3969 | bcm->was_initialized = (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED); |
3889 | if (bcm->initialized) | 3970 | if (bcm->was_initialized) |
3890 | try_to_shutdown = 1; | 3971 | try_to_shutdown = 1; |
3891 | bcm43xx_unlock(bcm, flags); | 3972 | bcm43xx_unlock_irqsafe(bcm, flags); |
3892 | 3973 | ||
3893 | netif_device_detach(net_dev); | 3974 | netif_device_detach(net_dev); |
3894 | if (try_to_shutdown) { | 3975 | if (try_to_shutdown) { |
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c index b0abac515530..f8200deecc8a 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c | |||
@@ -1410,7 +1410,10 @@ static inline | |||
1410 | u16 bcm43xx_phy_lo_g_deviation_subval(struct bcm43xx_private *bcm, u16 control) | 1410 | u16 bcm43xx_phy_lo_g_deviation_subval(struct bcm43xx_private *bcm, u16 control) |
1411 | { | 1411 | { |
1412 | struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); | 1412 | struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); |
1413 | u16 ret; | ||
1414 | unsigned long flags; | ||
1413 | 1415 | ||
1416 | local_irq_save(flags); | ||
1414 | if (phy->connected) { | 1417 | if (phy->connected) { |
1415 | bcm43xx_phy_write(bcm, 0x15, 0xE300); | 1418 | bcm43xx_phy_write(bcm, 0x15, 0xE300); |
1416 | control <<= 8; | 1419 | control <<= 8; |
@@ -1430,8 +1433,10 @@ u16 bcm43xx_phy_lo_g_deviation_subval(struct bcm43xx_private *bcm, u16 control) | |||
1430 | bcm43xx_phy_write(bcm, 0x0015, control | 0xFFE0); | 1433 | bcm43xx_phy_write(bcm, 0x0015, control | 0xFFE0); |
1431 | udelay(8); | 1434 | udelay(8); |
1432 | } | 1435 | } |
1436 | ret = bcm43xx_phy_read(bcm, 0x002D); | ||
1437 | local_irq_restore(flags); | ||
1433 | 1438 | ||
1434 | return bcm43xx_phy_read(bcm, 0x002D); | 1439 | return ret; |
1435 | } | 1440 | } |
1436 | 1441 | ||
1437 | static u32 bcm43xx_phy_lo_g_singledeviation(struct bcm43xx_private *bcm, u16 control) | 1442 | static u32 bcm43xx_phy_lo_g_singledeviation(struct bcm43xx_private *bcm, u16 control) |
@@ -1648,7 +1653,7 @@ void bcm43xx_phy_set_baseband_attenuation(struct bcm43xx_private *bcm, | |||
1648 | void bcm43xx_phy_lo_g_measure(struct bcm43xx_private *bcm) | 1653 | void bcm43xx_phy_lo_g_measure(struct bcm43xx_private *bcm) |
1649 | { | 1654 | { |
1650 | static const u8 pairorder[10] = { 3, 1, 5, 7, 9, 2, 0, 4, 6, 8 }; | 1655 | static const u8 pairorder[10] = { 3, 1, 5, 7, 9, 2, 0, 4, 6, 8 }; |
1651 | const int is_initializing = bcm43xx_is_initializing(bcm); | 1656 | const int is_initializing = (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZING); |
1652 | struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); | 1657 | struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); |
1653 | struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); | 1658 | struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); |
1654 | u16 h, i, oldi = 0, j; | 1659 | u16 h, i, oldi = 0, j; |
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c index 0aa1bd269a25..574085c46152 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c | |||
@@ -262,8 +262,10 @@ static void tx_tasklet(unsigned long d) | |||
262 | int err; | 262 | int err; |
263 | u16 txctl; | 263 | u16 txctl; |
264 | 264 | ||
265 | bcm43xx_lock_mmio(bcm, flags); | 265 | bcm43xx_lock_irqonly(bcm, flags); |
266 | 266 | ||
267 | if (queue->tx_frozen) | ||
268 | goto out_unlock; | ||
267 | txctl = bcm43xx_pio_read(queue, BCM43xx_PIO_TXCTL); | 269 | txctl = bcm43xx_pio_read(queue, BCM43xx_PIO_TXCTL); |
268 | if (txctl & BCM43xx_PIO_TXCTL_SUSPEND) | 270 | if (txctl & BCM43xx_PIO_TXCTL_SUSPEND) |
269 | goto out_unlock; | 271 | goto out_unlock; |
@@ -298,7 +300,7 @@ static void tx_tasklet(unsigned long d) | |||
298 | continue; | 300 | continue; |
299 | } | 301 | } |
300 | out_unlock: | 302 | out_unlock: |
301 | bcm43xx_unlock_mmio(bcm, flags); | 303 | bcm43xx_unlock_irqonly(bcm, flags); |
302 | } | 304 | } |
303 | 305 | ||
304 | static void setup_txqueues(struct bcm43xx_pioqueue *queue) | 306 | static void setup_txqueues(struct bcm43xx_pioqueue *queue) |
@@ -374,7 +376,6 @@ static void cancel_transfers(struct bcm43xx_pioqueue *queue) | |||
374 | struct bcm43xx_pio_txpacket *packet, *tmp_packet; | 376 | struct bcm43xx_pio_txpacket *packet, *tmp_packet; |
375 | 377 | ||
376 | netif_tx_disable(queue->bcm->net_dev); | 378 | netif_tx_disable(queue->bcm->net_dev); |
377 | assert(queue->bcm->shutting_down); | ||
378 | tasklet_disable(&queue->txtask); | 379 | tasklet_disable(&queue->txtask); |
379 | 380 | ||
380 | list_for_each_entry_safe(packet, tmp_packet, &queue->txrunning, list) | 381 | list_for_each_entry_safe(packet, tmp_packet, &queue->txrunning, list) |
@@ -634,5 +635,40 @@ void bcm43xx_pio_tx_resume(struct bcm43xx_pioqueue *queue) | |||
634 | bcm43xx_pio_read(queue, BCM43xx_PIO_TXCTL) | 635 | bcm43xx_pio_read(queue, BCM43xx_PIO_TXCTL) |
635 | & ~BCM43xx_PIO_TXCTL_SUSPEND); | 636 | & ~BCM43xx_PIO_TXCTL_SUSPEND); |
636 | bcm43xx_power_saving_ctl_bits(queue->bcm, -1, -1); | 637 | bcm43xx_power_saving_ctl_bits(queue->bcm, -1, -1); |
637 | tasklet_schedule(&queue->txtask); | 638 | if (!list_empty(&queue->txqueue)) |
639 | tasklet_schedule(&queue->txtask); | ||
640 | } | ||
641 | |||
642 | void bcm43xx_pio_freeze_txqueues(struct bcm43xx_private *bcm) | ||
643 | { | ||
644 | struct bcm43xx_pio *pio; | ||
645 | |||
646 | assert(bcm43xx_using_pio(bcm)); | ||
647 | pio = bcm43xx_current_pio(bcm); | ||
648 | pio->queue0->tx_frozen = 1; | ||
649 | pio->queue1->tx_frozen = 1; | ||
650 | pio->queue2->tx_frozen = 1; | ||
651 | pio->queue3->tx_frozen = 1; | ||
638 | } | 652 | } |
653 | |||
654 | void bcm43xx_pio_thaw_txqueues(struct bcm43xx_private *bcm) | ||
655 | { | ||
656 | struct bcm43xx_pio *pio; | ||
657 | |||
658 | assert(bcm43xx_using_pio(bcm)); | ||
659 | pio = bcm43xx_current_pio(bcm); | ||
660 | pio->queue0->tx_frozen = 0; | ||
661 | pio->queue1->tx_frozen = 0; | ||
662 | pio->queue2->tx_frozen = 0; | ||
663 | pio->queue3->tx_frozen = 0; | ||
664 | if (!list_empty(&pio->queue0->txqueue)) | ||
665 | tasklet_schedule(&pio->queue0->txtask); | ||
666 | if (!list_empty(&pio->queue1->txqueue)) | ||
667 | tasklet_schedule(&pio->queue1->txtask); | ||
668 | if (!list_empty(&pio->queue2->txqueue)) | ||
669 | tasklet_schedule(&pio->queue2->txtask); | ||
670 | if (!list_empty(&pio->queue3->txqueue)) | ||
671 | tasklet_schedule(&pio->queue3->txtask); | ||
672 | } | ||
673 | |||
674 | |||
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.h b/drivers/net/wireless/bcm43xx/bcm43xx_pio.h index dfc78209e3a3..bc78a3c2cafb 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_pio.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_pio.h | |||
@@ -54,6 +54,7 @@ struct bcm43xx_pioqueue { | |||
54 | u16 mmio_base; | 54 | u16 mmio_base; |
55 | 55 | ||
56 | u8 tx_suspended:1, | 56 | u8 tx_suspended:1, |
57 | tx_frozen:1, | ||
57 | need_workarounds:1; /* Workarounds needed for core.rev < 3 */ | 58 | need_workarounds:1; /* Workarounds needed for core.rev < 3 */ |
58 | 59 | ||
59 | /* Adjusted size of the device internal TX buffer. */ | 60 | /* Adjusted size of the device internal TX buffer. */ |
@@ -108,8 +109,12 @@ void bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm, | |||
108 | struct bcm43xx_xmitstatus *status); | 109 | struct bcm43xx_xmitstatus *status); |
109 | void bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue); | 110 | void bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue); |
110 | 111 | ||
112 | /* Suspend a TX queue on hardware level. */ | ||
111 | void bcm43xx_pio_tx_suspend(struct bcm43xx_pioqueue *queue); | 113 | void bcm43xx_pio_tx_suspend(struct bcm43xx_pioqueue *queue); |
112 | void bcm43xx_pio_tx_resume(struct bcm43xx_pioqueue *queue); | 114 | void bcm43xx_pio_tx_resume(struct bcm43xx_pioqueue *queue); |
115 | /* Suspend (freeze) the TX tasklet (software level). */ | ||
116 | void bcm43xx_pio_freeze_txqueues(struct bcm43xx_private *bcm); | ||
117 | void bcm43xx_pio_thaw_txqueues(struct bcm43xx_private *bcm); | ||
113 | 118 | ||
114 | #else /* CONFIG_BCM43XX_PIO */ | 119 | #else /* CONFIG_BCM43XX_PIO */ |
115 | 120 | ||
@@ -145,6 +150,14 @@ static inline | |||
145 | void bcm43xx_pio_tx_resume(struct bcm43xx_pioqueue *queue) | 150 | void bcm43xx_pio_tx_resume(struct bcm43xx_pioqueue *queue) |
146 | { | 151 | { |
147 | } | 152 | } |
153 | static inline | ||
154 | void bcm43xx_pio_freeze_txqueues(struct bcm43xx_private *bcm) | ||
155 | { | ||
156 | } | ||
157 | static inline | ||
158 | void bcm43xx_pio_thaw_txqueues(struct bcm43xx_private *bcm) | ||
159 | { | ||
160 | } | ||
148 | 161 | ||
149 | #endif /* CONFIG_BCM43XX_PIO */ | 162 | #endif /* CONFIG_BCM43XX_PIO */ |
150 | #endif /* BCM43xx_PIO_H_ */ | 163 | #endif /* BCM43xx_PIO_H_ */ |
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c index b438f48e891d..6a23bdc75412 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c | |||
@@ -120,12 +120,12 @@ static ssize_t bcm43xx_attr_sprom_show(struct device *dev, | |||
120 | GFP_KERNEL); | 120 | GFP_KERNEL); |
121 | if (!sprom) | 121 | if (!sprom) |
122 | return -ENOMEM; | 122 | return -ENOMEM; |
123 | bcm43xx_lock_mmio(bcm, flags); | 123 | bcm43xx_lock_irqsafe(bcm, flags); |
124 | assert(bcm->initialized); | ||
125 | err = bcm43xx_sprom_read(bcm, sprom); | 124 | err = bcm43xx_sprom_read(bcm, sprom); |
126 | if (!err) | 125 | if (!err) |
127 | err = sprom2hex(sprom, buf, PAGE_SIZE); | 126 | err = sprom2hex(sprom, buf, PAGE_SIZE); |
128 | bcm43xx_unlock_mmio(bcm, flags); | 127 | mmiowb(); |
128 | bcm43xx_unlock_irqsafe(bcm, flags); | ||
129 | kfree(sprom); | 129 | kfree(sprom); |
130 | 130 | ||
131 | return err; | 131 | return err; |
@@ -150,10 +150,10 @@ static ssize_t bcm43xx_attr_sprom_store(struct device *dev, | |||
150 | err = hex2sprom(sprom, buf, count); | 150 | err = hex2sprom(sprom, buf, count); |
151 | if (err) | 151 | if (err) |
152 | goto out_kfree; | 152 | goto out_kfree; |
153 | bcm43xx_lock_mmio(bcm, flags); | 153 | bcm43xx_lock_irqsafe(bcm, flags); |
154 | assert(bcm->initialized); | ||
155 | err = bcm43xx_sprom_write(bcm, sprom); | 154 | err = bcm43xx_sprom_write(bcm, sprom); |
156 | bcm43xx_unlock_mmio(bcm, flags); | 155 | mmiowb(); |
156 | bcm43xx_unlock_irqsafe(bcm, flags); | ||
157 | out_kfree: | 157 | out_kfree: |
158 | kfree(sprom); | 158 | kfree(sprom); |
159 | 159 | ||
@@ -170,15 +170,13 @@ static ssize_t bcm43xx_attr_interfmode_show(struct device *dev, | |||
170 | char *buf) | 170 | char *buf) |
171 | { | 171 | { |
172 | struct bcm43xx_private *bcm = dev_to_bcm(dev); | 172 | struct bcm43xx_private *bcm = dev_to_bcm(dev); |
173 | unsigned long flags; | ||
174 | int err; | 173 | int err; |
175 | ssize_t count = 0; | 174 | ssize_t count = 0; |
176 | 175 | ||
177 | if (!capable(CAP_NET_ADMIN)) | 176 | if (!capable(CAP_NET_ADMIN)) |
178 | return -EPERM; | 177 | return -EPERM; |
179 | 178 | ||
180 | bcm43xx_lock(bcm, flags); | 179 | bcm43xx_lock_noirq(bcm); |
181 | assert(bcm->initialized); | ||
182 | 180 | ||
183 | switch (bcm43xx_current_radio(bcm)->interfmode) { | 181 | switch (bcm43xx_current_radio(bcm)->interfmode) { |
184 | case BCM43xx_RADIO_INTERFMODE_NONE: | 182 | case BCM43xx_RADIO_INTERFMODE_NONE: |
@@ -195,7 +193,7 @@ static ssize_t bcm43xx_attr_interfmode_show(struct device *dev, | |||
195 | } | 193 | } |
196 | err = 0; | 194 | err = 0; |
197 | 195 | ||
198 | bcm43xx_unlock(bcm, flags); | 196 | bcm43xx_unlock_noirq(bcm); |
199 | 197 | ||
200 | return err ? err : count; | 198 | return err ? err : count; |
201 | 199 | ||
@@ -231,16 +229,15 @@ static ssize_t bcm43xx_attr_interfmode_store(struct device *dev, | |||
231 | return -EINVAL; | 229 | return -EINVAL; |
232 | } | 230 | } |
233 | 231 | ||
234 | bcm43xx_lock_mmio(bcm, flags); | 232 | bcm43xx_lock_irqsafe(bcm, flags); |
235 | assert(bcm->initialized); | ||
236 | 233 | ||
237 | err = bcm43xx_radio_set_interference_mitigation(bcm, mode); | 234 | err = bcm43xx_radio_set_interference_mitigation(bcm, mode); |
238 | if (err) { | 235 | if (err) { |
239 | printk(KERN_ERR PFX "Interference Mitigation not " | 236 | printk(KERN_ERR PFX "Interference Mitigation not " |
240 | "supported by device\n"); | 237 | "supported by device\n"); |
241 | } | 238 | } |
242 | 239 | mmiowb(); | |
243 | bcm43xx_unlock_mmio(bcm, flags); | 240 | bcm43xx_unlock_irqsafe(bcm, flags); |
244 | 241 | ||
245 | return err ? err : count; | 242 | return err ? err : count; |
246 | } | 243 | } |
@@ -254,15 +251,13 @@ static ssize_t bcm43xx_attr_preamble_show(struct device *dev, | |||
254 | char *buf) | 251 | char *buf) |
255 | { | 252 | { |
256 | struct bcm43xx_private *bcm = dev_to_bcm(dev); | 253 | struct bcm43xx_private *bcm = dev_to_bcm(dev); |
257 | unsigned long flags; | ||
258 | int err; | 254 | int err; |
259 | ssize_t count; | 255 | ssize_t count; |
260 | 256 | ||
261 | if (!capable(CAP_NET_ADMIN)) | 257 | if (!capable(CAP_NET_ADMIN)) |
262 | return -EPERM; | 258 | return -EPERM; |
263 | 259 | ||
264 | bcm43xx_lock(bcm, flags); | 260 | bcm43xx_lock_noirq(bcm); |
265 | assert(bcm->initialized); | ||
266 | 261 | ||
267 | if (bcm->short_preamble) | 262 | if (bcm->short_preamble) |
268 | count = snprintf(buf, PAGE_SIZE, "1 (Short Preamble enabled)\n"); | 263 | count = snprintf(buf, PAGE_SIZE, "1 (Short Preamble enabled)\n"); |
@@ -270,7 +265,7 @@ static ssize_t bcm43xx_attr_preamble_show(struct device *dev, | |||
270 | count = snprintf(buf, PAGE_SIZE, "0 (Short Preamble disabled)\n"); | 265 | count = snprintf(buf, PAGE_SIZE, "0 (Short Preamble disabled)\n"); |
271 | 266 | ||
272 | err = 0; | 267 | err = 0; |
273 | bcm43xx_unlock(bcm, flags); | 268 | bcm43xx_unlock_noirq(bcm); |
274 | 269 | ||
275 | return err ? err : count; | 270 | return err ? err : count; |
276 | } | 271 | } |
@@ -290,13 +285,12 @@ static ssize_t bcm43xx_attr_preamble_store(struct device *dev, | |||
290 | value = get_boolean(buf, count); | 285 | value = get_boolean(buf, count); |
291 | if (value < 0) | 286 | if (value < 0) |
292 | return value; | 287 | return value; |
293 | bcm43xx_lock(bcm, flags); | 288 | bcm43xx_lock_irqsafe(bcm, flags); |
294 | assert(bcm->initialized); | ||
295 | 289 | ||
296 | bcm->short_preamble = !!value; | 290 | bcm->short_preamble = !!value; |
297 | 291 | ||
298 | err = 0; | 292 | err = 0; |
299 | bcm43xx_unlock(bcm, flags); | 293 | bcm43xx_unlock_irqsafe(bcm, flags); |
300 | 294 | ||
301 | return err ? err : count; | 295 | return err ? err : count; |
302 | } | 296 | } |
@@ -310,7 +304,7 @@ int bcm43xx_sysfs_register(struct bcm43xx_private *bcm) | |||
310 | struct device *dev = &bcm->pci_dev->dev; | 304 | struct device *dev = &bcm->pci_dev->dev; |
311 | int err; | 305 | int err; |
312 | 306 | ||
313 | assert(bcm->initialized); | 307 | assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED); |
314 | 308 | ||
315 | err = device_create_file(dev, &dev_attr_sprom); | 309 | err = device_create_file(dev, &dev_attr_sprom); |
316 | if (err) | 310 | if (err) |
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c index b45063974ae9..c35cb3a0777e 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c | |||
@@ -55,13 +55,13 @@ static int bcm43xx_wx_get_name(struct net_device *net_dev, | |||
55 | char *extra) | 55 | char *extra) |
56 | { | 56 | { |
57 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); | 57 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); |
58 | unsigned long flags; | ||
59 | int i; | 58 | int i; |
59 | unsigned long flags; | ||
60 | struct bcm43xx_phyinfo *phy; | 60 | struct bcm43xx_phyinfo *phy; |
61 | char suffix[7] = { 0 }; | 61 | char suffix[7] = { 0 }; |
62 | int have_a = 0, have_b = 0, have_g = 0; | 62 | int have_a = 0, have_b = 0, have_g = 0; |
63 | 63 | ||
64 | bcm43xx_lock(bcm, flags); | 64 | bcm43xx_lock_irqsafe(bcm, flags); |
65 | for (i = 0; i < bcm->nr_80211_available; i++) { | 65 | for (i = 0; i < bcm->nr_80211_available; i++) { |
66 | phy = &(bcm->core_80211_ext[i].phy); | 66 | phy = &(bcm->core_80211_ext[i].phy); |
67 | switch (phy->type) { | 67 | switch (phy->type) { |
@@ -77,7 +77,7 @@ static int bcm43xx_wx_get_name(struct net_device *net_dev, | |||
77 | assert(0); | 77 | assert(0); |
78 | } | 78 | } |
79 | } | 79 | } |
80 | bcm43xx_unlock(bcm, flags); | 80 | bcm43xx_unlock_irqsafe(bcm, flags); |
81 | 81 | ||
82 | i = 0; | 82 | i = 0; |
83 | if (have_a) { | 83 | if (have_a) { |
@@ -111,7 +111,7 @@ static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev, | |||
111 | int freq; | 111 | int freq; |
112 | int err = -EINVAL; | 112 | int err = -EINVAL; |
113 | 113 | ||
114 | bcm43xx_lock_mmio(bcm, flags); | 114 | bcm43xx_lock_irqsafe(bcm, flags); |
115 | if ((data->freq.m >= 0) && (data->freq.m <= 1000)) { | 115 | if ((data->freq.m >= 0) && (data->freq.m <= 1000)) { |
116 | channel = data->freq.m; | 116 | channel = data->freq.m; |
117 | freq = bcm43xx_channel_to_freq(bcm, channel); | 117 | freq = bcm43xx_channel_to_freq(bcm, channel); |
@@ -121,7 +121,7 @@ static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev, | |||
121 | } | 121 | } |
122 | if (!bcm43xx_is_valid_channel(bcm, channel)) | 122 | if (!bcm43xx_is_valid_channel(bcm, channel)) |
123 | goto out_unlock; | 123 | goto out_unlock; |
124 | if (bcm->initialized) { | 124 | if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) { |
125 | //ieee80211softmac_disassoc(softmac, $REASON); | 125 | //ieee80211softmac_disassoc(softmac, $REASON); |
126 | bcm43xx_mac_suspend(bcm); | 126 | bcm43xx_mac_suspend(bcm); |
127 | err = bcm43xx_radio_selectchannel(bcm, channel, 0); | 127 | err = bcm43xx_radio_selectchannel(bcm, channel, 0); |
@@ -131,7 +131,7 @@ static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev, | |||
131 | err = 0; | 131 | err = 0; |
132 | } | 132 | } |
133 | out_unlock: | 133 | out_unlock: |
134 | bcm43xx_unlock_mmio(bcm, flags); | 134 | bcm43xx_unlock_irqsafe(bcm, flags); |
135 | 135 | ||
136 | return err; | 136 | return err; |
137 | } | 137 | } |
@@ -147,11 +147,10 @@ static int bcm43xx_wx_get_channelfreq(struct net_device *net_dev, | |||
147 | int err = -ENODEV; | 147 | int err = -ENODEV; |
148 | u16 channel; | 148 | u16 channel; |
149 | 149 | ||
150 | bcm43xx_lock(bcm, flags); | 150 | bcm43xx_lock_irqsafe(bcm, flags); |
151 | radio = bcm43xx_current_radio(bcm); | 151 | radio = bcm43xx_current_radio(bcm); |
152 | channel = radio->channel; | 152 | channel = radio->channel; |
153 | if (channel == 0xFF) { | 153 | if (channel == 0xFF) { |
154 | assert(!bcm->initialized); | ||
155 | channel = radio->initial_channel; | 154 | channel = radio->initial_channel; |
156 | if (channel == 0xFF) | 155 | if (channel == 0xFF) |
157 | goto out_unlock; | 156 | goto out_unlock; |
@@ -163,7 +162,7 @@ static int bcm43xx_wx_get_channelfreq(struct net_device *net_dev, | |||
163 | 162 | ||
164 | err = 0; | 163 | err = 0; |
165 | out_unlock: | 164 | out_unlock: |
166 | bcm43xx_unlock(bcm, flags); | 165 | bcm43xx_unlock_irqsafe(bcm, flags); |
167 | 166 | ||
168 | return err; | 167 | return err; |
169 | } | 168 | } |
@@ -181,13 +180,13 @@ static int bcm43xx_wx_set_mode(struct net_device *net_dev, | |||
181 | if (mode == IW_MODE_AUTO) | 180 | if (mode == IW_MODE_AUTO) |
182 | mode = BCM43xx_INITIAL_IWMODE; | 181 | mode = BCM43xx_INITIAL_IWMODE; |
183 | 182 | ||
184 | bcm43xx_lock_mmio(bcm, flags); | 183 | bcm43xx_lock_irqsafe(bcm, flags); |
185 | if (bcm->initialized) { | 184 | if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) { |
186 | if (bcm->ieee->iw_mode != mode) | 185 | if (bcm->ieee->iw_mode != mode) |
187 | bcm43xx_set_iwmode(bcm, mode); | 186 | bcm43xx_set_iwmode(bcm, mode); |
188 | } else | 187 | } else |
189 | bcm->ieee->iw_mode = mode; | 188 | bcm->ieee->iw_mode = mode; |
190 | bcm43xx_unlock_mmio(bcm, flags); | 189 | bcm43xx_unlock_irqsafe(bcm, flags); |
191 | 190 | ||
192 | return 0; | 191 | return 0; |
193 | } | 192 | } |
@@ -200,9 +199,9 @@ static int bcm43xx_wx_get_mode(struct net_device *net_dev, | |||
200 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); | 199 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); |
201 | unsigned long flags; | 200 | unsigned long flags; |
202 | 201 | ||
203 | bcm43xx_lock(bcm, flags); | 202 | bcm43xx_lock_irqsafe(bcm, flags); |
204 | data->mode = bcm->ieee->iw_mode; | 203 | data->mode = bcm->ieee->iw_mode; |
205 | bcm43xx_unlock(bcm, flags); | 204 | bcm43xx_unlock_irqsafe(bcm, flags); |
206 | 205 | ||
207 | return 0; | 206 | return 0; |
208 | } | 207 | } |
@@ -255,7 +254,7 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev, | |||
255 | IW_ENC_CAPA_CIPHER_TKIP | | 254 | IW_ENC_CAPA_CIPHER_TKIP | |
256 | IW_ENC_CAPA_CIPHER_CCMP; | 255 | IW_ENC_CAPA_CIPHER_CCMP; |
257 | 256 | ||
258 | bcm43xx_lock(bcm, flags); | 257 | bcm43xx_lock_irqsafe(bcm, flags); |
259 | phy = bcm43xx_current_phy(bcm); | 258 | phy = bcm43xx_current_phy(bcm); |
260 | 259 | ||
261 | range->num_bitrates = 0; | 260 | range->num_bitrates = 0; |
@@ -302,7 +301,7 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev, | |||
302 | } | 301 | } |
303 | range->num_frequency = j; | 302 | range->num_frequency = j; |
304 | 303 | ||
305 | bcm43xx_unlock(bcm, flags); | 304 | bcm43xx_unlock_irqsafe(bcm, flags); |
306 | 305 | ||
307 | return 0; | 306 | return 0; |
308 | } | 307 | } |
@@ -313,14 +312,13 @@ static int bcm43xx_wx_set_nick(struct net_device *net_dev, | |||
313 | char *extra) | 312 | char *extra) |
314 | { | 313 | { |
315 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); | 314 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); |
316 | unsigned long flags; | ||
317 | size_t len; | 315 | size_t len; |
318 | 316 | ||
319 | bcm43xx_lock(bcm, flags); | 317 | bcm43xx_lock_noirq(bcm); |
320 | len = min((size_t)data->data.length, (size_t)IW_ESSID_MAX_SIZE); | 318 | len = min((size_t)data->data.length, (size_t)IW_ESSID_MAX_SIZE); |
321 | memcpy(bcm->nick, extra, len); | 319 | memcpy(bcm->nick, extra, len); |
322 | bcm->nick[len] = '\0'; | 320 | bcm->nick[len] = '\0'; |
323 | bcm43xx_unlock(bcm, flags); | 321 | bcm43xx_unlock_noirq(bcm); |
324 | 322 | ||
325 | return 0; | 323 | return 0; |
326 | } | 324 | } |
@@ -331,15 +329,14 @@ static int bcm43xx_wx_get_nick(struct net_device *net_dev, | |||
331 | char *extra) | 329 | char *extra) |
332 | { | 330 | { |
333 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); | 331 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); |
334 | unsigned long flags; | ||
335 | size_t len; | 332 | size_t len; |
336 | 333 | ||
337 | bcm43xx_lock(bcm, flags); | 334 | bcm43xx_lock_noirq(bcm); |
338 | len = strlen(bcm->nick) + 1; | 335 | len = strlen(bcm->nick) + 1; |
339 | memcpy(extra, bcm->nick, len); | 336 | memcpy(extra, bcm->nick, len); |
340 | data->data.length = (__u16)len; | 337 | data->data.length = (__u16)len; |
341 | data->data.flags = 1; | 338 | data->data.flags = 1; |
342 | bcm43xx_unlock(bcm, flags); | 339 | bcm43xx_unlock_noirq(bcm); |
343 | 340 | ||
344 | return 0; | 341 | return 0; |
345 | } | 342 | } |
@@ -353,7 +350,7 @@ static int bcm43xx_wx_set_rts(struct net_device *net_dev, | |||
353 | unsigned long flags; | 350 | unsigned long flags; |
354 | int err = -EINVAL; | 351 | int err = -EINVAL; |
355 | 352 | ||
356 | bcm43xx_lock(bcm, flags); | 353 | bcm43xx_lock_irqsafe(bcm, flags); |
357 | if (data->rts.disabled) { | 354 | if (data->rts.disabled) { |
358 | bcm->rts_threshold = BCM43xx_MAX_RTS_THRESHOLD; | 355 | bcm->rts_threshold = BCM43xx_MAX_RTS_THRESHOLD; |
359 | err = 0; | 356 | err = 0; |
@@ -364,7 +361,7 @@ static int bcm43xx_wx_set_rts(struct net_device *net_dev, | |||
364 | err = 0; | 361 | err = 0; |
365 | } | 362 | } |
366 | } | 363 | } |
367 | bcm43xx_unlock(bcm, flags); | 364 | bcm43xx_unlock_irqsafe(bcm, flags); |
368 | 365 | ||
369 | return err; | 366 | return err; |
370 | } | 367 | } |
@@ -377,11 +374,11 @@ static int bcm43xx_wx_get_rts(struct net_device *net_dev, | |||
377 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); | 374 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); |
378 | unsigned long flags; | 375 | unsigned long flags; |
379 | 376 | ||
380 | bcm43xx_lock(bcm, flags); | 377 | bcm43xx_lock_irqsafe(bcm, flags); |
381 | data->rts.value = bcm->rts_threshold; | 378 | data->rts.value = bcm->rts_threshold; |
382 | data->rts.fixed = 0; | 379 | data->rts.fixed = 0; |
383 | data->rts.disabled = (bcm->rts_threshold == BCM43xx_MAX_RTS_THRESHOLD); | 380 | data->rts.disabled = (bcm->rts_threshold == BCM43xx_MAX_RTS_THRESHOLD); |
384 | bcm43xx_unlock(bcm, flags); | 381 | bcm43xx_unlock_irqsafe(bcm, flags); |
385 | 382 | ||
386 | return 0; | 383 | return 0; |
387 | } | 384 | } |
@@ -395,7 +392,7 @@ static int bcm43xx_wx_set_frag(struct net_device *net_dev, | |||
395 | unsigned long flags; | 392 | unsigned long flags; |
396 | int err = -EINVAL; | 393 | int err = -EINVAL; |
397 | 394 | ||
398 | bcm43xx_lock(bcm, flags); | 395 | bcm43xx_lock_irqsafe(bcm, flags); |
399 | if (data->frag.disabled) { | 396 | if (data->frag.disabled) { |
400 | bcm->ieee->fts = MAX_FRAG_THRESHOLD; | 397 | bcm->ieee->fts = MAX_FRAG_THRESHOLD; |
401 | err = 0; | 398 | err = 0; |
@@ -406,7 +403,7 @@ static int bcm43xx_wx_set_frag(struct net_device *net_dev, | |||
406 | err = 0; | 403 | err = 0; |
407 | } | 404 | } |
408 | } | 405 | } |
409 | bcm43xx_unlock(bcm, flags); | 406 | bcm43xx_unlock_irqsafe(bcm, flags); |
410 | 407 | ||
411 | return err; | 408 | return err; |
412 | } | 409 | } |
@@ -419,11 +416,11 @@ static int bcm43xx_wx_get_frag(struct net_device *net_dev, | |||
419 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); | 416 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); |
420 | unsigned long flags; | 417 | unsigned long flags; |
421 | 418 | ||
422 | bcm43xx_lock(bcm, flags); | 419 | bcm43xx_lock_irqsafe(bcm, flags); |
423 | data->frag.value = bcm->ieee->fts; | 420 | data->frag.value = bcm->ieee->fts; |
424 | data->frag.fixed = 0; | 421 | data->frag.fixed = 0; |
425 | data->frag.disabled = (bcm->ieee->fts == MAX_FRAG_THRESHOLD); | 422 | data->frag.disabled = (bcm->ieee->fts == MAX_FRAG_THRESHOLD); |
426 | bcm43xx_unlock(bcm, flags); | 423 | bcm43xx_unlock_irqsafe(bcm, flags); |
427 | 424 | ||
428 | return 0; | 425 | return 0; |
429 | } | 426 | } |
@@ -445,8 +442,8 @@ static int bcm43xx_wx_set_xmitpower(struct net_device *net_dev, | |||
445 | return -EOPNOTSUPP; | 442 | return -EOPNOTSUPP; |
446 | } | 443 | } |
447 | 444 | ||
448 | bcm43xx_lock_mmio(bcm, flags); | 445 | bcm43xx_lock_irqsafe(bcm, flags); |
449 | if (!bcm->initialized) | 446 | if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) |
450 | goto out_unlock; | 447 | goto out_unlock; |
451 | radio = bcm43xx_current_radio(bcm); | 448 | radio = bcm43xx_current_radio(bcm); |
452 | phy = bcm43xx_current_phy(bcm); | 449 | phy = bcm43xx_current_phy(bcm); |
@@ -469,7 +466,7 @@ static int bcm43xx_wx_set_xmitpower(struct net_device *net_dev, | |||
469 | err = 0; | 466 | err = 0; |
470 | 467 | ||
471 | out_unlock: | 468 | out_unlock: |
472 | bcm43xx_unlock_mmio(bcm, flags); | 469 | bcm43xx_unlock_irqsafe(bcm, flags); |
473 | 470 | ||
474 | return err; | 471 | return err; |
475 | } | 472 | } |
@@ -484,8 +481,8 @@ static int bcm43xx_wx_get_xmitpower(struct net_device *net_dev, | |||
484 | unsigned long flags; | 481 | unsigned long flags; |
485 | int err = -ENODEV; | 482 | int err = -ENODEV; |
486 | 483 | ||
487 | bcm43xx_lock(bcm, flags); | 484 | bcm43xx_lock_irqsafe(bcm, flags); |
488 | if (!bcm->initialized) | 485 | if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) |
489 | goto out_unlock; | 486 | goto out_unlock; |
490 | radio = bcm43xx_current_radio(bcm); | 487 | radio = bcm43xx_current_radio(bcm); |
491 | /* desired dBm value is in Q5.2 */ | 488 | /* desired dBm value is in Q5.2 */ |
@@ -496,7 +493,7 @@ static int bcm43xx_wx_get_xmitpower(struct net_device *net_dev, | |||
496 | 493 | ||
497 | err = 0; | 494 | err = 0; |
498 | out_unlock: | 495 | out_unlock: |
499 | bcm43xx_unlock(bcm, flags); | 496 | bcm43xx_unlock_irqsafe(bcm, flags); |
500 | 497 | ||
501 | return err; | 498 | return err; |
502 | } | 499 | } |
@@ -583,8 +580,8 @@ static int bcm43xx_wx_set_interfmode(struct net_device *net_dev, | |||
583 | return -EINVAL; | 580 | return -EINVAL; |
584 | } | 581 | } |
585 | 582 | ||
586 | bcm43xx_lock_mmio(bcm, flags); | 583 | bcm43xx_lock_irqsafe(bcm, flags); |
587 | if (bcm->initialized) { | 584 | if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) { |
588 | err = bcm43xx_radio_set_interference_mitigation(bcm, mode); | 585 | err = bcm43xx_radio_set_interference_mitigation(bcm, mode); |
589 | if (err) { | 586 | if (err) { |
590 | printk(KERN_ERR PFX "Interference Mitigation not " | 587 | printk(KERN_ERR PFX "Interference Mitigation not " |
@@ -598,7 +595,7 @@ static int bcm43xx_wx_set_interfmode(struct net_device *net_dev, | |||
598 | } else | 595 | } else |
599 | bcm43xx_current_radio(bcm)->interfmode = mode; | 596 | bcm43xx_current_radio(bcm)->interfmode = mode; |
600 | } | 597 | } |
601 | bcm43xx_unlock_mmio(bcm, flags); | 598 | bcm43xx_unlock_irqsafe(bcm, flags); |
602 | 599 | ||
603 | return err; | 600 | return err; |
604 | } | 601 | } |
@@ -612,9 +609,9 @@ static int bcm43xx_wx_get_interfmode(struct net_device *net_dev, | |||
612 | unsigned long flags; | 609 | unsigned long flags; |
613 | int mode; | 610 | int mode; |
614 | 611 | ||
615 | bcm43xx_lock(bcm, flags); | 612 | bcm43xx_lock_irqsafe(bcm, flags); |
616 | mode = bcm43xx_current_radio(bcm)->interfmode; | 613 | mode = bcm43xx_current_radio(bcm)->interfmode; |
617 | bcm43xx_unlock(bcm, flags); | 614 | bcm43xx_unlock_irqsafe(bcm, flags); |
618 | 615 | ||
619 | switch (mode) { | 616 | switch (mode) { |
620 | case BCM43xx_RADIO_INTERFMODE_NONE: | 617 | case BCM43xx_RADIO_INTERFMODE_NONE: |
@@ -644,9 +641,9 @@ static int bcm43xx_wx_set_shortpreamble(struct net_device *net_dev, | |||
644 | int on; | 641 | int on; |
645 | 642 | ||
646 | on = *((int *)extra); | 643 | on = *((int *)extra); |
647 | bcm43xx_lock(bcm, flags); | 644 | bcm43xx_lock_irqsafe(bcm, flags); |
648 | bcm->short_preamble = !!on; | 645 | bcm->short_preamble = !!on; |
649 | bcm43xx_unlock(bcm, flags); | 646 | bcm43xx_unlock_irqsafe(bcm, flags); |
650 | 647 | ||
651 | return 0; | 648 | return 0; |
652 | } | 649 | } |
@@ -660,9 +657,9 @@ static int bcm43xx_wx_get_shortpreamble(struct net_device *net_dev, | |||
660 | unsigned long flags; | 657 | unsigned long flags; |
661 | int on; | 658 | int on; |
662 | 659 | ||
663 | bcm43xx_lock(bcm, flags); | 660 | bcm43xx_lock_irqsafe(bcm, flags); |
664 | on = bcm->short_preamble; | 661 | on = bcm->short_preamble; |
665 | bcm43xx_unlock(bcm, flags); | 662 | bcm43xx_unlock_irqsafe(bcm, flags); |
666 | 663 | ||
667 | if (on) | 664 | if (on) |
668 | strncpy(extra, "1 (Short Preamble enabled)", MAX_WX_STRING); | 665 | strncpy(extra, "1 (Short Preamble enabled)", MAX_WX_STRING); |
@@ -684,11 +681,11 @@ static int bcm43xx_wx_set_swencryption(struct net_device *net_dev, | |||
684 | 681 | ||
685 | on = *((int *)extra); | 682 | on = *((int *)extra); |
686 | 683 | ||
687 | bcm43xx_lock(bcm, flags); | 684 | bcm43xx_lock_irqsafe(bcm, flags); |
688 | bcm->ieee->host_encrypt = !!on; | 685 | bcm->ieee->host_encrypt = !!on; |
689 | bcm->ieee->host_decrypt = !!on; | 686 | bcm->ieee->host_decrypt = !!on; |
690 | bcm->ieee->host_build_iv = !on; | 687 | bcm->ieee->host_build_iv = !on; |
691 | bcm43xx_unlock(bcm, flags); | 688 | bcm43xx_unlock_irqsafe(bcm, flags); |
692 | 689 | ||
693 | return 0; | 690 | return 0; |
694 | } | 691 | } |
@@ -702,9 +699,9 @@ static int bcm43xx_wx_get_swencryption(struct net_device *net_dev, | |||
702 | unsigned long flags; | 699 | unsigned long flags; |
703 | int on; | 700 | int on; |
704 | 701 | ||
705 | bcm43xx_lock(bcm, flags); | 702 | bcm43xx_lock_irqsafe(bcm, flags); |
706 | on = bcm->ieee->host_encrypt; | 703 | on = bcm->ieee->host_encrypt; |
707 | bcm43xx_unlock(bcm, flags); | 704 | bcm43xx_unlock_irqsafe(bcm, flags); |
708 | 705 | ||
709 | if (on) | 706 | if (on) |
710 | strncpy(extra, "1 (SW encryption enabled) ", MAX_WX_STRING); | 707 | strncpy(extra, "1 (SW encryption enabled) ", MAX_WX_STRING); |
@@ -767,11 +764,11 @@ static int bcm43xx_wx_sprom_read(struct net_device *net_dev, | |||
767 | if (!sprom) | 764 | if (!sprom) |
768 | goto out; | 765 | goto out; |
769 | 766 | ||
770 | bcm43xx_lock_mmio(bcm, flags); | 767 | bcm43xx_lock_irqsafe(bcm, flags); |
771 | err = -ENODEV; | 768 | err = -ENODEV; |
772 | if (bcm->initialized) | 769 | if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) |
773 | err = bcm43xx_sprom_read(bcm, sprom); | 770 | err = bcm43xx_sprom_read(bcm, sprom); |
774 | bcm43xx_unlock_mmio(bcm, flags); | 771 | bcm43xx_unlock_irqsafe(bcm, flags); |
775 | if (!err) | 772 | if (!err) |
776 | data->data.length = sprom2hex(sprom, extra); | 773 | data->data.length = sprom2hex(sprom, extra); |
777 | kfree(sprom); | 774 | kfree(sprom); |
@@ -812,11 +809,11 @@ static int bcm43xx_wx_sprom_write(struct net_device *net_dev, | |||
812 | if (err) | 809 | if (err) |
813 | goto out_kfree; | 810 | goto out_kfree; |
814 | 811 | ||
815 | bcm43xx_lock_mmio(bcm, flags); | 812 | bcm43xx_lock_irqsafe(bcm, flags); |
816 | err = -ENODEV; | 813 | err = -ENODEV; |
817 | if (bcm->initialized) | 814 | if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) |
818 | err = bcm43xx_sprom_write(bcm, sprom); | 815 | err = bcm43xx_sprom_write(bcm, sprom); |
819 | bcm43xx_unlock_mmio(bcm, flags); | 816 | bcm43xx_unlock_irqsafe(bcm, flags); |
820 | out_kfree: | 817 | out_kfree: |
821 | kfree(sprom); | 818 | kfree(sprom); |
822 | out: | 819 | out: |
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 39f82f219749..081a8999666e 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c | |||
@@ -533,7 +533,7 @@ static inline void ipw_clear_bit(struct ipw_priv *priv, u32 reg, u32 mask) | |||
533 | ipw_write32(priv, reg, ipw_read32(priv, reg) & ~mask); | 533 | ipw_write32(priv, reg, ipw_read32(priv, reg) & ~mask); |
534 | } | 534 | } |
535 | 535 | ||
536 | static inline void ipw_enable_interrupts(struct ipw_priv *priv) | 536 | static inline void __ipw_enable_interrupts(struct ipw_priv *priv) |
537 | { | 537 | { |
538 | if (priv->status & STATUS_INT_ENABLED) | 538 | if (priv->status & STATUS_INT_ENABLED) |
539 | return; | 539 | return; |
@@ -541,7 +541,7 @@ static inline void ipw_enable_interrupts(struct ipw_priv *priv) | |||
541 | ipw_write32(priv, IPW_INTA_MASK_R, IPW_INTA_MASK_ALL); | 541 | ipw_write32(priv, IPW_INTA_MASK_R, IPW_INTA_MASK_ALL); |
542 | } | 542 | } |
543 | 543 | ||
544 | static inline void ipw_disable_interrupts(struct ipw_priv *priv) | 544 | static inline void __ipw_disable_interrupts(struct ipw_priv *priv) |
545 | { | 545 | { |
546 | if (!(priv->status & STATUS_INT_ENABLED)) | 546 | if (!(priv->status & STATUS_INT_ENABLED)) |
547 | return; | 547 | return; |
@@ -549,6 +549,24 @@ static inline void ipw_disable_interrupts(struct ipw_priv *priv) | |||
549 | ipw_write32(priv, IPW_INTA_MASK_R, ~IPW_INTA_MASK_ALL); | 549 | ipw_write32(priv, IPW_INTA_MASK_R, ~IPW_INTA_MASK_ALL); |
550 | } | 550 | } |
551 | 551 | ||
552 | static inline void ipw_enable_interrupts(struct ipw_priv *priv) | ||
553 | { | ||
554 | unsigned long flags; | ||
555 | |||
556 | spin_lock_irqsave(&priv->irq_lock, flags); | ||
557 | __ipw_enable_interrupts(priv); | ||
558 | spin_unlock_irqrestore(&priv->irq_lock, flags); | ||
559 | } | ||
560 | |||
561 | static inline void ipw_disable_interrupts(struct ipw_priv *priv) | ||
562 | { | ||
563 | unsigned long flags; | ||
564 | |||
565 | spin_lock_irqsave(&priv->irq_lock, flags); | ||
566 | __ipw_disable_interrupts(priv); | ||
567 | spin_unlock_irqrestore(&priv->irq_lock, flags); | ||
568 | } | ||
569 | |||
552 | #ifdef CONFIG_IPW2200_DEBUG | 570 | #ifdef CONFIG_IPW2200_DEBUG |
553 | static char *ipw_error_desc(u32 val) | 571 | static char *ipw_error_desc(u32 val) |
554 | { | 572 | { |
@@ -1856,7 +1874,7 @@ static void ipw_irq_tasklet(struct ipw_priv *priv) | |||
1856 | unsigned long flags; | 1874 | unsigned long flags; |
1857 | int rc = 0; | 1875 | int rc = 0; |
1858 | 1876 | ||
1859 | spin_lock_irqsave(&priv->lock, flags); | 1877 | spin_lock_irqsave(&priv->irq_lock, flags); |
1860 | 1878 | ||
1861 | inta = ipw_read32(priv, IPW_INTA_RW); | 1879 | inta = ipw_read32(priv, IPW_INTA_RW); |
1862 | inta_mask = ipw_read32(priv, IPW_INTA_MASK_R); | 1880 | inta_mask = ipw_read32(priv, IPW_INTA_MASK_R); |
@@ -1865,6 +1883,10 @@ static void ipw_irq_tasklet(struct ipw_priv *priv) | |||
1865 | /* Add any cached INTA values that need to be handled */ | 1883 | /* Add any cached INTA values that need to be handled */ |
1866 | inta |= priv->isr_inta; | 1884 | inta |= priv->isr_inta; |
1867 | 1885 | ||
1886 | spin_unlock_irqrestore(&priv->irq_lock, flags); | ||
1887 | |||
1888 | spin_lock_irqsave(&priv->lock, flags); | ||
1889 | |||
1868 | /* handle all the justifications for the interrupt */ | 1890 | /* handle all the justifications for the interrupt */ |
1869 | if (inta & IPW_INTA_BIT_RX_TRANSFER) { | 1891 | if (inta & IPW_INTA_BIT_RX_TRANSFER) { |
1870 | ipw_rx(priv); | 1892 | ipw_rx(priv); |
@@ -1993,10 +2015,10 @@ static void ipw_irq_tasklet(struct ipw_priv *priv) | |||
1993 | IPW_ERROR("Unhandled INTA bits 0x%08x\n", inta & ~handled); | 2015 | IPW_ERROR("Unhandled INTA bits 0x%08x\n", inta & ~handled); |
1994 | } | 2016 | } |
1995 | 2017 | ||
2018 | spin_unlock_irqrestore(&priv->lock, flags); | ||
2019 | |||
1996 | /* enable all interrupts */ | 2020 | /* enable all interrupts */ |
1997 | ipw_enable_interrupts(priv); | 2021 | ipw_enable_interrupts(priv); |
1998 | |||
1999 | spin_unlock_irqrestore(&priv->lock, flags); | ||
2000 | } | 2022 | } |
2001 | 2023 | ||
2002 | #define IPW_CMD(x) case IPW_CMD_ ## x : return #x | 2024 | #define IPW_CMD(x) case IPW_CMD_ ## x : return #x |
@@ -10460,7 +10482,7 @@ static irqreturn_t ipw_isr(int irq, void *data, struct pt_regs *regs) | |||
10460 | if (!priv) | 10482 | if (!priv) |
10461 | return IRQ_NONE; | 10483 | return IRQ_NONE; |
10462 | 10484 | ||
10463 | spin_lock(&priv->lock); | 10485 | spin_lock(&priv->irq_lock); |
10464 | 10486 | ||
10465 | if (!(priv->status & STATUS_INT_ENABLED)) { | 10487 | if (!(priv->status & STATUS_INT_ENABLED)) { |
10466 | /* Shared IRQ */ | 10488 | /* Shared IRQ */ |
@@ -10482,7 +10504,7 @@ static irqreturn_t ipw_isr(int irq, void *data, struct pt_regs *regs) | |||
10482 | } | 10504 | } |
10483 | 10505 | ||
10484 | /* tell the device to stop sending interrupts */ | 10506 | /* tell the device to stop sending interrupts */ |
10485 | ipw_disable_interrupts(priv); | 10507 | __ipw_disable_interrupts(priv); |
10486 | 10508 | ||
10487 | /* ack current interrupts */ | 10509 | /* ack current interrupts */ |
10488 | inta &= (IPW_INTA_MASK_ALL & inta_mask); | 10510 | inta &= (IPW_INTA_MASK_ALL & inta_mask); |
@@ -10493,11 +10515,11 @@ static irqreturn_t ipw_isr(int irq, void *data, struct pt_regs *regs) | |||
10493 | 10515 | ||
10494 | tasklet_schedule(&priv->irq_tasklet); | 10516 | tasklet_schedule(&priv->irq_tasklet); |
10495 | 10517 | ||
10496 | spin_unlock(&priv->lock); | 10518 | spin_unlock(&priv->irq_lock); |
10497 | 10519 | ||
10498 | return IRQ_HANDLED; | 10520 | return IRQ_HANDLED; |
10499 | none: | 10521 | none: |
10500 | spin_unlock(&priv->lock); | 10522 | spin_unlock(&priv->irq_lock); |
10501 | return IRQ_NONE; | 10523 | return IRQ_NONE; |
10502 | } | 10524 | } |
10503 | 10525 | ||
@@ -11477,6 +11499,7 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
11477 | #ifdef CONFIG_IPW2200_DEBUG | 11499 | #ifdef CONFIG_IPW2200_DEBUG |
11478 | ipw_debug_level = debug; | 11500 | ipw_debug_level = debug; |
11479 | #endif | 11501 | #endif |
11502 | spin_lock_init(&priv->irq_lock); | ||
11480 | spin_lock_init(&priv->lock); | 11503 | spin_lock_init(&priv->lock); |
11481 | for (i = 0; i < IPW_IBSS_MAC_HASH_SIZE; i++) | 11504 | for (i = 0; i < IPW_IBSS_MAC_HASH_SIZE; i++) |
11482 | INIT_LIST_HEAD(&priv->ibss_mac_hash[i]); | 11505 | INIT_LIST_HEAD(&priv->ibss_mac_hash[i]); |
diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h index 6044c0be2c80..ea12ad66b8e8 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2200.h | |||
@@ -1173,6 +1173,7 @@ struct ipw_priv { | |||
1173 | struct ieee80211_device *ieee; | 1173 | struct ieee80211_device *ieee; |
1174 | 1174 | ||
1175 | spinlock_t lock; | 1175 | spinlock_t lock; |
1176 | spinlock_t irq_lock; | ||
1176 | struct mutex mutex; | 1177 | struct mutex mutex; |
1177 | 1178 | ||
1178 | /* basic pci-network driver stuff */ | 1179 | /* basic pci-network driver stuff */ |
diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c index dade4b903579..5b69befdab74 100644 --- a/drivers/net/wireless/wavelan.c +++ b/drivers/net/wireless/wavelan.c | |||
@@ -1695,8 +1695,8 @@ static int wv_frequency_list(unsigned long ioaddr, /* I/O port of the card */ | |||
1695 | /* Look in the table if the frequency is allowed */ | 1695 | /* Look in the table if the frequency is allowed */ |
1696 | if (table[9 - (freq / 16)] & (1 << (freq % 16))) { | 1696 | if (table[9 - (freq / 16)] & (1 << (freq % 16))) { |
1697 | /* Compute approximate channel number */ | 1697 | /* Compute approximate channel number */ |
1698 | while ((((channel_bands[c] >> 1) - 24) < freq) && | 1698 | while ((c < NELS(channel_bands)) && |
1699 | (c < NELS(channel_bands))) | 1699 | (((channel_bands[c] >> 1) - 24) < freq)) |
1700 | c++; | 1700 | c++; |
1701 | list[i].i = c; /* Set the list index */ | 1701 | list[i].i = c; /* Set the list index */ |
1702 | 1702 | ||
@@ -2903,6 +2903,7 @@ static int wavelan_packet_xmit(struct sk_buff *skb, struct net_device * dev) | |||
2903 | { | 2903 | { |
2904 | net_local *lp = (net_local *) dev->priv; | 2904 | net_local *lp = (net_local *) dev->priv; |
2905 | unsigned long flags; | 2905 | unsigned long flags; |
2906 | char data[ETH_ZLEN]; | ||
2906 | 2907 | ||
2907 | #ifdef DEBUG_TX_TRACE | 2908 | #ifdef DEBUG_TX_TRACE |
2908 | printk(KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name, | 2909 | printk(KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name, |
@@ -2937,15 +2938,16 @@ static int wavelan_packet_xmit(struct sk_buff *skb, struct net_device * dev) | |||
2937 | * able to detect collisions, therefore in theory we don't really | 2938 | * able to detect collisions, therefore in theory we don't really |
2938 | * need to pad. Jean II */ | 2939 | * need to pad. Jean II */ |
2939 | if (skb->len < ETH_ZLEN) { | 2940 | if (skb->len < ETH_ZLEN) { |
2940 | skb = skb_padto(skb, ETH_ZLEN); | 2941 | memset(data, 0, ETH_ZLEN); |
2941 | if (skb == NULL) | 2942 | memcpy(data, skb->data, skb->len); |
2942 | return 0; | 2943 | /* Write packet on the card */ |
2944 | if(wv_packet_write(dev, data, ETH_ZLEN)) | ||
2945 | return 1; /* We failed */ | ||
2943 | } | 2946 | } |
2944 | 2947 | else if(wv_packet_write(dev, skb->data, skb->len)) | |
2945 | /* Write packet on the card */ | ||
2946 | if(wv_packet_write(dev, skb->data, skb->len)) | ||
2947 | return 1; /* We failed */ | 2948 | return 1; /* We failed */ |
2948 | 2949 | ||
2950 | |||
2949 | dev_kfree_skb(skb); | 2951 | dev_kfree_skb(skb); |
2950 | 2952 | ||
2951 | #ifdef DEBUG_TX_TRACE | 2953 | #ifdef DEBUG_TX_TRACE |
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 6707df968934..f2d152b818f0 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile | |||
@@ -26,7 +26,11 @@ obj-$(CONFIG_PPC32) += setup-irq.o | |||
26 | obj-$(CONFIG_PPC64) += setup-bus.o | 26 | obj-$(CONFIG_PPC64) += setup-bus.o |
27 | obj-$(CONFIG_MIPS) += setup-bus.o setup-irq.o | 27 | obj-$(CONFIG_MIPS) += setup-bus.o setup-irq.o |
28 | obj-$(CONFIG_X86_VISWS) += setup-irq.o | 28 | obj-$(CONFIG_X86_VISWS) += setup-irq.o |
29 | obj-$(CONFIG_PCI_MSI) += msi.o | 29 | |
30 | msiobj-y := msi.o msi-apic.o | ||
31 | msiobj-$(CONFIG_IA64_GENERIC) += msi-altix.o | ||
32 | msiobj-$(CONFIG_IA64_SGI_SN2) += msi-altix.o | ||
33 | obj-$(CONFIG_PCI_MSI) += $(msiobj-y) | ||
30 | 34 | ||
31 | # | 35 | # |
32 | # ACPI Related PCI FW Functions | 36 | # ACPI Related PCI FW Functions |
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index eed67d9e73bc..723092682023 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c | |||
@@ -81,9 +81,9 @@ void __devinit pci_bus_add_device(struct pci_dev *dev) | |||
81 | { | 81 | { |
82 | device_add(&dev->dev); | 82 | device_add(&dev->dev); |
83 | 83 | ||
84 | spin_lock(&pci_bus_lock); | 84 | down_write(&pci_bus_sem); |
85 | list_add_tail(&dev->global_list, &pci_devices); | 85 | list_add_tail(&dev->global_list, &pci_devices); |
86 | spin_unlock(&pci_bus_lock); | 86 | up_write(&pci_bus_sem); |
87 | 87 | ||
88 | pci_proc_attach_device(dev); | 88 | pci_proc_attach_device(dev); |
89 | pci_create_sysfs_dev_files(dev); | 89 | pci_create_sysfs_dev_files(dev); |
@@ -125,10 +125,10 @@ void __devinit pci_bus_add_devices(struct pci_bus *bus) | |||
125 | */ | 125 | */ |
126 | if (dev->subordinate) { | 126 | if (dev->subordinate) { |
127 | if (list_empty(&dev->subordinate->node)) { | 127 | if (list_empty(&dev->subordinate->node)) { |
128 | spin_lock(&pci_bus_lock); | 128 | down_write(&pci_bus_sem); |
129 | list_add_tail(&dev->subordinate->node, | 129 | list_add_tail(&dev->subordinate->node, |
130 | &dev->bus->children); | 130 | &dev->bus->children); |
131 | spin_unlock(&pci_bus_lock); | 131 | up_write(&pci_bus_sem); |
132 | } | 132 | } |
133 | pci_bus_add_devices(dev->subordinate); | 133 | pci_bus_add_devices(dev->subordinate); |
134 | 134 | ||
@@ -168,7 +168,7 @@ void pci_walk_bus(struct pci_bus *top, void (*cb)(struct pci_dev *, void *), | |||
168 | struct list_head *next; | 168 | struct list_head *next; |
169 | 169 | ||
170 | bus = top; | 170 | bus = top; |
171 | spin_lock(&pci_bus_lock); | 171 | down_read(&pci_bus_sem); |
172 | next = top->devices.next; | 172 | next = top->devices.next; |
173 | for (;;) { | 173 | for (;;) { |
174 | if (next == &bus->devices) { | 174 | if (next == &bus->devices) { |
@@ -180,22 +180,19 @@ void pci_walk_bus(struct pci_bus *top, void (*cb)(struct pci_dev *, void *), | |||
180 | continue; | 180 | continue; |
181 | } | 181 | } |
182 | dev = list_entry(next, struct pci_dev, bus_list); | 182 | dev = list_entry(next, struct pci_dev, bus_list); |
183 | pci_dev_get(dev); | ||
184 | if (dev->subordinate) { | 183 | if (dev->subordinate) { |
185 | /* this is a pci-pci bridge, do its devices next */ | 184 | /* this is a pci-pci bridge, do its devices next */ |
186 | next = dev->subordinate->devices.next; | 185 | next = dev->subordinate->devices.next; |
187 | bus = dev->subordinate; | 186 | bus = dev->subordinate; |
188 | } else | 187 | } else |
189 | next = dev->bus_list.next; | 188 | next = dev->bus_list.next; |
190 | spin_unlock(&pci_bus_lock); | ||
191 | 189 | ||
192 | /* Run device routines with the bus unlocked */ | 190 | /* Run device routines with the device locked */ |
191 | down(&dev->dev.sem); | ||
193 | cb(dev, userdata); | 192 | cb(dev, userdata); |
194 | 193 | up(&dev->dev.sem); | |
195 | spin_lock(&pci_bus_lock); | ||
196 | pci_dev_put(dev); | ||
197 | } | 194 | } |
198 | spin_unlock(&pci_bus_lock); | 195 | up_read(&pci_bus_sem); |
199 | } | 196 | } |
200 | EXPORT_SYMBOL_GPL(pci_walk_bus); | 197 | EXPORT_SYMBOL_GPL(pci_walk_bus); |
201 | 198 | ||
diff --git a/drivers/pci/msi-altix.c b/drivers/pci/msi-altix.c new file mode 100644 index 000000000000..bed4183a5e39 --- /dev/null +++ b/drivers/pci/msi-altix.c | |||
@@ -0,0 +1,210 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * Copyright (C) 2006 Silicon Graphics, Inc. All Rights Reserved. | ||
7 | */ | ||
8 | |||
9 | #include <linux/types.h> | ||
10 | #include <linux/pci.h> | ||
11 | #include <linux/cpumask.h> | ||
12 | |||
13 | #include <asm/sn/addrs.h> | ||
14 | #include <asm/sn/intr.h> | ||
15 | #include <asm/sn/pcibus_provider_defs.h> | ||
16 | #include <asm/sn/pcidev.h> | ||
17 | #include <asm/sn/nodepda.h> | ||
18 | |||
19 | #include "msi.h" | ||
20 | |||
21 | struct sn_msi_info { | ||
22 | u64 pci_addr; | ||
23 | struct sn_irq_info *sn_irq_info; | ||
24 | }; | ||
25 | |||
26 | static struct sn_msi_info *sn_msi_info; | ||
27 | |||
28 | static void | ||
29 | sn_msi_teardown(unsigned int vector) | ||
30 | { | ||
31 | nasid_t nasid; | ||
32 | int widget; | ||
33 | struct pci_dev *pdev; | ||
34 | struct pcidev_info *sn_pdev; | ||
35 | struct sn_irq_info *sn_irq_info; | ||
36 | struct pcibus_bussoft *bussoft; | ||
37 | struct sn_pcibus_provider *provider; | ||
38 | |||
39 | sn_irq_info = sn_msi_info[vector].sn_irq_info; | ||
40 | if (sn_irq_info == NULL || sn_irq_info->irq_int_bit >= 0) | ||
41 | return; | ||
42 | |||
43 | sn_pdev = (struct pcidev_info *)sn_irq_info->irq_pciioinfo; | ||
44 | pdev = sn_pdev->pdi_linux_pcidev; | ||
45 | provider = SN_PCIDEV_BUSPROVIDER(pdev); | ||
46 | |||
47 | (*provider->dma_unmap)(pdev, | ||
48 | sn_msi_info[vector].pci_addr, | ||
49 | PCI_DMA_FROMDEVICE); | ||
50 | sn_msi_info[vector].pci_addr = 0; | ||
51 | |||
52 | bussoft = SN_PCIDEV_BUSSOFT(pdev); | ||
53 | nasid = NASID_GET(bussoft->bs_base); | ||
54 | widget = (nasid & 1) ? | ||
55 | TIO_SWIN_WIDGETNUM(bussoft->bs_base) : | ||
56 | SWIN_WIDGETNUM(bussoft->bs_base); | ||
57 | |||
58 | sn_intr_free(nasid, widget, sn_irq_info); | ||
59 | sn_msi_info[vector].sn_irq_info = NULL; | ||
60 | |||
61 | return; | ||
62 | } | ||
63 | |||
64 | int | ||
65 | sn_msi_setup(struct pci_dev *pdev, unsigned int vector, | ||
66 | u32 *addr_hi, u32 *addr_lo, u32 *data) | ||
67 | { | ||
68 | int widget; | ||
69 | int status; | ||
70 | nasid_t nasid; | ||
71 | u64 bus_addr; | ||
72 | struct sn_irq_info *sn_irq_info; | ||
73 | struct pcibus_bussoft *bussoft = SN_PCIDEV_BUSSOFT(pdev); | ||
74 | struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev); | ||
75 | |||
76 | if (bussoft == NULL) | ||
77 | return -EINVAL; | ||
78 | |||
79 | if (provider == NULL || provider->dma_map_consistent == NULL) | ||
80 | return -EINVAL; | ||
81 | |||
82 | /* | ||
83 | * Set up the vector plumbing. Let the prom (via sn_intr_alloc) | ||
84 | * decide which cpu to direct this msi at by default. | ||
85 | */ | ||
86 | |||
87 | nasid = NASID_GET(bussoft->bs_base); | ||
88 | widget = (nasid & 1) ? | ||
89 | TIO_SWIN_WIDGETNUM(bussoft->bs_base) : | ||
90 | SWIN_WIDGETNUM(bussoft->bs_base); | ||
91 | |||
92 | sn_irq_info = kzalloc(sizeof(struct sn_irq_info), GFP_KERNEL); | ||
93 | if (! sn_irq_info) | ||
94 | return -ENOMEM; | ||
95 | |||
96 | status = sn_intr_alloc(nasid, widget, sn_irq_info, vector, -1, -1); | ||
97 | if (status) { | ||
98 | kfree(sn_irq_info); | ||
99 | return -ENOMEM; | ||
100 | } | ||
101 | |||
102 | sn_irq_info->irq_int_bit = -1; /* mark this as an MSI irq */ | ||
103 | sn_irq_fixup(pdev, sn_irq_info); | ||
104 | |||
105 | /* Prom probably should fill these in, but doesn't ... */ | ||
106 | sn_irq_info->irq_bridge_type = bussoft->bs_asic_type; | ||
107 | sn_irq_info->irq_bridge = (void *)bussoft->bs_base; | ||
108 | |||
109 | /* | ||
110 | * Map the xio address into bus space | ||
111 | */ | ||
112 | bus_addr = (*provider->dma_map_consistent)(pdev, | ||
113 | sn_irq_info->irq_xtalkaddr, | ||
114 | sizeof(sn_irq_info->irq_xtalkaddr), | ||
115 | SN_DMA_MSI|SN_DMA_ADDR_XIO); | ||
116 | if (! bus_addr) { | ||
117 | sn_intr_free(nasid, widget, sn_irq_info); | ||
118 | kfree(sn_irq_info); | ||
119 | return -ENOMEM; | ||
120 | } | ||
121 | |||
122 | sn_msi_info[vector].sn_irq_info = sn_irq_info; | ||
123 | sn_msi_info[vector].pci_addr = bus_addr; | ||
124 | |||
125 | *addr_hi = (u32)(bus_addr >> 32); | ||
126 | *addr_lo = (u32)(bus_addr & 0x00000000ffffffff); | ||
127 | |||
128 | /* | ||
129 | * In the SN platform, bit 16 is a "send vector" bit which | ||
130 | * must be present in order to move the vector through the system. | ||
131 | */ | ||
132 | *data = 0x100 + (unsigned int)vector; | ||
133 | |||
134 | #ifdef CONFIG_SMP | ||
135 | set_irq_affinity_info((vector & 0xff), sn_irq_info->irq_cpuid, 0); | ||
136 | #endif | ||
137 | |||
138 | return 0; | ||
139 | } | ||
140 | |||
141 | static void | ||
142 | sn_msi_target(unsigned int vector, unsigned int cpu, | ||
143 | u32 *addr_hi, u32 *addr_lo) | ||
144 | { | ||
145 | int slice; | ||
146 | nasid_t nasid; | ||
147 | u64 bus_addr; | ||
148 | struct pci_dev *pdev; | ||
149 | struct pcidev_info *sn_pdev; | ||
150 | struct sn_irq_info *sn_irq_info; | ||
151 | struct sn_irq_info *new_irq_info; | ||
152 | struct sn_pcibus_provider *provider; | ||
153 | |||
154 | sn_irq_info = sn_msi_info[vector].sn_irq_info; | ||
155 | if (sn_irq_info == NULL || sn_irq_info->irq_int_bit >= 0) | ||
156 | return; | ||
157 | |||
158 | /* | ||
159 | * Release XIO resources for the old MSI PCI address | ||
160 | */ | ||
161 | |||
162 | sn_pdev = (struct pcidev_info *)sn_irq_info->irq_pciioinfo; | ||
163 | pdev = sn_pdev->pdi_linux_pcidev; | ||
164 | provider = SN_PCIDEV_BUSPROVIDER(pdev); | ||
165 | |||
166 | bus_addr = (u64)(*addr_hi) << 32 | (u64)(*addr_lo); | ||
167 | (*provider->dma_unmap)(pdev, bus_addr, PCI_DMA_FROMDEVICE); | ||
168 | sn_msi_info[vector].pci_addr = 0; | ||
169 | |||
170 | nasid = cpuid_to_nasid(cpu); | ||
171 | slice = cpuid_to_slice(cpu); | ||
172 | |||
173 | new_irq_info = sn_retarget_vector(sn_irq_info, nasid, slice); | ||
174 | sn_msi_info[vector].sn_irq_info = new_irq_info; | ||
175 | if (new_irq_info == NULL) | ||
176 | return; | ||
177 | |||
178 | /* | ||
179 | * Map the xio address into bus space | ||
180 | */ | ||
181 | |||
182 | bus_addr = (*provider->dma_map_consistent)(pdev, | ||
183 | new_irq_info->irq_xtalkaddr, | ||
184 | sizeof(new_irq_info->irq_xtalkaddr), | ||
185 | SN_DMA_MSI|SN_DMA_ADDR_XIO); | ||
186 | |||
187 | sn_msi_info[vector].pci_addr = bus_addr; | ||
188 | *addr_hi = (u32)(bus_addr >> 32); | ||
189 | *addr_lo = (u32)(bus_addr & 0x00000000ffffffff); | ||
190 | } | ||
191 | |||
192 | struct msi_ops sn_msi_ops = { | ||
193 | .setup = sn_msi_setup, | ||
194 | .teardown = sn_msi_teardown, | ||
195 | #ifdef CONFIG_SMP | ||
196 | .target = sn_msi_target, | ||
197 | #endif | ||
198 | }; | ||
199 | |||
200 | int | ||
201 | sn_msi_init(void) | ||
202 | { | ||
203 | sn_msi_info = | ||
204 | kzalloc(sizeof(struct sn_msi_info) * NR_VECTORS, GFP_KERNEL); | ||
205 | if (! sn_msi_info) | ||
206 | return -ENOMEM; | ||
207 | |||
208 | msi_register(&sn_msi_ops); | ||
209 | return 0; | ||
210 | } | ||
diff --git a/drivers/pci/msi-apic.c b/drivers/pci/msi-apic.c new file mode 100644 index 000000000000..0eb5fe9003a2 --- /dev/null +++ b/drivers/pci/msi-apic.c | |||
@@ -0,0 +1,100 @@ | |||
1 | /* | ||
2 | * MSI hooks for standard x86 apic | ||
3 | */ | ||
4 | |||
5 | #include <linux/pci.h> | ||
6 | #include <linux/irq.h> | ||
7 | |||
8 | #include "msi.h" | ||
9 | |||
10 | /* | ||
11 | * Shifts for APIC-based data | ||
12 | */ | ||
13 | |||
14 | #define MSI_DATA_VECTOR_SHIFT 0 | ||
15 | #define MSI_DATA_VECTOR(v) (((u8)v) << MSI_DATA_VECTOR_SHIFT) | ||
16 | |||
17 | #define MSI_DATA_DELIVERY_SHIFT 8 | ||
18 | #define MSI_DATA_DELIVERY_FIXED (0 << MSI_DATA_DELIVERY_SHIFT) | ||
19 | #define MSI_DATA_DELIVERY_LOWPRI (1 << MSI_DATA_DELIVERY_SHIFT) | ||
20 | |||
21 | #define MSI_DATA_LEVEL_SHIFT 14 | ||
22 | #define MSI_DATA_LEVEL_DEASSERT (0 << MSI_DATA_LEVEL_SHIFT) | ||
23 | #define MSI_DATA_LEVEL_ASSERT (1 << MSI_DATA_LEVEL_SHIFT) | ||
24 | |||
25 | #define MSI_DATA_TRIGGER_SHIFT 15 | ||
26 | #define MSI_DATA_TRIGGER_EDGE (0 << MSI_DATA_TRIGGER_SHIFT) | ||
27 | #define MSI_DATA_TRIGGER_LEVEL (1 << MSI_DATA_TRIGGER_SHIFT) | ||
28 | |||
29 | /* | ||
30 | * Shift/mask fields for APIC-based bus address | ||
31 | */ | ||
32 | |||
33 | #define MSI_ADDR_HEADER 0xfee00000 | ||
34 | |||
35 | #define MSI_ADDR_DESTID_MASK 0xfff0000f | ||
36 | #define MSI_ADDR_DESTID_CPU(cpu) ((cpu) << MSI_TARGET_CPU_SHIFT) | ||
37 | |||
38 | #define MSI_ADDR_DESTMODE_SHIFT 2 | ||
39 | #define MSI_ADDR_DESTMODE_PHYS (0 << MSI_ADDR_DESTMODE_SHIFT) | ||
40 | #define MSI_ADDR_DESTMODE_LOGIC (1 << MSI_ADDR_DESTMODE_SHIFT) | ||
41 | |||
42 | #define MSI_ADDR_REDIRECTION_SHIFT 3 | ||
43 | #define MSI_ADDR_REDIRECTION_CPU (0 << MSI_ADDR_REDIRECTION_SHIFT) | ||
44 | #define MSI_ADDR_REDIRECTION_LOWPRI (1 << MSI_ADDR_REDIRECTION_SHIFT) | ||
45 | |||
46 | |||
47 | static void | ||
48 | msi_target_apic(unsigned int vector, | ||
49 | unsigned int dest_cpu, | ||
50 | u32 *address_hi, /* in/out */ | ||
51 | u32 *address_lo) /* in/out */ | ||
52 | { | ||
53 | u32 addr = *address_lo; | ||
54 | |||
55 | addr &= MSI_ADDR_DESTID_MASK; | ||
56 | addr |= MSI_ADDR_DESTID_CPU(cpu_physical_id(dest_cpu)); | ||
57 | |||
58 | *address_lo = addr; | ||
59 | } | ||
60 | |||
61 | static int | ||
62 | msi_setup_apic(struct pci_dev *pdev, /* unused in generic */ | ||
63 | unsigned int vector, | ||
64 | u32 *address_hi, | ||
65 | u32 *address_lo, | ||
66 | u32 *data) | ||
67 | { | ||
68 | unsigned long dest_phys_id; | ||
69 | |||
70 | dest_phys_id = cpu_physical_id(first_cpu(cpu_online_map)); | ||
71 | |||
72 | *address_hi = 0; | ||
73 | *address_lo = MSI_ADDR_HEADER | | ||
74 | MSI_ADDR_DESTMODE_PHYS | | ||
75 | MSI_ADDR_REDIRECTION_CPU | | ||
76 | MSI_ADDR_DESTID_CPU(dest_phys_id); | ||
77 | |||
78 | *data = MSI_DATA_TRIGGER_EDGE | | ||
79 | MSI_DATA_LEVEL_ASSERT | | ||
80 | MSI_DATA_DELIVERY_FIXED | | ||
81 | MSI_DATA_VECTOR(vector); | ||
82 | |||
83 | return 0; | ||
84 | } | ||
85 | |||
86 | static void | ||
87 | msi_teardown_apic(unsigned int vector) | ||
88 | { | ||
89 | return; /* no-op */ | ||
90 | } | ||
91 | |||
92 | /* | ||
93 | * Generic ops used on most IA archs/platforms. Set with msi_register() | ||
94 | */ | ||
95 | |||
96 | struct msi_ops msi_apic_ops = { | ||
97 | .setup = msi_setup_apic, | ||
98 | .teardown = msi_teardown_apic, | ||
99 | .target = msi_target_apic, | ||
100 | }; | ||
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 9855c4c920b8..7f8429284fab 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c | |||
@@ -23,8 +23,6 @@ | |||
23 | #include "pci.h" | 23 | #include "pci.h" |
24 | #include "msi.h" | 24 | #include "msi.h" |
25 | 25 | ||
26 | #define MSI_TARGET_CPU first_cpu(cpu_online_map) | ||
27 | |||
28 | static DEFINE_SPINLOCK(msi_lock); | 26 | static DEFINE_SPINLOCK(msi_lock); |
29 | static struct msi_desc* msi_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = NULL }; | 27 | static struct msi_desc* msi_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = NULL }; |
30 | static kmem_cache_t* msi_cachep; | 28 | static kmem_cache_t* msi_cachep; |
@@ -37,9 +35,17 @@ static int nr_msix_devices; | |||
37 | 35 | ||
38 | #ifndef CONFIG_X86_IO_APIC | 36 | #ifndef CONFIG_X86_IO_APIC |
39 | int vector_irq[NR_VECTORS] = { [0 ... NR_VECTORS - 1] = -1}; | 37 | int vector_irq[NR_VECTORS] = { [0 ... NR_VECTORS - 1] = -1}; |
40 | u8 irq_vector[NR_IRQ_VECTORS] = { FIRST_DEVICE_VECTOR , 0 }; | ||
41 | #endif | 38 | #endif |
42 | 39 | ||
40 | static struct msi_ops *msi_ops; | ||
41 | |||
42 | int | ||
43 | msi_register(struct msi_ops *ops) | ||
44 | { | ||
45 | msi_ops = ops; | ||
46 | return 0; | ||
47 | } | ||
48 | |||
43 | static void msi_cache_ctor(void *p, kmem_cache_t *cache, unsigned long flags) | 49 | static void msi_cache_ctor(void *p, kmem_cache_t *cache, unsigned long flags) |
44 | { | 50 | { |
45 | memset(p, 0, NR_IRQS * sizeof(struct msi_desc)); | 51 | memset(p, 0, NR_IRQS * sizeof(struct msi_desc)); |
@@ -92,7 +98,7 @@ static void msi_set_mask_bit(unsigned int vector, int flag) | |||
92 | static void set_msi_affinity(unsigned int vector, cpumask_t cpu_mask) | 98 | static void set_msi_affinity(unsigned int vector, cpumask_t cpu_mask) |
93 | { | 99 | { |
94 | struct msi_desc *entry; | 100 | struct msi_desc *entry; |
95 | struct msg_address address; | 101 | u32 address_hi, address_lo; |
96 | unsigned int irq = vector; | 102 | unsigned int irq = vector; |
97 | unsigned int dest_cpu = first_cpu(cpu_mask); | 103 | unsigned int dest_cpu = first_cpu(cpu_mask); |
98 | 104 | ||
@@ -108,28 +114,36 @@ static void set_msi_affinity(unsigned int vector, cpumask_t cpu_mask) | |||
108 | if (!pos) | 114 | if (!pos) |
109 | return; | 115 | return; |
110 | 116 | ||
117 | pci_read_config_dword(entry->dev, msi_upper_address_reg(pos), | ||
118 | &address_hi); | ||
111 | pci_read_config_dword(entry->dev, msi_lower_address_reg(pos), | 119 | pci_read_config_dword(entry->dev, msi_lower_address_reg(pos), |
112 | &address.lo_address.value); | 120 | &address_lo); |
113 | address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK; | 121 | |
114 | address.lo_address.value |= (cpu_physical_id(dest_cpu) << | 122 | msi_ops->target(vector, dest_cpu, &address_hi, &address_lo); |
115 | MSI_TARGET_CPU_SHIFT); | 123 | |
116 | entry->msi_attrib.current_cpu = cpu_physical_id(dest_cpu); | 124 | pci_write_config_dword(entry->dev, msi_upper_address_reg(pos), |
125 | address_hi); | ||
117 | pci_write_config_dword(entry->dev, msi_lower_address_reg(pos), | 126 | pci_write_config_dword(entry->dev, msi_lower_address_reg(pos), |
118 | address.lo_address.value); | 127 | address_lo); |
119 | set_native_irq_info(irq, cpu_mask); | 128 | set_native_irq_info(irq, cpu_mask); |
120 | break; | 129 | break; |
121 | } | 130 | } |
122 | case PCI_CAP_ID_MSIX: | 131 | case PCI_CAP_ID_MSIX: |
123 | { | 132 | { |
124 | int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + | 133 | int offset_hi = |
125 | PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET; | 134 | entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + |
126 | 135 | PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET; | |
127 | address.lo_address.value = readl(entry->mask_base + offset); | 136 | int offset_lo = |
128 | address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK; | 137 | entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + |
129 | address.lo_address.value |= (cpu_physical_id(dest_cpu) << | 138 | PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET; |
130 | MSI_TARGET_CPU_SHIFT); | 139 | |
131 | entry->msi_attrib.current_cpu = cpu_physical_id(dest_cpu); | 140 | address_hi = readl(entry->mask_base + offset_hi); |
132 | writel(address.lo_address.value, entry->mask_base + offset); | 141 | address_lo = readl(entry->mask_base + offset_lo); |
142 | |||
143 | msi_ops->target(vector, dest_cpu, &address_hi, &address_lo); | ||
144 | |||
145 | writel(address_hi, entry->mask_base + offset_hi); | ||
146 | writel(address_lo, entry->mask_base + offset_lo); | ||
133 | set_native_irq_info(irq, cpu_mask); | 147 | set_native_irq_info(irq, cpu_mask); |
134 | break; | 148 | break; |
135 | } | 149 | } |
@@ -251,30 +265,6 @@ static struct hw_interrupt_type msi_irq_wo_maskbit_type = { | |||
251 | .set_affinity = set_msi_affinity | 265 | .set_affinity = set_msi_affinity |
252 | }; | 266 | }; |
253 | 267 | ||
254 | static void msi_data_init(struct msg_data *msi_data, | ||
255 | unsigned int vector) | ||
256 | { | ||
257 | memset(msi_data, 0, sizeof(struct msg_data)); | ||
258 | msi_data->vector = (u8)vector; | ||
259 | msi_data->delivery_mode = MSI_DELIVERY_MODE; | ||
260 | msi_data->level = MSI_LEVEL_MODE; | ||
261 | msi_data->trigger = MSI_TRIGGER_MODE; | ||
262 | } | ||
263 | |||
264 | static void msi_address_init(struct msg_address *msi_address) | ||
265 | { | ||
266 | unsigned int dest_id; | ||
267 | unsigned long dest_phys_id = cpu_physical_id(MSI_TARGET_CPU); | ||
268 | |||
269 | memset(msi_address, 0, sizeof(struct msg_address)); | ||
270 | msi_address->hi_address = (u32)0; | ||
271 | dest_id = (MSI_ADDRESS_HEADER << MSI_ADDRESS_HEADER_SHIFT); | ||
272 | msi_address->lo_address.u.dest_mode = MSI_PHYSICAL_MODE; | ||
273 | msi_address->lo_address.u.redirection_hint = MSI_REDIRECTION_HINT_MODE; | ||
274 | msi_address->lo_address.u.dest_id = dest_id; | ||
275 | msi_address->lo_address.value |= (dest_phys_id << MSI_TARGET_CPU_SHIFT); | ||
276 | } | ||
277 | |||
278 | static int msi_free_vector(struct pci_dev* dev, int vector, int reassign); | 268 | static int msi_free_vector(struct pci_dev* dev, int vector, int reassign); |
279 | static int assign_msi_vector(void) | 269 | static int assign_msi_vector(void) |
280 | { | 270 | { |
@@ -369,13 +359,29 @@ static int msi_init(void) | |||
369 | return status; | 359 | return status; |
370 | } | 360 | } |
371 | 361 | ||
362 | status = msi_arch_init(); | ||
363 | if (status < 0) { | ||
364 | pci_msi_enable = 0; | ||
365 | printk(KERN_WARNING | ||
366 | "PCI: MSI arch init failed. MSI disabled.\n"); | ||
367 | return status; | ||
368 | } | ||
369 | |||
370 | if (! msi_ops) { | ||
371 | printk(KERN_WARNING | ||
372 | "PCI: MSI ops not registered. MSI disabled.\n"); | ||
373 | status = -EINVAL; | ||
374 | return status; | ||
375 | } | ||
376 | |||
377 | last_alloc_vector = assign_irq_vector(AUTO_ASSIGN); | ||
372 | status = msi_cache_init(); | 378 | status = msi_cache_init(); |
373 | if (status < 0) { | 379 | if (status < 0) { |
374 | pci_msi_enable = 0; | 380 | pci_msi_enable = 0; |
375 | printk(KERN_WARNING "PCI: MSI cache init failed\n"); | 381 | printk(KERN_WARNING "PCI: MSI cache init failed\n"); |
376 | return status; | 382 | return status; |
377 | } | 383 | } |
378 | last_alloc_vector = assign_irq_vector(AUTO_ASSIGN); | 384 | |
379 | if (last_alloc_vector < 0) { | 385 | if (last_alloc_vector < 0) { |
380 | pci_msi_enable = 0; | 386 | pci_msi_enable = 0; |
381 | printk(KERN_WARNING "PCI: No interrupt vectors available for MSI\n"); | 387 | printk(KERN_WARNING "PCI: No interrupt vectors available for MSI\n"); |
@@ -442,9 +448,11 @@ static void enable_msi_mode(struct pci_dev *dev, int pos, int type) | |||
442 | /* Set enabled bits to single MSI & enable MSI_enable bit */ | 448 | /* Set enabled bits to single MSI & enable MSI_enable bit */ |
443 | msi_enable(control, 1); | 449 | msi_enable(control, 1); |
444 | pci_write_config_word(dev, msi_control_reg(pos), control); | 450 | pci_write_config_word(dev, msi_control_reg(pos), control); |
451 | dev->msi_enabled = 1; | ||
445 | } else { | 452 | } else { |
446 | msix_enable(control); | 453 | msix_enable(control); |
447 | pci_write_config_word(dev, msi_control_reg(pos), control); | 454 | pci_write_config_word(dev, msi_control_reg(pos), control); |
455 | dev->msix_enabled = 1; | ||
448 | } | 456 | } |
449 | if (pci_find_capability(dev, PCI_CAP_ID_EXP)) { | 457 | if (pci_find_capability(dev, PCI_CAP_ID_EXP)) { |
450 | /* PCI Express Endpoint device detected */ | 458 | /* PCI Express Endpoint device detected */ |
@@ -461,9 +469,11 @@ void disable_msi_mode(struct pci_dev *dev, int pos, int type) | |||
461 | /* Set enabled bits to single MSI & enable MSI_enable bit */ | 469 | /* Set enabled bits to single MSI & enable MSI_enable bit */ |
462 | msi_disable(control); | 470 | msi_disable(control); |
463 | pci_write_config_word(dev, msi_control_reg(pos), control); | 471 | pci_write_config_word(dev, msi_control_reg(pos), control); |
472 | dev->msi_enabled = 0; | ||
464 | } else { | 473 | } else { |
465 | msix_disable(control); | 474 | msix_disable(control); |
466 | pci_write_config_word(dev, msi_control_reg(pos), control); | 475 | pci_write_config_word(dev, msi_control_reg(pos), control); |
476 | dev->msix_enabled = 0; | ||
467 | } | 477 | } |
468 | if (pci_find_capability(dev, PCI_CAP_ID_EXP)) { | 478 | if (pci_find_capability(dev, PCI_CAP_ID_EXP)) { |
469 | /* PCI Express Endpoint device detected */ | 479 | /* PCI Express Endpoint device detected */ |
@@ -538,7 +548,6 @@ int pci_save_msi_state(struct pci_dev *dev) | |||
538 | pci_read_config_dword(dev, pos + PCI_MSI_DATA_32, &cap[i++]); | 548 | pci_read_config_dword(dev, pos + PCI_MSI_DATA_32, &cap[i++]); |
539 | if (control & PCI_MSI_FLAGS_MASKBIT) | 549 | if (control & PCI_MSI_FLAGS_MASKBIT) |
540 | pci_read_config_dword(dev, pos + PCI_MSI_MASK_BIT, &cap[i++]); | 550 | pci_read_config_dword(dev, pos + PCI_MSI_MASK_BIT, &cap[i++]); |
541 | disable_msi_mode(dev, pos, PCI_CAP_ID_MSI); | ||
542 | save_state->cap_nr = PCI_CAP_ID_MSI; | 551 | save_state->cap_nr = PCI_CAP_ID_MSI; |
543 | pci_add_saved_cap(dev, save_state); | 552 | pci_add_saved_cap(dev, save_state); |
544 | return 0; | 553 | return 0; |
@@ -575,6 +584,8 @@ void pci_restore_msi_state(struct pci_dev *dev) | |||
575 | int pci_save_msix_state(struct pci_dev *dev) | 584 | int pci_save_msix_state(struct pci_dev *dev) |
576 | { | 585 | { |
577 | int pos; | 586 | int pos; |
587 | int temp; | ||
588 | int vector, head, tail = 0; | ||
578 | u16 control; | 589 | u16 control; |
579 | struct pci_cap_saved_state *save_state; | 590 | struct pci_cap_saved_state *save_state; |
580 | 591 | ||
@@ -582,6 +593,7 @@ int pci_save_msix_state(struct pci_dev *dev) | |||
582 | if (pos <= 0 || dev->no_msi) | 593 | if (pos <= 0 || dev->no_msi) |
583 | return 0; | 594 | return 0; |
584 | 595 | ||
596 | /* save the capability */ | ||
585 | pci_read_config_word(dev, msi_control_reg(pos), &control); | 597 | pci_read_config_word(dev, msi_control_reg(pos), &control); |
586 | if (!(control & PCI_MSIX_FLAGS_ENABLE)) | 598 | if (!(control & PCI_MSIX_FLAGS_ENABLE)) |
587 | return 0; | 599 | return 0; |
@@ -593,7 +605,38 @@ int pci_save_msix_state(struct pci_dev *dev) | |||
593 | } | 605 | } |
594 | *((u16 *)&save_state->data[0]) = control; | 606 | *((u16 *)&save_state->data[0]) = control; |
595 | 607 | ||
596 | disable_msi_mode(dev, pos, PCI_CAP_ID_MSIX); | 608 | /* save the table */ |
609 | temp = dev->irq; | ||
610 | if (msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) { | ||
611 | kfree(save_state); | ||
612 | return -EINVAL; | ||
613 | } | ||
614 | |||
615 | vector = head = dev->irq; | ||
616 | while (head != tail) { | ||
617 | int j; | ||
618 | void __iomem *base; | ||
619 | struct msi_desc *entry; | ||
620 | |||
621 | entry = msi_desc[vector]; | ||
622 | base = entry->mask_base; | ||
623 | j = entry->msi_attrib.entry_nr; | ||
624 | |||
625 | entry->address_lo_save = | ||
626 | readl(base + j * PCI_MSIX_ENTRY_SIZE + | ||
627 | PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); | ||
628 | entry->address_hi_save = | ||
629 | readl(base + j * PCI_MSIX_ENTRY_SIZE + | ||
630 | PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); | ||
631 | entry->data_save = | ||
632 | readl(base + j * PCI_MSIX_ENTRY_SIZE + | ||
633 | PCI_MSIX_ENTRY_DATA_OFFSET); | ||
634 | |||
635 | tail = msi_desc[vector]->link.tail; | ||
636 | vector = tail; | ||
637 | } | ||
638 | dev->irq = temp; | ||
639 | |||
597 | save_state->cap_nr = PCI_CAP_ID_MSIX; | 640 | save_state->cap_nr = PCI_CAP_ID_MSIX; |
598 | pci_add_saved_cap(dev, save_state); | 641 | pci_add_saved_cap(dev, save_state); |
599 | return 0; | 642 | return 0; |
@@ -606,8 +649,6 @@ void pci_restore_msix_state(struct pci_dev *dev) | |||
606 | int vector, head, tail = 0; | 649 | int vector, head, tail = 0; |
607 | void __iomem *base; | 650 | void __iomem *base; |
608 | int j; | 651 | int j; |
609 | struct msg_address address; | ||
610 | struct msg_data data; | ||
611 | struct msi_desc *entry; | 652 | struct msi_desc *entry; |
612 | int temp; | 653 | int temp; |
613 | struct pci_cap_saved_state *save_state; | 654 | struct pci_cap_saved_state *save_state; |
@@ -633,20 +674,13 @@ void pci_restore_msix_state(struct pci_dev *dev) | |||
633 | base = entry->mask_base; | 674 | base = entry->mask_base; |
634 | j = entry->msi_attrib.entry_nr; | 675 | j = entry->msi_attrib.entry_nr; |
635 | 676 | ||
636 | msi_address_init(&address); | 677 | writel(entry->address_lo_save, |
637 | msi_data_init(&data, vector); | ||
638 | |||
639 | address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK; | ||
640 | address.lo_address.value |= entry->msi_attrib.current_cpu << | ||
641 | MSI_TARGET_CPU_SHIFT; | ||
642 | |||
643 | writel(address.lo_address.value, | ||
644 | base + j * PCI_MSIX_ENTRY_SIZE + | 678 | base + j * PCI_MSIX_ENTRY_SIZE + |
645 | PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); | 679 | PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); |
646 | writel(address.hi_address, | 680 | writel(entry->address_hi_save, |
647 | base + j * PCI_MSIX_ENTRY_SIZE + | 681 | base + j * PCI_MSIX_ENTRY_SIZE + |
648 | PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); | 682 | PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); |
649 | writel(*(u32*)&data, | 683 | writel(entry->data_save, |
650 | base + j * PCI_MSIX_ENTRY_SIZE + | 684 | base + j * PCI_MSIX_ENTRY_SIZE + |
651 | PCI_MSIX_ENTRY_DATA_OFFSET); | 685 | PCI_MSIX_ENTRY_DATA_OFFSET); |
652 | 686 | ||
@@ -660,30 +694,32 @@ void pci_restore_msix_state(struct pci_dev *dev) | |||
660 | } | 694 | } |
661 | #endif | 695 | #endif |
662 | 696 | ||
663 | static void msi_register_init(struct pci_dev *dev, struct msi_desc *entry) | 697 | static int msi_register_init(struct pci_dev *dev, struct msi_desc *entry) |
664 | { | 698 | { |
665 | struct msg_address address; | 699 | int status; |
666 | struct msg_data data; | 700 | u32 address_hi; |
701 | u32 address_lo; | ||
702 | u32 data; | ||
667 | int pos, vector = dev->irq; | 703 | int pos, vector = dev->irq; |
668 | u16 control; | 704 | u16 control; |
669 | 705 | ||
670 | pos = pci_find_capability(dev, PCI_CAP_ID_MSI); | 706 | pos = pci_find_capability(dev, PCI_CAP_ID_MSI); |
671 | pci_read_config_word(dev, msi_control_reg(pos), &control); | 707 | pci_read_config_word(dev, msi_control_reg(pos), &control); |
708 | |||
672 | /* Configure MSI capability structure */ | 709 | /* Configure MSI capability structure */ |
673 | msi_address_init(&address); | 710 | status = msi_ops->setup(dev, vector, &address_hi, &address_lo, &data); |
674 | msi_data_init(&data, vector); | 711 | if (status < 0) |
675 | entry->msi_attrib.current_cpu = ((address.lo_address.u.dest_id >> | 712 | return status; |
676 | MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK); | 713 | |
677 | pci_write_config_dword(dev, msi_lower_address_reg(pos), | 714 | pci_write_config_dword(dev, msi_lower_address_reg(pos), address_lo); |
678 | address.lo_address.value); | ||
679 | if (is_64bit_address(control)) { | 715 | if (is_64bit_address(control)) { |
680 | pci_write_config_dword(dev, | 716 | pci_write_config_dword(dev, |
681 | msi_upper_address_reg(pos), address.hi_address); | 717 | msi_upper_address_reg(pos), address_hi); |
682 | pci_write_config_word(dev, | 718 | pci_write_config_word(dev, |
683 | msi_data_reg(pos, 1), *((u32*)&data)); | 719 | msi_data_reg(pos, 1), data); |
684 | } else | 720 | } else |
685 | pci_write_config_word(dev, | 721 | pci_write_config_word(dev, |
686 | msi_data_reg(pos, 0), *((u32*)&data)); | 722 | msi_data_reg(pos, 0), data); |
687 | if (entry->msi_attrib.maskbit) { | 723 | if (entry->msi_attrib.maskbit) { |
688 | unsigned int maskbits, temp; | 724 | unsigned int maskbits, temp; |
689 | /* All MSIs are unmasked by default, Mask them all */ | 725 | /* All MSIs are unmasked by default, Mask them all */ |
@@ -697,6 +733,8 @@ static void msi_register_init(struct pci_dev *dev, struct msi_desc *entry) | |||
697 | msi_mask_bits_reg(pos, is_64bit_address(control)), | 733 | msi_mask_bits_reg(pos, is_64bit_address(control)), |
698 | maskbits); | 734 | maskbits); |
699 | } | 735 | } |
736 | |||
737 | return 0; | ||
700 | } | 738 | } |
701 | 739 | ||
702 | /** | 740 | /** |
@@ -710,6 +748,7 @@ static void msi_register_init(struct pci_dev *dev, struct msi_desc *entry) | |||
710 | **/ | 748 | **/ |
711 | static int msi_capability_init(struct pci_dev *dev) | 749 | static int msi_capability_init(struct pci_dev *dev) |
712 | { | 750 | { |
751 | int status; | ||
713 | struct msi_desc *entry; | 752 | struct msi_desc *entry; |
714 | int pos, vector; | 753 | int pos, vector; |
715 | u16 control; | 754 | u16 control; |
@@ -742,7 +781,12 @@ static int msi_capability_init(struct pci_dev *dev) | |||
742 | /* Replace with MSI handler */ | 781 | /* Replace with MSI handler */ |
743 | irq_handler_init(PCI_CAP_ID_MSI, vector, entry->msi_attrib.maskbit); | 782 | irq_handler_init(PCI_CAP_ID_MSI, vector, entry->msi_attrib.maskbit); |
744 | /* Configure MSI capability structure */ | 783 | /* Configure MSI capability structure */ |
745 | msi_register_init(dev, entry); | 784 | status = msi_register_init(dev, entry); |
785 | if (status != 0) { | ||
786 | dev->irq = entry->msi_attrib.default_vector; | ||
787 | kmem_cache_free(msi_cachep, entry); | ||
788 | return status; | ||
789 | } | ||
746 | 790 | ||
747 | attach_msi_entry(entry, vector); | 791 | attach_msi_entry(entry, vector); |
748 | /* Set MSI enabled bits */ | 792 | /* Set MSI enabled bits */ |
@@ -765,8 +809,10 @@ static int msix_capability_init(struct pci_dev *dev, | |||
765 | struct msix_entry *entries, int nvec) | 809 | struct msix_entry *entries, int nvec) |
766 | { | 810 | { |
767 | struct msi_desc *head = NULL, *tail = NULL, *entry = NULL; | 811 | struct msi_desc *head = NULL, *tail = NULL, *entry = NULL; |
768 | struct msg_address address; | 812 | u32 address_hi; |
769 | struct msg_data data; | 813 | u32 address_lo; |
814 | u32 data; | ||
815 | int status; | ||
770 | int vector, pos, i, j, nr_entries, temp = 0; | 816 | int vector, pos, i, j, nr_entries, temp = 0; |
771 | unsigned long phys_addr; | 817 | unsigned long phys_addr; |
772 | u32 table_offset; | 818 | u32 table_offset; |
@@ -822,18 +868,20 @@ static int msix_capability_init(struct pci_dev *dev, | |||
822 | /* Replace with MSI-X handler */ | 868 | /* Replace with MSI-X handler */ |
823 | irq_handler_init(PCI_CAP_ID_MSIX, vector, 1); | 869 | irq_handler_init(PCI_CAP_ID_MSIX, vector, 1); |
824 | /* Configure MSI-X capability structure */ | 870 | /* Configure MSI-X capability structure */ |
825 | msi_address_init(&address); | 871 | status = msi_ops->setup(dev, vector, |
826 | msi_data_init(&data, vector); | 872 | &address_hi, |
827 | entry->msi_attrib.current_cpu = | 873 | &address_lo, |
828 | ((address.lo_address.u.dest_id >> | 874 | &data); |
829 | MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK); | 875 | if (status < 0) |
830 | writel(address.lo_address.value, | 876 | break; |
877 | |||
878 | writel(address_lo, | ||
831 | base + j * PCI_MSIX_ENTRY_SIZE + | 879 | base + j * PCI_MSIX_ENTRY_SIZE + |
832 | PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); | 880 | PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); |
833 | writel(address.hi_address, | 881 | writel(address_hi, |
834 | base + j * PCI_MSIX_ENTRY_SIZE + | 882 | base + j * PCI_MSIX_ENTRY_SIZE + |
835 | PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); | 883 | PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); |
836 | writel(*(u32*)&data, | 884 | writel(data, |
837 | base + j * PCI_MSIX_ENTRY_SIZE + | 885 | base + j * PCI_MSIX_ENTRY_SIZE + |
838 | PCI_MSIX_ENTRY_DATA_OFFSET); | 886 | PCI_MSIX_ENTRY_DATA_OFFSET); |
839 | attach_msi_entry(entry, vector); | 887 | attach_msi_entry(entry, vector); |
@@ -865,6 +913,7 @@ static int msix_capability_init(struct pci_dev *dev, | |||
865 | **/ | 913 | **/ |
866 | int pci_enable_msi(struct pci_dev* dev) | 914 | int pci_enable_msi(struct pci_dev* dev) |
867 | { | 915 | { |
916 | struct pci_bus *bus; | ||
868 | int pos, temp, status = -EINVAL; | 917 | int pos, temp, status = -EINVAL; |
869 | u16 control; | 918 | u16 control; |
870 | 919 | ||
@@ -874,8 +923,9 @@ int pci_enable_msi(struct pci_dev* dev) | |||
874 | if (dev->no_msi) | 923 | if (dev->no_msi) |
875 | return status; | 924 | return status; |
876 | 925 | ||
877 | if (dev->bus->bus_flags & PCI_BUS_FLAGS_NO_MSI) | 926 | for (bus = dev->bus; bus; bus = bus->parent) |
878 | return -EINVAL; | 927 | if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI) |
928 | return -EINVAL; | ||
879 | 929 | ||
880 | temp = dev->irq; | 930 | temp = dev->irq; |
881 | 931 | ||
@@ -887,23 +937,23 @@ int pci_enable_msi(struct pci_dev* dev) | |||
887 | if (!pos) | 937 | if (!pos) |
888 | return -EINVAL; | 938 | return -EINVAL; |
889 | 939 | ||
890 | pci_read_config_word(dev, msi_control_reg(pos), &control); | ||
891 | if (control & PCI_MSI_FLAGS_ENABLE) | ||
892 | return 0; /* Already in MSI mode */ | ||
893 | |||
894 | if (!msi_lookup_vector(dev, PCI_CAP_ID_MSI)) { | 940 | if (!msi_lookup_vector(dev, PCI_CAP_ID_MSI)) { |
895 | /* Lookup Sucess */ | 941 | /* Lookup Sucess */ |
896 | unsigned long flags; | 942 | unsigned long flags; |
897 | 943 | ||
944 | pci_read_config_word(dev, msi_control_reg(pos), &control); | ||
945 | if (control & PCI_MSI_FLAGS_ENABLE) | ||
946 | return 0; /* Already in MSI mode */ | ||
898 | spin_lock_irqsave(&msi_lock, flags); | 947 | spin_lock_irqsave(&msi_lock, flags); |
899 | if (!vector_irq[dev->irq]) { | 948 | if (!vector_irq[dev->irq]) { |
900 | msi_desc[dev->irq]->msi_attrib.state = 0; | 949 | msi_desc[dev->irq]->msi_attrib.state = 0; |
901 | vector_irq[dev->irq] = -1; | 950 | vector_irq[dev->irq] = -1; |
902 | nr_released_vectors--; | 951 | nr_released_vectors--; |
903 | spin_unlock_irqrestore(&msi_lock, flags); | 952 | spin_unlock_irqrestore(&msi_lock, flags); |
904 | msi_register_init(dev, msi_desc[dev->irq]); | 953 | status = msi_register_init(dev, msi_desc[dev->irq]); |
905 | enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); | 954 | if (status == 0) |
906 | return 0; | 955 | enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); |
956 | return status; | ||
907 | } | 957 | } |
908 | spin_unlock_irqrestore(&msi_lock, flags); | 958 | spin_unlock_irqrestore(&msi_lock, flags); |
909 | dev->irq = temp; | 959 | dev->irq = temp; |
@@ -980,6 +1030,8 @@ static int msi_free_vector(struct pci_dev* dev, int vector, int reassign) | |||
980 | void __iomem *base; | 1030 | void __iomem *base; |
981 | unsigned long flags; | 1031 | unsigned long flags; |
982 | 1032 | ||
1033 | msi_ops->teardown(vector); | ||
1034 | |||
983 | spin_lock_irqsave(&msi_lock, flags); | 1035 | spin_lock_irqsave(&msi_lock, flags); |
984 | entry = msi_desc[vector]; | 1036 | entry = msi_desc[vector]; |
985 | if (!entry || entry->dev != dev) { | 1037 | if (!entry || entry->dev != dev) { |
@@ -1008,33 +1060,8 @@ static int msi_free_vector(struct pci_dev* dev, int vector, int reassign) | |||
1008 | entry_nr * PCI_MSIX_ENTRY_SIZE + | 1060 | entry_nr * PCI_MSIX_ENTRY_SIZE + |
1009 | PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET); | 1061 | PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET); |
1010 | 1062 | ||
1011 | if (head == vector) { | 1063 | if (head == vector) |
1012 | /* | ||
1013 | * Detect last MSI-X vector to be released. | ||
1014 | * Release the MSI-X memory-mapped table. | ||
1015 | */ | ||
1016 | #if 0 | ||
1017 | int pos, nr_entries; | ||
1018 | unsigned long phys_addr; | ||
1019 | u32 table_offset; | ||
1020 | u16 control; | ||
1021 | u8 bir; | ||
1022 | |||
1023 | pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); | ||
1024 | pci_read_config_word(dev, msi_control_reg(pos), | ||
1025 | &control); | ||
1026 | nr_entries = multi_msix_capable(control); | ||
1027 | pci_read_config_dword(dev, msix_table_offset_reg(pos), | ||
1028 | &table_offset); | ||
1029 | bir = (u8)(table_offset & PCI_MSIX_FLAGS_BIRMASK); | ||
1030 | table_offset &= ~PCI_MSIX_FLAGS_BIRMASK; | ||
1031 | phys_addr = pci_resource_start(dev, bir) + table_offset; | ||
1032 | /* | ||
1033 | * FIXME! and what did you want to do with phys_addr? | ||
1034 | */ | ||
1035 | #endif | ||
1036 | iounmap(base); | 1064 | iounmap(base); |
1037 | } | ||
1038 | } | 1065 | } |
1039 | 1066 | ||
1040 | return 0; | 1067 | return 0; |
@@ -1108,6 +1135,7 @@ static int reroute_msix_table(int head, struct msix_entry *entries, int *nvec) | |||
1108 | **/ | 1135 | **/ |
1109 | int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) | 1136 | int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) |
1110 | { | 1137 | { |
1138 | struct pci_bus *bus; | ||
1111 | int status, pos, nr_entries, free_vectors; | 1139 | int status, pos, nr_entries, free_vectors; |
1112 | int i, j, temp; | 1140 | int i, j, temp; |
1113 | u16 control; | 1141 | u16 control; |
@@ -1116,6 +1144,13 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) | |||
1116 | if (!pci_msi_enable || !dev || !entries) | 1144 | if (!pci_msi_enable || !dev || !entries) |
1117 | return -EINVAL; | 1145 | return -EINVAL; |
1118 | 1146 | ||
1147 | if (dev->no_msi) | ||
1148 | return -EINVAL; | ||
1149 | |||
1150 | for (bus = dev->bus; bus; bus = bus->parent) | ||
1151 | if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI) | ||
1152 | return -EINVAL; | ||
1153 | |||
1119 | status = msi_init(); | 1154 | status = msi_init(); |
1120 | if (status < 0) | 1155 | if (status < 0) |
1121 | return status; | 1156 | return status; |
@@ -1300,24 +1335,6 @@ void msi_remove_pci_irq_vectors(struct pci_dev* dev) | |||
1300 | } | 1335 | } |
1301 | msi_free_vector(dev, vector, 0); | 1336 | msi_free_vector(dev, vector, 0); |
1302 | if (warning) { | 1337 | if (warning) { |
1303 | /* Force to release the MSI-X memory-mapped table */ | ||
1304 | #if 0 | ||
1305 | unsigned long phys_addr; | ||
1306 | u32 table_offset; | ||
1307 | u16 control; | ||
1308 | u8 bir; | ||
1309 | |||
1310 | pci_read_config_word(dev, msi_control_reg(pos), | ||
1311 | &control); | ||
1312 | pci_read_config_dword(dev, msix_table_offset_reg(pos), | ||
1313 | &table_offset); | ||
1314 | bir = (u8)(table_offset & PCI_MSIX_FLAGS_BIRMASK); | ||
1315 | table_offset &= ~PCI_MSIX_FLAGS_BIRMASK; | ||
1316 | phys_addr = pci_resource_start(dev, bir) + table_offset; | ||
1317 | /* | ||
1318 | * FIXME! and what did you want to do with phys_addr? | ||
1319 | */ | ||
1320 | #endif | ||
1321 | iounmap(base); | 1338 | iounmap(base); |
1322 | printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() " | 1339 | printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() " |
1323 | "called without free_irq() on all MSI-X vectors\n", | 1340 | "called without free_irq() on all MSI-X vectors\n", |
diff --git a/drivers/pci/msi.h b/drivers/pci/msi.h index 4ac52d441e47..56951c39d3a3 100644 --- a/drivers/pci/msi.h +++ b/drivers/pci/msi.h | |||
@@ -6,6 +6,68 @@ | |||
6 | #ifndef MSI_H | 6 | #ifndef MSI_H |
7 | #define MSI_H | 7 | #define MSI_H |
8 | 8 | ||
9 | /* | ||
10 | * MSI operation vector. Used by the msi core code (drivers/pci/msi.c) | ||
11 | * to abstract platform-specific tasks relating to MSI address generation | ||
12 | * and resource management. | ||
13 | */ | ||
14 | struct msi_ops { | ||
15 | /** | ||
16 | * setup - generate an MSI bus address and data for a given vector | ||
17 | * @pdev: PCI device context (in) | ||
18 | * @vector: vector allocated by the msi core (in) | ||
19 | * @addr_hi: upper 32 bits of PCI bus MSI address (out) | ||
20 | * @addr_lo: lower 32 bits of PCI bus MSI address (out) | ||
21 | * @data: MSI data payload (out) | ||
22 | * | ||
23 | * Description: The setup op is used to generate a PCI bus addres and | ||
24 | * data which the msi core will program into the card MSI capability | ||
25 | * registers. The setup routine is responsible for picking an initial | ||
26 | * cpu to target the MSI at. The setup routine is responsible for | ||
27 | * examining pdev to determine the MSI capabilities of the card and | ||
28 | * generating a suitable address/data. The setup routine is | ||
29 | * responsible for allocating and tracking any system resources it | ||
30 | * needs to route the MSI to the cpu it picks, and for associating | ||
31 | * those resources with the passed in vector. | ||
32 | * | ||
33 | * Returns 0 if the MSI address/data was successfully setup. | ||
34 | **/ | ||
35 | |||
36 | int (*setup) (struct pci_dev *pdev, unsigned int vector, | ||
37 | u32 *addr_hi, u32 *addr_lo, u32 *data); | ||
38 | |||
39 | /** | ||
40 | * teardown - release resources allocated by setup | ||
41 | * @vector: vector context for resources (in) | ||
42 | * | ||
43 | * Description: The teardown op is used to release any resources | ||
44 | * that were allocated in the setup routine associated with the passed | ||
45 | * in vector. | ||
46 | **/ | ||
47 | |||
48 | void (*teardown) (unsigned int vector); | ||
49 | |||
50 | /** | ||
51 | * target - retarget an MSI at a different cpu | ||
52 | * @vector: vector context for resources (in) | ||
53 | * @cpu: new cpu to direct vector at (in) | ||
54 | * @addr_hi: new value of PCI bus upper 32 bits (in/out) | ||
55 | * @addr_lo: new value of PCI bus lower 32 bits (in/out) | ||
56 | * | ||
57 | * Description: The target op is used to redirect an MSI vector | ||
58 | * at a different cpu. addr_hi/addr_lo coming in are the existing | ||
59 | * values that the MSI core has programmed into the card. The | ||
60 | * target code is responsible for freeing any resources (if any) | ||
61 | * associated with the old address, and generating a new PCI bus | ||
62 | * addr_hi/addr_lo that will redirect the vector at the indicated cpu. | ||
63 | **/ | ||
64 | |||
65 | void (*target) (unsigned int vector, unsigned int cpu, | ||
66 | u32 *addr_hi, u32 *addr_lo); | ||
67 | }; | ||
68 | |||
69 | extern int msi_register(struct msi_ops *ops); | ||
70 | |||
9 | #include <asm/msi.h> | 71 | #include <asm/msi.h> |
10 | 72 | ||
11 | /* | 73 | /* |
@@ -63,67 +125,6 @@ extern int pci_vector_resources(int last, int nr_released); | |||
63 | #define msix_mask(address) (address | PCI_MSIX_FLAGS_BITMASK) | 125 | #define msix_mask(address) (address | PCI_MSIX_FLAGS_BITMASK) |
64 | #define msix_is_pending(address) (address & PCI_MSIX_FLAGS_PENDMASK) | 126 | #define msix_is_pending(address) (address & PCI_MSIX_FLAGS_PENDMASK) |
65 | 127 | ||
66 | /* | ||
67 | * MSI Defined Data Structures | ||
68 | */ | ||
69 | #define MSI_ADDRESS_HEADER 0xfee | ||
70 | #define MSI_ADDRESS_HEADER_SHIFT 12 | ||
71 | #define MSI_ADDRESS_HEADER_MASK 0xfff000 | ||
72 | #define MSI_ADDRESS_DEST_ID_MASK 0xfff0000f | ||
73 | #define MSI_TARGET_CPU_MASK 0xff | ||
74 | #define MSI_DELIVERY_MODE 0 | ||
75 | #define MSI_LEVEL_MODE 1 /* Edge always assert */ | ||
76 | #define MSI_TRIGGER_MODE 0 /* MSI is edge sensitive */ | ||
77 | #define MSI_PHYSICAL_MODE 0 | ||
78 | #define MSI_LOGICAL_MODE 1 | ||
79 | #define MSI_REDIRECTION_HINT_MODE 0 | ||
80 | |||
81 | struct msg_data { | ||
82 | #if defined(__LITTLE_ENDIAN_BITFIELD) | ||
83 | __u32 vector : 8; | ||
84 | __u32 delivery_mode : 3; /* 000b: FIXED | 001b: lowest prior */ | ||
85 | __u32 reserved_1 : 3; | ||
86 | __u32 level : 1; /* 0: deassert | 1: assert */ | ||
87 | __u32 trigger : 1; /* 0: edge | 1: level */ | ||
88 | __u32 reserved_2 : 16; | ||
89 | #elif defined(__BIG_ENDIAN_BITFIELD) | ||
90 | __u32 reserved_2 : 16; | ||
91 | __u32 trigger : 1; /* 0: edge | 1: level */ | ||
92 | __u32 level : 1; /* 0: deassert | 1: assert */ | ||
93 | __u32 reserved_1 : 3; | ||
94 | __u32 delivery_mode : 3; /* 000b: FIXED | 001b: lowest prior */ | ||
95 | __u32 vector : 8; | ||
96 | #else | ||
97 | #error "Bitfield endianness not defined! Check your byteorder.h" | ||
98 | #endif | ||
99 | } __attribute__ ((packed)); | ||
100 | |||
101 | struct msg_address { | ||
102 | union { | ||
103 | struct { | ||
104 | #if defined(__LITTLE_ENDIAN_BITFIELD) | ||
105 | __u32 reserved_1 : 2; | ||
106 | __u32 dest_mode : 1; /*0:physic | 1:logic */ | ||
107 | __u32 redirection_hint: 1; /*0: dedicated CPU | ||
108 | 1: lowest priority */ | ||
109 | __u32 reserved_2 : 4; | ||
110 | __u32 dest_id : 24; /* Destination ID */ | ||
111 | #elif defined(__BIG_ENDIAN_BITFIELD) | ||
112 | __u32 dest_id : 24; /* Destination ID */ | ||
113 | __u32 reserved_2 : 4; | ||
114 | __u32 redirection_hint: 1; /*0: dedicated CPU | ||
115 | 1: lowest priority */ | ||
116 | __u32 dest_mode : 1; /*0:physic | 1:logic */ | ||
117 | __u32 reserved_1 : 2; | ||
118 | #else | ||
119 | #error "Bitfield endianness not defined! Check your byteorder.h" | ||
120 | #endif | ||
121 | }u; | ||
122 | __u32 value; | ||
123 | }lo_address; | ||
124 | __u32 hi_address; | ||
125 | } __attribute__ ((packed)); | ||
126 | |||
127 | struct msi_desc { | 128 | struct msi_desc { |
128 | struct { | 129 | struct { |
129 | __u8 type : 5; /* {0: unused, 5h:MSI, 11h:MSI-X} */ | 130 | __u8 type : 5; /* {0: unused, 5h:MSI, 11h:MSI-X} */ |
@@ -132,7 +133,7 @@ struct msi_desc { | |||
132 | __u8 reserved: 1; /* reserved */ | 133 | __u8 reserved: 1; /* reserved */ |
133 | __u8 entry_nr; /* specific enabled entry */ | 134 | __u8 entry_nr; /* specific enabled entry */ |
134 | __u8 default_vector; /* default pre-assigned vector */ | 135 | __u8 default_vector; /* default pre-assigned vector */ |
135 | __u8 current_cpu; /* current destination cpu */ | 136 | __u8 unused; /* formerly unused destination cpu*/ |
136 | }msi_attrib; | 137 | }msi_attrib; |
137 | 138 | ||
138 | struct { | 139 | struct { |
@@ -142,6 +143,14 @@ struct msi_desc { | |||
142 | 143 | ||
143 | void __iomem *mask_base; | 144 | void __iomem *mask_base; |
144 | struct pci_dev *dev; | 145 | struct pci_dev *dev; |
146 | |||
147 | #ifdef CONFIG_PM | ||
148 | /* PM save area for MSIX address/data */ | ||
149 | |||
150 | u32 address_hi_save; | ||
151 | u32 address_lo_save; | ||
152 | u32 data_save; | ||
153 | #endif | ||
145 | }; | 154 | }; |
146 | 155 | ||
147 | #endif /* MSI_H */ | 156 | #endif /* MSI_H */ |
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index c2ecae5ff0c1..bb7456c1dbac 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c | |||
@@ -267,7 +267,7 @@ static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state) | |||
267 | 267 | ||
268 | 268 | ||
269 | /* ACPI bus type */ | 269 | /* ACPI bus type */ |
270 | static int pci_acpi_find_device(struct device *dev, acpi_handle *handle) | 270 | static int acpi_pci_find_device(struct device *dev, acpi_handle *handle) |
271 | { | 271 | { |
272 | struct pci_dev * pci_dev; | 272 | struct pci_dev * pci_dev; |
273 | acpi_integer addr; | 273 | acpi_integer addr; |
@@ -281,7 +281,7 @@ static int pci_acpi_find_device(struct device *dev, acpi_handle *handle) | |||
281 | return 0; | 281 | return 0; |
282 | } | 282 | } |
283 | 283 | ||
284 | static int pci_acpi_find_root_bridge(struct device *dev, acpi_handle *handle) | 284 | static int acpi_pci_find_root_bridge(struct device *dev, acpi_handle *handle) |
285 | { | 285 | { |
286 | int num; | 286 | int num; |
287 | unsigned int seg, bus; | 287 | unsigned int seg, bus; |
@@ -299,21 +299,21 @@ static int pci_acpi_find_root_bridge(struct device *dev, acpi_handle *handle) | |||
299 | return 0; | 299 | return 0; |
300 | } | 300 | } |
301 | 301 | ||
302 | static struct acpi_bus_type pci_acpi_bus = { | 302 | static struct acpi_bus_type acpi_pci_bus = { |
303 | .bus = &pci_bus_type, | 303 | .bus = &pci_bus_type, |
304 | .find_device = pci_acpi_find_device, | 304 | .find_device = acpi_pci_find_device, |
305 | .find_bridge = pci_acpi_find_root_bridge, | 305 | .find_bridge = acpi_pci_find_root_bridge, |
306 | }; | 306 | }; |
307 | 307 | ||
308 | static int __init pci_acpi_init(void) | 308 | static int __init acpi_pci_init(void) |
309 | { | 309 | { |
310 | int ret; | 310 | int ret; |
311 | 311 | ||
312 | ret = register_acpi_bus_type(&pci_acpi_bus); | 312 | ret = register_acpi_bus_type(&acpi_pci_bus); |
313 | if (ret) | 313 | if (ret) |
314 | return 0; | 314 | return 0; |
315 | platform_pci_choose_state = acpi_pci_choose_state; | 315 | platform_pci_choose_state = acpi_pci_choose_state; |
316 | platform_pci_set_power_state = acpi_pci_set_power_state; | 316 | platform_pci_set_power_state = acpi_pci_set_power_state; |
317 | return 0; | 317 | return 0; |
318 | } | 318 | } |
319 | arch_initcall(pci_acpi_init); | 319 | arch_initcall(acpi_pci_init); |
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 56ac2bc003c7..bc405c035ce3 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c | |||
@@ -43,6 +43,29 @@ pci_config_attr(subsystem_vendor, "0x%04x\n"); | |||
43 | pci_config_attr(subsystem_device, "0x%04x\n"); | 43 | pci_config_attr(subsystem_device, "0x%04x\n"); |
44 | pci_config_attr(class, "0x%06x\n"); | 44 | pci_config_attr(class, "0x%06x\n"); |
45 | pci_config_attr(irq, "%u\n"); | 45 | pci_config_attr(irq, "%u\n"); |
46 | pci_config_attr(is_enabled, "%u\n"); | ||
47 | |||
48 | static ssize_t broken_parity_status_show(struct device *dev, | ||
49 | struct device_attribute *attr, | ||
50 | char *buf) | ||
51 | { | ||
52 | struct pci_dev *pdev = to_pci_dev(dev); | ||
53 | return sprintf (buf, "%u\n", pdev->broken_parity_status); | ||
54 | } | ||
55 | |||
56 | static ssize_t broken_parity_status_store(struct device *dev, | ||
57 | struct device_attribute *attr, | ||
58 | const char *buf, size_t count) | ||
59 | { | ||
60 | struct pci_dev *pdev = to_pci_dev(dev); | ||
61 | ssize_t consumed = -EINVAL; | ||
62 | |||
63 | if ((count > 0) && (*buf == '0' || *buf == '1')) { | ||
64 | pdev->broken_parity_status = *buf == '1' ? 1 : 0; | ||
65 | consumed = count; | ||
66 | } | ||
67 | return consumed; | ||
68 | } | ||
46 | 69 | ||
47 | static ssize_t local_cpus_show(struct device *dev, | 70 | static ssize_t local_cpus_show(struct device *dev, |
48 | struct device_attribute *attr, char *buf) | 71 | struct device_attribute *attr, char *buf) |
@@ -90,6 +113,25 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, | |||
90 | (u8)(pci_dev->class >> 16), (u8)(pci_dev->class >> 8), | 113 | (u8)(pci_dev->class >> 16), (u8)(pci_dev->class >> 8), |
91 | (u8)(pci_dev->class)); | 114 | (u8)(pci_dev->class)); |
92 | } | 115 | } |
116 | static ssize_t | ||
117 | is_enabled_store(struct device *dev, struct device_attribute *attr, | ||
118 | const char *buf, size_t count) | ||
119 | { | ||
120 | struct pci_dev *pdev = to_pci_dev(dev); | ||
121 | |||
122 | /* this can crash the machine when done on the "wrong" device */ | ||
123 | if (!capable(CAP_SYS_ADMIN)) | ||
124 | return count; | ||
125 | |||
126 | if (*buf == '0') | ||
127 | pci_disable_device(pdev); | ||
128 | |||
129 | if (*buf == '1') | ||
130 | pci_enable_device(pdev); | ||
131 | |||
132 | return count; | ||
133 | } | ||
134 | |||
93 | 135 | ||
94 | struct device_attribute pci_dev_attrs[] = { | 136 | struct device_attribute pci_dev_attrs[] = { |
95 | __ATTR_RO(resource), | 137 | __ATTR_RO(resource), |
@@ -101,6 +143,9 @@ struct device_attribute pci_dev_attrs[] = { | |||
101 | __ATTR_RO(irq), | 143 | __ATTR_RO(irq), |
102 | __ATTR_RO(local_cpus), | 144 | __ATTR_RO(local_cpus), |
103 | __ATTR_RO(modalias), | 145 | __ATTR_RO(modalias), |
146 | __ATTR(enable, 0600, is_enabled_show, is_enabled_store), | ||
147 | __ATTR(broken_parity_status,(S_IRUGO|S_IWUSR), | ||
148 | broken_parity_status_show,broken_parity_status_store), | ||
104 | __ATTR_NULL, | 149 | __ATTR_NULL, |
105 | }; | 150 | }; |
106 | 151 | ||
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index fde41cc14734..d408a3c30426 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c | |||
@@ -517,7 +517,12 @@ pci_enable_device_bars(struct pci_dev *dev, int bars) | |||
517 | int | 517 | int |
518 | pci_enable_device(struct pci_dev *dev) | 518 | pci_enable_device(struct pci_dev *dev) |
519 | { | 519 | { |
520 | int err = pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1); | 520 | int err; |
521 | |||
522 | if (dev->is_enabled) | ||
523 | return 0; | ||
524 | |||
525 | err = pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1); | ||
521 | if (err) | 526 | if (err) |
522 | return err; | 527 | return err; |
523 | pci_fixup_device(pci_fixup_enable, dev); | 528 | pci_fixup_device(pci_fixup_enable, dev); |
@@ -546,7 +551,14 @@ void | |||
546 | pci_disable_device(struct pci_dev *dev) | 551 | pci_disable_device(struct pci_dev *dev) |
547 | { | 552 | { |
548 | u16 pci_command; | 553 | u16 pci_command; |
549 | 554 | ||
555 | if (dev->msi_enabled) | ||
556 | disable_msi_mode(dev, pci_find_capability(dev, PCI_CAP_ID_MSI), | ||
557 | PCI_CAP_ID_MSI); | ||
558 | if (dev->msix_enabled) | ||
559 | disable_msi_mode(dev, pci_find_capability(dev, PCI_CAP_ID_MSI), | ||
560 | PCI_CAP_ID_MSIX); | ||
561 | |||
550 | pci_read_config_word(dev, PCI_COMMAND, &pci_command); | 562 | pci_read_config_word(dev, PCI_COMMAND, &pci_command); |
551 | if (pci_command & PCI_COMMAND_MASTER) { | 563 | if (pci_command & PCI_COMMAND_MASTER) { |
552 | pci_command &= ~PCI_COMMAND_MASTER; | 564 | pci_command &= ~PCI_COMMAND_MASTER; |
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 30630cbe2fe3..29bdeca031a8 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h | |||
@@ -40,7 +40,7 @@ extern int pci_bus_find_capability (struct pci_bus *bus, unsigned int devfn, int | |||
40 | extern void pci_remove_legacy_files(struct pci_bus *bus); | 40 | extern void pci_remove_legacy_files(struct pci_bus *bus); |
41 | 41 | ||
42 | /* Lock for read/write access to pci device and bus lists */ | 42 | /* Lock for read/write access to pci device and bus lists */ |
43 | extern spinlock_t pci_bus_lock; | 43 | extern struct rw_semaphore pci_bus_sem; |
44 | 44 | ||
45 | #ifdef CONFIG_X86_IO_APIC | 45 | #ifdef CONFIG_X86_IO_APIC |
46 | extern int pci_msi_quirk; | 46 | extern int pci_msi_quirk; |
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index a10ed9dab2c2..f89dbc3738b7 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c | |||
@@ -180,25 +180,31 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) | |||
180 | res->flags |= pci_calc_resource_flags(l); | 180 | res->flags |= pci_calc_resource_flags(l); |
181 | if ((l & (PCI_BASE_ADDRESS_SPACE | PCI_BASE_ADDRESS_MEM_TYPE_MASK)) | 181 | if ((l & (PCI_BASE_ADDRESS_SPACE | PCI_BASE_ADDRESS_MEM_TYPE_MASK)) |
182 | == (PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64)) { | 182 | == (PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64)) { |
183 | pci_read_config_dword(dev, reg+4, &l); | 183 | u32 szhi, lhi; |
184 | pci_read_config_dword(dev, reg+4, &lhi); | ||
185 | pci_write_config_dword(dev, reg+4, ~0); | ||
186 | pci_read_config_dword(dev, reg+4, &szhi); | ||
187 | pci_write_config_dword(dev, reg+4, lhi); | ||
188 | szhi = pci_size(lhi, szhi, 0xffffffff); | ||
184 | next++; | 189 | next++; |
185 | #if BITS_PER_LONG == 64 | 190 | #if BITS_PER_LONG == 64 |
186 | res->start |= ((unsigned long) l) << 32; | 191 | res->start |= ((unsigned long) lhi) << 32; |
187 | res->end = res->start + sz; | 192 | res->end = res->start + sz; |
188 | pci_write_config_dword(dev, reg+4, ~0); | 193 | if (szhi) { |
189 | pci_read_config_dword(dev, reg+4, &sz); | ||
190 | pci_write_config_dword(dev, reg+4, l); | ||
191 | sz = pci_size(l, sz, 0xffffffff); | ||
192 | if (sz) { | ||
193 | /* This BAR needs > 4GB? Wow. */ | 194 | /* This BAR needs > 4GB? Wow. */ |
194 | res->end |= (unsigned long)sz<<32; | 195 | res->end |= (unsigned long)szhi<<32; |
195 | } | 196 | } |
196 | #else | 197 | #else |
197 | if (l) { | 198 | if (szhi) { |
198 | printk(KERN_ERR "PCI: Unable to handle 64-bit address for device %s\n", pci_name(dev)); | 199 | printk(KERN_ERR "PCI: Unable to handle 64-bit BAR for device %s\n", pci_name(dev)); |
199 | res->start = 0; | 200 | res->start = 0; |
200 | res->flags = 0; | 201 | res->flags = 0; |
201 | continue; | 202 | } else if (lhi) { |
203 | /* 64-bit wide address, treat as disabled */ | ||
204 | pci_write_config_dword(dev, reg, l & ~(u32)PCI_BASE_ADDRESS_MEM_MASK); | ||
205 | pci_write_config_dword(dev, reg+4, 0); | ||
206 | res->start = 0; | ||
207 | res->end = sz; | ||
202 | } | 208 | } |
203 | #endif | 209 | #endif |
204 | } | 210 | } |
@@ -377,9 +383,9 @@ struct pci_bus * __devinit pci_add_new_bus(struct pci_bus *parent, struct pci_de | |||
377 | 383 | ||
378 | child = pci_alloc_child_bus(parent, dev, busnr); | 384 | child = pci_alloc_child_bus(parent, dev, busnr); |
379 | if (child) { | 385 | if (child) { |
380 | spin_lock(&pci_bus_lock); | 386 | down_write(&pci_bus_sem); |
381 | list_add_tail(&child->node, &parent->children); | 387 | list_add_tail(&child->node, &parent->children); |
382 | spin_unlock(&pci_bus_lock); | 388 | up_write(&pci_bus_sem); |
383 | } | 389 | } |
384 | return child; | 390 | return child; |
385 | } | 391 | } |
@@ -838,9 +844,9 @@ void __devinit pci_device_add(struct pci_dev *dev, struct pci_bus *bus) | |||
838 | * and the bus list for fixup functions, etc. | 844 | * and the bus list for fixup functions, etc. |
839 | */ | 845 | */ |
840 | INIT_LIST_HEAD(&dev->global_list); | 846 | INIT_LIST_HEAD(&dev->global_list); |
841 | spin_lock(&pci_bus_lock); | 847 | down_write(&pci_bus_sem); |
842 | list_add_tail(&dev->bus_list, &bus->devices); | 848 | list_add_tail(&dev->bus_list, &bus->devices); |
843 | spin_unlock(&pci_bus_lock); | 849 | up_write(&pci_bus_sem); |
844 | } | 850 | } |
845 | 851 | ||
846 | struct pci_dev * __devinit | 852 | struct pci_dev * __devinit |
@@ -975,9 +981,10 @@ struct pci_bus * __devinit pci_create_bus(struct device *parent, | |||
975 | pr_debug("PCI: Bus %04x:%02x already known\n", pci_domain_nr(b), bus); | 981 | pr_debug("PCI: Bus %04x:%02x already known\n", pci_domain_nr(b), bus); |
976 | goto err_out; | 982 | goto err_out; |
977 | } | 983 | } |
978 | spin_lock(&pci_bus_lock); | 984 | |
985 | down_write(&pci_bus_sem); | ||
979 | list_add_tail(&b->node, &pci_root_buses); | 986 | list_add_tail(&b->node, &pci_root_buses); |
980 | spin_unlock(&pci_bus_lock); | 987 | up_write(&pci_bus_sem); |
981 | 988 | ||
982 | memset(dev, 0, sizeof(*dev)); | 989 | memset(dev, 0, sizeof(*dev)); |
983 | dev->parent = parent; | 990 | dev->parent = parent; |
@@ -1017,9 +1024,9 @@ class_dev_create_file_err: | |||
1017 | class_dev_reg_err: | 1024 | class_dev_reg_err: |
1018 | device_unregister(dev); | 1025 | device_unregister(dev); |
1019 | dev_reg_err: | 1026 | dev_reg_err: |
1020 | spin_lock(&pci_bus_lock); | 1027 | down_write(&pci_bus_sem); |
1021 | list_del(&b->node); | 1028 | list_del(&b->node); |
1022 | spin_unlock(&pci_bus_lock); | 1029 | up_write(&pci_bus_sem); |
1023 | err_out: | 1030 | err_out: |
1024 | kfree(dev); | 1031 | kfree(dev); |
1025 | kfree(b); | 1032 | kfree(b); |
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index d378478612fb..4364d793f73b 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c | |||
@@ -24,6 +24,17 @@ | |||
24 | #include <linux/acpi.h> | 24 | #include <linux/acpi.h> |
25 | #include "pci.h" | 25 | #include "pci.h" |
26 | 26 | ||
27 | /* The Mellanox Tavor device gives false positive parity errors | ||
28 | * Mark this device with a broken_parity_status, to allow | ||
29 | * PCI scanning code to "skip" this now blacklisted device. | ||
30 | */ | ||
31 | static void __devinit quirk_mellanox_tavor(struct pci_dev *dev) | ||
32 | { | ||
33 | dev->broken_parity_status = 1; /* This device gives false positives */ | ||
34 | } | ||
35 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MELLANOX,PCI_DEVICE_ID_MELLANOX_TAVOR,quirk_mellanox_tavor); | ||
36 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MELLANOX,PCI_DEVICE_ID_MELLANOX_TAVOR_BRIDGE,quirk_mellanox_tavor); | ||
37 | |||
27 | /* Deal with broken BIOS'es that neglect to enable passive release, | 38 | /* Deal with broken BIOS'es that neglect to enable passive release, |
28 | which can cause problems in combination with the 82441FX/PPro MTRRs */ | 39 | which can cause problems in combination with the 82441FX/PPro MTRRs */ |
29 | static void __devinit quirk_passive_release(struct pci_dev *dev) | 40 | static void __devinit quirk_passive_release(struct pci_dev *dev) |
@@ -878,27 +889,30 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82375, quirk_e | |||
878 | * when a PCI-Soundcard is added. The BIOS only gives Options | 889 | * when a PCI-Soundcard is added. The BIOS only gives Options |
879 | * "Disabled" and "AUTO". This Quirk Sets the corresponding | 890 | * "Disabled" and "AUTO". This Quirk Sets the corresponding |
880 | * Register-Value to enable the Soundcard. | 891 | * Register-Value to enable the Soundcard. |
892 | * | ||
893 | * FIXME: Presently this quirk will run on anything that has an 8237 | ||
894 | * which isn't correct, we need to check DMI tables or something in | ||
895 | * order to make sure it only runs on the MSI-K8T-Neo2Fir. Because it | ||
896 | * runs everywhere at present we suppress the printk output in most | ||
897 | * irrelevant cases. | ||
881 | */ | 898 | */ |
882 | static void __init k8t_sound_hostbridge(struct pci_dev *dev) | 899 | static void __init k8t_sound_hostbridge(struct pci_dev *dev) |
883 | { | 900 | { |
884 | unsigned char val; | 901 | unsigned char val; |
885 | 902 | ||
886 | printk(KERN_INFO "PCI: Quirk-MSI-K8T Soundcard On\n"); | ||
887 | pci_read_config_byte(dev, 0x50, &val); | 903 | pci_read_config_byte(dev, 0x50, &val); |
888 | if (val == 0x88 || val == 0xc8) { | 904 | if (val == 0x88 || val == 0xc8) { |
905 | /* Assume it's probably a MSI-K8T-Neo2Fir */ | ||
906 | printk(KERN_INFO "PCI: MSI-K8T-Neo2Fir, attempting to turn soundcard ON\n"); | ||
889 | pci_write_config_byte(dev, 0x50, val & (~0x40)); | 907 | pci_write_config_byte(dev, 0x50, val & (~0x40)); |
890 | 908 | ||
891 | /* Verify the Change for Status output */ | 909 | /* Verify the Change for Status output */ |
892 | pci_read_config_byte(dev, 0x50, &val); | 910 | pci_read_config_byte(dev, 0x50, &val); |
893 | if (val & 0x40) | 911 | if (val & 0x40) |
894 | printk(KERN_INFO "PCI: MSI-K8T soundcard still off\n"); | 912 | printk(KERN_INFO "PCI: MSI-K8T-Neo2Fir, soundcard still off\n"); |
895 | else | 913 | else |
896 | printk(KERN_INFO "PCI: MSI-K8T soundcard on\n"); | 914 | printk(KERN_INFO "PCI: MSI-K8T-Neo2Fir, soundcard on\n"); |
897 | } else { | ||
898 | printk(KERN_INFO "PCI: Unexpected Value in PCI-Register: " | ||
899 | "no Change!\n"); | ||
900 | } | 915 | } |
901 | |||
902 | } | 916 | } |
903 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, k8t_sound_hostbridge); | 917 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, k8t_sound_hostbridge); |
904 | 918 | ||
@@ -1485,6 +1499,25 @@ static void __devinit quirk_p64h2_1k_io(struct pci_dev *dev) | |||
1485 | } | 1499 | } |
1486 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1460, quirk_p64h2_1k_io); | 1500 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1460, quirk_p64h2_1k_io); |
1487 | 1501 | ||
1502 | /* Under some circumstances, AER is not linked with extended capabilities. | ||
1503 | * Force it to be linked by setting the corresponding control bit in the | ||
1504 | * config space. | ||
1505 | */ | ||
1506 | static void __devinit quirk_nvidia_ck804_pcie_aer_ext_cap(struct pci_dev *dev) | ||
1507 | { | ||
1508 | uint8_t b; | ||
1509 | if (pci_read_config_byte(dev, 0xf41, &b) == 0) { | ||
1510 | if (!(b & 0x20)) { | ||
1511 | pci_write_config_byte(dev, 0xf41, b | 0x20); | ||
1512 | printk(KERN_INFO | ||
1513 | "PCI: Linking AER extended capability on %s\n", | ||
1514 | pci_name(dev)); | ||
1515 | } | ||
1516 | } | ||
1517 | } | ||
1518 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE, | ||
1519 | quirk_nvidia_ck804_pcie_aer_ext_cap); | ||
1520 | |||
1488 | EXPORT_SYMBOL(pcie_mch_quirk); | 1521 | EXPORT_SYMBOL(pcie_mch_quirk); |
1489 | #ifdef CONFIG_HOTPLUG | 1522 | #ifdef CONFIG_HOTPLUG |
1490 | EXPORT_SYMBOL(pci_fixup_device); | 1523 | EXPORT_SYMBOL(pci_fixup_device); |
diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c index 1a6bf9de166f..99ffbd478b29 100644 --- a/drivers/pci/remove.c +++ b/drivers/pci/remove.c | |||
@@ -22,18 +22,18 @@ static void pci_destroy_dev(struct pci_dev *dev) | |||
22 | pci_proc_detach_device(dev); | 22 | pci_proc_detach_device(dev); |
23 | pci_remove_sysfs_dev_files(dev); | 23 | pci_remove_sysfs_dev_files(dev); |
24 | device_unregister(&dev->dev); | 24 | device_unregister(&dev->dev); |
25 | spin_lock(&pci_bus_lock); | 25 | down_write(&pci_bus_sem); |
26 | list_del(&dev->global_list); | 26 | list_del(&dev->global_list); |
27 | dev->global_list.next = dev->global_list.prev = NULL; | 27 | dev->global_list.next = dev->global_list.prev = NULL; |
28 | spin_unlock(&pci_bus_lock); | 28 | up_write(&pci_bus_sem); |
29 | } | 29 | } |
30 | 30 | ||
31 | /* Remove the device from the device lists, and prevent any further | 31 | /* Remove the device from the device lists, and prevent any further |
32 | * list accesses from this device */ | 32 | * list accesses from this device */ |
33 | spin_lock(&pci_bus_lock); | 33 | down_write(&pci_bus_sem); |
34 | list_del(&dev->bus_list); | 34 | list_del(&dev->bus_list); |
35 | dev->bus_list.next = dev->bus_list.prev = NULL; | 35 | dev->bus_list.next = dev->bus_list.prev = NULL; |
36 | spin_unlock(&pci_bus_lock); | 36 | up_write(&pci_bus_sem); |
37 | 37 | ||
38 | pci_free_resources(dev); | 38 | pci_free_resources(dev); |
39 | pci_dev_put(dev); | 39 | pci_dev_put(dev); |
@@ -62,9 +62,9 @@ void pci_remove_bus(struct pci_bus *pci_bus) | |||
62 | { | 62 | { |
63 | pci_proc_detach_bus(pci_bus); | 63 | pci_proc_detach_bus(pci_bus); |
64 | 64 | ||
65 | spin_lock(&pci_bus_lock); | 65 | down_write(&pci_bus_sem); |
66 | list_del(&pci_bus->node); | 66 | list_del(&pci_bus->node); |
67 | spin_unlock(&pci_bus_lock); | 67 | up_write(&pci_bus_sem); |
68 | pci_remove_legacy_files(pci_bus); | 68 | pci_remove_legacy_files(pci_bus); |
69 | class_device_remove_file(&pci_bus->class_dev, | 69 | class_device_remove_file(&pci_bus->class_dev, |
70 | &class_device_attr_cpuaffinity); | 70 | &class_device_attr_cpuaffinity); |
diff --git a/drivers/pci/search.c b/drivers/pci/search.c index ce7dd6e7be60..622b3f8ba820 100644 --- a/drivers/pci/search.c +++ b/drivers/pci/search.c | |||
@@ -13,7 +13,7 @@ | |||
13 | #include <linux/interrupt.h> | 13 | #include <linux/interrupt.h> |
14 | #include "pci.h" | 14 | #include "pci.h" |
15 | 15 | ||
16 | DEFINE_SPINLOCK(pci_bus_lock); | 16 | DECLARE_RWSEM(pci_bus_sem); |
17 | 17 | ||
18 | static struct pci_bus * __devinit | 18 | static struct pci_bus * __devinit |
19 | pci_do_find_bus(struct pci_bus* bus, unsigned char busnr) | 19 | pci_do_find_bus(struct pci_bus* bus, unsigned char busnr) |
@@ -72,11 +72,11 @@ pci_find_next_bus(const struct pci_bus *from) | |||
72 | struct pci_bus *b = NULL; | 72 | struct pci_bus *b = NULL; |
73 | 73 | ||
74 | WARN_ON(in_interrupt()); | 74 | WARN_ON(in_interrupt()); |
75 | spin_lock(&pci_bus_lock); | 75 | down_read(&pci_bus_sem); |
76 | n = from ? from->node.next : pci_root_buses.next; | 76 | n = from ? from->node.next : pci_root_buses.next; |
77 | if (n != &pci_root_buses) | 77 | if (n != &pci_root_buses) |
78 | b = pci_bus_b(n); | 78 | b = pci_bus_b(n); |
79 | spin_unlock(&pci_bus_lock); | 79 | up_read(&pci_bus_sem); |
80 | return b; | 80 | return b; |
81 | } | 81 | } |
82 | 82 | ||
@@ -124,7 +124,7 @@ struct pci_dev * pci_get_slot(struct pci_bus *bus, unsigned int devfn) | |||
124 | struct pci_dev *dev; | 124 | struct pci_dev *dev; |
125 | 125 | ||
126 | WARN_ON(in_interrupt()); | 126 | WARN_ON(in_interrupt()); |
127 | spin_lock(&pci_bus_lock); | 127 | down_read(&pci_bus_sem); |
128 | 128 | ||
129 | list_for_each(tmp, &bus->devices) { | 129 | list_for_each(tmp, &bus->devices) { |
130 | dev = pci_dev_b(tmp); | 130 | dev = pci_dev_b(tmp); |
@@ -135,7 +135,7 @@ struct pci_dev * pci_get_slot(struct pci_bus *bus, unsigned int devfn) | |||
135 | dev = NULL; | 135 | dev = NULL; |
136 | out: | 136 | out: |
137 | pci_dev_get(dev); | 137 | pci_dev_get(dev); |
138 | spin_unlock(&pci_bus_lock); | 138 | up_read(&pci_bus_sem); |
139 | return dev; | 139 | return dev; |
140 | } | 140 | } |
141 | 141 | ||
@@ -167,7 +167,7 @@ static struct pci_dev * pci_find_subsys(unsigned int vendor, | |||
167 | struct pci_dev *dev; | 167 | struct pci_dev *dev; |
168 | 168 | ||
169 | WARN_ON(in_interrupt()); | 169 | WARN_ON(in_interrupt()); |
170 | spin_lock(&pci_bus_lock); | 170 | down_read(&pci_bus_sem); |
171 | n = from ? from->global_list.next : pci_devices.next; | 171 | n = from ? from->global_list.next : pci_devices.next; |
172 | 172 | ||
173 | while (n && (n != &pci_devices)) { | 173 | while (n && (n != &pci_devices)) { |
@@ -181,7 +181,7 @@ static struct pci_dev * pci_find_subsys(unsigned int vendor, | |||
181 | } | 181 | } |
182 | dev = NULL; | 182 | dev = NULL; |
183 | exit: | 183 | exit: |
184 | spin_unlock(&pci_bus_lock); | 184 | up_read(&pci_bus_sem); |
185 | return dev; | 185 | return dev; |
186 | } | 186 | } |
187 | 187 | ||
@@ -232,7 +232,7 @@ pci_get_subsys(unsigned int vendor, unsigned int device, | |||
232 | struct pci_dev *dev; | 232 | struct pci_dev *dev; |
233 | 233 | ||
234 | WARN_ON(in_interrupt()); | 234 | WARN_ON(in_interrupt()); |
235 | spin_lock(&pci_bus_lock); | 235 | down_read(&pci_bus_sem); |
236 | n = from ? from->global_list.next : pci_devices.next; | 236 | n = from ? from->global_list.next : pci_devices.next; |
237 | 237 | ||
238 | while (n && (n != &pci_devices)) { | 238 | while (n && (n != &pci_devices)) { |
@@ -247,7 +247,7 @@ pci_get_subsys(unsigned int vendor, unsigned int device, | |||
247 | dev = NULL; | 247 | dev = NULL; |
248 | exit: | 248 | exit: |
249 | dev = pci_dev_get(dev); | 249 | dev = pci_dev_get(dev); |
250 | spin_unlock(&pci_bus_lock); | 250 | up_read(&pci_bus_sem); |
251 | pci_dev_put(from); | 251 | pci_dev_put(from); |
252 | return dev; | 252 | return dev; |
253 | } | 253 | } |
@@ -292,7 +292,7 @@ pci_find_device_reverse(unsigned int vendor, unsigned int device, const struct p | |||
292 | struct pci_dev *dev; | 292 | struct pci_dev *dev; |
293 | 293 | ||
294 | WARN_ON(in_interrupt()); | 294 | WARN_ON(in_interrupt()); |
295 | spin_lock(&pci_bus_lock); | 295 | down_read(&pci_bus_sem); |
296 | n = from ? from->global_list.prev : pci_devices.prev; | 296 | n = from ? from->global_list.prev : pci_devices.prev; |
297 | 297 | ||
298 | while (n && (n != &pci_devices)) { | 298 | while (n && (n != &pci_devices)) { |
@@ -304,7 +304,7 @@ pci_find_device_reverse(unsigned int vendor, unsigned int device, const struct p | |||
304 | } | 304 | } |
305 | dev = NULL; | 305 | dev = NULL; |
306 | exit: | 306 | exit: |
307 | spin_unlock(&pci_bus_lock); | 307 | up_read(&pci_bus_sem); |
308 | return dev; | 308 | return dev; |
309 | } | 309 | } |
310 | 310 | ||
@@ -328,7 +328,7 @@ struct pci_dev *pci_get_class(unsigned int class, struct pci_dev *from) | |||
328 | struct pci_dev *dev; | 328 | struct pci_dev *dev; |
329 | 329 | ||
330 | WARN_ON(in_interrupt()); | 330 | WARN_ON(in_interrupt()); |
331 | spin_lock(&pci_bus_lock); | 331 | down_read(&pci_bus_sem); |
332 | n = from ? from->global_list.next : pci_devices.next; | 332 | n = from ? from->global_list.next : pci_devices.next; |
333 | 333 | ||
334 | while (n && (n != &pci_devices)) { | 334 | while (n && (n != &pci_devices)) { |
@@ -340,7 +340,7 @@ struct pci_dev *pci_get_class(unsigned int class, struct pci_dev *from) | |||
340 | dev = NULL; | 340 | dev = NULL; |
341 | exit: | 341 | exit: |
342 | dev = pci_dev_get(dev); | 342 | dev = pci_dev_get(dev); |
343 | spin_unlock(&pci_bus_lock); | 343 | up_read(&pci_bus_sem); |
344 | pci_dev_put(from); | 344 | pci_dev_put(from); |
345 | return dev; | 345 | return dev; |
346 | } | 346 | } |
@@ -362,7 +362,7 @@ int pci_dev_present(const struct pci_device_id *ids) | |||
362 | int found = 0; | 362 | int found = 0; |
363 | 363 | ||
364 | WARN_ON(in_interrupt()); | 364 | WARN_ON(in_interrupt()); |
365 | spin_lock(&pci_bus_lock); | 365 | down_read(&pci_bus_sem); |
366 | while (ids->vendor || ids->subvendor || ids->class_mask) { | 366 | while (ids->vendor || ids->subvendor || ids->class_mask) { |
367 | list_for_each_entry(dev, &pci_devices, global_list) { | 367 | list_for_each_entry(dev, &pci_devices, global_list) { |
368 | if (pci_match_one_device(ids, dev)) { | 368 | if (pci_match_one_device(ids, dev)) { |
@@ -372,8 +372,8 @@ int pci_dev_present(const struct pci_device_id *ids) | |||
372 | } | 372 | } |
373 | ids++; | 373 | ids++; |
374 | } | 374 | } |
375 | exit: | 375 | exit: |
376 | spin_unlock(&pci_bus_lock); | 376 | up_read(&pci_bus_sem); |
377 | return found; | 377 | return found; |
378 | } | 378 | } |
379 | EXPORT_SYMBOL(pci_dev_present); | 379 | EXPORT_SYMBOL(pci_dev_present); |
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 28ce3a7ee434..35086e80faa9 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c | |||
@@ -55,9 +55,10 @@ pbus_assign_resources_sorted(struct pci_bus *bus) | |||
55 | list_for_each_entry(dev, &bus->devices, bus_list) { | 55 | list_for_each_entry(dev, &bus->devices, bus_list) { |
56 | u16 class = dev->class >> 8; | 56 | u16 class = dev->class >> 8; |
57 | 57 | ||
58 | /* Don't touch classless devices and host bridges. */ | 58 | /* Don't touch classless devices or host bridges or ioapics. */ |
59 | if (class == PCI_CLASS_NOT_DEFINED || | 59 | if (class == PCI_CLASS_NOT_DEFINED || |
60 | class == PCI_CLASS_BRIDGE_HOST) | 60 | class == PCI_CLASS_BRIDGE_HOST || |
61 | class == PCI_CLASS_SYSTEM_PIC) | ||
61 | continue; | 62 | continue; |
62 | 63 | ||
63 | pdev_sort_resources(dev, &head); | 64 | pdev_sort_resources(dev, &head); |
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c index ea9277b7f899..577f4b55c46d 100644 --- a/drivers/pci/setup-res.c +++ b/drivers/pci/setup-res.c | |||
@@ -155,6 +155,46 @@ int pci_assign_resource(struct pci_dev *dev, int resno) | |||
155 | return ret; | 155 | return ret; |
156 | } | 156 | } |
157 | 157 | ||
158 | #ifdef CONFIG_EMBEDDED | ||
159 | int pci_assign_resource_fixed(struct pci_dev *dev, int resno) | ||
160 | { | ||
161 | struct pci_bus *bus = dev->bus; | ||
162 | struct resource *res = dev->resource + resno; | ||
163 | unsigned int type_mask; | ||
164 | int i, ret = -EBUSY; | ||
165 | |||
166 | type_mask = IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_PREFETCH; | ||
167 | |||
168 | for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) { | ||
169 | struct resource *r = bus->resource[i]; | ||
170 | if (!r) | ||
171 | continue; | ||
172 | |||
173 | /* type_mask must match */ | ||
174 | if ((res->flags ^ r->flags) & type_mask) | ||
175 | continue; | ||
176 | |||
177 | ret = request_resource(r, res); | ||
178 | |||
179 | if (ret == 0) | ||
180 | break; | ||
181 | } | ||
182 | |||
183 | if (ret) { | ||
184 | printk(KERN_ERR "PCI: Failed to allocate %s resource " | ||
185 | "#%d:%llx@%llx for %s\n", | ||
186 | res->flags & IORESOURCE_IO ? "I/O" : "mem", | ||
187 | resno, (unsigned long long)(res->end - res->start + 1), | ||
188 | (unsigned long long)res->start, pci_name(dev)); | ||
189 | } else if (resno < PCI_BRIDGE_RESOURCES) { | ||
190 | pci_update_resource(dev, res, resno); | ||
191 | } | ||
192 | |||
193 | return ret; | ||
194 | } | ||
195 | EXPORT_SYMBOL_GPL(pci_assign_resource_fixed); | ||
196 | #endif | ||
197 | |||
158 | /* Sort resources by alignment */ | 198 | /* Sort resources by alignment */ |
159 | void __devinit | 199 | void __devinit |
160 | pdev_sort_resources(struct pci_dev *dev, struct resource_list *head) | 200 | pdev_sort_resources(struct pci_dev *dev, struct resource_list *head) |
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index 77bb2351500c..680f6063954b 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c | |||
@@ -397,30 +397,6 @@ | |||
397 | #include "ql1280_fw.h" | 397 | #include "ql1280_fw.h" |
398 | #include "ql1040_fw.h" | 398 | #include "ql1040_fw.h" |
399 | 399 | ||
400 | |||
401 | /* | ||
402 | * Missing PCI ID's | ||
403 | */ | ||
404 | #ifndef PCI_DEVICE_ID_QLOGIC_ISP1080 | ||
405 | #define PCI_DEVICE_ID_QLOGIC_ISP1080 0x1080 | ||
406 | #endif | ||
407 | #ifndef PCI_DEVICE_ID_QLOGIC_ISP1240 | ||
408 | #define PCI_DEVICE_ID_QLOGIC_ISP1240 0x1240 | ||
409 | #endif | ||
410 | #ifndef PCI_DEVICE_ID_QLOGIC_ISP1280 | ||
411 | #define PCI_DEVICE_ID_QLOGIC_ISP1280 0x1280 | ||
412 | #endif | ||
413 | #ifndef PCI_DEVICE_ID_QLOGIC_ISP10160 | ||
414 | #define PCI_DEVICE_ID_QLOGIC_ISP10160 0x1016 | ||
415 | #endif | ||
416 | #ifndef PCI_DEVICE_ID_QLOGIC_ISP12160 | ||
417 | #define PCI_DEVICE_ID_QLOGIC_ISP12160 0x1216 | ||
418 | #endif | ||
419 | |||
420 | #ifndef PCI_VENDOR_ID_AMI | ||
421 | #define PCI_VENDOR_ID_AMI 0x101e | ||
422 | #endif | ||
423 | |||
424 | #ifndef BITS_PER_LONG | 400 | #ifndef BITS_PER_LONG |
425 | #error "BITS_PER_LONG not defined!" | 401 | #error "BITS_PER_LONG not defined!" |
426 | #endif | 402 | #endif |
diff --git a/drivers/scsi/sata_vsc.c b/drivers/scsi/sata_vsc.c index 8a29ce340b47..27d658704cf9 100644 --- a/drivers/scsi/sata_vsc.c +++ b/drivers/scsi/sata_vsc.c | |||
@@ -433,13 +433,14 @@ err_out: | |||
433 | 433 | ||
434 | 434 | ||
435 | /* | 435 | /* |
436 | * 0x1725/0x7174 is the Vitesse VSC-7174 | 436 | * Intel 31244 is supposed to be identical. |
437 | * 0x8086/0x3200 is the Intel 31244, which is supposed to be identical | 437 | * Compatibility is untested as of yet. |
438 | * compatibility is untested as of yet | ||
439 | */ | 438 | */ |
440 | static const struct pci_device_id vsc_sata_pci_tbl[] = { | 439 | static const struct pci_device_id vsc_sata_pci_tbl[] = { |
441 | { 0x1725, 0x7174, PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 }, | 440 | { PCI_VENDOR_ID_VITESSE, PCI_DEVICE_ID_VITESSE_VSC7174, |
442 | { 0x8086, 0x3200, PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 }, | 441 | PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 }, |
442 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_GD31244, | ||
443 | PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 }, | ||
443 | { } | 444 | { } |
444 | }; | 445 | }; |
445 | 446 | ||
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 5ea778fc1caa..bef4a9622ed7 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig | |||
@@ -937,4 +937,23 @@ config SERIAL_SGI_IOC3 | |||
937 | If you have an SGI Altix with an IOC3 serial card, | 937 | If you have an SGI Altix with an IOC3 serial card, |
938 | say Y or M. Otherwise, say N. | 938 | say Y or M. Otherwise, say N. |
939 | 939 | ||
940 | config SERIAL_NETX | ||
941 | bool "NetX serial port support" | ||
942 | depends on ARM && ARCH_NETX | ||
943 | select SERIAL_CORE | ||
944 | help | ||
945 | If you have a machine based on a Hilscher NetX SoC you | ||
946 | can enable its onboard serial port by enabling this option. | ||
947 | |||
948 | To compile this driver as a module, choose M here: the | ||
949 | module will be called netx-serial. | ||
950 | |||
951 | config SERIAL_NETX_CONSOLE | ||
952 | bool "Console on NetX serial port" | ||
953 | depends on SERIAL_NETX | ||
954 | select SERIAL_CORE_CONSOLE | ||
955 | help | ||
956 | If you have enabled the serial port on the Motorola IMX | ||
957 | CPU you can make it the console by answering Y to this option. | ||
958 | |||
940 | endmenu | 959 | endmenu |
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index 0a71bf68a03f..927faee0362e 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile | |||
@@ -55,3 +55,4 @@ obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_siu.o | |||
55 | obj-$(CONFIG_SERIAL_SGI_IOC4) += ioc4_serial.o | 55 | obj-$(CONFIG_SERIAL_SGI_IOC4) += ioc4_serial.o |
56 | obj-$(CONFIG_SERIAL_SGI_IOC3) += ioc3_serial.o | 56 | obj-$(CONFIG_SERIAL_SGI_IOC3) += ioc3_serial.o |
57 | obj-$(CONFIG_SERIAL_AT91) += at91_serial.o | 57 | obj-$(CONFIG_SERIAL_AT91) += at91_serial.o |
58 | obj-$(CONFIG_SERIAL_NETX) += netx-serial.o | ||
diff --git a/drivers/serial/amba-pl010.c b/drivers/serial/amba-pl010.c index 1631414000a2..e920d196d0b1 100644 --- a/drivers/serial/amba-pl010.c +++ b/drivers/serial/amba-pl010.c | |||
@@ -52,7 +52,7 @@ | |||
52 | 52 | ||
53 | #include <asm/io.h> | 53 | #include <asm/io.h> |
54 | 54 | ||
55 | #define UART_NR 2 | 55 | #define UART_NR 8 |
56 | 56 | ||
57 | #define SERIAL_AMBA_MAJOR 204 | 57 | #define SERIAL_AMBA_MAJOR 204 |
58 | #define SERIAL_AMBA_MINOR 16 | 58 | #define SERIAL_AMBA_MINOR 16 |
diff --git a/drivers/serial/netx-serial.c b/drivers/serial/netx-serial.c new file mode 100644 index 000000000000..c1adc9e4b239 --- /dev/null +++ b/drivers/serial/netx-serial.c | |||
@@ -0,0 +1,749 @@ | |||
1 | /* | ||
2 | * drivers/serial/netx-serial.c | ||
3 | * | ||
4 | * Copyright (c) 2005 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 | ||
8 | * as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | #include <linux/config.h> | ||
21 | |||
22 | #if defined(CONFIG_SERIAL_NETX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) | ||
23 | #define SUPPORT_SYSRQ | ||
24 | #endif | ||
25 | |||
26 | #include <linux/device.h> | ||
27 | #include <linux/module.h> | ||
28 | #include <linux/ioport.h> | ||
29 | #include <linux/init.h> | ||
30 | #include <linux/console.h> | ||
31 | #include <linux/sysrq.h> | ||
32 | #include <linux/platform_device.h> | ||
33 | #include <linux/tty.h> | ||
34 | #include <linux/tty_flip.h> | ||
35 | #include <linux/serial_core.h> | ||
36 | #include <linux/serial.h> | ||
37 | |||
38 | #include <asm/io.h> | ||
39 | #include <asm/irq.h> | ||
40 | #include <asm/hardware.h> | ||
41 | #include <asm/arch/netx-regs.h> | ||
42 | |||
43 | /* We've been assigned a range on the "Low-density serial ports" major */ | ||
44 | #define SERIAL_NX_MAJOR 204 | ||
45 | #define MINOR_START 170 | ||
46 | |||
47 | #ifdef CONFIG_SERIAL_NETX_CONSOLE | ||
48 | |||
49 | enum uart_regs { | ||
50 | UART_DR = 0x00, | ||
51 | UART_SR = 0x04, | ||
52 | UART_LINE_CR = 0x08, | ||
53 | UART_BAUDDIV_MSB = 0x0c, | ||
54 | UART_BAUDDIV_LSB = 0x10, | ||
55 | UART_CR = 0x14, | ||
56 | UART_FR = 0x18, | ||
57 | UART_IIR = 0x1c, | ||
58 | UART_ILPR = 0x20, | ||
59 | UART_RTS_CR = 0x24, | ||
60 | UART_RTS_LEAD = 0x28, | ||
61 | UART_RTS_TRAIL = 0x2c, | ||
62 | UART_DRV_ENABLE = 0x30, | ||
63 | UART_BRM_CR = 0x34, | ||
64 | UART_RXFIFO_IRQLEVEL = 0x38, | ||
65 | UART_TXFIFO_IRQLEVEL = 0x3c, | ||
66 | }; | ||
67 | |||
68 | #define SR_FE (1<<0) | ||
69 | #define SR_PE (1<<1) | ||
70 | #define SR_BE (1<<2) | ||
71 | #define SR_OE (1<<3) | ||
72 | |||
73 | #define LINE_CR_BRK (1<<0) | ||
74 | #define LINE_CR_PEN (1<<1) | ||
75 | #define LINE_CR_EPS (1<<2) | ||
76 | #define LINE_CR_STP2 (1<<3) | ||
77 | #define LINE_CR_FEN (1<<4) | ||
78 | #define LINE_CR_5BIT (0<<5) | ||
79 | #define LINE_CR_6BIT (1<<5) | ||
80 | #define LINE_CR_7BIT (2<<5) | ||
81 | #define LINE_CR_8BIT (3<<5) | ||
82 | #define LINE_CR_BITS_MASK (3<<5) | ||
83 | |||
84 | #define CR_UART_EN (1<<0) | ||
85 | #define CR_SIREN (1<<1) | ||
86 | #define CR_SIRLP (1<<2) | ||
87 | #define CR_MSIE (1<<3) | ||
88 | #define CR_RIE (1<<4) | ||
89 | #define CR_TIE (1<<5) | ||
90 | #define CR_RTIE (1<<6) | ||
91 | #define CR_LBE (1<<7) | ||
92 | |||
93 | #define FR_CTS (1<<0) | ||
94 | #define FR_DSR (1<<1) | ||
95 | #define FR_DCD (1<<2) | ||
96 | #define FR_BUSY (1<<3) | ||
97 | #define FR_RXFE (1<<4) | ||
98 | #define FR_TXFF (1<<5) | ||
99 | #define FR_RXFF (1<<6) | ||
100 | #define FR_TXFE (1<<7) | ||
101 | |||
102 | #define IIR_MIS (1<<0) | ||
103 | #define IIR_RIS (1<<1) | ||
104 | #define IIR_TIS (1<<2) | ||
105 | #define IIR_RTIS (1<<3) | ||
106 | #define IIR_MASK 0xf | ||
107 | |||
108 | #define RTS_CR_AUTO (1<<0) | ||
109 | #define RTS_CR_RTS (1<<1) | ||
110 | #define RTS_CR_COUNT (1<<2) | ||
111 | #define RTS_CR_MOD2 (1<<3) | ||
112 | #define RTS_CR_RTS_POL (1<<4) | ||
113 | #define RTS_CR_CTS_CTR (1<<5) | ||
114 | #define RTS_CR_CTS_POL (1<<6) | ||
115 | #define RTS_CR_STICK (1<<7) | ||
116 | |||
117 | #define UART_PORT_SIZE 0x40 | ||
118 | #define DRIVER_NAME "netx-uart" | ||
119 | |||
120 | struct netx_port { | ||
121 | struct uart_port port; | ||
122 | }; | ||
123 | |||
124 | static void netx_stop_tx(struct uart_port *port) | ||
125 | { | ||
126 | unsigned int val; | ||
127 | val = readl(port->membase + UART_CR); | ||
128 | writel(val & ~CR_TIE, port->membase + UART_CR); | ||
129 | } | ||
130 | |||
131 | static void netx_stop_rx(struct uart_port *port) | ||
132 | { | ||
133 | unsigned int val; | ||
134 | val = readl(port->membase + UART_CR); | ||
135 | writel(val & ~CR_RIE, port->membase + UART_CR); | ||
136 | } | ||
137 | |||
138 | static void netx_enable_ms(struct uart_port *port) | ||
139 | { | ||
140 | unsigned int val; | ||
141 | val = readl(port->membase + UART_CR); | ||
142 | writel(val | CR_MSIE, port->membase + UART_CR); | ||
143 | } | ||
144 | |||
145 | static inline void netx_transmit_buffer(struct uart_port *port) | ||
146 | { | ||
147 | struct circ_buf *xmit = &port->info->xmit; | ||
148 | |||
149 | if (port->x_char) { | ||
150 | writel(port->x_char, port->membase + UART_DR); | ||
151 | port->icount.tx++; | ||
152 | port->x_char = 0; | ||
153 | return; | ||
154 | } | ||
155 | |||
156 | if (uart_tx_stopped(port) || uart_circ_empty(xmit)) { | ||
157 | netx_stop_tx(port); | ||
158 | return; | ||
159 | } | ||
160 | |||
161 | do { | ||
162 | /* send xmit->buf[xmit->tail] | ||
163 | * out the port here */ | ||
164 | writel(xmit->buf[xmit->tail], port->membase + UART_DR); | ||
165 | xmit->tail = (xmit->tail + 1) & | ||
166 | (UART_XMIT_SIZE - 1); | ||
167 | port->icount.tx++; | ||
168 | if (uart_circ_empty(xmit)) | ||
169 | break; | ||
170 | } while (!(readl(port->membase + UART_FR) & FR_TXFF)); | ||
171 | |||
172 | if (uart_circ_empty(xmit)) | ||
173 | netx_stop_tx(port); | ||
174 | } | ||
175 | |||
176 | static void netx_start_tx(struct uart_port *port) | ||
177 | { | ||
178 | writel( | ||
179 | readl(port->membase + UART_CR) | CR_TIE, port->membase + UART_CR); | ||
180 | |||
181 | if (!(readl(port->membase + UART_FR) & FR_TXFF)) | ||
182 | netx_transmit_buffer(port); | ||
183 | } | ||
184 | |||
185 | static unsigned int netx_tx_empty(struct uart_port *port) | ||
186 | { | ||
187 | return readl(port->membase + UART_FR) & FR_BUSY ? 0 : TIOCSER_TEMT; | ||
188 | } | ||
189 | |||
190 | static void netx_txint(struct uart_port *port) | ||
191 | { | ||
192 | struct circ_buf *xmit = &port->info->xmit; | ||
193 | |||
194 | if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { | ||
195 | netx_stop_tx(port); | ||
196 | return; | ||
197 | } | ||
198 | |||
199 | netx_transmit_buffer(port); | ||
200 | |||
201 | if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) | ||
202 | uart_write_wakeup(port); | ||
203 | } | ||
204 | |||
205 | static void netx_rxint(struct uart_port *port, struct pt_regs *regs) | ||
206 | { | ||
207 | unsigned char rx, flg, status; | ||
208 | struct tty_struct *tty = port->info->tty; | ||
209 | |||
210 | while (!(readl(port->membase + UART_FR) & FR_RXFE)) { | ||
211 | rx = readl(port->membase + UART_DR); | ||
212 | flg = TTY_NORMAL; | ||
213 | port->icount.rx++; | ||
214 | status = readl(port->membase + UART_SR); | ||
215 | if (status & SR_BE) { | ||
216 | writel(0, port->membase + UART_SR); | ||
217 | if (uart_handle_break(port)) | ||
218 | continue; | ||
219 | } | ||
220 | |||
221 | if (unlikely(status & (SR_FE | SR_PE | SR_OE))) { | ||
222 | |||
223 | if (status & SR_PE) | ||
224 | port->icount.parity++; | ||
225 | else if (status & SR_FE) | ||
226 | port->icount.frame++; | ||
227 | if (status & SR_OE) | ||
228 | port->icount.overrun++; | ||
229 | |||
230 | status &= port->read_status_mask; | ||
231 | |||
232 | if (status & SR_BE) | ||
233 | flg = TTY_BREAK; | ||
234 | else if (status & SR_PE) | ||
235 | flg = TTY_PARITY; | ||
236 | else if (status & SR_FE) | ||
237 | flg = TTY_FRAME; | ||
238 | } | ||
239 | |||
240 | if (uart_handle_sysrq_char(port, rx, regs)) | ||
241 | continue; | ||
242 | |||
243 | uart_insert_char(port, status, SR_OE, rx, flg); | ||
244 | } | ||
245 | |||
246 | tty_flip_buffer_push(tty); | ||
247 | return; | ||
248 | } | ||
249 | |||
250 | static irqreturn_t netx_int(int irq, void *dev_id, struct pt_regs *regs) | ||
251 | { | ||
252 | struct uart_port *port = (struct uart_port *)dev_id; | ||
253 | unsigned long flags; | ||
254 | unsigned char status; | ||
255 | |||
256 | spin_lock_irqsave(&port->lock,flags); | ||
257 | |||
258 | status = readl(port->membase + UART_IIR) & IIR_MASK; | ||
259 | while (status) { | ||
260 | if (status & IIR_RIS) | ||
261 | netx_rxint(port, regs); | ||
262 | if (status & IIR_TIS) | ||
263 | netx_txint(port); | ||
264 | if (status & IIR_MIS) { | ||
265 | if (readl(port->membase + UART_FR) & FR_CTS) | ||
266 | uart_handle_cts_change(port, 1); | ||
267 | else | ||
268 | uart_handle_cts_change(port, 0); | ||
269 | } | ||
270 | writel(0, port->membase + UART_IIR); | ||
271 | status = readl(port->membase + UART_IIR) & IIR_MASK; | ||
272 | } | ||
273 | |||
274 | spin_unlock_irqrestore(&port->lock,flags); | ||
275 | return IRQ_HANDLED; | ||
276 | } | ||
277 | |||
278 | static unsigned int netx_get_mctrl(struct uart_port *port) | ||
279 | { | ||
280 | unsigned int ret = TIOCM_DSR | TIOCM_CAR; | ||
281 | |||
282 | if (readl(port->membase + UART_FR) & FR_CTS) | ||
283 | ret |= TIOCM_CTS; | ||
284 | |||
285 | return ret; | ||
286 | } | ||
287 | |||
288 | static void netx_set_mctrl(struct uart_port *port, unsigned int mctrl) | ||
289 | { | ||
290 | unsigned int val; | ||
291 | |||
292 | if (mctrl & TIOCM_RTS) { | ||
293 | val = readl(port->membase + UART_RTS_CR); | ||
294 | writel(val | RTS_CR_RTS, port->membase + UART_RTS_CR); | ||
295 | } | ||
296 | } | ||
297 | |||
298 | static void netx_break_ctl(struct uart_port *port, int break_state) | ||
299 | { | ||
300 | unsigned int line_cr; | ||
301 | spin_lock_irq(&port->lock); | ||
302 | |||
303 | line_cr = readl(port->membase + UART_LINE_CR); | ||
304 | if (break_state != 0) | ||
305 | line_cr |= LINE_CR_BRK; | ||
306 | else | ||
307 | line_cr &= ~LINE_CR_BRK; | ||
308 | writel(line_cr, port->membase + UART_LINE_CR); | ||
309 | |||
310 | spin_unlock_irq(&port->lock); | ||
311 | } | ||
312 | |||
313 | static int netx_startup(struct uart_port *port) | ||
314 | { | ||
315 | int ret; | ||
316 | |||
317 | ret = request_irq(port->irq, netx_int, 0, | ||
318 | DRIVER_NAME, port); | ||
319 | if (ret) { | ||
320 | dev_err(port->dev, "unable to grab irq%d\n",port->irq); | ||
321 | goto exit; | ||
322 | } | ||
323 | |||
324 | writel(readl(port->membase + UART_LINE_CR) | LINE_CR_FEN, | ||
325 | port->membase + UART_LINE_CR); | ||
326 | |||
327 | writel(CR_MSIE | CR_RIE | CR_TIE | CR_RTIE | CR_UART_EN, | ||
328 | port->membase + UART_CR); | ||
329 | |||
330 | exit: | ||
331 | return ret; | ||
332 | } | ||
333 | |||
334 | static void netx_shutdown(struct uart_port *port) | ||
335 | { | ||
336 | writel(0, port->membase + UART_CR) ; | ||
337 | |||
338 | free_irq(port->irq, port); | ||
339 | } | ||
340 | |||
341 | static void | ||
342 | netx_set_termios(struct uart_port *port, struct termios *termios, | ||
343 | struct termios *old) | ||
344 | { | ||
345 | unsigned int baud, quot; | ||
346 | unsigned char old_cr; | ||
347 | unsigned char line_cr = LINE_CR_FEN; | ||
348 | unsigned char rts_cr = 0; | ||
349 | |||
350 | switch (termios->c_cflag & CSIZE) { | ||
351 | case CS5: | ||
352 | line_cr |= LINE_CR_5BIT; | ||
353 | break; | ||
354 | case CS6: | ||
355 | line_cr |= LINE_CR_6BIT; | ||
356 | break; | ||
357 | case CS7: | ||
358 | line_cr |= LINE_CR_7BIT; | ||
359 | break; | ||
360 | case CS8: | ||
361 | line_cr |= LINE_CR_8BIT; | ||
362 | break; | ||
363 | } | ||
364 | |||
365 | if (termios->c_cflag & CSTOPB) | ||
366 | line_cr |= LINE_CR_STP2; | ||
367 | |||
368 | if (termios->c_cflag & PARENB) { | ||
369 | line_cr |= LINE_CR_PEN; | ||
370 | if (!(termios->c_cflag & PARODD)) | ||
371 | line_cr |= LINE_CR_EPS; | ||
372 | } | ||
373 | |||
374 | if (termios->c_cflag & CRTSCTS) | ||
375 | rts_cr = RTS_CR_AUTO | RTS_CR_CTS_CTR | RTS_CR_RTS_POL; | ||
376 | |||
377 | baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); | ||
378 | quot = baud * 4096; | ||
379 | quot /= 1000; | ||
380 | quot *= 256; | ||
381 | quot /= 100000; | ||
382 | |||
383 | spin_lock_irq(&port->lock); | ||
384 | |||
385 | uart_update_timeout(port, termios->c_cflag, baud); | ||
386 | |||
387 | old_cr = readl(port->membase + UART_CR); | ||
388 | |||
389 | /* disable interrupts */ | ||
390 | writel(old_cr & ~(CR_MSIE | CR_RIE | CR_TIE | CR_RTIE), | ||
391 | port->membase + UART_CR); | ||
392 | |||
393 | /* drain transmitter */ | ||
394 | while (readl(port->membase + UART_FR) & FR_BUSY); | ||
395 | |||
396 | /* disable UART */ | ||
397 | writel(old_cr & ~CR_UART_EN, port->membase + UART_CR); | ||
398 | |||
399 | /* modem status interrupts */ | ||
400 | old_cr &= ~CR_MSIE; | ||
401 | if (UART_ENABLE_MS(port, termios->c_cflag)) | ||
402 | old_cr |= CR_MSIE; | ||
403 | |||
404 | writel((quot>>8) & 0xff, port->membase + UART_BAUDDIV_MSB); | ||
405 | writel(quot & 0xff, port->membase + UART_BAUDDIV_LSB); | ||
406 | writel(line_cr, port->membase + UART_LINE_CR); | ||
407 | |||
408 | writel(rts_cr, port->membase + UART_RTS_CR); | ||
409 | |||
410 | /* | ||
411 | * Characters to ignore | ||
412 | */ | ||
413 | port->ignore_status_mask = 0; | ||
414 | if (termios->c_iflag & IGNPAR) | ||
415 | port->ignore_status_mask |= SR_PE; | ||
416 | if (termios->c_iflag & IGNBRK) { | ||
417 | port->ignore_status_mask |= SR_BE; | ||
418 | /* | ||
419 | * If we're ignoring parity and break indicators, | ||
420 | * ignore overruns too (for real raw support). | ||
421 | */ | ||
422 | if (termios->c_iflag & IGNPAR) | ||
423 | port->ignore_status_mask |= SR_PE; | ||
424 | } | ||
425 | |||
426 | port->read_status_mask = 0; | ||
427 | if (termios->c_iflag & (BRKINT | PARMRK)) | ||
428 | port->read_status_mask |= SR_BE; | ||
429 | if (termios->c_iflag & INPCK) | ||
430 | port->read_status_mask |= SR_PE | SR_FE; | ||
431 | |||
432 | writel(old_cr, port->membase + UART_CR); | ||
433 | |||
434 | spin_unlock_irq(&port->lock); | ||
435 | } | ||
436 | |||
437 | static const char *netx_type(struct uart_port *port) | ||
438 | { | ||
439 | return port->type == PORT_NETX ? "NETX" : NULL; | ||
440 | } | ||
441 | |||
442 | static void netx_release_port(struct uart_port *port) | ||
443 | { | ||
444 | release_mem_region(port->mapbase, UART_PORT_SIZE); | ||
445 | } | ||
446 | |||
447 | static int netx_request_port(struct uart_port *port) | ||
448 | { | ||
449 | return request_mem_region(port->mapbase, UART_PORT_SIZE, | ||
450 | DRIVER_NAME) != NULL ? 0 : -EBUSY; | ||
451 | } | ||
452 | |||
453 | static void netx_config_port(struct uart_port *port, int flags) | ||
454 | { | ||
455 | if (flags & UART_CONFIG_TYPE && netx_request_port(port) == 0) | ||
456 | port->type = PORT_NETX; | ||
457 | } | ||
458 | |||
459 | static int | ||
460 | netx_verify_port(struct uart_port *port, struct serial_struct *ser) | ||
461 | { | ||
462 | int ret = 0; | ||
463 | |||
464 | if (ser->type != PORT_UNKNOWN && ser->type != PORT_NETX) | ||
465 | ret = -EINVAL; | ||
466 | |||
467 | return ret; | ||
468 | } | ||
469 | |||
470 | static struct uart_ops netx_pops = { | ||
471 | .tx_empty = netx_tx_empty, | ||
472 | .set_mctrl = netx_set_mctrl, | ||
473 | .get_mctrl = netx_get_mctrl, | ||
474 | .stop_tx = netx_stop_tx, | ||
475 | .start_tx = netx_start_tx, | ||
476 | .stop_rx = netx_stop_rx, | ||
477 | .enable_ms = netx_enable_ms, | ||
478 | .break_ctl = netx_break_ctl, | ||
479 | .startup = netx_startup, | ||
480 | .shutdown = netx_shutdown, | ||
481 | .set_termios = netx_set_termios, | ||
482 | .type = netx_type, | ||
483 | .release_port = netx_release_port, | ||
484 | .request_port = netx_request_port, | ||
485 | .config_port = netx_config_port, | ||
486 | .verify_port = netx_verify_port, | ||
487 | }; | ||
488 | |||
489 | static struct netx_port netx_ports[] = { | ||
490 | { | ||
491 | .port = { | ||
492 | .type = PORT_NETX, | ||
493 | .iotype = UPIO_MEM, | ||
494 | .membase = (char __iomem *)io_p2v(NETX_PA_UART0), | ||
495 | .mapbase = NETX_PA_UART0, | ||
496 | .irq = NETX_IRQ_UART0, | ||
497 | .uartclk = 100000000, | ||
498 | .fifosize = 16, | ||
499 | .flags = UPF_BOOT_AUTOCONF, | ||
500 | .ops = &netx_pops, | ||
501 | .line = 0, | ||
502 | }, | ||
503 | }, { | ||
504 | .port = { | ||
505 | .type = PORT_NETX, | ||
506 | .iotype = UPIO_MEM, | ||
507 | .membase = (char __iomem *)io_p2v(NETX_PA_UART1), | ||
508 | .mapbase = NETX_PA_UART1, | ||
509 | .irq = NETX_IRQ_UART1, | ||
510 | .uartclk = 100000000, | ||
511 | .fifosize = 16, | ||
512 | .flags = UPF_BOOT_AUTOCONF, | ||
513 | .ops = &netx_pops, | ||
514 | .line = 1, | ||
515 | }, | ||
516 | }, { | ||
517 | .port = { | ||
518 | .type = PORT_NETX, | ||
519 | .iotype = UPIO_MEM, | ||
520 | .membase = (char __iomem *)io_p2v(NETX_PA_UART2), | ||
521 | .mapbase = NETX_PA_UART2, | ||
522 | .irq = NETX_IRQ_UART2, | ||
523 | .uartclk = 100000000, | ||
524 | .fifosize = 16, | ||
525 | .flags = UPF_BOOT_AUTOCONF, | ||
526 | .ops = &netx_pops, | ||
527 | .line = 2, | ||
528 | }, | ||
529 | } | ||
530 | }; | ||
531 | |||
532 | static void netx_console_putchar(struct uart_port *port, int ch) | ||
533 | { | ||
534 | while (readl(port->membase + UART_FR) & FR_BUSY); | ||
535 | writel(ch, port->membase + UART_DR); | ||
536 | } | ||
537 | |||
538 | static void | ||
539 | netx_console_write(struct console *co, const char *s, unsigned int count) | ||
540 | { | ||
541 | struct uart_port *port = &netx_ports[co->index].port; | ||
542 | unsigned char cr_save; | ||
543 | |||
544 | cr_save = readl(port->membase + UART_CR); | ||
545 | writel(cr_save | CR_UART_EN, port->membase + UART_CR); | ||
546 | |||
547 | uart_console_write(port, s, count, netx_console_putchar); | ||
548 | |||
549 | while (readl(port->membase + UART_FR) & FR_BUSY); | ||
550 | writel(cr_save, port->membase + UART_CR); | ||
551 | } | ||
552 | |||
553 | static void __init | ||
554 | netx_console_get_options(struct uart_port *port, int *baud, | ||
555 | int *parity, int *bits, int *flow) | ||
556 | { | ||
557 | unsigned char line_cr; | ||
558 | |||
559 | *baud = (readl(port->membase + UART_BAUDDIV_MSB) << 8) | | ||
560 | readl(port->membase + UART_BAUDDIV_LSB); | ||
561 | *baud *= 1000; | ||
562 | *baud /= 4096; | ||
563 | *baud *= 1000; | ||
564 | *baud /= 256; | ||
565 | *baud *= 100; | ||
566 | |||
567 | line_cr = readl(port->membase + UART_LINE_CR); | ||
568 | *parity = 'n'; | ||
569 | if (line_cr & LINE_CR_PEN) { | ||
570 | if (line_cr & LINE_CR_EPS) | ||
571 | *parity = 'e'; | ||
572 | else | ||
573 | *parity = 'o'; | ||
574 | } | ||
575 | |||
576 | switch (line_cr & LINE_CR_BITS_MASK) { | ||
577 | case LINE_CR_8BIT: | ||
578 | *bits = 8; | ||
579 | break; | ||
580 | case LINE_CR_7BIT: | ||
581 | *bits = 7; | ||
582 | break; | ||
583 | case LINE_CR_6BIT: | ||
584 | *bits = 6; | ||
585 | break; | ||
586 | case LINE_CR_5BIT: | ||
587 | *bits = 5; | ||
588 | break; | ||
589 | } | ||
590 | |||
591 | if (readl(port->membase + UART_RTS_CR) & RTS_CR_AUTO) | ||
592 | *flow = 'r'; | ||
593 | } | ||
594 | |||
595 | static int __init | ||
596 | netx_console_setup(struct console *co, char *options) | ||
597 | { | ||
598 | struct netx_port *sport; | ||
599 | int baud = 9600; | ||
600 | int bits = 8; | ||
601 | int parity = 'n'; | ||
602 | int flow = 'n'; | ||
603 | |||
604 | /* | ||
605 | * Check whether an invalid uart number has been specified, and | ||
606 | * if so, search for the first available port that does have | ||
607 | * console support. | ||
608 | */ | ||
609 | if (co->index == -1 || co->index >= ARRAY_SIZE(netx_ports)) | ||
610 | co->index = 0; | ||
611 | sport = &netx_ports[co->index]; | ||
612 | |||
613 | if (options) { | ||
614 | uart_parse_options(options, &baud, &parity, &bits, &flow); | ||
615 | } else { | ||
616 | /* if the UART is enabled, assume it has been correctly setup | ||
617 | * by the bootloader and get the options | ||
618 | */ | ||
619 | if (readl(sport->port.membase + UART_CR) & CR_UART_EN) { | ||
620 | netx_console_get_options(&sport->port, &baud, | ||
621 | &parity, &bits, &flow); | ||
622 | } | ||
623 | |||
624 | } | ||
625 | |||
626 | return uart_set_options(&sport->port, co, baud, parity, bits, flow); | ||
627 | } | ||
628 | |||
629 | static struct uart_driver netx_reg; | ||
630 | static struct console netx_console = { | ||
631 | .name = "ttyNX", | ||
632 | .write = netx_console_write, | ||
633 | .device = uart_console_device, | ||
634 | .setup = netx_console_setup, | ||
635 | .flags = CON_PRINTBUFFER, | ||
636 | .index = -1, | ||
637 | .data = &netx_reg, | ||
638 | }; | ||
639 | |||
640 | static int __init netx_console_init(void) | ||
641 | { | ||
642 | register_console(&netx_console); | ||
643 | return 0; | ||
644 | } | ||
645 | console_initcall(netx_console_init); | ||
646 | |||
647 | #define NETX_CONSOLE &netx_console | ||
648 | #else | ||
649 | #define NETX_CONSOLE NULL | ||
650 | #endif | ||
651 | |||
652 | static struct uart_driver netx_reg = { | ||
653 | .owner = THIS_MODULE, | ||
654 | .driver_name = DRIVER_NAME, | ||
655 | .dev_name = "ttyNX", | ||
656 | .major = SERIAL_NX_MAJOR, | ||
657 | .minor = MINOR_START, | ||
658 | .nr = ARRAY_SIZE(netx_ports), | ||
659 | .cons = NETX_CONSOLE, | ||
660 | }; | ||
661 | |||
662 | static int serial_netx_suspend(struct platform_device *pdev, pm_message_t state) | ||
663 | { | ||
664 | struct netx_port *sport = platform_get_drvdata(pdev); | ||
665 | |||
666 | if (sport) | ||
667 | uart_suspend_port(&netx_reg, &sport->port); | ||
668 | |||
669 | return 0; | ||
670 | } | ||
671 | |||
672 | static int serial_netx_resume(struct platform_device *pdev) | ||
673 | { | ||
674 | struct netx_port *sport = platform_get_drvdata(pdev); | ||
675 | |||
676 | if (sport) | ||
677 | uart_resume_port(&netx_reg, &sport->port); | ||
678 | |||
679 | return 0; | ||
680 | } | ||
681 | |||
682 | static int serial_netx_probe(struct platform_device *pdev) | ||
683 | { | ||
684 | struct uart_port *port = &netx_ports[pdev->id].port; | ||
685 | |||
686 | dev_info(&pdev->dev, "initialising\n"); | ||
687 | |||
688 | port->dev = &pdev->dev; | ||
689 | |||
690 | writel(1, port->membase + UART_RXFIFO_IRQLEVEL); | ||
691 | uart_add_one_port(&netx_reg, &netx_ports[pdev->id].port); | ||
692 | platform_set_drvdata(pdev, &netx_ports[pdev->id]); | ||
693 | |||
694 | return 0; | ||
695 | } | ||
696 | |||
697 | static int serial_netx_remove(struct platform_device *pdev) | ||
698 | { | ||
699 | struct netx_port *sport = platform_get_drvdata(pdev); | ||
700 | |||
701 | platform_set_drvdata(pdev, NULL); | ||
702 | |||
703 | if (sport) | ||
704 | uart_remove_one_port(&netx_reg, &sport->port); | ||
705 | |||
706 | return 0; | ||
707 | } | ||
708 | |||
709 | static struct platform_driver serial_netx_driver = { | ||
710 | .probe = serial_netx_probe, | ||
711 | .remove = serial_netx_remove, | ||
712 | |||
713 | .suspend = serial_netx_suspend, | ||
714 | .resume = serial_netx_resume, | ||
715 | |||
716 | .driver = { | ||
717 | .name = DRIVER_NAME, | ||
718 | }, | ||
719 | }; | ||
720 | |||
721 | static int __init netx_serial_init(void) | ||
722 | { | ||
723 | int ret; | ||
724 | |||
725 | printk(KERN_INFO "Serial: NetX driver\n"); | ||
726 | |||
727 | ret = uart_register_driver(&netx_reg); | ||
728 | if (ret) | ||
729 | return ret; | ||
730 | |||
731 | ret = platform_driver_register(&serial_netx_driver); | ||
732 | if (ret != 0) | ||
733 | uart_unregister_driver(&netx_reg); | ||
734 | |||
735 | return 0; | ||
736 | } | ||
737 | |||
738 | static void __exit netx_serial_exit(void) | ||
739 | { | ||
740 | platform_driver_unregister(&serial_netx_driver); | ||
741 | uart_unregister_driver(&netx_reg); | ||
742 | } | ||
743 | |||
744 | module_init(netx_serial_init); | ||
745 | module_exit(netx_serial_exit); | ||
746 | |||
747 | MODULE_AUTHOR("Sascha Hauer"); | ||
748 | MODULE_DESCRIPTION("NetX serial port driver"); | ||
749 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c index 989e4d49e5bb..7f939d066a5a 100644 --- a/drivers/video/console/mdacon.c +++ b/drivers/video/console/mdacon.c | |||
@@ -313,8 +313,8 @@ static const char __init *mdacon_startup(void) | |||
313 | mda_num_columns = 80; | 313 | mda_num_columns = 80; |
314 | mda_num_lines = 25; | 314 | mda_num_lines = 25; |
315 | 315 | ||
316 | mda_vram_base = VGA_MAP_MEM(0xb0000); | ||
317 | mda_vram_len = 0x01000; | 316 | mda_vram_len = 0x01000; |
317 | mda_vram_base = VGA_MAP_MEM(0xb0000, mda_vram_len); | ||
318 | 318 | ||
319 | mda_index_port = 0x3b4; | 319 | mda_index_port = 0x3b4; |
320 | mda_value_port = 0x3b5; | 320 | mda_value_port = 0x3b5; |
diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index d5a04b68c4d4..e64d42e2449e 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c | |||
@@ -391,7 +391,7 @@ static const char __init *vgacon_startup(void) | |||
391 | static struct resource ega_console_resource = | 391 | static struct resource ega_console_resource = |
392 | { "ega", 0x3B0, 0x3BF }; | 392 | { "ega", 0x3B0, 0x3BF }; |
393 | vga_video_type = VIDEO_TYPE_EGAM; | 393 | vga_video_type = VIDEO_TYPE_EGAM; |
394 | vga_vram_end = 0xb8000; | 394 | vga_vram_size = 0x8000; |
395 | display_desc = "EGA+"; | 395 | display_desc = "EGA+"; |
396 | request_resource(&ioport_resource, | 396 | request_resource(&ioport_resource, |
397 | &ega_console_resource); | 397 | &ega_console_resource); |
@@ -401,7 +401,7 @@ static const char __init *vgacon_startup(void) | |||
401 | static struct resource mda2_console_resource = | 401 | static struct resource mda2_console_resource = |
402 | { "mda", 0x3BF, 0x3BF }; | 402 | { "mda", 0x3BF, 0x3BF }; |
403 | vga_video_type = VIDEO_TYPE_MDA; | 403 | vga_video_type = VIDEO_TYPE_MDA; |
404 | vga_vram_end = 0xb2000; | 404 | vga_vram_size = 0x2000; |
405 | display_desc = "*MDA"; | 405 | display_desc = "*MDA"; |
406 | request_resource(&ioport_resource, | 406 | request_resource(&ioport_resource, |
407 | &mda1_console_resource); | 407 | &mda1_console_resource); |
@@ -418,7 +418,7 @@ static const char __init *vgacon_startup(void) | |||
418 | if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10) { | 418 | if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10) { |
419 | int i; | 419 | int i; |
420 | 420 | ||
421 | vga_vram_end = 0xc0000; | 421 | vga_vram_size = 0x8000; |
422 | 422 | ||
423 | if (!ORIG_VIDEO_ISVGA) { | 423 | if (!ORIG_VIDEO_ISVGA) { |
424 | static struct resource ega_console_resource | 424 | static struct resource ega_console_resource |
@@ -443,7 +443,7 @@ static const char __init *vgacon_startup(void) | |||
443 | * and COE=1 isn't necessarily a good idea) | 443 | * and COE=1 isn't necessarily a good idea) |
444 | */ | 444 | */ |
445 | vga_vram_base = 0xa0000; | 445 | vga_vram_base = 0xa0000; |
446 | vga_vram_end = 0xb0000; | 446 | vga_vram_size = 0x10000; |
447 | outb_p(6, VGA_GFX_I); | 447 | outb_p(6, VGA_GFX_I); |
448 | outb_p(6, VGA_GFX_D); | 448 | outb_p(6, VGA_GFX_D); |
449 | #endif | 449 | #endif |
@@ -475,7 +475,7 @@ static const char __init *vgacon_startup(void) | |||
475 | static struct resource cga_console_resource = | 475 | static struct resource cga_console_resource = |
476 | { "cga", 0x3D4, 0x3D5 }; | 476 | { "cga", 0x3D4, 0x3D5 }; |
477 | vga_video_type = VIDEO_TYPE_CGA; | 477 | vga_video_type = VIDEO_TYPE_CGA; |
478 | vga_vram_end = 0xba000; | 478 | vga_vram_size = 0x2000; |
479 | display_desc = "*CGA"; | 479 | display_desc = "*CGA"; |
480 | request_resource(&ioport_resource, | 480 | request_resource(&ioport_resource, |
481 | &cga_console_resource); | 481 | &cga_console_resource); |
@@ -483,9 +483,8 @@ static const char __init *vgacon_startup(void) | |||
483 | } | 483 | } |
484 | } | 484 | } |
485 | 485 | ||
486 | vga_vram_base = VGA_MAP_MEM(vga_vram_base); | 486 | vga_vram_base = VGA_MAP_MEM(vga_vram_base, vga_vram_size); |
487 | vga_vram_end = VGA_MAP_MEM(vga_vram_end); | 487 | vga_vram_end = vga_vram_base + vga_vram_size; |
488 | vga_vram_size = vga_vram_end - vga_vram_base; | ||
489 | 488 | ||
490 | /* | 489 | /* |
491 | * Find out if there is a graphics card present. | 490 | * Find out if there is a graphics card present. |
@@ -1020,14 +1019,14 @@ static int vgacon_do_font_op(struct vgastate *state,char *arg,int set,int ch512) | |||
1020 | char *charmap; | 1019 | char *charmap; |
1021 | 1020 | ||
1022 | if (vga_video_type != VIDEO_TYPE_EGAM) { | 1021 | if (vga_video_type != VIDEO_TYPE_EGAM) { |
1023 | charmap = (char *) VGA_MAP_MEM(colourmap); | 1022 | charmap = (char *) VGA_MAP_MEM(colourmap, 0); |
1024 | beg = 0x0e; | 1023 | beg = 0x0e; |
1025 | #ifdef VGA_CAN_DO_64KB | 1024 | #ifdef VGA_CAN_DO_64KB |
1026 | if (vga_video_type == VIDEO_TYPE_VGAC) | 1025 | if (vga_video_type == VIDEO_TYPE_VGAC) |
1027 | beg = 0x06; | 1026 | beg = 0x06; |
1028 | #endif | 1027 | #endif |
1029 | } else { | 1028 | } else { |
1030 | charmap = (char *) VGA_MAP_MEM(blackwmap); | 1029 | charmap = (char *) VGA_MAP_MEM(blackwmap, 0); |
1031 | beg = 0x0a; | 1030 | beg = 0x0a; |
1032 | } | 1031 | } |
1033 | 1032 | ||
diff --git a/drivers/video/vga16fb.c b/drivers/video/vga16fb.c index f3f16fd9f231..4fd2a272e03d 100644 --- a/drivers/video/vga16fb.c +++ b/drivers/video/vga16fb.c | |||
@@ -1351,7 +1351,7 @@ static int __init vga16fb_probe(struct device *device) | |||
1351 | } | 1351 | } |
1352 | 1352 | ||
1353 | /* XXX share VGA_FB_PHYS and I/O region with vgacon and others */ | 1353 | /* XXX share VGA_FB_PHYS and I/O region with vgacon and others */ |
1354 | info->screen_base = (void __iomem *)VGA_MAP_MEM(VGA_FB_PHYS); | 1354 | info->screen_base = (void __iomem *)VGA_MAP_MEM(VGA_FB_PHYS, 0); |
1355 | 1355 | ||
1356 | if (!info->screen_base) { | 1356 | if (!info->screen_base) { |
1357 | printk(KERN_ERR "vga16fb: unable to map device\n"); | 1357 | printk(KERN_ERR "vga16fb: unable to map device\n"); |
diff --git a/drivers/w1/Kconfig b/drivers/w1/Kconfig index 5e61ed59a41e..f2d9a08e89ae 100644 --- a/drivers/w1/Kconfig +++ b/drivers/w1/Kconfig | |||
@@ -3,7 +3,7 @@ menu "Dallas's 1-wire bus" | |||
3 | config W1 | 3 | config W1 |
4 | tristate "Dallas's 1-wire support" | 4 | tristate "Dallas's 1-wire support" |
5 | ---help--- | 5 | ---help--- |
6 | Dallas's 1-wire bus is useful to connect slow 1-pin devices | 6 | Dallas' 1-wire bus is useful to connect slow 1-pin devices |
7 | such as iButtons and thermal sensors. | 7 | such as iButtons and thermal sensors. |
8 | 8 | ||
9 | If you want W1 support, you should say Y here. | 9 | If you want W1 support, you should say Y here. |
@@ -11,6 +11,18 @@ config W1 | |||
11 | This W1 support can also be built as a module. If so, the module | 11 | This W1 support can also be built as a module. If so, the module |
12 | will be called wire.ko. | 12 | will be called wire.ko. |
13 | 13 | ||
14 | config W1_CON | ||
15 | depends on CONNECTOR && W1 | ||
16 | bool "Userspace communication over connector" | ||
17 | default y | ||
18 | --- help --- | ||
19 | This allows to communicate with userspace using connector [Documentation/connector]. | ||
20 | There are three types of messages between w1 core and userspace: | ||
21 | 1. Events. They are generated each time new master or slave device found | ||
22 | either due to automatic or requested search. | ||
23 | 2. Userspace commands. Includes read/write and search/alarm search comamnds. | ||
24 | 3. Replies to userspace commands. | ||
25 | |||
14 | source drivers/w1/masters/Kconfig | 26 | source drivers/w1/masters/Kconfig |
15 | source drivers/w1/slaves/Kconfig | 27 | source drivers/w1/slaves/Kconfig |
16 | 28 | ||
diff --git a/drivers/w1/Makefile b/drivers/w1/Makefile index 0c2aa22d8c04..93845a2c7c21 100644 --- a/drivers/w1/Makefile +++ b/drivers/w1/Makefile | |||
@@ -2,10 +2,6 @@ | |||
2 | # Makefile for the Dallas's 1-wire bus. | 2 | # Makefile for the Dallas's 1-wire bus. |
3 | # | 3 | # |
4 | 4 | ||
5 | ifneq ($(CONFIG_NET), y) | ||
6 | EXTRA_CFLAGS += -DNETLINK_DISABLED | ||
7 | endif | ||
8 | |||
9 | ifeq ($(CONFIG_W1_DS2433_CRC), y) | 5 | ifeq ($(CONFIG_W1_DS2433_CRC), y) |
10 | EXTRA_CFLAGS += -DCONFIG_W1_F23_CRC | 6 | EXTRA_CFLAGS += -DCONFIG_W1_F23_CRC |
11 | endif | 7 | endif |
diff --git a/drivers/w1/masters/Kconfig b/drivers/w1/masters/Kconfig index c6bad4dbdc64..2fb425536eae 100644 --- a/drivers/w1/masters/Kconfig +++ b/drivers/w1/masters/Kconfig | |||
@@ -15,24 +15,15 @@ config W1_MASTER_MATROX | |||
15 | This support is also available as a module. If so, the module | 15 | This support is also available as a module. If so, the module |
16 | will be called matrox_w1.ko. | 16 | will be called matrox_w1.ko. |
17 | 17 | ||
18 | config W1_MASTER_DS9490 | 18 | config W1_MASTER_DS2490 |
19 | tristate "DS9490R transport layer driver" | 19 | tristate "DS2490 USB <-> W1 transport layer for 1-wire" |
20 | depends on W1 && USB | 20 | depends on W1 && USB |
21 | help | 21 | help |
22 | Say Y here if you want to have a driver for DS9490R UWB <-> W1 bridge. | 22 | Say Y here if you want to have a driver for DS2490 based USB <-> W1 bridges, |
23 | 23 | for example DS9490*. | |
24 | This support is also available as a module. If so, the module | 24 | |
25 | will be called ds9490r.ko. | 25 | This support is also available as a module. If so, the module |
26 | 26 | will be called ds2490.ko. | |
27 | config W1_MASTER_DS9490_BRIDGE | ||
28 | tristate "DS9490R USB <-> W1 transport layer for 1-wire" | ||
29 | depends on W1_MASTER_DS9490 | ||
30 | help | ||
31 | Say Y here if you want to communicate with your 1-wire devices | ||
32 | using DS9490R USB bridge. | ||
33 | |||
34 | This support is also available as a module. If so, the module | ||
35 | will be called ds_w1_bridge.ko. | ||
36 | 27 | ||
37 | config W1_MASTER_DS2482 | 28 | config W1_MASTER_DS2482 |
38 | tristate "Maxim DS2482 I2C to 1-Wire bridge" | 29 | tristate "Maxim DS2482 I2C to 1-Wire bridge" |
diff --git a/drivers/w1/masters/Makefile b/drivers/w1/masters/Makefile index 1f3c8b983dc1..4cee256a8134 100644 --- a/drivers/w1/masters/Makefile +++ b/drivers/w1/masters/Makefile | |||
@@ -3,11 +3,6 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | obj-$(CONFIG_W1_MASTER_MATROX) += matrox_w1.o | 5 | obj-$(CONFIG_W1_MASTER_MATROX) += matrox_w1.o |
6 | 6 | obj-$(CONFIG_W1_MASTER_DS2490) += ds2490.o | |
7 | obj-$(CONFIG_W1_MASTER_DS9490) += ds9490r.o | ||
8 | ds9490r-objs := dscore.o | ||
9 | |||
10 | obj-$(CONFIG_W1_MASTER_DS9490_BRIDGE) += ds_w1_bridge.o | ||
11 | |||
12 | obj-$(CONFIG_W1_MASTER_DS2482) += ds2482.o | 7 | obj-$(CONFIG_W1_MASTER_DS2482) += ds2482.o |
13 | 8 | ||
diff --git a/drivers/w1/masters/ds2482.c b/drivers/w1/masters/ds2482.c index d1cacd23576b..af492cc48db2 100644 --- a/drivers/w1/masters/ds2482.c +++ b/drivers/w1/masters/ds2482.c | |||
@@ -125,7 +125,7 @@ struct ds2482_w1_chan { | |||
125 | 125 | ||
126 | struct ds2482_data { | 126 | struct ds2482_data { |
127 | struct i2c_client client; | 127 | struct i2c_client client; |
128 | struct semaphore access_lock; | 128 | struct mutex access_lock; |
129 | 129 | ||
130 | /* 1-wire interface(s) */ | 130 | /* 1-wire interface(s) */ |
131 | int w1_count; /* 1 or 8 */ | 131 | int w1_count; /* 1 or 8 */ |
@@ -265,7 +265,7 @@ static u8 ds2482_w1_touch_bit(void *data, u8 bit) | |||
265 | struct ds2482_data *pdev = pchan->pdev; | 265 | struct ds2482_data *pdev = pchan->pdev; |
266 | int status = -1; | 266 | int status = -1; |
267 | 267 | ||
268 | down(&pdev->access_lock); | 268 | mutex_lock(&pdev->access_lock); |
269 | 269 | ||
270 | /* Select the channel */ | 270 | /* Select the channel */ |
271 | ds2482_wait_1wire_idle(pdev); | 271 | ds2482_wait_1wire_idle(pdev); |
@@ -277,7 +277,7 @@ static u8 ds2482_w1_touch_bit(void *data, u8 bit) | |||
277 | bit ? 0xFF : 0)) | 277 | bit ? 0xFF : 0)) |
278 | status = ds2482_wait_1wire_idle(pdev); | 278 | status = ds2482_wait_1wire_idle(pdev); |
279 | 279 | ||
280 | up(&pdev->access_lock); | 280 | mutex_unlock(&pdev->access_lock); |
281 | 281 | ||
282 | return (status & DS2482_REG_STS_SBR) ? 1 : 0; | 282 | return (status & DS2482_REG_STS_SBR) ? 1 : 0; |
283 | } | 283 | } |
@@ -297,7 +297,7 @@ static u8 ds2482_w1_triplet(void *data, u8 dbit) | |||
297 | struct ds2482_data *pdev = pchan->pdev; | 297 | struct ds2482_data *pdev = pchan->pdev; |
298 | int status = (3 << 5); | 298 | int status = (3 << 5); |
299 | 299 | ||
300 | down(&pdev->access_lock); | 300 | mutex_lock(&pdev->access_lock); |
301 | 301 | ||
302 | /* Select the channel */ | 302 | /* Select the channel */ |
303 | ds2482_wait_1wire_idle(pdev); | 303 | ds2482_wait_1wire_idle(pdev); |
@@ -309,7 +309,7 @@ static u8 ds2482_w1_triplet(void *data, u8 dbit) | |||
309 | dbit ? 0xFF : 0)) | 309 | dbit ? 0xFF : 0)) |
310 | status = ds2482_wait_1wire_idle(pdev); | 310 | status = ds2482_wait_1wire_idle(pdev); |
311 | 311 | ||
312 | up(&pdev->access_lock); | 312 | mutex_unlock(&pdev->access_lock); |
313 | 313 | ||
314 | /* Decode the status */ | 314 | /* Decode the status */ |
315 | return (status >> 5); | 315 | return (status >> 5); |
@@ -326,7 +326,7 @@ static void ds2482_w1_write_byte(void *data, u8 byte) | |||
326 | struct ds2482_w1_chan *pchan = data; | 326 | struct ds2482_w1_chan *pchan = data; |
327 | struct ds2482_data *pdev = pchan->pdev; | 327 | struct ds2482_data *pdev = pchan->pdev; |
328 | 328 | ||
329 | down(&pdev->access_lock); | 329 | mutex_lock(&pdev->access_lock); |
330 | 330 | ||
331 | /* Select the channel */ | 331 | /* Select the channel */ |
332 | ds2482_wait_1wire_idle(pdev); | 332 | ds2482_wait_1wire_idle(pdev); |
@@ -336,7 +336,7 @@ static void ds2482_w1_write_byte(void *data, u8 byte) | |||
336 | /* Send the write byte command */ | 336 | /* Send the write byte command */ |
337 | ds2482_send_cmd_data(pdev, DS2482_CMD_1WIRE_WRITE_BYTE, byte); | 337 | ds2482_send_cmd_data(pdev, DS2482_CMD_1WIRE_WRITE_BYTE, byte); |
338 | 338 | ||
339 | up(&pdev->access_lock); | 339 | mutex_unlock(&pdev->access_lock); |
340 | } | 340 | } |
341 | 341 | ||
342 | /** | 342 | /** |
@@ -351,7 +351,7 @@ static u8 ds2482_w1_read_byte(void *data) | |||
351 | struct ds2482_data *pdev = pchan->pdev; | 351 | struct ds2482_data *pdev = pchan->pdev; |
352 | int result; | 352 | int result; |
353 | 353 | ||
354 | down(&pdev->access_lock); | 354 | mutex_lock(&pdev->access_lock); |
355 | 355 | ||
356 | /* Select the channel */ | 356 | /* Select the channel */ |
357 | ds2482_wait_1wire_idle(pdev); | 357 | ds2482_wait_1wire_idle(pdev); |
@@ -370,7 +370,7 @@ static u8 ds2482_w1_read_byte(void *data) | |||
370 | /* Read the data byte */ | 370 | /* Read the data byte */ |
371 | result = i2c_smbus_read_byte(&pdev->client); | 371 | result = i2c_smbus_read_byte(&pdev->client); |
372 | 372 | ||
373 | up(&pdev->access_lock); | 373 | mutex_unlock(&pdev->access_lock); |
374 | 374 | ||
375 | return result; | 375 | return result; |
376 | } | 376 | } |
@@ -389,7 +389,7 @@ static u8 ds2482_w1_reset_bus(void *data) | |||
389 | int err; | 389 | int err; |
390 | u8 retval = 1; | 390 | u8 retval = 1; |
391 | 391 | ||
392 | down(&pdev->access_lock); | 392 | mutex_lock(&pdev->access_lock); |
393 | 393 | ||
394 | /* Select the channel */ | 394 | /* Select the channel */ |
395 | ds2482_wait_1wire_idle(pdev); | 395 | ds2482_wait_1wire_idle(pdev); |
@@ -409,7 +409,7 @@ static u8 ds2482_w1_reset_bus(void *data) | |||
409 | 0xF0); | 409 | 0xF0); |
410 | } | 410 | } |
411 | 411 | ||
412 | up(&pdev->access_lock); | 412 | mutex_unlock(&pdev->access_lock); |
413 | 413 | ||
414 | return retval; | 414 | return retval; |
415 | } | 415 | } |
@@ -482,7 +482,7 @@ static int ds2482_detect(struct i2c_adapter *adapter, int address, int kind) | |||
482 | snprintf(new_client->name, sizeof(new_client->name), "ds2482-%d00", | 482 | snprintf(new_client->name, sizeof(new_client->name), "ds2482-%d00", |
483 | data->w1_count); | 483 | data->w1_count); |
484 | 484 | ||
485 | init_MUTEX(&data->access_lock); | 485 | mutex_init(&data->access_lock); |
486 | 486 | ||
487 | /* Tell the I2C layer a new client has arrived */ | 487 | /* Tell the I2C layer a new client has arrived */ |
488 | if ((err = i2c_attach_client(new_client))) | 488 | if ((err = i2c_attach_client(new_client))) |
diff --git a/drivers/w1/masters/dscore.c b/drivers/w1/masters/ds2490.c index 2cf7776a7080..299e274d241a 100644 --- a/drivers/w1/masters/dscore.c +++ b/drivers/w1/masters/ds2490.c | |||
@@ -24,7 +24,136 @@ | |||
24 | #include <linux/mod_devicetable.h> | 24 | #include <linux/mod_devicetable.h> |
25 | #include <linux/usb.h> | 25 | #include <linux/usb.h> |
26 | 26 | ||
27 | #include "dscore.h" | 27 | #include "../w1_int.h" |
28 | #include "../w1.h" | ||
29 | |||
30 | /* COMMAND TYPE CODES */ | ||
31 | #define CONTROL_CMD 0x00 | ||
32 | #define COMM_CMD 0x01 | ||
33 | #define MODE_CMD 0x02 | ||
34 | |||
35 | /* CONTROL COMMAND CODES */ | ||
36 | #define CTL_RESET_DEVICE 0x0000 | ||
37 | #define CTL_START_EXE 0x0001 | ||
38 | #define CTL_RESUME_EXE 0x0002 | ||
39 | #define CTL_HALT_EXE_IDLE 0x0003 | ||
40 | #define CTL_HALT_EXE_DONE 0x0004 | ||
41 | #define CTL_FLUSH_COMM_CMDS 0x0007 | ||
42 | #define CTL_FLUSH_RCV_BUFFER 0x0008 | ||
43 | #define CTL_FLUSH_XMT_BUFFER 0x0009 | ||
44 | #define CTL_GET_COMM_CMDS 0x000A | ||
45 | |||
46 | /* MODE COMMAND CODES */ | ||
47 | #define MOD_PULSE_EN 0x0000 | ||
48 | #define MOD_SPEED_CHANGE_EN 0x0001 | ||
49 | #define MOD_1WIRE_SPEED 0x0002 | ||
50 | #define MOD_STRONG_PU_DURATION 0x0003 | ||
51 | #define MOD_PULLDOWN_SLEWRATE 0x0004 | ||
52 | #define MOD_PROG_PULSE_DURATION 0x0005 | ||
53 | #define MOD_WRITE1_LOWTIME 0x0006 | ||
54 | #define MOD_DSOW0_TREC 0x0007 | ||
55 | |||
56 | /* COMMUNICATION COMMAND CODES */ | ||
57 | #define COMM_ERROR_ESCAPE 0x0601 | ||
58 | #define COMM_SET_DURATION 0x0012 | ||
59 | #define COMM_BIT_IO 0x0020 | ||
60 | #define COMM_PULSE 0x0030 | ||
61 | #define COMM_1_WIRE_RESET 0x0042 | ||
62 | #define COMM_BYTE_IO 0x0052 | ||
63 | #define COMM_MATCH_ACCESS 0x0064 | ||
64 | #define COMM_BLOCK_IO 0x0074 | ||
65 | #define COMM_READ_STRAIGHT 0x0080 | ||
66 | #define COMM_DO_RELEASE 0x6092 | ||
67 | #define COMM_SET_PATH 0x00A2 | ||
68 | #define COMM_WRITE_SRAM_PAGE 0x00B2 | ||
69 | #define COMM_WRITE_EPROM 0x00C4 | ||
70 | #define COMM_READ_CRC_PROT_PAGE 0x00D4 | ||
71 | #define COMM_READ_REDIRECT_PAGE_CRC 0x21E4 | ||
72 | #define COMM_SEARCH_ACCESS 0x00F4 | ||
73 | |||
74 | /* Communication command bits */ | ||
75 | #define COMM_TYPE 0x0008 | ||
76 | #define COMM_SE 0x0008 | ||
77 | #define COMM_D 0x0008 | ||
78 | #define COMM_Z 0x0008 | ||
79 | #define COMM_CH 0x0008 | ||
80 | #define COMM_SM 0x0008 | ||
81 | #define COMM_R 0x0008 | ||
82 | #define COMM_IM 0x0001 | ||
83 | |||
84 | #define COMM_PS 0x4000 | ||
85 | #define COMM_PST 0x4000 | ||
86 | #define COMM_CIB 0x4000 | ||
87 | #define COMM_RTS 0x4000 | ||
88 | #define COMM_DT 0x2000 | ||
89 | #define COMM_SPU 0x1000 | ||
90 | #define COMM_F 0x0800 | ||
91 | #define COMM_NTP 0x0400 | ||
92 | #define COMM_ICP 0x0200 | ||
93 | #define COMM_RST 0x0100 | ||
94 | |||
95 | #define PULSE_PROG 0x01 | ||
96 | #define PULSE_SPUE 0x02 | ||
97 | |||
98 | #define BRANCH_MAIN 0xCC | ||
99 | #define BRANCH_AUX 0x33 | ||
100 | |||
101 | /* | ||
102 | * Duration of the strong pull-up pulse in milliseconds. | ||
103 | */ | ||
104 | #define PULLUP_PULSE_DURATION 750 | ||
105 | |||
106 | /* Status flags */ | ||
107 | #define ST_SPUA 0x01 /* Strong Pull-up is active */ | ||
108 | #define ST_PRGA 0x02 /* 12V programming pulse is being generated */ | ||
109 | #define ST_12VP 0x04 /* external 12V programming voltage is present */ | ||
110 | #define ST_PMOD 0x08 /* DS2490 powered from USB and external sources */ | ||
111 | #define ST_HALT 0x10 /* DS2490 is currently halted */ | ||
112 | #define ST_IDLE 0x20 /* DS2490 is currently idle */ | ||
113 | #define ST_EPOF 0x80 | ||
114 | |||
115 | #define SPEED_NORMAL 0x00 | ||
116 | #define SPEED_FLEXIBLE 0x01 | ||
117 | #define SPEED_OVERDRIVE 0x02 | ||
118 | |||
119 | #define NUM_EP 4 | ||
120 | #define EP_CONTROL 0 | ||
121 | #define EP_STATUS 1 | ||
122 | #define EP_DATA_OUT 2 | ||
123 | #define EP_DATA_IN 3 | ||
124 | |||
125 | struct ds_device | ||
126 | { | ||
127 | struct list_head ds_entry; | ||
128 | |||
129 | struct usb_device *udev; | ||
130 | struct usb_interface *intf; | ||
131 | |||
132 | int ep[NUM_EP]; | ||
133 | |||
134 | struct w1_bus_master master; | ||
135 | }; | ||
136 | |||
137 | struct ds_status | ||
138 | { | ||
139 | u8 enable; | ||
140 | u8 speed; | ||
141 | u8 pullup_dur; | ||
142 | u8 ppuls_dur; | ||
143 | u8 pulldown_slew; | ||
144 | u8 write1_time; | ||
145 | u8 write0_time; | ||
146 | u8 reserved0; | ||
147 | u8 status; | ||
148 | u8 command0; | ||
149 | u8 command1; | ||
150 | u8 command_buffer_status; | ||
151 | u8 data_out_buffer_status; | ||
152 | u8 data_in_buffer_status; | ||
153 | u8 reserved1; | ||
154 | u8 reserved2; | ||
155 | |||
156 | }; | ||
28 | 157 | ||
29 | static struct usb_device_id ds_id_table [] = { | 158 | static struct usb_device_id ds_id_table [] = { |
30 | { USB_DEVICE(0x04fa, 0x2490) }, | 159 | { USB_DEVICE(0x04fa, 0x2490) }, |
@@ -35,21 +164,12 @@ MODULE_DEVICE_TABLE(usb, ds_id_table); | |||
35 | static int ds_probe(struct usb_interface *, const struct usb_device_id *); | 164 | static int ds_probe(struct usb_interface *, const struct usb_device_id *); |
36 | static void ds_disconnect(struct usb_interface *); | 165 | static void ds_disconnect(struct usb_interface *); |
37 | 166 | ||
38 | int ds_touch_bit(struct ds_device *, u8, u8 *); | ||
39 | int ds_read_byte(struct ds_device *, u8 *); | ||
40 | int ds_read_bit(struct ds_device *, u8 *); | ||
41 | int ds_write_byte(struct ds_device *, u8); | ||
42 | int ds_write_bit(struct ds_device *, u8); | ||
43 | static int ds_start_pulse(struct ds_device *, int); | ||
44 | int ds_reset(struct ds_device *, struct ds_status *); | ||
45 | struct ds_device * ds_get_device(void); | ||
46 | void ds_put_device(struct ds_device *); | ||
47 | |||
48 | static inline void ds_dump_status(unsigned char *, unsigned char *, int); | 167 | static inline void ds_dump_status(unsigned char *, unsigned char *, int); |
49 | static int ds_send_control(struct ds_device *, u16, u16); | 168 | static int ds_send_control(struct ds_device *, u16, u16); |
50 | static int ds_send_control_mode(struct ds_device *, u16, u16); | ||
51 | static int ds_send_control_cmd(struct ds_device *, u16, u16); | 169 | static int ds_send_control_cmd(struct ds_device *, u16, u16); |
52 | 170 | ||
171 | static LIST_HEAD(ds_devices); | ||
172 | static DEFINE_MUTEX(ds_mutex); | ||
53 | 173 | ||
54 | static struct usb_driver ds_driver = { | 174 | static struct usb_driver ds_driver = { |
55 | .name = "DS9490R", | 175 | .name = "DS9490R", |
@@ -58,20 +178,6 @@ static struct usb_driver ds_driver = { | |||
58 | .id_table = ds_id_table, | 178 | .id_table = ds_id_table, |
59 | }; | 179 | }; |
60 | 180 | ||
61 | static struct ds_device *ds_dev; | ||
62 | |||
63 | struct ds_device * ds_get_device(void) | ||
64 | { | ||
65 | if (ds_dev) | ||
66 | atomic_inc(&ds_dev->refcnt); | ||
67 | return ds_dev; | ||
68 | } | ||
69 | |||
70 | void ds_put_device(struct ds_device *dev) | ||
71 | { | ||
72 | atomic_dec(&dev->refcnt); | ||
73 | } | ||
74 | |||
75 | static int ds_send_control_cmd(struct ds_device *dev, u16 value, u16 index) | 181 | static int ds_send_control_cmd(struct ds_device *dev, u16 value, u16 index) |
76 | { | 182 | { |
77 | int err; | 183 | int err; |
@@ -86,7 +192,7 @@ static int ds_send_control_cmd(struct ds_device *dev, u16 value, u16 index) | |||
86 | 192 | ||
87 | return err; | 193 | return err; |
88 | } | 194 | } |
89 | 195 | #if 0 | |
90 | static int ds_send_control_mode(struct ds_device *dev, u16 value, u16 index) | 196 | static int ds_send_control_mode(struct ds_device *dev, u16 value, u16 index) |
91 | { | 197 | { |
92 | int err; | 198 | int err; |
@@ -101,7 +207,7 @@ static int ds_send_control_mode(struct ds_device *dev, u16 value, u16 index) | |||
101 | 207 | ||
102 | return err; | 208 | return err; |
103 | } | 209 | } |
104 | 210 | #endif | |
105 | static int ds_send_control(struct ds_device *dev, u16 value, u16 index) | 211 | static int ds_send_control(struct ds_device *dev, u16 value, u16 index) |
106 | { | 212 | { |
107 | int err; | 213 | int err; |
@@ -324,7 +430,7 @@ static int ds_wait_status(struct ds_device *dev, struct ds_status *st) | |||
324 | return 0; | 430 | return 0; |
325 | } | 431 | } |
326 | 432 | ||
327 | int ds_reset(struct ds_device *dev, struct ds_status *st) | 433 | static int ds_reset(struct ds_device *dev, struct ds_status *st) |
328 | { | 434 | { |
329 | int err; | 435 | int err; |
330 | 436 | ||
@@ -345,7 +451,7 @@ int ds_reset(struct ds_device *dev, struct ds_status *st) | |||
345 | } | 451 | } |
346 | 452 | ||
347 | #if 0 | 453 | #if 0 |
348 | int ds_set_speed(struct ds_device *dev, int speed) | 454 | static int ds_set_speed(struct ds_device *dev, int speed) |
349 | { | 455 | { |
350 | int err; | 456 | int err; |
351 | 457 | ||
@@ -395,7 +501,7 @@ static int ds_start_pulse(struct ds_device *dev, int delay) | |||
395 | return err; | 501 | return err; |
396 | } | 502 | } |
397 | 503 | ||
398 | int ds_touch_bit(struct ds_device *dev, u8 bit, u8 *tbit) | 504 | static int ds_touch_bit(struct ds_device *dev, u8 bit, u8 *tbit) |
399 | { | 505 | { |
400 | int err, count; | 506 | int err, count; |
401 | struct ds_status st; | 507 | struct ds_status st; |
@@ -427,7 +533,7 @@ int ds_touch_bit(struct ds_device *dev, u8 bit, u8 *tbit) | |||
427 | return 0; | 533 | return 0; |
428 | } | 534 | } |
429 | 535 | ||
430 | int ds_write_bit(struct ds_device *dev, u8 bit) | 536 | static int ds_write_bit(struct ds_device *dev, u8 bit) |
431 | { | 537 | { |
432 | int err; | 538 | int err; |
433 | struct ds_status st; | 539 | struct ds_status st; |
@@ -441,7 +547,7 @@ int ds_write_bit(struct ds_device *dev, u8 bit) | |||
441 | return 0; | 547 | return 0; |
442 | } | 548 | } |
443 | 549 | ||
444 | int ds_write_byte(struct ds_device *dev, u8 byte) | 550 | static int ds_write_byte(struct ds_device *dev, u8 byte) |
445 | { | 551 | { |
446 | int err; | 552 | int err; |
447 | struct ds_status st; | 553 | struct ds_status st; |
@@ -464,26 +570,7 @@ int ds_write_byte(struct ds_device *dev, u8 byte) | |||
464 | return !(byte == rbyte); | 570 | return !(byte == rbyte); |
465 | } | 571 | } |
466 | 572 | ||
467 | int ds_read_bit(struct ds_device *dev, u8 *bit) | 573 | static int ds_read_byte(struct ds_device *dev, u8 *byte) |
468 | { | ||
469 | int err; | ||
470 | |||
471 | err = ds_send_control_mode(dev, MOD_PULSE_EN, PULSE_SPUE); | ||
472 | if (err) | ||
473 | return err; | ||
474 | |||
475 | err = ds_send_control(dev, COMM_BIT_IO | COMM_IM | COMM_SPU | COMM_D, 0); | ||
476 | if (err) | ||
477 | return err; | ||
478 | |||
479 | err = ds_recv_data(dev, bit, sizeof(*bit)); | ||
480 | if (err < 0) | ||
481 | return err; | ||
482 | |||
483 | return 0; | ||
484 | } | ||
485 | |||
486 | int ds_read_byte(struct ds_device *dev, u8 *byte) | ||
487 | { | 574 | { |
488 | int err; | 575 | int err; |
489 | struct ds_status st; | 576 | struct ds_status st; |
@@ -501,7 +588,7 @@ int ds_read_byte(struct ds_device *dev, u8 *byte) | |||
501 | return 0; | 588 | return 0; |
502 | } | 589 | } |
503 | 590 | ||
504 | int ds_read_block(struct ds_device *dev, u8 *buf, int len) | 591 | static int ds_read_block(struct ds_device *dev, u8 *buf, int len) |
505 | { | 592 | { |
506 | struct ds_status st; | 593 | struct ds_status st; |
507 | int err; | 594 | int err; |
@@ -527,7 +614,7 @@ int ds_read_block(struct ds_device *dev, u8 *buf, int len) | |||
527 | return err; | 614 | return err; |
528 | } | 615 | } |
529 | 616 | ||
530 | int ds_write_block(struct ds_device *dev, u8 *buf, int len) | 617 | static int ds_write_block(struct ds_device *dev, u8 *buf, int len) |
531 | { | 618 | { |
532 | int err; | 619 | int err; |
533 | struct ds_status st; | 620 | struct ds_status st; |
@@ -555,7 +642,7 @@ int ds_write_block(struct ds_device *dev, u8 *buf, int len) | |||
555 | 642 | ||
556 | #if 0 | 643 | #if 0 |
557 | 644 | ||
558 | int ds_search(struct ds_device *dev, u64 init, u64 *buf, u8 id_number, int conditional_search) | 645 | static int ds_search(struct ds_device *dev, u64 init, u64 *buf, u8 id_number, int conditional_search) |
559 | { | 646 | { |
560 | int err; | 647 | int err; |
561 | u16 value, index; | 648 | u16 value, index; |
@@ -584,7 +671,7 @@ int ds_search(struct ds_device *dev, u64 init, u64 *buf, u8 id_number, int condi | |||
584 | return err/8; | 671 | return err/8; |
585 | } | 672 | } |
586 | 673 | ||
587 | int ds_match_access(struct ds_device *dev, u64 init) | 674 | static int ds_match_access(struct ds_device *dev, u64 init) |
588 | { | 675 | { |
589 | int err; | 676 | int err; |
590 | struct ds_status st; | 677 | struct ds_status st; |
@@ -604,7 +691,7 @@ int ds_match_access(struct ds_device *dev, u64 init) | |||
604 | return 0; | 691 | return 0; |
605 | } | 692 | } |
606 | 693 | ||
607 | int ds_set_path(struct ds_device *dev, u64 init) | 694 | static int ds_set_path(struct ds_device *dev, u64 init) |
608 | { | 695 | { |
609 | int err; | 696 | int err; |
610 | struct ds_status st; | 697 | struct ds_status st; |
@@ -630,45 +717,156 @@ int ds_set_path(struct ds_device *dev, u64 init) | |||
630 | 717 | ||
631 | #endif /* 0 */ | 718 | #endif /* 0 */ |
632 | 719 | ||
720 | static u8 ds9490r_touch_bit(void *data, u8 bit) | ||
721 | { | ||
722 | u8 ret; | ||
723 | struct ds_device *dev = data; | ||
724 | |||
725 | if (ds_touch_bit(dev, bit, &ret)) | ||
726 | return 0; | ||
727 | |||
728 | return ret; | ||
729 | } | ||
730 | |||
731 | static void ds9490r_write_bit(void *data, u8 bit) | ||
732 | { | ||
733 | struct ds_device *dev = data; | ||
734 | |||
735 | ds_write_bit(dev, bit); | ||
736 | } | ||
737 | |||
738 | static void ds9490r_write_byte(void *data, u8 byte) | ||
739 | { | ||
740 | struct ds_device *dev = data; | ||
741 | |||
742 | ds_write_byte(dev, byte); | ||
743 | } | ||
744 | |||
745 | static u8 ds9490r_read_bit(void *data) | ||
746 | { | ||
747 | struct ds_device *dev = data; | ||
748 | int err; | ||
749 | u8 bit = 0; | ||
750 | |||
751 | err = ds_touch_bit(dev, 1, &bit); | ||
752 | if (err) | ||
753 | return 0; | ||
754 | |||
755 | return bit & 1; | ||
756 | } | ||
757 | |||
758 | static u8 ds9490r_read_byte(void *data) | ||
759 | { | ||
760 | struct ds_device *dev = data; | ||
761 | int err; | ||
762 | u8 byte = 0; | ||
763 | |||
764 | err = ds_read_byte(dev, &byte); | ||
765 | if (err) | ||
766 | return 0; | ||
767 | |||
768 | return byte; | ||
769 | } | ||
770 | |||
771 | static void ds9490r_write_block(void *data, const u8 *buf, int len) | ||
772 | { | ||
773 | struct ds_device *dev = data; | ||
774 | |||
775 | ds_write_block(dev, (u8 *)buf, len); | ||
776 | } | ||
777 | |||
778 | static u8 ds9490r_read_block(void *data, u8 *buf, int len) | ||
779 | { | ||
780 | struct ds_device *dev = data; | ||
781 | int err; | ||
782 | |||
783 | err = ds_read_block(dev, buf, len); | ||
784 | if (err < 0) | ||
785 | return 0; | ||
786 | |||
787 | return len; | ||
788 | } | ||
789 | |||
790 | static u8 ds9490r_reset(void *data) | ||
791 | { | ||
792 | struct ds_device *dev = data; | ||
793 | struct ds_status st; | ||
794 | int err; | ||
795 | |||
796 | memset(&st, 0, sizeof(st)); | ||
797 | |||
798 | err = ds_reset(dev, &st); | ||
799 | if (err) | ||
800 | return 1; | ||
801 | |||
802 | return 0; | ||
803 | } | ||
804 | |||
805 | static int ds_w1_init(struct ds_device *dev) | ||
806 | { | ||
807 | memset(&dev->master, 0, sizeof(struct w1_bus_master)); | ||
808 | |||
809 | dev->master.data = dev; | ||
810 | dev->master.touch_bit = &ds9490r_touch_bit; | ||
811 | dev->master.read_bit = &ds9490r_read_bit; | ||
812 | dev->master.write_bit = &ds9490r_write_bit; | ||
813 | dev->master.read_byte = &ds9490r_read_byte; | ||
814 | dev->master.write_byte = &ds9490r_write_byte; | ||
815 | dev->master.read_block = &ds9490r_read_block; | ||
816 | dev->master.write_block = &ds9490r_write_block; | ||
817 | dev->master.reset_bus = &ds9490r_reset; | ||
818 | |||
819 | return w1_add_master_device(&dev->master); | ||
820 | } | ||
821 | |||
822 | static void ds_w1_fini(struct ds_device *dev) | ||
823 | { | ||
824 | w1_remove_master_device(&dev->master); | ||
825 | } | ||
826 | |||
633 | static int ds_probe(struct usb_interface *intf, | 827 | static int ds_probe(struct usb_interface *intf, |
634 | const struct usb_device_id *udev_id) | 828 | const struct usb_device_id *udev_id) |
635 | { | 829 | { |
636 | struct usb_device *udev = interface_to_usbdev(intf); | 830 | struct usb_device *udev = interface_to_usbdev(intf); |
637 | struct usb_endpoint_descriptor *endpoint; | 831 | struct usb_endpoint_descriptor *endpoint; |
638 | struct usb_host_interface *iface_desc; | 832 | struct usb_host_interface *iface_desc; |
833 | struct ds_device *dev; | ||
639 | int i, err; | 834 | int i, err; |
640 | 835 | ||
641 | ds_dev = kmalloc(sizeof(struct ds_device), GFP_KERNEL); | 836 | dev = kmalloc(sizeof(struct ds_device), GFP_KERNEL); |
642 | if (!ds_dev) { | 837 | if (!dev) { |
643 | printk(KERN_INFO "Failed to allocate new DS9490R structure.\n"); | 838 | printk(KERN_INFO "Failed to allocate new DS9490R structure.\n"); |
644 | return -ENOMEM; | 839 | return -ENOMEM; |
645 | } | 840 | } |
841 | dev->udev = usb_get_dev(udev); | ||
842 | if (!dev->udev) { | ||
843 | err = -ENOMEM; | ||
844 | goto err_out_free; | ||
845 | } | ||
846 | memset(dev->ep, 0, sizeof(dev->ep)); | ||
646 | 847 | ||
647 | ds_dev->udev = usb_get_dev(udev); | 848 | usb_set_intfdata(intf, dev); |
648 | usb_set_intfdata(intf, ds_dev); | ||
649 | 849 | ||
650 | err = usb_set_interface(ds_dev->udev, intf->altsetting[0].desc.bInterfaceNumber, 3); | 850 | err = usb_set_interface(dev->udev, intf->altsetting[0].desc.bInterfaceNumber, 3); |
651 | if (err) { | 851 | if (err) { |
652 | printk(KERN_ERR "Failed to set alternative setting 3 for %d interface: err=%d.\n", | 852 | printk(KERN_ERR "Failed to set alternative setting 3 for %d interface: err=%d.\n", |
653 | intf->altsetting[0].desc.bInterfaceNumber, err); | 853 | intf->altsetting[0].desc.bInterfaceNumber, err); |
654 | return err; | 854 | goto err_out_clear; |
655 | } | 855 | } |
656 | 856 | ||
657 | err = usb_reset_configuration(ds_dev->udev); | 857 | err = usb_reset_configuration(dev->udev); |
658 | if (err) { | 858 | if (err) { |
659 | printk(KERN_ERR "Failed to reset configuration: err=%d.\n", err); | 859 | printk(KERN_ERR "Failed to reset configuration: err=%d.\n", err); |
660 | return err; | 860 | goto err_out_clear; |
661 | } | 861 | } |
662 | 862 | ||
663 | iface_desc = &intf->altsetting[0]; | 863 | iface_desc = &intf->altsetting[0]; |
664 | if (iface_desc->desc.bNumEndpoints != NUM_EP-1) { | 864 | if (iface_desc->desc.bNumEndpoints != NUM_EP-1) { |
665 | printk(KERN_INFO "Num endpoints=%d. It is not DS9490R.\n", iface_desc->desc.bNumEndpoints); | 865 | printk(KERN_INFO "Num endpoints=%d. It is not DS9490R.\n", iface_desc->desc.bNumEndpoints); |
666 | return -ENODEV; | 866 | err = -EINVAL; |
867 | goto err_out_clear; | ||
667 | } | 868 | } |
668 | 869 | ||
669 | atomic_set(&ds_dev->refcnt, 0); | ||
670 | memset(ds_dev->ep, 0, sizeof(ds_dev->ep)); | ||
671 | |||
672 | /* | 870 | /* |
673 | * This loop doesn'd show control 0 endpoint, | 871 | * This loop doesn'd show control 0 endpoint, |
674 | * so we will fill only 1-3 endpoints entry. | 872 | * so we will fill only 1-3 endpoints entry. |
@@ -676,54 +874,31 @@ static int ds_probe(struct usb_interface *intf, | |||
676 | for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { | 874 | for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { |
677 | endpoint = &iface_desc->endpoint[i].desc; | 875 | endpoint = &iface_desc->endpoint[i].desc; |
678 | 876 | ||
679 | ds_dev->ep[i+1] = endpoint->bEndpointAddress; | 877 | dev->ep[i+1] = endpoint->bEndpointAddress; |
680 | 878 | #if 0 | |
681 | printk("%d: addr=%x, size=%d, dir=%s, type=%x\n", | 879 | printk("%d: addr=%x, size=%d, dir=%s, type=%x\n", |
682 | i, endpoint->bEndpointAddress, le16_to_cpu(endpoint->wMaxPacketSize), | 880 | i, endpoint->bEndpointAddress, le16_to_cpu(endpoint->wMaxPacketSize), |
683 | (endpoint->bEndpointAddress & USB_DIR_IN)?"IN":"OUT", | 881 | (endpoint->bEndpointAddress & USB_DIR_IN)?"IN":"OUT", |
684 | endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK); | 882 | endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK); |
883 | #endif | ||
685 | } | 884 | } |
686 | 885 | ||
687 | #if 0 | 886 | err = ds_w1_init(dev); |
688 | { | 887 | if (err) |
689 | int err, i; | 888 | goto err_out_clear; |
690 | u64 buf[3]; | ||
691 | u64 init=0xb30000002078ee81ull; | ||
692 | struct ds_status st; | ||
693 | |||
694 | ds_reset(ds_dev, &st); | ||
695 | err = ds_search(ds_dev, init, buf, 3, 0); | ||
696 | if (err < 0) | ||
697 | return err; | ||
698 | for (i=0; i<err; ++i) | ||
699 | printk("%d: %llx\n", i, buf[i]); | ||
700 | |||
701 | printk("Resetting...\n"); | ||
702 | ds_reset(ds_dev, &st); | ||
703 | printk("Setting path for %llx.\n", init); | ||
704 | err = ds_set_path(ds_dev, init); | ||
705 | if (err) | ||
706 | return err; | ||
707 | printk("Calling MATCH_ACCESS.\n"); | ||
708 | err = ds_match_access(ds_dev, init); | ||
709 | if (err) | ||
710 | return err; | ||
711 | |||
712 | printk("Searching the bus...\n"); | ||
713 | err = ds_search(ds_dev, init, buf, 3, 0); | ||
714 | |||
715 | printk("ds_search() returned %d\n", err); | ||
716 | |||
717 | if (err < 0) | ||
718 | return err; | ||
719 | for (i=0; i<err; ++i) | ||
720 | printk("%d: %llx\n", i, buf[i]); | ||
721 | 889 | ||
722 | return 0; | 890 | mutex_lock(&ds_mutex); |
723 | } | 891 | list_add_tail(&dev->ds_entry, &ds_devices); |
724 | #endif | 892 | mutex_unlock(&ds_mutex); |
725 | 893 | ||
726 | return 0; | 894 | return 0; |
895 | |||
896 | err_out_clear: | ||
897 | usb_set_intfdata(intf, NULL); | ||
898 | usb_put_dev(dev->udev); | ||
899 | err_out_free: | ||
900 | kfree(dev); | ||
901 | return err; | ||
727 | } | 902 | } |
728 | 903 | ||
729 | static void ds_disconnect(struct usb_interface *intf) | 904 | static void ds_disconnect(struct usb_interface *intf) |
@@ -731,19 +906,19 @@ static void ds_disconnect(struct usb_interface *intf) | |||
731 | struct ds_device *dev; | 906 | struct ds_device *dev; |
732 | 907 | ||
733 | dev = usb_get_intfdata(intf); | 908 | dev = usb_get_intfdata(intf); |
734 | usb_set_intfdata(intf, NULL); | 909 | if (!dev) |
910 | return; | ||
735 | 911 | ||
736 | while (atomic_read(&dev->refcnt)) { | 912 | mutex_lock(&ds_mutex); |
737 | printk(KERN_INFO "Waiting for DS to become free: refcnt=%d.\n", | 913 | list_del(&dev->ds_entry); |
738 | atomic_read(&dev->refcnt)); | 914 | mutex_unlock(&ds_mutex); |
739 | 915 | ||
740 | if (msleep_interruptible(1000)) | 916 | ds_w1_fini(dev); |
741 | flush_signals(current); | 917 | |
742 | } | 918 | usb_set_intfdata(intf, NULL); |
743 | 919 | ||
744 | usb_put_dev(dev->udev); | 920 | usb_put_dev(dev->udev); |
745 | kfree(dev); | 921 | kfree(dev); |
746 | ds_dev = NULL; | ||
747 | } | 922 | } |
748 | 923 | ||
749 | static int ds_init(void) | 924 | static int ds_init(void) |
@@ -769,27 +944,4 @@ module_exit(ds_fini); | |||
769 | 944 | ||
770 | MODULE_LICENSE("GPL"); | 945 | MODULE_LICENSE("GPL"); |
771 | MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>"); | 946 | MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>"); |
772 | 947 | MODULE_DESCRIPTION("DS2490 USB <-> W1 bus master driver (DS9490*)"); | |
773 | EXPORT_SYMBOL(ds_touch_bit); | ||
774 | EXPORT_SYMBOL(ds_read_byte); | ||
775 | EXPORT_SYMBOL(ds_read_bit); | ||
776 | EXPORT_SYMBOL(ds_read_block); | ||
777 | EXPORT_SYMBOL(ds_write_byte); | ||
778 | EXPORT_SYMBOL(ds_write_bit); | ||
779 | EXPORT_SYMBOL(ds_write_block); | ||
780 | EXPORT_SYMBOL(ds_reset); | ||
781 | EXPORT_SYMBOL(ds_get_device); | ||
782 | EXPORT_SYMBOL(ds_put_device); | ||
783 | |||
784 | /* | ||
785 | * This functions can be used for EEPROM programming, | ||
786 | * when driver will be included into mainline this will | ||
787 | * require uncommenting. | ||
788 | */ | ||
789 | #if 0 | ||
790 | EXPORT_SYMBOL(ds_start_pulse); | ||
791 | EXPORT_SYMBOL(ds_set_speed); | ||
792 | EXPORT_SYMBOL(ds_detect); | ||
793 | EXPORT_SYMBOL(ds_stop_pulse); | ||
794 | EXPORT_SYMBOL(ds_search); | ||
795 | #endif | ||
diff --git a/drivers/w1/masters/ds_w1_bridge.c b/drivers/w1/masters/ds_w1_bridge.c deleted file mode 100644 index 5d30783a3eb6..000000000000 --- a/drivers/w1/masters/ds_w1_bridge.c +++ /dev/null | |||
@@ -1,174 +0,0 @@ | |||
1 | /* | ||
2 | * ds_w1_bridge.c | ||
3 | * | ||
4 | * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru> | ||
5 | * | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | |||
22 | #include <linux/module.h> | ||
23 | #include <linux/types.h> | ||
24 | |||
25 | #include "../w1.h" | ||
26 | #include "../w1_int.h" | ||
27 | #include "dscore.h" | ||
28 | |||
29 | static struct ds_device *ds_dev; | ||
30 | static struct w1_bus_master *ds_bus_master; | ||
31 | |||
32 | static u8 ds9490r_touch_bit(void *data, u8 bit) | ||
33 | { | ||
34 | u8 ret; | ||
35 | struct ds_device *dev = data; | ||
36 | |||
37 | if (ds_touch_bit(dev, bit, &ret)) | ||
38 | return 0; | ||
39 | |||
40 | return ret; | ||
41 | } | ||
42 | |||
43 | static void ds9490r_write_bit(void *data, u8 bit) | ||
44 | { | ||
45 | struct ds_device *dev = data; | ||
46 | |||
47 | ds_write_bit(dev, bit); | ||
48 | } | ||
49 | |||
50 | static void ds9490r_write_byte(void *data, u8 byte) | ||
51 | { | ||
52 | struct ds_device *dev = data; | ||
53 | |||
54 | ds_write_byte(dev, byte); | ||
55 | } | ||
56 | |||
57 | static u8 ds9490r_read_bit(void *data) | ||
58 | { | ||
59 | struct ds_device *dev = data; | ||
60 | int err; | ||
61 | u8 bit = 0; | ||
62 | |||
63 | err = ds_touch_bit(dev, 1, &bit); | ||
64 | if (err) | ||
65 | return 0; | ||
66 | //err = ds_read_bit(dev, &bit); | ||
67 | //if (err) | ||
68 | // return 0; | ||
69 | |||
70 | return bit & 1; | ||
71 | } | ||
72 | |||
73 | static u8 ds9490r_read_byte(void *data) | ||
74 | { | ||
75 | struct ds_device *dev = data; | ||
76 | int err; | ||
77 | u8 byte = 0; | ||
78 | |||
79 | err = ds_read_byte(dev, &byte); | ||
80 | if (err) | ||
81 | return 0; | ||
82 | |||
83 | return byte; | ||
84 | } | ||
85 | |||
86 | static void ds9490r_write_block(void *data, const u8 *buf, int len) | ||
87 | { | ||
88 | struct ds_device *dev = data; | ||
89 | |||
90 | ds_write_block(dev, (u8 *)buf, len); | ||
91 | } | ||
92 | |||
93 | static u8 ds9490r_read_block(void *data, u8 *buf, int len) | ||
94 | { | ||
95 | struct ds_device *dev = data; | ||
96 | int err; | ||
97 | |||
98 | err = ds_read_block(dev, buf, len); | ||
99 | if (err < 0) | ||
100 | return 0; | ||
101 | |||
102 | return len; | ||
103 | } | ||
104 | |||
105 | static u8 ds9490r_reset(void *data) | ||
106 | { | ||
107 | struct ds_device *dev = data; | ||
108 | struct ds_status st; | ||
109 | int err; | ||
110 | |||
111 | memset(&st, 0, sizeof(st)); | ||
112 | |||
113 | err = ds_reset(dev, &st); | ||
114 | if (err) | ||
115 | return 1; | ||
116 | |||
117 | return 0; | ||
118 | } | ||
119 | |||
120 | static int __devinit ds_w1_init(void) | ||
121 | { | ||
122 | int err; | ||
123 | |||
124 | ds_bus_master = kmalloc(sizeof(*ds_bus_master), GFP_KERNEL); | ||
125 | if (!ds_bus_master) { | ||
126 | printk(KERN_ERR "Failed to allocate DS9490R USB<->W1 bus_master structure.\n"); | ||
127 | return -ENOMEM; | ||
128 | } | ||
129 | |||
130 | ds_dev = ds_get_device(); | ||
131 | if (!ds_dev) { | ||
132 | printk(KERN_ERR "DS9490R is not registered.\n"); | ||
133 | err = -ENODEV; | ||
134 | goto err_out_free_bus_master; | ||
135 | } | ||
136 | |||
137 | memset(ds_bus_master, 0, sizeof(*ds_bus_master)); | ||
138 | |||
139 | ds_bus_master->data = ds_dev; | ||
140 | ds_bus_master->touch_bit = &ds9490r_touch_bit; | ||
141 | ds_bus_master->read_bit = &ds9490r_read_bit; | ||
142 | ds_bus_master->write_bit = &ds9490r_write_bit; | ||
143 | ds_bus_master->read_byte = &ds9490r_read_byte; | ||
144 | ds_bus_master->write_byte = &ds9490r_write_byte; | ||
145 | ds_bus_master->read_block = &ds9490r_read_block; | ||
146 | ds_bus_master->write_block = &ds9490r_write_block; | ||
147 | ds_bus_master->reset_bus = &ds9490r_reset; | ||
148 | |||
149 | err = w1_add_master_device(ds_bus_master); | ||
150 | if (err) | ||
151 | goto err_out_put_device; | ||
152 | |||
153 | return 0; | ||
154 | |||
155 | err_out_put_device: | ||
156 | ds_put_device(ds_dev); | ||
157 | err_out_free_bus_master: | ||
158 | kfree(ds_bus_master); | ||
159 | |||
160 | return err; | ||
161 | } | ||
162 | |||
163 | static void __devexit ds_w1_fini(void) | ||
164 | { | ||
165 | w1_remove_master_device(ds_bus_master); | ||
166 | ds_put_device(ds_dev); | ||
167 | kfree(ds_bus_master); | ||
168 | } | ||
169 | |||
170 | module_init(ds_w1_init); | ||
171 | module_exit(ds_w1_fini); | ||
172 | |||
173 | MODULE_LICENSE("GPL"); | ||
174 | MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>"); | ||
diff --git a/drivers/w1/masters/dscore.h b/drivers/w1/masters/dscore.h deleted file mode 100644 index 6cf5671d6ebe..000000000000 --- a/drivers/w1/masters/dscore.h +++ /dev/null | |||
@@ -1,166 +0,0 @@ | |||
1 | /* | ||
2 | * dscore.h | ||
3 | * | ||
4 | * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru> | ||
5 | * | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | |||
22 | #ifndef __DSCORE_H | ||
23 | #define __DSCORE_H | ||
24 | |||
25 | #include <linux/usb.h> | ||
26 | #include <asm/atomic.h> | ||
27 | |||
28 | /* COMMAND TYPE CODES */ | ||
29 | #define CONTROL_CMD 0x00 | ||
30 | #define COMM_CMD 0x01 | ||
31 | #define MODE_CMD 0x02 | ||
32 | |||
33 | /* CONTROL COMMAND CODES */ | ||
34 | #define CTL_RESET_DEVICE 0x0000 | ||
35 | #define CTL_START_EXE 0x0001 | ||
36 | #define CTL_RESUME_EXE 0x0002 | ||
37 | #define CTL_HALT_EXE_IDLE 0x0003 | ||
38 | #define CTL_HALT_EXE_DONE 0x0004 | ||
39 | #define CTL_FLUSH_COMM_CMDS 0x0007 | ||
40 | #define CTL_FLUSH_RCV_BUFFER 0x0008 | ||
41 | #define CTL_FLUSH_XMT_BUFFER 0x0009 | ||
42 | #define CTL_GET_COMM_CMDS 0x000A | ||
43 | |||
44 | /* MODE COMMAND CODES */ | ||
45 | #define MOD_PULSE_EN 0x0000 | ||
46 | #define MOD_SPEED_CHANGE_EN 0x0001 | ||
47 | #define MOD_1WIRE_SPEED 0x0002 | ||
48 | #define MOD_STRONG_PU_DURATION 0x0003 | ||
49 | #define MOD_PULLDOWN_SLEWRATE 0x0004 | ||
50 | #define MOD_PROG_PULSE_DURATION 0x0005 | ||
51 | #define MOD_WRITE1_LOWTIME 0x0006 | ||
52 | #define MOD_DSOW0_TREC 0x0007 | ||
53 | |||
54 | /* COMMUNICATION COMMAND CODES */ | ||
55 | #define COMM_ERROR_ESCAPE 0x0601 | ||
56 | #define COMM_SET_DURATION 0x0012 | ||
57 | #define COMM_BIT_IO 0x0020 | ||
58 | #define COMM_PULSE 0x0030 | ||
59 | #define COMM_1_WIRE_RESET 0x0042 | ||
60 | #define COMM_BYTE_IO 0x0052 | ||
61 | #define COMM_MATCH_ACCESS 0x0064 | ||
62 | #define COMM_BLOCK_IO 0x0074 | ||
63 | #define COMM_READ_STRAIGHT 0x0080 | ||
64 | #define COMM_DO_RELEASE 0x6092 | ||
65 | #define COMM_SET_PATH 0x00A2 | ||
66 | #define COMM_WRITE_SRAM_PAGE 0x00B2 | ||
67 | #define COMM_WRITE_EPROM 0x00C4 | ||
68 | #define COMM_READ_CRC_PROT_PAGE 0x00D4 | ||
69 | #define COMM_READ_REDIRECT_PAGE_CRC 0x21E4 | ||
70 | #define COMM_SEARCH_ACCESS 0x00F4 | ||
71 | |||
72 | /* Communication command bits */ | ||
73 | #define COMM_TYPE 0x0008 | ||
74 | #define COMM_SE 0x0008 | ||
75 | #define COMM_D 0x0008 | ||
76 | #define COMM_Z 0x0008 | ||
77 | #define COMM_CH 0x0008 | ||
78 | #define COMM_SM 0x0008 | ||
79 | #define COMM_R 0x0008 | ||
80 | #define COMM_IM 0x0001 | ||
81 | |||
82 | #define COMM_PS 0x4000 | ||
83 | #define COMM_PST 0x4000 | ||
84 | #define COMM_CIB 0x4000 | ||
85 | #define COMM_RTS 0x4000 | ||
86 | #define COMM_DT 0x2000 | ||
87 | #define COMM_SPU 0x1000 | ||
88 | #define COMM_F 0x0800 | ||
89 | #define COMM_NTP 0x0400 | ||
90 | #define COMM_ICP 0x0200 | ||
91 | #define COMM_RST 0x0100 | ||
92 | |||
93 | #define PULSE_PROG 0x01 | ||
94 | #define PULSE_SPUE 0x02 | ||
95 | |||
96 | #define BRANCH_MAIN 0xCC | ||
97 | #define BRANCH_AUX 0x33 | ||
98 | |||
99 | /* | ||
100 | * Duration of the strong pull-up pulse in milliseconds. | ||
101 | */ | ||
102 | #define PULLUP_PULSE_DURATION 750 | ||
103 | |||
104 | /* Status flags */ | ||
105 | #define ST_SPUA 0x01 /* Strong Pull-up is active */ | ||
106 | #define ST_PRGA 0x02 /* 12V programming pulse is being generated */ | ||
107 | #define ST_12VP 0x04 /* external 12V programming voltage is present */ | ||
108 | #define ST_PMOD 0x08 /* DS2490 powered from USB and external sources */ | ||
109 | #define ST_HALT 0x10 /* DS2490 is currently halted */ | ||
110 | #define ST_IDLE 0x20 /* DS2490 is currently idle */ | ||
111 | #define ST_EPOF 0x80 | ||
112 | |||
113 | #define SPEED_NORMAL 0x00 | ||
114 | #define SPEED_FLEXIBLE 0x01 | ||
115 | #define SPEED_OVERDRIVE 0x02 | ||
116 | |||
117 | #define NUM_EP 4 | ||
118 | #define EP_CONTROL 0 | ||
119 | #define EP_STATUS 1 | ||
120 | #define EP_DATA_OUT 2 | ||
121 | #define EP_DATA_IN 3 | ||
122 | |||
123 | struct ds_device | ||
124 | { | ||
125 | struct usb_device *udev; | ||
126 | struct usb_interface *intf; | ||
127 | |||
128 | int ep[NUM_EP]; | ||
129 | |||
130 | atomic_t refcnt; | ||
131 | }; | ||
132 | |||
133 | struct ds_status | ||
134 | { | ||
135 | u8 enable; | ||
136 | u8 speed; | ||
137 | u8 pullup_dur; | ||
138 | u8 ppuls_dur; | ||
139 | u8 pulldown_slew; | ||
140 | u8 write1_time; | ||
141 | u8 write0_time; | ||
142 | u8 reserved0; | ||
143 | u8 status; | ||
144 | u8 command0; | ||
145 | u8 command1; | ||
146 | u8 command_buffer_status; | ||
147 | u8 data_out_buffer_status; | ||
148 | u8 data_in_buffer_status; | ||
149 | u8 reserved1; | ||
150 | u8 reserved2; | ||
151 | |||
152 | }; | ||
153 | |||
154 | int ds_touch_bit(struct ds_device *, u8, u8 *); | ||
155 | int ds_read_byte(struct ds_device *, u8 *); | ||
156 | int ds_read_bit(struct ds_device *, u8 *); | ||
157 | int ds_write_byte(struct ds_device *, u8); | ||
158 | int ds_write_bit(struct ds_device *, u8); | ||
159 | int ds_reset(struct ds_device *, struct ds_status *); | ||
160 | struct ds_device * ds_get_device(void); | ||
161 | void ds_put_device(struct ds_device *); | ||
162 | int ds_write_block(struct ds_device *, u8 *, int); | ||
163 | int ds_read_block(struct ds_device *, u8 *, int); | ||
164 | |||
165 | #endif /* __DSCORE_H */ | ||
166 | |||
diff --git a/drivers/w1/slaves/Kconfig b/drivers/w1/slaves/Kconfig index f9d4c91fc533..d18d6424cd21 100644 --- a/drivers/w1/slaves/Kconfig +++ b/drivers/w1/slaves/Kconfig | |||
@@ -28,7 +28,7 @@ config W1_SLAVE_DS2433 | |||
28 | 28 | ||
29 | config W1_SLAVE_DS2433_CRC | 29 | config W1_SLAVE_DS2433_CRC |
30 | bool "Protect DS2433 data with a CRC16" | 30 | bool "Protect DS2433 data with a CRC16" |
31 | depends on W1_DS2433 | 31 | depends on W1_SLAVE_DS2433 |
32 | select CRC16 | 32 | select CRC16 |
33 | help | 33 | help |
34 | Say Y here to protect DS2433 data with a CRC16. | 34 | Say Y here to protect DS2433 data with a CRC16. |
diff --git a/drivers/w1/slaves/w1_ds2433.c b/drivers/w1/slaves/w1_ds2433.c index fb118be789ea..2ac238f1480e 100644 --- a/drivers/w1/slaves/w1_ds2433.c +++ b/drivers/w1/slaves/w1_ds2433.c | |||
@@ -22,7 +22,6 @@ | |||
22 | #endif | 22 | #endif |
23 | 23 | ||
24 | #include "../w1.h" | 24 | #include "../w1.h" |
25 | #include "../w1_io.h" | ||
26 | #include "../w1_int.h" | 25 | #include "../w1_int.h" |
27 | #include "../w1_family.h" | 26 | #include "../w1_family.h" |
28 | 27 | ||
@@ -106,11 +105,7 @@ static ssize_t w1_f23_read_bin(struct kobject *kobj, char *buf, loff_t off, | |||
106 | if ((count = w1_f23_fix_count(off, count, W1_EEPROM_SIZE)) == 0) | 105 | if ((count = w1_f23_fix_count(off, count, W1_EEPROM_SIZE)) == 0) |
107 | return 0; | 106 | return 0; |
108 | 107 | ||
109 | atomic_inc(&sl->refcnt); | 108 | mutex_lock(&sl->master->mutex); |
110 | if (down_interruptible(&sl->master->mutex)) { | ||
111 | count = 0; | ||
112 | goto out_dec; | ||
113 | } | ||
114 | 109 | ||
115 | #ifdef CONFIG_W1_F23_CRC | 110 | #ifdef CONFIG_W1_F23_CRC |
116 | 111 | ||
@@ -141,9 +136,7 @@ static ssize_t w1_f23_read_bin(struct kobject *kobj, char *buf, loff_t off, | |||
141 | #endif /* CONFIG_W1_F23_CRC */ | 136 | #endif /* CONFIG_W1_F23_CRC */ |
142 | 137 | ||
143 | out_up: | 138 | out_up: |
144 | up(&sl->master->mutex); | 139 | mutex_unlock(&sl->master->mutex); |
145 | out_dec: | ||
146 | atomic_dec(&sl->refcnt); | ||
147 | 140 | ||
148 | return count; | 141 | return count; |
149 | } | 142 | } |
@@ -232,11 +225,7 @@ static ssize_t w1_f23_write_bin(struct kobject *kobj, char *buf, loff_t off, | |||
232 | } | 225 | } |
233 | #endif /* CONFIG_W1_F23_CRC */ | 226 | #endif /* CONFIG_W1_F23_CRC */ |
234 | 227 | ||
235 | atomic_inc(&sl->refcnt); | 228 | mutex_lock(&sl->master->mutex); |
236 | if (down_interruptible(&sl->master->mutex)) { | ||
237 | count = 0; | ||
238 | goto out_dec; | ||
239 | } | ||
240 | 229 | ||
241 | /* Can only write data to one page at a time */ | 230 | /* Can only write data to one page at a time */ |
242 | idx = 0; | 231 | idx = 0; |
@@ -254,9 +243,7 @@ static ssize_t w1_f23_write_bin(struct kobject *kobj, char *buf, loff_t off, | |||
254 | } | 243 | } |
255 | 244 | ||
256 | out_up: | 245 | out_up: |
257 | up(&sl->master->mutex); | 246 | mutex_unlock(&sl->master->mutex); |
258 | out_dec: | ||
259 | atomic_dec(&sl->refcnt); | ||
260 | 247 | ||
261 | return count; | 248 | return count; |
262 | } | 249 | } |
diff --git a/drivers/w1/slaves/w1_smem.c b/drivers/w1/slaves/w1_smem.c index c6d3be54f94c..cc8c02e92593 100644 --- a/drivers/w1/slaves/w1_smem.c +++ b/drivers/w1/slaves/w1_smem.c | |||
@@ -28,7 +28,6 @@ | |||
28 | #include <linux/types.h> | 28 | #include <linux/types.h> |
29 | 29 | ||
30 | #include "../w1.h" | 30 | #include "../w1.h" |
31 | #include "../w1_io.h" | ||
32 | #include "../w1_int.h" | 31 | #include "../w1_int.h" |
33 | #include "../w1_family.h" | 32 | #include "../w1_family.h" |
34 | 33 | ||
diff --git a/drivers/w1/slaves/w1_therm.c b/drivers/w1/slaves/w1_therm.c index 536d16d78de7..5372cfcbd054 100644 --- a/drivers/w1/slaves/w1_therm.c +++ b/drivers/w1/slaves/w1_therm.c | |||
@@ -29,7 +29,6 @@ | |||
29 | #include <linux/delay.h> | 29 | #include <linux/delay.h> |
30 | 30 | ||
31 | #include "../w1.h" | 31 | #include "../w1.h" |
32 | #include "../w1_io.h" | ||
33 | #include "../w1_int.h" | 32 | #include "../w1_int.h" |
34 | #include "../w1_family.h" | 33 | #include "../w1_family.h" |
35 | 34 | ||
@@ -166,12 +165,7 @@ static ssize_t w1_therm_read_bin(struct kobject *kobj, char *buf, loff_t off, si | |||
166 | u8 rom[9], crc, verdict; | 165 | u8 rom[9], crc, verdict; |
167 | int i, max_trying = 10; | 166 | int i, max_trying = 10; |
168 | 167 | ||
169 | atomic_inc(&sl->refcnt); | 168 | mutex_lock(&sl->master->mutex); |
170 | smp_mb__after_atomic_inc(); | ||
171 | if (down_interruptible(&sl->master->mutex)) { | ||
172 | count = 0; | ||
173 | goto out_dec; | ||
174 | } | ||
175 | 169 | ||
176 | if (off > W1_SLAVE_DATA_SIZE) { | 170 | if (off > W1_SLAVE_DATA_SIZE) { |
177 | count = 0; | 171 | count = 0; |
@@ -234,10 +228,7 @@ static ssize_t w1_therm_read_bin(struct kobject *kobj, char *buf, loff_t off, si | |||
234 | 228 | ||
235 | count += sprintf(buf + count, "t=%d\n", w1_convert_temp(rom, sl->family->fid)); | 229 | count += sprintf(buf + count, "t=%d\n", w1_convert_temp(rom, sl->family->fid)); |
236 | out: | 230 | out: |
237 | up(&dev->mutex); | 231 | mutex_unlock(&dev->mutex); |
238 | out_dec: | ||
239 | smp_mb__before_atomic_inc(); | ||
240 | atomic_dec(&sl->refcnt); | ||
241 | 232 | ||
242 | return count; | 233 | return count; |
243 | } | 234 | } |
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index a698b517e863..de3e9791f80d 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c | |||
@@ -35,7 +35,6 @@ | |||
35 | #include <asm/atomic.h> | 35 | #include <asm/atomic.h> |
36 | 36 | ||
37 | #include "w1.h" | 37 | #include "w1.h" |
38 | #include "w1_io.h" | ||
39 | #include "w1_log.h" | 38 | #include "w1_log.h" |
40 | #include "w1_int.h" | 39 | #include "w1_int.h" |
41 | #include "w1_family.h" | 40 | #include "w1_family.h" |
@@ -55,7 +54,7 @@ module_param_named(control_timeout, w1_control_timeout, int, 0); | |||
55 | module_param_named(max_slave_count, w1_max_slave_count, int, 0); | 54 | module_param_named(max_slave_count, w1_max_slave_count, int, 0); |
56 | module_param_named(slave_ttl, w1_max_slave_ttl, int, 0); | 55 | module_param_named(slave_ttl, w1_max_slave_ttl, int, 0); |
57 | 56 | ||
58 | DEFINE_SPINLOCK(w1_mlock); | 57 | DEFINE_MUTEX(w1_mlock); |
59 | LIST_HEAD(w1_masters); | 58 | LIST_HEAD(w1_masters); |
60 | 59 | ||
61 | static struct task_struct *w1_control_thread; | 60 | static struct task_struct *w1_control_thread; |
@@ -75,8 +74,6 @@ static void w1_master_release(struct device *dev) | |||
75 | struct w1_master *md = dev_to_w1_master(dev); | 74 | struct w1_master *md = dev_to_w1_master(dev); |
76 | 75 | ||
77 | dev_dbg(dev, "%s: Releasing %s.\n", __func__, md->name); | 76 | dev_dbg(dev, "%s: Releasing %s.\n", __func__, md->name); |
78 | |||
79 | dev_fini_netlink(md); | ||
80 | memset(md, 0, sizeof(struct w1_master) + sizeof(struct w1_bus_master)); | 77 | memset(md, 0, sizeof(struct w1_master) + sizeof(struct w1_bus_master)); |
81 | kfree(md); | 78 | kfree(md); |
82 | } | 79 | } |
@@ -85,10 +82,10 @@ static void w1_slave_release(struct device *dev) | |||
85 | { | 82 | { |
86 | struct w1_slave *sl = dev_to_w1_slave(dev); | 83 | struct w1_slave *sl = dev_to_w1_slave(dev); |
87 | 84 | ||
88 | dev_dbg(dev, "%s: Releasing %s.\n", __func__, sl->name); | 85 | printk("%s: Releasing %s.\n", __func__, sl->name); |
89 | 86 | ||
90 | while (atomic_read(&sl->refcnt)) { | 87 | while (atomic_read(&sl->refcnt)) { |
91 | dev_dbg(dev, "Waiting for %s to become free: refcnt=%d.\n", | 88 | printk("Waiting for %s to become free: refcnt=%d.\n", |
92 | sl->name, atomic_read(&sl->refcnt)); | 89 | sl->name, atomic_read(&sl->refcnt)); |
93 | if (msleep_interruptible(1000)) | 90 | if (msleep_interruptible(1000)) |
94 | flush_signals(current); | 91 | flush_signals(current); |
@@ -111,7 +108,6 @@ static ssize_t w1_slave_read_id(struct kobject *kobj, char *buf, loff_t off, siz | |||
111 | { | 108 | { |
112 | struct w1_slave *sl = kobj_to_w1_slave(kobj); | 109 | struct w1_slave *sl = kobj_to_w1_slave(kobj); |
113 | 110 | ||
114 | atomic_inc(&sl->refcnt); | ||
115 | if (off > 8) { | 111 | if (off > 8) { |
116 | count = 0; | 112 | count = 0; |
117 | } else { | 113 | } else { |
@@ -120,7 +116,6 @@ static ssize_t w1_slave_read_id(struct kobject *kobj, char *buf, loff_t off, siz | |||
120 | 116 | ||
121 | memcpy(buf, (u8 *)&sl->reg_num, count); | 117 | memcpy(buf, (u8 *)&sl->reg_num, count); |
122 | } | 118 | } |
123 | atomic_dec(&sl->refcnt); | ||
124 | 119 | ||
125 | return count; | 120 | return count; |
126 | } | 121 | } |
@@ -139,7 +134,63 @@ static struct bin_attribute w1_slave_attr_bin_id = { | |||
139 | }; | 134 | }; |
140 | 135 | ||
141 | /* Default family */ | 136 | /* Default family */ |
142 | static struct w1_family w1_default_family; | 137 | |
138 | static ssize_t w1_default_write(struct kobject *kobj, char *buf, loff_t off, size_t count) | ||
139 | { | ||
140 | struct w1_slave *sl = kobj_to_w1_slave(kobj); | ||
141 | |||
142 | mutex_lock(&sl->master->mutex); | ||
143 | if (w1_reset_select_slave(sl)) { | ||
144 | count = 0; | ||
145 | goto out_up; | ||
146 | } | ||
147 | |||
148 | w1_write_block(sl->master, buf, count); | ||
149 | |||
150 | out_up: | ||
151 | mutex_unlock(&sl->master->mutex); | ||
152 | return count; | ||
153 | } | ||
154 | |||
155 | static ssize_t w1_default_read(struct kobject *kobj, char *buf, loff_t off, size_t count) | ||
156 | { | ||
157 | struct w1_slave *sl = kobj_to_w1_slave(kobj); | ||
158 | |||
159 | mutex_lock(&sl->master->mutex); | ||
160 | w1_read_block(sl->master, buf, count); | ||
161 | mutex_unlock(&sl->master->mutex); | ||
162 | return count; | ||
163 | } | ||
164 | |||
165 | static struct bin_attribute w1_default_attr = { | ||
166 | .attr = { | ||
167 | .name = "rw", | ||
168 | .mode = S_IRUGO | S_IWUSR, | ||
169 | .owner = THIS_MODULE, | ||
170 | }, | ||
171 | .size = PAGE_SIZE, | ||
172 | .read = w1_default_read, | ||
173 | .write = w1_default_write, | ||
174 | }; | ||
175 | |||
176 | static int w1_default_add_slave(struct w1_slave *sl) | ||
177 | { | ||
178 | return sysfs_create_bin_file(&sl->dev.kobj, &w1_default_attr); | ||
179 | } | ||
180 | |||
181 | static void w1_default_remove_slave(struct w1_slave *sl) | ||
182 | { | ||
183 | sysfs_remove_bin_file(&sl->dev.kobj, &w1_default_attr); | ||
184 | } | ||
185 | |||
186 | static struct w1_family_ops w1_default_fops = { | ||
187 | .add_slave = w1_default_add_slave, | ||
188 | .remove_slave = w1_default_remove_slave, | ||
189 | }; | ||
190 | |||
191 | static struct w1_family w1_default_family = { | ||
192 | .fops = &w1_default_fops, | ||
193 | }; | ||
143 | 194 | ||
144 | static int w1_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size); | 195 | static int w1_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size); |
145 | 196 | ||
@@ -183,12 +234,9 @@ static ssize_t w1_master_attribute_show_name(struct device *dev, struct device_a | |||
183 | struct w1_master *md = dev_to_w1_master(dev); | 234 | struct w1_master *md = dev_to_w1_master(dev); |
184 | ssize_t count; | 235 | ssize_t count; |
185 | 236 | ||
186 | if (down_interruptible (&md->mutex)) | 237 | mutex_lock(&md->mutex); |
187 | return -EBUSY; | ||
188 | |||
189 | count = sprintf(buf, "%s\n", md->name); | 238 | count = sprintf(buf, "%s\n", md->name); |
190 | 239 | mutex_unlock(&md->mutex); | |
191 | up(&md->mutex); | ||
192 | 240 | ||
193 | return count; | 241 | return count; |
194 | } | 242 | } |
@@ -199,12 +247,9 @@ static ssize_t w1_master_attribute_store_search(struct device * dev, | |||
199 | { | 247 | { |
200 | struct w1_master *md = dev_to_w1_master(dev); | 248 | struct w1_master *md = dev_to_w1_master(dev); |
201 | 249 | ||
202 | if (down_interruptible (&md->mutex)) | 250 | mutex_lock(&md->mutex); |
203 | return -EBUSY; | ||
204 | |||
205 | md->search_count = simple_strtol(buf, NULL, 0); | 251 | md->search_count = simple_strtol(buf, NULL, 0); |
206 | 252 | mutex_unlock(&md->mutex); | |
207 | up(&md->mutex); | ||
208 | 253 | ||
209 | return count; | 254 | return count; |
210 | } | 255 | } |
@@ -216,12 +261,9 @@ static ssize_t w1_master_attribute_show_search(struct device *dev, | |||
216 | struct w1_master *md = dev_to_w1_master(dev); | 261 | struct w1_master *md = dev_to_w1_master(dev); |
217 | ssize_t count; | 262 | ssize_t count; |
218 | 263 | ||
219 | if (down_interruptible (&md->mutex)) | 264 | mutex_lock(&md->mutex); |
220 | return -EBUSY; | ||
221 | |||
222 | count = sprintf(buf, "%d\n", md->search_count); | 265 | count = sprintf(buf, "%d\n", md->search_count); |
223 | 266 | mutex_unlock(&md->mutex); | |
224 | up(&md->mutex); | ||
225 | 267 | ||
226 | return count; | 268 | return count; |
227 | } | 269 | } |
@@ -231,12 +273,9 @@ static ssize_t w1_master_attribute_show_pointer(struct device *dev, struct devic | |||
231 | struct w1_master *md = dev_to_w1_master(dev); | 273 | struct w1_master *md = dev_to_w1_master(dev); |
232 | ssize_t count; | 274 | ssize_t count; |
233 | 275 | ||
234 | if (down_interruptible(&md->mutex)) | 276 | mutex_lock(&md->mutex); |
235 | return -EBUSY; | ||
236 | |||
237 | count = sprintf(buf, "0x%p\n", md->bus_master); | 277 | count = sprintf(buf, "0x%p\n", md->bus_master); |
238 | 278 | mutex_unlock(&md->mutex); | |
239 | up(&md->mutex); | ||
240 | return count; | 279 | return count; |
241 | } | 280 | } |
242 | 281 | ||
@@ -252,12 +291,9 @@ static ssize_t w1_master_attribute_show_max_slave_count(struct device *dev, stru | |||
252 | struct w1_master *md = dev_to_w1_master(dev); | 291 | struct w1_master *md = dev_to_w1_master(dev); |
253 | ssize_t count; | 292 | ssize_t count; |
254 | 293 | ||
255 | if (down_interruptible(&md->mutex)) | 294 | mutex_lock(&md->mutex); |
256 | return -EBUSY; | ||
257 | |||
258 | count = sprintf(buf, "%d\n", md->max_slave_count); | 295 | count = sprintf(buf, "%d\n", md->max_slave_count); |
259 | 296 | mutex_unlock(&md->mutex); | |
260 | up(&md->mutex); | ||
261 | return count; | 297 | return count; |
262 | } | 298 | } |
263 | 299 | ||
@@ -266,12 +302,9 @@ static ssize_t w1_master_attribute_show_attempts(struct device *dev, struct devi | |||
266 | struct w1_master *md = dev_to_w1_master(dev); | 302 | struct w1_master *md = dev_to_w1_master(dev); |
267 | ssize_t count; | 303 | ssize_t count; |
268 | 304 | ||
269 | if (down_interruptible(&md->mutex)) | 305 | mutex_lock(&md->mutex); |
270 | return -EBUSY; | ||
271 | |||
272 | count = sprintf(buf, "%lu\n", md->attempts); | 306 | count = sprintf(buf, "%lu\n", md->attempts); |
273 | 307 | mutex_unlock(&md->mutex); | |
274 | up(&md->mutex); | ||
275 | return count; | 308 | return count; |
276 | } | 309 | } |
277 | 310 | ||
@@ -280,12 +313,9 @@ static ssize_t w1_master_attribute_show_slave_count(struct device *dev, struct d | |||
280 | struct w1_master *md = dev_to_w1_master(dev); | 313 | struct w1_master *md = dev_to_w1_master(dev); |
281 | ssize_t count; | 314 | ssize_t count; |
282 | 315 | ||
283 | if (down_interruptible(&md->mutex)) | 316 | mutex_lock(&md->mutex); |
284 | return -EBUSY; | ||
285 | |||
286 | count = sprintf(buf, "%d\n", md->slave_count); | 317 | count = sprintf(buf, "%d\n", md->slave_count); |
287 | 318 | mutex_unlock(&md->mutex); | |
288 | up(&md->mutex); | ||
289 | return count; | 319 | return count; |
290 | } | 320 | } |
291 | 321 | ||
@@ -294,8 +324,7 @@ static ssize_t w1_master_attribute_show_slaves(struct device *dev, struct device | |||
294 | struct w1_master *md = dev_to_w1_master(dev); | 324 | struct w1_master *md = dev_to_w1_master(dev); |
295 | int c = PAGE_SIZE; | 325 | int c = PAGE_SIZE; |
296 | 326 | ||
297 | if (down_interruptible(&md->mutex)) | 327 | mutex_lock(&md->mutex); |
298 | return -EBUSY; | ||
299 | 328 | ||
300 | if (md->slave_count == 0) | 329 | if (md->slave_count == 0) |
301 | c -= snprintf(buf + PAGE_SIZE - c, c, "not found.\n"); | 330 | c -= snprintf(buf + PAGE_SIZE - c, c, "not found.\n"); |
@@ -310,7 +339,7 @@ static ssize_t w1_master_attribute_show_slaves(struct device *dev, struct device | |||
310 | } | 339 | } |
311 | } | 340 | } |
312 | 341 | ||
313 | up(&md->mutex); | 342 | mutex_unlock(&md->mutex); |
314 | 343 | ||
315 | return PAGE_SIZE - c; | 344 | return PAGE_SIZE - c; |
316 | } | 345 | } |
@@ -362,7 +391,8 @@ static void w1_destroy_master_attributes(struct w1_master *master) | |||
362 | } | 391 | } |
363 | 392 | ||
364 | #ifdef CONFIG_HOTPLUG | 393 | #ifdef CONFIG_HOTPLUG |
365 | static int w1_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size) | 394 | static int w1_uevent(struct device *dev, char **envp, int num_envp, |
395 | char *buffer, int buffer_size) | ||
366 | { | 396 | { |
367 | struct w1_master *md = NULL; | 397 | struct w1_master *md = NULL; |
368 | struct w1_slave *sl = NULL; | 398 | struct w1_slave *sl = NULL; |
@@ -382,7 +412,8 @@ static int w1_uevent(struct device *dev, char **envp, int num_envp, char *buffer | |||
382 | return -EINVAL; | 412 | return -EINVAL; |
383 | } | 413 | } |
384 | 414 | ||
385 | dev_dbg(dev, "Hotplug event for %s %s, bus_id=%s.\n", event_owner, name, dev->bus_id); | 415 | dev_dbg(dev, "Hotplug event for %s %s, bus_id=%s.\n", |
416 | event_owner, name, dev->bus_id); | ||
386 | 417 | ||
387 | if (dev->driver != &w1_slave_driver || !sl) | 418 | if (dev->driver != &w1_slave_driver || !sl) |
388 | return 0; | 419 | return 0; |
@@ -401,7 +432,8 @@ static int w1_uevent(struct device *dev, char **envp, int num_envp, char *buffer | |||
401 | return 0; | 432 | return 0; |
402 | }; | 433 | }; |
403 | #else | 434 | #else |
404 | static int w1_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size) | 435 | static int w1_uevent(struct device *dev, char **envp, int num_envp, |
436 | char *buffer, int buffer_size) | ||
405 | { | 437 | { |
406 | return 0; | 438 | return 0; |
407 | } | 439 | } |
@@ -425,7 +457,8 @@ static int __w1_attach_slave_device(struct w1_slave *sl) | |||
425 | (unsigned int) sl->reg_num.family, | 457 | (unsigned int) sl->reg_num.family, |
426 | (unsigned long long) sl->reg_num.id); | 458 | (unsigned long long) sl->reg_num.id); |
427 | 459 | ||
428 | dev_dbg(&sl->dev, "%s: registering %s as %p.\n", __func__, &sl->dev.bus_id[0]); | 460 | dev_dbg(&sl->dev, "%s: registering %s as %p.\n", __func__, |
461 | &sl->dev.bus_id[0]); | ||
429 | 462 | ||
430 | err = device_register(&sl->dev); | 463 | err = device_register(&sl->dev); |
431 | if (err < 0) { | 464 | if (err < 0) { |
@@ -496,6 +529,7 @@ static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn) | |||
496 | sl->master = dev; | 529 | sl->master = dev; |
497 | set_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags); | 530 | set_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags); |
498 | 531 | ||
532 | memset(&msg, 0, sizeof(msg)); | ||
499 | memcpy(&sl->reg_num, rn, sizeof(sl->reg_num)); | 533 | memcpy(&sl->reg_num, rn, sizeof(sl->reg_num)); |
500 | atomic_set(&sl->refcnt, 0); | 534 | atomic_set(&sl->refcnt, 0); |
501 | init_completion(&sl->released); | 535 | init_completion(&sl->released); |
@@ -526,7 +560,7 @@ static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn) | |||
526 | sl->ttl = dev->slave_ttl; | 560 | sl->ttl = dev->slave_ttl; |
527 | dev->slave_count++; | 561 | dev->slave_count++; |
528 | 562 | ||
529 | memcpy(&msg.id.id, rn, sizeof(msg.id.id)); | 563 | memcpy(msg.id.id, rn, sizeof(msg.id)); |
530 | msg.type = W1_SLAVE_ADD; | 564 | msg.type = W1_SLAVE_ADD; |
531 | w1_netlink_send(dev, &msg); | 565 | w1_netlink_send(dev, &msg); |
532 | 566 | ||
@@ -544,7 +578,8 @@ static void w1_slave_detach(struct w1_slave *sl) | |||
544 | if (sl->family->fops && sl->family->fops->remove_slave) | 578 | if (sl->family->fops && sl->family->fops->remove_slave) |
545 | sl->family->fops->remove_slave(sl); | 579 | sl->family->fops->remove_slave(sl); |
546 | 580 | ||
547 | memcpy(&msg.id.id, &sl->reg_num, sizeof(msg.id.id)); | 581 | memset(&msg, 0, sizeof(msg)); |
582 | memcpy(msg.id.id, &sl->reg_num, sizeof(msg.id)); | ||
548 | msg.type = W1_SLAVE_REMOVE; | 583 | msg.type = W1_SLAVE_REMOVE; |
549 | w1_netlink_send(sl->master, &msg); | 584 | w1_netlink_send(sl->master, &msg); |
550 | 585 | ||
@@ -561,7 +596,7 @@ static struct w1_master *w1_search_master(void *data) | |||
561 | struct w1_master *dev; | 596 | struct w1_master *dev; |
562 | int found = 0; | 597 | int found = 0; |
563 | 598 | ||
564 | spin_lock_bh(&w1_mlock); | 599 | mutex_lock(&w1_mlock); |
565 | list_for_each_entry(dev, &w1_masters, w1_master_entry) { | 600 | list_for_each_entry(dev, &w1_masters, w1_master_entry) { |
566 | if (dev->bus_master->data == data) { | 601 | if (dev->bus_master->data == data) { |
567 | found = 1; | 602 | found = 1; |
@@ -569,22 +604,69 @@ static struct w1_master *w1_search_master(void *data) | |||
569 | break; | 604 | break; |
570 | } | 605 | } |
571 | } | 606 | } |
572 | spin_unlock_bh(&w1_mlock); | 607 | mutex_unlock(&w1_mlock); |
608 | |||
609 | return (found)?dev:NULL; | ||
610 | } | ||
611 | |||
612 | struct w1_master *w1_search_master_id(u32 id) | ||
613 | { | ||
614 | struct w1_master *dev; | ||
615 | int found = 0; | ||
616 | |||
617 | mutex_lock(&w1_mlock); | ||
618 | list_for_each_entry(dev, &w1_masters, w1_master_entry) { | ||
619 | if (dev->id == id) { | ||
620 | found = 1; | ||
621 | atomic_inc(&dev->refcnt); | ||
622 | break; | ||
623 | } | ||
624 | } | ||
625 | mutex_unlock(&w1_mlock); | ||
573 | 626 | ||
574 | return (found)?dev:NULL; | 627 | return (found)?dev:NULL; |
575 | } | 628 | } |
576 | 629 | ||
630 | struct w1_slave *w1_search_slave(struct w1_reg_num *id) | ||
631 | { | ||
632 | struct w1_master *dev; | ||
633 | struct w1_slave *sl = NULL; | ||
634 | int found = 0; | ||
635 | |||
636 | mutex_lock(&w1_mlock); | ||
637 | list_for_each_entry(dev, &w1_masters, w1_master_entry) { | ||
638 | mutex_lock(&dev->mutex); | ||
639 | list_for_each_entry(sl, &dev->slist, w1_slave_entry) { | ||
640 | if (sl->reg_num.family == id->family && | ||
641 | sl->reg_num.id == id->id && | ||
642 | sl->reg_num.crc == id->crc) { | ||
643 | found = 1; | ||
644 | atomic_inc(&dev->refcnt); | ||
645 | atomic_inc(&sl->refcnt); | ||
646 | break; | ||
647 | } | ||
648 | } | ||
649 | mutex_unlock(&dev->mutex); | ||
650 | |||
651 | if (found) | ||
652 | break; | ||
653 | } | ||
654 | mutex_unlock(&w1_mlock); | ||
655 | |||
656 | return (found)?sl:NULL; | ||
657 | } | ||
658 | |||
577 | void w1_reconnect_slaves(struct w1_family *f) | 659 | void w1_reconnect_slaves(struct w1_family *f) |
578 | { | 660 | { |
579 | struct w1_master *dev; | 661 | struct w1_master *dev; |
580 | 662 | ||
581 | spin_lock_bh(&w1_mlock); | 663 | mutex_lock(&w1_mlock); |
582 | list_for_each_entry(dev, &w1_masters, w1_master_entry) { | 664 | list_for_each_entry(dev, &w1_masters, w1_master_entry) { |
583 | dev_dbg(&dev->dev, "Reconnecting slaves in %s into new family %02x.\n", | 665 | dev_dbg(&dev->dev, "Reconnecting slaves in %s into new family %02x.\n", |
584 | dev->name, f->fid); | 666 | dev->name, f->fid); |
585 | set_bit(W1_MASTER_NEED_RECONNECT, &dev->flags); | 667 | set_bit(W1_MASTER_NEED_RECONNECT, &dev->flags); |
586 | } | 668 | } |
587 | spin_unlock_bh(&w1_mlock); | 669 | mutex_unlock(&w1_mlock); |
588 | } | 670 | } |
589 | 671 | ||
590 | static void w1_slave_found(void *data, u64 rn) | 672 | static void w1_slave_found(void *data, u64 rn) |
@@ -646,7 +728,7 @@ static void w1_slave_found(void *data, u64 rn) | |||
646 | * @dev The master device to search | 728 | * @dev The master device to search |
647 | * @cb Function to call when a device is found | 729 | * @cb Function to call when a device is found |
648 | */ | 730 | */ |
649 | void w1_search(struct w1_master *dev, w1_slave_found_callback cb) | 731 | void w1_search(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb) |
650 | { | 732 | { |
651 | u64 last_rn, rn, tmp64; | 733 | u64 last_rn, rn, tmp64; |
652 | int i, slave_count = 0; | 734 | int i, slave_count = 0; |
@@ -677,7 +759,7 @@ void w1_search(struct w1_master *dev, w1_slave_found_callback cb) | |||
677 | } | 759 | } |
678 | 760 | ||
679 | /* Start the search */ | 761 | /* Start the search */ |
680 | w1_write_8(dev, W1_SEARCH); | 762 | w1_write_8(dev, search_type); |
681 | for (i = 0; i < 64; ++i) { | 763 | for (i = 0; i < 64; ++i) { |
682 | /* Determine the direction/search bit */ | 764 | /* Determine the direction/search bit */ |
683 | if (i == desc_bit) | 765 | if (i == desc_bit) |
@@ -739,23 +821,23 @@ static int w1_control(void *data) | |||
739 | if (kthread_should_stop() || test_bit(W1_MASTER_NEED_EXIT, &dev->flags)) { | 821 | if (kthread_should_stop() || test_bit(W1_MASTER_NEED_EXIT, &dev->flags)) { |
740 | set_bit(W1_MASTER_NEED_EXIT, &dev->flags); | 822 | set_bit(W1_MASTER_NEED_EXIT, &dev->flags); |
741 | 823 | ||
742 | spin_lock(&w1_mlock); | 824 | mutex_lock(&w1_mlock); |
743 | list_del(&dev->w1_master_entry); | 825 | list_del(&dev->w1_master_entry); |
744 | spin_unlock(&w1_mlock); | 826 | mutex_unlock(&w1_mlock); |
745 | 827 | ||
746 | down(&dev->mutex); | 828 | mutex_lock(&dev->mutex); |
747 | list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) { | 829 | list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) { |
748 | w1_slave_detach(sl); | 830 | w1_slave_detach(sl); |
749 | } | 831 | } |
750 | w1_destroy_master_attributes(dev); | 832 | w1_destroy_master_attributes(dev); |
751 | up(&dev->mutex); | 833 | mutex_unlock(&dev->mutex); |
752 | atomic_dec(&dev->refcnt); | 834 | atomic_dec(&dev->refcnt); |
753 | continue; | 835 | continue; |
754 | } | 836 | } |
755 | 837 | ||
756 | if (test_bit(W1_MASTER_NEED_RECONNECT, &dev->flags)) { | 838 | if (test_bit(W1_MASTER_NEED_RECONNECT, &dev->flags)) { |
757 | dev_dbg(&dev->dev, "Reconnecting slaves in device %s.\n", dev->name); | 839 | dev_dbg(&dev->dev, "Reconnecting slaves in device %s.\n", dev->name); |
758 | down(&dev->mutex); | 840 | mutex_lock(&dev->mutex); |
759 | list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) { | 841 | list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) { |
760 | if (sl->family->fid == W1_FAMILY_DEFAULT) { | 842 | if (sl->family->fid == W1_FAMILY_DEFAULT) { |
761 | struct w1_reg_num rn; | 843 | struct w1_reg_num rn; |
@@ -768,7 +850,7 @@ static int w1_control(void *data) | |||
768 | } | 850 | } |
769 | dev_dbg(&dev->dev, "Reconnecting slaves in device %s has been finished.\n", dev->name); | 851 | dev_dbg(&dev->dev, "Reconnecting slaves in device %s has been finished.\n", dev->name); |
770 | clear_bit(W1_MASTER_NEED_RECONNECT, &dev->flags); | 852 | clear_bit(W1_MASTER_NEED_RECONNECT, &dev->flags); |
771 | up(&dev->mutex); | 853 | mutex_unlock(&dev->mutex); |
772 | } | 854 | } |
773 | } | 855 | } |
774 | } | 856 | } |
@@ -776,10 +858,31 @@ static int w1_control(void *data) | |||
776 | return 0; | 858 | return 0; |
777 | } | 859 | } |
778 | 860 | ||
861 | void w1_search_process(struct w1_master *dev, u8 search_type) | ||
862 | { | ||
863 | struct w1_slave *sl, *sln; | ||
864 | |||
865 | list_for_each_entry(sl, &dev->slist, w1_slave_entry) | ||
866 | clear_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags); | ||
867 | |||
868 | w1_search_devices(dev, search_type, w1_slave_found); | ||
869 | |||
870 | list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) { | ||
871 | if (!test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags) && !--sl->ttl) { | ||
872 | w1_slave_detach(sl); | ||
873 | |||
874 | dev->slave_count--; | ||
875 | } else if (test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags)) | ||
876 | sl->ttl = dev->slave_ttl; | ||
877 | } | ||
878 | |||
879 | if (dev->search_count > 0) | ||
880 | dev->search_count--; | ||
881 | } | ||
882 | |||
779 | int w1_process(void *data) | 883 | int w1_process(void *data) |
780 | { | 884 | { |
781 | struct w1_master *dev = (struct w1_master *) data; | 885 | struct w1_master *dev = (struct w1_master *) data; |
782 | struct w1_slave *sl, *sln; | ||
783 | 886 | ||
784 | while (!kthread_should_stop() && !test_bit(W1_MASTER_NEED_EXIT, &dev->flags)) { | 887 | while (!kthread_should_stop() && !test_bit(W1_MASTER_NEED_EXIT, &dev->flags)) { |
785 | try_to_freeze(); | 888 | try_to_freeze(); |
@@ -794,27 +897,9 @@ int w1_process(void *data) | |||
794 | if (dev->search_count == 0) | 897 | if (dev->search_count == 0) |
795 | continue; | 898 | continue; |
796 | 899 | ||
797 | if (down_interruptible(&dev->mutex)) | 900 | mutex_lock(&dev->mutex); |
798 | continue; | 901 | w1_search_process(dev, W1_SEARCH); |
799 | 902 | mutex_unlock(&dev->mutex); | |
800 | list_for_each_entry(sl, &dev->slist, w1_slave_entry) | ||
801 | clear_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags); | ||
802 | |||
803 | w1_search_devices(dev, w1_slave_found); | ||
804 | |||
805 | list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) { | ||
806 | if (!test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags) && !--sl->ttl) { | ||
807 | w1_slave_detach(sl); | ||
808 | |||
809 | dev->slave_count--; | ||
810 | } else if (test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags)) | ||
811 | sl->ttl = dev->slave_ttl; | ||
812 | } | ||
813 | |||
814 | if (dev->search_count > 0) | ||
815 | dev->search_count--; | ||
816 | |||
817 | up(&dev->mutex); | ||
818 | } | 903 | } |
819 | 904 | ||
820 | atomic_dec(&dev->refcnt); | 905 | atomic_dec(&dev->refcnt); |
@@ -828,6 +913,8 @@ static int w1_init(void) | |||
828 | 913 | ||
829 | printk(KERN_INFO "Driver for 1-wire Dallas network protocol.\n"); | 914 | printk(KERN_INFO "Driver for 1-wire Dallas network protocol.\n"); |
830 | 915 | ||
916 | w1_init_netlink(); | ||
917 | |||
831 | retval = bus_register(&w1_bus_type); | 918 | retval = bus_register(&w1_bus_type); |
832 | if (retval) { | 919 | if (retval) { |
833 | printk(KERN_ERR "Failed to register bus. err=%d.\n", retval); | 920 | printk(KERN_ERR "Failed to register bus. err=%d.\n", retval); |
@@ -880,6 +967,8 @@ static void w1_fini(void) | |||
880 | list_for_each_entry(dev, &w1_masters, w1_master_entry) | 967 | list_for_each_entry(dev, &w1_masters, w1_master_entry) |
881 | __w1_remove_master_device(dev); | 968 | __w1_remove_master_device(dev); |
882 | 969 | ||
970 | w1_fini_netlink(); | ||
971 | |||
883 | kthread_stop(w1_control_thread); | 972 | kthread_stop(w1_control_thread); |
884 | 973 | ||
885 | driver_unregister(&w1_slave_driver); | 974 | driver_unregister(&w1_slave_driver); |
diff --git a/drivers/w1/w1.h b/drivers/w1/w1.h index 56980505e6c4..f1df5343f4ad 100644 --- a/drivers/w1/w1.h +++ b/drivers/w1/w1.h | |||
@@ -41,10 +41,7 @@ struct w1_reg_num | |||
41 | 41 | ||
42 | #include <linux/completion.h> | 42 | #include <linux/completion.h> |
43 | #include <linux/device.h> | 43 | #include <linux/device.h> |
44 | 44 | #include <linux/mutex.h> | |
45 | #include <net/sock.h> | ||
46 | |||
47 | #include <asm/semaphore.h> | ||
48 | 45 | ||
49 | #include "w1_family.h" | 46 | #include "w1_family.h" |
50 | 47 | ||
@@ -52,7 +49,7 @@ struct w1_reg_num | |||
52 | #define W1_SLAVE_DATA_SIZE 128 | 49 | #define W1_SLAVE_DATA_SIZE 128 |
53 | 50 | ||
54 | #define W1_SEARCH 0xF0 | 51 | #define W1_SEARCH 0xF0 |
55 | #define W1_CONDITIONAL_SEARCH 0xEC | 52 | #define W1_ALARM_SEARCH 0xEC |
56 | #define W1_CONVERT_TEMP 0x44 | 53 | #define W1_CONVERT_TEMP 0x44 |
57 | #define W1_SKIP_ROM 0xCC | 54 | #define W1_SKIP_ROM 0xCC |
58 | #define W1_READ_SCRATCHPAD 0xBE | 55 | #define W1_READ_SCRATCHPAD 0xBE |
@@ -60,7 +57,7 @@ struct w1_reg_num | |||
60 | #define W1_READ_PSUPPLY 0xB4 | 57 | #define W1_READ_PSUPPLY 0xB4 |
61 | #define W1_MATCH_ROM 0x55 | 58 | #define W1_MATCH_ROM 0x55 |
62 | 59 | ||
63 | #define W1_SLAVE_ACTIVE (1<<0) | 60 | #define W1_SLAVE_ACTIVE 0 |
64 | 61 | ||
65 | struct w1_slave | 62 | struct w1_slave |
66 | { | 63 | { |
@@ -145,8 +142,8 @@ struct w1_bus_master | |||
145 | */ | 142 | */ |
146 | u8 (*reset_bus)(void *); | 143 | u8 (*reset_bus)(void *); |
147 | 144 | ||
148 | /** Really nice hardware can handles the ROM searches */ | 145 | /** Really nice hardware can handles the different types of ROM search */ |
149 | void (*search)(void *, w1_slave_found_callback); | 146 | void (*search)(void *, u8, w1_slave_found_callback); |
150 | }; | 147 | }; |
151 | 148 | ||
152 | #define W1_MASTER_NEED_EXIT 0 | 149 | #define W1_MASTER_NEED_EXIT 0 |
@@ -173,19 +170,30 @@ struct w1_master | |||
173 | long flags; | 170 | long flags; |
174 | 171 | ||
175 | struct task_struct *thread; | 172 | struct task_struct *thread; |
176 | struct semaphore mutex; | 173 | struct mutex mutex; |
177 | 174 | ||
178 | struct device_driver *driver; | 175 | struct device_driver *driver; |
179 | struct device dev; | 176 | struct device dev; |
180 | 177 | ||
181 | struct w1_bus_master *bus_master; | 178 | struct w1_bus_master *bus_master; |
182 | 179 | ||
183 | u32 seq, groups; | 180 | u32 seq; |
184 | struct sock *nls; | ||
185 | }; | 181 | }; |
186 | 182 | ||
187 | int w1_create_master_attributes(struct w1_master *); | 183 | int w1_create_master_attributes(struct w1_master *); |
188 | void w1_search(struct w1_master *dev, w1_slave_found_callback cb); | 184 | void w1_search(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb); |
185 | void w1_search_devices(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb); | ||
186 | struct w1_slave *w1_search_slave(struct w1_reg_num *id); | ||
187 | void w1_search_process(struct w1_master *dev, u8 search_type); | ||
188 | struct w1_master *w1_search_master_id(u32 id); | ||
189 | |||
190 | u8 w1_triplet(struct w1_master *dev, int bdir); | ||
191 | void w1_write_8(struct w1_master *, u8); | ||
192 | int w1_reset_bus(struct w1_master *); | ||
193 | u8 w1_calc_crc8(u8 *, int); | ||
194 | void w1_write_block(struct w1_master *, const u8 *, int); | ||
195 | u8 w1_read_block(struct w1_master *, u8 *, int); | ||
196 | int w1_reset_select_slave(struct w1_slave *sl); | ||
189 | 197 | ||
190 | static inline struct w1_slave* dev_to_w1_slave(struct device *dev) | 198 | static inline struct w1_slave* dev_to_w1_slave(struct device *dev) |
191 | { | 199 | { |
@@ -202,15 +210,14 @@ static inline struct w1_master* dev_to_w1_master(struct device *dev) | |||
202 | return container_of(dev, struct w1_master, dev); | 210 | return container_of(dev, struct w1_master, dev); |
203 | } | 211 | } |
204 | 212 | ||
213 | extern struct device_driver w1_master_driver; | ||
214 | extern struct device w1_master_device; | ||
205 | extern int w1_max_slave_count; | 215 | extern int w1_max_slave_count; |
206 | extern int w1_max_slave_ttl; | 216 | extern int w1_max_slave_ttl; |
207 | extern spinlock_t w1_mlock; | ||
208 | extern struct list_head w1_masters; | 217 | extern struct list_head w1_masters; |
209 | extern struct device_driver w1_master_driver; | 218 | extern struct mutex w1_mlock; |
210 | extern struct device w1_master_device; | ||
211 | 219 | ||
212 | int w1_process(void *data); | 220 | extern int w1_process(void *); |
213 | void w1_reconnect_slaves(struct w1_family *f); | ||
214 | 221 | ||
215 | #endif /* __KERNEL__ */ | 222 | #endif /* __KERNEL__ */ |
216 | 223 | ||
diff --git a/drivers/w1/w1_family.c b/drivers/w1/w1_family.c index 0e32c114f906..a3c95bd6890a 100644 --- a/drivers/w1/w1_family.c +++ b/drivers/w1/w1_family.c | |||
@@ -107,6 +107,12 @@ struct w1_family * w1_family_registered(u8 fid) | |||
107 | return (ret) ? f : NULL; | 107 | return (ret) ? f : NULL; |
108 | } | 108 | } |
109 | 109 | ||
110 | static void __w1_family_put(struct w1_family *f) | ||
111 | { | ||
112 | if (atomic_dec_and_test(&f->refcnt)) | ||
113 | f->need_exit = 1; | ||
114 | } | ||
115 | |||
110 | void w1_family_put(struct w1_family *f) | 116 | void w1_family_put(struct w1_family *f) |
111 | { | 117 | { |
112 | spin_lock(&w1_flock); | 118 | spin_lock(&w1_flock); |
@@ -114,19 +120,14 @@ void w1_family_put(struct w1_family *f) | |||
114 | spin_unlock(&w1_flock); | 120 | spin_unlock(&w1_flock); |
115 | } | 121 | } |
116 | 122 | ||
117 | void __w1_family_put(struct w1_family *f) | 123 | #if 0 |
118 | { | ||
119 | if (atomic_dec_and_test(&f->refcnt)) | ||
120 | f->need_exit = 1; | ||
121 | } | ||
122 | |||
123 | void w1_family_get(struct w1_family *f) | 124 | void w1_family_get(struct w1_family *f) |
124 | { | 125 | { |
125 | spin_lock(&w1_flock); | 126 | spin_lock(&w1_flock); |
126 | __w1_family_get(f); | 127 | __w1_family_get(f); |
127 | spin_unlock(&w1_flock); | 128 | spin_unlock(&w1_flock); |
128 | |||
129 | } | 129 | } |
130 | #endif /* 0 */ | ||
130 | 131 | ||
131 | void __w1_family_get(struct w1_family *f) | 132 | void __w1_family_get(struct w1_family *f) |
132 | { | 133 | { |
@@ -135,8 +136,5 @@ void __w1_family_get(struct w1_family *f) | |||
135 | smp_mb__after_atomic_inc(); | 136 | smp_mb__after_atomic_inc(); |
136 | } | 137 | } |
137 | 138 | ||
138 | EXPORT_SYMBOL(w1_family_get); | ||
139 | EXPORT_SYMBOL(w1_family_put); | ||
140 | EXPORT_SYMBOL(w1_family_registered); | ||
141 | EXPORT_SYMBOL(w1_unregister_family); | 139 | EXPORT_SYMBOL(w1_unregister_family); |
142 | EXPORT_SYMBOL(w1_register_family); | 140 | EXPORT_SYMBOL(w1_register_family); |
diff --git a/drivers/w1/w1_family.h b/drivers/w1/w1_family.h index 2ca0489c716a..1e2ac40c2c14 100644 --- a/drivers/w1/w1_family.h +++ b/drivers/w1/w1_family.h | |||
@@ -57,12 +57,11 @@ struct w1_family | |||
57 | 57 | ||
58 | extern spinlock_t w1_flock; | 58 | extern spinlock_t w1_flock; |
59 | 59 | ||
60 | void w1_family_get(struct w1_family *); | ||
61 | void w1_family_put(struct w1_family *); | 60 | void w1_family_put(struct w1_family *); |
62 | void __w1_family_get(struct w1_family *); | 61 | void __w1_family_get(struct w1_family *); |
63 | void __w1_family_put(struct w1_family *); | ||
64 | struct w1_family * w1_family_registered(u8); | 62 | struct w1_family * w1_family_registered(u8); |
65 | void w1_unregister_family(struct w1_family *); | 63 | void w1_unregister_family(struct w1_family *); |
66 | int w1_register_family(struct w1_family *); | 64 | int w1_register_family(struct w1_family *); |
65 | void w1_reconnect_slaves(struct w1_family *f); | ||
67 | 66 | ||
68 | #endif /* __W1_FAMILY_H */ | 67 | #endif /* __W1_FAMILY_H */ |
diff --git a/drivers/w1/w1_int.c b/drivers/w1/w1_int.c index 68565aacec7b..357a2e0f637a 100644 --- a/drivers/w1/w1_int.c +++ b/drivers/w1/w1_int.c | |||
@@ -65,7 +65,7 @@ static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl, | |||
65 | atomic_set(&dev->refcnt, 2); | 65 | atomic_set(&dev->refcnt, 2); |
66 | 66 | ||
67 | INIT_LIST_HEAD(&dev->slist); | 67 | INIT_LIST_HEAD(&dev->slist); |
68 | init_MUTEX(&dev->mutex); | 68 | mutex_init(&dev->mutex); |
69 | 69 | ||
70 | memcpy(&dev->dev, device, sizeof(struct device)); | 70 | memcpy(&dev->dev, device, sizeof(struct device)); |
71 | snprintf(dev->dev.bus_id, sizeof(dev->dev.bus_id), | 71 | snprintf(dev->dev.bus_id, sizeof(dev->dev.bus_id), |
@@ -74,16 +74,11 @@ static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl, | |||
74 | 74 | ||
75 | dev->driver = driver; | 75 | dev->driver = driver; |
76 | 76 | ||
77 | dev->groups = 1; | ||
78 | dev->seq = 1; | 77 | dev->seq = 1; |
79 | dev_init_netlink(dev); | ||
80 | 78 | ||
81 | err = device_register(&dev->dev); | 79 | err = device_register(&dev->dev); |
82 | if (err) { | 80 | if (err) { |
83 | printk(KERN_ERR "Failed to register master device. err=%d\n", err); | 81 | printk(KERN_ERR "Failed to register master device. err=%d\n", err); |
84 | |||
85 | dev_fini_netlink(dev); | ||
86 | |||
87 | memset(dev, 0, sizeof(struct w1_master)); | 82 | memset(dev, 0, sizeof(struct w1_master)); |
88 | kfree(dev); | 83 | kfree(dev); |
89 | dev = NULL; | 84 | dev = NULL; |
@@ -131,12 +126,12 @@ int w1_add_master_device(struct w1_bus_master *master) | |||
131 | 126 | ||
132 | dev->initialized = 1; | 127 | dev->initialized = 1; |
133 | 128 | ||
134 | spin_lock(&w1_mlock); | 129 | mutex_lock(&w1_mlock); |
135 | list_add(&dev->w1_master_entry, &w1_masters); | 130 | list_add(&dev->w1_master_entry, &w1_masters); |
136 | spin_unlock(&w1_mlock); | 131 | mutex_unlock(&w1_mlock); |
137 | 132 | ||
133 | memset(&msg, 0, sizeof(msg)); | ||
138 | msg.id.mst.id = dev->id; | 134 | msg.id.mst.id = dev->id; |
139 | msg.id.mst.pid = dev->thread->pid; | ||
140 | msg.type = W1_MASTER_ADD; | 135 | msg.type = W1_MASTER_ADD; |
141 | w1_netlink_send(dev, &msg); | 136 | w1_netlink_send(dev, &msg); |
142 | 137 | ||
@@ -153,7 +148,6 @@ err_out_free_dev: | |||
153 | void __w1_remove_master_device(struct w1_master *dev) | 148 | void __w1_remove_master_device(struct w1_master *dev) |
154 | { | 149 | { |
155 | struct w1_netlink_msg msg; | 150 | struct w1_netlink_msg msg; |
156 | pid_t pid = dev->thread->pid; | ||
157 | 151 | ||
158 | set_bit(W1_MASTER_NEED_EXIT, &dev->flags); | 152 | set_bit(W1_MASTER_NEED_EXIT, &dev->flags); |
159 | kthread_stop(dev->thread); | 153 | kthread_stop(dev->thread); |
@@ -166,8 +160,8 @@ void __w1_remove_master_device(struct w1_master *dev) | |||
166 | flush_signals(current); | 160 | flush_signals(current); |
167 | } | 161 | } |
168 | 162 | ||
163 | memset(&msg, 0, sizeof(msg)); | ||
169 | msg.id.mst.id = dev->id; | 164 | msg.id.mst.id = dev->id; |
170 | msg.id.mst.pid = pid; | ||
171 | msg.type = W1_MASTER_REMOVE; | 165 | msg.type = W1_MASTER_REMOVE; |
172 | w1_netlink_send(dev, &msg); | 166 | w1_netlink_send(dev, &msg); |
173 | 167 | ||
diff --git a/drivers/w1/w1_io.c b/drivers/w1/w1_io.c index f7f7e8bec30e..30b6fbf83bd4 100644 --- a/drivers/w1/w1_io.c +++ b/drivers/w1/w1_io.c | |||
@@ -23,10 +23,10 @@ | |||
23 | 23 | ||
24 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
25 | #include <linux/moduleparam.h> | 25 | #include <linux/moduleparam.h> |
26 | #include <linux/module.h> | ||
26 | 27 | ||
27 | #include "w1.h" | 28 | #include "w1.h" |
28 | #include "w1_log.h" | 29 | #include "w1_log.h" |
29 | #include "w1_io.h" | ||
30 | 30 | ||
31 | static int w1_delay_parm = 1; | 31 | static int w1_delay_parm = 1; |
32 | module_param_named(delay_coef, w1_delay_parm, int, 0); | 32 | module_param_named(delay_coef, w1_delay_parm, int, 0); |
@@ -50,7 +50,7 @@ static u8 w1_crc8_table[] = { | |||
50 | 116, 42, 200, 150, 21, 75, 169, 247, 182, 232, 10, 84, 215, 137, 107, 53 | 50 | 116, 42, 200, 150, 21, 75, 169, 247, 182, 232, 10, 84, 215, 137, 107, 53 |
51 | }; | 51 | }; |
52 | 52 | ||
53 | void w1_delay(unsigned long tm) | 53 | static void w1_delay(unsigned long tm) |
54 | { | 54 | { |
55 | udelay(tm * w1_delay_parm); | 55 | udelay(tm * w1_delay_parm); |
56 | } | 56 | } |
@@ -61,7 +61,7 @@ static u8 w1_read_bit(struct w1_master *dev); | |||
61 | /** | 61 | /** |
62 | * Generates a write-0 or write-1 cycle and samples the level. | 62 | * Generates a write-0 or write-1 cycle and samples the level. |
63 | */ | 63 | */ |
64 | u8 w1_touch_bit(struct w1_master *dev, int bit) | 64 | static u8 w1_touch_bit(struct w1_master *dev, int bit) |
65 | { | 65 | { |
66 | if (dev->bus_master->touch_bit) | 66 | if (dev->bus_master->touch_bit) |
67 | return dev->bus_master->touch_bit(dev->bus_master->data, bit); | 67 | return dev->bus_master->touch_bit(dev->bus_master->data, bit); |
@@ -108,6 +108,7 @@ void w1_write_8(struct w1_master *dev, u8 byte) | |||
108 | for (i = 0; i < 8; ++i) | 108 | for (i = 0; i < 8; ++i) |
109 | w1_touch_bit(dev, (byte >> i) & 0x1); | 109 | w1_touch_bit(dev, (byte >> i) & 0x1); |
110 | } | 110 | } |
111 | EXPORT_SYMBOL_GPL(w1_write_8); | ||
111 | 112 | ||
112 | 113 | ||
113 | /** | 114 | /** |
@@ -176,7 +177,7 @@ u8 w1_triplet(struct w1_master *dev, int bdir) | |||
176 | * @param dev the master device | 177 | * @param dev the master device |
177 | * @return the byte read | 178 | * @return the byte read |
178 | */ | 179 | */ |
179 | u8 w1_read_8(struct w1_master * dev) | 180 | static u8 w1_read_8(struct w1_master * dev) |
180 | { | 181 | { |
181 | int i; | 182 | int i; |
182 | u8 res = 0; | 183 | u8 res = 0; |
@@ -208,6 +209,7 @@ void w1_write_block(struct w1_master *dev, const u8 *buf, int len) | |||
208 | for (i = 0; i < len; ++i) | 209 | for (i = 0; i < len; ++i) |
209 | w1_write_8(dev, buf[i]); | 210 | w1_write_8(dev, buf[i]); |
210 | } | 211 | } |
212 | EXPORT_SYMBOL_GPL(w1_write_block); | ||
211 | 213 | ||
212 | /** | 214 | /** |
213 | * Reads a series of bytes. | 215 | * Reads a series of bytes. |
@@ -232,6 +234,7 @@ u8 w1_read_block(struct w1_master *dev, u8 *buf, int len) | |||
232 | 234 | ||
233 | return ret; | 235 | return ret; |
234 | } | 236 | } |
237 | EXPORT_SYMBOL_GPL(w1_read_block); | ||
235 | 238 | ||
236 | /** | 239 | /** |
237 | * Issues a reset bus sequence. | 240 | * Issues a reset bus sequence. |
@@ -257,6 +260,7 @@ int w1_reset_bus(struct w1_master *dev) | |||
257 | 260 | ||
258 | return result; | 261 | return result; |
259 | } | 262 | } |
263 | EXPORT_SYMBOL_GPL(w1_reset_bus); | ||
260 | 264 | ||
261 | u8 w1_calc_crc8(u8 * data, int len) | 265 | u8 w1_calc_crc8(u8 * data, int len) |
262 | { | 266 | { |
@@ -267,14 +271,15 @@ u8 w1_calc_crc8(u8 * data, int len) | |||
267 | 271 | ||
268 | return crc; | 272 | return crc; |
269 | } | 273 | } |
274 | EXPORT_SYMBOL_GPL(w1_calc_crc8); | ||
270 | 275 | ||
271 | void w1_search_devices(struct w1_master *dev, w1_slave_found_callback cb) | 276 | void w1_search_devices(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb) |
272 | { | 277 | { |
273 | dev->attempts++; | 278 | dev->attempts++; |
274 | if (dev->bus_master->search) | 279 | if (dev->bus_master->search) |
275 | dev->bus_master->search(dev->bus_master->data, cb); | 280 | dev->bus_master->search(dev->bus_master->data, search_type, cb); |
276 | else | 281 | else |
277 | w1_search(dev, cb); | 282 | w1_search(dev, search_type, cb); |
278 | } | 283 | } |
279 | 284 | ||
280 | /** | 285 | /** |
@@ -299,14 +304,4 @@ int w1_reset_select_slave(struct w1_slave *sl) | |||
299 | } | 304 | } |
300 | return 0; | 305 | return 0; |
301 | } | 306 | } |
302 | 307 | EXPORT_SYMBOL_GPL(w1_reset_select_slave); | |
303 | EXPORT_SYMBOL(w1_touch_bit); | ||
304 | EXPORT_SYMBOL(w1_write_8); | ||
305 | EXPORT_SYMBOL(w1_read_8); | ||
306 | EXPORT_SYMBOL(w1_reset_bus); | ||
307 | EXPORT_SYMBOL(w1_calc_crc8); | ||
308 | EXPORT_SYMBOL(w1_delay); | ||
309 | EXPORT_SYMBOL(w1_read_block); | ||
310 | EXPORT_SYMBOL(w1_write_block); | ||
311 | EXPORT_SYMBOL(w1_search_devices); | ||
312 | EXPORT_SYMBOL(w1_reset_select_slave); | ||
diff --git a/drivers/w1/w1_io.h b/drivers/w1/w1_io.h index 232860184a29..9a76d2ad69c5 100644 --- a/drivers/w1/w1_io.h +++ b/drivers/w1/w1_io.h | |||
@@ -24,11 +24,8 @@ | |||
24 | 24 | ||
25 | #include "w1.h" | 25 | #include "w1.h" |
26 | 26 | ||
27 | void w1_delay(unsigned long); | ||
28 | u8 w1_touch_bit(struct w1_master *, int); | ||
29 | u8 w1_triplet(struct w1_master *dev, int bdir); | 27 | u8 w1_triplet(struct w1_master *dev, int bdir); |
30 | void w1_write_8(struct w1_master *, u8); | 28 | void w1_write_8(struct w1_master *, u8); |
31 | u8 w1_read_8(struct w1_master *); | ||
32 | int w1_reset_bus(struct w1_master *); | 29 | int w1_reset_bus(struct w1_master *); |
33 | u8 w1_calc_crc8(u8 *, int); | 30 | u8 w1_calc_crc8(u8 *, int); |
34 | void w1_write_block(struct w1_master *, const u8 *, int); | 31 | void w1_write_block(struct w1_master *, const u8 *, int); |
diff --git a/drivers/w1/w1_netlink.c b/drivers/w1/w1_netlink.c index 328645da7972..65c5ebd0787e 100644 --- a/drivers/w1/w1_netlink.c +++ b/drivers/w1/w1_netlink.c | |||
@@ -21,72 +21,225 @@ | |||
21 | 21 | ||
22 | #include <linux/skbuff.h> | 22 | #include <linux/skbuff.h> |
23 | #include <linux/netlink.h> | 23 | #include <linux/netlink.h> |
24 | #include <linux/connector.h> | ||
24 | 25 | ||
25 | #include "w1.h" | 26 | #include "w1.h" |
26 | #include "w1_log.h" | 27 | #include "w1_log.h" |
27 | #include "w1_netlink.h" | 28 | #include "w1_netlink.h" |
28 | 29 | ||
29 | #ifndef NETLINK_DISABLED | 30 | #if defined(CONFIG_W1_CON) && (defined(CONFIG_CONNECTOR) || (defined(CONFIG_CONNECTOR_MODULE) && defined(CONFIG_W1_MODULE))) |
30 | void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg) | 31 | void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg) |
31 | { | 32 | { |
32 | unsigned int size; | 33 | char buf[sizeof(struct cn_msg) + sizeof(struct w1_netlink_msg)]; |
33 | struct sk_buff *skb; | 34 | struct cn_msg *m = (struct cn_msg *)buf; |
34 | struct w1_netlink_msg *data; | 35 | struct w1_netlink_msg *w = (struct w1_netlink_msg *)(m+1); |
35 | struct nlmsghdr *nlh; | ||
36 | 36 | ||
37 | if (!dev->nls) | 37 | memset(buf, 0, sizeof(buf)); |
38 | return; | ||
39 | 38 | ||
40 | size = NLMSG_SPACE(sizeof(struct w1_netlink_msg)); | 39 | m->id.idx = CN_W1_IDX; |
40 | m->id.val = CN_W1_VAL; | ||
41 | 41 | ||
42 | skb = alloc_skb(size, GFP_ATOMIC); | 42 | m->seq = dev->seq++; |
43 | if (!skb) { | 43 | m->len = sizeof(struct w1_netlink_msg); |
44 | dev_err(&dev->dev, "skb_alloc() failed.\n"); | 44 | |
45 | return; | 45 | memcpy(w, msg, sizeof(struct w1_netlink_msg)); |
46 | } | 46 | |
47 | cn_netlink_send(m, 0, GFP_KERNEL); | ||
48 | } | ||
49 | |||
50 | static int w1_process_command_master(struct w1_master *dev, struct cn_msg *msg, | ||
51 | struct w1_netlink_msg *hdr, struct w1_netlink_cmd *cmd) | ||
52 | { | ||
53 | dev_dbg(&dev->dev, "%s: %s: cmd=%02x, len=%u.\n", | ||
54 | __func__, dev->name, cmd->cmd, cmd->len); | ||
55 | |||
56 | if (cmd->cmd != W1_CMD_SEARCH && cmd->cmd != W1_CMD_ALARM_SEARCH) | ||
57 | return -EINVAL; | ||
58 | |||
59 | w1_search_process(dev, (cmd->cmd == W1_CMD_ALARM_SEARCH)?W1_ALARM_SEARCH:W1_SEARCH); | ||
60 | return 0; | ||
61 | } | ||
62 | |||
63 | static int w1_send_read_reply(struct w1_slave *sl, struct cn_msg *msg, | ||
64 | struct w1_netlink_msg *hdr, struct w1_netlink_cmd *cmd) | ||
65 | { | ||
66 | void *data; | ||
67 | struct w1_netlink_msg *h; | ||
68 | struct w1_netlink_cmd *c; | ||
69 | struct cn_msg *cm; | ||
70 | int err; | ||
71 | |||
72 | data = kzalloc(sizeof(struct cn_msg) + | ||
73 | sizeof(struct w1_netlink_msg) + | ||
74 | sizeof(struct w1_netlink_cmd) + | ||
75 | cmd->len, GFP_KERNEL); | ||
76 | if (!data) | ||
77 | return -ENOMEM; | ||
78 | |||
79 | cm = (struct cn_msg *)(data); | ||
80 | h = (struct w1_netlink_msg *)(cm + 1); | ||
81 | c = (struct w1_netlink_cmd *)(h + 1); | ||
82 | |||
83 | memcpy(cm, msg, sizeof(struct cn_msg)); | ||
84 | memcpy(h, hdr, sizeof(struct w1_netlink_msg)); | ||
85 | memcpy(c, cmd, sizeof(struct w1_netlink_cmd)); | ||
47 | 86 | ||
48 | nlh = NLMSG_PUT(skb, 0, dev->seq++, NLMSG_DONE, size - sizeof(*nlh)); | 87 | cm->ack = msg->seq+1; |
88 | cm->len = sizeof(struct w1_netlink_msg) + sizeof(struct w1_netlink_cmd) + cmd->len; | ||
49 | 89 | ||
50 | data = (struct w1_netlink_msg *)NLMSG_DATA(nlh); | 90 | h->len = sizeof(struct w1_netlink_cmd) + cmd->len; |
51 | 91 | ||
52 | memcpy(data, msg, sizeof(struct w1_netlink_msg)); | 92 | memcpy(c->data, cmd->data, c->len); |
53 | 93 | ||
54 | NETLINK_CB(skb).dst_group = dev->groups; | 94 | err = cn_netlink_send(cm, 0, GFP_KERNEL); |
55 | netlink_broadcast(dev->nls, skb, 0, dev->groups, GFP_ATOMIC); | ||
56 | 95 | ||
57 | nlmsg_failure: | 96 | kfree(data); |
58 | return; | 97 | |
98 | return err; | ||
59 | } | 99 | } |
60 | 100 | ||
61 | int dev_init_netlink(struct w1_master *dev) | 101 | static int w1_process_command_slave(struct w1_slave *sl, struct cn_msg *msg, |
102 | struct w1_netlink_msg *hdr, struct w1_netlink_cmd *cmd) | ||
62 | { | 103 | { |
63 | dev->nls = netlink_kernel_create(NETLINK_W1, 1, NULL, THIS_MODULE); | 104 | int err = 0; |
64 | if (!dev->nls) { | 105 | |
65 | printk(KERN_ERR "Failed to create new netlink socket(%u) for w1 master %s.\n", | 106 | dev_dbg(&sl->master->dev, "%s: %02x.%012llx.%02x: cmd=%02x, len=%u.\n", |
66 | NETLINK_W1, dev->dev.bus_id); | 107 | __func__, sl->reg_num.family, (unsigned long long)sl->reg_num.id, sl->reg_num.crc, |
108 | cmd->cmd, cmd->len); | ||
109 | |||
110 | switch (cmd->cmd) { | ||
111 | case W1_CMD_READ: | ||
112 | w1_read_block(sl->master, cmd->data, cmd->len); | ||
113 | w1_send_read_reply(sl, msg, hdr, cmd); | ||
114 | break; | ||
115 | case W1_CMD_WRITE: | ||
116 | w1_write_block(sl->master, cmd->data, cmd->len); | ||
117 | break; | ||
118 | case W1_CMD_SEARCH: | ||
119 | case W1_CMD_ALARM_SEARCH: | ||
120 | w1_search_process(sl->master, | ||
121 | (cmd->cmd == W1_CMD_ALARM_SEARCH)?W1_ALARM_SEARCH:W1_SEARCH); | ||
122 | break; | ||
123 | default: | ||
124 | err = -1; | ||
125 | break; | ||
67 | } | 126 | } |
68 | 127 | ||
69 | return 0; | 128 | return err; |
70 | } | 129 | } |
71 | 130 | ||
72 | void dev_fini_netlink(struct w1_master *dev) | 131 | static void w1_cn_callback(void *data) |
73 | { | 132 | { |
74 | if (dev->nls && dev->nls->sk_socket) | 133 | struct cn_msg *msg = data; |
75 | sock_release(dev->nls->sk_socket); | 134 | struct w1_netlink_msg *m = (struct w1_netlink_msg *)(msg + 1); |
135 | struct w1_netlink_cmd *cmd; | ||
136 | struct w1_slave *sl; | ||
137 | struct w1_master *dev; | ||
138 | int err = 0; | ||
139 | |||
140 | while (msg->len && !err) { | ||
141 | struct w1_reg_num id; | ||
142 | u16 mlen = m->len; | ||
143 | u8 *cmd_data = m->data; | ||
144 | |||
145 | dev = NULL; | ||
146 | sl = NULL; | ||
147 | |||
148 | memcpy(&id, m->id.id, sizeof(id)); | ||
149 | #if 0 | ||
150 | printk("%s: %02x.%012llx.%02x: type=%02x, len=%u.\n", | ||
151 | __func__, id.family, (unsigned long long)id.id, id.crc, m->type, m->len); | ||
152 | #endif | ||
153 | if (m->len + sizeof(struct w1_netlink_msg) > msg->len) { | ||
154 | err = -E2BIG; | ||
155 | break; | ||
156 | } | ||
157 | |||
158 | if (!mlen) | ||
159 | goto out_cont; | ||
160 | |||
161 | if (m->type == W1_MASTER_CMD) { | ||
162 | dev = w1_search_master_id(m->id.mst.id); | ||
163 | } else if (m->type == W1_SLAVE_CMD) { | ||
164 | sl = w1_search_slave(&id); | ||
165 | if (sl) | ||
166 | dev = sl->master; | ||
167 | } | ||
168 | |||
169 | if (!dev) { | ||
170 | err = -ENODEV; | ||
171 | goto out_cont; | ||
172 | } | ||
173 | |||
174 | mutex_lock(&dev->mutex); | ||
175 | |||
176 | if (sl && w1_reset_select_slave(sl)) { | ||
177 | err = -ENODEV; | ||
178 | goto out_up; | ||
179 | } | ||
180 | |||
181 | while (mlen) { | ||
182 | cmd = (struct w1_netlink_cmd *)cmd_data; | ||
183 | |||
184 | if (cmd->len + sizeof(struct w1_netlink_cmd) > mlen) { | ||
185 | err = -E2BIG; | ||
186 | break; | ||
187 | } | ||
188 | |||
189 | if (sl) | ||
190 | w1_process_command_slave(sl, msg, m, cmd); | ||
191 | else | ||
192 | w1_process_command_master(dev, msg, m, cmd); | ||
193 | |||
194 | cmd_data += cmd->len + sizeof(struct w1_netlink_cmd); | ||
195 | mlen -= cmd->len + sizeof(struct w1_netlink_cmd); | ||
196 | } | ||
197 | out_up: | ||
198 | atomic_dec(&dev->refcnt); | ||
199 | if (sl) | ||
200 | atomic_dec(&sl->refcnt); | ||
201 | mutex_unlock(&dev->mutex); | ||
202 | out_cont: | ||
203 | msg->len -= sizeof(struct w1_netlink_msg) + m->len; | ||
204 | m = (struct w1_netlink_msg *)(((u8 *)m) + sizeof(struct w1_netlink_msg) + m->len); | ||
205 | |||
206 | /* | ||
207 | * Let's allow requests for nonexisting devices. | ||
208 | */ | ||
209 | if (err == -ENODEV) | ||
210 | err = 0; | ||
211 | } | ||
212 | #if 0 | ||
213 | if (err) { | ||
214 | printk("%s: malformed message. Dropping.\n", __func__); | ||
215 | } | ||
216 | #endif | ||
76 | } | 217 | } |
77 | #else | ||
78 | #warning Netlink support is disabled. Please compile with NET support enabled. | ||
79 | 218 | ||
219 | int w1_init_netlink(void) | ||
220 | { | ||
221 | struct cb_id w1_id = {.idx = CN_W1_IDX, .val = CN_W1_VAL}; | ||
222 | |||
223 | return cn_add_callback(&w1_id, "w1", &w1_cn_callback); | ||
224 | } | ||
225 | |||
226 | void w1_fini_netlink(void) | ||
227 | { | ||
228 | struct cb_id w1_id = {.idx = CN_W1_IDX, .val = CN_W1_VAL}; | ||
229 | |||
230 | cn_del_callback(&w1_id); | ||
231 | } | ||
232 | #else | ||
80 | void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg) | 233 | void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg) |
81 | { | 234 | { |
82 | } | 235 | } |
83 | 236 | ||
84 | int dev_init_netlink(struct w1_master *dev) | 237 | int w1_init_netlink(void) |
85 | { | 238 | { |
86 | return 0; | 239 | return 0; |
87 | } | 240 | } |
88 | 241 | ||
89 | void dev_fini_netlink(struct w1_master *dev) | 242 | void w1_fini_netlink(void) |
90 | { | 243 | { |
91 | } | 244 | } |
92 | #endif | 245 | #endif |
diff --git a/drivers/w1/w1_netlink.h b/drivers/w1/w1_netlink.h index eb0c8b3152c8..56122b9e9294 100644 --- a/drivers/w1/w1_netlink.h +++ b/drivers/w1/w1_netlink.h | |||
@@ -23,6 +23,7 @@ | |||
23 | #define __W1_NETLINK_H | 23 | #define __W1_NETLINK_H |
24 | 24 | ||
25 | #include <asm/types.h> | 25 | #include <asm/types.h> |
26 | #include <linux/connector.h> | ||
26 | 27 | ||
27 | #include "w1.h" | 28 | #include "w1.h" |
28 | 29 | ||
@@ -31,29 +32,43 @@ enum w1_netlink_message_types { | |||
31 | W1_SLAVE_REMOVE, | 32 | W1_SLAVE_REMOVE, |
32 | W1_MASTER_ADD, | 33 | W1_MASTER_ADD, |
33 | W1_MASTER_REMOVE, | 34 | W1_MASTER_REMOVE, |
35 | W1_MASTER_CMD, | ||
36 | W1_SLAVE_CMD, | ||
34 | }; | 37 | }; |
35 | 38 | ||
36 | struct w1_netlink_msg | 39 | struct w1_netlink_msg |
37 | { | 40 | { |
38 | __u8 type; | 41 | __u8 type; |
39 | __u8 reserved[3]; | 42 | __u8 reserved; |
40 | union | 43 | __u16 len; |
41 | { | 44 | union { |
42 | struct w1_reg_num id; | 45 | __u8 id[8]; |
43 | __u64 w1_id; | 46 | struct w1_mst { |
44 | struct | ||
45 | { | ||
46 | __u32 id; | 47 | __u32 id; |
47 | __u32 pid; | 48 | __u32 res; |
48 | } mst; | 49 | } mst; |
49 | } id; | 50 | } id; |
51 | __u8 data[0]; | ||
52 | }; | ||
53 | |||
54 | #define W1_CMD_READ 0x0 | ||
55 | #define W1_CMD_WRITE 0x1 | ||
56 | #define W1_CMD_SEARCH 0x2 | ||
57 | #define W1_CMD_ALARM_SEARCH 0x3 | ||
58 | |||
59 | struct w1_netlink_cmd | ||
60 | { | ||
61 | __u8 cmd; | ||
62 | __u8 res; | ||
63 | __u16 len; | ||
64 | __u8 data[0]; | ||
50 | }; | 65 | }; |
51 | 66 | ||
52 | #ifdef __KERNEL__ | 67 | #ifdef __KERNEL__ |
53 | 68 | ||
54 | void w1_netlink_send(struct w1_master *, struct w1_netlink_msg *); | 69 | void w1_netlink_send(struct w1_master *, struct w1_netlink_msg *); |
55 | int dev_init_netlink(struct w1_master *dev); | 70 | int w1_init_netlink(void); |
56 | void dev_fini_netlink(struct w1_master *dev); | 71 | void w1_fini_netlink(void); |
57 | 72 | ||
58 | #endif /* __KERNEL__ */ | 73 | #endif /* __KERNEL__ */ |
59 | #endif /* __W1_NETLINK_H */ | 74 | #endif /* __W1_NETLINK_H */ |