diff options
author | James Bottomley <jejb@mulgrave.il.steeleye.com> | 2006-06-28 14:06:39 -0400 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.il.steeleye.com> | 2006-06-28 14:06:39 -0400 |
commit | f28e71617ddaf2483e3e5c5237103484a303743f (patch) | |
tree | 67627d2d8ddbf6a4449371e9261d796c013b1fa1 /drivers | |
parent | dc6a78f1af10d28fb8c395034ae1e099b85c05b0 (diff) | |
parent | a39727f212426b9d5f9267b3318a2afaf9922d3b (diff) |
Merge ../linux-2.6/
Conflicts:
drivers/scsi/aacraid/comminit.c
Fixed up by removing the now renamed CONFIG_IOMMU option from
aacraid
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers')
382 files changed, 23432 insertions, 7630 deletions
diff --git a/drivers/Makefile b/drivers/Makefile index 3c5170310bd0..fc2d744a4e4a 100644 --- a/drivers/Makefile +++ b/drivers/Makefile | |||
@@ -74,4 +74,5 @@ obj-$(CONFIG_SGI_SN) += sn/ | |||
74 | obj-y += firmware/ | 74 | obj-y += firmware/ |
75 | obj-$(CONFIG_CRYPTO) += crypto/ | 75 | obj-$(CONFIG_CRYPTO) += crypto/ |
76 | obj-$(CONFIG_SUPERH) += sh/ | 76 | obj-$(CONFIG_SUPERH) += sh/ |
77 | obj-$(CONFIG_GENERIC_TIME) += clocksource/ | ||
77 | obj-$(CONFIG_DMA_ENGINE) += dma/ | 78 | obj-$(CONFIG_DMA_ENGINE) += dma/ |
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 94b8d820c512..610d2cc02cf8 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig | |||
@@ -328,7 +328,7 @@ config ACPI_CONTAINER | |||
328 | config ACPI_HOTPLUG_MEMORY | 328 | config ACPI_HOTPLUG_MEMORY |
329 | tristate "Memory Hotplug" | 329 | tristate "Memory Hotplug" |
330 | depends on ACPI | 330 | depends on ACPI |
331 | depends on MEMORY_HOTPLUG || X86_64 | 331 | depends on MEMORY_HOTPLUG |
332 | default n | 332 | default n |
333 | help | 333 | help |
334 | This driver adds supports for ACPI Memory Hotplug. This driver | 334 | This driver adds supports for ACPI Memory Hotplug. This driver |
diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c index e0a95ba72371..1012284ff4f7 100644 --- a/drivers/acpi/acpi_memhotplug.c +++ b/drivers/acpi/acpi_memhotplug.c | |||
@@ -57,6 +57,7 @@ MODULE_LICENSE("GPL"); | |||
57 | 57 | ||
58 | static int acpi_memory_device_add(struct acpi_device *device); | 58 | static int acpi_memory_device_add(struct acpi_device *device); |
59 | static int acpi_memory_device_remove(struct acpi_device *device, int type); | 59 | static int acpi_memory_device_remove(struct acpi_device *device, int type); |
60 | static int acpi_memory_device_start(struct acpi_device *device); | ||
60 | 61 | ||
61 | static struct acpi_driver acpi_memory_device_driver = { | 62 | static struct acpi_driver acpi_memory_device_driver = { |
62 | .name = ACPI_MEMORY_DEVICE_DRIVER_NAME, | 63 | .name = ACPI_MEMORY_DEVICE_DRIVER_NAME, |
@@ -65,48 +66,79 @@ static struct acpi_driver acpi_memory_device_driver = { | |||
65 | .ops = { | 66 | .ops = { |
66 | .add = acpi_memory_device_add, | 67 | .add = acpi_memory_device_add, |
67 | .remove = acpi_memory_device_remove, | 68 | .remove = acpi_memory_device_remove, |
69 | .start = acpi_memory_device_start, | ||
68 | }, | 70 | }, |
69 | }; | 71 | }; |
70 | 72 | ||
73 | struct acpi_memory_info { | ||
74 | struct list_head list; | ||
75 | u64 start_addr; /* Memory Range start physical addr */ | ||
76 | u64 length; /* Memory Range length */ | ||
77 | unsigned short caching; /* memory cache attribute */ | ||
78 | unsigned short write_protect; /* memory read/write attribute */ | ||
79 | unsigned int enabled:1; | ||
80 | }; | ||
81 | |||
71 | struct acpi_memory_device { | 82 | struct acpi_memory_device { |
72 | acpi_handle handle; | 83 | acpi_handle handle; |
73 | unsigned int state; /* State of the memory device */ | 84 | unsigned int state; /* State of the memory device */ |
74 | unsigned short caching; /* memory cache attribute */ | 85 | struct list_head res_list; |
75 | unsigned short write_protect; /* memory read/write attribute */ | ||
76 | u64 start_addr; /* Memory Range start physical addr */ | ||
77 | u64 length; /* Memory Range length */ | ||
78 | }; | 86 | }; |
79 | 87 | ||
88 | static acpi_status | ||
89 | acpi_memory_get_resource(struct acpi_resource *resource, void *context) | ||
90 | { | ||
91 | struct acpi_memory_device *mem_device = context; | ||
92 | struct acpi_resource_address64 address64; | ||
93 | struct acpi_memory_info *info, *new; | ||
94 | acpi_status status; | ||
95 | |||
96 | status = acpi_resource_to_address64(resource, &address64); | ||
97 | if (ACPI_FAILURE(status) || | ||
98 | (address64.resource_type != ACPI_MEMORY_RANGE)) | ||
99 | return AE_OK; | ||
100 | |||
101 | list_for_each_entry(info, &mem_device->res_list, list) { | ||
102 | /* Can we combine the resource range information? */ | ||
103 | if ((info->caching == address64.info.mem.caching) && | ||
104 | (info->write_protect == address64.info.mem.write_protect) && | ||
105 | (info->start_addr + info->length == address64.minimum)) { | ||
106 | info->length += address64.address_length; | ||
107 | return AE_OK; | ||
108 | } | ||
109 | } | ||
110 | |||
111 | new = kzalloc(sizeof(struct acpi_memory_info), GFP_KERNEL); | ||
112 | if (!new) | ||
113 | return AE_ERROR; | ||
114 | |||
115 | INIT_LIST_HEAD(&new->list); | ||
116 | new->caching = address64.info.mem.caching; | ||
117 | new->write_protect = address64.info.mem.write_protect; | ||
118 | new->start_addr = address64.minimum; | ||
119 | new->length = address64.address_length; | ||
120 | list_add_tail(&new->list, &mem_device->res_list); | ||
121 | |||
122 | return AE_OK; | ||
123 | } | ||
124 | |||
80 | static int | 125 | static int |
81 | acpi_memory_get_device_resources(struct acpi_memory_device *mem_device) | 126 | acpi_memory_get_device_resources(struct acpi_memory_device *mem_device) |
82 | { | 127 | { |
83 | acpi_status status; | 128 | acpi_status status; |
84 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | 129 | struct acpi_memory_info *info, *n; |
85 | struct acpi_resource *resource = NULL; | ||
86 | struct acpi_resource_address64 address64; | ||
87 | 130 | ||
88 | ACPI_FUNCTION_TRACE("acpi_memory_get_device_resources"); | 131 | ACPI_FUNCTION_TRACE("acpi_memory_get_device_resources"); |
89 | 132 | ||
90 | /* Get the range from the _CRS */ | 133 | status = acpi_walk_resources(mem_device->handle, METHOD_NAME__CRS, |
91 | status = acpi_get_current_resources(mem_device->handle, &buffer); | 134 | acpi_memory_get_resource, mem_device); |
92 | if (ACPI_FAILURE(status)) | 135 | if (ACPI_FAILURE(status)) { |
93 | return_VALUE(-EINVAL); | 136 | list_for_each_entry_safe(info, n, &mem_device->res_list, list) |
94 | 137 | kfree(info); | |
95 | resource = (struct acpi_resource *)buffer.pointer; | 138 | return -EINVAL; |
96 | status = acpi_resource_to_address64(resource, &address64); | ||
97 | if (ACPI_SUCCESS(status)) { | ||
98 | if (address64.resource_type == ACPI_MEMORY_RANGE) { | ||
99 | /* Populate the structure */ | ||
100 | mem_device->caching = address64.info.mem.caching; | ||
101 | mem_device->write_protect = | ||
102 | address64.info.mem.write_protect; | ||
103 | mem_device->start_addr = address64.minimum; | ||
104 | mem_device->length = address64.address_length; | ||
105 | } | ||
106 | } | 139 | } |
107 | 140 | ||
108 | acpi_os_free(buffer.pointer); | 141 | return 0; |
109 | return_VALUE(0); | ||
110 | } | 142 | } |
111 | 143 | ||
112 | static int | 144 | static int |
@@ -181,7 +213,9 @@ static int acpi_memory_check_device(struct acpi_memory_device *mem_device) | |||
181 | 213 | ||
182 | static int acpi_memory_enable_device(struct acpi_memory_device *mem_device) | 214 | static int acpi_memory_enable_device(struct acpi_memory_device *mem_device) |
183 | { | 215 | { |
184 | int result; | 216 | int result, num_enabled = 0; |
217 | struct acpi_memory_info *info; | ||
218 | int node; | ||
185 | 219 | ||
186 | ACPI_FUNCTION_TRACE("acpi_memory_enable_device"); | 220 | ACPI_FUNCTION_TRACE("acpi_memory_enable_device"); |
187 | 221 | ||
@@ -194,15 +228,35 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device) | |||
194 | return result; | 228 | return result; |
195 | } | 229 | } |
196 | 230 | ||
231 | node = acpi_get_node(mem_device->handle); | ||
197 | /* | 232 | /* |
198 | * Tell the VM there is more memory here... | 233 | * Tell the VM there is more memory here... |
199 | * Note: Assume that this function returns zero on success | 234 | * Note: Assume that this function returns zero on success |
235 | * We don't have memory-hot-add rollback function,now. | ||
236 | * (i.e. memory-hot-remove function) | ||
200 | */ | 237 | */ |
201 | result = add_memory(mem_device->start_addr, mem_device->length); | 238 | list_for_each_entry(info, &mem_device->res_list, list) { |
202 | if (result) { | 239 | u64 start_pfn, end_pfn; |
240 | |||
241 | start_pfn = info->start_addr >> PAGE_SHIFT; | ||
242 | end_pfn = (info->start_addr + info->length - 1) >> PAGE_SHIFT; | ||
243 | |||
244 | if (pfn_valid(start_pfn) || pfn_valid(end_pfn)) { | ||
245 | /* already enabled. try next area */ | ||
246 | num_enabled++; | ||
247 | continue; | ||
248 | } | ||
249 | |||
250 | result = add_memory(node, info->start_addr, info->length); | ||
251 | if (result) | ||
252 | continue; | ||
253 | info->enabled = 1; | ||
254 | num_enabled++; | ||
255 | } | ||
256 | if (!num_enabled) { | ||
203 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "\nadd_memory failed\n")); | 257 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "\nadd_memory failed\n")); |
204 | mem_device->state = MEMORY_INVALID_STATE; | 258 | mem_device->state = MEMORY_INVALID_STATE; |
205 | return result; | 259 | return -EINVAL; |
206 | } | 260 | } |
207 | 261 | ||
208 | return result; | 262 | return result; |
@@ -246,8 +300,7 @@ static int acpi_memory_powerdown_device(struct acpi_memory_device *mem_device) | |||
246 | static int acpi_memory_disable_device(struct acpi_memory_device *mem_device) | 300 | static int acpi_memory_disable_device(struct acpi_memory_device *mem_device) |
247 | { | 301 | { |
248 | int result; | 302 | int result; |
249 | u64 start = mem_device->start_addr; | 303 | struct acpi_memory_info *info, *n; |
250 | u64 len = mem_device->length; | ||
251 | 304 | ||
252 | ACPI_FUNCTION_TRACE("acpi_memory_disable_device"); | 305 | ACPI_FUNCTION_TRACE("acpi_memory_disable_device"); |
253 | 306 | ||
@@ -255,10 +308,13 @@ static int acpi_memory_disable_device(struct acpi_memory_device *mem_device) | |||
255 | * Ask the VM to offline this memory range. | 308 | * Ask the VM to offline this memory range. |
256 | * Note: Assume that this function returns zero on success | 309 | * Note: Assume that this function returns zero on success |
257 | */ | 310 | */ |
258 | result = remove_memory(start, len); | 311 | list_for_each_entry_safe(info, n, &mem_device->res_list, list) { |
259 | if (result) { | 312 | if (info->enabled) { |
260 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Hot-Remove failed.\n")); | 313 | result = remove_memory(info->start_addr, info->length); |
261 | return_VALUE(result); | 314 | if (result) |
315 | return result; | ||
316 | } | ||
317 | kfree(info); | ||
262 | } | 318 | } |
263 | 319 | ||
264 | /* Power-off and eject the device */ | 320 | /* Power-off and eject the device */ |
@@ -356,6 +412,7 @@ static int acpi_memory_device_add(struct acpi_device *device) | |||
356 | return_VALUE(-ENOMEM); | 412 | return_VALUE(-ENOMEM); |
357 | memset(mem_device, 0, sizeof(struct acpi_memory_device)); | 413 | memset(mem_device, 0, sizeof(struct acpi_memory_device)); |
358 | 414 | ||
415 | INIT_LIST_HEAD(&mem_device->res_list); | ||
359 | mem_device->handle = device->handle; | 416 | mem_device->handle = device->handle; |
360 | sprintf(acpi_device_name(device), "%s", ACPI_MEMORY_DEVICE_NAME); | 417 | sprintf(acpi_device_name(device), "%s", ACPI_MEMORY_DEVICE_NAME); |
361 | sprintf(acpi_device_class(device), "%s", ACPI_MEMORY_DEVICE_CLASS); | 418 | sprintf(acpi_device_class(device), "%s", ACPI_MEMORY_DEVICE_CLASS); |
@@ -391,6 +448,25 @@ static int acpi_memory_device_remove(struct acpi_device *device, int type) | |||
391 | return_VALUE(0); | 448 | return_VALUE(0); |
392 | } | 449 | } |
393 | 450 | ||
451 | static int acpi_memory_device_start (struct acpi_device *device) | ||
452 | { | ||
453 | struct acpi_memory_device *mem_device; | ||
454 | int result = 0; | ||
455 | |||
456 | ACPI_FUNCTION_TRACE("acpi_memory_device_start"); | ||
457 | |||
458 | mem_device = acpi_driver_data(device); | ||
459 | |||
460 | if (!acpi_memory_check_device(mem_device)) { | ||
461 | /* call add_memory func */ | ||
462 | result = acpi_memory_enable_device(mem_device); | ||
463 | if (result) | ||
464 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, | ||
465 | "Error in acpi_memory_enable_device\n")); | ||
466 | } | ||
467 | return_VALUE(result); | ||
468 | } | ||
469 | |||
394 | /* | 470 | /* |
395 | * Helper function to check for memory device | 471 | * Helper function to check for memory device |
396 | */ | 472 | */ |
diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c index e2c1a16078c9..13d6d5bdea26 100644 --- a/drivers/acpi/numa.c +++ b/drivers/acpi/numa.c | |||
@@ -254,5 +254,18 @@ int acpi_get_pxm(acpi_handle h) | |||
254 | } while (ACPI_SUCCESS(status)); | 254 | } while (ACPI_SUCCESS(status)); |
255 | return -1; | 255 | return -1; |
256 | } | 256 | } |
257 | |||
258 | EXPORT_SYMBOL(acpi_get_pxm); | 257 | EXPORT_SYMBOL(acpi_get_pxm); |
258 | |||
259 | int acpi_get_node(acpi_handle *handle) | ||
260 | { | ||
261 | int pxm, node = -1; | ||
262 | |||
263 | ACPI_FUNCTION_TRACE("acpi_get_node"); | ||
264 | |||
265 | pxm = acpi_get_pxm(handle); | ||
266 | if (pxm >= 0) | ||
267 | node = acpi_map_pxm_to_node(pxm); | ||
268 | |||
269 | return_VALUE(node); | ||
270 | } | ||
271 | EXPORT_SYMBOL(acpi_get_node); | ||
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 3b97a5eae9e8..8a74bf3efd8e 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c | |||
@@ -206,11 +206,11 @@ acpi_processor_power_activate(struct acpi_processor *pr, | |||
206 | 206 | ||
207 | static void acpi_safe_halt(void) | 207 | static void acpi_safe_halt(void) |
208 | { | 208 | { |
209 | clear_thread_flag(TIF_POLLING_NRFLAG); | 209 | current_thread_info()->status &= ~TS_POLLING; |
210 | smp_mb__after_clear_bit(); | 210 | smp_mb__after_clear_bit(); |
211 | if (!need_resched()) | 211 | if (!need_resched()) |
212 | safe_halt(); | 212 | safe_halt(); |
213 | set_thread_flag(TIF_POLLING_NRFLAG); | 213 | current_thread_info()->status |= TS_POLLING; |
214 | } | 214 | } |
215 | 215 | ||
216 | static atomic_t c3_cpu_count; | 216 | static atomic_t c3_cpu_count; |
@@ -330,10 +330,10 @@ static void acpi_processor_idle(void) | |||
330 | * Invoke the current Cx state to put the processor to sleep. | 330 | * Invoke the current Cx state to put the processor to sleep. |
331 | */ | 331 | */ |
332 | if (cx->type == ACPI_STATE_C2 || cx->type == ACPI_STATE_C3) { | 332 | if (cx->type == ACPI_STATE_C2 || cx->type == ACPI_STATE_C3) { |
333 | clear_thread_flag(TIF_POLLING_NRFLAG); | 333 | current_thread_info()->status &= ~TS_POLLING; |
334 | smp_mb__after_clear_bit(); | 334 | smp_mb__after_clear_bit(); |
335 | if (need_resched()) { | 335 | if (need_resched()) { |
336 | set_thread_flag(TIF_POLLING_NRFLAG); | 336 | current_thread_info()->status |= TS_POLLING; |
337 | local_irq_enable(); | 337 | local_irq_enable(); |
338 | return; | 338 | return; |
339 | } | 339 | } |
@@ -369,9 +369,14 @@ static void acpi_processor_idle(void) | |||
369 | t2 = inl(acpi_fadt.xpm_tmr_blk.address); | 369 | t2 = inl(acpi_fadt.xpm_tmr_blk.address); |
370 | /* Get end time (ticks) */ | 370 | /* Get end time (ticks) */ |
371 | t2 = inl(acpi_fadt.xpm_tmr_blk.address); | 371 | t2 = inl(acpi_fadt.xpm_tmr_blk.address); |
372 | |||
373 | #ifdef CONFIG_GENERIC_TIME | ||
374 | /* TSC halts in C2, so notify users */ | ||
375 | mark_tsc_unstable(); | ||
376 | #endif | ||
372 | /* Re-enable interrupts */ | 377 | /* Re-enable interrupts */ |
373 | local_irq_enable(); | 378 | local_irq_enable(); |
374 | set_thread_flag(TIF_POLLING_NRFLAG); | 379 | current_thread_info()->status |= TS_POLLING; |
375 | /* Compute time (ticks) that we were actually asleep */ | 380 | /* Compute time (ticks) that we were actually asleep */ |
376 | sleep_ticks = | 381 | sleep_ticks = |
377 | ticks_elapsed(t1, t2) - cx->latency_ticks - C2_OVERHEAD; | 382 | ticks_elapsed(t1, t2) - cx->latency_ticks - C2_OVERHEAD; |
@@ -409,9 +414,13 @@ static void acpi_processor_idle(void) | |||
409 | ACPI_MTX_DO_NOT_LOCK); | 414 | ACPI_MTX_DO_NOT_LOCK); |
410 | } | 415 | } |
411 | 416 | ||
417 | #ifdef CONFIG_GENERIC_TIME | ||
418 | /* TSC halts in C3, so notify users */ | ||
419 | mark_tsc_unstable(); | ||
420 | #endif | ||
412 | /* Re-enable interrupts */ | 421 | /* Re-enable interrupts */ |
413 | local_irq_enable(); | 422 | local_irq_enable(); |
414 | set_thread_flag(TIF_POLLING_NRFLAG); | 423 | current_thread_info()->status |= TS_POLLING; |
415 | /* Compute time (ticks) that we were actually asleep */ | 424 | /* Compute time (ticks) that we were actually asleep */ |
416 | sleep_ticks = | 425 | sleep_ticks = |
417 | ticks_elapsed(t1, t2) - cx->latency_ticks - C3_OVERHEAD; | 426 | ticks_elapsed(t1, t2) - cx->latency_ticks - C3_OVERHEAD; |
diff --git a/drivers/atm/firestream.c b/drivers/atm/firestream.c index 7f7ec288824d..1bca86edf570 100644 --- a/drivers/atm/firestream.c +++ b/drivers/atm/firestream.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/kernel.h> | 33 | #include <linux/kernel.h> |
34 | #include <linux/mm.h> | 34 | #include <linux/mm.h> |
35 | #include <linux/pci.h> | 35 | #include <linux/pci.h> |
36 | #include <linux/poison.h> | ||
36 | #include <linux/errno.h> | 37 | #include <linux/errno.h> |
37 | #include <linux/atm.h> | 38 | #include <linux/atm.h> |
38 | #include <linux/atmdev.h> | 39 | #include <linux/atmdev.h> |
@@ -754,7 +755,7 @@ static void process_txdone_queue (struct fs_dev *dev, struct queue *q) | |||
754 | fs_kfree_skb (skb); | 755 | fs_kfree_skb (skb); |
755 | 756 | ||
756 | fs_dprintk (FS_DEBUG_ALLOC, "Free trans-d: %p\n", td); | 757 | fs_dprintk (FS_DEBUG_ALLOC, "Free trans-d: %p\n", td); |
757 | memset (td, 0x12, sizeof (struct FS_BPENTRY)); | 758 | memset (td, ATM_POISON_FREE, sizeof(struct FS_BPENTRY)); |
758 | kfree (td); | 759 | kfree (td); |
759 | break; | 760 | break; |
760 | default: | 761 | default: |
@@ -951,7 +952,7 @@ static int fs_open(struct atm_vcc *atm_vcc) | |||
951 | it most likely that the chip will notice it. It also prevents us | 952 | it most likely that the chip will notice it. It also prevents us |
952 | from having to wait for completion. On the other hand, we may | 953 | from having to wait for completion. On the other hand, we may |
953 | need to wait for completion anyway, to see if it completed | 954 | need to wait for completion anyway, to see if it completed |
954 | succesfully. */ | 955 | successfully. */ |
955 | 956 | ||
956 | switch (atm_vcc->qos.aal) { | 957 | switch (atm_vcc->qos.aal) { |
957 | case ATM_AAL2: | 958 | case ATM_AAL2: |
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index dd712b24ec91..4bef76a2f3f2 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c | |||
@@ -8,6 +8,7 @@ | |||
8 | #include <linux/cpu.h> | 8 | #include <linux/cpu.h> |
9 | #include <linux/topology.h> | 9 | #include <linux/topology.h> |
10 | #include <linux/device.h> | 10 | #include <linux/device.h> |
11 | #include <linux/node.h> | ||
11 | 12 | ||
12 | #include "base.h" | 13 | #include "base.h" |
13 | 14 | ||
@@ -57,13 +58,12 @@ static void __devinit register_cpu_control(struct cpu *cpu) | |||
57 | { | 58 | { |
58 | sysdev_create_file(&cpu->sysdev, &attr_online); | 59 | sysdev_create_file(&cpu->sysdev, &attr_online); |
59 | } | 60 | } |
60 | void unregister_cpu(struct cpu *cpu, struct node *root) | 61 | void unregister_cpu(struct cpu *cpu) |
61 | { | 62 | { |
62 | int logical_cpu = cpu->sysdev.id; | 63 | int logical_cpu = cpu->sysdev.id; |
63 | 64 | ||
64 | if (root) | 65 | unregister_cpu_under_node(logical_cpu, cpu_to_node(logical_cpu)); |
65 | sysfs_remove_link(&root->sysdev.kobj, | 66 | |
66 | kobject_name(&cpu->sysdev.kobj)); | ||
67 | sysdev_remove_file(&cpu->sysdev, &attr_online); | 67 | sysdev_remove_file(&cpu->sysdev, &attr_online); |
68 | 68 | ||
69 | sysdev_unregister(&cpu->sysdev); | 69 | sysdev_unregister(&cpu->sysdev); |
@@ -109,23 +109,21 @@ static SYSDEV_ATTR(crash_notes, 0400, show_crash_notes, NULL); | |||
109 | * | 109 | * |
110 | * Initialize and register the CPU device. | 110 | * Initialize and register the CPU device. |
111 | */ | 111 | */ |
112 | int __devinit register_cpu(struct cpu *cpu, int num, struct node *root) | 112 | int __devinit register_cpu(struct cpu *cpu, int num) |
113 | { | 113 | { |
114 | int error; | 114 | int error; |
115 | |||
116 | cpu->node_id = cpu_to_node(num); | 115 | cpu->node_id = cpu_to_node(num); |
117 | cpu->sysdev.id = num; | 116 | cpu->sysdev.id = num; |
118 | cpu->sysdev.cls = &cpu_sysdev_class; | 117 | cpu->sysdev.cls = &cpu_sysdev_class; |
119 | 118 | ||
120 | error = sysdev_register(&cpu->sysdev); | 119 | error = sysdev_register(&cpu->sysdev); |
121 | if (!error && root) | 120 | |
122 | error = sysfs_create_link(&root->sysdev.kobj, | ||
123 | &cpu->sysdev.kobj, | ||
124 | kobject_name(&cpu->sysdev.kobj)); | ||
125 | if (!error && !cpu->no_control) | 121 | if (!error && !cpu->no_control) |
126 | register_cpu_control(cpu); | 122 | register_cpu_control(cpu); |
127 | if (!error) | 123 | if (!error) |
128 | cpu_sys_devices[num] = &cpu->sysdev; | 124 | cpu_sys_devices[num] = &cpu->sysdev; |
125 | if (!error) | ||
126 | register_cpu_under_node(num, cpu_to_node(num)); | ||
129 | 127 | ||
130 | #ifdef CONFIG_KEXEC | 128 | #ifdef CONFIG_KEXEC |
131 | if (!error) | 129 | if (!error) |
@@ -145,5 +143,13 @@ EXPORT_SYMBOL_GPL(get_cpu_sysdev); | |||
145 | 143 | ||
146 | int __init cpu_dev_init(void) | 144 | int __init cpu_dev_init(void) |
147 | { | 145 | { |
148 | return sysdev_class_register(&cpu_sysdev_class); | 146 | int err; |
147 | |||
148 | err = sysdev_class_register(&cpu_sysdev_class); | ||
149 | #if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT) | ||
150 | if (!err) | ||
151 | err = sched_create_sysfs_power_savings_entries(&cpu_sysdev_class); | ||
152 | #endif | ||
153 | |||
154 | return err; | ||
149 | } | 155 | } |
diff --git a/drivers/base/dmapool.c b/drivers/base/dmapool.c index e2f64f91ed05..33c5cce1560b 100644 --- a/drivers/base/dmapool.c +++ b/drivers/base/dmapool.c | |||
@@ -7,6 +7,7 @@ | |||
7 | #include <linux/dmapool.h> | 7 | #include <linux/dmapool.h> |
8 | #include <linux/slab.h> | 8 | #include <linux/slab.h> |
9 | #include <linux/module.h> | 9 | #include <linux/module.h> |
10 | #include <linux/poison.h> | ||
10 | 11 | ||
11 | /* | 12 | /* |
12 | * Pool allocator ... wraps the dma_alloc_coherent page allocator, so | 13 | * Pool allocator ... wraps the dma_alloc_coherent page allocator, so |
@@ -35,8 +36,6 @@ struct dma_page { /* cacheable header for 'allocation' bytes */ | |||
35 | }; | 36 | }; |
36 | 37 | ||
37 | #define POOL_TIMEOUT_JIFFIES ((100 /* msec */ * HZ) / 1000) | 38 | #define POOL_TIMEOUT_JIFFIES ((100 /* msec */ * HZ) / 1000) |
38 | #define POOL_POISON_FREED 0xa7 /* !inuse */ | ||
39 | #define POOL_POISON_ALLOCATED 0xa9 /* !initted */ | ||
40 | 39 | ||
41 | static DECLARE_MUTEX (pools_lock); | 40 | static DECLARE_MUTEX (pools_lock); |
42 | 41 | ||
diff --git a/drivers/base/memory.c b/drivers/base/memory.c index dd547af4681a..c6b7d9c4b651 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c | |||
@@ -306,11 +306,13 @@ static ssize_t | |||
306 | memory_probe_store(struct class *class, const char *buf, size_t count) | 306 | memory_probe_store(struct class *class, const char *buf, size_t count) |
307 | { | 307 | { |
308 | u64 phys_addr; | 308 | u64 phys_addr; |
309 | int nid; | ||
309 | int ret; | 310 | int ret; |
310 | 311 | ||
311 | phys_addr = simple_strtoull(buf, NULL, 0); | 312 | phys_addr = simple_strtoull(buf, NULL, 0); |
312 | 313 | ||
313 | ret = add_memory(phys_addr, PAGES_PER_SECTION << PAGE_SHIFT); | 314 | nid = memory_add_physaddr_to_nid(phys_addr); |
315 | ret = add_memory(nid, phys_addr, PAGES_PER_SECTION << PAGE_SHIFT); | ||
314 | 316 | ||
315 | if (ret) | 317 | if (ret) |
316 | count = ret; | 318 | count = ret; |
diff --git a/drivers/base/node.c b/drivers/base/node.c index c80c3aeed004..eae2bdc183bb 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/cpumask.h> | 11 | #include <linux/cpumask.h> |
12 | #include <linux/topology.h> | 12 | #include <linux/topology.h> |
13 | #include <linux/nodemask.h> | 13 | #include <linux/nodemask.h> |
14 | #include <linux/cpu.h> | ||
14 | 15 | ||
15 | static struct sysdev_class node_class = { | 16 | static struct sysdev_class node_class = { |
16 | set_kset_name("node"), | 17 | set_kset_name("node"), |
@@ -190,6 +191,66 @@ void unregister_node(struct node *node) | |||
190 | sysdev_unregister(&node->sysdev); | 191 | sysdev_unregister(&node->sysdev); |
191 | } | 192 | } |
192 | 193 | ||
194 | struct node node_devices[MAX_NUMNODES]; | ||
195 | |||
196 | /* | ||
197 | * register cpu under node | ||
198 | */ | ||
199 | int register_cpu_under_node(unsigned int cpu, unsigned int nid) | ||
200 | { | ||
201 | if (node_online(nid)) { | ||
202 | struct sys_device *obj = get_cpu_sysdev(cpu); | ||
203 | if (!obj) | ||
204 | return 0; | ||
205 | return sysfs_create_link(&node_devices[nid].sysdev.kobj, | ||
206 | &obj->kobj, | ||
207 | kobject_name(&obj->kobj)); | ||
208 | } | ||
209 | |||
210 | return 0; | ||
211 | } | ||
212 | |||
213 | int unregister_cpu_under_node(unsigned int cpu, unsigned int nid) | ||
214 | { | ||
215 | if (node_online(nid)) { | ||
216 | struct sys_device *obj = get_cpu_sysdev(cpu); | ||
217 | if (obj) | ||
218 | sysfs_remove_link(&node_devices[nid].sysdev.kobj, | ||
219 | kobject_name(&obj->kobj)); | ||
220 | } | ||
221 | return 0; | ||
222 | } | ||
223 | |||
224 | int register_one_node(int nid) | ||
225 | { | ||
226 | int error = 0; | ||
227 | int cpu; | ||
228 | |||
229 | if (node_online(nid)) { | ||
230 | int p_node = parent_node(nid); | ||
231 | struct node *parent = NULL; | ||
232 | |||
233 | if (p_node != nid) | ||
234 | parent = &node_devices[p_node]; | ||
235 | |||
236 | error = register_node(&node_devices[nid], nid, parent); | ||
237 | |||
238 | /* link cpu under this node */ | ||
239 | for_each_present_cpu(cpu) { | ||
240 | if (cpu_to_node(cpu) == nid) | ||
241 | register_cpu_under_node(cpu, nid); | ||
242 | } | ||
243 | } | ||
244 | |||
245 | return error; | ||
246 | |||
247 | } | ||
248 | |||
249 | void unregister_one_node(int nid) | ||
250 | { | ||
251 | unregister_node(&node_devices[nid]); | ||
252 | } | ||
253 | |||
193 | static int __init register_node_type(void) | 254 | static int __init register_node_type(void) |
194 | { | 255 | { |
195 | return sysdev_class_register(&node_class); | 256 | return sysdev_class_register(&node_class); |
diff --git a/drivers/base/power/resume.c b/drivers/base/power/resume.c index 520679ce53a8..826093ef4c7e 100644 --- a/drivers/base/power/resume.c +++ b/drivers/base/power/resume.c | |||
@@ -53,8 +53,7 @@ void dpm_resume(void) | |||
53 | struct device * dev = to_device(entry); | 53 | struct device * dev = to_device(entry); |
54 | 54 | ||
55 | get_device(dev); | 55 | get_device(dev); |
56 | list_del_init(entry); | 56 | list_move_tail(entry, &dpm_active); |
57 | list_add_tail(entry, &dpm_active); | ||
58 | 57 | ||
59 | up(&dpm_list_sem); | 58 | up(&dpm_list_sem); |
60 | if (!dev->power.prev_state.event) | 59 | if (!dev->power.prev_state.event) |
@@ -101,8 +100,7 @@ void dpm_power_up(void) | |||
101 | struct device * dev = to_device(entry); | 100 | struct device * dev = to_device(entry); |
102 | 101 | ||
103 | get_device(dev); | 102 | get_device(dev); |
104 | list_del_init(entry); | 103 | list_move_tail(entry, &dpm_active); |
105 | list_add_tail(entry, &dpm_active); | ||
106 | resume_device(dev); | 104 | resume_device(dev); |
107 | put_device(dev); | 105 | put_device(dev); |
108 | } | 106 | } |
diff --git a/drivers/base/power/suspend.c b/drivers/base/power/suspend.c index 1a1fe43a3057..69509e02f703 100644 --- a/drivers/base/power/suspend.c +++ b/drivers/base/power/suspend.c | |||
@@ -116,12 +116,10 @@ int device_suspend(pm_message_t state) | |||
116 | /* Check if the device got removed */ | 116 | /* Check if the device got removed */ |
117 | if (!list_empty(&dev->power.entry)) { | 117 | if (!list_empty(&dev->power.entry)) { |
118 | /* Move it to the dpm_off or dpm_off_irq list */ | 118 | /* Move it to the dpm_off or dpm_off_irq list */ |
119 | if (!error) { | 119 | if (!error) |
120 | list_del(&dev->power.entry); | 120 | list_move(&dev->power.entry, &dpm_off); |
121 | list_add(&dev->power.entry, &dpm_off); | 121 | else if (error == -EAGAIN) { |
122 | } else if (error == -EAGAIN) { | 122 | list_move(&dev->power.entry, &dpm_off_irq); |
123 | list_del(&dev->power.entry); | ||
124 | list_add(&dev->power.entry, &dpm_off_irq); | ||
125 | error = 0; | 123 | error = 0; |
126 | } | 124 | } |
127 | } | 125 | } |
@@ -139,8 +137,7 @@ int device_suspend(pm_message_t state) | |||
139 | */ | 137 | */ |
140 | while (!list_empty(&dpm_off_irq)) { | 138 | while (!list_empty(&dpm_off_irq)) { |
141 | struct list_head * entry = dpm_off_irq.next; | 139 | struct list_head * entry = dpm_off_irq.next; |
142 | list_del(entry); | 140 | list_move(entry, &dpm_off); |
143 | list_add(entry, &dpm_off); | ||
144 | } | 141 | } |
145 | dpm_resume(); | 142 | dpm_resume(); |
146 | } | 143 | } |
diff --git a/drivers/base/topology.c b/drivers/base/topology.c index 8c52421cbc54..c2d621632383 100644 --- a/drivers/base/topology.c +++ b/drivers/base/topology.c | |||
@@ -107,7 +107,7 @@ static int __cpuinit topology_remove_dev(struct sys_device * sys_dev) | |||
107 | return 0; | 107 | return 0; |
108 | } | 108 | } |
109 | 109 | ||
110 | static int topology_cpu_callback(struct notifier_block *nfb, | 110 | static int __cpuinit topology_cpu_callback(struct notifier_block *nfb, |
111 | unsigned long action, void *hcpu) | 111 | unsigned long action, void *hcpu) |
112 | { | 112 | { |
113 | unsigned int cpu = (unsigned long)hcpu; | 113 | unsigned int cpu = (unsigned long)hcpu; |
@@ -125,7 +125,7 @@ static int topology_cpu_callback(struct notifier_block *nfb, | |||
125 | return NOTIFY_OK; | 125 | return NOTIFY_OK; |
126 | } | 126 | } |
127 | 127 | ||
128 | static struct notifier_block topology_cpu_notifier = | 128 | static struct notifier_block __cpuinitdata topology_cpu_notifier = |
129 | { | 129 | { |
130 | .notifier_call = topology_cpu_callback, | 130 | .notifier_call = topology_cpu_callback, |
131 | }; | 131 | }; |
diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 9dc294a74953..3c74ea729fc7 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c | |||
@@ -74,7 +74,6 @@ | |||
74 | #include <linux/completion.h> | 74 | #include <linux/completion.h> |
75 | #include <linux/highmem.h> | 75 | #include <linux/highmem.h> |
76 | #include <linux/gfp.h> | 76 | #include <linux/gfp.h> |
77 | #include <linux/kthread.h> | ||
78 | 77 | ||
79 | #include <asm/uaccess.h> | 78 | #include <asm/uaccess.h> |
80 | 79 | ||
@@ -579,6 +578,8 @@ static int loop_thread(void *data) | |||
579 | struct loop_device *lo = data; | 578 | struct loop_device *lo = data; |
580 | struct bio *bio; | 579 | struct bio *bio; |
581 | 580 | ||
581 | daemonize("loop%d", lo->lo_number); | ||
582 | |||
582 | /* | 583 | /* |
583 | * loop can be used in an encrypted device, | 584 | * loop can be used in an encrypted device, |
584 | * hence, it mustn't be stopped at all | 585 | * hence, it mustn't be stopped at all |
@@ -591,6 +592,11 @@ static int loop_thread(void *data) | |||
591 | lo->lo_state = Lo_bound; | 592 | lo->lo_state = Lo_bound; |
592 | lo->lo_pending = 1; | 593 | lo->lo_pending = 1; |
593 | 594 | ||
595 | /* | ||
596 | * complete it, we are running | ||
597 | */ | ||
598 | complete(&lo->lo_done); | ||
599 | |||
594 | for (;;) { | 600 | for (;;) { |
595 | int pending; | 601 | int pending; |
596 | 602 | ||
@@ -623,6 +629,7 @@ static int loop_thread(void *data) | |||
623 | break; | 629 | break; |
624 | } | 630 | } |
625 | 631 | ||
632 | complete(&lo->lo_done); | ||
626 | return 0; | 633 | return 0; |
627 | } | 634 | } |
628 | 635 | ||
@@ -739,7 +746,6 @@ static int loop_set_fd(struct loop_device *lo, struct file *lo_file, | |||
739 | unsigned lo_blocksize; | 746 | unsigned lo_blocksize; |
740 | int lo_flags = 0; | 747 | int lo_flags = 0; |
741 | int error; | 748 | int error; |
742 | struct task_struct *tsk; | ||
743 | loff_t size; | 749 | loff_t size; |
744 | 750 | ||
745 | /* This is safe, since we have a reference from open(). */ | 751 | /* This is safe, since we have a reference from open(). */ |
@@ -833,11 +839,10 @@ static int loop_set_fd(struct loop_device *lo, struct file *lo_file, | |||
833 | 839 | ||
834 | set_blocksize(bdev, lo_blocksize); | 840 | set_blocksize(bdev, lo_blocksize); |
835 | 841 | ||
836 | tsk = kthread_run(loop_thread, lo, "loop%d", lo->lo_number); | 842 | error = kernel_thread(loop_thread, lo, CLONE_KERNEL); |
837 | if (IS_ERR(tsk)) { | 843 | if (error < 0) |
838 | error = PTR_ERR(tsk); | ||
839 | goto out_putf; | 844 | goto out_putf; |
840 | } | 845 | wait_for_completion(&lo->lo_done); |
841 | return 0; | 846 | return 0; |
842 | 847 | ||
843 | out_putf: | 848 | out_putf: |
@@ -893,9 +898,6 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev) | |||
893 | if (lo->lo_state != Lo_bound) | 898 | if (lo->lo_state != Lo_bound) |
894 | return -ENXIO; | 899 | return -ENXIO; |
895 | 900 | ||
896 | if (!lo->lo_thread) | ||
897 | return -EINVAL; | ||
898 | |||
899 | if (lo->lo_refcnt > 1) /* we needed one fd for the ioctl */ | 901 | if (lo->lo_refcnt > 1) /* we needed one fd for the ioctl */ |
900 | return -EBUSY; | 902 | return -EBUSY; |
901 | 903 | ||
@@ -909,7 +911,7 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev) | |||
909 | complete(&lo->lo_bh_done); | 911 | complete(&lo->lo_bh_done); |
910 | spin_unlock_irq(&lo->lo_lock); | 912 | spin_unlock_irq(&lo->lo_lock); |
911 | 913 | ||
912 | kthread_stop(lo->lo_thread); | 914 | wait_for_completion(&lo->lo_done); |
913 | 915 | ||
914 | lo->lo_backing_file = NULL; | 916 | lo->lo_backing_file = NULL; |
915 | 917 | ||
@@ -922,7 +924,6 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev) | |||
922 | lo->lo_sizelimit = 0; | 924 | lo->lo_sizelimit = 0; |
923 | lo->lo_encrypt_key_size = 0; | 925 | lo->lo_encrypt_key_size = 0; |
924 | lo->lo_flags = 0; | 926 | lo->lo_flags = 0; |
925 | lo->lo_thread = NULL; | ||
926 | memset(lo->lo_encrypt_key, 0, LO_KEY_SIZE); | 927 | memset(lo->lo_encrypt_key, 0, LO_KEY_SIZE); |
927 | memset(lo->lo_crypt_name, 0, LO_NAME_SIZE); | 928 | memset(lo->lo_crypt_name, 0, LO_NAME_SIZE); |
928 | memset(lo->lo_file_name, 0, LO_NAME_SIZE); | 929 | memset(lo->lo_file_name, 0, LO_NAME_SIZE); |
@@ -1287,6 +1288,7 @@ static int __init loop_init(void) | |||
1287 | if (!lo->lo_queue) | 1288 | if (!lo->lo_queue) |
1288 | goto out_mem4; | 1289 | goto out_mem4; |
1289 | mutex_init(&lo->lo_ctl_mutex); | 1290 | mutex_init(&lo->lo_ctl_mutex); |
1291 | init_completion(&lo->lo_done); | ||
1290 | init_completion(&lo->lo_bh_done); | 1292 | init_completion(&lo->lo_bh_done); |
1291 | lo->lo_number = i; | 1293 | lo->lo_number = i; |
1292 | spin_lock_init(&lo->lo_lock); | 1294 | spin_lock_init(&lo->lo_lock); |
diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c index a71a240611e0..ed8dca84ff69 100644 --- a/drivers/bluetooth/dtl1_cs.c +++ b/drivers/bluetooth/dtl1_cs.c | |||
@@ -423,6 +423,9 @@ static int dtl1_hci_send_frame(struct sk_buff *skb) | |||
423 | nsh.len = skb->len; | 423 | nsh.len = skb->len; |
424 | 424 | ||
425 | s = bt_skb_alloc(NSHL + skb->len + 1, GFP_ATOMIC); | 425 | s = bt_skb_alloc(NSHL + skb->len + 1, GFP_ATOMIC); |
426 | if (!s) | ||
427 | return -ENOMEM; | ||
428 | |||
426 | skb_reserve(s, NSHL); | 429 | skb_reserve(s, NSHL); |
427 | memcpy(skb_put(s, skb->len), skb->data, skb->len); | 430 | memcpy(skb_put(s, skb->len), skb->data, skb->len); |
428 | if (skb->len & 0x0001) | 431 | if (skb->len & 0x0001) |
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 63f28d169b36..410d70cb76fb 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig | |||
@@ -62,6 +62,23 @@ config HW_CONSOLE | |||
62 | depends on VT && !S390 && !UML | 62 | depends on VT && !S390 && !UML |
63 | default y | 63 | default y |
64 | 64 | ||
65 | config VT_HW_CONSOLE_BINDING | ||
66 | bool "Support for binding and unbinding console drivers" | ||
67 | depends on HW_CONSOLE | ||
68 | default n | ||
69 | ---help--- | ||
70 | The virtual terminal is the device that interacts with the physical | ||
71 | terminal through console drivers. On these systems, at least one | ||
72 | console driver is loaded. In other configurations, additional console | ||
73 | drivers may be enabled, such as the framebuffer console. If more than | ||
74 | 1 console driver is enabled, setting this to 'y' will allow you to | ||
75 | select the console driver that will serve as the backend for the | ||
76 | virtual terminals. | ||
77 | |||
78 | See <file:Documentation/console/console.txt> for more | ||
79 | information. For framebuffer console users, please refer to | ||
80 | <file:Documentation/fb/fbcon.txt>. | ||
81 | |||
65 | config SERIAL_NONSTANDARD | 82 | config SERIAL_NONSTANDARD |
66 | bool "Non-standard serial port support" | 83 | bool "Non-standard serial port support" |
67 | ---help--- | 84 | ---help--- |
@@ -670,20 +687,7 @@ config NWFLASH | |||
670 | 687 | ||
671 | If you're not sure, say N. | 688 | If you're not sure, say N. |
672 | 689 | ||
673 | config HW_RANDOM | 690 | source "drivers/char/hw_random/Kconfig" |
674 | tristate "Intel/AMD/VIA HW Random Number Generator support" | ||
675 | depends on (X86 || IA64) && PCI | ||
676 | ---help--- | ||
677 | This driver provides kernel-side support for the Random Number | ||
678 | Generator hardware found on Intel i8xx-based motherboards, | ||
679 | AMD 76x-based motherboards, and Via Nehemiah CPUs. | ||
680 | |||
681 | Provides a character driver, used to read() entropy data. | ||
682 | |||
683 | To compile this driver as a module, choose M here: the | ||
684 | module will be called hw_random. | ||
685 | |||
686 | If unsure, say N. | ||
687 | 691 | ||
688 | config NVRAM | 692 | config NVRAM |
689 | tristate "/dev/nvram support" | 693 | tristate "/dev/nvram support" |
@@ -935,12 +939,35 @@ config MWAVE | |||
935 | config SCx200_GPIO | 939 | config SCx200_GPIO |
936 | tristate "NatSemi SCx200 GPIO Support" | 940 | tristate "NatSemi SCx200 GPIO Support" |
937 | depends on SCx200 | 941 | depends on SCx200 |
942 | select NSC_GPIO | ||
938 | help | 943 | help |
939 | Give userspace access to the GPIO pins on the National | 944 | Give userspace access to the GPIO pins on the National |
940 | Semiconductor SCx200 processors. | 945 | Semiconductor SCx200 processors. |
941 | 946 | ||
942 | If compiled as a module, it will be called scx200_gpio. | 947 | If compiled as a module, it will be called scx200_gpio. |
943 | 948 | ||
949 | config PC8736x_GPIO | ||
950 | tristate "NatSemi PC8736x GPIO Support" | ||
951 | depends on X86 | ||
952 | default SCx200_GPIO # mostly N | ||
953 | select NSC_GPIO # needed for support routines | ||
954 | help | ||
955 | Give userspace access to the GPIO pins on the National | ||
956 | Semiconductor PC-8736x (x=[03456]) SuperIO chip. The chip | ||
957 | has multiple functional units, inc several managed by | ||
958 | hwmon/pc87360 driver. Tested with PC-87366 | ||
959 | |||
960 | If compiled as a module, it will be called pc8736x_gpio. | ||
961 | |||
962 | config NSC_GPIO | ||
963 | tristate "NatSemi Base GPIO Support" | ||
964 | # selected by SCx200_GPIO and PC8736x_GPIO | ||
965 | # what about 2 selectors differing: m != y | ||
966 | help | ||
967 | Common support used (and needed) by scx200_gpio and | ||
968 | pc8736x_gpio drivers. If those drivers are built as | ||
969 | modules, this one will be too, named nsc_gpio | ||
970 | |||
944 | config CS5535_GPIO | 971 | config CS5535_GPIO |
945 | tristate "AMD CS5535/CS5536 GPIO (Geode Companion Device)" | 972 | tristate "AMD CS5535/CS5536 GPIO (Geode Companion Device)" |
946 | depends on X86_32 | 973 | depends on X86_32 |
diff --git a/drivers/char/Makefile b/drivers/char/Makefile index fb919bfb2824..6e0f4469d8bb 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile | |||
@@ -75,13 +75,15 @@ endif | |||
75 | obj-$(CONFIG_TOSHIBA) += toshiba.o | 75 | obj-$(CONFIG_TOSHIBA) += toshiba.o |
76 | obj-$(CONFIG_I8K) += i8k.o | 76 | obj-$(CONFIG_I8K) += i8k.o |
77 | obj-$(CONFIG_DS1620) += ds1620.o | 77 | obj-$(CONFIG_DS1620) += ds1620.o |
78 | obj-$(CONFIG_HW_RANDOM) += hw_random.o | 78 | obj-$(CONFIG_HW_RANDOM) += hw_random/ |
79 | obj-$(CONFIG_FTAPE) += ftape/ | 79 | obj-$(CONFIG_FTAPE) += ftape/ |
80 | obj-$(CONFIG_COBALT_LCD) += lcd.o | 80 | obj-$(CONFIG_COBALT_LCD) += lcd.o |
81 | obj-$(CONFIG_PPDEV) += ppdev.o | 81 | obj-$(CONFIG_PPDEV) += ppdev.o |
82 | obj-$(CONFIG_NWBUTTON) += nwbutton.o | 82 | obj-$(CONFIG_NWBUTTON) += nwbutton.o |
83 | obj-$(CONFIG_NWFLASH) += nwflash.o | 83 | obj-$(CONFIG_NWFLASH) += nwflash.o |
84 | obj-$(CONFIG_SCx200_GPIO) += scx200_gpio.o | 84 | obj-$(CONFIG_SCx200_GPIO) += scx200_gpio.o |
85 | obj-$(CONFIG_PC8736x_GPIO) += pc8736x_gpio.o | ||
86 | obj-$(CONFIG_NSC_GPIO) += nsc_gpio.o | ||
85 | obj-$(CONFIG_CS5535_GPIO) += cs5535_gpio.o | 87 | obj-$(CONFIG_CS5535_GPIO) += cs5535_gpio.o |
86 | obj-$(CONFIG_GPIO_VR41XX) += vr41xx_giu.o | 88 | obj-$(CONFIG_GPIO_VR41XX) += vr41xx_giu.o |
87 | obj-$(CONFIG_TANBAC_TB0219) += tb0219.o | 89 | obj-$(CONFIG_TANBAC_TB0219) += tb0219.o |
diff --git a/drivers/char/agp/Kconfig b/drivers/char/agp/Kconfig index 46685a540772..9826a399fa02 100644 --- a/drivers/char/agp/Kconfig +++ b/drivers/char/agp/Kconfig | |||
@@ -55,9 +55,9 @@ config AGP_AMD | |||
55 | X on AMD Irongate, 761, and 762 chipsets. | 55 | X on AMD Irongate, 761, and 762 chipsets. |
56 | 56 | ||
57 | config AGP_AMD64 | 57 | config AGP_AMD64 |
58 | tristate "AMD Opteron/Athlon64 on-CPU GART support" if !GART_IOMMU | 58 | tristate "AMD Opteron/Athlon64 on-CPU GART support" if !IOMMU |
59 | depends on AGP && X86 | 59 | depends on AGP && X86 |
60 | default y if GART_IOMMU | 60 | default y if IOMMU |
61 | help | 61 | help |
62 | This option gives you AGP support for the GLX component of | 62 | This option gives you AGP support for the GLX component of |
63 | X using the on-CPU northbridge of the AMD Athlon64/Opteron CPUs. | 63 | X using the on-CPU northbridge of the AMD Athlon64/Opteron CPUs. |
diff --git a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c index 1f776651ac64..51d0d562d01e 100644 --- a/drivers/char/agp/amd-k7-agp.c +++ b/drivers/char/agp/amd-k7-agp.c | |||
@@ -118,7 +118,7 @@ static int amd_create_gatt_pages(int nr_tables) | |||
118 | return retval; | 118 | return retval; |
119 | } | 119 | } |
120 | 120 | ||
121 | /* Since we don't need contigious memory we just try | 121 | /* Since we don't need contiguous memory we just try |
122 | * to get the gatt table once | 122 | * to get the gatt table once |
123 | */ | 123 | */ |
124 | 124 | ||
diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c index ac3c33a2e37d..f690ee8cb732 100644 --- a/drivers/char/agp/amd64-agp.c +++ b/drivers/char/agp/amd64-agp.c | |||
@@ -15,11 +15,9 @@ | |||
15 | #include <linux/agp_backend.h> | 15 | #include <linux/agp_backend.h> |
16 | #include <linux/mmzone.h> | 16 | #include <linux/mmzone.h> |
17 | #include <asm/page.h> /* PAGE_SIZE */ | 17 | #include <asm/page.h> /* PAGE_SIZE */ |
18 | #include <asm/k8.h> | ||
18 | #include "agp.h" | 19 | #include "agp.h" |
19 | 20 | ||
20 | /* Will need to be increased if AMD64 ever goes >8-way. */ | ||
21 | #define MAX_HAMMER_GARTS 8 | ||
22 | |||
23 | /* PTE bits. */ | 21 | /* PTE bits. */ |
24 | #define GPTE_VALID 1 | 22 | #define GPTE_VALID 1 |
25 | #define GPTE_COHERENT 2 | 23 | #define GPTE_COHERENT 2 |
@@ -53,28 +51,12 @@ | |||
53 | #define ULI_X86_64_HTT_FEA_REG 0x50 | 51 | #define ULI_X86_64_HTT_FEA_REG 0x50 |
54 | #define ULI_X86_64_ENU_SCR_REG 0x54 | 52 | #define ULI_X86_64_ENU_SCR_REG 0x54 |
55 | 53 | ||
56 | static int nr_garts; | ||
57 | static struct pci_dev * hammers[MAX_HAMMER_GARTS]; | ||
58 | |||
59 | static struct resource *aperture_resource; | 54 | static struct resource *aperture_resource; |
60 | static int __initdata agp_try_unsupported = 1; | 55 | static int __initdata agp_try_unsupported = 1; |
61 | 56 | ||
62 | #define for_each_nb() for(gart_iterator=0;gart_iterator<nr_garts;gart_iterator++) | ||
63 | |||
64 | static void flush_amd64_tlb(struct pci_dev *dev) | ||
65 | { | ||
66 | u32 tmp; | ||
67 | |||
68 | pci_read_config_dword (dev, AMD64_GARTCACHECTL, &tmp); | ||
69 | tmp |= INVGART; | ||
70 | pci_write_config_dword (dev, AMD64_GARTCACHECTL, tmp); | ||
71 | } | ||
72 | |||
73 | static void amd64_tlbflush(struct agp_memory *temp) | 57 | static void amd64_tlbflush(struct agp_memory *temp) |
74 | { | 58 | { |
75 | int gart_iterator; | 59 | k8_flush_garts(); |
76 | for_each_nb() | ||
77 | flush_amd64_tlb(hammers[gart_iterator]); | ||
78 | } | 60 | } |
79 | 61 | ||
80 | static int amd64_insert_memory(struct agp_memory *mem, off_t pg_start, int type) | 62 | static int amd64_insert_memory(struct agp_memory *mem, off_t pg_start, int type) |
@@ -153,7 +135,7 @@ static int amd64_fetch_size(void) | |||
153 | u32 temp; | 135 | u32 temp; |
154 | struct aper_size_info_32 *values; | 136 | struct aper_size_info_32 *values; |
155 | 137 | ||
156 | dev = hammers[0]; | 138 | dev = k8_northbridges[0]; |
157 | if (dev==NULL) | 139 | if (dev==NULL) |
158 | return 0; | 140 | return 0; |
159 | 141 | ||
@@ -201,9 +183,6 @@ static u64 amd64_configure (struct pci_dev *hammer, u64 gatt_table) | |||
201 | tmp &= ~(DISGARTCPU | DISGARTIO); | 183 | tmp &= ~(DISGARTCPU | DISGARTIO); |
202 | pci_write_config_dword(hammer, AMD64_GARTAPERTURECTL, tmp); | 184 | pci_write_config_dword(hammer, AMD64_GARTAPERTURECTL, tmp); |
203 | 185 | ||
204 | /* keep CPU's coherent. */ | ||
205 | flush_amd64_tlb (hammer); | ||
206 | |||
207 | return aper_base; | 186 | return aper_base; |
208 | } | 187 | } |
209 | 188 | ||
@@ -222,13 +201,14 @@ static struct aper_size_info_32 amd_8151_sizes[7] = | |||
222 | static int amd_8151_configure(void) | 201 | static int amd_8151_configure(void) |
223 | { | 202 | { |
224 | unsigned long gatt_bus = virt_to_gart(agp_bridge->gatt_table_real); | 203 | unsigned long gatt_bus = virt_to_gart(agp_bridge->gatt_table_real); |
225 | int gart_iterator; | 204 | int i; |
226 | 205 | ||
227 | /* Configure AGP regs in each x86-64 host bridge. */ | 206 | /* Configure AGP regs in each x86-64 host bridge. */ |
228 | for_each_nb() { | 207 | for (i = 0; i < num_k8_northbridges; i++) { |
229 | agp_bridge->gart_bus_addr = | 208 | agp_bridge->gart_bus_addr = |
230 | amd64_configure(hammers[gart_iterator],gatt_bus); | 209 | amd64_configure(k8_northbridges[i], gatt_bus); |
231 | } | 210 | } |
211 | k8_flush_garts(); | ||
232 | return 0; | 212 | return 0; |
233 | } | 213 | } |
234 | 214 | ||
@@ -236,12 +216,13 @@ static int amd_8151_configure(void) | |||
236 | static void amd64_cleanup(void) | 216 | static void amd64_cleanup(void) |
237 | { | 217 | { |
238 | u32 tmp; | 218 | u32 tmp; |
239 | int gart_iterator; | 219 | int i; |
240 | for_each_nb() { | 220 | for (i = 0; i < num_k8_northbridges; i++) { |
221 | struct pci_dev *dev = k8_northbridges[i]; | ||
241 | /* disable gart translation */ | 222 | /* disable gart translation */ |
242 | pci_read_config_dword (hammers[gart_iterator], AMD64_GARTAPERTURECTL, &tmp); | 223 | pci_read_config_dword (dev, AMD64_GARTAPERTURECTL, &tmp); |
243 | tmp &= ~AMD64_GARTEN; | 224 | tmp &= ~AMD64_GARTEN; |
244 | pci_write_config_dword (hammers[gart_iterator], AMD64_GARTAPERTURECTL, tmp); | 225 | pci_write_config_dword (dev, AMD64_GARTAPERTURECTL, tmp); |
245 | } | 226 | } |
246 | } | 227 | } |
247 | 228 | ||
@@ -311,7 +292,7 @@ static int __devinit aperture_valid(u64 aper, u32 size) | |||
311 | /* | 292 | /* |
312 | * W*s centric BIOS sometimes only set up the aperture in the AGP | 293 | * W*s centric BIOS sometimes only set up the aperture in the AGP |
313 | * bridge, not the northbridge. On AMD64 this is handled early | 294 | * bridge, not the northbridge. On AMD64 this is handled early |
314 | * in aperture.c, but when GART_IOMMU is not enabled or we run | 295 | * in aperture.c, but when IOMMU is not enabled or we run |
315 | * on a 32bit kernel this needs to be redone. | 296 | * on a 32bit kernel this needs to be redone. |
316 | * Unfortunately it is impossible to fix the aperture here because it's too late | 297 | * Unfortunately it is impossible to fix the aperture here because it's too late |
317 | * to allocate that much memory. But at least error out cleanly instead of | 298 | * to allocate that much memory. But at least error out cleanly instead of |
@@ -361,17 +342,15 @@ static __devinit int fix_northbridge(struct pci_dev *nb, struct pci_dev *agp, | |||
361 | 342 | ||
362 | static __devinit int cache_nbs (struct pci_dev *pdev, u32 cap_ptr) | 343 | static __devinit int cache_nbs (struct pci_dev *pdev, u32 cap_ptr) |
363 | { | 344 | { |
364 | struct pci_dev *loop_dev = NULL; | 345 | int i; |
365 | int i = 0; | 346 | |
366 | 347 | if (cache_k8_northbridges() < 0) | |
367 | /* cache pci_devs of northbridges. */ | 348 | return -ENODEV; |
368 | while ((loop_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x1103, loop_dev)) | 349 | |
369 | != NULL) { | 350 | i = 0; |
370 | if (i == MAX_HAMMER_GARTS) { | 351 | for (i = 0; i < num_k8_northbridges; i++) { |
371 | printk(KERN_ERR PFX "Too many northbridges for AGP\n"); | 352 | struct pci_dev *dev = k8_northbridges[i]; |
372 | return -1; | 353 | if (fix_northbridge(dev, pdev, cap_ptr) < 0) { |
373 | } | ||
374 | if (fix_northbridge(loop_dev, pdev, cap_ptr) < 0) { | ||
375 | printk(KERN_ERR PFX "No usable aperture found.\n"); | 354 | printk(KERN_ERR PFX "No usable aperture found.\n"); |
376 | #ifdef __x86_64__ | 355 | #ifdef __x86_64__ |
377 | /* should port this to i386 */ | 356 | /* should port this to i386 */ |
@@ -379,10 +358,8 @@ static __devinit int cache_nbs (struct pci_dev *pdev, u32 cap_ptr) | |||
379 | #endif | 358 | #endif |
380 | return -1; | 359 | return -1; |
381 | } | 360 | } |
382 | hammers[i++] = loop_dev; | ||
383 | } | 361 | } |
384 | nr_garts = i; | 362 | return 0; |
385 | return i == 0 ? -1 : 0; | ||
386 | } | 363 | } |
387 | 364 | ||
388 | /* Handle AMD 8151 quirks */ | 365 | /* Handle AMD 8151 quirks */ |
@@ -450,7 +427,7 @@ static int __devinit uli_agp_init(struct pci_dev *pdev) | |||
450 | } | 427 | } |
451 | 428 | ||
452 | /* shadow x86-64 registers into ULi registers */ | 429 | /* shadow x86-64 registers into ULi registers */ |
453 | pci_read_config_dword (hammers[0], AMD64_GARTAPERTUREBASE, &httfea); | 430 | pci_read_config_dword (k8_northbridges[0], AMD64_GARTAPERTUREBASE, &httfea); |
454 | 431 | ||
455 | /* if x86-64 aperture base is beyond 4G, exit here */ | 432 | /* if x86-64 aperture base is beyond 4G, exit here */ |
456 | if ((httfea & 0x7fff) >> (32 - 25)) | 433 | if ((httfea & 0x7fff) >> (32 - 25)) |
@@ -513,7 +490,7 @@ static int __devinit nforce3_agp_init(struct pci_dev *pdev) | |||
513 | pci_write_config_dword(dev1, NVIDIA_X86_64_1_APSIZE, tmp); | 490 | pci_write_config_dword(dev1, NVIDIA_X86_64_1_APSIZE, tmp); |
514 | 491 | ||
515 | /* shadow x86-64 registers into NVIDIA registers */ | 492 | /* shadow x86-64 registers into NVIDIA registers */ |
516 | pci_read_config_dword (hammers[0], AMD64_GARTAPERTUREBASE, &apbase); | 493 | pci_read_config_dword (k8_northbridges[0], AMD64_GARTAPERTUREBASE, &apbase); |
517 | 494 | ||
518 | /* if x86-64 aperture base is beyond 4G, exit here */ | 495 | /* if x86-64 aperture base is beyond 4G, exit here */ |
519 | if ( (apbase & 0x7fff) >> (32 - 25) ) { | 496 | if ( (apbase & 0x7fff) >> (32 - 25) ) { |
@@ -754,10 +731,6 @@ static struct pci_driver agp_amd64_pci_driver = { | |||
754 | int __init agp_amd64_init(void) | 731 | int __init agp_amd64_init(void) |
755 | { | 732 | { |
756 | int err = 0; | 733 | int err = 0; |
757 | static struct pci_device_id amd64nb[] = { | ||
758 | { PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x1103) }, | ||
759 | { }, | ||
760 | }; | ||
761 | 734 | ||
762 | if (agp_off) | 735 | if (agp_off) |
763 | return -EINVAL; | 736 | return -EINVAL; |
@@ -774,7 +747,7 @@ int __init agp_amd64_init(void) | |||
774 | } | 747 | } |
775 | 748 | ||
776 | /* First check that we have at least one AMD64 NB */ | 749 | /* First check that we have at least one AMD64 NB */ |
777 | if (!pci_dev_present(amd64nb)) | 750 | if (!pci_dev_present(k8_nb_ids)) |
778 | return -ENODEV; | 751 | return -ENODEV; |
779 | 752 | ||
780 | /* Look for any AGP bridge */ | 753 | /* Look for any AGP bridge */ |
@@ -802,7 +775,7 @@ static void __exit agp_amd64_cleanup(void) | |||
802 | 775 | ||
803 | /* On AMD64 the PCI driver needs to initialize this driver early | 776 | /* On AMD64 the PCI driver needs to initialize this driver early |
804 | for the IOMMU, so it has to be called via a backdoor. */ | 777 | for the IOMMU, so it has to be called via a backdoor. */ |
805 | #ifndef CONFIG_GART_IOMMU | 778 | #ifndef CONFIG_IOMMU |
806 | module_init(agp_amd64_init); | 779 | module_init(agp_amd64_init); |
807 | module_exit(agp_amd64_cleanup); | 780 | module_exit(agp_amd64_cleanup); |
808 | #endif | 781 | #endif |
diff --git a/drivers/char/agp/ati-agp.c b/drivers/char/agp/ati-agp.c index 06fd10ba0c5e..160564345993 100644 --- a/drivers/char/agp/ati-agp.c +++ b/drivers/char/agp/ati-agp.c | |||
@@ -261,7 +261,7 @@ static int agp_ati_suspend(struct pci_dev *dev, pm_message_t state) | |||
261 | #endif | 261 | #endif |
262 | 262 | ||
263 | /* | 263 | /* |
264 | *Since we don't need contigious memory we just try | 264 | *Since we don't need contiguous memory we just try |
265 | * to get the gatt table once | 265 | * to get the gatt table once |
266 | */ | 266 | */ |
267 | 267 | ||
diff --git a/drivers/char/agp/efficeon-agp.c b/drivers/char/agp/efficeon-agp.c index 86a966b65236..b788b0a3bbf3 100644 --- a/drivers/char/agp/efficeon-agp.c +++ b/drivers/char/agp/efficeon-agp.c | |||
@@ -177,7 +177,7 @@ static int efficeon_free_gatt_table(struct agp_bridge_data *bridge) | |||
177 | 177 | ||
178 | 178 | ||
179 | /* | 179 | /* |
180 | * Since we don't need contigious memory we just try | 180 | * Since we don't need contiguous memory we just try |
181 | * to get the gatt table once | 181 | * to get the gatt table once |
182 | */ | 182 | */ |
183 | 183 | ||
diff --git a/drivers/char/agp/sgi-agp.c b/drivers/char/agp/sgi-agp.c index cfa7922cb431..d73be4c2db8a 100644 --- a/drivers/char/agp/sgi-agp.c +++ b/drivers/char/agp/sgi-agp.c | |||
@@ -329,9 +329,8 @@ static int __devinit agp_sgi_init(void) | |||
329 | 329 | ||
330 | static void __devexit agp_sgi_cleanup(void) | 330 | static void __devexit agp_sgi_cleanup(void) |
331 | { | 331 | { |
332 | if (sgi_tioca_agp_bridges) | 332 | kfree(sgi_tioca_agp_bridges); |
333 | kfree(sgi_tioca_agp_bridges); | 333 | sgi_tioca_agp_bridges = NULL; |
334 | sgi_tioca_agp_bridges=NULL; | ||
335 | } | 334 | } |
336 | 335 | ||
337 | module_init(agp_sgi_init); | 336 | module_init(agp_sgi_init); |
diff --git a/drivers/char/drm/drm_memory_debug.h b/drivers/char/drm/drm_memory_debug.h index 6543b9a14c42..d117cc997192 100644 --- a/drivers/char/drm/drm_memory_debug.h +++ b/drivers/char/drm/drm_memory_debug.h | |||
@@ -43,7 +43,7 @@ typedef struct drm_mem_stats { | |||
43 | unsigned long bytes_freed; | 43 | unsigned long bytes_freed; |
44 | } drm_mem_stats_t; | 44 | } drm_mem_stats_t; |
45 | 45 | ||
46 | static spinlock_t drm_mem_lock = SPIN_LOCK_UNLOCKED; | 46 | static DEFINE_SPINLOCK(drm_mem_lock); |
47 | static unsigned long drm_ram_available = 0; /* In pages */ | 47 | static unsigned long drm_ram_available = 0; /* In pages */ |
48 | static unsigned long drm_ram_used = 0; | 48 | static unsigned long drm_ram_used = 0; |
49 | static drm_mem_stats_t drm_mem_stats[] = | 49 | static drm_mem_stats_t drm_mem_stats[] = |
diff --git a/drivers/char/drm/via_dmablit.c b/drivers/char/drm/via_dmablit.c index b7f17457b424..78a81a4a99c5 100644 --- a/drivers/char/drm/via_dmablit.c +++ b/drivers/char/drm/via_dmablit.c | |||
@@ -557,7 +557,7 @@ via_init_dmablit(drm_device_t *dev) | |||
557 | blitq->num_outstanding = 0; | 557 | blitq->num_outstanding = 0; |
558 | blitq->is_active = 0; | 558 | blitq->is_active = 0; |
559 | blitq->aborting = 0; | 559 | blitq->aborting = 0; |
560 | blitq->blit_lock = SPIN_LOCK_UNLOCKED; | 560 | spin_lock_init(&blitq->blit_lock); |
561 | for (j=0; j<VIA_NUM_BLIT_SLOTS; ++j) { | 561 | for (j=0; j<VIA_NUM_BLIT_SLOTS; ++j) { |
562 | DRM_INIT_WAITQUEUE(blitq->blit_queue + j); | 562 | DRM_INIT_WAITQUEUE(blitq->blit_queue + j); |
563 | } | 563 | } |
diff --git a/drivers/char/epca.c b/drivers/char/epca.c index 9cad8501d62c..dc0602ae8503 100644 --- a/drivers/char/epca.c +++ b/drivers/char/epca.c | |||
@@ -80,7 +80,7 @@ static int invalid_lilo_config; | |||
80 | /* The ISA boards do window flipping into the same spaces so its only sane | 80 | /* The ISA boards do window flipping into the same spaces so its only sane |
81 | with a single lock. It's still pretty efficient */ | 81 | with a single lock. It's still pretty efficient */ |
82 | 82 | ||
83 | static spinlock_t epca_lock = SPIN_LOCK_UNLOCKED; | 83 | static DEFINE_SPINLOCK(epca_lock); |
84 | 84 | ||
85 | /* ----------------------------------------------------------------------- | 85 | /* ----------------------------------------------------------------------- |
86 | MAXBOARDS is typically 12, but ISA and EISA cards are restricted to | 86 | MAXBOARDS is typically 12, but ISA and EISA cards are restricted to |
diff --git a/drivers/char/hangcheck-timer.c b/drivers/char/hangcheck-timer.c index ac626418b329..d69f2ad9a67d 100644 --- a/drivers/char/hangcheck-timer.c +++ b/drivers/char/hangcheck-timer.c | |||
@@ -117,12 +117,12 @@ __setup("hcheck_reboot", hangcheck_parse_reboot); | |||
117 | __setup("hcheck_dump_tasks", hangcheck_parse_dump_tasks); | 117 | __setup("hcheck_dump_tasks", hangcheck_parse_dump_tasks); |
118 | #endif /* not MODULE */ | 118 | #endif /* not MODULE */ |
119 | 119 | ||
120 | #if defined(CONFIG_X86) || defined(CONFIG_S390) | 120 | #if defined(CONFIG_X86_64) || defined(CONFIG_S390) |
121 | # define HAVE_MONOTONIC | 121 | # define HAVE_MONOTONIC |
122 | # define TIMER_FREQ 1000000000ULL | 122 | # define TIMER_FREQ 1000000000ULL |
123 | #elif defined(CONFIG_IA64) | 123 | #elif defined(CONFIG_IA64) |
124 | # define TIMER_FREQ ((unsigned long long)local_cpu_data->itc_freq) | 124 | # define TIMER_FREQ ((unsigned long long)local_cpu_data->itc_freq) |
125 | #elif defined(CONFIG_PPC64) | 125 | #else |
126 | # define TIMER_FREQ (HZ*loops_per_jiffy) | 126 | # define TIMER_FREQ (HZ*loops_per_jiffy) |
127 | #endif | 127 | #endif |
128 | 128 | ||
diff --git a/drivers/char/hvcs.c b/drivers/char/hvcs.c index 8d97b3911293..afa26b65dac3 100644 --- a/drivers/char/hvcs.c +++ b/drivers/char/hvcs.c | |||
@@ -1320,11 +1320,12 @@ static struct tty_operations hvcs_ops = { | |||
1320 | static int hvcs_alloc_index_list(int n) | 1320 | static int hvcs_alloc_index_list(int n) |
1321 | { | 1321 | { |
1322 | int i; | 1322 | int i; |
1323 | |||
1323 | hvcs_index_list = kmalloc(n * sizeof(hvcs_index_count),GFP_KERNEL); | 1324 | hvcs_index_list = kmalloc(n * sizeof(hvcs_index_count),GFP_KERNEL); |
1324 | if (!hvcs_index_list) | 1325 | if (!hvcs_index_list) |
1325 | return -ENOMEM; | 1326 | return -ENOMEM; |
1326 | hvcs_index_count = n; | 1327 | hvcs_index_count = n; |
1327 | for(i = 0; i < hvcs_index_count; i++) | 1328 | for (i = 0; i < hvcs_index_count; i++) |
1328 | hvcs_index_list[i] = -1; | 1329 | hvcs_index_list[i] = -1; |
1329 | return 0; | 1330 | return 0; |
1330 | } | 1331 | } |
@@ -1332,11 +1333,9 @@ static int hvcs_alloc_index_list(int n) | |||
1332 | static void hvcs_free_index_list(void) | 1333 | static void hvcs_free_index_list(void) |
1333 | { | 1334 | { |
1334 | /* Paranoia check to be thorough. */ | 1335 | /* Paranoia check to be thorough. */ |
1335 | if (hvcs_index_list) { | 1336 | kfree(hvcs_index_list); |
1336 | kfree(hvcs_index_list); | 1337 | hvcs_index_list = NULL; |
1337 | hvcs_index_list = NULL; | 1338 | hvcs_index_count = 0; |
1338 | hvcs_index_count = 0; | ||
1339 | } | ||
1340 | } | 1339 | } |
1341 | 1340 | ||
1342 | static int __init hvcs_module_init(void) | 1341 | static int __init hvcs_module_init(void) |
diff --git a/drivers/char/hw_random.c b/drivers/char/hw_random.c deleted file mode 100644 index 29dc87e59020..000000000000 --- a/drivers/char/hw_random.c +++ /dev/null | |||
@@ -1,698 +0,0 @@ | |||
1 | /* | ||
2 | Added support for the AMD Geode LX RNG | ||
3 | (c) Copyright 2004-2005 Advanced Micro Devices, Inc. | ||
4 | |||
5 | derived from | ||
6 | |||
7 | Hardware driver for the Intel/AMD/VIA Random Number Generators (RNG) | ||
8 | (c) Copyright 2003 Red Hat Inc <jgarzik@redhat.com> | ||
9 | |||
10 | derived from | ||
11 | |||
12 | Hardware driver for the AMD 768 Random Number Generator (RNG) | ||
13 | (c) Copyright 2001 Red Hat Inc <alan@redhat.com> | ||
14 | |||
15 | derived from | ||
16 | |||
17 | Hardware driver for Intel i810 Random Number Generator (RNG) | ||
18 | Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com> | ||
19 | Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com> | ||
20 | |||
21 | Please read Documentation/hw_random.txt for details on use. | ||
22 | |||
23 | ---------------------------------------------------------- | ||
24 | This software may be used and distributed according to the terms | ||
25 | of the GNU General Public License, incorporated herein by reference. | ||
26 | |||
27 | */ | ||
28 | |||
29 | |||
30 | #include <linux/module.h> | ||
31 | #include <linux/kernel.h> | ||
32 | #include <linux/fs.h> | ||
33 | #include <linux/init.h> | ||
34 | #include <linux/pci.h> | ||
35 | #include <linux/interrupt.h> | ||
36 | #include <linux/spinlock.h> | ||
37 | #include <linux/random.h> | ||
38 | #include <linux/miscdevice.h> | ||
39 | #include <linux/smp_lock.h> | ||
40 | #include <linux/mm.h> | ||
41 | #include <linux/delay.h> | ||
42 | |||
43 | #ifdef __i386__ | ||
44 | #include <asm/msr.h> | ||
45 | #include <asm/cpufeature.h> | ||
46 | #endif | ||
47 | |||
48 | #include <asm/io.h> | ||
49 | #include <asm/uaccess.h> | ||
50 | |||
51 | |||
52 | /* | ||
53 | * core module and version information | ||
54 | */ | ||
55 | #define RNG_VERSION "1.0.0" | ||
56 | #define RNG_MODULE_NAME "hw_random" | ||
57 | #define RNG_DRIVER_NAME RNG_MODULE_NAME " hardware driver " RNG_VERSION | ||
58 | #define PFX RNG_MODULE_NAME ": " | ||
59 | |||
60 | |||
61 | /* | ||
62 | * debugging macros | ||
63 | */ | ||
64 | |||
65 | /* pr_debug() collapses to a no-op if DEBUG is not defined */ | ||
66 | #define DPRINTK(fmt, args...) pr_debug(PFX "%s: " fmt, __FUNCTION__ , ## args) | ||
67 | |||
68 | |||
69 | #undef RNG_NDEBUG /* define to enable lightweight runtime checks */ | ||
70 | #ifdef RNG_NDEBUG | ||
71 | #define assert(expr) \ | ||
72 | if(!(expr)) { \ | ||
73 | printk(KERN_DEBUG PFX "Assertion failed! %s,%s,%s," \ | ||
74 | "line=%d\n", #expr, __FILE__, __FUNCTION__, __LINE__); \ | ||
75 | } | ||
76 | #else | ||
77 | #define assert(expr) | ||
78 | #endif | ||
79 | |||
80 | #define RNG_MISCDEV_MINOR 183 /* official */ | ||
81 | |||
82 | static int rng_dev_open (struct inode *inode, struct file *filp); | ||
83 | static ssize_t rng_dev_read (struct file *filp, char __user *buf, size_t size, | ||
84 | loff_t * offp); | ||
85 | |||
86 | static int __init intel_init (struct pci_dev *dev); | ||
87 | static void intel_cleanup(void); | ||
88 | static unsigned int intel_data_present (void); | ||
89 | static u32 intel_data_read (void); | ||
90 | |||
91 | static int __init amd_init (struct pci_dev *dev); | ||
92 | static void amd_cleanup(void); | ||
93 | static unsigned int amd_data_present (void); | ||
94 | static u32 amd_data_read (void); | ||
95 | |||
96 | #ifdef __i386__ | ||
97 | static int __init via_init(struct pci_dev *dev); | ||
98 | static void via_cleanup(void); | ||
99 | static unsigned int via_data_present (void); | ||
100 | static u32 via_data_read (void); | ||
101 | #endif | ||
102 | |||
103 | static int __init geode_init(struct pci_dev *dev); | ||
104 | static void geode_cleanup(void); | ||
105 | static unsigned int geode_data_present (void); | ||
106 | static u32 geode_data_read (void); | ||
107 | |||
108 | struct rng_operations { | ||
109 | int (*init) (struct pci_dev *dev); | ||
110 | void (*cleanup) (void); | ||
111 | unsigned int (*data_present) (void); | ||
112 | u32 (*data_read) (void); | ||
113 | unsigned int n_bytes; /* number of bytes per ->data_read */ | ||
114 | }; | ||
115 | static struct rng_operations *rng_ops; | ||
116 | |||
117 | static struct file_operations rng_chrdev_ops = { | ||
118 | .owner = THIS_MODULE, | ||
119 | .open = rng_dev_open, | ||
120 | .read = rng_dev_read, | ||
121 | }; | ||
122 | |||
123 | |||
124 | static struct miscdevice rng_miscdev = { | ||
125 | RNG_MISCDEV_MINOR, | ||
126 | RNG_MODULE_NAME, | ||
127 | &rng_chrdev_ops, | ||
128 | }; | ||
129 | |||
130 | enum { | ||
131 | rng_hw_none, | ||
132 | rng_hw_intel, | ||
133 | rng_hw_amd, | ||
134 | #ifdef __i386__ | ||
135 | rng_hw_via, | ||
136 | #endif | ||
137 | rng_hw_geode, | ||
138 | }; | ||
139 | |||
140 | static struct rng_operations rng_vendor_ops[] = { | ||
141 | /* rng_hw_none */ | ||
142 | { }, | ||
143 | |||
144 | /* rng_hw_intel */ | ||
145 | { intel_init, intel_cleanup, intel_data_present, | ||
146 | intel_data_read, 1 }, | ||
147 | |||
148 | /* rng_hw_amd */ | ||
149 | { amd_init, amd_cleanup, amd_data_present, amd_data_read, 4 }, | ||
150 | |||
151 | #ifdef __i386__ | ||
152 | /* rng_hw_via */ | ||
153 | { via_init, via_cleanup, via_data_present, via_data_read, 1 }, | ||
154 | #endif | ||
155 | |||
156 | /* rng_hw_geode */ | ||
157 | { geode_init, geode_cleanup, geode_data_present, geode_data_read, 4 } | ||
158 | }; | ||
159 | |||
160 | /* | ||
161 | * Data for PCI driver interface | ||
162 | * | ||
163 | * This data only exists for exporting the supported | ||
164 | * PCI ids via MODULE_DEVICE_TABLE. We do not actually | ||
165 | * register a pci_driver, because someone else might one day | ||
166 | * want to register another driver on the same PCI id. | ||
167 | */ | ||
168 | static struct pci_device_id rng_pci_tbl[] = { | ||
169 | { 0x1022, 0x7443, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_amd }, | ||
170 | { 0x1022, 0x746b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_amd }, | ||
171 | |||
172 | { 0x8086, 0x2418, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel }, | ||
173 | { 0x8086, 0x2428, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel }, | ||
174 | { 0x8086, 0x2430, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel }, | ||
175 | { 0x8086, 0x2448, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel }, | ||
176 | { 0x8086, 0x244e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel }, | ||
177 | { 0x8086, 0x245e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel }, | ||
178 | |||
179 | { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LX_AES, | ||
180 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_geode }, | ||
181 | |||
182 | { 0, }, /* terminate list */ | ||
183 | }; | ||
184 | MODULE_DEVICE_TABLE (pci, rng_pci_tbl); | ||
185 | |||
186 | |||
187 | /*********************************************************************** | ||
188 | * | ||
189 | * Intel RNG operations | ||
190 | * | ||
191 | */ | ||
192 | |||
193 | /* | ||
194 | * RNG registers (offsets from rng_mem) | ||
195 | */ | ||
196 | #define INTEL_RNG_HW_STATUS 0 | ||
197 | #define INTEL_RNG_PRESENT 0x40 | ||
198 | #define INTEL_RNG_ENABLED 0x01 | ||
199 | #define INTEL_RNG_STATUS 1 | ||
200 | #define INTEL_RNG_DATA_PRESENT 0x01 | ||
201 | #define INTEL_RNG_DATA 2 | ||
202 | |||
203 | /* | ||
204 | * Magic address at which Intel PCI bridges locate the RNG | ||
205 | */ | ||
206 | #define INTEL_RNG_ADDR 0xFFBC015F | ||
207 | #define INTEL_RNG_ADDR_LEN 3 | ||
208 | |||
209 | /* token to our ioremap'd RNG register area */ | ||
210 | static void __iomem *rng_mem; | ||
211 | |||
212 | static inline u8 intel_hwstatus (void) | ||
213 | { | ||
214 | assert (rng_mem != NULL); | ||
215 | return readb (rng_mem + INTEL_RNG_HW_STATUS); | ||
216 | } | ||
217 | |||
218 | static inline u8 intel_hwstatus_set (u8 hw_status) | ||
219 | { | ||
220 | assert (rng_mem != NULL); | ||
221 | writeb (hw_status, rng_mem + INTEL_RNG_HW_STATUS); | ||
222 | return intel_hwstatus (); | ||
223 | } | ||
224 | |||
225 | static unsigned int intel_data_present(void) | ||
226 | { | ||
227 | assert (rng_mem != NULL); | ||
228 | |||
229 | return (readb (rng_mem + INTEL_RNG_STATUS) & INTEL_RNG_DATA_PRESENT) ? | ||
230 | 1 : 0; | ||
231 | } | ||
232 | |||
233 | static u32 intel_data_read(void) | ||
234 | { | ||
235 | assert (rng_mem != NULL); | ||
236 | |||
237 | return readb (rng_mem + INTEL_RNG_DATA); | ||
238 | } | ||
239 | |||
240 | static int __init intel_init (struct pci_dev *dev) | ||
241 | { | ||
242 | int rc; | ||
243 | u8 hw_status; | ||
244 | |||
245 | DPRINTK ("ENTER\n"); | ||
246 | |||
247 | rng_mem = ioremap (INTEL_RNG_ADDR, INTEL_RNG_ADDR_LEN); | ||
248 | if (rng_mem == NULL) { | ||
249 | printk (KERN_ERR PFX "cannot ioremap RNG Memory\n"); | ||
250 | rc = -EBUSY; | ||
251 | goto err_out; | ||
252 | } | ||
253 | |||
254 | /* Check for Intel 82802 */ | ||
255 | hw_status = intel_hwstatus (); | ||
256 | if ((hw_status & INTEL_RNG_PRESENT) == 0) { | ||
257 | printk (KERN_ERR PFX "RNG not detected\n"); | ||
258 | rc = -ENODEV; | ||
259 | goto err_out_free_map; | ||
260 | } | ||
261 | |||
262 | /* turn RNG h/w on, if it's off */ | ||
263 | if ((hw_status & INTEL_RNG_ENABLED) == 0) | ||
264 | hw_status = intel_hwstatus_set (hw_status | INTEL_RNG_ENABLED); | ||
265 | if ((hw_status & INTEL_RNG_ENABLED) == 0) { | ||
266 | printk (KERN_ERR PFX "cannot enable RNG, aborting\n"); | ||
267 | rc = -EIO; | ||
268 | goto err_out_free_map; | ||
269 | } | ||
270 | |||
271 | DPRINTK ("EXIT, returning 0\n"); | ||
272 | return 0; | ||
273 | |||
274 | err_out_free_map: | ||
275 | iounmap (rng_mem); | ||
276 | rng_mem = NULL; | ||
277 | err_out: | ||
278 | DPRINTK ("EXIT, returning %d\n", rc); | ||
279 | return rc; | ||
280 | } | ||
281 | |||
282 | static void intel_cleanup(void) | ||
283 | { | ||
284 | u8 hw_status; | ||
285 | |||
286 | hw_status = intel_hwstatus (); | ||
287 | if (hw_status & INTEL_RNG_ENABLED) | ||
288 | intel_hwstatus_set (hw_status & ~INTEL_RNG_ENABLED); | ||
289 | else | ||
290 | printk(KERN_WARNING PFX "unusual: RNG already disabled\n"); | ||
291 | iounmap(rng_mem); | ||
292 | rng_mem = NULL; | ||
293 | } | ||
294 | |||
295 | /*********************************************************************** | ||
296 | * | ||
297 | * AMD RNG operations | ||
298 | * | ||
299 | */ | ||
300 | |||
301 | static u32 pmbase; /* PMxx I/O base */ | ||
302 | static struct pci_dev *amd_dev; | ||
303 | |||
304 | static unsigned int amd_data_present (void) | ||
305 | { | ||
306 | return inl(pmbase + 0xF4) & 1; | ||
307 | } | ||
308 | |||
309 | |||
310 | static u32 amd_data_read (void) | ||
311 | { | ||
312 | return inl(pmbase + 0xF0); | ||
313 | } | ||
314 | |||
315 | static int __init amd_init (struct pci_dev *dev) | ||
316 | { | ||
317 | int rc; | ||
318 | u8 rnen; | ||
319 | |||
320 | DPRINTK ("ENTER\n"); | ||
321 | |||
322 | pci_read_config_dword(dev, 0x58, &pmbase); | ||
323 | |||
324 | pmbase &= 0x0000FF00; | ||
325 | |||
326 | if (pmbase == 0) | ||
327 | { | ||
328 | printk (KERN_ERR PFX "power management base not set\n"); | ||
329 | rc = -EIO; | ||
330 | goto err_out; | ||
331 | } | ||
332 | |||
333 | pci_read_config_byte(dev, 0x40, &rnen); | ||
334 | rnen |= (1 << 7); /* RNG on */ | ||
335 | pci_write_config_byte(dev, 0x40, rnen); | ||
336 | |||
337 | pci_read_config_byte(dev, 0x41, &rnen); | ||
338 | rnen |= (1 << 7); /* PMIO enable */ | ||
339 | pci_write_config_byte(dev, 0x41, rnen); | ||
340 | |||
341 | pr_info( PFX "AMD768 system management I/O registers at 0x%X.\n", | ||
342 | pmbase); | ||
343 | |||
344 | amd_dev = dev; | ||
345 | |||
346 | DPRINTK ("EXIT, returning 0\n"); | ||
347 | return 0; | ||
348 | |||
349 | err_out: | ||
350 | DPRINTK ("EXIT, returning %d\n", rc); | ||
351 | return rc; | ||
352 | } | ||
353 | |||
354 | static void amd_cleanup(void) | ||
355 | { | ||
356 | u8 rnen; | ||
357 | |||
358 | pci_read_config_byte(amd_dev, 0x40, &rnen); | ||
359 | rnen &= ~(1 << 7); /* RNG off */ | ||
360 | pci_write_config_byte(amd_dev, 0x40, rnen); | ||
361 | |||
362 | /* FIXME: twiddle pmio, also? */ | ||
363 | } | ||
364 | |||
365 | #ifdef __i386__ | ||
366 | /*********************************************************************** | ||
367 | * | ||
368 | * VIA RNG operations | ||
369 | * | ||
370 | */ | ||
371 | |||
372 | enum { | ||
373 | VIA_STRFILT_CNT_SHIFT = 16, | ||
374 | VIA_STRFILT_FAIL = (1 << 15), | ||
375 | VIA_STRFILT_ENABLE = (1 << 14), | ||
376 | VIA_RAWBITS_ENABLE = (1 << 13), | ||
377 | VIA_RNG_ENABLE = (1 << 6), | ||
378 | VIA_XSTORE_CNT_MASK = 0x0F, | ||
379 | |||
380 | VIA_RNG_CHUNK_8 = 0x00, /* 64 rand bits, 64 stored bits */ | ||
381 | VIA_RNG_CHUNK_4 = 0x01, /* 32 rand bits, 32 stored bits */ | ||
382 | VIA_RNG_CHUNK_4_MASK = 0xFFFFFFFF, | ||
383 | VIA_RNG_CHUNK_2 = 0x02, /* 16 rand bits, 32 stored bits */ | ||
384 | VIA_RNG_CHUNK_2_MASK = 0xFFFF, | ||
385 | VIA_RNG_CHUNK_1 = 0x03, /* 8 rand bits, 32 stored bits */ | ||
386 | VIA_RNG_CHUNK_1_MASK = 0xFF, | ||
387 | }; | ||
388 | |||
389 | static u32 via_rng_datum; | ||
390 | |||
391 | /* | ||
392 | * Investigate using the 'rep' prefix to obtain 32 bits of random data | ||
393 | * in one insn. The upside is potentially better performance. The | ||
394 | * downside is that the instruction becomes no longer atomic. Due to | ||
395 | * this, just like familiar issues with /dev/random itself, the worst | ||
396 | * case of a 'rep xstore' could potentially pause a cpu for an | ||
397 | * unreasonably long time. In practice, this condition would likely | ||
398 | * only occur when the hardware is failing. (or so we hope :)) | ||
399 | * | ||
400 | * Another possible performance boost may come from simply buffering | ||
401 | * until we have 4 bytes, thus returning a u32 at a time, | ||
402 | * instead of the current u8-at-a-time. | ||
403 | */ | ||
404 | |||
405 | static inline u32 xstore(u32 *addr, u32 edx_in) | ||
406 | { | ||
407 | u32 eax_out; | ||
408 | |||
409 | asm(".byte 0x0F,0xA7,0xC0 /* xstore %%edi (addr=%0) */" | ||
410 | :"=m"(*addr), "=a"(eax_out) | ||
411 | :"D"(addr), "d"(edx_in)); | ||
412 | |||
413 | return eax_out; | ||
414 | } | ||
415 | |||
416 | static unsigned int via_data_present(void) | ||
417 | { | ||
418 | u32 bytes_out; | ||
419 | |||
420 | /* We choose the recommended 1-byte-per-instruction RNG rate, | ||
421 | * for greater randomness at the expense of speed. Larger | ||
422 | * values 2, 4, or 8 bytes-per-instruction yield greater | ||
423 | * speed at lesser randomness. | ||
424 | * | ||
425 | * If you change this to another VIA_CHUNK_n, you must also | ||
426 | * change the ->n_bytes values in rng_vendor_ops[] tables. | ||
427 | * VIA_CHUNK_8 requires further code changes. | ||
428 | * | ||
429 | * A copy of MSR_VIA_RNG is placed in eax_out when xstore | ||
430 | * completes. | ||
431 | */ | ||
432 | via_rng_datum = 0; /* paranoia, not really necessary */ | ||
433 | bytes_out = xstore(&via_rng_datum, VIA_RNG_CHUNK_1) & VIA_XSTORE_CNT_MASK; | ||
434 | if (bytes_out == 0) | ||
435 | return 0; | ||
436 | |||
437 | return 1; | ||
438 | } | ||
439 | |||
440 | static u32 via_data_read(void) | ||
441 | { | ||
442 | return via_rng_datum; | ||
443 | } | ||
444 | |||
445 | static int __init via_init(struct pci_dev *dev) | ||
446 | { | ||
447 | u32 lo, hi, old_lo; | ||
448 | |||
449 | /* Control the RNG via MSR. Tread lightly and pay very close | ||
450 | * close attention to values written, as the reserved fields | ||
451 | * are documented to be "undefined and unpredictable"; but it | ||
452 | * does not say to write them as zero, so I make a guess that | ||
453 | * we restore the values we find in the register. | ||
454 | */ | ||
455 | rdmsr(MSR_VIA_RNG, lo, hi); | ||
456 | |||
457 | old_lo = lo; | ||
458 | lo &= ~(0x7f << VIA_STRFILT_CNT_SHIFT); | ||
459 | lo &= ~VIA_XSTORE_CNT_MASK; | ||
460 | lo &= ~(VIA_STRFILT_ENABLE | VIA_STRFILT_FAIL | VIA_RAWBITS_ENABLE); | ||
461 | lo |= VIA_RNG_ENABLE; | ||
462 | |||
463 | if (lo != old_lo) | ||
464 | wrmsr(MSR_VIA_RNG, lo, hi); | ||
465 | |||
466 | /* perhaps-unnecessary sanity check; remove after testing if | ||
467 | unneeded */ | ||
468 | rdmsr(MSR_VIA_RNG, lo, hi); | ||
469 | if ((lo & VIA_RNG_ENABLE) == 0) { | ||
470 | printk(KERN_ERR PFX "cannot enable VIA C3 RNG, aborting\n"); | ||
471 | return -ENODEV; | ||
472 | } | ||
473 | |||
474 | return 0; | ||
475 | } | ||
476 | |||
477 | static void via_cleanup(void) | ||
478 | { | ||
479 | /* do nothing */ | ||
480 | } | ||
481 | #endif | ||
482 | |||
483 | /*********************************************************************** | ||
484 | * | ||
485 | * AMD Geode RNG operations | ||
486 | * | ||
487 | */ | ||
488 | |||
489 | static void __iomem *geode_rng_base = NULL; | ||
490 | |||
491 | #define GEODE_RNG_DATA_REG 0x50 | ||
492 | #define GEODE_RNG_STATUS_REG 0x54 | ||
493 | |||
494 | static u32 geode_data_read(void) | ||
495 | { | ||
496 | u32 val; | ||
497 | |||
498 | assert(geode_rng_base != NULL); | ||
499 | val = readl(geode_rng_base + GEODE_RNG_DATA_REG); | ||
500 | return val; | ||
501 | } | ||
502 | |||
503 | static unsigned int geode_data_present(void) | ||
504 | { | ||
505 | u32 val; | ||
506 | |||
507 | assert(geode_rng_base != NULL); | ||
508 | val = readl(geode_rng_base + GEODE_RNG_STATUS_REG); | ||
509 | return val; | ||
510 | } | ||
511 | |||
512 | static void geode_cleanup(void) | ||
513 | { | ||
514 | iounmap(geode_rng_base); | ||
515 | geode_rng_base = NULL; | ||
516 | } | ||
517 | |||
518 | static int geode_init(struct pci_dev *dev) | ||
519 | { | ||
520 | unsigned long rng_base = pci_resource_start(dev, 0); | ||
521 | |||
522 | if (rng_base == 0) | ||
523 | return 1; | ||
524 | |||
525 | geode_rng_base = ioremap(rng_base, 0x58); | ||
526 | |||
527 | if (geode_rng_base == NULL) { | ||
528 | printk(KERN_ERR PFX "Cannot ioremap RNG memory\n"); | ||
529 | return -EBUSY; | ||
530 | } | ||
531 | |||
532 | return 0; | ||
533 | } | ||
534 | |||
535 | /*********************************************************************** | ||
536 | * | ||
537 | * /dev/hwrandom character device handling (major 10, minor 183) | ||
538 | * | ||
539 | */ | ||
540 | |||
541 | static int rng_dev_open (struct inode *inode, struct file *filp) | ||
542 | { | ||
543 | /* enforce read-only access to this chrdev */ | ||
544 | if ((filp->f_mode & FMODE_READ) == 0) | ||
545 | return -EINVAL; | ||
546 | if (filp->f_mode & FMODE_WRITE) | ||
547 | return -EINVAL; | ||
548 | |||
549 | return 0; | ||
550 | } | ||
551 | |||
552 | |||
553 | static ssize_t rng_dev_read (struct file *filp, char __user *buf, size_t size, | ||
554 | loff_t * offp) | ||
555 | { | ||
556 | static DEFINE_SPINLOCK(rng_lock); | ||
557 | unsigned int have_data; | ||
558 | u32 data = 0; | ||
559 | ssize_t ret = 0; | ||
560 | |||
561 | while (size) { | ||
562 | spin_lock(&rng_lock); | ||
563 | |||
564 | have_data = 0; | ||
565 | if (rng_ops->data_present()) { | ||
566 | data = rng_ops->data_read(); | ||
567 | have_data = rng_ops->n_bytes; | ||
568 | } | ||
569 | |||
570 | spin_unlock (&rng_lock); | ||
571 | |||
572 | while (have_data && size) { | ||
573 | if (put_user((u8)data, buf++)) { | ||
574 | ret = ret ? : -EFAULT; | ||
575 | break; | ||
576 | } | ||
577 | size--; | ||
578 | ret++; | ||
579 | have_data--; | ||
580 | data>>=8; | ||
581 | } | ||
582 | |||
583 | if (filp->f_flags & O_NONBLOCK) | ||
584 | return ret ? : -EAGAIN; | ||
585 | |||
586 | if(need_resched()) | ||
587 | schedule_timeout_interruptible(1); | ||
588 | else | ||
589 | udelay(200); /* FIXME: We could poll for 250uS ?? */ | ||
590 | |||
591 | if (signal_pending (current)) | ||
592 | return ret ? : -ERESTARTSYS; | ||
593 | } | ||
594 | return ret; | ||
595 | } | ||
596 | |||
597 | |||
598 | |||
599 | /* | ||
600 | * rng_init_one - look for and attempt to init a single RNG | ||
601 | */ | ||
602 | static int __init rng_init_one (struct pci_dev *dev) | ||
603 | { | ||
604 | int rc; | ||
605 | |||
606 | DPRINTK ("ENTER\n"); | ||
607 | |||
608 | assert(rng_ops != NULL); | ||
609 | |||
610 | rc = rng_ops->init(dev); | ||
611 | if (rc) | ||
612 | goto err_out; | ||
613 | |||
614 | rc = misc_register (&rng_miscdev); | ||
615 | if (rc) { | ||
616 | printk (KERN_ERR PFX "misc device register failed\n"); | ||
617 | goto err_out_cleanup_hw; | ||
618 | } | ||
619 | |||
620 | DPRINTK ("EXIT, returning 0\n"); | ||
621 | return 0; | ||
622 | |||
623 | err_out_cleanup_hw: | ||
624 | rng_ops->cleanup(); | ||
625 | err_out: | ||
626 | DPRINTK ("EXIT, returning %d\n", rc); | ||
627 | return rc; | ||
628 | } | ||
629 | |||
630 | |||
631 | |||
632 | MODULE_AUTHOR("The Linux Kernel team"); | ||
633 | MODULE_DESCRIPTION("H/W Random Number Generator (RNG) driver"); | ||
634 | MODULE_LICENSE("GPL"); | ||
635 | |||
636 | |||
637 | /* | ||
638 | * rng_init - initialize RNG module | ||
639 | */ | ||
640 | static int __init rng_init (void) | ||
641 | { | ||
642 | int rc; | ||
643 | struct pci_dev *pdev = NULL; | ||
644 | const struct pci_device_id *ent; | ||
645 | |||
646 | DPRINTK ("ENTER\n"); | ||
647 | |||
648 | /* Probe for Intel, AMD, Geode RNGs */ | ||
649 | for_each_pci_dev(pdev) { | ||
650 | ent = pci_match_id(rng_pci_tbl, pdev); | ||
651 | if (ent) { | ||
652 | rng_ops = &rng_vendor_ops[ent->driver_data]; | ||
653 | goto match; | ||
654 | } | ||
655 | } | ||
656 | |||
657 | #ifdef __i386__ | ||
658 | /* Probe for VIA RNG */ | ||
659 | if (cpu_has_xstore) { | ||
660 | rng_ops = &rng_vendor_ops[rng_hw_via]; | ||
661 | pdev = NULL; | ||
662 | goto match; | ||
663 | } | ||
664 | #endif | ||
665 | |||
666 | DPRINTK ("EXIT, returning -ENODEV\n"); | ||
667 | return -ENODEV; | ||
668 | |||
669 | match: | ||
670 | rc = rng_init_one (pdev); | ||
671 | if (rc) | ||
672 | return rc; | ||
673 | |||
674 | pr_info( RNG_DRIVER_NAME " loaded\n"); | ||
675 | |||
676 | DPRINTK ("EXIT, returning 0\n"); | ||
677 | return 0; | ||
678 | } | ||
679 | |||
680 | |||
681 | /* | ||
682 | * rng_init - shutdown RNG module | ||
683 | */ | ||
684 | static void __exit rng_cleanup (void) | ||
685 | { | ||
686 | DPRINTK ("ENTER\n"); | ||
687 | |||
688 | misc_deregister (&rng_miscdev); | ||
689 | |||
690 | if (rng_ops->cleanup) | ||
691 | rng_ops->cleanup(); | ||
692 | |||
693 | DPRINTK ("EXIT\n"); | ||
694 | } | ||
695 | |||
696 | |||
697 | module_init (rng_init); | ||
698 | module_exit (rng_cleanup); | ||
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig new file mode 100644 index 000000000000..9f7635f75178 --- /dev/null +++ b/drivers/char/hw_random/Kconfig | |||
@@ -0,0 +1,90 @@ | |||
1 | # | ||
2 | # Hardware Random Number Generator (RNG) configuration | ||
3 | # | ||
4 | |||
5 | config HW_RANDOM | ||
6 | bool "Hardware Random Number Generator Core support" | ||
7 | default y | ||
8 | ---help--- | ||
9 | Hardware Random Number Generator Core infrastructure. | ||
10 | |||
11 | If unsure, say Y. | ||
12 | |||
13 | config HW_RANDOM_INTEL | ||
14 | tristate "Intel HW Random Number Generator support" | ||
15 | depends on HW_RANDOM && (X86 || IA64) && PCI | ||
16 | default y | ||
17 | ---help--- | ||
18 | This driver provides kernel-side support for the Random Number | ||
19 | Generator hardware found on Intel i8xx-based motherboards. | ||
20 | |||
21 | To compile this driver as a module, choose M here: the | ||
22 | module will be called intel-rng. | ||
23 | |||
24 | If unsure, say Y. | ||
25 | |||
26 | config HW_RANDOM_AMD | ||
27 | tristate "AMD HW Random Number Generator support" | ||
28 | depends on HW_RANDOM && X86 && PCI | ||
29 | default y | ||
30 | ---help--- | ||
31 | This driver provides kernel-side support for the Random Number | ||
32 | Generator hardware found on AMD 76x-based motherboards. | ||
33 | |||
34 | To compile this driver as a module, choose M here: the | ||
35 | module will be called amd-rng. | ||
36 | |||
37 | If unsure, say Y. | ||
38 | |||
39 | config HW_RANDOM_GEODE | ||
40 | tristate "AMD Geode HW Random Number Generator support" | ||
41 | depends on HW_RANDOM && X86 && PCI | ||
42 | default y | ||
43 | ---help--- | ||
44 | This driver provides kernel-side support for the Random Number | ||
45 | Generator hardware found on the AMD Geode LX. | ||
46 | |||
47 | To compile this driver as a module, choose M here: the | ||
48 | module will be called geode-rng. | ||
49 | |||
50 | If unsure, say Y. | ||
51 | |||
52 | config HW_RANDOM_VIA | ||
53 | tristate "VIA HW Random Number Generator support" | ||
54 | depends on HW_RANDOM && X86_32 | ||
55 | default y | ||
56 | ---help--- | ||
57 | This driver provides kernel-side support for the Random Number | ||
58 | Generator hardware found on VIA based motherboards. | ||
59 | |||
60 | To compile this driver as a module, choose M here: the | ||
61 | module will be called via-rng. | ||
62 | |||
63 | If unsure, say Y. | ||
64 | |||
65 | config HW_RANDOM_IXP4XX | ||
66 | tristate "Intel IXP4xx NPU HW Random Number Generator support" | ||
67 | depends on HW_RANDOM && ARCH_IXP4XX | ||
68 | default y | ||
69 | ---help--- | ||
70 | This driver provides kernel-side support for the Random | ||
71 | Number Generator hardware found on the Intel IXP4xx NPU. | ||
72 | |||
73 | To compile this driver as a module, choose M here: the | ||
74 | module will be called ixp4xx-rng. | ||
75 | |||
76 | If unsure, say Y. | ||
77 | |||
78 | config HW_RANDOM_OMAP | ||
79 | tristate "OMAP Random Number Generator support" | ||
80 | depends on HW_RANDOM && (ARCH_OMAP16XX || ARCH_OMAP24XX) | ||
81 | default y | ||
82 | ---help--- | ||
83 | This driver provides kernel-side support for the Random Number | ||
84 | Generator hardware found on OMAP16xx and OMAP24xx multimedia | ||
85 | processors. | ||
86 | |||
87 | To compile this driver as a module, choose M here: the | ||
88 | module will be called omap-rng. | ||
89 | |||
90 | If unsure, say Y. | ||
diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile new file mode 100644 index 000000000000..e263ae96f940 --- /dev/null +++ b/drivers/char/hw_random/Makefile | |||
@@ -0,0 +1,11 @@ | |||
1 | # | ||
2 | # Makefile for HW Random Number Generator (RNG) device drivers. | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_HW_RANDOM) += core.o | ||
6 | obj-$(CONFIG_HW_RANDOM_INTEL) += intel-rng.o | ||
7 | obj-$(CONFIG_HW_RANDOM_AMD) += amd-rng.o | ||
8 | obj-$(CONFIG_HW_RANDOM_GEODE) += geode-rng.o | ||
9 | obj-$(CONFIG_HW_RANDOM_VIA) += via-rng.o | ||
10 | obj-$(CONFIG_HW_RANDOM_IXP4XX) += ixp4xx-rng.o | ||
11 | obj-$(CONFIG_HW_RANDOM_OMAP) += omap-rng.o | ||
diff --git a/drivers/char/hw_random/amd-rng.c b/drivers/char/hw_random/amd-rng.c new file mode 100644 index 000000000000..71e4e0f3fd54 --- /dev/null +++ b/drivers/char/hw_random/amd-rng.c | |||
@@ -0,0 +1,152 @@ | |||
1 | /* | ||
2 | * RNG driver for AMD RNGs | ||
3 | * | ||
4 | * Copyright 2005 (c) MontaVista Software, Inc. | ||
5 | * | ||
6 | * with the majority of the code coming from: | ||
7 | * | ||
8 | * Hardware driver for the Intel/AMD/VIA Random Number Generators (RNG) | ||
9 | * (c) Copyright 2003 Red Hat Inc <jgarzik@redhat.com> | ||
10 | * | ||
11 | * derived from | ||
12 | * | ||
13 | * Hardware driver for the AMD 768 Random Number Generator (RNG) | ||
14 | * (c) Copyright 2001 Red Hat Inc <alan@redhat.com> | ||
15 | * | ||
16 | * derived from | ||
17 | * | ||
18 | * Hardware driver for Intel i810 Random Number Generator (RNG) | ||
19 | * Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com> | ||
20 | * Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com> | ||
21 | * | ||
22 | * This file is licensed under the terms of the GNU General Public | ||
23 | * License version 2. This program is licensed "as is" without any | ||
24 | * warranty of any kind, whether express or implied. | ||
25 | */ | ||
26 | |||
27 | #include <linux/module.h> | ||
28 | #include <linux/kernel.h> | ||
29 | #include <linux/pci.h> | ||
30 | #include <linux/hw_random.h> | ||
31 | #include <asm/io.h> | ||
32 | |||
33 | |||
34 | #define PFX KBUILD_MODNAME ": " | ||
35 | |||
36 | |||
37 | /* | ||
38 | * Data for PCI driver interface | ||
39 | * | ||
40 | * This data only exists for exporting the supported | ||
41 | * PCI ids via MODULE_DEVICE_TABLE. We do not actually | ||
42 | * register a pci_driver, because someone else might one day | ||
43 | * want to register another driver on the same PCI id. | ||
44 | */ | ||
45 | static const struct pci_device_id pci_tbl[] = { | ||
46 | { 0x1022, 0x7443, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, | ||
47 | { 0x1022, 0x746b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, | ||
48 | { 0, }, /* terminate list */ | ||
49 | }; | ||
50 | MODULE_DEVICE_TABLE(pci, pci_tbl); | ||
51 | |||
52 | static struct pci_dev *amd_pdev; | ||
53 | |||
54 | |||
55 | static int amd_rng_data_present(struct hwrng *rng) | ||
56 | { | ||
57 | u32 pmbase = (u32)rng->priv; | ||
58 | |||
59 | return !!(inl(pmbase + 0xF4) & 1); | ||
60 | } | ||
61 | |||
62 | static int amd_rng_data_read(struct hwrng *rng, u32 *data) | ||
63 | { | ||
64 | u32 pmbase = (u32)rng->priv; | ||
65 | |||
66 | *data = inl(pmbase + 0xF0); | ||
67 | |||
68 | return 4; | ||
69 | } | ||
70 | |||
71 | static int amd_rng_init(struct hwrng *rng) | ||
72 | { | ||
73 | u8 rnen; | ||
74 | |||
75 | pci_read_config_byte(amd_pdev, 0x40, &rnen); | ||
76 | rnen |= (1 << 7); /* RNG on */ | ||
77 | pci_write_config_byte(amd_pdev, 0x40, rnen); | ||
78 | |||
79 | pci_read_config_byte(amd_pdev, 0x41, &rnen); | ||
80 | rnen |= (1 << 7); /* PMIO enable */ | ||
81 | pci_write_config_byte(amd_pdev, 0x41, rnen); | ||
82 | |||
83 | return 0; | ||
84 | } | ||
85 | |||
86 | static void amd_rng_cleanup(struct hwrng *rng) | ||
87 | { | ||
88 | u8 rnen; | ||
89 | |||
90 | pci_read_config_byte(amd_pdev, 0x40, &rnen); | ||
91 | rnen &= ~(1 << 7); /* RNG off */ | ||
92 | pci_write_config_byte(amd_pdev, 0x40, rnen); | ||
93 | } | ||
94 | |||
95 | |||
96 | static struct hwrng amd_rng = { | ||
97 | .name = "amd", | ||
98 | .init = amd_rng_init, | ||
99 | .cleanup = amd_rng_cleanup, | ||
100 | .data_present = amd_rng_data_present, | ||
101 | .data_read = amd_rng_data_read, | ||
102 | }; | ||
103 | |||
104 | |||
105 | static int __init mod_init(void) | ||
106 | { | ||
107 | int err = -ENODEV; | ||
108 | struct pci_dev *pdev = NULL; | ||
109 | const struct pci_device_id *ent; | ||
110 | u32 pmbase; | ||
111 | |||
112 | for_each_pci_dev(pdev) { | ||
113 | ent = pci_match_id(pci_tbl, pdev); | ||
114 | if (ent) | ||
115 | goto found; | ||
116 | } | ||
117 | /* Device not found. */ | ||
118 | goto out; | ||
119 | |||
120 | found: | ||
121 | err = pci_read_config_dword(pdev, 0x58, &pmbase); | ||
122 | if (err) | ||
123 | goto out; | ||
124 | err = -EIO; | ||
125 | pmbase &= 0x0000FF00; | ||
126 | if (pmbase == 0) | ||
127 | goto out; | ||
128 | amd_rng.priv = (unsigned long)pmbase; | ||
129 | amd_pdev = pdev; | ||
130 | |||
131 | printk(KERN_INFO "AMD768 RNG detected\n"); | ||
132 | err = hwrng_register(&amd_rng); | ||
133 | if (err) { | ||
134 | printk(KERN_ERR PFX "RNG registering failed (%d)\n", | ||
135 | err); | ||
136 | goto out; | ||
137 | } | ||
138 | out: | ||
139 | return err; | ||
140 | } | ||
141 | |||
142 | static void __exit mod_exit(void) | ||
143 | { | ||
144 | hwrng_unregister(&amd_rng); | ||
145 | } | ||
146 | |||
147 | subsys_initcall(mod_init); | ||
148 | module_exit(mod_exit); | ||
149 | |||
150 | MODULE_AUTHOR("The Linux Kernel team"); | ||
151 | MODULE_DESCRIPTION("H/W RNG driver for AMD chipsets"); | ||
152 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c new file mode 100644 index 000000000000..88b026639f10 --- /dev/null +++ b/drivers/char/hw_random/core.c | |||
@@ -0,0 +1,354 @@ | |||
1 | /* | ||
2 | Added support for the AMD Geode LX RNG | ||
3 | (c) Copyright 2004-2005 Advanced Micro Devices, Inc. | ||
4 | |||
5 | derived from | ||
6 | |||
7 | Hardware driver for the Intel/AMD/VIA Random Number Generators (RNG) | ||
8 | (c) Copyright 2003 Red Hat Inc <jgarzik@redhat.com> | ||
9 | |||
10 | derived from | ||
11 | |||
12 | Hardware driver for the AMD 768 Random Number Generator (RNG) | ||
13 | (c) Copyright 2001 Red Hat Inc <alan@redhat.com> | ||
14 | |||
15 | derived from | ||
16 | |||
17 | Hardware driver for Intel i810 Random Number Generator (RNG) | ||
18 | Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com> | ||
19 | Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com> | ||
20 | |||
21 | Added generic RNG API | ||
22 | Copyright 2006 Michael Buesch <mbuesch@freenet.de> | ||
23 | Copyright 2005 (c) MontaVista Software, Inc. | ||
24 | |||
25 | Please read Documentation/hw_random.txt for details on use. | ||
26 | |||
27 | ---------------------------------------------------------- | ||
28 | This software may be used and distributed according to the terms | ||
29 | of the GNU General Public License, incorporated herein by reference. | ||
30 | |||
31 | */ | ||
32 | |||
33 | |||
34 | #include <linux/device.h> | ||
35 | #include <linux/hw_random.h> | ||
36 | #include <linux/module.h> | ||
37 | #include <linux/kernel.h> | ||
38 | #include <linux/fs.h> | ||
39 | #include <linux/init.h> | ||
40 | #include <linux/miscdevice.h> | ||
41 | #include <linux/delay.h> | ||
42 | #include <asm/uaccess.h> | ||
43 | |||
44 | |||
45 | #define RNG_MODULE_NAME "hw_random" | ||
46 | #define PFX RNG_MODULE_NAME ": " | ||
47 | #define RNG_MISCDEV_MINOR 183 /* official */ | ||
48 | |||
49 | |||
50 | static struct hwrng *current_rng; | ||
51 | static LIST_HEAD(rng_list); | ||
52 | static DEFINE_MUTEX(rng_mutex); | ||
53 | |||
54 | |||
55 | static inline int hwrng_init(struct hwrng *rng) | ||
56 | { | ||
57 | if (!rng->init) | ||
58 | return 0; | ||
59 | return rng->init(rng); | ||
60 | } | ||
61 | |||
62 | static inline void hwrng_cleanup(struct hwrng *rng) | ||
63 | { | ||
64 | if (rng && rng->cleanup) | ||
65 | rng->cleanup(rng); | ||
66 | } | ||
67 | |||
68 | static inline int hwrng_data_present(struct hwrng *rng) | ||
69 | { | ||
70 | if (!rng->data_present) | ||
71 | return 1; | ||
72 | return rng->data_present(rng); | ||
73 | } | ||
74 | |||
75 | static inline int hwrng_data_read(struct hwrng *rng, u32 *data) | ||
76 | { | ||
77 | return rng->data_read(rng, data); | ||
78 | } | ||
79 | |||
80 | |||
81 | static int rng_dev_open(struct inode *inode, struct file *filp) | ||
82 | { | ||
83 | /* enforce read-only access to this chrdev */ | ||
84 | if ((filp->f_mode & FMODE_READ) == 0) | ||
85 | return -EINVAL; | ||
86 | if (filp->f_mode & FMODE_WRITE) | ||
87 | return -EINVAL; | ||
88 | return 0; | ||
89 | } | ||
90 | |||
91 | static ssize_t rng_dev_read(struct file *filp, char __user *buf, | ||
92 | size_t size, loff_t *offp) | ||
93 | { | ||
94 | u32 data; | ||
95 | ssize_t ret = 0; | ||
96 | int i, err = 0; | ||
97 | int data_present; | ||
98 | int bytes_read; | ||
99 | |||
100 | while (size) { | ||
101 | err = -ERESTARTSYS; | ||
102 | if (mutex_lock_interruptible(&rng_mutex)) | ||
103 | goto out; | ||
104 | if (!current_rng) { | ||
105 | mutex_unlock(&rng_mutex); | ||
106 | err = -ENODEV; | ||
107 | goto out; | ||
108 | } | ||
109 | if (filp->f_flags & O_NONBLOCK) { | ||
110 | data_present = hwrng_data_present(current_rng); | ||
111 | } else { | ||
112 | /* Some RNG require some time between data_reads to gather | ||
113 | * new entropy. Poll it. | ||
114 | */ | ||
115 | for (i = 0; i < 20; i++) { | ||
116 | data_present = hwrng_data_present(current_rng); | ||
117 | if (data_present) | ||
118 | break; | ||
119 | udelay(10); | ||
120 | } | ||
121 | } | ||
122 | bytes_read = 0; | ||
123 | if (data_present) | ||
124 | bytes_read = hwrng_data_read(current_rng, &data); | ||
125 | mutex_unlock(&rng_mutex); | ||
126 | |||
127 | err = -EAGAIN; | ||
128 | if (!bytes_read && (filp->f_flags & O_NONBLOCK)) | ||
129 | goto out; | ||
130 | |||
131 | err = -EFAULT; | ||
132 | while (bytes_read && size) { | ||
133 | if (put_user((u8)data, buf++)) | ||
134 | goto out; | ||
135 | size--; | ||
136 | ret++; | ||
137 | bytes_read--; | ||
138 | data >>= 8; | ||
139 | } | ||
140 | |||
141 | if (need_resched()) | ||
142 | schedule_timeout_interruptible(1); | ||
143 | err = -ERESTARTSYS; | ||
144 | if (signal_pending(current)) | ||
145 | goto out; | ||
146 | } | ||
147 | out: | ||
148 | return ret ? : err; | ||
149 | } | ||
150 | |||
151 | |||
152 | static struct file_operations rng_chrdev_ops = { | ||
153 | .owner = THIS_MODULE, | ||
154 | .open = rng_dev_open, | ||
155 | .read = rng_dev_read, | ||
156 | }; | ||
157 | |||
158 | static struct miscdevice rng_miscdev = { | ||
159 | .minor = RNG_MISCDEV_MINOR, | ||
160 | .name = RNG_MODULE_NAME, | ||
161 | .fops = &rng_chrdev_ops, | ||
162 | }; | ||
163 | |||
164 | |||
165 | static ssize_t hwrng_attr_current_store(struct class_device *class, | ||
166 | const char *buf, size_t len) | ||
167 | { | ||
168 | int err; | ||
169 | struct hwrng *rng; | ||
170 | |||
171 | err = mutex_lock_interruptible(&rng_mutex); | ||
172 | if (err) | ||
173 | return -ERESTARTSYS; | ||
174 | err = -ENODEV; | ||
175 | list_for_each_entry(rng, &rng_list, list) { | ||
176 | if (strcmp(rng->name, buf) == 0) { | ||
177 | if (rng == current_rng) { | ||
178 | err = 0; | ||
179 | break; | ||
180 | } | ||
181 | err = hwrng_init(rng); | ||
182 | if (err) | ||
183 | break; | ||
184 | hwrng_cleanup(current_rng); | ||
185 | current_rng = rng; | ||
186 | err = 0; | ||
187 | break; | ||
188 | } | ||
189 | } | ||
190 | mutex_unlock(&rng_mutex); | ||
191 | |||
192 | return err ? : len; | ||
193 | } | ||
194 | |||
195 | static ssize_t hwrng_attr_current_show(struct class_device *class, | ||
196 | char *buf) | ||
197 | { | ||
198 | int err; | ||
199 | ssize_t ret; | ||
200 | const char *name = "none"; | ||
201 | |||
202 | err = mutex_lock_interruptible(&rng_mutex); | ||
203 | if (err) | ||
204 | return -ERESTARTSYS; | ||
205 | if (current_rng) | ||
206 | name = current_rng->name; | ||
207 | ret = snprintf(buf, PAGE_SIZE, "%s\n", name); | ||
208 | mutex_unlock(&rng_mutex); | ||
209 | |||
210 | return ret; | ||
211 | } | ||
212 | |||
213 | static ssize_t hwrng_attr_available_show(struct class_device *class, | ||
214 | char *buf) | ||
215 | { | ||
216 | int err; | ||
217 | ssize_t ret = 0; | ||
218 | struct hwrng *rng; | ||
219 | |||
220 | err = mutex_lock_interruptible(&rng_mutex); | ||
221 | if (err) | ||
222 | return -ERESTARTSYS; | ||
223 | buf[0] = '\0'; | ||
224 | list_for_each_entry(rng, &rng_list, list) { | ||
225 | strncat(buf, rng->name, PAGE_SIZE - ret - 1); | ||
226 | ret += strlen(rng->name); | ||
227 | strncat(buf, " ", PAGE_SIZE - ret - 1); | ||
228 | ret++; | ||
229 | } | ||
230 | strncat(buf, "\n", PAGE_SIZE - ret - 1); | ||
231 | ret++; | ||
232 | mutex_unlock(&rng_mutex); | ||
233 | |||
234 | return ret; | ||
235 | } | ||
236 | |||
237 | static CLASS_DEVICE_ATTR(rng_current, S_IRUGO | S_IWUSR, | ||
238 | hwrng_attr_current_show, | ||
239 | hwrng_attr_current_store); | ||
240 | static CLASS_DEVICE_ATTR(rng_available, S_IRUGO, | ||
241 | hwrng_attr_available_show, | ||
242 | NULL); | ||
243 | |||
244 | |||
245 | static void unregister_miscdev(void) | ||
246 | { | ||
247 | class_device_remove_file(rng_miscdev.class, | ||
248 | &class_device_attr_rng_available); | ||
249 | class_device_remove_file(rng_miscdev.class, | ||
250 | &class_device_attr_rng_current); | ||
251 | misc_deregister(&rng_miscdev); | ||
252 | } | ||
253 | |||
254 | static int register_miscdev(void) | ||
255 | { | ||
256 | int err; | ||
257 | |||
258 | err = misc_register(&rng_miscdev); | ||
259 | if (err) | ||
260 | goto out; | ||
261 | err = class_device_create_file(rng_miscdev.class, | ||
262 | &class_device_attr_rng_current); | ||
263 | if (err) | ||
264 | goto err_misc_dereg; | ||
265 | err = class_device_create_file(rng_miscdev.class, | ||
266 | &class_device_attr_rng_available); | ||
267 | if (err) | ||
268 | goto err_remove_current; | ||
269 | out: | ||
270 | return err; | ||
271 | |||
272 | err_remove_current: | ||
273 | class_device_remove_file(rng_miscdev.class, | ||
274 | &class_device_attr_rng_current); | ||
275 | err_misc_dereg: | ||
276 | misc_deregister(&rng_miscdev); | ||
277 | goto out; | ||
278 | } | ||
279 | |||
280 | int hwrng_register(struct hwrng *rng) | ||
281 | { | ||
282 | int must_register_misc; | ||
283 | int err = -EINVAL; | ||
284 | struct hwrng *old_rng, *tmp; | ||
285 | |||
286 | if (rng->name == NULL || | ||
287 | rng->data_read == NULL) | ||
288 | goto out; | ||
289 | |||
290 | mutex_lock(&rng_mutex); | ||
291 | |||
292 | /* Must not register two RNGs with the same name. */ | ||
293 | err = -EEXIST; | ||
294 | list_for_each_entry(tmp, &rng_list, list) { | ||
295 | if (strcmp(tmp->name, rng->name) == 0) | ||
296 | goto out_unlock; | ||
297 | } | ||
298 | |||
299 | must_register_misc = (current_rng == NULL); | ||
300 | old_rng = current_rng; | ||
301 | if (!old_rng) { | ||
302 | err = hwrng_init(rng); | ||
303 | if (err) | ||
304 | goto out_unlock; | ||
305 | current_rng = rng; | ||
306 | } | ||
307 | err = 0; | ||
308 | if (must_register_misc) { | ||
309 | err = register_miscdev(); | ||
310 | if (err) { | ||
311 | if (!old_rng) { | ||
312 | hwrng_cleanup(rng); | ||
313 | current_rng = NULL; | ||
314 | } | ||
315 | goto out_unlock; | ||
316 | } | ||
317 | } | ||
318 | INIT_LIST_HEAD(&rng->list); | ||
319 | list_add_tail(&rng->list, &rng_list); | ||
320 | out_unlock: | ||
321 | mutex_unlock(&rng_mutex); | ||
322 | out: | ||
323 | return err; | ||
324 | } | ||
325 | EXPORT_SYMBOL_GPL(hwrng_register); | ||
326 | |||
327 | void hwrng_unregister(struct hwrng *rng) | ||
328 | { | ||
329 | int err; | ||
330 | |||
331 | mutex_lock(&rng_mutex); | ||
332 | |||
333 | list_del(&rng->list); | ||
334 | if (current_rng == rng) { | ||
335 | hwrng_cleanup(rng); | ||
336 | if (list_empty(&rng_list)) { | ||
337 | current_rng = NULL; | ||
338 | } else { | ||
339 | current_rng = list_entry(rng_list.prev, struct hwrng, list); | ||
340 | err = hwrng_init(current_rng); | ||
341 | if (err) | ||
342 | current_rng = NULL; | ||
343 | } | ||
344 | } | ||
345 | if (list_empty(&rng_list)) | ||
346 | unregister_miscdev(); | ||
347 | |||
348 | mutex_unlock(&rng_mutex); | ||
349 | } | ||
350 | EXPORT_SYMBOL_GPL(hwrng_unregister); | ||
351 | |||
352 | |||
353 | MODULE_DESCRIPTION("H/W Random Number Generator (RNG) driver"); | ||
354 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/char/hw_random/geode-rng.c b/drivers/char/hw_random/geode-rng.c new file mode 100644 index 000000000000..be61f22ee7bb --- /dev/null +++ b/drivers/char/hw_random/geode-rng.c | |||
@@ -0,0 +1,128 @@ | |||
1 | /* | ||
2 | * RNG driver for AMD Geode RNGs | ||
3 | * | ||
4 | * Copyright 2005 (c) MontaVista Software, Inc. | ||
5 | * | ||
6 | * with the majority of the code coming from: | ||
7 | * | ||
8 | * Hardware driver for the Intel/AMD/VIA Random Number Generators (RNG) | ||
9 | * (c) Copyright 2003 Red Hat Inc <jgarzik@redhat.com> | ||
10 | * | ||
11 | * derived from | ||
12 | * | ||
13 | * Hardware driver for the AMD 768 Random Number Generator (RNG) | ||
14 | * (c) Copyright 2001 Red Hat Inc <alan@redhat.com> | ||
15 | * | ||
16 | * derived from | ||
17 | * | ||
18 | * Hardware driver for Intel i810 Random Number Generator (RNG) | ||
19 | * Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com> | ||
20 | * Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com> | ||
21 | * | ||
22 | * This file is licensed under the terms of the GNU General Public | ||
23 | * License version 2. This program is licensed "as is" without any | ||
24 | * warranty of any kind, whether express or implied. | ||
25 | */ | ||
26 | |||
27 | #include <linux/module.h> | ||
28 | #include <linux/kernel.h> | ||
29 | #include <linux/pci.h> | ||
30 | #include <linux/hw_random.h> | ||
31 | #include <asm/io.h> | ||
32 | |||
33 | |||
34 | #define PFX KBUILD_MODNAME ": " | ||
35 | |||
36 | #define GEODE_RNG_DATA_REG 0x50 | ||
37 | #define GEODE_RNG_STATUS_REG 0x54 | ||
38 | |||
39 | /* | ||
40 | * Data for PCI driver interface | ||
41 | * | ||
42 | * This data only exists for exporting the supported | ||
43 | * PCI ids via MODULE_DEVICE_TABLE. We do not actually | ||
44 | * register a pci_driver, because someone else might one day | ||
45 | * want to register another driver on the same PCI id. | ||
46 | */ | ||
47 | static const struct pci_device_id pci_tbl[] = { | ||
48 | { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LX_AES, | ||
49 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, | ||
50 | { 0, }, /* terminate list */ | ||
51 | }; | ||
52 | MODULE_DEVICE_TABLE(pci, pci_tbl); | ||
53 | |||
54 | |||
55 | static int geode_rng_data_read(struct hwrng *rng, u32 *data) | ||
56 | { | ||
57 | void __iomem *mem = (void __iomem *)rng->priv; | ||
58 | |||
59 | *data = readl(mem + GEODE_RNG_DATA_REG); | ||
60 | |||
61 | return 4; | ||
62 | } | ||
63 | |||
64 | static int geode_rng_data_present(struct hwrng *rng) | ||
65 | { | ||
66 | void __iomem *mem = (void __iomem *)rng->priv; | ||
67 | |||
68 | return !!(readl(mem + GEODE_RNG_STATUS_REG)); | ||
69 | } | ||
70 | |||
71 | |||
72 | static struct hwrng geode_rng = { | ||
73 | .name = "geode", | ||
74 | .data_present = geode_rng_data_present, | ||
75 | .data_read = geode_rng_data_read, | ||
76 | }; | ||
77 | |||
78 | |||
79 | static int __init mod_init(void) | ||
80 | { | ||
81 | int err = -ENODEV; | ||
82 | struct pci_dev *pdev = NULL; | ||
83 | const struct pci_device_id *ent; | ||
84 | void __iomem *mem; | ||
85 | unsigned long rng_base; | ||
86 | |||
87 | for_each_pci_dev(pdev) { | ||
88 | ent = pci_match_id(pci_tbl, pdev); | ||
89 | if (ent) | ||
90 | goto found; | ||
91 | } | ||
92 | /* Device not found. */ | ||
93 | goto out; | ||
94 | |||
95 | found: | ||
96 | rng_base = pci_resource_start(pdev, 0); | ||
97 | if (rng_base == 0) | ||
98 | goto out; | ||
99 | err = -ENOMEM; | ||
100 | mem = ioremap(rng_base, 0x58); | ||
101 | if (!mem) | ||
102 | goto out; | ||
103 | geode_rng.priv = (unsigned long)mem; | ||
104 | |||
105 | printk(KERN_INFO "AMD Geode RNG detected\n"); | ||
106 | err = hwrng_register(&geode_rng); | ||
107 | if (err) { | ||
108 | printk(KERN_ERR PFX "RNG registering failed (%d)\n", | ||
109 | err); | ||
110 | goto out; | ||
111 | } | ||
112 | out: | ||
113 | return err; | ||
114 | } | ||
115 | |||
116 | static void __exit mod_exit(void) | ||
117 | { | ||
118 | void __iomem *mem = (void __iomem *)geode_rng.priv; | ||
119 | |||
120 | hwrng_unregister(&geode_rng); | ||
121 | iounmap(mem); | ||
122 | } | ||
123 | |||
124 | subsys_initcall(mod_init); | ||
125 | module_exit(mod_exit); | ||
126 | |||
127 | MODULE_DESCRIPTION("H/W RNG driver for AMD Geode LX CPUs"); | ||
128 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/char/hw_random/intel-rng.c b/drivers/char/hw_random/intel-rng.c new file mode 100644 index 000000000000..6594bd5645f4 --- /dev/null +++ b/drivers/char/hw_random/intel-rng.c | |||
@@ -0,0 +1,189 @@ | |||
1 | /* | ||
2 | * RNG driver for Intel RNGs | ||
3 | * | ||
4 | * Copyright 2005 (c) MontaVista Software, Inc. | ||
5 | * | ||
6 | * with the majority of the code coming from: | ||
7 | * | ||
8 | * Hardware driver for the Intel/AMD/VIA Random Number Generators (RNG) | ||
9 | * (c) Copyright 2003 Red Hat Inc <jgarzik@redhat.com> | ||
10 | * | ||
11 | * derived from | ||
12 | * | ||
13 | * Hardware driver for the AMD 768 Random Number Generator (RNG) | ||
14 | * (c) Copyright 2001 Red Hat Inc <alan@redhat.com> | ||
15 | * | ||
16 | * derived from | ||
17 | * | ||
18 | * Hardware driver for Intel i810 Random Number Generator (RNG) | ||
19 | * Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com> | ||
20 | * Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com> | ||
21 | * | ||
22 | * This file is licensed under the terms of the GNU General Public | ||
23 | * License version 2. This program is licensed "as is" without any | ||
24 | * warranty of any kind, whether express or implied. | ||
25 | */ | ||
26 | |||
27 | #include <linux/module.h> | ||
28 | #include <linux/kernel.h> | ||
29 | #include <linux/pci.h> | ||
30 | #include <linux/hw_random.h> | ||
31 | #include <asm/io.h> | ||
32 | |||
33 | |||
34 | #define PFX KBUILD_MODNAME ": " | ||
35 | |||
36 | /* | ||
37 | * RNG registers | ||
38 | */ | ||
39 | #define INTEL_RNG_HW_STATUS 0 | ||
40 | #define INTEL_RNG_PRESENT 0x40 | ||
41 | #define INTEL_RNG_ENABLED 0x01 | ||
42 | #define INTEL_RNG_STATUS 1 | ||
43 | #define INTEL_RNG_DATA_PRESENT 0x01 | ||
44 | #define INTEL_RNG_DATA 2 | ||
45 | |||
46 | /* | ||
47 | * Magic address at which Intel PCI bridges locate the RNG | ||
48 | */ | ||
49 | #define INTEL_RNG_ADDR 0xFFBC015F | ||
50 | #define INTEL_RNG_ADDR_LEN 3 | ||
51 | |||
52 | /* | ||
53 | * Data for PCI driver interface | ||
54 | * | ||
55 | * This data only exists for exporting the supported | ||
56 | * PCI ids via MODULE_DEVICE_TABLE. We do not actually | ||
57 | * register a pci_driver, because someone else might one day | ||
58 | * want to register another driver on the same PCI id. | ||
59 | */ | ||
60 | static const struct pci_device_id pci_tbl[] = { | ||
61 | { 0x8086, 0x2418, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, | ||
62 | { 0x8086, 0x2428, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, | ||
63 | { 0x8086, 0x2430, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, | ||
64 | { 0x8086, 0x2448, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, | ||
65 | { 0x8086, 0x244e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, | ||
66 | { 0x8086, 0x245e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, | ||
67 | { 0, }, /* terminate list */ | ||
68 | }; | ||
69 | MODULE_DEVICE_TABLE(pci, pci_tbl); | ||
70 | |||
71 | |||
72 | static inline u8 hwstatus_get(void __iomem *mem) | ||
73 | { | ||
74 | return readb(mem + INTEL_RNG_HW_STATUS); | ||
75 | } | ||
76 | |||
77 | static inline u8 hwstatus_set(void __iomem *mem, | ||
78 | u8 hw_status) | ||
79 | { | ||
80 | writeb(hw_status, mem + INTEL_RNG_HW_STATUS); | ||
81 | return hwstatus_get(mem); | ||
82 | } | ||
83 | |||
84 | static int intel_rng_data_present(struct hwrng *rng) | ||
85 | { | ||
86 | void __iomem *mem = (void __iomem *)rng->priv; | ||
87 | |||
88 | return !!(readb(mem + INTEL_RNG_STATUS) & INTEL_RNG_DATA_PRESENT); | ||
89 | } | ||
90 | |||
91 | static int intel_rng_data_read(struct hwrng *rng, u32 *data) | ||
92 | { | ||
93 | void __iomem *mem = (void __iomem *)rng->priv; | ||
94 | |||
95 | *data = readb(mem + INTEL_RNG_DATA); | ||
96 | |||
97 | return 1; | ||
98 | } | ||
99 | |||
100 | static int intel_rng_init(struct hwrng *rng) | ||
101 | { | ||
102 | void __iomem *mem = (void __iomem *)rng->priv; | ||
103 | u8 hw_status; | ||
104 | int err = -EIO; | ||
105 | |||
106 | hw_status = hwstatus_get(mem); | ||
107 | /* turn RNG h/w on, if it's off */ | ||
108 | if ((hw_status & INTEL_RNG_ENABLED) == 0) | ||
109 | hw_status = hwstatus_set(mem, hw_status | INTEL_RNG_ENABLED); | ||
110 | if ((hw_status & INTEL_RNG_ENABLED) == 0) { | ||
111 | printk(KERN_ERR PFX "cannot enable RNG, aborting\n"); | ||
112 | goto out; | ||
113 | } | ||
114 | err = 0; | ||
115 | out: | ||
116 | return err; | ||
117 | } | ||
118 | |||
119 | static void intel_rng_cleanup(struct hwrng *rng) | ||
120 | { | ||
121 | void __iomem *mem = (void __iomem *)rng->priv; | ||
122 | u8 hw_status; | ||
123 | |||
124 | hw_status = hwstatus_get(mem); | ||
125 | if (hw_status & INTEL_RNG_ENABLED) | ||
126 | hwstatus_set(mem, hw_status & ~INTEL_RNG_ENABLED); | ||
127 | else | ||
128 | printk(KERN_WARNING PFX "unusual: RNG already disabled\n"); | ||
129 | } | ||
130 | |||
131 | |||
132 | static struct hwrng intel_rng = { | ||
133 | .name = "intel", | ||
134 | .init = intel_rng_init, | ||
135 | .cleanup = intel_rng_cleanup, | ||
136 | .data_present = intel_rng_data_present, | ||
137 | .data_read = intel_rng_data_read, | ||
138 | }; | ||
139 | |||
140 | |||
141 | static int __init mod_init(void) | ||
142 | { | ||
143 | int err = -ENODEV; | ||
144 | void __iomem *mem; | ||
145 | u8 hw_status; | ||
146 | |||
147 | if (!pci_dev_present(pci_tbl)) | ||
148 | goto out; /* Device not found. */ | ||
149 | |||
150 | err = -ENOMEM; | ||
151 | mem = ioremap(INTEL_RNG_ADDR, INTEL_RNG_ADDR_LEN); | ||
152 | if (!mem) | ||
153 | goto out; | ||
154 | intel_rng.priv = (unsigned long)mem; | ||
155 | |||
156 | /* Check for Intel 82802 */ | ||
157 | err = -ENODEV; | ||
158 | hw_status = hwstatus_get(mem); | ||
159 | if ((hw_status & INTEL_RNG_PRESENT) == 0) | ||
160 | goto err_unmap; | ||
161 | |||
162 | printk(KERN_INFO "Intel 82802 RNG detected\n"); | ||
163 | err = hwrng_register(&intel_rng); | ||
164 | if (err) { | ||
165 | printk(KERN_ERR PFX "RNG registering failed (%d)\n", | ||
166 | err); | ||
167 | goto out; | ||
168 | } | ||
169 | out: | ||
170 | return err; | ||
171 | |||
172 | err_unmap: | ||
173 | iounmap(mem); | ||
174 | goto out; | ||
175 | } | ||
176 | |||
177 | static void __exit mod_exit(void) | ||
178 | { | ||
179 | void __iomem *mem = (void __iomem *)intel_rng.priv; | ||
180 | |||
181 | hwrng_unregister(&intel_rng); | ||
182 | iounmap(mem); | ||
183 | } | ||
184 | |||
185 | subsys_initcall(mod_init); | ||
186 | module_exit(mod_exit); | ||
187 | |||
188 | MODULE_DESCRIPTION("H/W RNG driver for Intel chipsets"); | ||
189 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/char/hw_random/ixp4xx-rng.c b/drivers/char/hw_random/ixp4xx-rng.c new file mode 100644 index 000000000000..ef71022423c9 --- /dev/null +++ b/drivers/char/hw_random/ixp4xx-rng.c | |||
@@ -0,0 +1,73 @@ | |||
1 | /* | ||
2 | * drivers/char/rng/ixp4xx-rng.c | ||
3 | * | ||
4 | * RNG driver for Intel IXP4xx family of NPUs | ||
5 | * | ||
6 | * Author: Deepak Saxena <dsaxena@plexity.net> | ||
7 | * | ||
8 | * Copyright 2005 (c) MontaVista Software, Inc. | ||
9 | * | ||
10 | * Fixes by Michael Buesch | ||
11 | * | ||
12 | * This file is licensed under the terms of the GNU General Public | ||
13 | * License version 2. This program is licensed "as is" without any | ||
14 | * warranty of any kind, whether express or implied. | ||
15 | */ | ||
16 | |||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/config.h> | ||
19 | #include <linux/types.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/moduleparam.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/bitops.h> | ||
24 | #include <linux/hw_random.h> | ||
25 | |||
26 | #include <asm/io.h> | ||
27 | #include <asm/hardware.h> | ||
28 | |||
29 | |||
30 | static int ixp4xx_rng_data_read(struct hwrng *rng, u32 *buffer) | ||
31 | { | ||
32 | void __iomem * rng_base = (void __iomem *)rng->priv; | ||
33 | |||
34 | *buffer = __raw_readl(rng_base); | ||
35 | |||
36 | return 4; | ||
37 | } | ||
38 | |||
39 | static struct hwrng ixp4xx_rng_ops = { | ||
40 | .name = "ixp4xx", | ||
41 | .data_read = ixp4xx_rng_data_read, | ||
42 | }; | ||
43 | |||
44 | static int __init ixp4xx_rng_init(void) | ||
45 | { | ||
46 | void __iomem * rng_base; | ||
47 | int err; | ||
48 | |||
49 | rng_base = ioremap(0x70002100, 4); | ||
50 | if (!rng_base) | ||
51 | return -ENOMEM; | ||
52 | ixp4xx_rng_ops.priv = (unsigned long)rng_base; | ||
53 | err = hwrng_register(&ixp4xx_rng_ops); | ||
54 | if (err) | ||
55 | iounmap(rng_base); | ||
56 | |||
57 | return err; | ||
58 | } | ||
59 | |||
60 | static void __exit ixp4xx_rng_exit(void) | ||
61 | { | ||
62 | void __iomem * rng_base = (void __iomem *)ixp4xx_rng_ops.priv; | ||
63 | |||
64 | hwrng_unregister(&ixp4xx_rng_ops); | ||
65 | iounmap(rng_base); | ||
66 | } | ||
67 | |||
68 | subsys_initcall(ixp4xx_rng_init); | ||
69 | module_exit(ixp4xx_rng_exit); | ||
70 | |||
71 | MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net>"); | ||
72 | MODULE_DESCRIPTION("H/W Random Number Generator (RNG) driver for IXP4xx"); | ||
73 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/char/hw_random/omap-rng.c b/drivers/char/hw_random/omap-rng.c new file mode 100644 index 000000000000..819516b35a79 --- /dev/null +++ b/drivers/char/hw_random/omap-rng.c | |||
@@ -0,0 +1,208 @@ | |||
1 | /* | ||
2 | * driver/char/hw_random/omap-rng.c | ||
3 | * | ||
4 | * RNG driver for TI OMAP CPU family | ||
5 | * | ||
6 | * Author: Deepak Saxena <dsaxena@plexity.net> | ||
7 | * | ||
8 | * Copyright 2005 (c) MontaVista Software, Inc. | ||
9 | * | ||
10 | * Mostly based on original driver: | ||
11 | * | ||
12 | * Copyright (C) 2005 Nokia Corporation | ||
13 | * Author: Juha Yrj��<juha.yrjola@nokia.com> | ||
14 | * | ||
15 | * This file is licensed under the terms of the GNU General Public | ||
16 | * License version 2. This program is licensed "as is" without any | ||
17 | * warranty of any kind, whether express or implied. | ||
18 | * | ||
19 | * TODO: | ||
20 | * | ||
21 | * - Make status updated be interrupt driven so we don't poll | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #include <linux/module.h> | ||
26 | #include <linux/init.h> | ||
27 | #include <linux/random.h> | ||
28 | #include <linux/err.h> | ||
29 | #include <linux/device.h> | ||
30 | #include <linux/hw_random.h> | ||
31 | |||
32 | #include <asm/io.h> | ||
33 | #include <asm/hardware/clock.h> | ||
34 | |||
35 | #define RNG_OUT_REG 0x00 /* Output register */ | ||
36 | #define RNG_STAT_REG 0x04 /* Status register | ||
37 | [0] = STAT_BUSY */ | ||
38 | #define RNG_ALARM_REG 0x24 /* Alarm register | ||
39 | [7:0] = ALARM_COUNTER */ | ||
40 | #define RNG_CONFIG_REG 0x28 /* Configuration register | ||
41 | [11:6] = RESET_COUNT | ||
42 | [5:3] = RING2_DELAY | ||
43 | [2:0] = RING1_DELAY */ | ||
44 | #define RNG_REV_REG 0x3c /* Revision register | ||
45 | [7:0] = REV_NB */ | ||
46 | #define RNG_MASK_REG 0x40 /* Mask and reset register | ||
47 | [2] = IT_EN | ||
48 | [1] = SOFTRESET | ||
49 | [0] = AUTOIDLE */ | ||
50 | #define RNG_SYSSTATUS 0x44 /* System status | ||
51 | [0] = RESETDONE */ | ||
52 | |||
53 | static void __iomem *rng_base; | ||
54 | static struct clk *rng_ick; | ||
55 | static struct device *rng_dev; | ||
56 | |||
57 | static u32 omap_rng_read_reg(int reg) | ||
58 | { | ||
59 | return __raw_readl(rng_base + reg); | ||
60 | } | ||
61 | |||
62 | static void omap_rng_write_reg(int reg, u32 val) | ||
63 | { | ||
64 | __raw_writel(val, rng_base + reg); | ||
65 | } | ||
66 | |||
67 | /* REVISIT: Does the status bit really work on 16xx? */ | ||
68 | static int omap_rng_data_present(struct hwrng *rng) | ||
69 | { | ||
70 | return omap_rng_read_reg(RNG_STAT_REG) ? 0 : 1; | ||
71 | } | ||
72 | |||
73 | static int omap_rng_data_read(struct hwrng *rng, u32 *data) | ||
74 | { | ||
75 | *data = omap_rng_read_reg(RNG_OUT_REG); | ||
76 | |||
77 | return 4; | ||
78 | } | ||
79 | |||
80 | static struct hwrng omap_rng_ops = { | ||
81 | .name = "omap", | ||
82 | .data_present = omap_rng_data_present, | ||
83 | .data_read = omap_rng_data_read, | ||
84 | }; | ||
85 | |||
86 | static int __init omap_rng_probe(struct device *dev) | ||
87 | { | ||
88 | struct platform_device *pdev = to_platform_device(dev); | ||
89 | struct resource *res, *mem; | ||
90 | int ret; | ||
91 | |||
92 | /* | ||
93 | * A bit ugly, and it will never actually happen but there can | ||
94 | * be only one RNG and this catches any bork | ||
95 | */ | ||
96 | BUG_ON(rng_dev); | ||
97 | |||
98 | if (cpu_is_omap24xx()) { | ||
99 | rng_ick = clk_get(NULL, "rng_ick"); | ||
100 | if (IS_ERR(rng_ick)) { | ||
101 | dev_err(dev, "Could not get rng_ick\n"); | ||
102 | ret = PTR_ERR(rng_ick); | ||
103 | return ret; | ||
104 | } | ||
105 | else { | ||
106 | clk_use(rng_ick); | ||
107 | } | ||
108 | } | ||
109 | |||
110 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
111 | |||
112 | if (!res) | ||
113 | return -ENOENT; | ||
114 | |||
115 | mem = request_mem_region(res->start, res->end - res->start + 1, | ||
116 | pdev->name); | ||
117 | if (mem == NULL) | ||
118 | return -EBUSY; | ||
119 | |||
120 | dev_set_drvdata(dev, mem); | ||
121 | rng_base = (u32 __iomem *)io_p2v(res->start); | ||
122 | |||
123 | ret = hwrng_register(&omap_rng_ops); | ||
124 | if (ret) { | ||
125 | release_resource(mem); | ||
126 | rng_base = NULL; | ||
127 | return ret; | ||
128 | } | ||
129 | |||
130 | dev_info(dev, "OMAP Random Number Generator ver. %02x\n", | ||
131 | omap_rng_read_reg(RNG_REV_REG)); | ||
132 | omap_rng_write_reg(RNG_MASK_REG, 0x1); | ||
133 | |||
134 | rng_dev = dev; | ||
135 | |||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | static int __exit omap_rng_remove(struct device *dev) | ||
140 | { | ||
141 | struct resource *mem = dev_get_drvdata(dev); | ||
142 | |||
143 | hwrng_unregister(&omap_rng_ops); | ||
144 | |||
145 | omap_rng_write_reg(RNG_MASK_REG, 0x0); | ||
146 | |||
147 | if (cpu_is_omap24xx()) { | ||
148 | clk_unuse(rng_ick); | ||
149 | clk_put(rng_ick); | ||
150 | } | ||
151 | |||
152 | release_resource(mem); | ||
153 | rng_base = NULL; | ||
154 | |||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | #ifdef CONFIG_PM | ||
159 | |||
160 | static int omap_rng_suspend(struct device *dev, pm_message_t message, u32 level) | ||
161 | { | ||
162 | omap_rng_write_reg(RNG_MASK_REG, 0x0); | ||
163 | |||
164 | return 0; | ||
165 | } | ||
166 | |||
167 | static int omap_rng_resume(struct device *dev, pm_message_t message, u32 level) | ||
168 | { | ||
169 | omap_rng_write_reg(RNG_MASK_REG, 0x1); | ||
170 | |||
171 | return 1; | ||
172 | } | ||
173 | |||
174 | #else | ||
175 | |||
176 | #define omap_rng_suspend NULL | ||
177 | #define omap_rng_resume NULL | ||
178 | |||
179 | #endif | ||
180 | |||
181 | |||
182 | static struct device_driver omap_rng_driver = { | ||
183 | .name = "omap_rng", | ||
184 | .bus = &platform_bus_type, | ||
185 | .probe = omap_rng_probe, | ||
186 | .remove = __exit_p(omap_rng_remove), | ||
187 | .suspend = omap_rng_suspend, | ||
188 | .resume = omap_rng_resume | ||
189 | }; | ||
190 | |||
191 | static int __init omap_rng_init(void) | ||
192 | { | ||
193 | if (!cpu_is_omap16xx() && !cpu_is_omap24xx()) | ||
194 | return -ENODEV; | ||
195 | |||
196 | return driver_register(&omap_rng_driver); | ||
197 | } | ||
198 | |||
199 | static void __exit omap_rng_exit(void) | ||
200 | { | ||
201 | driver_unregister(&omap_rng_driver); | ||
202 | } | ||
203 | |||
204 | module_init(omap_rng_init); | ||
205 | module_exit(omap_rng_exit); | ||
206 | |||
207 | MODULE_AUTHOR("Deepak Saxena (and others)"); | ||
208 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/char/hw_random/via-rng.c b/drivers/char/hw_random/via-rng.c new file mode 100644 index 000000000000..0e786b617bb8 --- /dev/null +++ b/drivers/char/hw_random/via-rng.c | |||
@@ -0,0 +1,183 @@ | |||
1 | /* | ||
2 | * RNG driver for VIA RNGs | ||
3 | * | ||
4 | * Copyright 2005 (c) MontaVista Software, Inc. | ||
5 | * | ||
6 | * with the majority of the code coming from: | ||
7 | * | ||
8 | * Hardware driver for the Intel/AMD/VIA Random Number Generators (RNG) | ||
9 | * (c) Copyright 2003 Red Hat Inc <jgarzik@redhat.com> | ||
10 | * | ||
11 | * derived from | ||
12 | * | ||
13 | * Hardware driver for the AMD 768 Random Number Generator (RNG) | ||
14 | * (c) Copyright 2001 Red Hat Inc <alan@redhat.com> | ||
15 | * | ||
16 | * derived from | ||
17 | * | ||
18 | * Hardware driver for Intel i810 Random Number Generator (RNG) | ||
19 | * Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com> | ||
20 | * Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com> | ||
21 | * | ||
22 | * This file is licensed under the terms of the GNU General Public | ||
23 | * License version 2. This program is licensed "as is" without any | ||
24 | * warranty of any kind, whether express or implied. | ||
25 | */ | ||
26 | |||
27 | #include <linux/module.h> | ||
28 | #include <linux/kernel.h> | ||
29 | #include <linux/pci.h> | ||
30 | #include <linux/hw_random.h> | ||
31 | #include <asm/io.h> | ||
32 | #include <asm/msr.h> | ||
33 | #include <asm/cpufeature.h> | ||
34 | |||
35 | |||
36 | #define PFX KBUILD_MODNAME ": " | ||
37 | |||
38 | |||
39 | enum { | ||
40 | VIA_STRFILT_CNT_SHIFT = 16, | ||
41 | VIA_STRFILT_FAIL = (1 << 15), | ||
42 | VIA_STRFILT_ENABLE = (1 << 14), | ||
43 | VIA_RAWBITS_ENABLE = (1 << 13), | ||
44 | VIA_RNG_ENABLE = (1 << 6), | ||
45 | VIA_XSTORE_CNT_MASK = 0x0F, | ||
46 | |||
47 | VIA_RNG_CHUNK_8 = 0x00, /* 64 rand bits, 64 stored bits */ | ||
48 | VIA_RNG_CHUNK_4 = 0x01, /* 32 rand bits, 32 stored bits */ | ||
49 | VIA_RNG_CHUNK_4_MASK = 0xFFFFFFFF, | ||
50 | VIA_RNG_CHUNK_2 = 0x02, /* 16 rand bits, 32 stored bits */ | ||
51 | VIA_RNG_CHUNK_2_MASK = 0xFFFF, | ||
52 | VIA_RNG_CHUNK_1 = 0x03, /* 8 rand bits, 32 stored bits */ | ||
53 | VIA_RNG_CHUNK_1_MASK = 0xFF, | ||
54 | }; | ||
55 | |||
56 | /* | ||
57 | * Investigate using the 'rep' prefix to obtain 32 bits of random data | ||
58 | * in one insn. The upside is potentially better performance. The | ||
59 | * downside is that the instruction becomes no longer atomic. Due to | ||
60 | * this, just like familiar issues with /dev/random itself, the worst | ||
61 | * case of a 'rep xstore' could potentially pause a cpu for an | ||
62 | * unreasonably long time. In practice, this condition would likely | ||
63 | * only occur when the hardware is failing. (or so we hope :)) | ||
64 | * | ||
65 | * Another possible performance boost may come from simply buffering | ||
66 | * until we have 4 bytes, thus returning a u32 at a time, | ||
67 | * instead of the current u8-at-a-time. | ||
68 | */ | ||
69 | |||
70 | static inline u32 xstore(u32 *addr, u32 edx_in) | ||
71 | { | ||
72 | u32 eax_out; | ||
73 | |||
74 | asm(".byte 0x0F,0xA7,0xC0 /* xstore %%edi (addr=%0) */" | ||
75 | :"=m"(*addr), "=a"(eax_out) | ||
76 | :"D"(addr), "d"(edx_in)); | ||
77 | |||
78 | return eax_out; | ||
79 | } | ||
80 | |||
81 | static int via_rng_data_present(struct hwrng *rng) | ||
82 | { | ||
83 | u32 bytes_out; | ||
84 | u32 *via_rng_datum = (u32 *)(&rng->priv); | ||
85 | |||
86 | /* We choose the recommended 1-byte-per-instruction RNG rate, | ||
87 | * for greater randomness at the expense of speed. Larger | ||
88 | * values 2, 4, or 8 bytes-per-instruction yield greater | ||
89 | * speed at lesser randomness. | ||
90 | * | ||
91 | * If you change this to another VIA_CHUNK_n, you must also | ||
92 | * change the ->n_bytes values in rng_vendor_ops[] tables. | ||
93 | * VIA_CHUNK_8 requires further code changes. | ||
94 | * | ||
95 | * A copy of MSR_VIA_RNG is placed in eax_out when xstore | ||
96 | * completes. | ||
97 | */ | ||
98 | |||
99 | *via_rng_datum = 0; /* paranoia, not really necessary */ | ||
100 | bytes_out = xstore(via_rng_datum, VIA_RNG_CHUNK_1); | ||
101 | bytes_out &= VIA_XSTORE_CNT_MASK; | ||
102 | if (bytes_out == 0) | ||
103 | return 0; | ||
104 | return 1; | ||
105 | } | ||
106 | |||
107 | static int via_rng_data_read(struct hwrng *rng, u32 *data) | ||
108 | { | ||
109 | u32 via_rng_datum = (u32)rng->priv; | ||
110 | |||
111 | *data = via_rng_datum; | ||
112 | |||
113 | return 1; | ||
114 | } | ||
115 | |||
116 | static int via_rng_init(struct hwrng *rng) | ||
117 | { | ||
118 | u32 lo, hi, old_lo; | ||
119 | |||
120 | /* Control the RNG via MSR. Tread lightly and pay very close | ||
121 | * close attention to values written, as the reserved fields | ||
122 | * are documented to be "undefined and unpredictable"; but it | ||
123 | * does not say to write them as zero, so I make a guess that | ||
124 | * we restore the values we find in the register. | ||
125 | */ | ||
126 | rdmsr(MSR_VIA_RNG, lo, hi); | ||
127 | |||
128 | old_lo = lo; | ||
129 | lo &= ~(0x7f << VIA_STRFILT_CNT_SHIFT); | ||
130 | lo &= ~VIA_XSTORE_CNT_MASK; | ||
131 | lo &= ~(VIA_STRFILT_ENABLE | VIA_STRFILT_FAIL | VIA_RAWBITS_ENABLE); | ||
132 | lo |= VIA_RNG_ENABLE; | ||
133 | |||
134 | if (lo != old_lo) | ||
135 | wrmsr(MSR_VIA_RNG, lo, hi); | ||
136 | |||
137 | /* perhaps-unnecessary sanity check; remove after testing if | ||
138 | unneeded */ | ||
139 | rdmsr(MSR_VIA_RNG, lo, hi); | ||
140 | if ((lo & VIA_RNG_ENABLE) == 0) { | ||
141 | printk(KERN_ERR PFX "cannot enable VIA C3 RNG, aborting\n"); | ||
142 | return -ENODEV; | ||
143 | } | ||
144 | |||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | |||
149 | static struct hwrng via_rng = { | ||
150 | .name = "via", | ||
151 | .init = via_rng_init, | ||
152 | .data_present = via_rng_data_present, | ||
153 | .data_read = via_rng_data_read, | ||
154 | }; | ||
155 | |||
156 | |||
157 | static int __init mod_init(void) | ||
158 | { | ||
159 | int err; | ||
160 | |||
161 | if (!cpu_has_xstore) | ||
162 | return -ENODEV; | ||
163 | printk(KERN_INFO "VIA RNG detected\n"); | ||
164 | err = hwrng_register(&via_rng); | ||
165 | if (err) { | ||
166 | printk(KERN_ERR PFX "RNG registering failed (%d)\n", | ||
167 | err); | ||
168 | goto out; | ||
169 | } | ||
170 | out: | ||
171 | return err; | ||
172 | } | ||
173 | |||
174 | static void __exit mod_exit(void) | ||
175 | { | ||
176 | hwrng_unregister(&via_rng); | ||
177 | } | ||
178 | |||
179 | subsys_initcall(mod_init); | ||
180 | module_exit(mod_exit); | ||
181 | |||
182 | MODULE_DESCRIPTION("H/W RNG driver for VIA chipsets"); | ||
183 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 9f2f8fdec69a..83ed6ae466a5 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c | |||
@@ -57,8 +57,7 @@ static int ipmi_init_msghandler(void); | |||
57 | static int initialized = 0; | 57 | static int initialized = 0; |
58 | 58 | ||
59 | #ifdef CONFIG_PROC_FS | 59 | #ifdef CONFIG_PROC_FS |
60 | struct proc_dir_entry *proc_ipmi_root = NULL; | 60 | static struct proc_dir_entry *proc_ipmi_root = NULL; |
61 | EXPORT_SYMBOL(proc_ipmi_root); | ||
62 | #endif /* CONFIG_PROC_FS */ | 61 | #endif /* CONFIG_PROC_FS */ |
63 | 62 | ||
64 | #define MAX_EVENTS_IN_QUEUE 25 | 63 | #define MAX_EVENTS_IN_QUEUE 25 |
@@ -936,11 +935,8 @@ int ipmi_set_gets_events(ipmi_user_t user, int val) | |||
936 | 935 | ||
937 | if (val) { | 936 | if (val) { |
938 | /* Deliver any queued events. */ | 937 | /* Deliver any queued events. */ |
939 | list_for_each_entry_safe(msg, msg2, &intf->waiting_events, | 938 | list_for_each_entry_safe(msg, msg2, &intf->waiting_events, link) |
940 | link) { | 939 | list_move_tail(&msg->link, &msgs); |
941 | list_del(&msg->link); | ||
942 | list_add_tail(&msg->link, &msgs); | ||
943 | } | ||
944 | intf->waiting_events_count = 0; | 940 | intf->waiting_events_count = 0; |
945 | } | 941 | } |
946 | 942 | ||
@@ -3677,7 +3673,7 @@ static void send_panic_events(char *str) | |||
3677 | } | 3673 | } |
3678 | #endif /* CONFIG_IPMI_PANIC_EVENT */ | 3674 | #endif /* CONFIG_IPMI_PANIC_EVENT */ |
3679 | 3675 | ||
3680 | static int has_paniced = 0; | 3676 | static int has_panicked = 0; |
3681 | 3677 | ||
3682 | static int panic_event(struct notifier_block *this, | 3678 | static int panic_event(struct notifier_block *this, |
3683 | unsigned long event, | 3679 | unsigned long event, |
@@ -3686,9 +3682,9 @@ static int panic_event(struct notifier_block *this, | |||
3686 | int i; | 3682 | int i; |
3687 | ipmi_smi_t intf; | 3683 | ipmi_smi_t intf; |
3688 | 3684 | ||
3689 | if (has_paniced) | 3685 | if (has_panicked) |
3690 | return NOTIFY_DONE; | 3686 | return NOTIFY_DONE; |
3691 | has_paniced = 1; | 3687 | has_panicked = 1; |
3692 | 3688 | ||
3693 | /* For every registered interface, set it to run to completion. */ | 3689 | /* For every registered interface, set it to run to completion. */ |
3694 | for (i = 0; i < MAX_IPMI_INTERFACES; i++) { | 3690 | for (i = 0; i < MAX_IPMI_INTERFACES; i++) { |
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 02a7dd7a8a55..101c14b9b26d 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c | |||
@@ -809,7 +809,7 @@ static int ipmi_thread(void *data) | |||
809 | /* do nothing */ | 809 | /* do nothing */ |
810 | } | 810 | } |
811 | else if (smi_result == SI_SM_CALL_WITH_DELAY) | 811 | else if (smi_result == SI_SM_CALL_WITH_DELAY) |
812 | udelay(1); | 812 | schedule(); |
813 | else | 813 | else |
814 | schedule_timeout_interruptible(1); | 814 | schedule_timeout_interruptible(1); |
815 | } | 815 | } |
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index edd996f6fb87..4bb3d2272604 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c | |||
@@ -151,6 +151,7 @@ unsigned char kbd_sysrq_xlate[KEY_MAX + 1] = | |||
151 | "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */ | 151 | "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */ |
152 | "\r\000/"; /* 0x60 - 0x6f */ | 152 | "\r\000/"; /* 0x60 - 0x6f */ |
153 | static int sysrq_down; | 153 | static int sysrq_down; |
154 | static int sysrq_alt_use; | ||
154 | #endif | 155 | #endif |
155 | static int sysrq_alt; | 156 | static int sysrq_alt; |
156 | 157 | ||
@@ -673,7 +674,7 @@ static void k_dead2(struct vc_data *vc, unsigned char value, char up_flag, struc | |||
673 | */ | 674 | */ |
674 | static void k_dead(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) | 675 | static void k_dead(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) |
675 | { | 676 | { |
676 | static unsigned char ret_diacr[NR_DEAD] = {'`', '\'', '^', '~', '"', ',' }; | 677 | static const unsigned char ret_diacr[NR_DEAD] = {'`', '\'', '^', '~', '"', ',' }; |
677 | value = ret_diacr[value]; | 678 | value = ret_diacr[value]; |
678 | k_deadunicode(vc, value, up_flag, regs); | 679 | k_deadunicode(vc, value, up_flag, regs); |
679 | } | 680 | } |
@@ -710,8 +711,8 @@ static void k_cur(struct vc_data *vc, unsigned char value, char up_flag, struct | |||
710 | 711 | ||
711 | static void k_pad(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) | 712 | static void k_pad(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) |
712 | { | 713 | { |
713 | static const char *pad_chars = "0123456789+-*/\015,.?()#"; | 714 | static const char pad_chars[] = "0123456789+-*/\015,.?()#"; |
714 | static const char *app_map = "pqrstuvwxylSRQMnnmPQS"; | 715 | static const char app_map[] = "pqrstuvwxylSRQMnnmPQS"; |
715 | 716 | ||
716 | if (up_flag) | 717 | if (up_flag) |
717 | return; /* no action, if this is a key release */ | 718 | return; /* no action, if this is a key release */ |
@@ -1036,7 +1037,7 @@ static void kbd_refresh_leds(struct input_handle *handle) | |||
1036 | #define HW_RAW(dev) (test_bit(EV_MSC, dev->evbit) && test_bit(MSC_RAW, dev->mscbit) &&\ | 1037 | #define HW_RAW(dev) (test_bit(EV_MSC, dev->evbit) && test_bit(MSC_RAW, dev->mscbit) &&\ |
1037 | ((dev)->id.bustype == BUS_I8042) && ((dev)->id.vendor == 0x0001) && ((dev)->id.product == 0x0001)) | 1038 | ((dev)->id.bustype == BUS_I8042) && ((dev)->id.vendor == 0x0001) && ((dev)->id.product == 0x0001)) |
1038 | 1039 | ||
1039 | static unsigned short x86_keycodes[256] = | 1040 | static const unsigned short x86_keycodes[256] = |
1040 | { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, | 1041 | { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, |
1041 | 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, | 1042 | 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, |
1042 | 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, | 1043 | 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, |
@@ -1074,11 +1075,13 @@ static int emulate_raw(struct vc_data *vc, unsigned int keycode, | |||
1074 | put_queue(vc, 0x1d | up_flag); | 1075 | put_queue(vc, 0x1d | up_flag); |
1075 | put_queue(vc, 0x45 | up_flag); | 1076 | put_queue(vc, 0x45 | up_flag); |
1076 | return 0; | 1077 | return 0; |
1077 | case KEY_HANGUEL: | 1078 | case KEY_HANGEUL: |
1078 | if (!up_flag) put_queue(vc, 0xf1); | 1079 | if (!up_flag) |
1080 | put_queue(vc, 0xf2); | ||
1079 | return 0; | 1081 | return 0; |
1080 | case KEY_HANJA: | 1082 | case KEY_HANJA: |
1081 | if (!up_flag) put_queue(vc, 0xf2); | 1083 | if (!up_flag) |
1084 | put_queue(vc, 0xf1); | ||
1082 | return 0; | 1085 | return 0; |
1083 | } | 1086 | } |
1084 | 1087 | ||
@@ -1143,7 +1146,7 @@ static void kbd_keycode(unsigned int keycode, int down, | |||
1143 | kbd = kbd_table + fg_console; | 1146 | kbd = kbd_table + fg_console; |
1144 | 1147 | ||
1145 | if (keycode == KEY_LEFTALT || keycode == KEY_RIGHTALT) | 1148 | if (keycode == KEY_LEFTALT || keycode == KEY_RIGHTALT) |
1146 | sysrq_alt = down; | 1149 | sysrq_alt = down ? keycode : 0; |
1147 | #ifdef CONFIG_SPARC | 1150 | #ifdef CONFIG_SPARC |
1148 | if (keycode == KEY_STOP) | 1151 | if (keycode == KEY_STOP) |
1149 | sparc_l1_a_state = down; | 1152 | sparc_l1_a_state = down; |
@@ -1163,9 +1166,14 @@ static void kbd_keycode(unsigned int keycode, int down, | |||
1163 | 1166 | ||
1164 | #ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */ | 1167 | #ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */ |
1165 | if (keycode == KEY_SYSRQ && (sysrq_down || (down == 1 && sysrq_alt))) { | 1168 | if (keycode == KEY_SYSRQ && (sysrq_down || (down == 1 && sysrq_alt))) { |
1166 | sysrq_down = down; | 1169 | if (!sysrq_down) { |
1170 | sysrq_down = down; | ||
1171 | sysrq_alt_use = sysrq_alt; | ||
1172 | } | ||
1167 | return; | 1173 | return; |
1168 | } | 1174 | } |
1175 | if (sysrq_down && !down && keycode == sysrq_alt_use) | ||
1176 | sysrq_down = 0; | ||
1169 | if (sysrq_down && down && !rep) { | 1177 | if (sysrq_down && down && !rep) { |
1170 | handle_sysrq(kbd_sysrq_xlate[keycode], regs, tty); | 1178 | handle_sysrq(kbd_sysrq_xlate[keycode], regs, tty); |
1171 | return; | 1179 | return; |
diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c index f43c2e04eadd..01247cccb89f 100644 --- a/drivers/char/moxa.c +++ b/drivers/char/moxa.c | |||
@@ -301,7 +301,7 @@ static struct tty_operations moxa_ops = { | |||
301 | .tiocmset = moxa_tiocmset, | 301 | .tiocmset = moxa_tiocmset, |
302 | }; | 302 | }; |
303 | 303 | ||
304 | static spinlock_t moxa_lock = SPIN_LOCK_UNLOCKED; | 304 | static DEFINE_SPINLOCK(moxa_lock); |
305 | 305 | ||
306 | #ifdef CONFIG_PCI | 306 | #ifdef CONFIG_PCI |
307 | static int moxa_get_PCI_conf(struct pci_dev *p, int board_type, moxa_board_conf * board) | 307 | static int moxa_get_PCI_conf(struct pci_dev *p, int board_type, moxa_board_conf * board) |
diff --git a/drivers/char/nsc_gpio.c b/drivers/char/nsc_gpio.c new file mode 100644 index 000000000000..5b91e4e25641 --- /dev/null +++ b/drivers/char/nsc_gpio.c | |||
@@ -0,0 +1,142 @@ | |||
1 | /* linux/drivers/char/nsc_gpio.c | ||
2 | |||
3 | National Semiconductor common GPIO device-file/VFS methods. | ||
4 | Allows a user space process to control the GPIO pins. | ||
5 | |||
6 | Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com> | ||
7 | Copyright (c) 2005 Jim Cromie <jim.cromie@gmail.com> | ||
8 | */ | ||
9 | |||
10 | #include <linux/config.h> | ||
11 | #include <linux/fs.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/errno.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/nsc_gpio.h> | ||
17 | #include <linux/platform_device.h> | ||
18 | #include <asm/uaccess.h> | ||
19 | #include <asm/io.h> | ||
20 | |||
21 | #define NAME "nsc_gpio" | ||
22 | |||
23 | void nsc_gpio_dump(struct nsc_gpio_ops *amp, unsigned index) | ||
24 | { | ||
25 | /* retrieve current config w/o changing it */ | ||
26 | u32 config = amp->gpio_config(index, ~0, 0); | ||
27 | |||
28 | /* user requested via 'v' command, so its INFO */ | ||
29 | dev_info(amp->dev, "io%02u: 0x%04x %s %s %s %s %s %s %s\tio:%d/%d\n", | ||
30 | index, config, | ||
31 | (config & 1) ? "OE" : "TS", /* output-enabled/tristate */ | ||
32 | (config & 2) ? "PP" : "OD", /* push pull / open drain */ | ||
33 | (config & 4) ? "PUE" : "PUD", /* pull up enabled/disabled */ | ||
34 | (config & 8) ? "LOCKED" : "", /* locked / unlocked */ | ||
35 | (config & 16) ? "LEVEL" : "EDGE",/* level/edge input */ | ||
36 | (config & 32) ? "HI" : "LO", /* trigger on rise/fall edge */ | ||
37 | (config & 64) ? "DEBOUNCE" : "", /* debounce */ | ||
38 | |||
39 | amp->gpio_get(index), amp->gpio_current(index)); | ||
40 | } | ||
41 | |||
42 | ssize_t nsc_gpio_write(struct file *file, const char __user *data, | ||
43 | size_t len, loff_t *ppos) | ||
44 | { | ||
45 | unsigned m = iminor(file->f_dentry->d_inode); | ||
46 | struct nsc_gpio_ops *amp = file->private_data; | ||
47 | struct device *dev = amp->dev; | ||
48 | size_t i; | ||
49 | int err = 0; | ||
50 | |||
51 | for (i = 0; i < len; ++i) { | ||
52 | char c; | ||
53 | if (get_user(c, data + i)) | ||
54 | return -EFAULT; | ||
55 | switch (c) { | ||
56 | case '0': | ||
57 | amp->gpio_set(m, 0); | ||
58 | break; | ||
59 | case '1': | ||
60 | amp->gpio_set(m, 1); | ||
61 | break; | ||
62 | case 'O': | ||
63 | dev_dbg(dev, "GPIO%d output enabled\n", m); | ||
64 | amp->gpio_config(m, ~1, 1); | ||
65 | break; | ||
66 | case 'o': | ||
67 | dev_dbg(dev, "GPIO%d output disabled\n", m); | ||
68 | amp->gpio_config(m, ~1, 0); | ||
69 | break; | ||
70 | case 'T': | ||
71 | dev_dbg(dev, "GPIO%d output is push pull\n", | ||
72 | m); | ||
73 | amp->gpio_config(m, ~2, 2); | ||
74 | break; | ||
75 | case 't': | ||
76 | dev_dbg(dev, "GPIO%d output is open drain\n", | ||
77 | m); | ||
78 | amp->gpio_config(m, ~2, 0); | ||
79 | break; | ||
80 | case 'P': | ||
81 | dev_dbg(dev, "GPIO%d pull up enabled\n", m); | ||
82 | amp->gpio_config(m, ~4, 4); | ||
83 | break; | ||
84 | case 'p': | ||
85 | dev_dbg(dev, "GPIO%d pull up disabled\n", m); | ||
86 | amp->gpio_config(m, ~4, 0); | ||
87 | break; | ||
88 | case 'v': | ||
89 | /* View Current pin settings */ | ||
90 | amp->gpio_dump(amp, m); | ||
91 | break; | ||
92 | case '\n': | ||
93 | /* end of settings string, do nothing */ | ||
94 | break; | ||
95 | default: | ||
96 | dev_err(dev, "io%2d bad setting: chr<0x%2x>\n", | ||
97 | m, (int)c); | ||
98 | err++; | ||
99 | } | ||
100 | } | ||
101 | if (err) | ||
102 | return -EINVAL; /* full string handled, report error */ | ||
103 | |||
104 | return len; | ||
105 | } | ||
106 | |||
107 | ssize_t nsc_gpio_read(struct file *file, char __user * buf, | ||
108 | size_t len, loff_t * ppos) | ||
109 | { | ||
110 | unsigned m = iminor(file->f_dentry->d_inode); | ||
111 | int value; | ||
112 | struct nsc_gpio_ops *amp = file->private_data; | ||
113 | |||
114 | value = amp->gpio_get(m); | ||
115 | if (put_user(value ? '1' : '0', buf)) | ||
116 | return -EFAULT; | ||
117 | |||
118 | return 1; | ||
119 | } | ||
120 | |||
121 | /* common file-ops routines for both scx200_gpio and pc87360_gpio */ | ||
122 | EXPORT_SYMBOL(nsc_gpio_write); | ||
123 | EXPORT_SYMBOL(nsc_gpio_read); | ||
124 | EXPORT_SYMBOL(nsc_gpio_dump); | ||
125 | |||
126 | static int __init nsc_gpio_init(void) | ||
127 | { | ||
128 | printk(KERN_DEBUG NAME " initializing\n"); | ||
129 | return 0; | ||
130 | } | ||
131 | |||
132 | static void __exit nsc_gpio_cleanup(void) | ||
133 | { | ||
134 | printk(KERN_DEBUG NAME " cleanup\n"); | ||
135 | } | ||
136 | |||
137 | module_init(nsc_gpio_init); | ||
138 | module_exit(nsc_gpio_cleanup); | ||
139 | |||
140 | MODULE_AUTHOR("Jim Cromie <jim.cromie@gmail.com>"); | ||
141 | MODULE_DESCRIPTION("NatSemi GPIO Common Methods"); | ||
142 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/char/pc8736x_gpio.c b/drivers/char/pc8736x_gpio.c new file mode 100644 index 000000000000..1c706ccfdbb3 --- /dev/null +++ b/drivers/char/pc8736x_gpio.c | |||
@@ -0,0 +1,340 @@ | |||
1 | /* linux/drivers/char/pc8736x_gpio.c | ||
2 | |||
3 | National Semiconductor PC8736x GPIO driver. Allows a user space | ||
4 | process to play with the GPIO pins. | ||
5 | |||
6 | Copyright (c) 2005 Jim Cromie <jim.cromie@gmail.com> | ||
7 | |||
8 | adapted from linux/drivers/char/scx200_gpio.c | ||
9 | Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>, | ||
10 | */ | ||
11 | |||
12 | #include <linux/config.h> | ||
13 | #include <linux/fs.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/errno.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/io.h> | ||
19 | #include <linux/ioport.h> | ||
20 | #include <linux/mutex.h> | ||
21 | #include <linux/nsc_gpio.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <asm/uaccess.h> | ||
24 | |||
25 | #define DEVNAME "pc8736x_gpio" | ||
26 | |||
27 | MODULE_AUTHOR("Jim Cromie <jim.cromie@gmail.com>"); | ||
28 | MODULE_DESCRIPTION("NatSemi PC-8736x GPIO Pin Driver"); | ||
29 | MODULE_LICENSE("GPL"); | ||
30 | |||
31 | static int major; /* default to dynamic major */ | ||
32 | module_param(major, int, 0); | ||
33 | MODULE_PARM_DESC(major, "Major device number"); | ||
34 | |||
35 | static DEFINE_MUTEX(pc8736x_gpio_config_lock); | ||
36 | static unsigned pc8736x_gpio_base; | ||
37 | static u8 pc8736x_gpio_shadow[4]; | ||
38 | |||
39 | #define SIO_BASE1 0x2E /* 1st command-reg to check */ | ||
40 | #define SIO_BASE2 0x4E /* alt command-reg to check */ | ||
41 | #define SIO_BASE_OFFSET 0x20 | ||
42 | |||
43 | #define SIO_SID 0x20 /* SuperI/O ID Register */ | ||
44 | #define SIO_SID_VALUE 0xe9 /* Expected value in SuperI/O ID Register */ | ||
45 | |||
46 | #define SIO_CF1 0x21 /* chip config, bit0 is chip enable */ | ||
47 | |||
48 | #define PC8736X_GPIO_SIZE 16 | ||
49 | |||
50 | #define SIO_UNIT_SEL 0x7 /* unit select reg */ | ||
51 | #define SIO_UNIT_ACT 0x30 /* unit enable */ | ||
52 | #define SIO_GPIO_UNIT 0x7 /* unit number of GPIO */ | ||
53 | #define SIO_VLM_UNIT 0x0D | ||
54 | #define SIO_TMS_UNIT 0x0E | ||
55 | |||
56 | /* config-space addrs to read/write each unit's runtime addr */ | ||
57 | #define SIO_BASE_HADDR 0x60 | ||
58 | #define SIO_BASE_LADDR 0x61 | ||
59 | |||
60 | /* GPIO config-space pin-control addresses */ | ||
61 | #define SIO_GPIO_PIN_SELECT 0xF0 | ||
62 | #define SIO_GPIO_PIN_CONFIG 0xF1 | ||
63 | #define SIO_GPIO_PIN_EVENT 0xF2 | ||
64 | |||
65 | static unsigned char superio_cmd = 0; | ||
66 | static unsigned char selected_device = 0xFF; /* bogus start val */ | ||
67 | |||
68 | /* GPIO port runtime access, functionality */ | ||
69 | static int port_offset[] = { 0, 4, 8, 10 }; /* non-uniform offsets ! */ | ||
70 | /* static int event_capable[] = { 1, 1, 0, 0 }; ports 2,3 are hobbled */ | ||
71 | |||
72 | #define PORT_OUT 0 | ||
73 | #define PORT_IN 1 | ||
74 | #define PORT_EVT_EN 2 | ||
75 | #define PORT_EVT_STST 3 | ||
76 | |||
77 | static struct platform_device *pdev; /* use in dev_*() */ | ||
78 | |||
79 | static inline void superio_outb(int addr, int val) | ||
80 | { | ||
81 | outb_p(addr, superio_cmd); | ||
82 | outb_p(val, superio_cmd + 1); | ||
83 | } | ||
84 | |||
85 | static inline int superio_inb(int addr) | ||
86 | { | ||
87 | outb_p(addr, superio_cmd); | ||
88 | return inb_p(superio_cmd + 1); | ||
89 | } | ||
90 | |||
91 | static int pc8736x_superio_present(void) | ||
92 | { | ||
93 | /* try the 2 possible values, read a hardware reg to verify */ | ||
94 | superio_cmd = SIO_BASE1; | ||
95 | if (superio_inb(SIO_SID) == SIO_SID_VALUE) | ||
96 | return superio_cmd; | ||
97 | |||
98 | superio_cmd = SIO_BASE2; | ||
99 | if (superio_inb(SIO_SID) == SIO_SID_VALUE) | ||
100 | return superio_cmd; | ||
101 | |||
102 | return 0; | ||
103 | } | ||
104 | |||
105 | static void device_select(unsigned devldn) | ||
106 | { | ||
107 | superio_outb(SIO_UNIT_SEL, devldn); | ||
108 | selected_device = devldn; | ||
109 | } | ||
110 | |||
111 | static void select_pin(unsigned iminor) | ||
112 | { | ||
113 | /* select GPIO port/pin from device minor number */ | ||
114 | device_select(SIO_GPIO_UNIT); | ||
115 | superio_outb(SIO_GPIO_PIN_SELECT, | ||
116 | ((iminor << 1) & 0xF0) | (iminor & 0x7)); | ||
117 | } | ||
118 | |||
119 | static inline u32 pc8736x_gpio_configure_fn(unsigned index, u32 mask, u32 bits, | ||
120 | u32 func_slct) | ||
121 | { | ||
122 | u32 config, new_config; | ||
123 | |||
124 | mutex_lock(&pc8736x_gpio_config_lock); | ||
125 | |||
126 | device_select(SIO_GPIO_UNIT); | ||
127 | select_pin(index); | ||
128 | |||
129 | /* read current config value */ | ||
130 | config = superio_inb(func_slct); | ||
131 | |||
132 | /* set new config */ | ||
133 | new_config = (config & mask) | bits; | ||
134 | superio_outb(func_slct, new_config); | ||
135 | |||
136 | mutex_unlock(&pc8736x_gpio_config_lock); | ||
137 | |||
138 | return config; | ||
139 | } | ||
140 | |||
141 | static u32 pc8736x_gpio_configure(unsigned index, u32 mask, u32 bits) | ||
142 | { | ||
143 | return pc8736x_gpio_configure_fn(index, mask, bits, | ||
144 | SIO_GPIO_PIN_CONFIG); | ||
145 | } | ||
146 | |||
147 | static int pc8736x_gpio_get(unsigned minor) | ||
148 | { | ||
149 | int port, bit, val; | ||
150 | |||
151 | port = minor >> 3; | ||
152 | bit = minor & 7; | ||
153 | val = inb_p(pc8736x_gpio_base + port_offset[port] + PORT_IN); | ||
154 | val >>= bit; | ||
155 | val &= 1; | ||
156 | |||
157 | dev_dbg(&pdev->dev, "_gpio_get(%d from %x bit %d) == val %d\n", | ||
158 | minor, pc8736x_gpio_base + port_offset[port] + PORT_IN, bit, | ||
159 | val); | ||
160 | |||
161 | return val; | ||
162 | } | ||
163 | |||
164 | static void pc8736x_gpio_set(unsigned minor, int val) | ||
165 | { | ||
166 | int port, bit, curval; | ||
167 | |||
168 | minor &= 0x1f; | ||
169 | port = minor >> 3; | ||
170 | bit = minor & 7; | ||
171 | curval = inb_p(pc8736x_gpio_base + port_offset[port] + PORT_OUT); | ||
172 | |||
173 | dev_dbg(&pdev->dev, "addr:%x cur:%x bit-pos:%d cur-bit:%x + new:%d -> bit-new:%d\n", | ||
174 | pc8736x_gpio_base + port_offset[port] + PORT_OUT, | ||
175 | curval, bit, (curval & ~(1 << bit)), val, (val << bit)); | ||
176 | |||
177 | val = (curval & ~(1 << bit)) | (val << bit); | ||
178 | |||
179 | dev_dbg(&pdev->dev, "gpio_set(minor:%d port:%d bit:%d)" | ||
180 | " %2x -> %2x\n", minor, port, bit, curval, val); | ||
181 | |||
182 | outb_p(val, pc8736x_gpio_base + port_offset[port] + PORT_OUT); | ||
183 | |||
184 | curval = inb_p(pc8736x_gpio_base + port_offset[port] + PORT_OUT); | ||
185 | val = inb_p(pc8736x_gpio_base + port_offset[port] + PORT_IN); | ||
186 | |||
187 | dev_dbg(&pdev->dev, "wrote %x, read: %x\n", curval, val); | ||
188 | pc8736x_gpio_shadow[port] = val; | ||
189 | } | ||
190 | |||
191 | static void pc8736x_gpio_set_high(unsigned index) | ||
192 | { | ||
193 | pc8736x_gpio_set(index, 1); | ||
194 | } | ||
195 | |||
196 | static void pc8736x_gpio_set_low(unsigned index) | ||
197 | { | ||
198 | pc8736x_gpio_set(index, 0); | ||
199 | } | ||
200 | |||
201 | static int pc8736x_gpio_current(unsigned minor) | ||
202 | { | ||
203 | int port, bit; | ||
204 | minor &= 0x1f; | ||
205 | port = minor >> 3; | ||
206 | bit = minor & 7; | ||
207 | return ((pc8736x_gpio_shadow[port] >> bit) & 0x01); | ||
208 | } | ||
209 | |||
210 | static void pc8736x_gpio_change(unsigned index) | ||
211 | { | ||
212 | pc8736x_gpio_set(index, !pc8736x_gpio_current(index)); | ||
213 | } | ||
214 | |||
215 | static struct nsc_gpio_ops pc8736x_access = { | ||
216 | .owner = THIS_MODULE, | ||
217 | .gpio_config = pc8736x_gpio_configure, | ||
218 | .gpio_dump = nsc_gpio_dump, | ||
219 | .gpio_get = pc8736x_gpio_get, | ||
220 | .gpio_set = pc8736x_gpio_set, | ||
221 | .gpio_set_high = pc8736x_gpio_set_high, | ||
222 | .gpio_set_low = pc8736x_gpio_set_low, | ||
223 | .gpio_change = pc8736x_gpio_change, | ||
224 | .gpio_current = pc8736x_gpio_current | ||
225 | }; | ||
226 | |||
227 | static int pc8736x_gpio_open(struct inode *inode, struct file *file) | ||
228 | { | ||
229 | unsigned m = iminor(inode); | ||
230 | file->private_data = &pc8736x_access; | ||
231 | |||
232 | dev_dbg(&pdev->dev, "open %d\n", m); | ||
233 | |||
234 | if (m > 63) | ||
235 | return -EINVAL; | ||
236 | return nonseekable_open(inode, file); | ||
237 | } | ||
238 | |||
239 | static struct file_operations pc8736x_gpio_fops = { | ||
240 | .owner = THIS_MODULE, | ||
241 | .open = pc8736x_gpio_open, | ||
242 | .write = nsc_gpio_write, | ||
243 | .read = nsc_gpio_read, | ||
244 | }; | ||
245 | |||
246 | static void __init pc8736x_init_shadow(void) | ||
247 | { | ||
248 | int port; | ||
249 | |||
250 | /* read the current values driven on the GPIO signals */ | ||
251 | for (port = 0; port < 4; ++port) | ||
252 | pc8736x_gpio_shadow[port] | ||
253 | = inb_p(pc8736x_gpio_base + port_offset[port] | ||
254 | + PORT_OUT); | ||
255 | |||
256 | } | ||
257 | |||
258 | static int __init pc8736x_gpio_init(void) | ||
259 | { | ||
260 | int rc = 0; | ||
261 | |||
262 | pdev = platform_device_alloc(DEVNAME, 0); | ||
263 | if (!pdev) | ||
264 | return -ENOMEM; | ||
265 | |||
266 | rc = platform_device_add(pdev); | ||
267 | if (rc) { | ||
268 | rc = -ENODEV; | ||
269 | goto undo_platform_dev_alloc; | ||
270 | } | ||
271 | dev_info(&pdev->dev, "NatSemi pc8736x GPIO Driver Initializing\n"); | ||
272 | |||
273 | if (!pc8736x_superio_present()) { | ||
274 | rc = -ENODEV; | ||
275 | dev_err(&pdev->dev, "no device found\n"); | ||
276 | goto undo_platform_dev_add; | ||
277 | } | ||
278 | pc8736x_access.dev = &pdev->dev; | ||
279 | |||
280 | /* Verify that chip and it's GPIO unit are both enabled. | ||
281 | My BIOS does this, so I take minimum action here | ||
282 | */ | ||
283 | rc = superio_inb(SIO_CF1); | ||
284 | if (!(rc & 0x01)) { | ||
285 | rc = -ENODEV; | ||
286 | dev_err(&pdev->dev, "device not enabled\n"); | ||
287 | goto undo_platform_dev_add; | ||
288 | } | ||
289 | device_select(SIO_GPIO_UNIT); | ||
290 | if (!superio_inb(SIO_UNIT_ACT)) { | ||
291 | rc = -ENODEV; | ||
292 | dev_err(&pdev->dev, "GPIO unit not enabled\n"); | ||
293 | goto undo_platform_dev_add; | ||
294 | } | ||
295 | |||
296 | /* read the GPIO unit base addr that chip responds to */ | ||
297 | pc8736x_gpio_base = (superio_inb(SIO_BASE_HADDR) << 8 | ||
298 | | superio_inb(SIO_BASE_LADDR)); | ||
299 | |||
300 | if (!request_region(pc8736x_gpio_base, 16, DEVNAME)) { | ||
301 | rc = -ENODEV; | ||
302 | dev_err(&pdev->dev, "GPIO ioport %x busy\n", | ||
303 | pc8736x_gpio_base); | ||
304 | goto undo_platform_dev_add; | ||
305 | } | ||
306 | dev_info(&pdev->dev, "GPIO ioport %x reserved\n", pc8736x_gpio_base); | ||
307 | |||
308 | rc = register_chrdev(major, DEVNAME, &pc8736x_gpio_fops); | ||
309 | if (rc < 0) { | ||
310 | dev_err(&pdev->dev, "register-chrdev failed: %d\n", rc); | ||
311 | goto undo_platform_dev_add; | ||
312 | } | ||
313 | if (!major) { | ||
314 | major = rc; | ||
315 | dev_dbg(&pdev->dev, "got dynamic major %d\n", major); | ||
316 | } | ||
317 | |||
318 | pc8736x_init_shadow(); | ||
319 | return 0; | ||
320 | |||
321 | undo_platform_dev_add: | ||
322 | platform_device_put(pdev); | ||
323 | undo_platform_dev_alloc: | ||
324 | kfree(pdev); | ||
325 | return rc; | ||
326 | } | ||
327 | |||
328 | static void __exit pc8736x_gpio_cleanup(void) | ||
329 | { | ||
330 | dev_dbg(&pdev->dev, " cleanup\n"); | ||
331 | |||
332 | release_region(pc8736x_gpio_base, 16); | ||
333 | |||
334 | unregister_chrdev(major, DEVNAME); | ||
335 | } | ||
336 | |||
337 | EXPORT_SYMBOL(pc8736x_access); | ||
338 | |||
339 | module_init(pc8736x_gpio_init); | ||
340 | module_exit(pc8736x_gpio_cleanup); | ||
diff --git a/drivers/char/rio/riointr.c b/drivers/char/rio/riointr.c index eec1fea0cb92..0bd09040a5c0 100644 --- a/drivers/char/rio/riointr.c +++ b/drivers/char/rio/riointr.c | |||
@@ -546,7 +546,7 @@ static void RIOReceive(struct rio_info *p, struct Port *PortP) | |||
546 | ** run out of space it will be set to the offset of the | 546 | ** run out of space it will be set to the offset of the |
547 | ** next byte to copy from the packet data area. The packet | 547 | ** next byte to copy from the packet data area. The packet |
548 | ** length field is decremented by the number of bytes that | 548 | ** length field is decremented by the number of bytes that |
549 | ** we succesfully removed from the packet. When this reaches | 549 | ** we successfully removed from the packet. When this reaches |
550 | ** zero, we reset the offset pointer to be zero, and free | 550 | ** zero, we reset the offset pointer to be zero, and free |
551 | ** the packet from the front of the queue. | 551 | ** the packet from the front of the queue. |
552 | */ | 552 | */ |
diff --git a/drivers/char/scx200_gpio.c b/drivers/char/scx200_gpio.c index 664a6e97eb1a..5a280a330401 100644 --- a/drivers/char/scx200_gpio.c +++ b/drivers/char/scx200_gpio.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* linux/drivers/char/scx200_gpio.c | 1 | /* linux/drivers/char/scx200_gpio.c |
2 | 2 | ||
3 | National Semiconductor SCx200 GPIO driver. Allows a user space | 3 | National Semiconductor SCx200 GPIO driver. Allows a user space |
4 | process to play with the GPIO pins. | 4 | process to play with the GPIO pins. |
@@ -6,17 +6,26 @@ | |||
6 | Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com> */ | 6 | Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com> */ |
7 | 7 | ||
8 | #include <linux/config.h> | 8 | #include <linux/config.h> |
9 | #include <linux/device.h> | ||
9 | #include <linux/fs.h> | 10 | #include <linux/fs.h> |
10 | #include <linux/module.h> | 11 | #include <linux/module.h> |
11 | #include <linux/errno.h> | 12 | #include <linux/errno.h> |
12 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
13 | #include <linux/init.h> | 14 | #include <linux/init.h> |
15 | #include <linux/platform_device.h> | ||
14 | #include <asm/uaccess.h> | 16 | #include <asm/uaccess.h> |
15 | #include <asm/io.h> | 17 | #include <asm/io.h> |
16 | 18 | ||
19 | #include <linux/types.h> | ||
20 | #include <linux/cdev.h> | ||
21 | |||
17 | #include <linux/scx200_gpio.h> | 22 | #include <linux/scx200_gpio.h> |
23 | #include <linux/nsc_gpio.h> | ||
18 | 24 | ||
19 | #define NAME "scx200_gpio" | 25 | #define NAME "scx200_gpio" |
26 | #define DEVNAME NAME | ||
27 | |||
28 | static struct platform_device *pdev; | ||
20 | 29 | ||
21 | MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>"); | 30 | MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>"); |
22 | MODULE_DESCRIPTION("NatSemi SCx200 GPIO Pin Driver"); | 31 | MODULE_DESCRIPTION("NatSemi SCx200 GPIO Pin Driver"); |
@@ -26,70 +35,23 @@ static int major = 0; /* default to dynamic major */ | |||
26 | module_param(major, int, 0); | 35 | module_param(major, int, 0); |
27 | MODULE_PARM_DESC(major, "Major device number"); | 36 | MODULE_PARM_DESC(major, "Major device number"); |
28 | 37 | ||
29 | static ssize_t scx200_gpio_write(struct file *file, const char __user *data, | 38 | struct nsc_gpio_ops scx200_access = { |
30 | size_t len, loff_t *ppos) | 39 | .owner = THIS_MODULE, |
31 | { | 40 | .gpio_config = scx200_gpio_configure, |
32 | unsigned m = iminor(file->f_dentry->d_inode); | 41 | .gpio_dump = nsc_gpio_dump, |
33 | size_t i; | 42 | .gpio_get = scx200_gpio_get, |
34 | 43 | .gpio_set = scx200_gpio_set, | |
35 | for (i = 0; i < len; ++i) { | 44 | .gpio_set_high = scx200_gpio_set_high, |
36 | char c; | 45 | .gpio_set_low = scx200_gpio_set_low, |
37 | if (get_user(c, data+i)) | 46 | .gpio_change = scx200_gpio_change, |
38 | return -EFAULT; | 47 | .gpio_current = scx200_gpio_current |
39 | switch (c) | 48 | }; |
40 | { | ||
41 | case '0': | ||
42 | scx200_gpio_set(m, 0); | ||
43 | break; | ||
44 | case '1': | ||
45 | scx200_gpio_set(m, 1); | ||
46 | break; | ||
47 | case 'O': | ||
48 | printk(KERN_INFO NAME ": GPIO%d output enabled\n", m); | ||
49 | scx200_gpio_configure(m, ~1, 1); | ||
50 | break; | ||
51 | case 'o': | ||
52 | printk(KERN_INFO NAME ": GPIO%d output disabled\n", m); | ||
53 | scx200_gpio_configure(m, ~1, 0); | ||
54 | break; | ||
55 | case 'T': | ||
56 | printk(KERN_INFO NAME ": GPIO%d output is push pull\n", m); | ||
57 | scx200_gpio_configure(m, ~2, 2); | ||
58 | break; | ||
59 | case 't': | ||
60 | printk(KERN_INFO NAME ": GPIO%d output is open drain\n", m); | ||
61 | scx200_gpio_configure(m, ~2, 0); | ||
62 | break; | ||
63 | case 'P': | ||
64 | printk(KERN_INFO NAME ": GPIO%d pull up enabled\n", m); | ||
65 | scx200_gpio_configure(m, ~4, 4); | ||
66 | break; | ||
67 | case 'p': | ||
68 | printk(KERN_INFO NAME ": GPIO%d pull up disabled\n", m); | ||
69 | scx200_gpio_configure(m, ~4, 0); | ||
70 | break; | ||
71 | } | ||
72 | } | ||
73 | |||
74 | return len; | ||
75 | } | ||
76 | |||
77 | static ssize_t scx200_gpio_read(struct file *file, char __user *buf, | ||
78 | size_t len, loff_t *ppos) | ||
79 | { | ||
80 | unsigned m = iminor(file->f_dentry->d_inode); | ||
81 | int value; | ||
82 | |||
83 | value = scx200_gpio_get(m); | ||
84 | if (put_user(value ? '1' : '0', buf)) | ||
85 | return -EFAULT; | ||
86 | |||
87 | return 1; | ||
88 | } | ||
89 | 49 | ||
90 | static int scx200_gpio_open(struct inode *inode, struct file *file) | 50 | static int scx200_gpio_open(struct inode *inode, struct file *file) |
91 | { | 51 | { |
92 | unsigned m = iminor(inode); | 52 | unsigned m = iminor(inode); |
53 | file->private_data = &scx200_access; | ||
54 | |||
93 | if (m > 63) | 55 | if (m > 63) |
94 | return -EINVAL; | 56 | return -EINVAL; |
95 | return nonseekable_open(inode, file); | 57 | return nonseekable_open(inode, file); |
@@ -103,47 +65,81 @@ static int scx200_gpio_release(struct inode *inode, struct file *file) | |||
103 | 65 | ||
104 | static struct file_operations scx200_gpio_fops = { | 66 | static struct file_operations scx200_gpio_fops = { |
105 | .owner = THIS_MODULE, | 67 | .owner = THIS_MODULE, |
106 | .write = scx200_gpio_write, | 68 | .write = nsc_gpio_write, |
107 | .read = scx200_gpio_read, | 69 | .read = nsc_gpio_read, |
108 | .open = scx200_gpio_open, | 70 | .open = scx200_gpio_open, |
109 | .release = scx200_gpio_release, | 71 | .release = scx200_gpio_release, |
110 | }; | 72 | }; |
111 | 73 | ||
74 | struct cdev *scx200_devices; | ||
75 | static int num_pins = 32; | ||
76 | |||
112 | static int __init scx200_gpio_init(void) | 77 | static int __init scx200_gpio_init(void) |
113 | { | 78 | { |
114 | int r; | 79 | int rc, i; |
115 | 80 | dev_t dev = MKDEV(major, 0); | |
116 | printk(KERN_DEBUG NAME ": NatSemi SCx200 GPIO Driver\n"); | ||
117 | 81 | ||
118 | if (!scx200_gpio_present()) { | 82 | if (!scx200_gpio_present()) { |
119 | printk(KERN_ERR NAME ": no SCx200 gpio pins available\n"); | 83 | printk(KERN_ERR NAME ": no SCx200 gpio present\n"); |
120 | return -ENODEV; | 84 | return -ENODEV; |
121 | } | 85 | } |
122 | 86 | ||
123 | r = register_chrdev(major, NAME, &scx200_gpio_fops); | 87 | /* support dev_dbg() with pdev->dev */ |
124 | if (r < 0) { | 88 | pdev = platform_device_alloc(DEVNAME, 0); |
125 | printk(KERN_ERR NAME ": unable to register character device\n"); | 89 | if (!pdev) |
126 | return r; | 90 | return -ENOMEM; |
91 | |||
92 | rc = platform_device_add(pdev); | ||
93 | if (rc) | ||
94 | goto undo_malloc; | ||
95 | |||
96 | /* nsc_gpio uses dev_dbg(), so needs this */ | ||
97 | scx200_access.dev = &pdev->dev; | ||
98 | |||
99 | if (major) | ||
100 | rc = register_chrdev_region(dev, num_pins, "scx200_gpio"); | ||
101 | else { | ||
102 | rc = alloc_chrdev_region(&dev, 0, num_pins, "scx200_gpio"); | ||
103 | major = MAJOR(dev); | ||
127 | } | 104 | } |
128 | if (!major) { | 105 | if (rc < 0) { |
129 | major = r; | 106 | dev_err(&pdev->dev, "SCx200 chrdev_region err: %d\n", rc); |
130 | printk(KERN_DEBUG NAME ": got dynamic major %d\n", major); | 107 | goto undo_platform_device_add; |
108 | } | ||
109 | scx200_devices = kzalloc(num_pins * sizeof(struct cdev), GFP_KERNEL); | ||
110 | if (!scx200_devices) { | ||
111 | rc = -ENOMEM; | ||
112 | goto undo_chrdev_region; | ||
113 | } | ||
114 | for (i = 0; i < num_pins; i++) { | ||
115 | struct cdev *cdev = &scx200_devices[i]; | ||
116 | cdev_init(cdev, &scx200_gpio_fops); | ||
117 | cdev->owner = THIS_MODULE; | ||
118 | rc = cdev_add(cdev, MKDEV(major, i), 1); | ||
119 | /* tolerate 'minor' errors */ | ||
120 | if (rc) | ||
121 | dev_err(&pdev->dev, "Error %d on minor %d", rc, i); | ||
131 | } | 122 | } |
132 | 123 | ||
133 | return 0; | 124 | return 0; /* succeed */ |
125 | |||
126 | undo_chrdev_region: | ||
127 | unregister_chrdev_region(dev, num_pins); | ||
128 | undo_platform_device_add: | ||
129 | platform_device_put(pdev); | ||
130 | undo_malloc: | ||
131 | kfree(pdev); | ||
132 | return rc; | ||
134 | } | 133 | } |
135 | 134 | ||
136 | static void __exit scx200_gpio_cleanup(void) | 135 | static void __exit scx200_gpio_cleanup(void) |
137 | { | 136 | { |
138 | unregister_chrdev(major, NAME); | 137 | kfree(scx200_devices); |
138 | unregister_chrdev_region(MKDEV(major, 0), num_pins); | ||
139 | platform_device_put(pdev); | ||
140 | platform_device_unregister(pdev); | ||
141 | /* kfree(pdev); */ | ||
139 | } | 142 | } |
140 | 143 | ||
141 | module_init(scx200_gpio_init); | 144 | module_init(scx200_gpio_init); |
142 | module_exit(scx200_gpio_cleanup); | 145 | module_exit(scx200_gpio_cleanup); |
143 | |||
144 | /* | ||
145 | Local variables: | ||
146 | compile-command: "make -k -C ../.. SUBDIRS=drivers/char modules" | ||
147 | c-basic-offset: 8 | ||
148 | End: | ||
149 | */ | ||
diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c index 1b5330299e30..d2d6b01dcd05 100644 --- a/drivers/char/specialix.c +++ b/drivers/char/specialix.c | |||
@@ -2477,7 +2477,7 @@ static int __init specialix_init(void) | |||
2477 | #endif | 2477 | #endif |
2478 | 2478 | ||
2479 | for (i = 0; i < SX_NBOARD; i++) | 2479 | for (i = 0; i < SX_NBOARD; i++) |
2480 | sx_board[i].lock = SPIN_LOCK_UNLOCKED; | 2480 | spin_lock_init(&sx_board[i].lock); |
2481 | 2481 | ||
2482 | if (sx_init_drivers()) { | 2482 | if (sx_init_drivers()) { |
2483 | func_exit(); | 2483 | func_exit(); |
diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c index a9c5a7230f89..bf361a5ba70d 100644 --- a/drivers/char/stallion.c +++ b/drivers/char/stallion.c | |||
@@ -141,15 +141,6 @@ static char *stl_drvversion = "5.6.0"; | |||
141 | static struct tty_driver *stl_serial; | 141 | static struct tty_driver *stl_serial; |
142 | 142 | ||
143 | /* | 143 | /* |
144 | * We will need to allocate a temporary write buffer for chars that | ||
145 | * come direct from user space. The problem is that a copy from user | ||
146 | * space might cause a page fault (typically on a system that is | ||
147 | * swapping!). All ports will share one buffer - since if the system | ||
148 | * is already swapping a shared buffer won't make things any worse. | ||
149 | */ | ||
150 | static char *stl_tmpwritebuf; | ||
151 | |||
152 | /* | ||
153 | * Define a local default termios struct. All ports will be created | 144 | * Define a local default termios struct. All ports will be created |
154 | * with this termios initially. Basically all it defines is a raw port | 145 | * with this termios initially. Basically all it defines is a raw port |
155 | * at 9600, 8 data bits, 1 stop bit. | 146 | * at 9600, 8 data bits, 1 stop bit. |
@@ -363,6 +354,14 @@ static unsigned char stl_vecmap[] = { | |||
363 | }; | 354 | }; |
364 | 355 | ||
365 | /* | 356 | /* |
357 | * Lock ordering is that you may not take stallion_lock holding | ||
358 | * brd_lock. | ||
359 | */ | ||
360 | |||
361 | static spinlock_t brd_lock; /* Guard the board mapping */ | ||
362 | static spinlock_t stallion_lock; /* Guard the tty driver */ | ||
363 | |||
364 | /* | ||
366 | * Set up enable and disable macros for the ECH boards. They require | 365 | * Set up enable and disable macros for the ECH boards. They require |
367 | * the secondary io address space to be activated and deactivated. | 366 | * the secondary io address space to be activated and deactivated. |
368 | * This way all ECH boards can share their secondary io region. | 367 | * This way all ECH boards can share their secondary io region. |
@@ -725,17 +724,7 @@ static struct class *stallion_class; | |||
725 | 724 | ||
726 | static int __init stallion_module_init(void) | 725 | static int __init stallion_module_init(void) |
727 | { | 726 | { |
728 | unsigned long flags; | ||
729 | |||
730 | #ifdef DEBUG | ||
731 | printk("init_module()\n"); | ||
732 | #endif | ||
733 | |||
734 | save_flags(flags); | ||
735 | cli(); | ||
736 | stl_init(); | 727 | stl_init(); |
737 | restore_flags(flags); | ||
738 | |||
739 | return 0; | 728 | return 0; |
740 | } | 729 | } |
741 | 730 | ||
@@ -746,7 +735,6 @@ static void __exit stallion_module_exit(void) | |||
746 | stlbrd_t *brdp; | 735 | stlbrd_t *brdp; |
747 | stlpanel_t *panelp; | 736 | stlpanel_t *panelp; |
748 | stlport_t *portp; | 737 | stlport_t *portp; |
749 | unsigned long flags; | ||
750 | int i, j, k; | 738 | int i, j, k; |
751 | 739 | ||
752 | #ifdef DEBUG | 740 | #ifdef DEBUG |
@@ -756,9 +744,6 @@ static void __exit stallion_module_exit(void) | |||
756 | printk(KERN_INFO "Unloading %s: version %s\n", stl_drvtitle, | 744 | printk(KERN_INFO "Unloading %s: version %s\n", stl_drvtitle, |
757 | stl_drvversion); | 745 | stl_drvversion); |
758 | 746 | ||
759 | save_flags(flags); | ||
760 | cli(); | ||
761 | |||
762 | /* | 747 | /* |
763 | * Free up all allocated resources used by the ports. This includes | 748 | * Free up all allocated resources used by the ports. This includes |
764 | * memory and interrupts. As part of this process we will also do | 749 | * memory and interrupts. As part of this process we will also do |
@@ -770,7 +755,6 @@ static void __exit stallion_module_exit(void) | |||
770 | if (i) { | 755 | if (i) { |
771 | printk("STALLION: failed to un-register tty driver, " | 756 | printk("STALLION: failed to un-register tty driver, " |
772 | "errno=%d\n", -i); | 757 | "errno=%d\n", -i); |
773 | restore_flags(flags); | ||
774 | return; | 758 | return; |
775 | } | 759 | } |
776 | for (i = 0; i < 4; i++) { | 760 | for (i = 0; i < 4; i++) { |
@@ -783,8 +767,6 @@ static void __exit stallion_module_exit(void) | |||
783 | "errno=%d\n", -i); | 767 | "errno=%d\n", -i); |
784 | class_destroy(stallion_class); | 768 | class_destroy(stallion_class); |
785 | 769 | ||
786 | kfree(stl_tmpwritebuf); | ||
787 | |||
788 | for (i = 0; (i < stl_nrbrds); i++) { | 770 | for (i = 0; (i < stl_nrbrds); i++) { |
789 | if ((brdp = stl_brds[i]) == (stlbrd_t *) NULL) | 771 | if ((brdp = stl_brds[i]) == (stlbrd_t *) NULL) |
790 | continue; | 772 | continue; |
@@ -814,8 +796,6 @@ static void __exit stallion_module_exit(void) | |||
814 | kfree(brdp); | 796 | kfree(brdp); |
815 | stl_brds[i] = (stlbrd_t *) NULL; | 797 | stl_brds[i] = (stlbrd_t *) NULL; |
816 | } | 798 | } |
817 | |||
818 | restore_flags(flags); | ||
819 | } | 799 | } |
820 | 800 | ||
821 | module_init(stallion_module_init); | 801 | module_init(stallion_module_init); |
@@ -948,7 +928,7 @@ static stlbrd_t *stl_allocbrd(void) | |||
948 | 928 | ||
949 | brdp = kzalloc(sizeof(stlbrd_t), GFP_KERNEL); | 929 | brdp = kzalloc(sizeof(stlbrd_t), GFP_KERNEL); |
950 | if (!brdp) { | 930 | if (!brdp) { |
951 | printk("STALLION: failed to allocate memory (size=%d)\n", | 931 | printk("STALLION: failed to allocate memory (size=%Zd)\n", |
952 | sizeof(stlbrd_t)); | 932 | sizeof(stlbrd_t)); |
953 | return NULL; | 933 | return NULL; |
954 | } | 934 | } |
@@ -1066,16 +1046,17 @@ static int stl_waitcarrier(stlport_t *portp, struct file *filp) | |||
1066 | rc = 0; | 1046 | rc = 0; |
1067 | doclocal = 0; | 1047 | doclocal = 0; |
1068 | 1048 | ||
1049 | spin_lock_irqsave(&stallion_lock, flags); | ||
1050 | |||
1069 | if (portp->tty->termios->c_cflag & CLOCAL) | 1051 | if (portp->tty->termios->c_cflag & CLOCAL) |
1070 | doclocal++; | 1052 | doclocal++; |
1071 | 1053 | ||
1072 | save_flags(flags); | ||
1073 | cli(); | ||
1074 | portp->openwaitcnt++; | 1054 | portp->openwaitcnt++; |
1075 | if (! tty_hung_up_p(filp)) | 1055 | if (! tty_hung_up_p(filp)) |
1076 | portp->refcount--; | 1056 | portp->refcount--; |
1077 | 1057 | ||
1078 | for (;;) { | 1058 | for (;;) { |
1059 | /* Takes brd_lock internally */ | ||
1079 | stl_setsignals(portp, 1, 1); | 1060 | stl_setsignals(portp, 1, 1); |
1080 | if (tty_hung_up_p(filp) || | 1061 | if (tty_hung_up_p(filp) || |
1081 | ((portp->flags & ASYNC_INITIALIZED) == 0)) { | 1062 | ((portp->flags & ASYNC_INITIALIZED) == 0)) { |
@@ -1093,13 +1074,14 @@ static int stl_waitcarrier(stlport_t *portp, struct file *filp) | |||
1093 | rc = -ERESTARTSYS; | 1074 | rc = -ERESTARTSYS; |
1094 | break; | 1075 | break; |
1095 | } | 1076 | } |
1077 | /* FIXME */ | ||
1096 | interruptible_sleep_on(&portp->open_wait); | 1078 | interruptible_sleep_on(&portp->open_wait); |
1097 | } | 1079 | } |
1098 | 1080 | ||
1099 | if (! tty_hung_up_p(filp)) | 1081 | if (! tty_hung_up_p(filp)) |
1100 | portp->refcount++; | 1082 | portp->refcount++; |
1101 | portp->openwaitcnt--; | 1083 | portp->openwaitcnt--; |
1102 | restore_flags(flags); | 1084 | spin_unlock_irqrestore(&stallion_lock, flags); |
1103 | 1085 | ||
1104 | return rc; | 1086 | return rc; |
1105 | } | 1087 | } |
@@ -1119,16 +1101,15 @@ static void stl_close(struct tty_struct *tty, struct file *filp) | |||
1119 | if (portp == (stlport_t *) NULL) | 1101 | if (portp == (stlport_t *) NULL) |
1120 | return; | 1102 | return; |
1121 | 1103 | ||
1122 | save_flags(flags); | 1104 | spin_lock_irqsave(&stallion_lock, flags); |
1123 | cli(); | ||
1124 | if (tty_hung_up_p(filp)) { | 1105 | if (tty_hung_up_p(filp)) { |
1125 | restore_flags(flags); | 1106 | spin_unlock_irqrestore(&stallion_lock, flags); |
1126 | return; | 1107 | return; |
1127 | } | 1108 | } |
1128 | if ((tty->count == 1) && (portp->refcount != 1)) | 1109 | if ((tty->count == 1) && (portp->refcount != 1)) |
1129 | portp->refcount = 1; | 1110 | portp->refcount = 1; |
1130 | if (portp->refcount-- > 1) { | 1111 | if (portp->refcount-- > 1) { |
1131 | restore_flags(flags); | 1112 | spin_unlock_irqrestore(&stallion_lock, flags); |
1132 | return; | 1113 | return; |
1133 | } | 1114 | } |
1134 | 1115 | ||
@@ -1142,11 +1123,18 @@ static void stl_close(struct tty_struct *tty, struct file *filp) | |||
1142 | * (The sc26198 has no "end-of-data" interrupt only empty FIFO) | 1123 | * (The sc26198 has no "end-of-data" interrupt only empty FIFO) |
1143 | */ | 1124 | */ |
1144 | tty->closing = 1; | 1125 | tty->closing = 1; |
1126 | |||
1127 | spin_unlock_irqrestore(&stallion_lock, flags); | ||
1128 | |||
1145 | if (portp->closing_wait != ASYNC_CLOSING_WAIT_NONE) | 1129 | if (portp->closing_wait != ASYNC_CLOSING_WAIT_NONE) |
1146 | tty_wait_until_sent(tty, portp->closing_wait); | 1130 | tty_wait_until_sent(tty, portp->closing_wait); |
1147 | stl_waituntilsent(tty, (HZ / 2)); | 1131 | stl_waituntilsent(tty, (HZ / 2)); |
1148 | 1132 | ||
1133 | |||
1134 | spin_lock_irqsave(&stallion_lock, flags); | ||
1149 | portp->flags &= ~ASYNC_INITIALIZED; | 1135 | portp->flags &= ~ASYNC_INITIALIZED; |
1136 | spin_unlock_irqrestore(&stallion_lock, flags); | ||
1137 | |||
1150 | stl_disableintrs(portp); | 1138 | stl_disableintrs(portp); |
1151 | if (tty->termios->c_cflag & HUPCL) | 1139 | if (tty->termios->c_cflag & HUPCL) |
1152 | stl_setsignals(portp, 0, 0); | 1140 | stl_setsignals(portp, 0, 0); |
@@ -1173,7 +1161,6 @@ static void stl_close(struct tty_struct *tty, struct file *filp) | |||
1173 | 1161 | ||
1174 | portp->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); | 1162 | portp->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); |
1175 | wake_up_interruptible(&portp->close_wait); | 1163 | wake_up_interruptible(&portp->close_wait); |
1176 | restore_flags(flags); | ||
1177 | } | 1164 | } |
1178 | 1165 | ||
1179 | /*****************************************************************************/ | 1166 | /*****************************************************************************/ |
@@ -1195,9 +1182,6 @@ static int stl_write(struct tty_struct *tty, const unsigned char *buf, int count | |||
1195 | (int) tty, (int) buf, count); | 1182 | (int) tty, (int) buf, count); |
1196 | #endif | 1183 | #endif |
1197 | 1184 | ||
1198 | if ((tty == (struct tty_struct *) NULL) || | ||
1199 | (stl_tmpwritebuf == (char *) NULL)) | ||
1200 | return 0; | ||
1201 | portp = tty->driver_data; | 1185 | portp = tty->driver_data; |
1202 | if (portp == (stlport_t *) NULL) | 1186 | if (portp == (stlport_t *) NULL) |
1203 | return 0; | 1187 | return 0; |
@@ -1302,11 +1286,6 @@ static void stl_flushchars(struct tty_struct *tty) | |||
1302 | if (portp->tx.buf == (char *) NULL) | 1286 | if (portp->tx.buf == (char *) NULL) |
1303 | return; | 1287 | return; |
1304 | 1288 | ||
1305 | #if 0 | ||
1306 | if (tty->stopped || tty->hw_stopped || | ||
1307 | (portp->tx.head == portp->tx.tail)) | ||
1308 | return; | ||
1309 | #endif | ||
1310 | stl_startrxtx(portp, -1, 1); | 1289 | stl_startrxtx(portp, -1, 1); |
1311 | } | 1290 | } |
1312 | 1291 | ||
@@ -1977,12 +1956,14 @@ static int stl_eiointr(stlbrd_t *brdp) | |||
1977 | unsigned int iobase; | 1956 | unsigned int iobase; |
1978 | int handled = 0; | 1957 | int handled = 0; |
1979 | 1958 | ||
1959 | spin_lock(&brd_lock); | ||
1980 | panelp = brdp->panels[0]; | 1960 | panelp = brdp->panels[0]; |
1981 | iobase = panelp->iobase; | 1961 | iobase = panelp->iobase; |
1982 | while (inb(brdp->iostatus) & EIO_INTRPEND) { | 1962 | while (inb(brdp->iostatus) & EIO_INTRPEND) { |
1983 | handled = 1; | 1963 | handled = 1; |
1984 | (* panelp->isr)(panelp, iobase); | 1964 | (* panelp->isr)(panelp, iobase); |
1985 | } | 1965 | } |
1966 | spin_unlock(&brd_lock); | ||
1986 | return handled; | 1967 | return handled; |
1987 | } | 1968 | } |
1988 | 1969 | ||
@@ -2168,7 +2149,7 @@ static int __init stl_initports(stlbrd_t *brdp, stlpanel_t *panelp) | |||
2168 | portp = kzalloc(sizeof(stlport_t), GFP_KERNEL); | 2149 | portp = kzalloc(sizeof(stlport_t), GFP_KERNEL); |
2169 | if (!portp) { | 2150 | if (!portp) { |
2170 | printk("STALLION: failed to allocate memory " | 2151 | printk("STALLION: failed to allocate memory " |
2171 | "(size=%d)\n", sizeof(stlport_t)); | 2152 | "(size=%Zd)\n", sizeof(stlport_t)); |
2172 | break; | 2153 | break; |
2173 | } | 2154 | } |
2174 | 2155 | ||
@@ -2304,7 +2285,7 @@ static inline int stl_initeio(stlbrd_t *brdp) | |||
2304 | panelp = kzalloc(sizeof(stlpanel_t), GFP_KERNEL); | 2285 | panelp = kzalloc(sizeof(stlpanel_t), GFP_KERNEL); |
2305 | if (!panelp) { | 2286 | if (!panelp) { |
2306 | printk(KERN_WARNING "STALLION: failed to allocate memory " | 2287 | printk(KERN_WARNING "STALLION: failed to allocate memory " |
2307 | "(size=%d)\n", sizeof(stlpanel_t)); | 2288 | "(size=%Zd)\n", sizeof(stlpanel_t)); |
2308 | return -ENOMEM; | 2289 | return -ENOMEM; |
2309 | } | 2290 | } |
2310 | 2291 | ||
@@ -2478,7 +2459,7 @@ static inline int stl_initech(stlbrd_t *brdp) | |||
2478 | panelp = kzalloc(sizeof(stlpanel_t), GFP_KERNEL); | 2459 | panelp = kzalloc(sizeof(stlpanel_t), GFP_KERNEL); |
2479 | if (!panelp) { | 2460 | if (!panelp) { |
2480 | printk("STALLION: failed to allocate memory " | 2461 | printk("STALLION: failed to allocate memory " |
2481 | "(size=%d)\n", sizeof(stlpanel_t)); | 2462 | "(size=%Zd)\n", sizeof(stlpanel_t)); |
2482 | break; | 2463 | break; |
2483 | } | 2464 | } |
2484 | panelp->magic = STL_PANELMAGIC; | 2465 | panelp->magic = STL_PANELMAGIC; |
@@ -2879,8 +2860,7 @@ static int stl_getportstats(stlport_t *portp, comstats_t __user *cp) | |||
2879 | portp->stats.lflags = 0; | 2860 | portp->stats.lflags = 0; |
2880 | portp->stats.rxbuffered = 0; | 2861 | portp->stats.rxbuffered = 0; |
2881 | 2862 | ||
2882 | save_flags(flags); | 2863 | spin_lock_irqsave(&stallion_lock, flags); |
2883 | cli(); | ||
2884 | if (portp->tty != (struct tty_struct *) NULL) { | 2864 | if (portp->tty != (struct tty_struct *) NULL) { |
2885 | if (portp->tty->driver_data == portp) { | 2865 | if (portp->tty->driver_data == portp) { |
2886 | portp->stats.ttystate = portp->tty->flags; | 2866 | portp->stats.ttystate = portp->tty->flags; |
@@ -2894,7 +2874,7 @@ static int stl_getportstats(stlport_t *portp, comstats_t __user *cp) | |||
2894 | } | 2874 | } |
2895 | } | 2875 | } |
2896 | } | 2876 | } |
2897 | restore_flags(flags); | 2877 | spin_unlock_irqrestore(&stallion_lock, flags); |
2898 | 2878 | ||
2899 | head = portp->tx.head; | 2879 | head = portp->tx.head; |
2900 | tail = portp->tx.tail; | 2880 | tail = portp->tx.tail; |
@@ -3056,14 +3036,6 @@ static int __init stl_init(void) | |||
3056 | return -1; | 3036 | return -1; |
3057 | 3037 | ||
3058 | /* | 3038 | /* |
3059 | * Allocate a temporary write buffer. | ||
3060 | */ | ||
3061 | stl_tmpwritebuf = kmalloc(STL_TXBUFSIZE, GFP_KERNEL); | ||
3062 | if (!stl_tmpwritebuf) | ||
3063 | printk("STALLION: failed to allocate memory (size=%d)\n", | ||
3064 | STL_TXBUFSIZE); | ||
3065 | |||
3066 | /* | ||
3067 | * Set up a character driver for per board stuff. This is mainly used | 3039 | * Set up a character driver for per board stuff. This is mainly used |
3068 | * to do stats ioctls on the ports. | 3040 | * to do stats ioctls on the ports. |
3069 | */ | 3041 | */ |
@@ -3147,11 +3119,13 @@ static int stl_cd1400panelinit(stlbrd_t *brdp, stlpanel_t *panelp) | |||
3147 | unsigned int gfrcr; | 3119 | unsigned int gfrcr; |
3148 | int chipmask, i, j; | 3120 | int chipmask, i, j; |
3149 | int nrchips, uartaddr, ioaddr; | 3121 | int nrchips, uartaddr, ioaddr; |
3122 | unsigned long flags; | ||
3150 | 3123 | ||
3151 | #ifdef DEBUG | 3124 | #ifdef DEBUG |
3152 | printk("stl_panelinit(brdp=%x,panelp=%x)\n", (int) brdp, (int) panelp); | 3125 | printk("stl_panelinit(brdp=%x,panelp=%x)\n", (int) brdp, (int) panelp); |
3153 | #endif | 3126 | #endif |
3154 | 3127 | ||
3128 | spin_lock_irqsave(&brd_lock, flags); | ||
3155 | BRDENABLE(panelp->brdnr, panelp->pagenr); | 3129 | BRDENABLE(panelp->brdnr, panelp->pagenr); |
3156 | 3130 | ||
3157 | /* | 3131 | /* |
@@ -3189,6 +3163,7 @@ static int stl_cd1400panelinit(stlbrd_t *brdp, stlpanel_t *panelp) | |||
3189 | } | 3163 | } |
3190 | 3164 | ||
3191 | BRDDISABLE(panelp->brdnr); | 3165 | BRDDISABLE(panelp->brdnr); |
3166 | spin_unlock_irqrestore(&brd_lock, flags); | ||
3192 | return chipmask; | 3167 | return chipmask; |
3193 | } | 3168 | } |
3194 | 3169 | ||
@@ -3200,6 +3175,7 @@ static int stl_cd1400panelinit(stlbrd_t *brdp, stlpanel_t *panelp) | |||
3200 | 3175 | ||
3201 | static void stl_cd1400portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp) | 3176 | static void stl_cd1400portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp) |
3202 | { | 3177 | { |
3178 | unsigned long flags; | ||
3203 | #ifdef DEBUG | 3179 | #ifdef DEBUG |
3204 | printk("stl_cd1400portinit(brdp=%x,panelp=%x,portp=%x)\n", | 3180 | printk("stl_cd1400portinit(brdp=%x,panelp=%x,portp=%x)\n", |
3205 | (int) brdp, (int) panelp, (int) portp); | 3181 | (int) brdp, (int) panelp, (int) portp); |
@@ -3209,6 +3185,7 @@ static void stl_cd1400portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *po | |||
3209 | (portp == (stlport_t *) NULL)) | 3185 | (portp == (stlport_t *) NULL)) |
3210 | return; | 3186 | return; |
3211 | 3187 | ||
3188 | spin_lock_irqsave(&brd_lock, flags); | ||
3212 | portp->ioaddr = panelp->iobase + (((brdp->brdtype == BRD_ECHPCI) || | 3189 | portp->ioaddr = panelp->iobase + (((brdp->brdtype == BRD_ECHPCI) || |
3213 | (portp->portnr < 8)) ? 0 : EREG_BANKSIZE); | 3190 | (portp->portnr < 8)) ? 0 : EREG_BANKSIZE); |
3214 | portp->uartaddr = (portp->portnr & 0x04) << 5; | 3191 | portp->uartaddr = (portp->portnr & 0x04) << 5; |
@@ -3219,6 +3196,7 @@ static void stl_cd1400portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *po | |||
3219 | stl_cd1400setreg(portp, LIVR, (portp->portnr << 3)); | 3196 | stl_cd1400setreg(portp, LIVR, (portp->portnr << 3)); |
3220 | portp->hwid = stl_cd1400getreg(portp, GFRCR); | 3197 | portp->hwid = stl_cd1400getreg(portp, GFRCR); |
3221 | BRDDISABLE(portp->brdnr); | 3198 | BRDDISABLE(portp->brdnr); |
3199 | spin_unlock_irqrestore(&brd_lock, flags); | ||
3222 | } | 3200 | } |
3223 | 3201 | ||
3224 | /*****************************************************************************/ | 3202 | /*****************************************************************************/ |
@@ -3428,8 +3406,7 @@ static void stl_cd1400setport(stlport_t *portp, struct termios *tiosp) | |||
3428 | tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP]); | 3406 | tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP]); |
3429 | #endif | 3407 | #endif |
3430 | 3408 | ||
3431 | save_flags(flags); | 3409 | spin_lock_irqsave(&brd_lock, flags); |
3432 | cli(); | ||
3433 | BRDENABLE(portp->brdnr, portp->pagenr); | 3410 | BRDENABLE(portp->brdnr, portp->pagenr); |
3434 | stl_cd1400setreg(portp, CAR, (portp->portnr & 0x3)); | 3411 | stl_cd1400setreg(portp, CAR, (portp->portnr & 0x3)); |
3435 | srer = stl_cd1400getreg(portp, SRER); | 3412 | srer = stl_cd1400getreg(portp, SRER); |
@@ -3466,7 +3443,7 @@ static void stl_cd1400setport(stlport_t *portp, struct termios *tiosp) | |||
3466 | portp->sigs &= ~TIOCM_CD; | 3443 | portp->sigs &= ~TIOCM_CD; |
3467 | stl_cd1400setreg(portp, SRER, ((srer & ~sreroff) | sreron)); | 3444 | stl_cd1400setreg(portp, SRER, ((srer & ~sreroff) | sreron)); |
3468 | BRDDISABLE(portp->brdnr); | 3445 | BRDDISABLE(portp->brdnr); |
3469 | restore_flags(flags); | 3446 | spin_unlock_irqrestore(&brd_lock, flags); |
3470 | } | 3447 | } |
3471 | 3448 | ||
3472 | /*****************************************************************************/ | 3449 | /*****************************************************************************/ |
@@ -3492,8 +3469,7 @@ static void stl_cd1400setsignals(stlport_t *portp, int dtr, int rts) | |||
3492 | if (rts > 0) | 3469 | if (rts > 0) |
3493 | msvr2 = MSVR2_RTS; | 3470 | msvr2 = MSVR2_RTS; |
3494 | 3471 | ||
3495 | save_flags(flags); | 3472 | spin_lock_irqsave(&brd_lock, flags); |
3496 | cli(); | ||
3497 | BRDENABLE(portp->brdnr, portp->pagenr); | 3473 | BRDENABLE(portp->brdnr, portp->pagenr); |
3498 | stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); | 3474 | stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); |
3499 | if (rts >= 0) | 3475 | if (rts >= 0) |
@@ -3501,7 +3477,7 @@ static void stl_cd1400setsignals(stlport_t *portp, int dtr, int rts) | |||
3501 | if (dtr >= 0) | 3477 | if (dtr >= 0) |
3502 | stl_cd1400setreg(portp, MSVR1, msvr1); | 3478 | stl_cd1400setreg(portp, MSVR1, msvr1); |
3503 | BRDDISABLE(portp->brdnr); | 3479 | BRDDISABLE(portp->brdnr); |
3504 | restore_flags(flags); | 3480 | spin_unlock_irqrestore(&brd_lock, flags); |
3505 | } | 3481 | } |
3506 | 3482 | ||
3507 | /*****************************************************************************/ | 3483 | /*****************************************************************************/ |
@@ -3520,14 +3496,13 @@ static int stl_cd1400getsignals(stlport_t *portp) | |||
3520 | printk("stl_cd1400getsignals(portp=%x)\n", (int) portp); | 3496 | printk("stl_cd1400getsignals(portp=%x)\n", (int) portp); |
3521 | #endif | 3497 | #endif |
3522 | 3498 | ||
3523 | save_flags(flags); | 3499 | spin_lock_irqsave(&brd_lock, flags); |
3524 | cli(); | ||
3525 | BRDENABLE(portp->brdnr, portp->pagenr); | 3500 | BRDENABLE(portp->brdnr, portp->pagenr); |
3526 | stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); | 3501 | stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); |
3527 | msvr1 = stl_cd1400getreg(portp, MSVR1); | 3502 | msvr1 = stl_cd1400getreg(portp, MSVR1); |
3528 | msvr2 = stl_cd1400getreg(portp, MSVR2); | 3503 | msvr2 = stl_cd1400getreg(portp, MSVR2); |
3529 | BRDDISABLE(portp->brdnr); | 3504 | BRDDISABLE(portp->brdnr); |
3530 | restore_flags(flags); | 3505 | spin_unlock_irqrestore(&brd_lock, flags); |
3531 | 3506 | ||
3532 | sigs = 0; | 3507 | sigs = 0; |
3533 | sigs |= (msvr1 & MSVR1_DCD) ? TIOCM_CD : 0; | 3508 | sigs |= (msvr1 & MSVR1_DCD) ? TIOCM_CD : 0; |
@@ -3569,15 +3544,14 @@ static void stl_cd1400enablerxtx(stlport_t *portp, int rx, int tx) | |||
3569 | else if (rx > 0) | 3544 | else if (rx > 0) |
3570 | ccr |= CCR_RXENABLE; | 3545 | ccr |= CCR_RXENABLE; |
3571 | 3546 | ||
3572 | save_flags(flags); | 3547 | spin_lock_irqsave(&brd_lock, flags); |
3573 | cli(); | ||
3574 | BRDENABLE(portp->brdnr, portp->pagenr); | 3548 | BRDENABLE(portp->brdnr, portp->pagenr); |
3575 | stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); | 3549 | stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); |
3576 | stl_cd1400ccrwait(portp); | 3550 | stl_cd1400ccrwait(portp); |
3577 | stl_cd1400setreg(portp, CCR, ccr); | 3551 | stl_cd1400setreg(portp, CCR, ccr); |
3578 | stl_cd1400ccrwait(portp); | 3552 | stl_cd1400ccrwait(portp); |
3579 | BRDDISABLE(portp->brdnr); | 3553 | BRDDISABLE(portp->brdnr); |
3580 | restore_flags(flags); | 3554 | spin_unlock_irqrestore(&brd_lock, flags); |
3581 | } | 3555 | } |
3582 | 3556 | ||
3583 | /*****************************************************************************/ | 3557 | /*****************************************************************************/ |
@@ -3609,8 +3583,7 @@ static void stl_cd1400startrxtx(stlport_t *portp, int rx, int tx) | |||
3609 | else if (rx > 0) | 3583 | else if (rx > 0) |
3610 | sreron |= SRER_RXDATA; | 3584 | sreron |= SRER_RXDATA; |
3611 | 3585 | ||
3612 | save_flags(flags); | 3586 | spin_lock_irqsave(&brd_lock, flags); |
3613 | cli(); | ||
3614 | BRDENABLE(portp->brdnr, portp->pagenr); | 3587 | BRDENABLE(portp->brdnr, portp->pagenr); |
3615 | stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); | 3588 | stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); |
3616 | stl_cd1400setreg(portp, SRER, | 3589 | stl_cd1400setreg(portp, SRER, |
@@ -3618,7 +3591,7 @@ static void stl_cd1400startrxtx(stlport_t *portp, int rx, int tx) | |||
3618 | BRDDISABLE(portp->brdnr); | 3591 | BRDDISABLE(portp->brdnr); |
3619 | if (tx > 0) | 3592 | if (tx > 0) |
3620 | set_bit(ASYI_TXBUSY, &portp->istate); | 3593 | set_bit(ASYI_TXBUSY, &portp->istate); |
3621 | restore_flags(flags); | 3594 | spin_unlock_irqrestore(&brd_lock, flags); |
3622 | } | 3595 | } |
3623 | 3596 | ||
3624 | /*****************************************************************************/ | 3597 | /*****************************************************************************/ |
@@ -3634,13 +3607,12 @@ static void stl_cd1400disableintrs(stlport_t *portp) | |||
3634 | #ifdef DEBUG | 3607 | #ifdef DEBUG |
3635 | printk("stl_cd1400disableintrs(portp=%x)\n", (int) portp); | 3608 | printk("stl_cd1400disableintrs(portp=%x)\n", (int) portp); |
3636 | #endif | 3609 | #endif |
3637 | save_flags(flags); | 3610 | spin_lock_irqsave(&brd_lock, flags); |
3638 | cli(); | ||
3639 | BRDENABLE(portp->brdnr, portp->pagenr); | 3611 | BRDENABLE(portp->brdnr, portp->pagenr); |
3640 | stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); | 3612 | stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); |
3641 | stl_cd1400setreg(portp, SRER, 0); | 3613 | stl_cd1400setreg(portp, SRER, 0); |
3642 | BRDDISABLE(portp->brdnr); | 3614 | BRDDISABLE(portp->brdnr); |
3643 | restore_flags(flags); | 3615 | spin_unlock_irqrestore(&brd_lock, flags); |
3644 | } | 3616 | } |
3645 | 3617 | ||
3646 | /*****************************************************************************/ | 3618 | /*****************************************************************************/ |
@@ -3653,8 +3625,7 @@ static void stl_cd1400sendbreak(stlport_t *portp, int len) | |||
3653 | printk("stl_cd1400sendbreak(portp=%x,len=%d)\n", (int) portp, len); | 3625 | printk("stl_cd1400sendbreak(portp=%x,len=%d)\n", (int) portp, len); |
3654 | #endif | 3626 | #endif |
3655 | 3627 | ||
3656 | save_flags(flags); | 3628 | spin_lock_irqsave(&brd_lock, flags); |
3657 | cli(); | ||
3658 | BRDENABLE(portp->brdnr, portp->pagenr); | 3629 | BRDENABLE(portp->brdnr, portp->pagenr); |
3659 | stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); | 3630 | stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); |
3660 | stl_cd1400setreg(portp, SRER, | 3631 | stl_cd1400setreg(portp, SRER, |
@@ -3664,7 +3635,7 @@ static void stl_cd1400sendbreak(stlport_t *portp, int len) | |||
3664 | portp->brklen = len; | 3635 | portp->brklen = len; |
3665 | if (len == 1) | 3636 | if (len == 1) |
3666 | portp->stats.txbreaks++; | 3637 | portp->stats.txbreaks++; |
3667 | restore_flags(flags); | 3638 | spin_unlock_irqrestore(&brd_lock, flags); |
3668 | } | 3639 | } |
3669 | 3640 | ||
3670 | /*****************************************************************************/ | 3641 | /*****************************************************************************/ |
@@ -3688,8 +3659,7 @@ static void stl_cd1400flowctrl(stlport_t *portp, int state) | |||
3688 | if (tty == (struct tty_struct *) NULL) | 3659 | if (tty == (struct tty_struct *) NULL) |
3689 | return; | 3660 | return; |
3690 | 3661 | ||
3691 | save_flags(flags); | 3662 | spin_lock_irqsave(&brd_lock, flags); |
3692 | cli(); | ||
3693 | BRDENABLE(portp->brdnr, portp->pagenr); | 3663 | BRDENABLE(portp->brdnr, portp->pagenr); |
3694 | stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); | 3664 | stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); |
3695 | 3665 | ||
@@ -3729,7 +3699,7 @@ static void stl_cd1400flowctrl(stlport_t *portp, int state) | |||
3729 | } | 3699 | } |
3730 | 3700 | ||
3731 | BRDDISABLE(portp->brdnr); | 3701 | BRDDISABLE(portp->brdnr); |
3732 | restore_flags(flags); | 3702 | spin_unlock_irqrestore(&brd_lock, flags); |
3733 | } | 3703 | } |
3734 | 3704 | ||
3735 | /*****************************************************************************/ | 3705 | /*****************************************************************************/ |
@@ -3753,8 +3723,7 @@ static void stl_cd1400sendflow(stlport_t *portp, int state) | |||
3753 | if (tty == (struct tty_struct *) NULL) | 3723 | if (tty == (struct tty_struct *) NULL) |
3754 | return; | 3724 | return; |
3755 | 3725 | ||
3756 | save_flags(flags); | 3726 | spin_lock_irqsave(&brd_lock, flags); |
3757 | cli(); | ||
3758 | BRDENABLE(portp->brdnr, portp->pagenr); | 3727 | BRDENABLE(portp->brdnr, portp->pagenr); |
3759 | stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); | 3728 | stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); |
3760 | if (state) { | 3729 | if (state) { |
@@ -3769,7 +3738,7 @@ static void stl_cd1400sendflow(stlport_t *portp, int state) | |||
3769 | stl_cd1400ccrwait(portp); | 3738 | stl_cd1400ccrwait(portp); |
3770 | } | 3739 | } |
3771 | BRDDISABLE(portp->brdnr); | 3740 | BRDDISABLE(portp->brdnr); |
3772 | restore_flags(flags); | 3741 | spin_unlock_irqrestore(&brd_lock, flags); |
3773 | } | 3742 | } |
3774 | 3743 | ||
3775 | /*****************************************************************************/ | 3744 | /*****************************************************************************/ |
@@ -3785,8 +3754,7 @@ static void stl_cd1400flush(stlport_t *portp) | |||
3785 | if (portp == (stlport_t *) NULL) | 3754 | if (portp == (stlport_t *) NULL) |
3786 | return; | 3755 | return; |
3787 | 3756 | ||
3788 | save_flags(flags); | 3757 | spin_lock_irqsave(&brd_lock, flags); |
3789 | cli(); | ||
3790 | BRDENABLE(portp->brdnr, portp->pagenr); | 3758 | BRDENABLE(portp->brdnr, portp->pagenr); |
3791 | stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); | 3759 | stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); |
3792 | stl_cd1400ccrwait(portp); | 3760 | stl_cd1400ccrwait(portp); |
@@ -3794,7 +3762,7 @@ static void stl_cd1400flush(stlport_t *portp) | |||
3794 | stl_cd1400ccrwait(portp); | 3762 | stl_cd1400ccrwait(portp); |
3795 | portp->tx.tail = portp->tx.head; | 3763 | portp->tx.tail = portp->tx.head; |
3796 | BRDDISABLE(portp->brdnr); | 3764 | BRDDISABLE(portp->brdnr); |
3797 | restore_flags(flags); | 3765 | spin_unlock_irqrestore(&brd_lock, flags); |
3798 | } | 3766 | } |
3799 | 3767 | ||
3800 | /*****************************************************************************/ | 3768 | /*****************************************************************************/ |
@@ -3833,6 +3801,7 @@ static void stl_cd1400eiointr(stlpanel_t *panelp, unsigned int iobase) | |||
3833 | (int) panelp, iobase); | 3801 | (int) panelp, iobase); |
3834 | #endif | 3802 | #endif |
3835 | 3803 | ||
3804 | spin_lock(&brd_lock); | ||
3836 | outb(SVRR, iobase); | 3805 | outb(SVRR, iobase); |
3837 | svrtype = inb(iobase + EREG_DATA); | 3806 | svrtype = inb(iobase + EREG_DATA); |
3838 | if (panelp->nrports > 4) { | 3807 | if (panelp->nrports > 4) { |
@@ -3846,6 +3815,8 @@ static void stl_cd1400eiointr(stlpanel_t *panelp, unsigned int iobase) | |||
3846 | stl_cd1400txisr(panelp, iobase); | 3815 | stl_cd1400txisr(panelp, iobase); |
3847 | else if (svrtype & SVRR_MDM) | 3816 | else if (svrtype & SVRR_MDM) |
3848 | stl_cd1400mdmisr(panelp, iobase); | 3817 | stl_cd1400mdmisr(panelp, iobase); |
3818 | |||
3819 | spin_unlock(&brd_lock); | ||
3849 | } | 3820 | } |
3850 | 3821 | ||
3851 | /*****************************************************************************/ | 3822 | /*****************************************************************************/ |
@@ -4433,8 +4404,7 @@ static void stl_sc26198setport(stlport_t *portp, struct termios *tiosp) | |||
4433 | tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP]); | 4404 | tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP]); |
4434 | #endif | 4405 | #endif |
4435 | 4406 | ||
4436 | save_flags(flags); | 4407 | spin_lock_irqsave(&brd_lock, flags); |
4437 | cli(); | ||
4438 | BRDENABLE(portp->brdnr, portp->pagenr); | 4408 | BRDENABLE(portp->brdnr, portp->pagenr); |
4439 | stl_sc26198setreg(portp, IMR, 0); | 4409 | stl_sc26198setreg(portp, IMR, 0); |
4440 | stl_sc26198updatereg(portp, MR0, mr0); | 4410 | stl_sc26198updatereg(portp, MR0, mr0); |
@@ -4461,7 +4431,7 @@ static void stl_sc26198setport(stlport_t *portp, struct termios *tiosp) | |||
4461 | portp->imr = (portp->imr & ~imroff) | imron; | 4431 | portp->imr = (portp->imr & ~imroff) | imron; |
4462 | stl_sc26198setreg(portp, IMR, portp->imr); | 4432 | stl_sc26198setreg(portp, IMR, portp->imr); |
4463 | BRDDISABLE(portp->brdnr); | 4433 | BRDDISABLE(portp->brdnr); |
4464 | restore_flags(flags); | 4434 | spin_unlock_irqrestore(&brd_lock, flags); |
4465 | } | 4435 | } |
4466 | 4436 | ||
4467 | /*****************************************************************************/ | 4437 | /*****************************************************************************/ |
@@ -4491,13 +4461,12 @@ static void stl_sc26198setsignals(stlport_t *portp, int dtr, int rts) | |||
4491 | else if (rts > 0) | 4461 | else if (rts > 0) |
4492 | iopioron |= IPR_RTS; | 4462 | iopioron |= IPR_RTS; |
4493 | 4463 | ||
4494 | save_flags(flags); | 4464 | spin_lock_irqsave(&brd_lock, flags); |
4495 | cli(); | ||
4496 | BRDENABLE(portp->brdnr, portp->pagenr); | 4465 | BRDENABLE(portp->brdnr, portp->pagenr); |
4497 | stl_sc26198setreg(portp, IOPIOR, | 4466 | stl_sc26198setreg(portp, IOPIOR, |
4498 | ((stl_sc26198getreg(portp, IOPIOR) & ~iopioroff) | iopioron)); | 4467 | ((stl_sc26198getreg(portp, IOPIOR) & ~iopioroff) | iopioron)); |
4499 | BRDDISABLE(portp->brdnr); | 4468 | BRDDISABLE(portp->brdnr); |
4500 | restore_flags(flags); | 4469 | spin_unlock_irqrestore(&brd_lock, flags); |
4501 | } | 4470 | } |
4502 | 4471 | ||
4503 | /*****************************************************************************/ | 4472 | /*****************************************************************************/ |
@@ -4516,12 +4485,11 @@ static int stl_sc26198getsignals(stlport_t *portp) | |||
4516 | printk("stl_sc26198getsignals(portp=%x)\n", (int) portp); | 4485 | printk("stl_sc26198getsignals(portp=%x)\n", (int) portp); |
4517 | #endif | 4486 | #endif |
4518 | 4487 | ||
4519 | save_flags(flags); | 4488 | spin_lock_irqsave(&brd_lock, flags); |
4520 | cli(); | ||
4521 | BRDENABLE(portp->brdnr, portp->pagenr); | 4489 | BRDENABLE(portp->brdnr, portp->pagenr); |
4522 | ipr = stl_sc26198getreg(portp, IPR); | 4490 | ipr = stl_sc26198getreg(portp, IPR); |
4523 | BRDDISABLE(portp->brdnr); | 4491 | BRDDISABLE(portp->brdnr); |
4524 | restore_flags(flags); | 4492 | spin_unlock_irqrestore(&brd_lock, flags); |
4525 | 4493 | ||
4526 | sigs = 0; | 4494 | sigs = 0; |
4527 | sigs |= (ipr & IPR_DCD) ? 0 : TIOCM_CD; | 4495 | sigs |= (ipr & IPR_DCD) ? 0 : TIOCM_CD; |
@@ -4558,13 +4526,12 @@ static void stl_sc26198enablerxtx(stlport_t *portp, int rx, int tx) | |||
4558 | else if (rx > 0) | 4526 | else if (rx > 0) |
4559 | ccr |= CR_RXENABLE; | 4527 | ccr |= CR_RXENABLE; |
4560 | 4528 | ||
4561 | save_flags(flags); | 4529 | spin_lock_irqsave(&brd_lock, flags); |
4562 | cli(); | ||
4563 | BRDENABLE(portp->brdnr, portp->pagenr); | 4530 | BRDENABLE(portp->brdnr, portp->pagenr); |
4564 | stl_sc26198setreg(portp, SCCR, ccr); | 4531 | stl_sc26198setreg(portp, SCCR, ccr); |
4565 | BRDDISABLE(portp->brdnr); | 4532 | BRDDISABLE(portp->brdnr); |
4566 | portp->crenable = ccr; | 4533 | portp->crenable = ccr; |
4567 | restore_flags(flags); | 4534 | spin_unlock_irqrestore(&brd_lock, flags); |
4568 | } | 4535 | } |
4569 | 4536 | ||
4570 | /*****************************************************************************/ | 4537 | /*****************************************************************************/ |
@@ -4593,15 +4560,14 @@ static void stl_sc26198startrxtx(stlport_t *portp, int rx, int tx) | |||
4593 | else if (rx > 0) | 4560 | else if (rx > 0) |
4594 | imr |= IR_RXRDY | IR_RXBREAK | IR_RXWATCHDOG; | 4561 | imr |= IR_RXRDY | IR_RXBREAK | IR_RXWATCHDOG; |
4595 | 4562 | ||
4596 | save_flags(flags); | 4563 | spin_lock_irqsave(&brd_lock, flags); |
4597 | cli(); | ||
4598 | BRDENABLE(portp->brdnr, portp->pagenr); | 4564 | BRDENABLE(portp->brdnr, portp->pagenr); |
4599 | stl_sc26198setreg(portp, IMR, imr); | 4565 | stl_sc26198setreg(portp, IMR, imr); |
4600 | BRDDISABLE(portp->brdnr); | 4566 | BRDDISABLE(portp->brdnr); |
4601 | portp->imr = imr; | 4567 | portp->imr = imr; |
4602 | if (tx > 0) | 4568 | if (tx > 0) |
4603 | set_bit(ASYI_TXBUSY, &portp->istate); | 4569 | set_bit(ASYI_TXBUSY, &portp->istate); |
4604 | restore_flags(flags); | 4570 | spin_unlock_irqrestore(&brd_lock, flags); |
4605 | } | 4571 | } |
4606 | 4572 | ||
4607 | /*****************************************************************************/ | 4573 | /*****************************************************************************/ |
@@ -4618,13 +4584,12 @@ static void stl_sc26198disableintrs(stlport_t *portp) | |||
4618 | printk("stl_sc26198disableintrs(portp=%x)\n", (int) portp); | 4584 | printk("stl_sc26198disableintrs(portp=%x)\n", (int) portp); |
4619 | #endif | 4585 | #endif |
4620 | 4586 | ||
4621 | save_flags(flags); | 4587 | spin_lock_irqsave(&brd_lock, flags); |
4622 | cli(); | ||
4623 | BRDENABLE(portp->brdnr, portp->pagenr); | 4588 | BRDENABLE(portp->brdnr, portp->pagenr); |
4624 | portp->imr = 0; | 4589 | portp->imr = 0; |
4625 | stl_sc26198setreg(portp, IMR, 0); | 4590 | stl_sc26198setreg(portp, IMR, 0); |
4626 | BRDDISABLE(portp->brdnr); | 4591 | BRDDISABLE(portp->brdnr); |
4627 | restore_flags(flags); | 4592 | spin_unlock_irqrestore(&brd_lock, flags); |
4628 | } | 4593 | } |
4629 | 4594 | ||
4630 | /*****************************************************************************/ | 4595 | /*****************************************************************************/ |
@@ -4637,8 +4602,7 @@ static void stl_sc26198sendbreak(stlport_t *portp, int len) | |||
4637 | printk("stl_sc26198sendbreak(portp=%x,len=%d)\n", (int) portp, len); | 4602 | printk("stl_sc26198sendbreak(portp=%x,len=%d)\n", (int) portp, len); |
4638 | #endif | 4603 | #endif |
4639 | 4604 | ||
4640 | save_flags(flags); | 4605 | spin_lock_irqsave(&brd_lock, flags); |
4641 | cli(); | ||
4642 | BRDENABLE(portp->brdnr, portp->pagenr); | 4606 | BRDENABLE(portp->brdnr, portp->pagenr); |
4643 | if (len == 1) { | 4607 | if (len == 1) { |
4644 | stl_sc26198setreg(portp, SCCR, CR_TXSTARTBREAK); | 4608 | stl_sc26198setreg(portp, SCCR, CR_TXSTARTBREAK); |
@@ -4647,7 +4611,7 @@ static void stl_sc26198sendbreak(stlport_t *portp, int len) | |||
4647 | stl_sc26198setreg(portp, SCCR, CR_TXSTOPBREAK); | 4611 | stl_sc26198setreg(portp, SCCR, CR_TXSTOPBREAK); |
4648 | } | 4612 | } |
4649 | BRDDISABLE(portp->brdnr); | 4613 | BRDDISABLE(portp->brdnr); |
4650 | restore_flags(flags); | 4614 | spin_unlock_irqrestore(&brd_lock, flags); |
4651 | } | 4615 | } |
4652 | 4616 | ||
4653 | /*****************************************************************************/ | 4617 | /*****************************************************************************/ |
@@ -4672,8 +4636,7 @@ static void stl_sc26198flowctrl(stlport_t *portp, int state) | |||
4672 | if (tty == (struct tty_struct *) NULL) | 4636 | if (tty == (struct tty_struct *) NULL) |
4673 | return; | 4637 | return; |
4674 | 4638 | ||
4675 | save_flags(flags); | 4639 | spin_lock_irqsave(&brd_lock, flags); |
4676 | cli(); | ||
4677 | BRDENABLE(portp->brdnr, portp->pagenr); | 4640 | BRDENABLE(portp->brdnr, portp->pagenr); |
4678 | 4641 | ||
4679 | if (state) { | 4642 | if (state) { |
@@ -4719,7 +4682,7 @@ static void stl_sc26198flowctrl(stlport_t *portp, int state) | |||
4719 | } | 4682 | } |
4720 | 4683 | ||
4721 | BRDDISABLE(portp->brdnr); | 4684 | BRDDISABLE(portp->brdnr); |
4722 | restore_flags(flags); | 4685 | spin_unlock_irqrestore(&brd_lock, flags); |
4723 | } | 4686 | } |
4724 | 4687 | ||
4725 | /*****************************************************************************/ | 4688 | /*****************************************************************************/ |
@@ -4744,8 +4707,7 @@ static void stl_sc26198sendflow(stlport_t *portp, int state) | |||
4744 | if (tty == (struct tty_struct *) NULL) | 4707 | if (tty == (struct tty_struct *) NULL) |
4745 | return; | 4708 | return; |
4746 | 4709 | ||
4747 | save_flags(flags); | 4710 | spin_lock_irqsave(&brd_lock, flags); |
4748 | cli(); | ||
4749 | BRDENABLE(portp->brdnr, portp->pagenr); | 4711 | BRDENABLE(portp->brdnr, portp->pagenr); |
4750 | if (state) { | 4712 | if (state) { |
4751 | mr0 = stl_sc26198getreg(portp, MR0); | 4713 | mr0 = stl_sc26198getreg(portp, MR0); |
@@ -4765,7 +4727,7 @@ static void stl_sc26198sendflow(stlport_t *portp, int state) | |||
4765 | stl_sc26198setreg(portp, MR0, mr0); | 4727 | stl_sc26198setreg(portp, MR0, mr0); |
4766 | } | 4728 | } |
4767 | BRDDISABLE(portp->brdnr); | 4729 | BRDDISABLE(portp->brdnr); |
4768 | restore_flags(flags); | 4730 | spin_unlock_irqrestore(&brd_lock, flags); |
4769 | } | 4731 | } |
4770 | 4732 | ||
4771 | /*****************************************************************************/ | 4733 | /*****************************************************************************/ |
@@ -4781,14 +4743,13 @@ static void stl_sc26198flush(stlport_t *portp) | |||
4781 | if (portp == (stlport_t *) NULL) | 4743 | if (portp == (stlport_t *) NULL) |
4782 | return; | 4744 | return; |
4783 | 4745 | ||
4784 | save_flags(flags); | 4746 | spin_lock_irqsave(&brd_lock, flags); |
4785 | cli(); | ||
4786 | BRDENABLE(portp->brdnr, portp->pagenr); | 4747 | BRDENABLE(portp->brdnr, portp->pagenr); |
4787 | stl_sc26198setreg(portp, SCCR, CR_TXRESET); | 4748 | stl_sc26198setreg(portp, SCCR, CR_TXRESET); |
4788 | stl_sc26198setreg(portp, SCCR, portp->crenable); | 4749 | stl_sc26198setreg(portp, SCCR, portp->crenable); |
4789 | BRDDISABLE(portp->brdnr); | 4750 | BRDDISABLE(portp->brdnr); |
4790 | portp->tx.tail = portp->tx.head; | 4751 | portp->tx.tail = portp->tx.head; |
4791 | restore_flags(flags); | 4752 | spin_unlock_irqrestore(&brd_lock, flags); |
4792 | } | 4753 | } |
4793 | 4754 | ||
4794 | /*****************************************************************************/ | 4755 | /*****************************************************************************/ |
@@ -4815,12 +4776,11 @@ static int stl_sc26198datastate(stlport_t *portp) | |||
4815 | if (test_bit(ASYI_TXBUSY, &portp->istate)) | 4776 | if (test_bit(ASYI_TXBUSY, &portp->istate)) |
4816 | return 1; | 4777 | return 1; |
4817 | 4778 | ||
4818 | save_flags(flags); | 4779 | spin_lock_irqsave(&brd_lock, flags); |
4819 | cli(); | ||
4820 | BRDENABLE(portp->brdnr, portp->pagenr); | 4780 | BRDENABLE(portp->brdnr, portp->pagenr); |
4821 | sr = stl_sc26198getreg(portp, SR); | 4781 | sr = stl_sc26198getreg(portp, SR); |
4822 | BRDDISABLE(portp->brdnr); | 4782 | BRDDISABLE(portp->brdnr); |
4823 | restore_flags(flags); | 4783 | spin_unlock_irqrestore(&brd_lock, flags); |
4824 | 4784 | ||
4825 | return (sr & SR_TXEMPTY) ? 0 : 1; | 4785 | return (sr & SR_TXEMPTY) ? 0 : 1; |
4826 | } | 4786 | } |
@@ -4878,6 +4838,8 @@ static void stl_sc26198intr(stlpanel_t *panelp, unsigned int iobase) | |||
4878 | stlport_t *portp; | 4838 | stlport_t *portp; |
4879 | unsigned int iack; | 4839 | unsigned int iack; |
4880 | 4840 | ||
4841 | spin_lock(&brd_lock); | ||
4842 | |||
4881 | /* | 4843 | /* |
4882 | * Work around bug in sc26198 chip... Cannot have A6 address | 4844 | * Work around bug in sc26198 chip... Cannot have A6 address |
4883 | * line of UART high, else iack will be returned as 0. | 4845 | * line of UART high, else iack will be returned as 0. |
@@ -4893,6 +4855,8 @@ static void stl_sc26198intr(stlpanel_t *panelp, unsigned int iobase) | |||
4893 | stl_sc26198txisr(portp); | 4855 | stl_sc26198txisr(portp); |
4894 | else | 4856 | else |
4895 | stl_sc26198otherisr(portp, iack); | 4857 | stl_sc26198otherisr(portp, iack); |
4858 | |||
4859 | spin_unlock(&brd_lock); | ||
4896 | } | 4860 | } |
4897 | 4861 | ||
4898 | /*****************************************************************************/ | 4862 | /*****************************************************************************/ |
diff --git a/drivers/char/sx.c b/drivers/char/sx.c index 3b4747230270..76b9107f7f81 100644 --- a/drivers/char/sx.c +++ b/drivers/char/sx.c | |||
@@ -2320,7 +2320,7 @@ static int sx_init_portstructs (int nboards, int nports) | |||
2320 | #ifdef NEW_WRITE_LOCKING | 2320 | #ifdef NEW_WRITE_LOCKING |
2321 | port->gs.port_write_mutex = MUTEX; | 2321 | port->gs.port_write_mutex = MUTEX; |
2322 | #endif | 2322 | #endif |
2323 | port->gs.driver_lock = SPIN_LOCK_UNLOCKED; | 2323 | spin_lock_init(&port->gs.driver_lock); |
2324 | /* | 2324 | /* |
2325 | * Initializing wait queue | 2325 | * Initializing wait queue |
2326 | */ | 2326 | */ |
diff --git a/drivers/char/tlclk.c b/drivers/char/tlclk.c index f58ad7f68267..ef68d152d3e4 100644 --- a/drivers/char/tlclk.c +++ b/drivers/char/tlclk.c | |||
@@ -343,7 +343,7 @@ static ssize_t store_received_ref_clk3b(struct device *d, | |||
343 | 343 | ||
344 | val = (unsigned char)tmp; | 344 | val = (unsigned char)tmp; |
345 | spin_lock_irqsave(&event_lock, flags); | 345 | spin_lock_irqsave(&event_lock, flags); |
346 | SET_PORT_BITS(TLCLK_REG1, 0xef, val << 1); | 346 | SET_PORT_BITS(TLCLK_REG1, 0xdf, val << 1); |
347 | spin_unlock_irqrestore(&event_lock, flags); | 347 | spin_unlock_irqrestore(&event_lock, flags); |
348 | 348 | ||
349 | return strnlen(buf, count); | 349 | return strnlen(buf, count); |
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 8b2a59969868..bd74e82d8a72 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c | |||
@@ -2621,10 +2621,9 @@ int tty_ioctl(struct inode * inode, struct file * file, | |||
2621 | tty->driver->break_ctl(tty, 0); | 2621 | tty->driver->break_ctl(tty, 0); |
2622 | return 0; | 2622 | return 0; |
2623 | case TCSBRK: /* SVID version: non-zero arg --> no break */ | 2623 | case TCSBRK: /* SVID version: non-zero arg --> no break */ |
2624 | /* | 2624 | /* non-zero arg means wait for all output data |
2625 | * XXX is the above comment correct, or the | 2625 | * to be sent (performed above) but don't send break. |
2626 | * code below correct? Is this ioctl used at | 2626 | * This is used by the tcdrain() termios function. |
2627 | * all by anyone? | ||
2628 | */ | 2627 | */ |
2629 | if (!arg) | 2628 | if (!arg) |
2630 | return send_break(tty, 250); | 2629 | return send_break(tty, 250); |
diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 6c94879e0b99..714d95ff2f1e 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c | |||
@@ -98,7 +98,22 @@ | |||
98 | #include <asm/system.h> | 98 | #include <asm/system.h> |
99 | #include <asm/uaccess.h> | 99 | #include <asm/uaccess.h> |
100 | 100 | ||
101 | #define MAX_NR_CON_DRIVER 16 | ||
101 | 102 | ||
103 | #define CON_DRIVER_FLAG_MODULE 1 | ||
104 | #define CON_DRIVER_FLAG_INIT 2 | ||
105 | |||
106 | struct con_driver { | ||
107 | const struct consw *con; | ||
108 | const char *desc; | ||
109 | struct class_device *class_dev; | ||
110 | int node; | ||
111 | int first; | ||
112 | int last; | ||
113 | int flag; | ||
114 | }; | ||
115 | |||
116 | static struct con_driver registered_con_driver[MAX_NR_CON_DRIVER]; | ||
102 | const struct consw *conswitchp; | 117 | const struct consw *conswitchp; |
103 | 118 | ||
104 | /* A bitmap for codes <32. A bit of 1 indicates that the code | 119 | /* A bitmap for codes <32. A bit of 1 indicates that the code |
@@ -2557,7 +2572,7 @@ static int __init con_init(void) | |||
2557 | { | 2572 | { |
2558 | const char *display_desc = NULL; | 2573 | const char *display_desc = NULL; |
2559 | struct vc_data *vc; | 2574 | struct vc_data *vc; |
2560 | unsigned int currcons = 0; | 2575 | unsigned int currcons = 0, i; |
2561 | 2576 | ||
2562 | acquire_console_sem(); | 2577 | acquire_console_sem(); |
2563 | 2578 | ||
@@ -2569,6 +2584,22 @@ static int __init con_init(void) | |||
2569 | return 0; | 2584 | return 0; |
2570 | } | 2585 | } |
2571 | 2586 | ||
2587 | for (i = 0; i < MAX_NR_CON_DRIVER; i++) { | ||
2588 | struct con_driver *con_driver = ®istered_con_driver[i]; | ||
2589 | |||
2590 | if (con_driver->con == NULL) { | ||
2591 | con_driver->con = conswitchp; | ||
2592 | con_driver->desc = display_desc; | ||
2593 | con_driver->flag = CON_DRIVER_FLAG_INIT; | ||
2594 | con_driver->first = 0; | ||
2595 | con_driver->last = MAX_NR_CONSOLES - 1; | ||
2596 | break; | ||
2597 | } | ||
2598 | } | ||
2599 | |||
2600 | for (i = 0; i < MAX_NR_CONSOLES; i++) | ||
2601 | con_driver_map[i] = conswitchp; | ||
2602 | |||
2572 | init_timer(&console_timer); | 2603 | init_timer(&console_timer); |
2573 | console_timer.function = blank_screen_t; | 2604 | console_timer.function = blank_screen_t; |
2574 | if (blankinterval) { | 2605 | if (blankinterval) { |
@@ -2656,38 +2687,53 @@ int __init vty_init(void) | |||
2656 | } | 2687 | } |
2657 | 2688 | ||
2658 | #ifndef VT_SINGLE_DRIVER | 2689 | #ifndef VT_SINGLE_DRIVER |
2690 | #include <linux/device.h> | ||
2659 | 2691 | ||
2660 | /* | 2692 | static struct class *vtconsole_class; |
2661 | * If we support more console drivers, this function is used | ||
2662 | * when a driver wants to take over some existing consoles | ||
2663 | * and become default driver for newly opened ones. | ||
2664 | */ | ||
2665 | 2693 | ||
2666 | int take_over_console(const struct consw *csw, int first, int last, int deflt) | 2694 | static int bind_con_driver(const struct consw *csw, int first, int last, |
2695 | int deflt) | ||
2667 | { | 2696 | { |
2668 | int i, j = -1; | 2697 | struct module *owner = csw->owner; |
2669 | const char *desc; | 2698 | const char *desc = NULL; |
2670 | struct module *owner; | 2699 | struct con_driver *con_driver; |
2700 | int i, j = -1, k = -1, retval = -ENODEV; | ||
2671 | 2701 | ||
2672 | owner = csw->owner; | ||
2673 | if (!try_module_get(owner)) | 2702 | if (!try_module_get(owner)) |
2674 | return -ENODEV; | 2703 | return -ENODEV; |
2675 | 2704 | ||
2676 | acquire_console_sem(); | 2705 | acquire_console_sem(); |
2677 | 2706 | ||
2678 | desc = csw->con_startup(); | 2707 | /* check if driver is registered */ |
2679 | if (!desc) { | 2708 | for (i = 0; i < MAX_NR_CON_DRIVER; i++) { |
2680 | release_console_sem(); | 2709 | con_driver = ®istered_con_driver[i]; |
2681 | module_put(owner); | 2710 | |
2682 | return -ENODEV; | 2711 | if (con_driver->con == csw) { |
2712 | desc = con_driver->desc; | ||
2713 | retval = 0; | ||
2714 | break; | ||
2715 | } | ||
2716 | } | ||
2717 | |||
2718 | if (retval) | ||
2719 | goto err; | ||
2720 | |||
2721 | if (!(con_driver->flag & CON_DRIVER_FLAG_INIT)) { | ||
2722 | csw->con_startup(); | ||
2723 | con_driver->flag |= CON_DRIVER_FLAG_INIT; | ||
2683 | } | 2724 | } |
2725 | |||
2684 | if (deflt) { | 2726 | if (deflt) { |
2685 | if (conswitchp) | 2727 | if (conswitchp) |
2686 | module_put(conswitchp->owner); | 2728 | module_put(conswitchp->owner); |
2729 | |||
2687 | __module_get(owner); | 2730 | __module_get(owner); |
2688 | conswitchp = csw; | 2731 | conswitchp = csw; |
2689 | } | 2732 | } |
2690 | 2733 | ||
2734 | first = max(first, con_driver->first); | ||
2735 | last = min(last, con_driver->last); | ||
2736 | |||
2691 | for (i = first; i <= last; i++) { | 2737 | for (i = first; i <= last; i++) { |
2692 | int old_was_color; | 2738 | int old_was_color; |
2693 | struct vc_data *vc = vc_cons[i].d; | 2739 | struct vc_data *vc = vc_cons[i].d; |
@@ -2701,15 +2747,17 @@ int take_over_console(const struct consw *csw, int first, int last, int deflt) | |||
2701 | continue; | 2747 | continue; |
2702 | 2748 | ||
2703 | j = i; | 2749 | j = i; |
2704 | if (CON_IS_VISIBLE(vc)) | 2750 | |
2751 | if (CON_IS_VISIBLE(vc)) { | ||
2752 | k = i; | ||
2705 | save_screen(vc); | 2753 | save_screen(vc); |
2754 | } | ||
2755 | |||
2706 | old_was_color = vc->vc_can_do_color; | 2756 | old_was_color = vc->vc_can_do_color; |
2707 | vc->vc_sw->con_deinit(vc); | 2757 | vc->vc_sw->con_deinit(vc); |
2708 | vc->vc_origin = (unsigned long)vc->vc_screenbuf; | 2758 | vc->vc_origin = (unsigned long)vc->vc_screenbuf; |
2709 | vc->vc_visible_origin = vc->vc_origin; | ||
2710 | vc->vc_scr_end = vc->vc_origin + vc->vc_screenbuf_size; | ||
2711 | vc->vc_pos = vc->vc_origin + vc->vc_size_row * vc->vc_y + 2 * vc->vc_x; | ||
2712 | visual_init(vc, i, 0); | 2759 | visual_init(vc, i, 0); |
2760 | set_origin(vc); | ||
2713 | update_attr(vc); | 2761 | update_attr(vc); |
2714 | 2762 | ||
2715 | /* If the console changed between mono <-> color, then | 2763 | /* If the console changed between mono <-> color, then |
@@ -2718,36 +2766,506 @@ int take_over_console(const struct consw *csw, int first, int last, int deflt) | |||
2718 | */ | 2766 | */ |
2719 | if (old_was_color != vc->vc_can_do_color) | 2767 | if (old_was_color != vc->vc_can_do_color) |
2720 | clear_buffer_attributes(vc); | 2768 | clear_buffer_attributes(vc); |
2721 | |||
2722 | if (CON_IS_VISIBLE(vc)) | ||
2723 | update_screen(vc); | ||
2724 | } | 2769 | } |
2770 | |||
2725 | printk("Console: switching "); | 2771 | printk("Console: switching "); |
2726 | if (!deflt) | 2772 | if (!deflt) |
2727 | printk("consoles %d-%d ", first+1, last+1); | 2773 | printk("consoles %d-%d ", first+1, last+1); |
2728 | if (j >= 0) | 2774 | if (j >= 0) { |
2775 | struct vc_data *vc = vc_cons[j].d; | ||
2776 | |||
2729 | printk("to %s %s %dx%d\n", | 2777 | printk("to %s %s %dx%d\n", |
2730 | vc_cons[j].d->vc_can_do_color ? "colour" : "mono", | 2778 | vc->vc_can_do_color ? "colour" : "mono", |
2731 | desc, vc_cons[j].d->vc_cols, vc_cons[j].d->vc_rows); | 2779 | desc, vc->vc_cols, vc->vc_rows); |
2732 | else | 2780 | |
2781 | if (k >= 0) { | ||
2782 | vc = vc_cons[k].d; | ||
2783 | update_screen(vc); | ||
2784 | } | ||
2785 | } else | ||
2733 | printk("to %s\n", desc); | 2786 | printk("to %s\n", desc); |
2734 | 2787 | ||
2788 | retval = 0; | ||
2789 | err: | ||
2735 | release_console_sem(); | 2790 | release_console_sem(); |
2791 | module_put(owner); | ||
2792 | return retval; | ||
2793 | }; | ||
2794 | |||
2795 | #ifdef CONFIG_VT_HW_CONSOLE_BINDING | ||
2796 | static int con_is_graphics(const struct consw *csw, int first, int last) | ||
2797 | { | ||
2798 | int i, retval = 0; | ||
2799 | |||
2800 | for (i = first; i <= last; i++) { | ||
2801 | struct vc_data *vc = vc_cons[i].d; | ||
2802 | |||
2803 | if (vc && vc->vc_mode == KD_GRAPHICS) { | ||
2804 | retval = 1; | ||
2805 | break; | ||
2806 | } | ||
2807 | } | ||
2808 | |||
2809 | return retval; | ||
2810 | } | ||
2811 | |||
2812 | static int unbind_con_driver(const struct consw *csw, int first, int last, | ||
2813 | int deflt) | ||
2814 | { | ||
2815 | struct module *owner = csw->owner; | ||
2816 | const struct consw *defcsw = NULL; | ||
2817 | struct con_driver *con_driver = NULL, *con_back = NULL; | ||
2818 | int i, retval = -ENODEV; | ||
2819 | |||
2820 | if (!try_module_get(owner)) | ||
2821 | return -ENODEV; | ||
2822 | |||
2823 | acquire_console_sem(); | ||
2824 | |||
2825 | /* check if driver is registered and if it is unbindable */ | ||
2826 | for (i = 0; i < MAX_NR_CON_DRIVER; i++) { | ||
2827 | con_driver = ®istered_con_driver[i]; | ||
2828 | |||
2829 | if (con_driver->con == csw && | ||
2830 | con_driver->flag & CON_DRIVER_FLAG_MODULE) { | ||
2831 | retval = 0; | ||
2832 | break; | ||
2833 | } | ||
2834 | } | ||
2835 | |||
2836 | if (retval) { | ||
2837 | release_console_sem(); | ||
2838 | goto err; | ||
2839 | } | ||
2840 | |||
2841 | retval = -ENODEV; | ||
2842 | |||
2843 | /* check if backup driver exists */ | ||
2844 | for (i = 0; i < MAX_NR_CON_DRIVER; i++) { | ||
2845 | con_back = ®istered_con_driver[i]; | ||
2846 | |||
2847 | if (con_back->con && | ||
2848 | !(con_back->flag & CON_DRIVER_FLAG_MODULE)) { | ||
2849 | defcsw = con_back->con; | ||
2850 | retval = 0; | ||
2851 | break; | ||
2852 | } | ||
2853 | } | ||
2854 | |||
2855 | if (retval) { | ||
2856 | release_console_sem(); | ||
2857 | goto err; | ||
2858 | } | ||
2859 | |||
2860 | if (!con_is_bound(csw)) { | ||
2861 | release_console_sem(); | ||
2862 | goto err; | ||
2863 | } | ||
2864 | |||
2865 | first = max(first, con_driver->first); | ||
2866 | last = min(last, con_driver->last); | ||
2867 | |||
2868 | for (i = first; i <= last; i++) { | ||
2869 | if (con_driver_map[i] == csw) { | ||
2870 | module_put(csw->owner); | ||
2871 | con_driver_map[i] = NULL; | ||
2872 | } | ||
2873 | } | ||
2874 | |||
2875 | if (!con_is_bound(defcsw)) { | ||
2876 | const struct consw *defconsw = conswitchp; | ||
2877 | |||
2878 | defcsw->con_startup(); | ||
2879 | con_back->flag |= CON_DRIVER_FLAG_INIT; | ||
2880 | /* | ||
2881 | * vgacon may change the default driver to point | ||
2882 | * to dummycon, we restore it here... | ||
2883 | */ | ||
2884 | conswitchp = defconsw; | ||
2885 | } | ||
2886 | |||
2887 | if (!con_is_bound(csw)) | ||
2888 | con_driver->flag &= ~CON_DRIVER_FLAG_INIT; | ||
2736 | 2889 | ||
2890 | release_console_sem(); | ||
2891 | /* ignore return value, binding should not fail */ | ||
2892 | bind_con_driver(defcsw, first, last, deflt); | ||
2893 | err: | ||
2737 | module_put(owner); | 2894 | module_put(owner); |
2895 | return retval; | ||
2896 | |||
2897 | } | ||
2898 | |||
2899 | static int vt_bind(struct con_driver *con) | ||
2900 | { | ||
2901 | const struct consw *defcsw = NULL, *csw = NULL; | ||
2902 | int i, more = 1, first = -1, last = -1, deflt = 0; | ||
2903 | |||
2904 | if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) || | ||
2905 | con_is_graphics(con->con, con->first, con->last)) | ||
2906 | goto err; | ||
2907 | |||
2908 | csw = con->con; | ||
2909 | |||
2910 | for (i = 0; i < MAX_NR_CON_DRIVER; i++) { | ||
2911 | struct con_driver *con = ®istered_con_driver[i]; | ||
2912 | |||
2913 | if (con->con && !(con->flag & CON_DRIVER_FLAG_MODULE)) { | ||
2914 | defcsw = con->con; | ||
2915 | break; | ||
2916 | } | ||
2917 | } | ||
2918 | |||
2919 | if (!defcsw) | ||
2920 | goto err; | ||
2921 | |||
2922 | while (more) { | ||
2923 | more = 0; | ||
2924 | |||
2925 | for (i = con->first; i <= con->last; i++) { | ||
2926 | if (con_driver_map[i] == defcsw) { | ||
2927 | if (first == -1) | ||
2928 | first = i; | ||
2929 | last = i; | ||
2930 | more = 1; | ||
2931 | } else if (first != -1) | ||
2932 | break; | ||
2933 | } | ||
2934 | |||
2935 | if (first == 0 && last == MAX_NR_CONSOLES -1) | ||
2936 | deflt = 1; | ||
2937 | |||
2938 | if (first != -1) | ||
2939 | bind_con_driver(csw, first, last, deflt); | ||
2940 | |||
2941 | first = -1; | ||
2942 | last = -1; | ||
2943 | deflt = 0; | ||
2944 | } | ||
2945 | |||
2946 | err: | ||
2738 | return 0; | 2947 | return 0; |
2739 | } | 2948 | } |
2740 | 2949 | ||
2741 | void give_up_console(const struct consw *csw) | 2950 | static int vt_unbind(struct con_driver *con) |
2951 | { | ||
2952 | const struct consw *csw = NULL; | ||
2953 | int i, more = 1, first = -1, last = -1, deflt = 0; | ||
2954 | |||
2955 | if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) || | ||
2956 | con_is_graphics(con->con, con->first, con->last)) | ||
2957 | goto err; | ||
2958 | |||
2959 | csw = con->con; | ||
2960 | |||
2961 | while (more) { | ||
2962 | more = 0; | ||
2963 | |||
2964 | for (i = con->first; i <= con->last; i++) { | ||
2965 | if (con_driver_map[i] == csw) { | ||
2966 | if (first == -1) | ||
2967 | first = i; | ||
2968 | last = i; | ||
2969 | more = 1; | ||
2970 | } else if (first != -1) | ||
2971 | break; | ||
2972 | } | ||
2973 | |||
2974 | if (first == 0 && last == MAX_NR_CONSOLES -1) | ||
2975 | deflt = 1; | ||
2976 | |||
2977 | if (first != -1) | ||
2978 | unbind_con_driver(csw, first, last, deflt); | ||
2979 | |||
2980 | first = -1; | ||
2981 | last = -1; | ||
2982 | deflt = 0; | ||
2983 | } | ||
2984 | |||
2985 | err: | ||
2986 | return 0; | ||
2987 | } | ||
2988 | #else | ||
2989 | static inline int vt_bind(struct con_driver *con) | ||
2990 | { | ||
2991 | return 0; | ||
2992 | } | ||
2993 | static inline int vt_unbind(struct con_driver *con) | ||
2994 | { | ||
2995 | return 0; | ||
2996 | } | ||
2997 | #endif /* CONFIG_VT_HW_CONSOLE_BINDING */ | ||
2998 | |||
2999 | static ssize_t store_bind(struct class_device *class_device, | ||
3000 | const char *buf, size_t count) | ||
3001 | { | ||
3002 | struct con_driver *con = class_get_devdata(class_device); | ||
3003 | int bind = simple_strtoul(buf, NULL, 0); | ||
3004 | |||
3005 | if (bind) | ||
3006 | vt_bind(con); | ||
3007 | else | ||
3008 | vt_unbind(con); | ||
3009 | |||
3010 | return count; | ||
3011 | } | ||
3012 | |||
3013 | static ssize_t show_bind(struct class_device *class_device, char *buf) | ||
3014 | { | ||
3015 | struct con_driver *con = class_get_devdata(class_device); | ||
3016 | int bind = con_is_bound(con->con); | ||
3017 | |||
3018 | return snprintf(buf, PAGE_SIZE, "%i\n", bind); | ||
3019 | } | ||
3020 | |||
3021 | static ssize_t show_name(struct class_device *class_device, char *buf) | ||
3022 | { | ||
3023 | struct con_driver *con = class_get_devdata(class_device); | ||
3024 | |||
3025 | return snprintf(buf, PAGE_SIZE, "%s %s\n", | ||
3026 | (con->flag & CON_DRIVER_FLAG_MODULE) ? "(M)" : "(S)", | ||
3027 | con->desc); | ||
3028 | |||
3029 | } | ||
3030 | |||
3031 | static struct class_device_attribute class_device_attrs[] = { | ||
3032 | __ATTR(bind, S_IRUGO|S_IWUSR, show_bind, store_bind), | ||
3033 | __ATTR(name, S_IRUGO, show_name, NULL), | ||
3034 | }; | ||
3035 | |||
3036 | static int vtconsole_init_class_device(struct con_driver *con) | ||
3037 | { | ||
3038 | int i; | ||
3039 | |||
3040 | class_set_devdata(con->class_dev, con); | ||
3041 | for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) | ||
3042 | class_device_create_file(con->class_dev, | ||
3043 | &class_device_attrs[i]); | ||
3044 | |||
3045 | return 0; | ||
3046 | } | ||
3047 | |||
3048 | static void vtconsole_deinit_class_device(struct con_driver *con) | ||
2742 | { | 3049 | { |
2743 | int i; | 3050 | int i; |
2744 | 3051 | ||
2745 | for(i = 0; i < MAX_NR_CONSOLES; i++) | 3052 | for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) |
3053 | class_device_remove_file(con->class_dev, | ||
3054 | &class_device_attrs[i]); | ||
3055 | } | ||
3056 | |||
3057 | /** | ||
3058 | * con_is_bound - checks if driver is bound to the console | ||
3059 | * @csw: console driver | ||
3060 | * | ||
3061 | * RETURNS: zero if unbound, nonzero if bound | ||
3062 | * | ||
3063 | * Drivers can call this and if zero, they should release | ||
3064 | * all resources allocated on con_startup() | ||
3065 | */ | ||
3066 | int con_is_bound(const struct consw *csw) | ||
3067 | { | ||
3068 | int i, bound = 0; | ||
3069 | |||
3070 | for (i = 0; i < MAX_NR_CONSOLES; i++) { | ||
2746 | if (con_driver_map[i] == csw) { | 3071 | if (con_driver_map[i] == csw) { |
2747 | module_put(csw->owner); | 3072 | bound = 1; |
2748 | con_driver_map[i] = NULL; | 3073 | break; |
3074 | } | ||
3075 | } | ||
3076 | |||
3077 | return bound; | ||
3078 | } | ||
3079 | EXPORT_SYMBOL(con_is_bound); | ||
3080 | |||
3081 | /** | ||
3082 | * register_con_driver - register console driver to console layer | ||
3083 | * @csw: console driver | ||
3084 | * @first: the first console to take over, minimum value is 0 | ||
3085 | * @last: the last console to take over, maximum value is MAX_NR_CONSOLES -1 | ||
3086 | * | ||
3087 | * DESCRIPTION: This function registers a console driver which can later | ||
3088 | * bind to a range of consoles specified by @first and @last. It will | ||
3089 | * also initialize the console driver by calling con_startup(). | ||
3090 | */ | ||
3091 | int register_con_driver(const struct consw *csw, int first, int last) | ||
3092 | { | ||
3093 | struct module *owner = csw->owner; | ||
3094 | struct con_driver *con_driver; | ||
3095 | const char *desc; | ||
3096 | int i, retval = 0; | ||
3097 | |||
3098 | if (!try_module_get(owner)) | ||
3099 | return -ENODEV; | ||
3100 | |||
3101 | acquire_console_sem(); | ||
3102 | |||
3103 | for (i = 0; i < MAX_NR_CON_DRIVER; i++) { | ||
3104 | con_driver = ®istered_con_driver[i]; | ||
3105 | |||
3106 | /* already registered */ | ||
3107 | if (con_driver->con == csw) | ||
3108 | retval = -EINVAL; | ||
3109 | } | ||
3110 | |||
3111 | if (retval) | ||
3112 | goto err; | ||
3113 | |||
3114 | desc = csw->con_startup(); | ||
3115 | |||
3116 | if (!desc) | ||
3117 | goto err; | ||
3118 | |||
3119 | retval = -EINVAL; | ||
3120 | |||
3121 | for (i = 0; i < MAX_NR_CON_DRIVER; i++) { | ||
3122 | con_driver = ®istered_con_driver[i]; | ||
3123 | |||
3124 | if (con_driver->con == NULL) { | ||
3125 | con_driver->con = csw; | ||
3126 | con_driver->desc = desc; | ||
3127 | con_driver->node = i; | ||
3128 | con_driver->flag = CON_DRIVER_FLAG_MODULE | | ||
3129 | CON_DRIVER_FLAG_INIT; | ||
3130 | con_driver->first = first; | ||
3131 | con_driver->last = last; | ||
3132 | retval = 0; | ||
3133 | break; | ||
3134 | } | ||
3135 | } | ||
3136 | |||
3137 | if (retval) | ||
3138 | goto err; | ||
3139 | |||
3140 | con_driver->class_dev = class_device_create(vtconsole_class, NULL, | ||
3141 | MKDEV(0, con_driver->node), | ||
3142 | NULL, "vtcon%i", | ||
3143 | con_driver->node); | ||
3144 | |||
3145 | if (IS_ERR(con_driver->class_dev)) { | ||
3146 | printk(KERN_WARNING "Unable to create class_device for %s; " | ||
3147 | "errno = %ld\n", con_driver->desc, | ||
3148 | PTR_ERR(con_driver->class_dev)); | ||
3149 | con_driver->class_dev = NULL; | ||
3150 | } else { | ||
3151 | vtconsole_init_class_device(con_driver); | ||
3152 | } | ||
3153 | err: | ||
3154 | release_console_sem(); | ||
3155 | module_put(owner); | ||
3156 | return retval; | ||
3157 | } | ||
3158 | EXPORT_SYMBOL(register_con_driver); | ||
3159 | |||
3160 | /** | ||
3161 | * unregister_con_driver - unregister console driver from console layer | ||
3162 | * @csw: console driver | ||
3163 | * | ||
3164 | * DESCRIPTION: All drivers that registers to the console layer must | ||
3165 | * call this function upon exit, or if the console driver is in a state | ||
3166 | * where it won't be able to handle console services, such as the | ||
3167 | * framebuffer console without loaded framebuffer drivers. | ||
3168 | * | ||
3169 | * The driver must unbind first prior to unregistration. | ||
3170 | */ | ||
3171 | int unregister_con_driver(const struct consw *csw) | ||
3172 | { | ||
3173 | int i, retval = -ENODEV; | ||
3174 | |||
3175 | acquire_console_sem(); | ||
3176 | |||
3177 | /* cannot unregister a bound driver */ | ||
3178 | if (con_is_bound(csw)) | ||
3179 | goto err; | ||
3180 | |||
3181 | for (i = 0; i < MAX_NR_CON_DRIVER; i++) { | ||
3182 | struct con_driver *con_driver = ®istered_con_driver[i]; | ||
3183 | |||
3184 | if (con_driver->con == csw && | ||
3185 | con_driver->flag & CON_DRIVER_FLAG_MODULE) { | ||
3186 | vtconsole_deinit_class_device(con_driver); | ||
3187 | class_device_destroy(vtconsole_class, | ||
3188 | MKDEV(0, con_driver->node)); | ||
3189 | con_driver->con = NULL; | ||
3190 | con_driver->desc = NULL; | ||
3191 | con_driver->class_dev = NULL; | ||
3192 | con_driver->node = 0; | ||
3193 | con_driver->flag = 0; | ||
3194 | con_driver->first = 0; | ||
3195 | con_driver->last = 0; | ||
3196 | retval = 0; | ||
3197 | break; | ||
3198 | } | ||
3199 | } | ||
3200 | err: | ||
3201 | release_console_sem(); | ||
3202 | return retval; | ||
3203 | } | ||
3204 | EXPORT_SYMBOL(unregister_con_driver); | ||
3205 | |||
3206 | /* | ||
3207 | * If we support more console drivers, this function is used | ||
3208 | * when a driver wants to take over some existing consoles | ||
3209 | * and become default driver for newly opened ones. | ||
3210 | * | ||
3211 | * take_over_console is basically a register followed by unbind | ||
3212 | */ | ||
3213 | int take_over_console(const struct consw *csw, int first, int last, int deflt) | ||
3214 | { | ||
3215 | int err; | ||
3216 | |||
3217 | err = register_con_driver(csw, first, last); | ||
3218 | |||
3219 | if (!err) | ||
3220 | bind_con_driver(csw, first, last, deflt); | ||
3221 | |||
3222 | return err; | ||
3223 | } | ||
3224 | |||
3225 | /* | ||
3226 | * give_up_console is a wrapper to unregister_con_driver. It will only | ||
3227 | * work if driver is fully unbound. | ||
3228 | */ | ||
3229 | void give_up_console(const struct consw *csw) | ||
3230 | { | ||
3231 | unregister_con_driver(csw); | ||
3232 | } | ||
3233 | |||
3234 | static int __init vtconsole_class_init(void) | ||
3235 | { | ||
3236 | int i; | ||
3237 | |||
3238 | vtconsole_class = class_create(THIS_MODULE, "vtconsole"); | ||
3239 | if (IS_ERR(vtconsole_class)) { | ||
3240 | printk(KERN_WARNING "Unable to create vt console class; " | ||
3241 | "errno = %ld\n", PTR_ERR(vtconsole_class)); | ||
3242 | vtconsole_class = NULL; | ||
3243 | } | ||
3244 | |||
3245 | /* Add system drivers to sysfs */ | ||
3246 | for (i = 0; i < MAX_NR_CON_DRIVER; i++) { | ||
3247 | struct con_driver *con = ®istered_con_driver[i]; | ||
3248 | |||
3249 | if (con->con && !con->class_dev) { | ||
3250 | con->class_dev = | ||
3251 | class_device_create(vtconsole_class, NULL, | ||
3252 | MKDEV(0, con->node), NULL, | ||
3253 | "vtcon%i", con->node); | ||
3254 | |||
3255 | if (IS_ERR(con->class_dev)) { | ||
3256 | printk(KERN_WARNING "Unable to create " | ||
3257 | "class_device for %s; errno = %ld\n", | ||
3258 | con->desc, PTR_ERR(con->class_dev)); | ||
3259 | con->class_dev = NULL; | ||
3260 | } else { | ||
3261 | vtconsole_init_class_device(con); | ||
3262 | } | ||
2749 | } | 3263 | } |
3264 | } | ||
3265 | |||
3266 | return 0; | ||
2750 | } | 3267 | } |
3268 | postcore_initcall(vtconsole_class_init); | ||
2751 | 3269 | ||
2752 | #endif | 3270 | #endif |
2753 | 3271 | ||
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile new file mode 100644 index 000000000000..a52225470225 --- /dev/null +++ b/drivers/clocksource/Makefile | |||
@@ -0,0 +1,3 @@ | |||
1 | obj-$(CONFIG_X86_CYCLONE_TIMER) += cyclone.o | ||
2 | obj-$(CONFIG_X86_PM_TIMER) += acpi_pm.o | ||
3 | obj-$(CONFIG_SCx200HR_TIMER) += scx200_hrt.o | ||
diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c new file mode 100644 index 000000000000..7ad3be8c0f49 --- /dev/null +++ b/drivers/clocksource/acpi_pm.c | |||
@@ -0,0 +1,177 @@ | |||
1 | /* | ||
2 | * linux/drivers/clocksource/acpi_pm.c | ||
3 | * | ||
4 | * This file contains the ACPI PM based clocksource. | ||
5 | * | ||
6 | * This code was largely moved from the i386 timer_pm.c file | ||
7 | * which was (C) Dominik Brodowski <linux@brodo.de> 2003 | ||
8 | * and contained the following comments: | ||
9 | * | ||
10 | * Driver to use the Power Management Timer (PMTMR) available in some | ||
11 | * southbridges as primary timing source for the Linux kernel. | ||
12 | * | ||
13 | * Based on parts of linux/drivers/acpi/hardware/hwtimer.c, timer_pit.c, | ||
14 | * timer_hpet.c, and on Arjan van de Ven's implementation for 2.4. | ||
15 | * | ||
16 | * This file is licensed under the GPL v2. | ||
17 | */ | ||
18 | |||
19 | #include <linux/clocksource.h> | ||
20 | #include <linux/errno.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/pci.h> | ||
23 | #include <asm/io.h> | ||
24 | |||
25 | /* Number of PMTMR ticks expected during calibration run */ | ||
26 | #define PMTMR_TICKS_PER_SEC 3579545 | ||
27 | |||
28 | /* | ||
29 | * The I/O port the PMTMR resides at. | ||
30 | * The location is detected during setup_arch(), | ||
31 | * in arch/i386/acpi/boot.c | ||
32 | */ | ||
33 | u32 pmtmr_ioport __read_mostly; | ||
34 | |||
35 | #define ACPI_PM_MASK CLOCKSOURCE_MASK(24) /* limit it to 24 bits */ | ||
36 | |||
37 | static inline u32 read_pmtmr(void) | ||
38 | { | ||
39 | /* mask the output to 24 bits */ | ||
40 | return inl(pmtmr_ioport) & ACPI_PM_MASK; | ||
41 | } | ||
42 | |||
43 | static cycle_t acpi_pm_read_verified(void) | ||
44 | { | ||
45 | u32 v1 = 0, v2 = 0, v3 = 0; | ||
46 | |||
47 | /* | ||
48 | * It has been reported that because of various broken | ||
49 | * chipsets (ICH4, PIIX4 and PIIX4E) where the ACPI PM clock | ||
50 | * source is not latched, you must read it multiple | ||
51 | * times to ensure a safe value is read: | ||
52 | */ | ||
53 | do { | ||
54 | v1 = read_pmtmr(); | ||
55 | v2 = read_pmtmr(); | ||
56 | v3 = read_pmtmr(); | ||
57 | } while ((v1 > v2 && v1 < v3) || (v2 > v3 && v2 < v1) | ||
58 | || (v3 > v1 && v3 < v2)); | ||
59 | |||
60 | return (cycle_t)v2; | ||
61 | } | ||
62 | |||
63 | static cycle_t acpi_pm_read(void) | ||
64 | { | ||
65 | return (cycle_t)read_pmtmr(); | ||
66 | } | ||
67 | |||
68 | static struct clocksource clocksource_acpi_pm = { | ||
69 | .name = "acpi_pm", | ||
70 | .rating = 200, | ||
71 | .read = acpi_pm_read, | ||
72 | .mask = (cycle_t)ACPI_PM_MASK, | ||
73 | .mult = 0, /*to be caluclated*/ | ||
74 | .shift = 22, | ||
75 | .is_continuous = 1, | ||
76 | }; | ||
77 | |||
78 | |||
79 | #ifdef CONFIG_PCI | ||
80 | static int acpi_pm_good; | ||
81 | static int __init acpi_pm_good_setup(char *__str) | ||
82 | { | ||
83 | acpi_pm_good = 1; | ||
84 | return 1; | ||
85 | } | ||
86 | __setup("acpi_pm_good", acpi_pm_good_setup); | ||
87 | |||
88 | static inline void acpi_pm_need_workaround(void) | ||
89 | { | ||
90 | clocksource_acpi_pm.read = acpi_pm_read_verified; | ||
91 | clocksource_acpi_pm.rating = 110; | ||
92 | } | ||
93 | |||
94 | /* | ||
95 | * PIIX4 Errata: | ||
96 | * | ||
97 | * The power management timer may return improper results when read. | ||
98 | * Although the timer value settles properly after incrementing, | ||
99 | * while incrementing there is a 3 ns window every 69.8 ns where the | ||
100 | * timer value is indeterminate (a 4.2% chance that the data will be | ||
101 | * incorrect when read). As a result, the ACPI free running count up | ||
102 | * timer specification is violated due to erroneous reads. | ||
103 | */ | ||
104 | static void __devinit acpi_pm_check_blacklist(struct pci_dev *dev) | ||
105 | { | ||
106 | u8 rev; | ||
107 | |||
108 | if (acpi_pm_good) | ||
109 | return; | ||
110 | |||
111 | pci_read_config_byte(dev, PCI_REVISION_ID, &rev); | ||
112 | /* the bug has been fixed in PIIX4M */ | ||
113 | if (rev < 3) { | ||
114 | printk(KERN_WARNING "* Found PM-Timer Bug on the chipset." | ||
115 | " Due to workarounds for a bug,\n" | ||
116 | "* this clock source is slow. Consider trying" | ||
117 | " other clock sources\n"); | ||
118 | |||
119 | acpi_pm_need_workaround(); | ||
120 | } | ||
121 | } | ||
122 | DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, | ||
123 | acpi_pm_check_blacklist); | ||
124 | |||
125 | static void __devinit acpi_pm_check_graylist(struct pci_dev *dev) | ||
126 | { | ||
127 | if (acpi_pm_good) | ||
128 | return; | ||
129 | |||
130 | printk(KERN_WARNING "* The chipset may have PM-Timer Bug. Due to" | ||
131 | " workarounds for a bug,\n" | ||
132 | "* this clock source is slow. If you are sure your timer" | ||
133 | " does not have\n" | ||
134 | "* this bug, please use \"acpi_pm_good\" to disable the" | ||
135 | " workaround\n"); | ||
136 | |||
137 | acpi_pm_need_workaround(); | ||
138 | } | ||
139 | DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, | ||
140 | acpi_pm_check_graylist); | ||
141 | #endif | ||
142 | |||
143 | |||
144 | static int __init init_acpi_pm_clocksource(void) | ||
145 | { | ||
146 | u32 value1, value2; | ||
147 | unsigned int i; | ||
148 | |||
149 | if (!pmtmr_ioport) | ||
150 | return -ENODEV; | ||
151 | |||
152 | clocksource_acpi_pm.mult = clocksource_hz2mult(PMTMR_TICKS_PER_SEC, | ||
153 | clocksource_acpi_pm.shift); | ||
154 | |||
155 | /* "verify" this timing source: */ | ||
156 | value1 = read_pmtmr(); | ||
157 | for (i = 0; i < 10000; i++) { | ||
158 | value2 = read_pmtmr(); | ||
159 | if (value2 == value1) | ||
160 | continue; | ||
161 | if (value2 > value1) | ||
162 | goto pm_good; | ||
163 | if ((value2 < value1) && ((value2) < 0xFFF)) | ||
164 | goto pm_good; | ||
165 | printk(KERN_INFO "PM-Timer had inconsistent results:" | ||
166 | " 0x%#x, 0x%#x - aborting.\n", value1, value2); | ||
167 | return -EINVAL; | ||
168 | } | ||
169 | printk(KERN_INFO "PM-Timer had no reasonable result:" | ||
170 | " 0x%#x - aborting.\n", value1); | ||
171 | return -ENODEV; | ||
172 | |||
173 | pm_good: | ||
174 | return clocksource_register(&clocksource_acpi_pm); | ||
175 | } | ||
176 | |||
177 | module_init(init_acpi_pm_clocksource); | ||
diff --git a/drivers/clocksource/cyclone.c b/drivers/clocksource/cyclone.c new file mode 100644 index 000000000000..bf4d3d50d1c4 --- /dev/null +++ b/drivers/clocksource/cyclone.c | |||
@@ -0,0 +1,119 @@ | |||
1 | #include <linux/clocksource.h> | ||
2 | #include <linux/string.h> | ||
3 | #include <linux/errno.h> | ||
4 | #include <linux/timex.h> | ||
5 | #include <linux/init.h> | ||
6 | |||
7 | #include <asm/pgtable.h> | ||
8 | #include <asm/io.h> | ||
9 | |||
10 | #include "mach_timer.h" | ||
11 | |||
12 | #define CYCLONE_CBAR_ADDR 0xFEB00CD0 /* base address ptr */ | ||
13 | #define CYCLONE_PMCC_OFFSET 0x51A0 /* offset to control register */ | ||
14 | #define CYCLONE_MPCS_OFFSET 0x51A8 /* offset to select register */ | ||
15 | #define CYCLONE_MPMC_OFFSET 0x51D0 /* offset to count register */ | ||
16 | #define CYCLONE_TIMER_FREQ 99780000 /* 100Mhz, but not really */ | ||
17 | #define CYCLONE_TIMER_MASK CLOCKSOURCE_MASK(32) /* 32 bit mask */ | ||
18 | |||
19 | int use_cyclone = 0; | ||
20 | static void __iomem *cyclone_ptr; | ||
21 | |||
22 | static cycle_t read_cyclone(void) | ||
23 | { | ||
24 | return (cycle_t)readl(cyclone_ptr); | ||
25 | } | ||
26 | |||
27 | static struct clocksource clocksource_cyclone = { | ||
28 | .name = "cyclone", | ||
29 | .rating = 250, | ||
30 | .read = read_cyclone, | ||
31 | .mask = CYCLONE_TIMER_MASK, | ||
32 | .mult = 10, | ||
33 | .shift = 0, | ||
34 | .is_continuous = 1, | ||
35 | }; | ||
36 | |||
37 | static int __init init_cyclone_clocksource(void) | ||
38 | { | ||
39 | unsigned long base; /* saved value from CBAR */ | ||
40 | unsigned long offset; | ||
41 | u32 __iomem* volatile cyclone_timer; /* Cyclone MPMC0 register */ | ||
42 | u32 __iomem* reg; | ||
43 | int i; | ||
44 | |||
45 | /* make sure we're on a summit box: */ | ||
46 | if (!use_cyclone) | ||
47 | return -ENODEV; | ||
48 | |||
49 | printk(KERN_INFO "Summit chipset: Starting Cyclone Counter.\n"); | ||
50 | |||
51 | /* find base address: */ | ||
52 | offset = CYCLONE_CBAR_ADDR; | ||
53 | reg = ioremap_nocache(offset, sizeof(reg)); | ||
54 | if (!reg) { | ||
55 | printk(KERN_ERR "Summit chipset: Could not find valid CBAR register.\n"); | ||
56 | return -ENODEV; | ||
57 | } | ||
58 | /* even on 64bit systems, this is only 32bits: */ | ||
59 | base = readl(reg); | ||
60 | if (!base) { | ||
61 | printk(KERN_ERR "Summit chipset: Could not find valid CBAR value.\n"); | ||
62 | return -ENODEV; | ||
63 | } | ||
64 | iounmap(reg); | ||
65 | |||
66 | /* setup PMCC: */ | ||
67 | offset = base + CYCLONE_PMCC_OFFSET; | ||
68 | reg = ioremap_nocache(offset, sizeof(reg)); | ||
69 | if (!reg) { | ||
70 | printk(KERN_ERR "Summit chipset: Could not find valid PMCC register.\n"); | ||
71 | return -ENODEV; | ||
72 | } | ||
73 | writel(0x00000001,reg); | ||
74 | iounmap(reg); | ||
75 | |||
76 | /* setup MPCS: */ | ||
77 | offset = base + CYCLONE_MPCS_OFFSET; | ||
78 | reg = ioremap_nocache(offset, sizeof(reg)); | ||
79 | if (!reg) { | ||
80 | printk(KERN_ERR "Summit chipset: Could not find valid MPCS register.\n"); | ||
81 | return -ENODEV; | ||
82 | } | ||
83 | writel(0x00000001,reg); | ||
84 | iounmap(reg); | ||
85 | |||
86 | /* map in cyclone_timer: */ | ||
87 | offset = base + CYCLONE_MPMC_OFFSET; | ||
88 | cyclone_timer = ioremap_nocache(offset, sizeof(u64)); | ||
89 | if (!cyclone_timer) { | ||
90 | printk(KERN_ERR "Summit chipset: Could not find valid MPMC register.\n"); | ||
91 | return -ENODEV; | ||
92 | } | ||
93 | |||
94 | /* quick test to make sure its ticking: */ | ||
95 | for (i = 0; i < 3; i++){ | ||
96 | u32 old = readl(cyclone_timer); | ||
97 | int stall = 100; | ||
98 | |||
99 | while (stall--) | ||
100 | barrier(); | ||
101 | |||
102 | if (readl(cyclone_timer) == old) { | ||
103 | printk(KERN_ERR "Summit chipset: Counter not counting! DISABLED\n"); | ||
104 | iounmap(cyclone_timer); | ||
105 | cyclone_timer = NULL; | ||
106 | return -ENODEV; | ||
107 | } | ||
108 | } | ||
109 | cyclone_ptr = cyclone_timer; | ||
110 | |||
111 | /* sort out mult/shift values: */ | ||
112 | clocksource_cyclone.shift = 22; | ||
113 | clocksource_cyclone.mult = clocksource_hz2mult(CYCLONE_TIMER_FREQ, | ||
114 | clocksource_cyclone.shift); | ||
115 | |||
116 | return clocksource_register(&clocksource_cyclone); | ||
117 | } | ||
118 | |||
119 | module_init(init_cyclone_clocksource); | ||
diff --git a/drivers/clocksource/scx200_hrt.c b/drivers/clocksource/scx200_hrt.c new file mode 100644 index 000000000000..d418b8297211 --- /dev/null +++ b/drivers/clocksource/scx200_hrt.c | |||
@@ -0,0 +1,101 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2006 Jim Cromie | ||
3 | * | ||
4 | * This is a clocksource driver for the Geode SCx200's 1 or 27 MHz | ||
5 | * high-resolution timer. The Geode SC-1100 (at least) has a buggy | ||
6 | * time stamp counter (TSC), which loses time unless 'idle=poll' is | ||
7 | * given as a boot-arg. In its absence, the Generic Timekeeping code | ||
8 | * will detect and de-rate the bad TSC, allowing this timer to take | ||
9 | * over timekeeping duties. | ||
10 | * | ||
11 | * Based on work by John Stultz, and Ted Phelps (in a 2.6.12-rc6 patch) | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or | ||
14 | * modify it under the terms of the GNU General Public License as | ||
15 | * published by the Free Software Foundation; either version 2 of the | ||
16 | * License, or (at your option) any later version. | ||
17 | */ | ||
18 | |||
19 | #include <linux/clocksource.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/ioport.h> | ||
23 | #include <linux/scx200.h> | ||
24 | |||
25 | #define NAME "scx200_hrt" | ||
26 | |||
27 | static int mhz27; | ||
28 | module_param(mhz27, int, 0); /* load time only */ | ||
29 | MODULE_PARM_DESC(mhz27, "count at 27.0 MHz (default is 1.0 MHz)"); | ||
30 | |||
31 | static int ppm; | ||
32 | module_param(ppm, int, 0); /* load time only */ | ||
33 | MODULE_PARM_DESC(ppm, "+-adjust to actual XO freq (ppm)"); | ||
34 | |||
35 | /* HiRes Timer configuration register address */ | ||
36 | #define SCx200_TMCNFG_OFFSET (SCx200_TIMER_OFFSET + 5) | ||
37 | |||
38 | /* and config settings */ | ||
39 | #define HR_TMEN (1 << 0) /* timer interrupt enable */ | ||
40 | #define HR_TMCLKSEL (1 << 1) /* 1|0 counts at 27|1 MHz */ | ||
41 | #define HR_TM27MPD (1 << 2) /* 1 turns off input clock (power-down) */ | ||
42 | |||
43 | /* The base timer frequency, * 27 if selected */ | ||
44 | #define HRT_FREQ 1000000 | ||
45 | |||
46 | static cycle_t read_hrt(void) | ||
47 | { | ||
48 | /* Read the timer value */ | ||
49 | return (cycle_t) inl(scx200_cb_base + SCx200_TIMER_OFFSET); | ||
50 | } | ||
51 | |||
52 | #define HRT_SHIFT_1 22 | ||
53 | #define HRT_SHIFT_27 26 | ||
54 | |||
55 | static struct clocksource cs_hrt = { | ||
56 | .name = "scx200_hrt", | ||
57 | .rating = 250, | ||
58 | .read = read_hrt, | ||
59 | .mask = CLOCKSOURCE_MASK(32), | ||
60 | .is_continuous = 1, | ||
61 | /* mult, shift are set based on mhz27 flag */ | ||
62 | }; | ||
63 | |||
64 | static int __init init_hrt_clocksource(void) | ||
65 | { | ||
66 | /* Make sure scx200 has initializedd the configuration block */ | ||
67 | if (!scx200_cb_present()) | ||
68 | return -ENODEV; | ||
69 | |||
70 | /* Reserve the timer's ISA io-region for ourselves */ | ||
71 | if (!request_region(scx200_cb_base + SCx200_TIMER_OFFSET, | ||
72 | SCx200_TIMER_SIZE, | ||
73 | "NatSemi SCx200 High-Resolution Timer")) { | ||
74 | printk(KERN_WARNING NAME ": unable to lock timer region\n"); | ||
75 | return -ENODEV; | ||
76 | } | ||
77 | |||
78 | /* write timer config */ | ||
79 | outb(HR_TMEN | (mhz27) ? HR_TMCLKSEL : 0, | ||
80 | scx200_cb_base + SCx200_TMCNFG_OFFSET); | ||
81 | |||
82 | if (mhz27) { | ||
83 | cs_hrt.shift = HRT_SHIFT_27; | ||
84 | cs_hrt.mult = clocksource_hz2mult((HRT_FREQ + ppm) * 27, | ||
85 | cs_hrt.shift); | ||
86 | } else { | ||
87 | cs_hrt.shift = HRT_SHIFT_1; | ||
88 | cs_hrt.mult = clocksource_hz2mult(HRT_FREQ + ppm, | ||
89 | cs_hrt.shift); | ||
90 | } | ||
91 | printk(KERN_INFO "enabling scx200 high-res timer (%s MHz +%d ppm)\n", | ||
92 | mhz27 ? "27":"1", ppm); | ||
93 | |||
94 | return clocksource_register(&cs_hrt); | ||
95 | } | ||
96 | |||
97 | module_init(init_hrt_clocksource); | ||
98 | |||
99 | MODULE_AUTHOR("Jim Cromie <jim.cromie@gmail.com>"); | ||
100 | MODULE_DESCRIPTION("clocksource on SCx200 HiRes Timer"); | ||
101 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 44d1eca83a72..35e0b9ceecf7 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c | |||
@@ -1497,6 +1497,7 @@ int cpufreq_update_policy(unsigned int cpu) | |||
1497 | } | 1497 | } |
1498 | EXPORT_SYMBOL(cpufreq_update_policy); | 1498 | EXPORT_SYMBOL(cpufreq_update_policy); |
1499 | 1499 | ||
1500 | #ifdef CONFIG_HOTPLUG_CPU | ||
1500 | static int cpufreq_cpu_callback(struct notifier_block *nfb, | 1501 | static int cpufreq_cpu_callback(struct notifier_block *nfb, |
1501 | unsigned long action, void *hcpu) | 1502 | unsigned long action, void *hcpu) |
1502 | { | 1503 | { |
@@ -1532,10 +1533,11 @@ static int cpufreq_cpu_callback(struct notifier_block *nfb, | |||
1532 | return NOTIFY_OK; | 1533 | return NOTIFY_OK; |
1533 | } | 1534 | } |
1534 | 1535 | ||
1535 | static struct notifier_block cpufreq_cpu_notifier = | 1536 | static struct notifier_block __cpuinitdata cpufreq_cpu_notifier = |
1536 | { | 1537 | { |
1537 | .notifier_call = cpufreq_cpu_callback, | 1538 | .notifier_call = cpufreq_cpu_callback, |
1538 | }; | 1539 | }; |
1540 | #endif /* CONFIG_HOTPLUG_CPU */ | ||
1539 | 1541 | ||
1540 | /********************************************************************* | 1542 | /********************************************************************* |
1541 | * REGISTER / UNREGISTER CPUFREQ DRIVER * | 1543 | * REGISTER / UNREGISTER CPUFREQ DRIVER * |
@@ -1596,7 +1598,7 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data) | |||
1596 | } | 1598 | } |
1597 | 1599 | ||
1598 | if (!ret) { | 1600 | if (!ret) { |
1599 | register_cpu_notifier(&cpufreq_cpu_notifier); | 1601 | register_hotcpu_notifier(&cpufreq_cpu_notifier); |
1600 | dprintk("driver %s up and running\n", driver_data->name); | 1602 | dprintk("driver %s up and running\n", driver_data->name); |
1601 | cpufreq_debug_enable_ratelimit(); | 1603 | cpufreq_debug_enable_ratelimit(); |
1602 | } | 1604 | } |
@@ -1628,7 +1630,7 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver) | |||
1628 | dprintk("unregistering driver %s\n", driver->name); | 1630 | dprintk("unregistering driver %s\n", driver->name); |
1629 | 1631 | ||
1630 | sysdev_driver_unregister(&cpu_sysdev_class, &cpufreq_sysdev_driver); | 1632 | sysdev_driver_unregister(&cpu_sysdev_class, &cpufreq_sysdev_driver); |
1631 | unregister_cpu_notifier(&cpufreq_cpu_notifier); | 1633 | unregister_hotcpu_notifier(&cpufreq_cpu_notifier); |
1632 | 1634 | ||
1633 | spin_lock_irqsave(&cpufreq_driver_lock, flags); | 1635 | spin_lock_irqsave(&cpufreq_driver_lock, flags); |
1634 | cpufreq_driver = NULL; | 1636 | cpufreq_driver = NULL; |
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index c576c0b3f452..145061b8472a 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c | |||
@@ -350,7 +350,7 @@ __init cpufreq_stats_init(void) | |||
350 | return ret; | 350 | return ret; |
351 | } | 351 | } |
352 | 352 | ||
353 | register_cpu_notifier(&cpufreq_stat_cpu_notifier); | 353 | register_hotcpu_notifier(&cpufreq_stat_cpu_notifier); |
354 | lock_cpu_hotplug(); | 354 | lock_cpu_hotplug(); |
355 | for_each_online_cpu(cpu) { | 355 | for_each_online_cpu(cpu) { |
356 | cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier, CPU_ONLINE, | 356 | cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier, CPU_ONLINE, |
@@ -368,7 +368,7 @@ __exit cpufreq_stats_exit(void) | |||
368 | CPUFREQ_POLICY_NOTIFIER); | 368 | CPUFREQ_POLICY_NOTIFIER); |
369 | cpufreq_unregister_notifier(¬ifier_trans_block, | 369 | cpufreq_unregister_notifier(¬ifier_trans_block, |
370 | CPUFREQ_TRANSITION_NOTIFIER); | 370 | CPUFREQ_TRANSITION_NOTIFIER); |
371 | unregister_cpu_notifier(&cpufreq_stat_cpu_notifier); | 371 | unregister_hotcpu_notifier(&cpufreq_stat_cpu_notifier); |
372 | lock_cpu_hotplug(); | 372 | lock_cpu_hotplug(); |
373 | for_each_online_cpu(cpu) { | 373 | for_each_online_cpu(cpu) { |
374 | cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier, CPU_DEAD, | 374 | cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier, CPU_DEAD, |
diff --git a/drivers/crypto/padlock-aes.c b/drivers/crypto/padlock-aes.c index 5158a9db4bc5..17ee684144f9 100644 --- a/drivers/crypto/padlock-aes.c +++ b/drivers/crypto/padlock-aes.c | |||
@@ -60,15 +60,14 @@ | |||
60 | #define AES_EXTENDED_KEY_SIZE_B (AES_EXTENDED_KEY_SIZE * sizeof(uint32_t)) | 60 | #define AES_EXTENDED_KEY_SIZE_B (AES_EXTENDED_KEY_SIZE * sizeof(uint32_t)) |
61 | 61 | ||
62 | struct aes_ctx { | 62 | struct aes_ctx { |
63 | uint32_t e_data[AES_EXTENDED_KEY_SIZE]; | ||
64 | uint32_t d_data[AES_EXTENDED_KEY_SIZE]; | ||
65 | struct { | 63 | struct { |
66 | struct cword encrypt; | 64 | struct cword encrypt; |
67 | struct cword decrypt; | 65 | struct cword decrypt; |
68 | } cword; | 66 | } cword; |
69 | uint32_t *E; | 67 | u32 *D; |
70 | uint32_t *D; | ||
71 | int key_length; | 68 | int key_length; |
69 | u32 E[AES_EXTENDED_KEY_SIZE]; | ||
70 | u32 d_data[AES_EXTENDED_KEY_SIZE]; | ||
72 | }; | 71 | }; |
73 | 72 | ||
74 | /* ====== Key management routines ====== */ | 73 | /* ====== Key management routines ====== */ |
@@ -282,19 +281,20 @@ aes_hw_extkey_available(uint8_t key_len) | |||
282 | return 0; | 281 | return 0; |
283 | } | 282 | } |
284 | 283 | ||
285 | static inline struct aes_ctx *aes_ctx(void *ctx) | 284 | static inline struct aes_ctx *aes_ctx(struct crypto_tfm *tfm) |
286 | { | 285 | { |
286 | unsigned long addr = (unsigned long)crypto_tfm_ctx(tfm); | ||
287 | unsigned long align = PADLOCK_ALIGNMENT; | 287 | unsigned long align = PADLOCK_ALIGNMENT; |
288 | 288 | ||
289 | if (align <= crypto_tfm_ctx_alignment()) | 289 | if (align <= crypto_tfm_ctx_alignment()) |
290 | align = 1; | 290 | align = 1; |
291 | return (struct aes_ctx *)ALIGN((unsigned long)ctx, align); | 291 | return (struct aes_ctx *)ALIGN(addr, align); |
292 | } | 292 | } |
293 | 293 | ||
294 | static int | 294 | static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, |
295 | aes_set_key(void *ctx_arg, const uint8_t *in_key, unsigned int key_len, uint32_t *flags) | 295 | unsigned int key_len, u32 *flags) |
296 | { | 296 | { |
297 | struct aes_ctx *ctx = aes_ctx(ctx_arg); | 297 | struct aes_ctx *ctx = aes_ctx(tfm); |
298 | const __le32 *key = (const __le32 *)in_key; | 298 | const __le32 *key = (const __le32 *)in_key; |
299 | uint32_t i, t, u, v, w; | 299 | uint32_t i, t, u, v, w; |
300 | uint32_t P[AES_EXTENDED_KEY_SIZE]; | 300 | uint32_t P[AES_EXTENDED_KEY_SIZE]; |
@@ -312,8 +312,7 @@ aes_set_key(void *ctx_arg, const uint8_t *in_key, unsigned int key_len, uint32_t | |||
312 | * itself we must supply the plain key for both encryption | 312 | * itself we must supply the plain key for both encryption |
313 | * and decryption. | 313 | * and decryption. |
314 | */ | 314 | */ |
315 | ctx->E = ctx->e_data; | 315 | ctx->D = ctx->E; |
316 | ctx->D = ctx->e_data; | ||
317 | 316 | ||
318 | E_KEY[0] = le32_to_cpu(key[0]); | 317 | E_KEY[0] = le32_to_cpu(key[0]); |
319 | E_KEY[1] = le32_to_cpu(key[1]); | 318 | E_KEY[1] = le32_to_cpu(key[1]); |
@@ -414,24 +413,22 @@ static inline u8 *padlock_xcrypt_cbc(const u8 *input, u8 *output, void *key, | |||
414 | return iv; | 413 | return iv; |
415 | } | 414 | } |
416 | 415 | ||
417 | static void | 416 | static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) |
418 | aes_encrypt(void *ctx_arg, uint8_t *out, const uint8_t *in) | ||
419 | { | 417 | { |
420 | struct aes_ctx *ctx = aes_ctx(ctx_arg); | 418 | struct aes_ctx *ctx = aes_ctx(tfm); |
421 | padlock_xcrypt_ecb(in, out, ctx->E, &ctx->cword.encrypt, 1); | 419 | padlock_xcrypt_ecb(in, out, ctx->E, &ctx->cword.encrypt, 1); |
422 | } | 420 | } |
423 | 421 | ||
424 | static void | 422 | static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) |
425 | aes_decrypt(void *ctx_arg, uint8_t *out, const uint8_t *in) | ||
426 | { | 423 | { |
427 | struct aes_ctx *ctx = aes_ctx(ctx_arg); | 424 | struct aes_ctx *ctx = aes_ctx(tfm); |
428 | padlock_xcrypt_ecb(in, out, ctx->D, &ctx->cword.decrypt, 1); | 425 | padlock_xcrypt_ecb(in, out, ctx->D, &ctx->cword.decrypt, 1); |
429 | } | 426 | } |
430 | 427 | ||
431 | static unsigned int aes_encrypt_ecb(const struct cipher_desc *desc, u8 *out, | 428 | static unsigned int aes_encrypt_ecb(const struct cipher_desc *desc, u8 *out, |
432 | const u8 *in, unsigned int nbytes) | 429 | const u8 *in, unsigned int nbytes) |
433 | { | 430 | { |
434 | struct aes_ctx *ctx = aes_ctx(crypto_tfm_ctx(desc->tfm)); | 431 | struct aes_ctx *ctx = aes_ctx(desc->tfm); |
435 | padlock_xcrypt_ecb(in, out, ctx->E, &ctx->cword.encrypt, | 432 | padlock_xcrypt_ecb(in, out, ctx->E, &ctx->cword.encrypt, |
436 | nbytes / AES_BLOCK_SIZE); | 433 | nbytes / AES_BLOCK_SIZE); |
437 | return nbytes & ~(AES_BLOCK_SIZE - 1); | 434 | return nbytes & ~(AES_BLOCK_SIZE - 1); |
@@ -440,7 +437,7 @@ static unsigned int aes_encrypt_ecb(const struct cipher_desc *desc, u8 *out, | |||
440 | static unsigned int aes_decrypt_ecb(const struct cipher_desc *desc, u8 *out, | 437 | static unsigned int aes_decrypt_ecb(const struct cipher_desc *desc, u8 *out, |
441 | const u8 *in, unsigned int nbytes) | 438 | const u8 *in, unsigned int nbytes) |
442 | { | 439 | { |
443 | struct aes_ctx *ctx = aes_ctx(crypto_tfm_ctx(desc->tfm)); | 440 | struct aes_ctx *ctx = aes_ctx(desc->tfm); |
444 | padlock_xcrypt_ecb(in, out, ctx->D, &ctx->cword.decrypt, | 441 | padlock_xcrypt_ecb(in, out, ctx->D, &ctx->cword.decrypt, |
445 | nbytes / AES_BLOCK_SIZE); | 442 | nbytes / AES_BLOCK_SIZE); |
446 | return nbytes & ~(AES_BLOCK_SIZE - 1); | 443 | return nbytes & ~(AES_BLOCK_SIZE - 1); |
@@ -449,7 +446,7 @@ static unsigned int aes_decrypt_ecb(const struct cipher_desc *desc, u8 *out, | |||
449 | static unsigned int aes_encrypt_cbc(const struct cipher_desc *desc, u8 *out, | 446 | static unsigned int aes_encrypt_cbc(const struct cipher_desc *desc, u8 *out, |
450 | const u8 *in, unsigned int nbytes) | 447 | const u8 *in, unsigned int nbytes) |
451 | { | 448 | { |
452 | struct aes_ctx *ctx = aes_ctx(crypto_tfm_ctx(desc->tfm)); | 449 | struct aes_ctx *ctx = aes_ctx(desc->tfm); |
453 | u8 *iv; | 450 | u8 *iv; |
454 | 451 | ||
455 | iv = padlock_xcrypt_cbc(in, out, ctx->E, desc->info, | 452 | iv = padlock_xcrypt_cbc(in, out, ctx->E, desc->info, |
@@ -462,7 +459,7 @@ static unsigned int aes_encrypt_cbc(const struct cipher_desc *desc, u8 *out, | |||
462 | static unsigned int aes_decrypt_cbc(const struct cipher_desc *desc, u8 *out, | 459 | static unsigned int aes_decrypt_cbc(const struct cipher_desc *desc, u8 *out, |
463 | const u8 *in, unsigned int nbytes) | 460 | const u8 *in, unsigned int nbytes) |
464 | { | 461 | { |
465 | struct aes_ctx *ctx = aes_ctx(crypto_tfm_ctx(desc->tfm)); | 462 | struct aes_ctx *ctx = aes_ctx(desc->tfm); |
466 | padlock_xcrypt_cbc(in, out, ctx->D, desc->info, &ctx->cword.decrypt, | 463 | padlock_xcrypt_cbc(in, out, ctx->D, desc->info, &ctx->cword.decrypt, |
467 | nbytes / AES_BLOCK_SIZE); | 464 | nbytes / AES_BLOCK_SIZE); |
468 | return nbytes & ~(AES_BLOCK_SIZE - 1); | 465 | return nbytes & ~(AES_BLOCK_SIZE - 1); |
diff --git a/drivers/dma/ioatdma.c b/drivers/dma/ioatdma.c index 0fdf7fbd6495..2801d14a5e42 100644 --- a/drivers/dma/ioatdma.c +++ b/drivers/dma/ioatdma.c | |||
@@ -824,10 +824,9 @@ static int __init ioat_init_module(void) | |||
824 | { | 824 | { |
825 | /* it's currently unsafe to unload this module */ | 825 | /* it's currently unsafe to unload this module */ |
826 | /* if forced, worst case is that rmmod hangs */ | 826 | /* if forced, worst case is that rmmod hangs */ |
827 | if (THIS_MODULE != NULL) | 827 | __unsafe(THIS_MODULE); |
828 | THIS_MODULE->unsafe = 1; | ||
829 | 828 | ||
830 | return pci_module_init(&ioat_pci_drv); | 829 | pci_module_init(&ioat_pci_drv); |
831 | } | 830 | } |
832 | 831 | ||
833 | module_init(ioat_init_module); | 832 | module_init(ioat_init_module); |
diff --git a/drivers/hwmon/asb100.c b/drivers/hwmon/asb100.c index 65b2709f750c..facc1ccb8338 100644 --- a/drivers/hwmon/asb100.c +++ b/drivers/hwmon/asb100.c | |||
@@ -341,7 +341,7 @@ static ssize_t set_fan_min(struct device *dev, const char *buf, | |||
341 | 341 | ||
342 | /* Note: we save and restore the fan minimum here, because its value is | 342 | /* Note: we save and restore the fan minimum here, because its value is |
343 | determined in part by the fan divisor. This follows the principle of | 343 | determined in part by the fan divisor. This follows the principle of |
344 | least suprise; the user doesn't expect the fan minimum to change just | 344 | least surprise; the user doesn't expect the fan minimum to change just |
345 | because the divisor changed. */ | 345 | because the divisor changed. */ |
346 | static ssize_t set_fan_div(struct device *dev, const char *buf, | 346 | static ssize_t set_fan_div(struct device *dev, const char *buf, |
347 | size_t count, int nr) | 347 | size_t count, int nr) |
diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c index 94be3d797e61..a6ce7abf8602 100644 --- a/drivers/hwmon/lm78.c +++ b/drivers/hwmon/lm78.c | |||
@@ -358,7 +358,7 @@ static ssize_t show_fan_div(struct device *dev, char *buf, int nr) | |||
358 | 358 | ||
359 | /* Note: we save and restore the fan minimum here, because its value is | 359 | /* Note: we save and restore the fan minimum here, because its value is |
360 | determined in part by the fan divisor. This follows the principle of | 360 | determined in part by the fan divisor. This follows the principle of |
361 | least suprise; the user doesn't expect the fan minimum to change just | 361 | least surprise; the user doesn't expect the fan minimum to change just |
362 | because the divisor changed. */ | 362 | because the divisor changed. */ |
363 | static ssize_t set_fan_div(struct device *dev, const char *buf, | 363 | static ssize_t set_fan_div(struct device *dev, const char *buf, |
364 | size_t count, int nr) | 364 | size_t count, int nr) |
diff --git a/drivers/hwmon/lm80.c b/drivers/hwmon/lm80.c index f72120d08c4c..b4ccdfc01203 100644 --- a/drivers/hwmon/lm80.c +++ b/drivers/hwmon/lm80.c | |||
@@ -253,7 +253,7 @@ set_fan(min2, fan_min[1], LM80_REG_FAN_MIN(2), fan_div[1]); | |||
253 | 253 | ||
254 | /* Note: we save and restore the fan minimum here, because its value is | 254 | /* Note: we save and restore the fan minimum here, because its value is |
255 | determined in part by the fan divisor. This follows the principle of | 255 | determined in part by the fan divisor. This follows the principle of |
256 | least suprise; the user doesn't expect the fan minimum to change just | 256 | least surprise; the user doesn't expect the fan minimum to change just |
257 | because the divisor changed. */ | 257 | because the divisor changed. */ |
258 | static ssize_t set_fan_div(struct device *dev, const char *buf, | 258 | static ssize_t set_fan_div(struct device *dev, const char *buf, |
259 | size_t count, int nr) | 259 | size_t count, int nr) |
diff --git a/drivers/hwmon/lm87.c b/drivers/hwmon/lm87.c index e229daf666de..e6c1b638c971 100644 --- a/drivers/hwmon/lm87.c +++ b/drivers/hwmon/lm87.c | |||
@@ -421,7 +421,7 @@ static void set_fan_min(struct device *dev, const char *buf, int nr) | |||
421 | 421 | ||
422 | /* Note: we save and restore the fan minimum here, because its value is | 422 | /* Note: we save and restore the fan minimum here, because its value is |
423 | determined in part by the fan clock divider. This follows the principle | 423 | determined in part by the fan clock divider. This follows the principle |
424 | of least suprise; the user doesn't expect the fan minimum to change just | 424 | of least surprise; the user doesn't expect the fan minimum to change just |
425 | because the divider changed. */ | 425 | because the divider changed. */ |
426 | static ssize_t set_fan_div(struct device *dev, const char *buf, | 426 | static ssize_t set_fan_div(struct device *dev, const char *buf, |
427 | size_t count, int nr) | 427 | size_t count, int nr) |
diff --git a/drivers/hwmon/sis5595.c b/drivers/hwmon/sis5595.c index 6f3fda73f70c..063f71c5f07e 100644 --- a/drivers/hwmon/sis5595.c +++ b/drivers/hwmon/sis5595.c | |||
@@ -380,7 +380,7 @@ static ssize_t show_fan_div(struct device *dev, char *buf, int nr) | |||
380 | 380 | ||
381 | /* Note: we save and restore the fan minimum here, because its value is | 381 | /* Note: we save and restore the fan minimum here, because its value is |
382 | determined in part by the fan divisor. This follows the principle of | 382 | determined in part by the fan divisor. This follows the principle of |
383 | least suprise; the user doesn't expect the fan minimum to change just | 383 | least surprise; the user doesn't expect the fan minimum to change just |
384 | because the divisor changed. */ | 384 | because the divisor changed. */ |
385 | static ssize_t set_fan_div(struct device *dev, const char *buf, | 385 | static ssize_t set_fan_div(struct device *dev, const char *buf, |
386 | size_t count, int nr) | 386 | size_t count, int nr) |
diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c index 7732aec54594..825e8f72698f 100644 --- a/drivers/hwmon/smsc47m1.c +++ b/drivers/hwmon/smsc47m1.c | |||
@@ -207,7 +207,7 @@ static ssize_t set_fan_min(struct device *dev, const char *buf, | |||
207 | 207 | ||
208 | /* Note: we save and restore the fan minimum here, because its value is | 208 | /* Note: we save and restore the fan minimum here, because its value is |
209 | determined in part by the fan clock divider. This follows the principle | 209 | determined in part by the fan clock divider. This follows the principle |
210 | of least suprise; the user doesn't expect the fan minimum to change just | 210 | of least surprise; the user doesn't expect the fan minimum to change just |
211 | because the divider changed. */ | 211 | because the divider changed. */ |
212 | static ssize_t set_fan_div(struct device *dev, const char *buf, | 212 | static ssize_t set_fan_div(struct device *dev, const char *buf, |
213 | size_t count, int nr) | 213 | size_t count, int nr) |
diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c index 71fb7f1af8f5..79368d53c363 100644 --- a/drivers/hwmon/w83627hf.c +++ b/drivers/hwmon/w83627hf.c | |||
@@ -781,7 +781,7 @@ show_fan_div_reg(struct device *dev, char *buf, int nr) | |||
781 | 781 | ||
782 | /* Note: we save and restore the fan minimum here, because its value is | 782 | /* Note: we save and restore the fan minimum here, because its value is |
783 | determined in part by the fan divisor. This follows the principle of | 783 | determined in part by the fan divisor. This follows the principle of |
784 | least suprise; the user doesn't expect the fan minimum to change just | 784 | least surprise; the user doesn't expect the fan minimum to change just |
785 | because the divisor changed. */ | 785 | because the divisor changed. */ |
786 | static ssize_t | 786 | static ssize_t |
787 | store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr) | 787 | store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr) |
diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c index e4c700356c44..7be469ed0f8f 100644 --- a/drivers/hwmon/w83781d.c +++ b/drivers/hwmon/w83781d.c | |||
@@ -630,7 +630,7 @@ show_fan_div_reg(struct device *dev, char *buf, int nr) | |||
630 | 630 | ||
631 | /* Note: we save and restore the fan minimum here, because its value is | 631 | /* Note: we save and restore the fan minimum here, because its value is |
632 | determined in part by the fan divisor. This follows the principle of | 632 | determined in part by the fan divisor. This follows the principle of |
633 | least suprise; the user doesn't expect the fan minimum to change just | 633 | least surprise; the user doesn't expect the fan minimum to change just |
634 | because the divisor changed. */ | 634 | because the divisor changed. */ |
635 | static ssize_t | 635 | static ssize_t |
636 | store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr) | 636 | store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr) |
diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c index 4ef884c216e2..e407c74bda35 100644 --- a/drivers/hwmon/w83792d.c +++ b/drivers/hwmon/w83792d.c | |||
@@ -463,7 +463,7 @@ show_fan_div(struct device *dev, struct device_attribute *attr, | |||
463 | 463 | ||
464 | /* Note: we save and restore the fan minimum here, because its value is | 464 | /* Note: we save and restore the fan minimum here, because its value is |
465 | determined in part by the fan divisor. This follows the principle of | 465 | determined in part by the fan divisor. This follows the principle of |
466 | least suprise; the user doesn't expect the fan minimum to change just | 466 | least surprise; the user doesn't expect the fan minimum to change just |
467 | because the divisor changed. */ | 467 | because the divisor changed. */ |
468 | static ssize_t | 468 | static ssize_t |
469 | store_fan_div(struct device *dev, struct device_attribute *attr, | 469 | store_fan_div(struct device *dev, struct device_attribute *attr, |
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 3e0d04d5a800..8b46ef7d9ff8 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c | |||
@@ -488,7 +488,7 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id | |||
488 | dev_err(&dev->dev, "SMBus base address uninitialized, " | 488 | dev_err(&dev->dev, "SMBus base address uninitialized, " |
489 | "upgrade BIOS\n"); | 489 | "upgrade BIOS\n"); |
490 | err = -ENODEV; | 490 | err = -ENODEV; |
491 | goto exit_disable; | 491 | goto exit; |
492 | } | 492 | } |
493 | 493 | ||
494 | err = pci_request_region(dev, SMBBAR, i801_driver.name); | 494 | err = pci_request_region(dev, SMBBAR, i801_driver.name); |
@@ -496,7 +496,7 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id | |||
496 | dev_err(&dev->dev, "Failed to request SMBus region " | 496 | dev_err(&dev->dev, "Failed to request SMBus region " |
497 | "0x%lx-0x%lx\n", i801_smba, | 497 | "0x%lx-0x%lx\n", i801_smba, |
498 | pci_resource_end(dev, SMBBAR)); | 498 | pci_resource_end(dev, SMBBAR)); |
499 | goto exit_disable; | 499 | goto exit; |
500 | } | 500 | } |
501 | 501 | ||
502 | pci_read_config_byte(I801_dev, SMBHSTCFG, &temp); | 502 | pci_read_config_byte(I801_dev, SMBHSTCFG, &temp); |
@@ -520,11 +520,12 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id | |||
520 | err = i2c_add_adapter(&i801_adapter); | 520 | err = i2c_add_adapter(&i801_adapter); |
521 | if (err) { | 521 | if (err) { |
522 | dev_err(&dev->dev, "Failed to add SMBus adapter\n"); | 522 | dev_err(&dev->dev, "Failed to add SMBus adapter\n"); |
523 | goto exit_disable; | 523 | goto exit_release; |
524 | } | 524 | } |
525 | return 0; | ||
525 | 526 | ||
526 | exit_disable: | 527 | exit_release: |
527 | pci_disable_device(dev); | 528 | pci_release_region(dev, SMBBAR); |
528 | exit: | 529 | exit: |
529 | return err; | 530 | return err; |
530 | } | 531 | } |
@@ -533,7 +534,10 @@ static void __devexit i801_remove(struct pci_dev *dev) | |||
533 | { | 534 | { |
534 | i2c_del_adapter(&i801_adapter); | 535 | i2c_del_adapter(&i801_adapter); |
535 | pci_release_region(dev, SMBBAR); | 536 | pci_release_region(dev, SMBBAR); |
536 | pci_disable_device(dev); | 537 | /* |
538 | * do not call pci_disable_device(dev) since it can cause hard hangs on | ||
539 | * some systems during power-off (eg. Fujitsu-Siemens Lifebook E8010) | ||
540 | */ | ||
537 | } | 541 | } |
538 | 542 | ||
539 | static struct pci_driver i801_driver = { | 543 | static struct pci_driver i801_driver = { |
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index a5017de72da5..f033d732f387 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c | |||
@@ -37,7 +37,7 @@ | |||
37 | * Version 1.15 convert all calls to ide_raw_taskfile | 37 | * Version 1.15 convert all calls to ide_raw_taskfile |
38 | * since args will return register content. | 38 | * since args will return register content. |
39 | * Version 1.16 added suspend-resume-checkpower | 39 | * Version 1.16 added suspend-resume-checkpower |
40 | * Version 1.17 do flush on standy, do flush on ATA < ATA6 | 40 | * Version 1.17 do flush on standby, do flush on ATA < ATA6 |
41 | * fix wcache setup. | 41 | * fix wcache setup. |
42 | */ | 42 | */ |
43 | 43 | ||
diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index 622a55c72f03..935cb2583770 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c | |||
@@ -959,7 +959,7 @@ static void ide_check_pm_state(ide_drive_t *drive, struct request *rq) | |||
959 | printk(KERN_WARNING "%s: bus not ready on wakeup\n", drive->name); | 959 | printk(KERN_WARNING "%s: bus not ready on wakeup\n", drive->name); |
960 | SELECT_DRIVE(drive); | 960 | SELECT_DRIVE(drive); |
961 | HWIF(drive)->OUTB(8, HWIF(drive)->io_ports[IDE_CONTROL_OFFSET]); | 961 | HWIF(drive)->OUTB(8, HWIF(drive)->io_ports[IDE_CONTROL_OFFSET]); |
962 | rc = ide_wait_not_busy(HWIF(drive), 10000); | 962 | rc = ide_wait_not_busy(HWIF(drive), 100000); |
963 | if (rc) | 963 | if (rc) |
964 | printk(KERN_WARNING "%s: drive not ready on wakeup\n", drive->name); | 964 | printk(KERN_WARNING "%s: drive not ready on wakeup\n", drive->name); |
965 | } | 965 | } |
@@ -1665,7 +1665,7 @@ irqreturn_t ide_intr (int irq, void *dev_id, struct pt_regs *regs) | |||
1665 | * Initialize a request before we fill it in and send it down to | 1665 | * Initialize a request before we fill it in and send it down to |
1666 | * ide_do_drive_cmd. Commands must be set up by this function. Right | 1666 | * ide_do_drive_cmd. Commands must be set up by this function. Right |
1667 | * now it doesn't do a lot, but if that changes abusers will have a | 1667 | * now it doesn't do a lot, but if that changes abusers will have a |
1668 | * nasty suprise. | 1668 | * nasty surprise. |
1669 | */ | 1669 | */ |
1670 | 1670 | ||
1671 | void ide_init_drive_cmd (struct request *rq) | 1671 | void ide_init_drive_cmd (struct request *rq) |
diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c index 16a143133f93..7ddb11828731 100644 --- a/drivers/ide/ide-lib.c +++ b/drivers/ide/ide-lib.c | |||
@@ -485,7 +485,7 @@ static u8 ide_dump_ata_status(ide_drive_t *drive, const char *msg, u8 stat) | |||
485 | unsigned long flags; | 485 | unsigned long flags; |
486 | u8 err = 0; | 486 | u8 err = 0; |
487 | 487 | ||
488 | local_irq_set(flags); | 488 | local_irq_save(flags); |
489 | printk("%s: %s: status=0x%02x { ", drive->name, msg, stat); | 489 | printk("%s: %s: status=0x%02x { ", drive->name, msg, stat); |
490 | if (stat & BUSY_STAT) | 490 | if (stat & BUSY_STAT) |
491 | printk("Busy "); | 491 | printk("Busy "); |
@@ -567,7 +567,7 @@ static u8 ide_dump_atapi_status(ide_drive_t *drive, const char *msg, u8 stat) | |||
567 | 567 | ||
568 | status.all = stat; | 568 | status.all = stat; |
569 | error.all = 0; | 569 | error.all = 0; |
570 | local_irq_set(flags); | 570 | local_irq_save(flags); |
571 | printk("%s: %s: status=0x%02x { ", drive->name, msg, stat); | 571 | printk("%s: %s: status=0x%02x { ", drive->name, msg, stat); |
572 | if (status.b.bsy) | 572 | if (status.b.bsy) |
573 | printk("Busy "); | 573 | printk("Busy "); |
diff --git a/drivers/ide/ide-timing.h b/drivers/ide/ide-timing.h index 2fcfac6e967a..c0864b1e9228 100644 --- a/drivers/ide/ide-timing.h +++ b/drivers/ide/ide-timing.h | |||
@@ -220,6 +220,12 @@ static int ide_timing_compute(ide_drive_t *drive, short speed, struct ide_timing | |||
220 | return -EINVAL; | 220 | return -EINVAL; |
221 | 221 | ||
222 | /* | 222 | /* |
223 | * Copy the timing from the table. | ||
224 | */ | ||
225 | |||
226 | *t = *s; | ||
227 | |||
228 | /* | ||
223 | * If the drive is an EIDE drive, it can tell us it needs extended | 229 | * If the drive is an EIDE drive, it can tell us it needs extended |
224 | * PIO/MWDMA cycle timing. | 230 | * PIO/MWDMA cycle timing. |
225 | */ | 231 | */ |
@@ -247,7 +253,7 @@ static int ide_timing_compute(ide_drive_t *drive, short speed, struct ide_timing | |||
247 | * Convert the timing to bus clock counts. | 253 | * Convert the timing to bus clock counts. |
248 | */ | 254 | */ |
249 | 255 | ||
250 | ide_timing_quantize(s, t, T, UT); | 256 | ide_timing_quantize(t, t, T, UT); |
251 | 257 | ||
252 | /* | 258 | /* |
253 | * Even in DMA/UDMA modes we still use PIO access for IDENTIFY, S.M.A.R.T | 259 | * Even in DMA/UDMA modes we still use PIO access for IDENTIFY, S.M.A.R.T |
diff --git a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c index 6e9dbf4d8077..85007cb12c52 100644 --- a/drivers/ide/pci/amd74xx.c +++ b/drivers/ide/pci/amd74xx.c | |||
@@ -75,6 +75,7 @@ static struct amd_ide_chip { | |||
75 | { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE, 0x50, AMD_UDMA_133 }, | 75 | { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE, 0x50, AMD_UDMA_133 }, |
76 | { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE, 0x50, AMD_UDMA_133 }, | 76 | { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE, 0x50, AMD_UDMA_133 }, |
77 | { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE, 0x50, AMD_UDMA_133 }, | 77 | { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE, 0x50, AMD_UDMA_133 }, |
78 | { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_IDE, 0x50, AMD_UDMA_133 }, | ||
78 | { PCI_DEVICE_ID_AMD_CS5536_IDE, 0x40, AMD_UDMA_100 }, | 79 | { PCI_DEVICE_ID_AMD_CS5536_IDE, 0x40, AMD_UDMA_100 }, |
79 | { 0 } | 80 | { 0 } |
80 | }; | 81 | }; |
@@ -490,7 +491,8 @@ static ide_pci_device_t amd74xx_chipsets[] __devinitdata = { | |||
490 | /* 15 */ DECLARE_NV_DEV("NFORCE-MCP51"), | 491 | /* 15 */ DECLARE_NV_DEV("NFORCE-MCP51"), |
491 | /* 16 */ DECLARE_NV_DEV("NFORCE-MCP55"), | 492 | /* 16 */ DECLARE_NV_DEV("NFORCE-MCP55"), |
492 | /* 17 */ DECLARE_NV_DEV("NFORCE-MCP61"), | 493 | /* 17 */ DECLARE_NV_DEV("NFORCE-MCP61"), |
493 | /* 18 */ DECLARE_AMD_DEV("AMD5536"), | 494 | /* 18 */ DECLARE_NV_DEV("NFORCE-MCP65"), |
495 | /* 19 */ DECLARE_AMD_DEV("AMD5536"), | ||
494 | }; | 496 | }; |
495 | 497 | ||
496 | static int __devinit amd74xx_probe(struct pci_dev *dev, const struct pci_device_id *id) | 498 | static int __devinit amd74xx_probe(struct pci_dev *dev, const struct pci_device_id *id) |
@@ -528,7 +530,8 @@ static struct pci_device_id amd74xx_pci_tbl[] = { | |||
528 | { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 15 }, | 530 | { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 15 }, |
529 | { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 16 }, | 531 | { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 16 }, |
530 | { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 17 }, | 532 | { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 17 }, |
531 | { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 18 }, | 533 | { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 18 }, |
534 | { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 19 }, | ||
532 | { 0, }, | 535 | { 0, }, |
533 | }; | 536 | }; |
534 | MODULE_DEVICE_TABLE(pci, amd74xx_pci_tbl); | 537 | MODULE_DEVICE_TABLE(pci, amd74xx_pci_tbl); |
diff --git a/drivers/ide/pci/pdc202xx_old.c b/drivers/ide/pci/pdc202xx_old.c index 7ce5bf783688..22d17548ecdb 100644 --- a/drivers/ide/pci/pdc202xx_old.c +++ b/drivers/ide/pci/pdc202xx_old.c | |||
@@ -370,7 +370,6 @@ chipset_is_set: | |||
370 | if (!(speed)) { | 370 | if (!(speed)) { |
371 | /* restore original pci-config space */ | 371 | /* restore original pci-config space */ |
372 | pci_write_config_dword(dev, drive_pci, drive_conf); | 372 | pci_write_config_dword(dev, drive_pci, drive_conf); |
373 | hwif->tuneproc(drive, 5); | ||
374 | return 0; | 373 | return 0; |
375 | } | 374 | } |
376 | 375 | ||
@@ -415,8 +414,6 @@ static void pdc202xx_old_ide_dma_start(ide_drive_t *drive) | |||
415 | if (drive->addressing == 1) { | 414 | if (drive->addressing == 1) { |
416 | struct request *rq = HWGROUP(drive)->rq; | 415 | struct request *rq = HWGROUP(drive)->rq; |
417 | ide_hwif_t *hwif = HWIF(drive); | 416 | ide_hwif_t *hwif = HWIF(drive); |
418 | // struct pci_dev *dev = hwif->pci_dev; | ||
419 | // unsgned long high_16 = pci_resource_start(dev, 4); | ||
420 | unsigned long high_16 = hwif->dma_master; | 417 | unsigned long high_16 = hwif->dma_master; |
421 | unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20); | 418 | unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20); |
422 | u32 word_count = 0; | 419 | u32 word_count = 0; |
@@ -436,7 +433,6 @@ static int pdc202xx_old_ide_dma_end(ide_drive_t *drive) | |||
436 | { | 433 | { |
437 | if (drive->addressing == 1) { | 434 | if (drive->addressing == 1) { |
438 | ide_hwif_t *hwif = HWIF(drive); | 435 | ide_hwif_t *hwif = HWIF(drive); |
439 | // unsigned long high_16 = pci_resource_start(hwif->pci_dev, 4); | ||
440 | unsigned long high_16 = hwif->dma_master; | 436 | unsigned long high_16 = hwif->dma_master; |
441 | unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20); | 437 | unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20); |
442 | u8 clock = 0; | 438 | u8 clock = 0; |
@@ -453,8 +449,6 @@ static int pdc202xx_old_ide_dma_end(ide_drive_t *drive) | |||
453 | static int pdc202xx_old_ide_dma_test_irq(ide_drive_t *drive) | 449 | static int pdc202xx_old_ide_dma_test_irq(ide_drive_t *drive) |
454 | { | 450 | { |
455 | ide_hwif_t *hwif = HWIF(drive); | 451 | ide_hwif_t *hwif = HWIF(drive); |
456 | // struct pci_dev *dev = hwif->pci_dev; | ||
457 | // unsigned long high_16 = pci_resource_start(dev, 4); | ||
458 | unsigned long high_16 = hwif->dma_master; | 452 | unsigned long high_16 = hwif->dma_master; |
459 | u8 dma_stat = hwif->INB(hwif->dma_status); | 453 | u8 dma_stat = hwif->INB(hwif->dma_status); |
460 | u8 sc1d = hwif->INB((high_16 + 0x001d)); | 454 | u8 sc1d = hwif->INB((high_16 + 0x001d)); |
@@ -492,12 +486,7 @@ static int pdc202xx_ide_dma_timeout(ide_drive_t *drive) | |||
492 | 486 | ||
493 | static void pdc202xx_reset_host (ide_hwif_t *hwif) | 487 | static void pdc202xx_reset_host (ide_hwif_t *hwif) |
494 | { | 488 | { |
495 | #ifdef CONFIG_BLK_DEV_IDEDMA | ||
496 | // unsigned long high_16 = hwif->dma_base - (8*(hwif->channel)); | ||
497 | unsigned long high_16 = hwif->dma_master; | 489 | unsigned long high_16 = hwif->dma_master; |
498 | #else /* !CONFIG_BLK_DEV_IDEDMA */ | ||
499 | unsigned long high_16 = pci_resource_start(hwif->pci_dev, 4); | ||
500 | #endif /* CONFIG_BLK_DEV_IDEDMA */ | ||
501 | u8 udma_speed_flag = hwif->INB(high_16|0x001f); | 490 | u8 udma_speed_flag = hwif->INB(high_16|0x001f); |
502 | 491 | ||
503 | hwif->OUTB((udma_speed_flag | 0x10), (high_16|0x001f)); | 492 | hwif->OUTB((udma_speed_flag | 0x10), (high_16|0x001f)); |
@@ -550,31 +539,6 @@ static void pdc202xx_reset (ide_drive_t *drive) | |||
550 | #endif | 539 | #endif |
551 | } | 540 | } |
552 | 541 | ||
553 | /* | ||
554 | * Since SUN Cobalt is attempting to do this operation, I should disclose | ||
555 | * this has been a long time ago Thu Jul 27 16:40:57 2000 was the patch date | ||
556 | * HOTSWAP ATA Infrastructure. | ||
557 | */ | ||
558 | static int pdc202xx_tristate (ide_drive_t * drive, int state) | ||
559 | { | ||
560 | ide_hwif_t *hwif = HWIF(drive); | ||
561 | // unsigned long high_16 = hwif->dma_base - (8*(hwif->channel)); | ||
562 | unsigned long high_16 = hwif->dma_master; | ||
563 | u8 sc1f = hwif->INB(high_16|0x001f); | ||
564 | |||
565 | if (!hwif) | ||
566 | return -EINVAL; | ||
567 | |||
568 | // hwif->bus_state = state; | ||
569 | |||
570 | if (state) { | ||
571 | hwif->OUTB(sc1f | 0x08, (high_16|0x001f)); | ||
572 | } else { | ||
573 | hwif->OUTB(sc1f & ~0x08, (high_16|0x001f)); | ||
574 | } | ||
575 | return 0; | ||
576 | } | ||
577 | |||
578 | static unsigned int __devinit init_chipset_pdc202xx(struct pci_dev *dev, const char *name) | 542 | static unsigned int __devinit init_chipset_pdc202xx(struct pci_dev *dev, const char *name) |
579 | { | 543 | { |
580 | if (dev->resource[PCI_ROM_RESOURCE].start) { | 544 | if (dev->resource[PCI_ROM_RESOURCE].start) { |
@@ -624,10 +588,8 @@ static void __devinit init_hwif_pdc202xx(ide_hwif_t *hwif) | |||
624 | hwif->tuneproc = &config_chipset_for_pio; | 588 | hwif->tuneproc = &config_chipset_for_pio; |
625 | hwif->quirkproc = &pdc202xx_quirkproc; | 589 | hwif->quirkproc = &pdc202xx_quirkproc; |
626 | 590 | ||
627 | if (hwif->pci_dev->device != PCI_DEVICE_ID_PROMISE_20246) { | 591 | if (hwif->pci_dev->device != PCI_DEVICE_ID_PROMISE_20246) |
628 | hwif->busproc = &pdc202xx_tristate; | ||
629 | hwif->resetproc = &pdc202xx_reset; | 592 | hwif->resetproc = &pdc202xx_reset; |
630 | } | ||
631 | 593 | ||
632 | hwif->speedproc = &pdc202xx_tune_chipset; | 594 | hwif->speedproc = &pdc202xx_tune_chipset; |
633 | 595 | ||
diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c index e9b83e1a3028..7fac6f57b5d6 100644 --- a/drivers/ide/pci/piix.c +++ b/drivers/ide/pci/piix.c | |||
@@ -222,6 +222,8 @@ static void piix_tune_drive (ide_drive_t *drive, u8 pio) | |||
222 | unsigned long flags; | 222 | unsigned long flags; |
223 | u16 master_data; | 223 | u16 master_data; |
224 | u8 slave_data; | 224 | u8 slave_data; |
225 | static DEFINE_SPINLOCK(tune_lock); | ||
226 | |||
225 | /* ISP RTC */ | 227 | /* ISP RTC */ |
226 | u8 timings[][2] = { { 0, 0 }, | 228 | u8 timings[][2] = { { 0, 0 }, |
227 | { 0, 0 }, | 229 | { 0, 0 }, |
@@ -230,7 +232,13 @@ static void piix_tune_drive (ide_drive_t *drive, u8 pio) | |||
230 | { 2, 3 }, }; | 232 | { 2, 3 }, }; |
231 | 233 | ||
232 | pio = ide_get_best_pio_mode(drive, pio, 5, NULL); | 234 | pio = ide_get_best_pio_mode(drive, pio, 5, NULL); |
233 | spin_lock_irqsave(&ide_lock, flags); | 235 | |
236 | /* | ||
237 | * Master vs slave is synchronized above us but the slave register is | ||
238 | * shared by the two hwifs so the corner case of two slave timeouts in | ||
239 | * parallel must be locked. | ||
240 | */ | ||
241 | spin_lock_irqsave(&tune_lock, flags); | ||
234 | pci_read_config_word(dev, master_port, &master_data); | 242 | pci_read_config_word(dev, master_port, &master_data); |
235 | if (is_slave) { | 243 | if (is_slave) { |
236 | master_data = master_data | 0x4000; | 244 | master_data = master_data | 0x4000; |
@@ -250,7 +258,7 @@ static void piix_tune_drive (ide_drive_t *drive, u8 pio) | |||
250 | pci_write_config_word(dev, master_port, master_data); | 258 | pci_write_config_word(dev, master_port, master_data); |
251 | if (is_slave) | 259 | if (is_slave) |
252 | pci_write_config_byte(dev, slave_port, slave_data); | 260 | pci_write_config_byte(dev, slave_port, slave_data); |
253 | spin_unlock_irqrestore(&ide_lock, flags); | 261 | spin_unlock_irqrestore(&tune_lock, flags); |
254 | } | 262 | } |
255 | 263 | ||
256 | /** | 264 | /** |
diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c index 5bda15904a08..2d5b57be98c3 100644 --- a/drivers/ieee1394/eth1394.c +++ b/drivers/ieee1394/eth1394.c | |||
@@ -1074,8 +1074,7 @@ static inline int update_partial_datagram(struct list_head *pdgl, struct list_he | |||
1074 | 1074 | ||
1075 | /* Move list entry to beginnig of list so that oldest partial | 1075 | /* Move list entry to beginnig of list so that oldest partial |
1076 | * datagrams percolate to the end of the list */ | 1076 | * datagrams percolate to the end of the list */ |
1077 | list_del(lh); | 1077 | list_move(lh, pdgl); |
1078 | list_add(lh, pdgl); | ||
1079 | 1078 | ||
1080 | return 0; | 1079 | return 0; |
1081 | } | 1080 | } |
diff --git a/drivers/ieee1394/hosts.c b/drivers/ieee1394/hosts.c index 2d47b11777a5..ad49c040b674 100644 --- a/drivers/ieee1394/hosts.c +++ b/drivers/ieee1394/hosts.c | |||
@@ -103,7 +103,7 @@ static int alloc_hostnum_cb(struct hpsb_host *host, void *__data) | |||
103 | * driver specific parts, enable the controller and make it available | 103 | * driver specific parts, enable the controller and make it available |
104 | * to the general subsystem using hpsb_add_host(). | 104 | * to the general subsystem using hpsb_add_host(). |
105 | * | 105 | * |
106 | * Return Value: a pointer to the &hpsb_host if succesful, %NULL if | 106 | * Return Value: a pointer to the &hpsb_host if successful, %NULL if |
107 | * no memory was available. | 107 | * no memory was available. |
108 | */ | 108 | */ |
109 | static DEFINE_MUTEX(host_num_alloc); | 109 | static DEFINE_MUTEX(host_num_alloc); |
diff --git a/drivers/ieee1394/ieee1394_core.h b/drivers/ieee1394/ieee1394_core.h index e7b55e895f50..0ecbf335c64f 100644 --- a/drivers/ieee1394/ieee1394_core.h +++ b/drivers/ieee1394/ieee1394_core.h | |||
@@ -139,7 +139,7 @@ int hpsb_bus_reset(struct hpsb_host *host); | |||
139 | 139 | ||
140 | /* | 140 | /* |
141 | * Hand over received selfid packet to the core. Complement check (second | 141 | * Hand over received selfid packet to the core. Complement check (second |
142 | * quadlet is complement of first) is expected to be done and succesful. | 142 | * quadlet is complement of first) is expected to be done and successful. |
143 | */ | 143 | */ |
144 | void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid); | 144 | void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid); |
145 | 145 | ||
diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c index 20ce539580f1..571ea68c0cf2 100644 --- a/drivers/ieee1394/raw1394.c +++ b/drivers/ieee1394/raw1394.c | |||
@@ -132,8 +132,7 @@ static void free_pending_request(struct pending_request *req) | |||
132 | static void __queue_complete_req(struct pending_request *req) | 132 | static void __queue_complete_req(struct pending_request *req) |
133 | { | 133 | { |
134 | struct file_info *fi = req->file_info; | 134 | struct file_info *fi = req->file_info; |
135 | list_del(&req->list); | 135 | list_move_tail(&req->list, &fi->req_complete); |
136 | list_add_tail(&req->list, &fi->req_complete); | ||
137 | 136 | ||
138 | up(&fi->complete_sem); | 137 | up(&fi->complete_sem); |
139 | wake_up_interruptible(&fi->poll_wait_complete); | 138 | wake_up_interruptible(&fi->poll_wait_complete); |
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index a76834edf608..863f64befc7c 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c | |||
@@ -476,7 +476,7 @@ static inline int cma_zero_addr(struct sockaddr *addr) | |||
476 | else { | 476 | else { |
477 | ip6 = &((struct sockaddr_in6 *) addr)->sin6_addr; | 477 | ip6 = &((struct sockaddr_in6 *) addr)->sin6_addr; |
478 | return (ip6->s6_addr32[0] | ip6->s6_addr32[1] | | 478 | return (ip6->s6_addr32[0] | ip6->s6_addr32[1] | |
479 | ip6->s6_addr32[3] | ip6->s6_addr32[4]) == 0; | 479 | ip6->s6_addr32[2] | ip6->s6_addr32[3]) == 0; |
480 | } | 480 | } |
481 | } | 481 | } |
482 | 482 | ||
diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index b38e02a5db35..5ed4dab52a6f 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c | |||
@@ -1775,11 +1775,9 @@ ib_find_send_mad(struct ib_mad_agent_private *mad_agent_priv, | |||
1775 | void ib_mark_mad_done(struct ib_mad_send_wr_private *mad_send_wr) | 1775 | void ib_mark_mad_done(struct ib_mad_send_wr_private *mad_send_wr) |
1776 | { | 1776 | { |
1777 | mad_send_wr->timeout = 0; | 1777 | mad_send_wr->timeout = 0; |
1778 | if (mad_send_wr->refcount == 1) { | 1778 | if (mad_send_wr->refcount == 1) |
1779 | list_del(&mad_send_wr->agent_list); | 1779 | list_move_tail(&mad_send_wr->agent_list, |
1780 | list_add_tail(&mad_send_wr->agent_list, | ||
1781 | &mad_send_wr->mad_agent_priv->done_list); | 1780 | &mad_send_wr->mad_agent_priv->done_list); |
1782 | } | ||
1783 | } | 1781 | } |
1784 | 1782 | ||
1785 | static void ib_mad_complete_recv(struct ib_mad_agent_private *mad_agent_priv, | 1783 | static void ib_mad_complete_recv(struct ib_mad_agent_private *mad_agent_priv, |
@@ -2098,8 +2096,7 @@ retry: | |||
2098 | queued_send_wr = container_of(mad_list, | 2096 | queued_send_wr = container_of(mad_list, |
2099 | struct ib_mad_send_wr_private, | 2097 | struct ib_mad_send_wr_private, |
2100 | mad_list); | 2098 | mad_list); |
2101 | list_del(&mad_list->list); | 2099 | list_move_tail(&mad_list->list, &send_queue->list); |
2102 | list_add_tail(&mad_list->list, &send_queue->list); | ||
2103 | } | 2100 | } |
2104 | spin_unlock_irqrestore(&send_queue->lock, flags); | 2101 | spin_unlock_irqrestore(&send_queue->lock, flags); |
2105 | 2102 | ||
diff --git a/drivers/infiniband/core/mad_rmpp.c b/drivers/infiniband/core/mad_rmpp.c index d4704e054e30..ebcd5b181770 100644 --- a/drivers/infiniband/core/mad_rmpp.c +++ b/drivers/infiniband/core/mad_rmpp.c | |||
@@ -665,8 +665,7 @@ static void process_rmpp_ack(struct ib_mad_agent_private *agent, | |||
665 | goto out; | 665 | goto out; |
666 | 666 | ||
667 | mad_send_wr->refcount++; | 667 | mad_send_wr->refcount++; |
668 | list_del(&mad_send_wr->agent_list); | 668 | list_move_tail(&mad_send_wr->agent_list, |
669 | list_add_tail(&mad_send_wr->agent_list, | ||
670 | &mad_send_wr->mad_agent_priv->send_list); | 669 | &mad_send_wr->mad_agent_priv->send_list); |
671 | } | 670 | } |
672 | out: | 671 | out: |
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index 216471fa01cc..ab40488182b3 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c | |||
@@ -864,8 +864,7 @@ void ipoib_mcast_restart_task(void *dev_ptr) | |||
864 | 864 | ||
865 | if (mcast) { | 865 | if (mcast) { |
866 | /* Destroy the send only entry */ | 866 | /* Destroy the send only entry */ |
867 | list_del(&mcast->list); | 867 | list_move_tail(&mcast->list, &remove_list); |
868 | list_add_tail(&mcast->list, &remove_list); | ||
869 | 868 | ||
870 | rb_replace_node(&mcast->rb_node, | 869 | rb_replace_node(&mcast->rb_node, |
871 | &nmcast->rb_node, | 870 | &nmcast->rb_node, |
@@ -890,8 +889,7 @@ void ipoib_mcast_restart_task(void *dev_ptr) | |||
890 | rb_erase(&mcast->rb_node, &priv->multicast_tree); | 889 | rb_erase(&mcast->rb_node, &priv->multicast_tree); |
891 | 890 | ||
892 | /* Move to the remove list */ | 891 | /* Move to the remove list */ |
893 | list_del(&mcast->list); | 892 | list_move_tail(&mcast->list, &remove_list); |
894 | list_add_tail(&mcast->list, &remove_list); | ||
895 | } | 893 | } |
896 | } | 894 | } |
897 | 895 | ||
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 5f561fce32d8..a29d5ceb00cf 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c | |||
@@ -78,14 +78,19 @@ static int evdev_fasync(int fd, struct file *file, int on) | |||
78 | { | 78 | { |
79 | int retval; | 79 | int retval; |
80 | struct evdev_list *list = file->private_data; | 80 | struct evdev_list *list = file->private_data; |
81 | |||
81 | retval = fasync_helper(fd, file, on, &list->fasync); | 82 | retval = fasync_helper(fd, file, on, &list->fasync); |
83 | |||
82 | return retval < 0 ? retval : 0; | 84 | return retval < 0 ? retval : 0; |
83 | } | 85 | } |
84 | 86 | ||
85 | static int evdev_flush(struct file * file, fl_owner_t id) | 87 | static int evdev_flush(struct file *file, fl_owner_t id) |
86 | { | 88 | { |
87 | struct evdev_list *list = file->private_data; | 89 | struct evdev_list *list = file->private_data; |
88 | if (!list->evdev->exist) return -ENODEV; | 90 | |
91 | if (!list->evdev->exist) | ||
92 | return -ENODEV; | ||
93 | |||
89 | return input_flush_device(&list->evdev->handle, file); | 94 | return input_flush_device(&list->evdev->handle, file); |
90 | } | 95 | } |
91 | 96 | ||
@@ -300,6 +305,7 @@ static ssize_t evdev_read(struct file * file, char __user * buffer, size_t count | |||
300 | static unsigned int evdev_poll(struct file *file, poll_table *wait) | 305 | static unsigned int evdev_poll(struct file *file, poll_table *wait) |
301 | { | 306 | { |
302 | struct evdev_list *list = file->private_data; | 307 | struct evdev_list *list = file->private_data; |
308 | |||
303 | poll_wait(file, &list->evdev->wait, wait); | 309 | poll_wait(file, &list->evdev->wait, wait); |
304 | return ((list->head == list->tail) ? 0 : (POLLIN | POLLRDNORM)) | | 310 | return ((list->head == list->tail) ? 0 : (POLLIN | POLLRDNORM)) | |
305 | (list->evdev->exist ? 0 : (POLLHUP | POLLERR)); | 311 | (list->evdev->exist ? 0 : (POLLHUP | POLLERR)); |
diff --git a/drivers/input/input.c b/drivers/input/input.c index 3038c268917d..a90486f5e491 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c | |||
@@ -28,20 +28,6 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>"); | |||
28 | MODULE_DESCRIPTION("Input core"); | 28 | MODULE_DESCRIPTION("Input core"); |
29 | MODULE_LICENSE("GPL"); | 29 | MODULE_LICENSE("GPL"); |
30 | 30 | ||
31 | EXPORT_SYMBOL(input_allocate_device); | ||
32 | EXPORT_SYMBOL(input_register_device); | ||
33 | EXPORT_SYMBOL(input_unregister_device); | ||
34 | EXPORT_SYMBOL(input_register_handler); | ||
35 | EXPORT_SYMBOL(input_unregister_handler); | ||
36 | EXPORT_SYMBOL(input_grab_device); | ||
37 | EXPORT_SYMBOL(input_release_device); | ||
38 | EXPORT_SYMBOL(input_open_device); | ||
39 | EXPORT_SYMBOL(input_close_device); | ||
40 | EXPORT_SYMBOL(input_accept_process); | ||
41 | EXPORT_SYMBOL(input_flush_device); | ||
42 | EXPORT_SYMBOL(input_event); | ||
43 | EXPORT_SYMBOL_GPL(input_class); | ||
44 | |||
45 | #define INPUT_DEVICES 256 | 31 | #define INPUT_DEVICES 256 |
46 | 32 | ||
47 | static LIST_HEAD(input_dev_list); | 33 | static LIST_HEAD(input_dev_list); |
@@ -63,11 +49,13 @@ void input_event(struct input_dev *dev, unsigned int type, unsigned int code, in | |||
63 | case EV_SYN: | 49 | case EV_SYN: |
64 | switch (code) { | 50 | switch (code) { |
65 | case SYN_CONFIG: | 51 | case SYN_CONFIG: |
66 | if (dev->event) dev->event(dev, type, code, value); | 52 | if (dev->event) |
53 | dev->event(dev, type, code, value); | ||
67 | break; | 54 | break; |
68 | 55 | ||
69 | case SYN_REPORT: | 56 | case SYN_REPORT: |
70 | if (dev->sync) return; | 57 | if (dev->sync) |
58 | return; | ||
71 | dev->sync = 1; | 59 | dev->sync = 1; |
72 | break; | 60 | break; |
73 | } | 61 | } |
@@ -136,7 +124,8 @@ void input_event(struct input_dev *dev, unsigned int type, unsigned int code, in | |||
136 | if (code > MSC_MAX || !test_bit(code, dev->mscbit)) | 124 | if (code > MSC_MAX || !test_bit(code, dev->mscbit)) |
137 | return; | 125 | return; |
138 | 126 | ||
139 | if (dev->event) dev->event(dev, type, code, value); | 127 | if (dev->event) |
128 | dev->event(dev, type, code, value); | ||
140 | 129 | ||
141 | break; | 130 | break; |
142 | 131 | ||
@@ -146,7 +135,9 @@ void input_event(struct input_dev *dev, unsigned int type, unsigned int code, in | |||
146 | return; | 135 | return; |
147 | 136 | ||
148 | change_bit(code, dev->led); | 137 | change_bit(code, dev->led); |
149 | if (dev->event) dev->event(dev, type, code, value); | 138 | |
139 | if (dev->event) | ||
140 | dev->event(dev, type, code, value); | ||
150 | 141 | ||
151 | break; | 142 | break; |
152 | 143 | ||
@@ -158,21 +149,25 @@ void input_event(struct input_dev *dev, unsigned int type, unsigned int code, in | |||
158 | if (!!test_bit(code, dev->snd) != !!value) | 149 | if (!!test_bit(code, dev->snd) != !!value) |
159 | change_bit(code, dev->snd); | 150 | change_bit(code, dev->snd); |
160 | 151 | ||
161 | if (dev->event) dev->event(dev, type, code, value); | 152 | if (dev->event) |
153 | dev->event(dev, type, code, value); | ||
162 | 154 | ||
163 | break; | 155 | break; |
164 | 156 | ||
165 | case EV_REP: | 157 | case EV_REP: |
166 | 158 | ||
167 | if (code > REP_MAX || value < 0 || dev->rep[code] == value) return; | 159 | if (code > REP_MAX || value < 0 || dev->rep[code] == value) |
160 | return; | ||
168 | 161 | ||
169 | dev->rep[code] = value; | 162 | dev->rep[code] = value; |
170 | if (dev->event) dev->event(dev, type, code, value); | 163 | if (dev->event) |
164 | dev->event(dev, type, code, value); | ||
171 | 165 | ||
172 | break; | 166 | break; |
173 | 167 | ||
174 | case EV_FF: | 168 | case EV_FF: |
175 | if (dev->event) dev->event(dev, type, code, value); | 169 | if (dev->event) |
170 | dev->event(dev, type, code, value); | ||
176 | break; | 171 | break; |
177 | } | 172 | } |
178 | 173 | ||
@@ -186,6 +181,7 @@ void input_event(struct input_dev *dev, unsigned int type, unsigned int code, in | |||
186 | if (handle->open) | 181 | if (handle->open) |
187 | handle->handler->event(handle, type, code, value); | 182 | handle->handler->event(handle, type, code, value); |
188 | } | 183 | } |
184 | EXPORT_SYMBOL(input_event); | ||
189 | 185 | ||
190 | static void input_repeat_key(unsigned long data) | 186 | static void input_repeat_key(unsigned long data) |
191 | { | 187 | { |
@@ -208,6 +204,7 @@ int input_accept_process(struct input_handle *handle, struct file *file) | |||
208 | 204 | ||
209 | return 0; | 205 | return 0; |
210 | } | 206 | } |
207 | EXPORT_SYMBOL(input_accept_process); | ||
211 | 208 | ||
212 | int input_grab_device(struct input_handle *handle) | 209 | int input_grab_device(struct input_handle *handle) |
213 | { | 210 | { |
@@ -217,12 +214,14 @@ int input_grab_device(struct input_handle *handle) | |||
217 | handle->dev->grab = handle; | 214 | handle->dev->grab = handle; |
218 | return 0; | 215 | return 0; |
219 | } | 216 | } |
217 | EXPORT_SYMBOL(input_grab_device); | ||
220 | 218 | ||
221 | void input_release_device(struct input_handle *handle) | 219 | void input_release_device(struct input_handle *handle) |
222 | { | 220 | { |
223 | if (handle->dev->grab == handle) | 221 | if (handle->dev->grab == handle) |
224 | handle->dev->grab = NULL; | 222 | handle->dev->grab = NULL; |
225 | } | 223 | } |
224 | EXPORT_SYMBOL(input_release_device); | ||
226 | 225 | ||
227 | int input_open_device(struct input_handle *handle) | 226 | int input_open_device(struct input_handle *handle) |
228 | { | 227 | { |
@@ -245,6 +244,7 @@ int input_open_device(struct input_handle *handle) | |||
245 | 244 | ||
246 | return err; | 245 | return err; |
247 | } | 246 | } |
247 | EXPORT_SYMBOL(input_open_device); | ||
248 | 248 | ||
249 | int input_flush_device(struct input_handle* handle, struct file* file) | 249 | int input_flush_device(struct input_handle* handle, struct file* file) |
250 | { | 250 | { |
@@ -253,6 +253,7 @@ int input_flush_device(struct input_handle* handle, struct file* file) | |||
253 | 253 | ||
254 | return 0; | 254 | return 0; |
255 | } | 255 | } |
256 | EXPORT_SYMBOL(input_flush_device); | ||
256 | 257 | ||
257 | void input_close_device(struct input_handle *handle) | 258 | void input_close_device(struct input_handle *handle) |
258 | { | 259 | { |
@@ -268,6 +269,7 @@ void input_close_device(struct input_handle *handle) | |||
268 | 269 | ||
269 | mutex_unlock(&dev->mutex); | 270 | mutex_unlock(&dev->mutex); |
270 | } | 271 | } |
272 | EXPORT_SYMBOL(input_close_device); | ||
271 | 273 | ||
272 | static void input_link_handle(struct input_handle *handle) | 274 | static void input_link_handle(struct input_handle *handle) |
273 | { | 275 | { |
@@ -335,9 +337,11 @@ static inline void input_wakeup_procfs_readers(void) | |||
335 | static unsigned int input_proc_devices_poll(struct file *file, poll_table *wait) | 337 | static unsigned int input_proc_devices_poll(struct file *file, poll_table *wait) |
336 | { | 338 | { |
337 | int state = input_devices_state; | 339 | int state = input_devices_state; |
340 | |||
338 | poll_wait(file, &input_devices_poll_wait, wait); | 341 | poll_wait(file, &input_devices_poll_wait, wait); |
339 | if (state != input_devices_state) | 342 | if (state != input_devices_state) |
340 | return POLLIN | POLLRDNORM; | 343 | return POLLIN | POLLRDNORM; |
344 | |||
341 | return 0; | 345 | return 0; |
342 | } | 346 | } |
343 | 347 | ||
@@ -629,7 +633,7 @@ static ssize_t input_dev_show_modalias(struct class_device *dev, char *buf) | |||
629 | 633 | ||
630 | len = input_print_modalias(buf, PAGE_SIZE, id, 1); | 634 | len = input_print_modalias(buf, PAGE_SIZE, id, 1); |
631 | 635 | ||
632 | return max_t(int, len, PAGE_SIZE); | 636 | return min_t(int, len, PAGE_SIZE); |
633 | } | 637 | } |
634 | static CLASS_DEVICE_ATTR(modalias, S_IRUGO, input_dev_show_modalias, NULL); | 638 | static CLASS_DEVICE_ATTR(modalias, S_IRUGO, input_dev_show_modalias, NULL); |
635 | 639 | ||
@@ -862,6 +866,7 @@ struct class input_class = { | |||
862 | .release = input_dev_release, | 866 | .release = input_dev_release, |
863 | .uevent = input_dev_uevent, | 867 | .uevent = input_dev_uevent, |
864 | }; | 868 | }; |
869 | EXPORT_SYMBOL_GPL(input_class); | ||
865 | 870 | ||
866 | struct input_dev *input_allocate_device(void) | 871 | struct input_dev *input_allocate_device(void) |
867 | { | 872 | { |
@@ -872,12 +877,27 @@ struct input_dev *input_allocate_device(void) | |||
872 | dev->dynalloc = 1; | 877 | dev->dynalloc = 1; |
873 | dev->cdev.class = &input_class; | 878 | dev->cdev.class = &input_class; |
874 | class_device_initialize(&dev->cdev); | 879 | class_device_initialize(&dev->cdev); |
880 | mutex_init(&dev->mutex); | ||
875 | INIT_LIST_HEAD(&dev->h_list); | 881 | INIT_LIST_HEAD(&dev->h_list); |
876 | INIT_LIST_HEAD(&dev->node); | 882 | INIT_LIST_HEAD(&dev->node); |
877 | } | 883 | } |
878 | 884 | ||
879 | return dev; | 885 | return dev; |
880 | } | 886 | } |
887 | EXPORT_SYMBOL(input_allocate_device); | ||
888 | |||
889 | void input_free_device(struct input_dev *dev) | ||
890 | { | ||
891 | if (dev) { | ||
892 | |||
893 | mutex_lock(&dev->mutex); | ||
894 | dev->name = dev->phys = dev->uniq = NULL; | ||
895 | mutex_unlock(&dev->mutex); | ||
896 | |||
897 | input_put_device(dev); | ||
898 | } | ||
899 | } | ||
900 | EXPORT_SYMBOL(input_free_device); | ||
881 | 901 | ||
882 | int input_register_device(struct input_dev *dev) | 902 | int input_register_device(struct input_dev *dev) |
883 | { | 903 | { |
@@ -895,7 +915,6 @@ int input_register_device(struct input_dev *dev) | |||
895 | return -EINVAL; | 915 | return -EINVAL; |
896 | } | 916 | } |
897 | 917 | ||
898 | mutex_init(&dev->mutex); | ||
899 | set_bit(EV_SYN, dev->evbit); | 918 | set_bit(EV_SYN, dev->evbit); |
900 | 919 | ||
901 | /* | 920 | /* |
@@ -956,12 +975,14 @@ int input_register_device(struct input_dev *dev) | |||
956 | fail1: class_device_del(&dev->cdev); | 975 | fail1: class_device_del(&dev->cdev); |
957 | return error; | 976 | return error; |
958 | } | 977 | } |
978 | EXPORT_SYMBOL(input_register_device); | ||
959 | 979 | ||
960 | void input_unregister_device(struct input_dev *dev) | 980 | void input_unregister_device(struct input_dev *dev) |
961 | { | 981 | { |
962 | struct list_head * node, * next; | 982 | struct list_head *node, *next; |
963 | 983 | ||
964 | if (!dev) return; | 984 | if (!dev) |
985 | return; | ||
965 | 986 | ||
966 | del_timer_sync(&dev->timer); | 987 | del_timer_sync(&dev->timer); |
967 | 988 | ||
@@ -977,10 +998,16 @@ void input_unregister_device(struct input_dev *dev) | |||
977 | sysfs_remove_group(&dev->cdev.kobj, &input_dev_caps_attr_group); | 998 | sysfs_remove_group(&dev->cdev.kobj, &input_dev_caps_attr_group); |
978 | sysfs_remove_group(&dev->cdev.kobj, &input_dev_id_attr_group); | 999 | sysfs_remove_group(&dev->cdev.kobj, &input_dev_id_attr_group); |
979 | sysfs_remove_group(&dev->cdev.kobj, &input_dev_attr_group); | 1000 | sysfs_remove_group(&dev->cdev.kobj, &input_dev_attr_group); |
1001 | |||
1002 | mutex_lock(&dev->mutex); | ||
1003 | dev->name = dev->phys = dev->uniq = NULL; | ||
1004 | mutex_unlock(&dev->mutex); | ||
1005 | |||
980 | class_device_unregister(&dev->cdev); | 1006 | class_device_unregister(&dev->cdev); |
981 | 1007 | ||
982 | input_wakeup_procfs_readers(); | 1008 | input_wakeup_procfs_readers(); |
983 | } | 1009 | } |
1010 | EXPORT_SYMBOL(input_unregister_device); | ||
984 | 1011 | ||
985 | void input_register_handler(struct input_handler *handler) | 1012 | void input_register_handler(struct input_handler *handler) |
986 | { | 1013 | { |
@@ -988,7 +1015,8 @@ void input_register_handler(struct input_handler *handler) | |||
988 | struct input_handle *handle; | 1015 | struct input_handle *handle; |
989 | struct input_device_id *id; | 1016 | struct input_device_id *id; |
990 | 1017 | ||
991 | if (!handler) return; | 1018 | if (!handler) |
1019 | return; | ||
992 | 1020 | ||
993 | INIT_LIST_HEAD(&handler->h_list); | 1021 | INIT_LIST_HEAD(&handler->h_list); |
994 | 1022 | ||
@@ -1005,10 +1033,11 @@ void input_register_handler(struct input_handler *handler) | |||
1005 | 1033 | ||
1006 | input_wakeup_procfs_readers(); | 1034 | input_wakeup_procfs_readers(); |
1007 | } | 1035 | } |
1036 | EXPORT_SYMBOL(input_register_handler); | ||
1008 | 1037 | ||
1009 | void input_unregister_handler(struct input_handler *handler) | 1038 | void input_unregister_handler(struct input_handler *handler) |
1010 | { | 1039 | { |
1011 | struct list_head * node, * next; | 1040 | struct list_head *node, *next; |
1012 | 1041 | ||
1013 | list_for_each_safe(node, next, &handler->h_list) { | 1042 | list_for_each_safe(node, next, &handler->h_list) { |
1014 | struct input_handle * handle = to_handle_h(node); | 1043 | struct input_handle * handle = to_handle_h(node); |
@@ -1024,6 +1053,7 @@ void input_unregister_handler(struct input_handler *handler) | |||
1024 | 1053 | ||
1025 | input_wakeup_procfs_readers(); | 1054 | input_wakeup_procfs_readers(); |
1026 | } | 1055 | } |
1056 | EXPORT_SYMBOL(input_unregister_handler); | ||
1027 | 1057 | ||
1028 | static int input_open_file(struct inode *inode, struct file *file) | 1058 | static int input_open_file(struct inode *inode, struct file *file) |
1029 | { | 1059 | { |
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index 949bdcef8c2b..d67157513bf7 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c | |||
@@ -81,10 +81,7 @@ static int joydev_correct(int value, struct js_corr *corr) | |||
81 | return 0; | 81 | return 0; |
82 | } | 82 | } |
83 | 83 | ||
84 | if (value < -32767) return -32767; | 84 | return value < -32767 ? -32767 : (value > 32767 ? 32767 : value); |
85 | if (value > 32767) return 32767; | ||
86 | |||
87 | return value; | ||
88 | } | 85 | } |
89 | 86 | ||
90 | static void joydev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) | 87 | static void joydev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) |
@@ -96,7 +93,8 @@ static void joydev_event(struct input_handle *handle, unsigned int type, unsigne | |||
96 | switch (type) { | 93 | switch (type) { |
97 | 94 | ||
98 | case EV_KEY: | 95 | case EV_KEY: |
99 | if (code < BTN_MISC || value == 2) return; | 96 | if (code < BTN_MISC || value == 2) |
97 | return; | ||
100 | event.type = JS_EVENT_BUTTON; | 98 | event.type = JS_EVENT_BUTTON; |
101 | event.number = joydev->keymap[code - BTN_MISC]; | 99 | event.number = joydev->keymap[code - BTN_MISC]; |
102 | event.value = value; | 100 | event.value = value; |
@@ -106,7 +104,8 @@ static void joydev_event(struct input_handle *handle, unsigned int type, unsigne | |||
106 | event.type = JS_EVENT_AXIS; | 104 | event.type = JS_EVENT_AXIS; |
107 | event.number = joydev->absmap[code]; | 105 | event.number = joydev->absmap[code]; |
108 | event.value = joydev_correct(value, joydev->corr + event.number); | 106 | event.value = joydev_correct(value, joydev->corr + event.number); |
109 | if (event.value == joydev->abs[event.number]) return; | 107 | if (event.value == joydev->abs[event.number]) |
108 | return; | ||
110 | joydev->abs[event.number] = event.value; | 109 | joydev->abs[event.number] = event.value; |
111 | break; | 110 | break; |
112 | 111 | ||
@@ -134,7 +133,9 @@ static int joydev_fasync(int fd, struct file *file, int on) | |||
134 | { | 133 | { |
135 | int retval; | 134 | int retval; |
136 | struct joydev_list *list = file->private_data; | 135 | struct joydev_list *list = file->private_data; |
136 | |||
137 | retval = fasync_helper(fd, file, on, &list->fasync); | 137 | retval = fasync_helper(fd, file, on, &list->fasync); |
138 | |||
138 | return retval < 0 ? retval : 0; | 139 | return retval < 0 ? retval : 0; |
139 | } | 140 | } |
140 | 141 | ||
@@ -222,12 +223,12 @@ static ssize_t joydev_read(struct file *file, char __user *buf, size_t count, lo | |||
222 | return sizeof(struct JS_DATA_TYPE); | 223 | return sizeof(struct JS_DATA_TYPE); |
223 | } | 224 | } |
224 | 225 | ||
225 | if (list->startup == joydev->nabs + joydev->nkey | 226 | if (list->startup == joydev->nabs + joydev->nkey && |
226 | && list->head == list->tail && (file->f_flags & O_NONBLOCK)) | 227 | list->head == list->tail && (file->f_flags & O_NONBLOCK)) |
227 | return -EAGAIN; | 228 | return -EAGAIN; |
228 | 229 | ||
229 | retval = wait_event_interruptible(list->joydev->wait, | 230 | retval = wait_event_interruptible(list->joydev->wait, |
230 | !list->joydev->exist || | 231 | !list->joydev->exist || |
231 | list->startup < joydev->nabs + joydev->nkey || | 232 | list->startup < joydev->nabs + joydev->nkey || |
232 | list->head != list->tail); | 233 | list->head != list->tail); |
233 | 234 | ||
@@ -276,8 +277,9 @@ static ssize_t joydev_read(struct file *file, char __user *buf, size_t count, lo | |||
276 | static unsigned int joydev_poll(struct file *file, poll_table *wait) | 277 | static unsigned int joydev_poll(struct file *file, poll_table *wait) |
277 | { | 278 | { |
278 | struct joydev_list *list = file->private_data; | 279 | struct joydev_list *list = file->private_data; |
280 | |||
279 | poll_wait(file, &list->joydev->wait, wait); | 281 | poll_wait(file, &list->joydev->wait, wait); |
280 | return ((list->head != list->tail || list->startup < list->joydev->nabs + list->joydev->nkey) ? | 282 | return ((list->head != list->tail || list->startup < list->joydev->nabs + list->joydev->nkey) ? |
281 | (POLLIN | POLLRDNORM) : 0) | (list->joydev->exist ? 0 : (POLLHUP | POLLERR)); | 283 | (POLLIN | POLLRDNORM) : 0) | (list->joydev->exist ? 0 : (POLLHUP | POLLERR)); |
282 | } | 284 | } |
283 | 285 | ||
@@ -291,20 +293,26 @@ static int joydev_ioctl_common(struct joydev *joydev, unsigned int cmd, void __u | |||
291 | case JS_SET_CAL: | 293 | case JS_SET_CAL: |
292 | return copy_from_user(&joydev->glue.JS_CORR, argp, | 294 | return copy_from_user(&joydev->glue.JS_CORR, argp, |
293 | sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0; | 295 | sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0; |
296 | |||
294 | case JS_GET_CAL: | 297 | case JS_GET_CAL: |
295 | return copy_to_user(argp, &joydev->glue.JS_CORR, | 298 | return copy_to_user(argp, &joydev->glue.JS_CORR, |
296 | sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0; | 299 | sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0; |
300 | |||
297 | case JS_SET_TIMEOUT: | 301 | case JS_SET_TIMEOUT: |
298 | return get_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp); | 302 | return get_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp); |
303 | |||
299 | case JS_GET_TIMEOUT: | 304 | case JS_GET_TIMEOUT: |
300 | return put_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp); | 305 | return put_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp); |
301 | 306 | ||
302 | case JSIOCGVERSION: | 307 | case JSIOCGVERSION: |
303 | return put_user(JS_VERSION, (__u32 __user *) argp); | 308 | return put_user(JS_VERSION, (__u32 __user *) argp); |
309 | |||
304 | case JSIOCGAXES: | 310 | case JSIOCGAXES: |
305 | return put_user(joydev->nabs, (__u8 __user *) argp); | 311 | return put_user(joydev->nabs, (__u8 __user *) argp); |
312 | |||
306 | case JSIOCGBUTTONS: | 313 | case JSIOCGBUTTONS: |
307 | return put_user(joydev->nkey, (__u8 __user *) argp); | 314 | return put_user(joydev->nkey, (__u8 __user *) argp); |
315 | |||
308 | case JSIOCSCORR: | 316 | case JSIOCSCORR: |
309 | if (copy_from_user(joydev->corr, argp, | 317 | if (copy_from_user(joydev->corr, argp, |
310 | sizeof(joydev->corr[0]) * joydev->nabs)) | 318 | sizeof(joydev->corr[0]) * joydev->nabs)) |
@@ -314,38 +322,49 @@ static int joydev_ioctl_common(struct joydev *joydev, unsigned int cmd, void __u | |||
314 | joydev->abs[i] = joydev_correct(dev->abs[j], joydev->corr + i); | 322 | joydev->abs[i] = joydev_correct(dev->abs[j], joydev->corr + i); |
315 | } | 323 | } |
316 | return 0; | 324 | return 0; |
325 | |||
317 | case JSIOCGCORR: | 326 | case JSIOCGCORR: |
318 | return copy_to_user(argp, joydev->corr, | 327 | return copy_to_user(argp, joydev->corr, |
319 | sizeof(joydev->corr[0]) * joydev->nabs) ? -EFAULT : 0; | 328 | sizeof(joydev->corr[0]) * joydev->nabs) ? -EFAULT : 0; |
329 | |||
320 | case JSIOCSAXMAP: | 330 | case JSIOCSAXMAP: |
321 | if (copy_from_user(joydev->abspam, argp, sizeof(__u8) * (ABS_MAX + 1))) | 331 | if (copy_from_user(joydev->abspam, argp, sizeof(__u8) * (ABS_MAX + 1))) |
322 | return -EFAULT; | 332 | return -EFAULT; |
323 | for (i = 0; i < joydev->nabs; i++) { | 333 | for (i = 0; i < joydev->nabs; i++) { |
324 | if (joydev->abspam[i] > ABS_MAX) return -EINVAL; | 334 | if (joydev->abspam[i] > ABS_MAX) |
335 | return -EINVAL; | ||
325 | joydev->absmap[joydev->abspam[i]] = i; | 336 | joydev->absmap[joydev->abspam[i]] = i; |
326 | } | 337 | } |
327 | return 0; | 338 | return 0; |
339 | |||
328 | case JSIOCGAXMAP: | 340 | case JSIOCGAXMAP: |
329 | return copy_to_user(argp, joydev->abspam, | 341 | return copy_to_user(argp, joydev->abspam, |
330 | sizeof(__u8) * (ABS_MAX + 1)) ? -EFAULT : 0; | 342 | sizeof(__u8) * (ABS_MAX + 1)) ? -EFAULT : 0; |
343 | |||
331 | case JSIOCSBTNMAP: | 344 | case JSIOCSBTNMAP: |
332 | if (copy_from_user(joydev->keypam, argp, sizeof(__u16) * (KEY_MAX - BTN_MISC + 1))) | 345 | if (copy_from_user(joydev->keypam, argp, sizeof(__u16) * (KEY_MAX - BTN_MISC + 1))) |
333 | return -EFAULT; | 346 | return -EFAULT; |
334 | for (i = 0; i < joydev->nkey; i++) { | 347 | for (i = 0; i < joydev->nkey; i++) { |
335 | if (joydev->keypam[i] > KEY_MAX || joydev->keypam[i] < BTN_MISC) return -EINVAL; | 348 | if (joydev->keypam[i] > KEY_MAX || joydev->keypam[i] < BTN_MISC) |
349 | return -EINVAL; | ||
336 | joydev->keymap[joydev->keypam[i] - BTN_MISC] = i; | 350 | joydev->keymap[joydev->keypam[i] - BTN_MISC] = i; |
337 | } | 351 | } |
338 | return 0; | 352 | return 0; |
353 | |||
339 | case JSIOCGBTNMAP: | 354 | case JSIOCGBTNMAP: |
340 | return copy_to_user(argp, joydev->keypam, | 355 | return copy_to_user(argp, joydev->keypam, |
341 | sizeof(__u16) * (KEY_MAX - BTN_MISC + 1)) ? -EFAULT : 0; | 356 | sizeof(__u16) * (KEY_MAX - BTN_MISC + 1)) ? -EFAULT : 0; |
357 | |||
342 | default: | 358 | default: |
343 | if ((cmd & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) == JSIOCGNAME(0)) { | 359 | if ((cmd & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) == JSIOCGNAME(0)) { |
344 | int len; | 360 | int len; |
345 | if (!dev->name) return 0; | 361 | if (!dev->name) |
362 | return 0; | ||
346 | len = strlen(dev->name) + 1; | 363 | len = strlen(dev->name) + 1; |
347 | if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); | 364 | if (len > _IOC_SIZE(cmd)) |
348 | if (copy_to_user(argp, dev->name, len)) return -EFAULT; | 365 | len = _IOC_SIZE(cmd); |
366 | if (copy_to_user(argp, dev->name, len)) | ||
367 | return -EFAULT; | ||
349 | return len; | 368 | return len; |
350 | } | 369 | } |
351 | } | 370 | } |
@@ -362,7 +381,9 @@ static long joydev_compat_ioctl(struct file *file, unsigned int cmd, unsigned lo | |||
362 | struct JS_DATA_SAVE_TYPE_32 ds32; | 381 | struct JS_DATA_SAVE_TYPE_32 ds32; |
363 | int err; | 382 | int err; |
364 | 383 | ||
365 | if (!joydev->exist) return -ENODEV; | 384 | if (!joydev->exist) |
385 | return -ENODEV; | ||
386 | |||
366 | switch(cmd) { | 387 | switch(cmd) { |
367 | case JS_SET_TIMELIMIT: | 388 | case JS_SET_TIMELIMIT: |
368 | err = get_user(tmp32, (s32 __user *) arg); | 389 | err = get_user(tmp32, (s32 __user *) arg); |
@@ -395,8 +416,7 @@ static long joydev_compat_ioctl(struct file *file, unsigned int cmd, unsigned lo | |||
395 | ds32.JS_SAVE = joydev->glue.JS_SAVE; | 416 | ds32.JS_SAVE = joydev->glue.JS_SAVE; |
396 | ds32.JS_CORR = joydev->glue.JS_CORR; | 417 | ds32.JS_CORR = joydev->glue.JS_CORR; |
397 | 418 | ||
398 | err = copy_to_user(argp, &ds32, | 419 | err = copy_to_user(argp, &ds32, sizeof(ds32)) ? -EFAULT : 0; |
399 | sizeof(ds32)) ? -EFAULT : 0; | ||
400 | break; | 420 | break; |
401 | 421 | ||
402 | default: | 422 | default: |
@@ -412,7 +432,8 @@ static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd | |||
412 | struct joydev *joydev = list->joydev; | 432 | struct joydev *joydev = list->joydev; |
413 | void __user *argp = (void __user *)arg; | 433 | void __user *argp = (void __user *)arg; |
414 | 434 | ||
415 | if (!joydev->exist) return -ENODEV; | 435 | if (!joydev->exist) |
436 | return -ENODEV; | ||
416 | 437 | ||
417 | switch(cmd) { | 438 | switch(cmd) { |
418 | case JS_SET_TIMELIMIT: | 439 | case JS_SET_TIMELIMIT: |
@@ -546,8 +567,8 @@ static struct input_device_id joydev_blacklist[] = { | |||
546 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, | 567 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, |
547 | .evbit = { BIT(EV_KEY) }, | 568 | .evbit = { BIT(EV_KEY) }, |
548 | .keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) }, | 569 | .keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) }, |
549 | }, /* Avoid itouchpads, touchscreens and tablets */ | 570 | }, /* Avoid itouchpads, touchscreens and tablets */ |
550 | { }, /* Terminating entry */ | 571 | { } /* Terminating entry */ |
551 | }; | 572 | }; |
552 | 573 | ||
553 | static struct input_device_id joydev_ids[] = { | 574 | static struct input_device_id joydev_ids[] = { |
@@ -566,7 +587,7 @@ static struct input_device_id joydev_ids[] = { | |||
566 | .evbit = { BIT(EV_ABS) }, | 587 | .evbit = { BIT(EV_ABS) }, |
567 | .absbit = { BIT(ABS_THROTTLE) }, | 588 | .absbit = { BIT(ABS_THROTTLE) }, |
568 | }, | 589 | }, |
569 | { }, /* Terminating entry */ | 590 | { } /* Terminating entry */ |
570 | }; | 591 | }; |
571 | 592 | ||
572 | MODULE_DEVICE_TABLE(input, joydev_ids); | 593 | MODULE_DEVICE_TABLE(input, joydev_ids); |
@@ -579,7 +600,7 @@ static struct input_handler joydev_handler = { | |||
579 | .minor = JOYDEV_MINOR_BASE, | 600 | .minor = JOYDEV_MINOR_BASE, |
580 | .name = "joydev", | 601 | .name = "joydev", |
581 | .id_table = joydev_ids, | 602 | .id_table = joydev_ids, |
582 | .blacklist = joydev_blacklist, | 603 | .blacklist = joydev_blacklist, |
583 | }; | 604 | }; |
584 | 605 | ||
585 | static int __init joydev_init(void) | 606 | static int __init joydev_init(void) |
diff --git a/drivers/input/joystick/a3d.c b/drivers/input/joystick/a3d.c index 4612d13ea756..b11a4bbc84c4 100644 --- a/drivers/input/joystick/a3d.c +++ b/drivers/input/joystick/a3d.c | |||
@@ -306,7 +306,7 @@ static int a3d_connect(struct gameport *gameport, struct gameport_driver *drv) | |||
306 | gameport_set_poll_handler(gameport, a3d_poll); | 306 | gameport_set_poll_handler(gameport, a3d_poll); |
307 | gameport_set_poll_interval(gameport, 20); | 307 | gameport_set_poll_interval(gameport, 20); |
308 | 308 | ||
309 | sprintf(a3d->phys, "%s/input0", gameport->phys); | 309 | snprintf(a3d->phys, sizeof(a3d->phys), "%s/input0", gameport->phys); |
310 | 310 | ||
311 | input_dev->name = a3d_names[a3d->mode]; | 311 | input_dev->name = a3d_names[a3d->mode]; |
312 | input_dev->phys = a3d->phys; | 312 | input_dev->phys = a3d->phys; |
diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c index 3121961e3e7c..01dc0b195d59 100644 --- a/drivers/input/joystick/analog.c +++ b/drivers/input/joystick/analog.c | |||
@@ -408,21 +408,23 @@ static void analog_calibrate_timer(struct analog_port *port) | |||
408 | 408 | ||
409 | static void analog_name(struct analog *analog) | 409 | static void analog_name(struct analog *analog) |
410 | { | 410 | { |
411 | sprintf(analog->name, "Analog %d-axis %d-button", | 411 | snprintf(analog->name, sizeof(analog->name), "Analog %d-axis %d-button", |
412 | hweight8(analog->mask & ANALOG_AXES_STD), | 412 | hweight8(analog->mask & ANALOG_AXES_STD), |
413 | hweight8(analog->mask & ANALOG_BTNS_STD) + !!(analog->mask & ANALOG_BTNS_CHF) * 2 + | 413 | hweight8(analog->mask & ANALOG_BTNS_STD) + !!(analog->mask & ANALOG_BTNS_CHF) * 2 + |
414 | hweight16(analog->mask & ANALOG_BTNS_GAMEPAD) + !!(analog->mask & ANALOG_HBTN_CHF) * 4); | 414 | hweight16(analog->mask & ANALOG_BTNS_GAMEPAD) + !!(analog->mask & ANALOG_HBTN_CHF) * 4); |
415 | 415 | ||
416 | if (analog->mask & ANALOG_HATS_ALL) | 416 | if (analog->mask & ANALOG_HATS_ALL) |
417 | sprintf(analog->name, "%s %d-hat", | 417 | snprintf(analog->name, sizeof(analog->name), "%s %d-hat", |
418 | analog->name, hweight16(analog->mask & ANALOG_HATS_ALL)); | 418 | analog->name, hweight16(analog->mask & ANALOG_HATS_ALL)); |
419 | 419 | ||
420 | if (analog->mask & ANALOG_HAT_FCS) | 420 | if (analog->mask & ANALOG_HAT_FCS) |
421 | strcat(analog->name, " FCS"); | 421 | strlcat(analog->name, " FCS", sizeof(analog->name)); |
422 | if (analog->mask & ANALOG_ANY_CHF) | 422 | if (analog->mask & ANALOG_ANY_CHF) |
423 | strcat(analog->name, (analog->mask & ANALOG_SAITEK) ? " Saitek" : " CHF"); | 423 | strlcat(analog->name, (analog->mask & ANALOG_SAITEK) ? " Saitek" : " CHF", |
424 | sizeof(analog->name)); | ||
424 | 425 | ||
425 | strcat(analog->name, (analog->mask & ANALOG_GAMEPAD) ? " gamepad": " joystick"); | 426 | strlcat(analog->name, (analog->mask & ANALOG_GAMEPAD) ? " gamepad": " joystick", |
427 | sizeof(analog->name)); | ||
426 | } | 428 | } |
427 | 429 | ||
428 | /* | 430 | /* |
@@ -435,7 +437,8 @@ static int analog_init_device(struct analog_port *port, struct analog *analog, i | |||
435 | int i, j, t, v, w, x, y, z; | 437 | int i, j, t, v, w, x, y, z; |
436 | 438 | ||
437 | analog_name(analog); | 439 | analog_name(analog); |
438 | sprintf(analog->phys, "%s/input%d", port->gameport->phys, index); | 440 | snprintf(analog->phys, sizeof(analog->phys), |
441 | "%s/input%d", port->gameport->phys, index); | ||
439 | analog->buttons = (analog->mask & ANALOG_GAMEPAD) ? analog_pad_btn : analog_joy_btn; | 442 | analog->buttons = (analog->mask & ANALOG_GAMEPAD) ? analog_pad_btn : analog_joy_btn; |
440 | 443 | ||
441 | analog->dev = input_dev = input_allocate_device(); | 444 | analog->dev = input_dev = input_allocate_device(); |
diff --git a/drivers/input/joystick/cobra.c b/drivers/input/joystick/cobra.c index 1909f7ef340c..d5e42eb88a20 100644 --- a/drivers/input/joystick/cobra.c +++ b/drivers/input/joystick/cobra.c | |||
@@ -202,7 +202,8 @@ static int cobra_connect(struct gameport *gameport, struct gameport_driver *drv) | |||
202 | goto fail3; | 202 | goto fail3; |
203 | } | 203 | } |
204 | 204 | ||
205 | sprintf(cobra->phys[i], "%s/input%d", gameport->phys, i); | 205 | snprintf(cobra->phys[i], sizeof(cobra->phys[i]), |
206 | "%s/input%d", gameport->phys, i); | ||
206 | 207 | ||
207 | input_dev->name = "Creative Labs Blaster GamePad Cobra"; | 208 | input_dev->name = "Creative Labs Blaster GamePad Cobra"; |
208 | input_dev->phys = cobra->phys[i]; | 209 | input_dev->phys = cobra->phys[i]; |
diff --git a/drivers/input/joystick/db9.c b/drivers/input/joystick/db9.c index e61894685cb1..6f31f054d1bb 100644 --- a/drivers/input/joystick/db9.c +++ b/drivers/input/joystick/db9.c | |||
@@ -620,7 +620,8 @@ static struct db9 __init *db9_probe(int parport, int mode) | |||
620 | goto err_unreg_devs; | 620 | goto err_unreg_devs; |
621 | } | 621 | } |
622 | 622 | ||
623 | sprintf(db9->phys[i], "%s/input%d", db9->pd->port->name, i); | 623 | snprintf(db9->phys[i], sizeof(db9->phys[i]), |
624 | "%s/input%d", db9->pd->port->name, i); | ||
624 | 625 | ||
625 | input_dev->name = db9_mode->name; | 626 | input_dev->name = db9_mode->name; |
626 | input_dev->phys = db9->phys[i]; | 627 | input_dev->phys = db9->phys[i]; |
diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c index ecbdb6b9bbd6..fe12aa37393d 100644 --- a/drivers/input/joystick/gamecon.c +++ b/drivers/input/joystick/gamecon.c | |||
@@ -761,7 +761,8 @@ static struct gc __init *gc_probe(int parport, int *pads, int n_pads) | |||
761 | if (!pads[i]) | 761 | if (!pads[i]) |
762 | continue; | 762 | continue; |
763 | 763 | ||
764 | sprintf(gc->phys[i], "%s/input%d", gc->pd->port->name, i); | 764 | snprintf(gc->phys[i], sizeof(gc->phys[i]), |
765 | "%s/input%d", gc->pd->port->name, i); | ||
765 | err = gc_setup_pad(gc, i, pads[i]); | 766 | err = gc_setup_pad(gc, i, pads[i]); |
766 | if (err) | 767 | if (err) |
767 | goto err_unreg_devs; | 768 | goto err_unreg_devs; |
diff --git a/drivers/input/joystick/gf2k.c b/drivers/input/joystick/gf2k.c index 8a3ad455eb38..e4a699f6ec87 100644 --- a/drivers/input/joystick/gf2k.c +++ b/drivers/input/joystick/gf2k.c | |||
@@ -298,7 +298,7 @@ static int gf2k_connect(struct gameport *gameport, struct gameport_driver *drv) | |||
298 | gameport_set_poll_handler(gameport, gf2k_poll); | 298 | gameport_set_poll_handler(gameport, gf2k_poll); |
299 | gameport_set_poll_interval(gameport, 20); | 299 | gameport_set_poll_interval(gameport, 20); |
300 | 300 | ||
301 | sprintf(gf2k->phys, "%s/input0", gameport->phys); | 301 | snprintf(gf2k->phys, sizeof(gf2k->phys), "%s/input0", gameport->phys); |
302 | 302 | ||
303 | gf2k->length = gf2k_lens[gf2k->id]; | 303 | gf2k->length = gf2k_lens[gf2k->id]; |
304 | 304 | ||
diff --git a/drivers/input/joystick/grip.c b/drivers/input/joystick/grip.c index 20cb98ac2d79..17a90c436de8 100644 --- a/drivers/input/joystick/grip.c +++ b/drivers/input/joystick/grip.c | |||
@@ -354,7 +354,8 @@ static int grip_connect(struct gameport *gameport, struct gameport_driver *drv) | |||
354 | goto fail3; | 354 | goto fail3; |
355 | } | 355 | } |
356 | 356 | ||
357 | sprintf(grip->phys[i], "%s/input%d", gameport->phys, i); | 357 | snprintf(grip->phys[i], sizeof(grip->phys[i]), |
358 | "%s/input%d", gameport->phys, i); | ||
358 | 359 | ||
359 | input_dev->name = grip_name[grip->mode[i]]; | 360 | input_dev->name = grip_name[grip->mode[i]]; |
360 | input_dev->phys = grip->phys[i]; | 361 | input_dev->phys = grip->phys[i]; |
diff --git a/drivers/input/joystick/guillemot.c b/drivers/input/joystick/guillemot.c index 6e2c721c26ba..840ed9b512b2 100644 --- a/drivers/input/joystick/guillemot.c +++ b/drivers/input/joystick/guillemot.c | |||
@@ -222,7 +222,7 @@ static int guillemot_connect(struct gameport *gameport, struct gameport_driver * | |||
222 | gameport_set_poll_handler(gameport, guillemot_poll); | 222 | gameport_set_poll_handler(gameport, guillemot_poll); |
223 | gameport_set_poll_interval(gameport, 20); | 223 | gameport_set_poll_interval(gameport, 20); |
224 | 224 | ||
225 | sprintf(guillemot->phys, "%s/input0", gameport->phys); | 225 | snprintf(guillemot->phys, sizeof(guillemot->phys), "%s/input0", gameport->phys); |
226 | guillemot->type = guillemot_type + i; | 226 | guillemot->type = guillemot_type + i; |
227 | 227 | ||
228 | input_dev->name = guillemot_type[i].name; | 228 | input_dev->name = guillemot_type[i].name; |
diff --git a/drivers/input/joystick/iforce/iforce-ff.c b/drivers/input/joystick/iforce/iforce-ff.c index 2b8e8456c9fa..50c90765aee1 100644 --- a/drivers/input/joystick/iforce/iforce-ff.c +++ b/drivers/input/joystick/iforce/iforce-ff.c | |||
@@ -47,7 +47,7 @@ static int make_magnitude_modifier(struct iforce* iforce, | |||
47 | iforce->device_memory.start, iforce->device_memory.end, 2L, | 47 | iforce->device_memory.start, iforce->device_memory.end, 2L, |
48 | NULL, NULL)) { | 48 | NULL, NULL)) { |
49 | mutex_unlock(&iforce->mem_mutex); | 49 | mutex_unlock(&iforce->mem_mutex); |
50 | return -ENOMEM; | 50 | return -ENOSPC; |
51 | } | 51 | } |
52 | mutex_unlock(&iforce->mem_mutex); | 52 | mutex_unlock(&iforce->mem_mutex); |
53 | } | 53 | } |
@@ -80,7 +80,7 @@ static int make_period_modifier(struct iforce* iforce, | |||
80 | iforce->device_memory.start, iforce->device_memory.end, 2L, | 80 | iforce->device_memory.start, iforce->device_memory.end, 2L, |
81 | NULL, NULL)) { | 81 | NULL, NULL)) { |
82 | mutex_unlock(&iforce->mem_mutex); | 82 | mutex_unlock(&iforce->mem_mutex); |
83 | return -ENOMEM; | 83 | return -ENOSPC; |
84 | } | 84 | } |
85 | mutex_unlock(&iforce->mem_mutex); | 85 | mutex_unlock(&iforce->mem_mutex); |
86 | } | 86 | } |
@@ -120,7 +120,7 @@ static int make_envelope_modifier(struct iforce* iforce, | |||
120 | iforce->device_memory.start, iforce->device_memory.end, 2L, | 120 | iforce->device_memory.start, iforce->device_memory.end, 2L, |
121 | NULL, NULL)) { | 121 | NULL, NULL)) { |
122 | mutex_unlock(&iforce->mem_mutex); | 122 | mutex_unlock(&iforce->mem_mutex); |
123 | return -ENOMEM; | 123 | return -ENOSPC; |
124 | } | 124 | } |
125 | mutex_unlock(&iforce->mem_mutex); | 125 | mutex_unlock(&iforce->mem_mutex); |
126 | } | 126 | } |
@@ -157,7 +157,7 @@ static int make_condition_modifier(struct iforce* iforce, | |||
157 | iforce->device_memory.start, iforce->device_memory.end, 2L, | 157 | iforce->device_memory.start, iforce->device_memory.end, 2L, |
158 | NULL, NULL)) { | 158 | NULL, NULL)) { |
159 | mutex_unlock(&iforce->mem_mutex); | 159 | mutex_unlock(&iforce->mem_mutex); |
160 | return -ENOMEM; | 160 | return -ENOSPC; |
161 | } | 161 | } |
162 | mutex_unlock(&iforce->mem_mutex); | 162 | mutex_unlock(&iforce->mem_mutex); |
163 | } | 163 | } |
diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c index ab0a26b924ca..6d99e3c37884 100644 --- a/drivers/input/joystick/iforce/iforce-main.c +++ b/drivers/input/joystick/iforce/iforce-main.c | |||
@@ -86,7 +86,7 @@ static struct iforce_device iforce_device[] = { | |||
86 | 86 | ||
87 | static int iforce_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) | 87 | static int iforce_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) |
88 | { | 88 | { |
89 | struct iforce* iforce = (struct iforce*)(dev->private); | 89 | struct iforce* iforce = dev->private; |
90 | unsigned char data[3]; | 90 | unsigned char data[3]; |
91 | 91 | ||
92 | if (type != EV_FF) | 92 | if (type != EV_FF) |
@@ -138,7 +138,7 @@ static int iforce_input_event(struct input_dev *dev, unsigned int type, unsigned | |||
138 | */ | 138 | */ |
139 | static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect) | 139 | static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect) |
140 | { | 140 | { |
141 | struct iforce* iforce = (struct iforce*)(dev->private); | 141 | struct iforce* iforce = dev->private; |
142 | int id; | 142 | int id; |
143 | int ret; | 143 | int ret; |
144 | int is_update; | 144 | int is_update; |
@@ -218,7 +218,7 @@ static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect) | |||
218 | */ | 218 | */ |
219 | static int iforce_erase_effect(struct input_dev *dev, int effect_id) | 219 | static int iforce_erase_effect(struct input_dev *dev, int effect_id) |
220 | { | 220 | { |
221 | struct iforce* iforce = (struct iforce*)(dev->private); | 221 | struct iforce* iforce = dev->private; |
222 | int err = 0; | 222 | int err = 0; |
223 | struct iforce_core_effect* core_effect; | 223 | struct iforce_core_effect* core_effect; |
224 | 224 | ||
diff --git a/drivers/input/joystick/interact.c b/drivers/input/joystick/interact.c index c4ed01758226..bbfeb9c59b87 100644 --- a/drivers/input/joystick/interact.c +++ b/drivers/input/joystick/interact.c | |||
@@ -251,7 +251,7 @@ static int interact_connect(struct gameport *gameport, struct gameport_driver *d | |||
251 | gameport_set_poll_handler(gameport, interact_poll); | 251 | gameport_set_poll_handler(gameport, interact_poll); |
252 | gameport_set_poll_interval(gameport, 20); | 252 | gameport_set_poll_interval(gameport, 20); |
253 | 253 | ||
254 | sprintf(interact->phys, "%s/input0", gameport->phys); | 254 | snprintf(interact->phys, sizeof(interact->phys), "%s/input0", gameport->phys); |
255 | 255 | ||
256 | interact->type = i; | 256 | interact->type = i; |
257 | interact->length = interact_type[i].length; | 257 | interact->length = interact_type[i].length; |
diff --git a/drivers/input/joystick/magellan.c b/drivers/input/joystick/magellan.c index ca3cc2319d6a..168b1061a03b 100644 --- a/drivers/input/joystick/magellan.c +++ b/drivers/input/joystick/magellan.c | |||
@@ -162,7 +162,7 @@ static int magellan_connect(struct serio *serio, struct serio_driver *drv) | |||
162 | goto fail; | 162 | goto fail; |
163 | 163 | ||
164 | magellan->dev = input_dev; | 164 | magellan->dev = input_dev; |
165 | sprintf(magellan->phys, "%s/input0", serio->phys); | 165 | snprintf(magellan->phys, sizeof(magellan->phys), "%s/input0", serio->phys); |
166 | 166 | ||
167 | input_dev->name = "LogiCad3D Magellan / SpaceMouse"; | 167 | input_dev->name = "LogiCad3D Magellan / SpaceMouse"; |
168 | input_dev->phys = magellan->phys; | 168 | input_dev->phys = magellan->phys; |
diff --git a/drivers/input/joystick/sidewinder.c b/drivers/input/joystick/sidewinder.c index 95c0de7964a0..e58b22c018e4 100644 --- a/drivers/input/joystick/sidewinder.c +++ b/drivers/input/joystick/sidewinder.c | |||
@@ -541,7 +541,7 @@ static void sw_print_packet(char *name, int length, unsigned char *buf, char bit | |||
541 | * Unfortunately I don't know how to do this for the other SW types. | 541 | * Unfortunately I don't know how to do this for the other SW types. |
542 | */ | 542 | */ |
543 | 543 | ||
544 | static void sw_3dp_id(unsigned char *buf, char *comment) | 544 | static void sw_3dp_id(unsigned char *buf, char *comment, size_t size) |
545 | { | 545 | { |
546 | int i; | 546 | int i; |
547 | char pnp[8], rev[9]; | 547 | char pnp[8], rev[9]; |
@@ -554,7 +554,7 @@ static void sw_3dp_id(unsigned char *buf, char *comment) | |||
554 | 554 | ||
555 | pnp[7] = rev[8] = 0; | 555 | pnp[7] = rev[8] = 0; |
556 | 556 | ||
557 | sprintf(comment, " [PnP %d.%02d id %s rev %s]", | 557 | snprintf(comment, size, " [PnP %d.%02d id %s rev %s]", |
558 | (int) ((sw_get_bits(buf, 8, 6, 1) << 6) | /* Two 6-bit values */ | 558 | (int) ((sw_get_bits(buf, 8, 6, 1) << 6) | /* Two 6-bit values */ |
559 | sw_get_bits(buf, 16, 6, 1)) / 100, | 559 | sw_get_bits(buf, 16, 6, 1)) / 100, |
560 | (int) ((sw_get_bits(buf, 8, 6, 1) << 6) | | 560 | (int) ((sw_get_bits(buf, 8, 6, 1) << 6) | |
@@ -695,7 +695,7 @@ static int sw_connect(struct gameport *gameport, struct gameport_driver *drv) | |||
695 | sw->type = SW_ID_FFP; | 695 | sw->type = SW_ID_FFP; |
696 | sprintf(comment, " [AC %s]", sw_get_bits(idbuf,38,1,3) ? "off" : "on"); | 696 | sprintf(comment, " [AC %s]", sw_get_bits(idbuf,38,1,3) ? "off" : "on"); |
697 | } else | 697 | } else |
698 | sw->type = SW_ID_PP; | 698 | sw->type = SW_ID_PP; |
699 | break; | 699 | break; |
700 | case 66: | 700 | case 66: |
701 | sw->bits = 3; | 701 | sw->bits = 3; |
@@ -703,7 +703,8 @@ static int sw_connect(struct gameport *gameport, struct gameport_driver *drv) | |||
703 | sw->length = 22; | 703 | sw->length = 22; |
704 | case 64: | 704 | case 64: |
705 | sw->type = SW_ID_3DP; | 705 | sw->type = SW_ID_3DP; |
706 | if (j == 160) sw_3dp_id(idbuf, comment); | 706 | if (j == 160) |
707 | sw_3dp_id(idbuf, comment, sizeof(comment)); | ||
707 | break; | 708 | break; |
708 | } | 709 | } |
709 | } | 710 | } |
@@ -733,8 +734,10 @@ static int sw_connect(struct gameport *gameport, struct gameport_driver *drv) | |||
733 | for (i = 0; i < sw->number; i++) { | 734 | for (i = 0; i < sw->number; i++) { |
734 | int bits, code; | 735 | int bits, code; |
735 | 736 | ||
736 | sprintf(sw->name, "Microsoft SideWinder %s", sw_name[sw->type]); | 737 | snprintf(sw->name, sizeof(sw->name), |
737 | sprintf(sw->phys[i], "%s/input%d", gameport->phys, i); | 738 | "Microsoft SideWinder %s", sw_name[sw->type]); |
739 | snprintf(sw->phys[i], sizeof(sw->phys[i]), | ||
740 | "%s/input%d", gameport->phys, i); | ||
738 | 741 | ||
739 | sw->dev[i] = input_dev = input_allocate_device(); | 742 | sw->dev[i] = input_dev = input_allocate_device(); |
740 | if (!input_dev) { | 743 | if (!input_dev) { |
diff --git a/drivers/input/joystick/spaceball.c b/drivers/input/joystick/spaceball.c index d6f8db8ec3fd..75eb5ca59992 100644 --- a/drivers/input/joystick/spaceball.c +++ b/drivers/input/joystick/spaceball.c | |||
@@ -220,7 +220,7 @@ static int spaceball_connect(struct serio *serio, struct serio_driver *drv) | |||
220 | goto fail; | 220 | goto fail; |
221 | 221 | ||
222 | spaceball->dev = input_dev; | 222 | spaceball->dev = input_dev; |
223 | sprintf(spaceball->phys, "%s/input0", serio->phys); | 223 | snprintf(spaceball->phys, sizeof(spaceball->phys), "%s/input0", serio->phys); |
224 | 224 | ||
225 | input_dev->name = spaceball_names[id]; | 225 | input_dev->name = spaceball_names[id]; |
226 | input_dev->phys = spaceball->phys; | 226 | input_dev->phys = spaceball->phys; |
diff --git a/drivers/input/joystick/spaceorb.c b/drivers/input/joystick/spaceorb.c index 7c123a01c58e..3e2782e79834 100644 --- a/drivers/input/joystick/spaceorb.c +++ b/drivers/input/joystick/spaceorb.c | |||
@@ -177,7 +177,7 @@ static int spaceorb_connect(struct serio *serio, struct serio_driver *drv) | |||
177 | goto fail; | 177 | goto fail; |
178 | 178 | ||
179 | spaceorb->dev = input_dev; | 179 | spaceorb->dev = input_dev; |
180 | sprintf(spaceorb->phys, "%s/input0", serio->phys); | 180 | snprintf(spaceorb->phys, sizeof(spaceorb->phys), "%s/input0", serio->phys); |
181 | 181 | ||
182 | input_dev->name = "SpaceTec SpaceOrb 360 / Avenger"; | 182 | input_dev->name = "SpaceTec SpaceOrb 360 / Avenger"; |
183 | input_dev->phys = spaceorb->phys; | 183 | input_dev->phys = spaceorb->phys; |
diff --git a/drivers/input/joystick/stinger.c b/drivers/input/joystick/stinger.c index 0a9ed1d30636..011ec4858e15 100644 --- a/drivers/input/joystick/stinger.c +++ b/drivers/input/joystick/stinger.c | |||
@@ -148,7 +148,7 @@ static int stinger_connect(struct serio *serio, struct serio_driver *drv) | |||
148 | goto fail; | 148 | goto fail; |
149 | 149 | ||
150 | stinger->dev = input_dev; | 150 | stinger->dev = input_dev; |
151 | sprintf(stinger->phys, "%s/serio0", serio->phys); | 151 | snprintf(stinger->phys, sizeof(stinger->phys), "%s/serio0", serio->phys); |
152 | 152 | ||
153 | input_dev->name = "Gravis Stinger"; | 153 | input_dev->name = "Gravis Stinger"; |
154 | input_dev->phys = stinger->phys; | 154 | input_dev->phys = stinger->phys; |
diff --git a/drivers/input/joystick/twidjoy.c b/drivers/input/joystick/twidjoy.c index 7f8b0093c5bc..076f237d9654 100644 --- a/drivers/input/joystick/twidjoy.c +++ b/drivers/input/joystick/twidjoy.c | |||
@@ -199,7 +199,7 @@ static int twidjoy_connect(struct serio *serio, struct serio_driver *drv) | |||
199 | goto fail; | 199 | goto fail; |
200 | 200 | ||
201 | twidjoy->dev = input_dev; | 201 | twidjoy->dev = input_dev; |
202 | sprintf(twidjoy->phys, "%s/input0", serio->phys); | 202 | snprintf(twidjoy->phys, sizeof(twidjoy->phys), "%s/input0", serio->phys); |
203 | 203 | ||
204 | input_dev->name = "Handykey Twiddler"; | 204 | input_dev->name = "Handykey Twiddler"; |
205 | input_dev->phys = twidjoy->phys; | 205 | input_dev->phys = twidjoy->phys; |
diff --git a/drivers/input/joystick/warrior.c b/drivers/input/joystick/warrior.c index 1849b176cf18..f9c1a03214eb 100644 --- a/drivers/input/joystick/warrior.c +++ b/drivers/input/joystick/warrior.c | |||
@@ -154,7 +154,7 @@ static int warrior_connect(struct serio *serio, struct serio_driver *drv) | |||
154 | goto fail; | 154 | goto fail; |
155 | 155 | ||
156 | warrior->dev = input_dev; | 156 | warrior->dev = input_dev; |
157 | sprintf(warrior->phys, "%s/input0", serio->phys); | 157 | snprintf(warrior->phys, sizeof(warrior->phys), "%s/input0", serio->phys); |
158 | 158 | ||
159 | input_dev->name = "Logitech WingMan Warrior"; | 159 | input_dev->name = "Logitech WingMan Warrior"; |
160 | input_dev->phys = warrior->phys; | 160 | input_dev->phys = warrior->phys; |
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index fad04b66d268..ffde8f86e0fb 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c | |||
@@ -55,7 +55,7 @@ static int atkbd_softraw = 1; | |||
55 | module_param_named(softraw, atkbd_softraw, bool, 0); | 55 | module_param_named(softraw, atkbd_softraw, bool, 0); |
56 | MODULE_PARM_DESC(softraw, "Use software generated rawmode"); | 56 | MODULE_PARM_DESC(softraw, "Use software generated rawmode"); |
57 | 57 | ||
58 | static int atkbd_scroll = 0; | 58 | static int atkbd_scroll; |
59 | module_param_named(scroll, atkbd_scroll, bool, 0); | 59 | module_param_named(scroll, atkbd_scroll, bool, 0); |
60 | MODULE_PARM_DESC(scroll, "Enable scroll-wheel on MS Office and similar keyboards"); | 60 | MODULE_PARM_DESC(scroll, "Enable scroll-wheel on MS Office and similar keyboards"); |
61 | 61 | ||
@@ -150,8 +150,8 @@ static unsigned char atkbd_unxlate_table[128] = { | |||
150 | #define ATKBD_RET_EMUL0 0xe0 | 150 | #define ATKBD_RET_EMUL0 0xe0 |
151 | #define ATKBD_RET_EMUL1 0xe1 | 151 | #define ATKBD_RET_EMUL1 0xe1 |
152 | #define ATKBD_RET_RELEASE 0xf0 | 152 | #define ATKBD_RET_RELEASE 0xf0 |
153 | #define ATKBD_RET_HANGUEL 0xf1 | 153 | #define ATKBD_RET_HANJA 0xf1 |
154 | #define ATKBD_RET_HANJA 0xf2 | 154 | #define ATKBD_RET_HANGEUL 0xf2 |
155 | #define ATKBD_RET_ERR 0xff | 155 | #define ATKBD_RET_ERR 0xff |
156 | 156 | ||
157 | #define ATKBD_KEY_UNKNOWN 0 | 157 | #define ATKBD_KEY_UNKNOWN 0 |
@@ -170,6 +170,13 @@ static unsigned char atkbd_unxlate_table[128] = { | |||
170 | #define ATKBD_LED_EVENT_BIT 0 | 170 | #define ATKBD_LED_EVENT_BIT 0 |
171 | #define ATKBD_REP_EVENT_BIT 1 | 171 | #define ATKBD_REP_EVENT_BIT 1 |
172 | 172 | ||
173 | #define ATKBD_XL_ERR 0x01 | ||
174 | #define ATKBD_XL_BAT 0x02 | ||
175 | #define ATKBD_XL_ACK 0x04 | ||
176 | #define ATKBD_XL_NAK 0x08 | ||
177 | #define ATKBD_XL_HANGEUL 0x10 | ||
178 | #define ATKBD_XL_HANJA 0x20 | ||
179 | |||
173 | static struct { | 180 | static struct { |
174 | unsigned char keycode; | 181 | unsigned char keycode; |
175 | unsigned char set2; | 182 | unsigned char set2; |
@@ -211,8 +218,7 @@ struct atkbd { | |||
211 | unsigned char emul; | 218 | unsigned char emul; |
212 | unsigned char resend; | 219 | unsigned char resend; |
213 | unsigned char release; | 220 | unsigned char release; |
214 | unsigned char bat_xl; | 221 | unsigned long xl_bit; |
215 | unsigned char err_xl; | ||
216 | unsigned int last; | 222 | unsigned int last; |
217 | unsigned long time; | 223 | unsigned long time; |
218 | 224 | ||
@@ -245,17 +251,65 @@ ATKBD_DEFINE_ATTR(set); | |||
245 | ATKBD_DEFINE_ATTR(softrepeat); | 251 | ATKBD_DEFINE_ATTR(softrepeat); |
246 | ATKBD_DEFINE_ATTR(softraw); | 252 | ATKBD_DEFINE_ATTR(softraw); |
247 | 253 | ||
254 | static const unsigned int xl_table[] = { | ||
255 | ATKBD_RET_BAT, ATKBD_RET_ERR, ATKBD_RET_ACK, | ||
256 | ATKBD_RET_NAK, ATKBD_RET_HANJA, ATKBD_RET_HANGEUL, | ||
257 | }; | ||
248 | 258 | ||
249 | static void atkbd_report_key(struct input_dev *dev, struct pt_regs *regs, int code, int value) | 259 | /* |
260 | * Checks if we should mangle the scancode to extract 'release' bit | ||
261 | * in translated mode. | ||
262 | */ | ||
263 | static int atkbd_need_xlate(unsigned long xl_bit, unsigned char code) | ||
250 | { | 264 | { |
251 | input_regs(dev, regs); | 265 | int i; |
252 | if (value == 3) { | 266 | |
253 | input_report_key(dev, code, 1); | 267 | if (code == ATKBD_RET_EMUL0 || code == ATKBD_RET_EMUL1) |
254 | input_sync(dev); | 268 | return 0; |
255 | input_report_key(dev, code, 0); | 269 | |
256 | } else | 270 | for (i = 0; i < ARRAY_SIZE(xl_table); i++) |
257 | input_event(dev, EV_KEY, code, value); | 271 | if (code == xl_table[i]) |
258 | input_sync(dev); | 272 | return test_bit(i, &xl_bit); |
273 | |||
274 | return 1; | ||
275 | } | ||
276 | |||
277 | /* | ||
278 | * Calculates new value of xl_bit so the driver can distinguish | ||
279 | * between make/break pair of scancodes for select keys and PS/2 | ||
280 | * protocol responses. | ||
281 | */ | ||
282 | static void atkbd_calculate_xl_bit(struct atkbd *atkbd, unsigned char code) | ||
283 | { | ||
284 | int i; | ||
285 | |||
286 | for (i = 0; i < ARRAY_SIZE(xl_table); i++) { | ||
287 | if (!((code ^ xl_table[i]) & 0x7f)) { | ||
288 | if (code & 0x80) | ||
289 | __clear_bit(i, &atkbd->xl_bit); | ||
290 | else | ||
291 | __set_bit(i, &atkbd->xl_bit); | ||
292 | break; | ||
293 | } | ||
294 | } | ||
295 | } | ||
296 | |||
297 | /* | ||
298 | * Encode the scancode, 0xe0 prefix, and high bit into a single integer, | ||
299 | * keeping kernel 2.4 compatibility for set 2 | ||
300 | */ | ||
301 | static unsigned int atkbd_compat_scancode(struct atkbd *atkbd, unsigned int code) | ||
302 | { | ||
303 | if (atkbd->set == 3) { | ||
304 | if (atkbd->emul == 1) | ||
305 | code |= 0x100; | ||
306 | } else { | ||
307 | code = (code & 0x7f) | ((code & 0x80) << 1); | ||
308 | if (atkbd->emul == 1) | ||
309 | code |= 0x80; | ||
310 | } | ||
311 | |||
312 | return code; | ||
259 | } | 313 | } |
260 | 314 | ||
261 | /* | 315 | /* |
@@ -267,9 +321,11 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, | |||
267 | unsigned int flags, struct pt_regs *regs) | 321 | unsigned int flags, struct pt_regs *regs) |
268 | { | 322 | { |
269 | struct atkbd *atkbd = serio_get_drvdata(serio); | 323 | struct atkbd *atkbd = serio_get_drvdata(serio); |
324 | struct input_dev *dev = atkbd->dev; | ||
270 | unsigned int code = data; | 325 | unsigned int code = data; |
271 | int scroll = 0, hscroll = 0, click = -1; | 326 | int scroll = 0, hscroll = 0, click = -1, add_release_event = 0; |
272 | int value; | 327 | int value; |
328 | unsigned char keycode; | ||
273 | 329 | ||
274 | #ifdef ATKBD_DEBUG | 330 | #ifdef ATKBD_DEBUG |
275 | printk(KERN_DEBUG "atkbd.c: Received %02x flags %02x\n", data, flags); | 331 | printk(KERN_DEBUG "atkbd.c: Received %02x flags %02x\n", data, flags); |
@@ -298,25 +354,17 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, | |||
298 | if (!atkbd->enabled) | 354 | if (!atkbd->enabled) |
299 | goto out; | 355 | goto out; |
300 | 356 | ||
301 | input_event(atkbd->dev, EV_MSC, MSC_RAW, code); | 357 | input_event(dev, EV_MSC, MSC_RAW, code); |
302 | 358 | ||
303 | if (atkbd->translated) { | 359 | if (atkbd->translated) { |
304 | 360 | ||
305 | if (atkbd->emul || | 361 | if (atkbd->emul || atkbd_need_xlate(atkbd->xl_bit, code)) { |
306 | (code != ATKBD_RET_EMUL0 && code != ATKBD_RET_EMUL1 && | ||
307 | code != ATKBD_RET_HANGUEL && code != ATKBD_RET_HANJA && | ||
308 | (code != ATKBD_RET_ERR || atkbd->err_xl) && | ||
309 | (code != ATKBD_RET_BAT || atkbd->bat_xl))) { | ||
310 | atkbd->release = code >> 7; | 362 | atkbd->release = code >> 7; |
311 | code &= 0x7f; | 363 | code &= 0x7f; |
312 | } | 364 | } |
313 | 365 | ||
314 | if (!atkbd->emul) { | 366 | if (!atkbd->emul) |
315 | if ((code & 0x7f) == (ATKBD_RET_BAT & 0x7f)) | 367 | atkbd_calculate_xl_bit(atkbd, data); |
316 | atkbd->bat_xl = !(data >> 7); | ||
317 | if ((code & 0x7f) == (ATKBD_RET_ERR & 0x7f)) | ||
318 | atkbd->err_xl = !(data >> 7); | ||
319 | } | ||
320 | } | 368 | } |
321 | 369 | ||
322 | switch (code) { | 370 | switch (code) { |
@@ -333,47 +381,48 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, | |||
333 | case ATKBD_RET_RELEASE: | 381 | case ATKBD_RET_RELEASE: |
334 | atkbd->release = 1; | 382 | atkbd->release = 1; |
335 | goto out; | 383 | goto out; |
336 | case ATKBD_RET_HANGUEL: | 384 | case ATKBD_RET_ACK: |
337 | atkbd_report_key(atkbd->dev, regs, KEY_HANGUEL, 3); | 385 | case ATKBD_RET_NAK: |
386 | printk(KERN_WARNING "atkbd.c: Spurious %s on %s. " | ||
387 | "Some program might be trying access hardware directly.\n", | ||
388 | data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys); | ||
338 | goto out; | 389 | goto out; |
390 | case ATKBD_RET_HANGEUL: | ||
339 | case ATKBD_RET_HANJA: | 391 | case ATKBD_RET_HANJA: |
340 | atkbd_report_key(atkbd->dev, regs, KEY_HANJA, 3); | 392 | /* |
341 | goto out; | 393 | * These keys do not report release and thus need to be |
394 | * flagged properly | ||
395 | */ | ||
396 | add_release_event = 1; | ||
397 | break; | ||
342 | case ATKBD_RET_ERR: | 398 | case ATKBD_RET_ERR: |
343 | printk(KERN_DEBUG "atkbd.c: Keyboard on %s reports too many keys pressed.\n", serio->phys); | 399 | printk(KERN_DEBUG "atkbd.c: Keyboard on %s reports too many keys pressed.\n", serio->phys); |
344 | goto out; | 400 | goto out; |
345 | } | 401 | } |
346 | 402 | ||
347 | if (atkbd->set != 3) | 403 | code = atkbd_compat_scancode(atkbd, code); |
348 | code = (code & 0x7f) | ((code & 0x80) << 1); | 404 | |
349 | if (atkbd->emul) { | 405 | if (atkbd->emul && --atkbd->emul) |
350 | if (--atkbd->emul) | 406 | goto out; |
351 | goto out; | ||
352 | code |= (atkbd->set != 3) ? 0x80 : 0x100; | ||
353 | } | ||
354 | 407 | ||
355 | if (atkbd->keycode[code] != ATKBD_KEY_NULL) | 408 | keycode = atkbd->keycode[code]; |
356 | input_event(atkbd->dev, EV_MSC, MSC_SCAN, code); | ||
357 | 409 | ||
358 | switch (atkbd->keycode[code]) { | 410 | if (keycode != ATKBD_KEY_NULL) |
411 | input_event(dev, EV_MSC, MSC_SCAN, code); | ||
412 | |||
413 | switch (keycode) { | ||
359 | case ATKBD_KEY_NULL: | 414 | case ATKBD_KEY_NULL: |
360 | break; | 415 | break; |
361 | case ATKBD_KEY_UNKNOWN: | 416 | case ATKBD_KEY_UNKNOWN: |
362 | if (data == ATKBD_RET_ACK || data == ATKBD_RET_NAK) { | 417 | printk(KERN_WARNING |
363 | printk(KERN_WARNING "atkbd.c: Spurious %s on %s. Some program, " | 418 | "atkbd.c: Unknown key %s (%s set %d, code %#x on %s).\n", |
364 | "like XFree86, might be trying access hardware directly.\n", | 419 | atkbd->release ? "released" : "pressed", |
365 | data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys); | 420 | atkbd->translated ? "translated" : "raw", |
366 | } else { | 421 | atkbd->set, code, serio->phys); |
367 | printk(KERN_WARNING "atkbd.c: Unknown key %s " | 422 | printk(KERN_WARNING |
368 | "(%s set %d, code %#x on %s).\n", | 423 | "atkbd.c: Use 'setkeycodes %s%02x <keycode>' to make it known.\n", |
369 | atkbd->release ? "released" : "pressed", | 424 | code & 0x80 ? "e0" : "", code & 0x7f); |
370 | atkbd->translated ? "translated" : "raw", | 425 | input_sync(dev); |
371 | atkbd->set, code, serio->phys); | ||
372 | printk(KERN_WARNING "atkbd.c: Use 'setkeycodes %s%02x <keycode>' " | ||
373 | "to make it known.\n", | ||
374 | code & 0x80 ? "e0" : "", code & 0x7f); | ||
375 | } | ||
376 | input_sync(atkbd->dev); | ||
377 | break; | 426 | break; |
378 | case ATKBD_SCR_1: | 427 | case ATKBD_SCR_1: |
379 | scroll = 1 - atkbd->release * 2; | 428 | scroll = 1 - atkbd->release * 2; |
@@ -397,33 +446,35 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, | |||
397 | hscroll = 1; | 446 | hscroll = 1; |
398 | break; | 447 | break; |
399 | default: | 448 | default: |
400 | value = atkbd->release ? 0 : | 449 | if (atkbd->release) { |
401 | (1 + (!atkbd->softrepeat && test_bit(atkbd->keycode[code], atkbd->dev->key))); | 450 | value = 0; |
402 | 451 | atkbd->last = 0; | |
403 | switch (value) { /* Workaround Toshiba laptop multiple keypress */ | 452 | } else if (!atkbd->softrepeat && test_bit(keycode, dev->key)) { |
404 | case 0: | 453 | /* Workaround Toshiba laptop multiple keypress */ |
405 | atkbd->last = 0; | 454 | value = time_before(jiffies, atkbd->time) && atkbd->last == code ? 1 : 2; |
406 | break; | 455 | } else { |
407 | case 1: | 456 | value = 1; |
408 | atkbd->last = code; | 457 | atkbd->last = code; |
409 | atkbd->time = jiffies + msecs_to_jiffies(atkbd->dev->rep[REP_DELAY]) / 2; | 458 | atkbd->time = jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]) / 2; |
410 | break; | ||
411 | case 2: | ||
412 | if (!time_after(jiffies, atkbd->time) && atkbd->last == code) | ||
413 | value = 1; | ||
414 | break; | ||
415 | } | 459 | } |
416 | 460 | ||
417 | atkbd_report_key(atkbd->dev, regs, atkbd->keycode[code], value); | 461 | input_regs(dev, regs); |
462 | input_report_key(dev, keycode, value); | ||
463 | input_sync(dev); | ||
464 | |||
465 | if (value && add_release_event) { | ||
466 | input_report_key(dev, keycode, 0); | ||
467 | input_sync(dev); | ||
468 | } | ||
418 | } | 469 | } |
419 | 470 | ||
420 | if (atkbd->scroll) { | 471 | if (atkbd->scroll) { |
421 | input_regs(atkbd->dev, regs); | 472 | input_regs(dev, regs); |
422 | if (click != -1) | 473 | if (click != -1) |
423 | input_report_key(atkbd->dev, BTN_MIDDLE, click); | 474 | input_report_key(dev, BTN_MIDDLE, click); |
424 | input_report_rel(atkbd->dev, REL_WHEEL, scroll); | 475 | input_report_rel(dev, REL_WHEEL, scroll); |
425 | input_report_rel(atkbd->dev, REL_HWHEEL, hscroll); | 476 | input_report_rel(dev, REL_HWHEEL, hscroll); |
426 | input_sync(atkbd->dev); | 477 | input_sync(dev); |
427 | } | 478 | } |
428 | 479 | ||
429 | atkbd->release = 0; | 480 | atkbd->release = 0; |
@@ -764,6 +815,9 @@ static void atkbd_set_keycode_table(struct atkbd *atkbd) | |||
764 | for (i = 0; i < ARRAY_SIZE(atkbd_scroll_keys); i++) | 815 | for (i = 0; i < ARRAY_SIZE(atkbd_scroll_keys); i++) |
765 | atkbd->keycode[atkbd_scroll_keys[i].set2] = atkbd_scroll_keys[i].keycode; | 816 | atkbd->keycode[atkbd_scroll_keys[i].set2] = atkbd_scroll_keys[i].keycode; |
766 | } | 817 | } |
818 | |||
819 | atkbd->keycode[atkbd_compat_scancode(atkbd, ATKBD_RET_HANGEUL)] = KEY_HANGUEL; | ||
820 | atkbd->keycode[atkbd_compat_scancode(atkbd, ATKBD_RET_HANJA)] = KEY_HANJA; | ||
767 | } | 821 | } |
768 | 822 | ||
769 | /* | 823 | /* |
@@ -776,12 +830,15 @@ static void atkbd_set_device_attrs(struct atkbd *atkbd) | |||
776 | int i; | 830 | int i; |
777 | 831 | ||
778 | if (atkbd->extra) | 832 | if (atkbd->extra) |
779 | sprintf(atkbd->name, "AT Set 2 Extra keyboard"); | 833 | snprintf(atkbd->name, sizeof(atkbd->name), |
834 | "AT Set 2 Extra keyboard"); | ||
780 | else | 835 | else |
781 | sprintf(atkbd->name, "AT %s Set %d keyboard", | 836 | snprintf(atkbd->name, sizeof(atkbd->name), |
782 | atkbd->translated ? "Translated" : "Raw", atkbd->set); | 837 | "AT %s Set %d keyboard", |
838 | atkbd->translated ? "Translated" : "Raw", atkbd->set); | ||
783 | 839 | ||
784 | sprintf(atkbd->phys, "%s/input0", atkbd->ps2dev.serio->phys); | 840 | snprintf(atkbd->phys, sizeof(atkbd->phys), |
841 | "%s/input0", atkbd->ps2dev.serio->phys); | ||
785 | 842 | ||
786 | input_dev->name = atkbd->name; | 843 | input_dev->name = atkbd->name; |
787 | input_dev->phys = atkbd->phys; | 844 | input_dev->phys = atkbd->phys; |
diff --git a/drivers/input/keyboard/lkkbd.c b/drivers/input/keyboard/lkkbd.c index 77c4d9669ad0..5174224cadb4 100644 --- a/drivers/input/keyboard/lkkbd.c +++ b/drivers/input/keyboard/lkkbd.c | |||
@@ -384,18 +384,21 @@ lkkbd_detection_done (struct lkkbd *lk) | |||
384 | */ | 384 | */ |
385 | switch (lk->id[4]) { | 385 | switch (lk->id[4]) { |
386 | case 1: | 386 | case 1: |
387 | sprintf (lk->name, "DEC LK201 keyboard"); | 387 | strlcpy (lk->name, "DEC LK201 keyboard", |
388 | sizeof (lk->name)); | ||
388 | 389 | ||
389 | if (lk201_compose_is_alt) | 390 | if (lk201_compose_is_alt) |
390 | lk->keycode[0xb1] = KEY_LEFTALT; | 391 | lk->keycode[0xb1] = KEY_LEFTALT; |
391 | break; | 392 | break; |
392 | 393 | ||
393 | case 2: | 394 | case 2: |
394 | sprintf (lk->name, "DEC LK401 keyboard"); | 395 | strlcpy (lk->name, "DEC LK401 keyboard", |
396 | sizeof (lk->name)); | ||
395 | break; | 397 | break; |
396 | 398 | ||
397 | default: | 399 | default: |
398 | sprintf (lk->name, "Unknown DEC keyboard"); | 400 | strlcpy (lk->name, "Unknown DEC keyboard", |
401 | sizeof (lk->name)); | ||
399 | printk (KERN_ERR "lkkbd: keyboard on %s is unknown, " | 402 | printk (KERN_ERR "lkkbd: keyboard on %s is unknown, " |
400 | "please report to Jan-Benedict Glaw " | 403 | "please report to Jan-Benedict Glaw " |
401 | "<jbglaw@lug-owl.de>\n", lk->phys); | 404 | "<jbglaw@lug-owl.de>\n", lk->phys); |
diff --git a/drivers/input/keyboard/newtonkbd.c b/drivers/input/keyboard/newtonkbd.c index d10983c521e6..40a3f551247e 100644 --- a/drivers/input/keyboard/newtonkbd.c +++ b/drivers/input/keyboard/newtonkbd.c | |||
@@ -96,7 +96,7 @@ static int nkbd_connect(struct serio *serio, struct serio_driver *drv) | |||
96 | 96 | ||
97 | nkbd->serio = serio; | 97 | nkbd->serio = serio; |
98 | nkbd->dev = input_dev; | 98 | nkbd->dev = input_dev; |
99 | sprintf(nkbd->phys, "%s/input0", serio->phys); | 99 | snprintf(nkbd->phys, sizeof(nkbd->phys), "%s/input0", serio->phys); |
100 | memcpy(nkbd->keycode, nkbd_keycode, sizeof(nkbd->keycode)); | 100 | memcpy(nkbd->keycode, nkbd_keycode, sizeof(nkbd->keycode)); |
101 | 101 | ||
102 | input_dev->name = "Newton Keyboard"; | 102 | input_dev->name = "Newton Keyboard"; |
diff --git a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c index b15b6d8d4f83..9dbd7b85686d 100644 --- a/drivers/input/keyboard/sunkbd.c +++ b/drivers/input/keyboard/sunkbd.c | |||
@@ -263,7 +263,7 @@ static int sunkbd_connect(struct serio *serio, struct serio_driver *drv) | |||
263 | goto fail; | 263 | goto fail; |
264 | } | 264 | } |
265 | 265 | ||
266 | sprintf(sunkbd->name, "Sun Type %d keyboard", sunkbd->type); | 266 | snprintf(sunkbd->name, sizeof(sunkbd->name), "Sun Type %d keyboard", sunkbd->type); |
267 | memcpy(sunkbd->keycode, sunkbd_keycode, sizeof(sunkbd->keycode)); | 267 | memcpy(sunkbd->keycode, sunkbd_keycode, sizeof(sunkbd->keycode)); |
268 | 268 | ||
269 | input_dev->name = sunkbd->name; | 269 | input_dev->name = sunkbd->name; |
diff --git a/drivers/input/keyboard/xtkbd.c b/drivers/input/keyboard/xtkbd.c index 4135e3e16c51..0821d53cf0c1 100644 --- a/drivers/input/keyboard/xtkbd.c +++ b/drivers/input/keyboard/xtkbd.c | |||
@@ -100,7 +100,7 @@ static int xtkbd_connect(struct serio *serio, struct serio_driver *drv) | |||
100 | 100 | ||
101 | xtkbd->serio = serio; | 101 | xtkbd->serio = serio; |
102 | xtkbd->dev = input_dev; | 102 | xtkbd->dev = input_dev; |
103 | sprintf(xtkbd->phys, "%s/input0", serio->phys); | 103 | snprintf(xtkbd->phys, sizeof(xtkbd->phys), "%s/input0", serio->phys); |
104 | memcpy(xtkbd->keycode, xtkbd_keycode, sizeof(xtkbd->keycode)); | 104 | memcpy(xtkbd->keycode, xtkbd_keycode, sizeof(xtkbd->keycode)); |
105 | 105 | ||
106 | input_dev->name = "XT Keyboard"; | 106 | input_dev->name = "XT Keyboard"; |
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index a0e2e797c6d5..070d75330afd 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c | |||
@@ -470,7 +470,7 @@ int alps_init(struct psmouse *psmouse) | |||
470 | dev1->keybit[LONG(BTN_BACK)] |= BIT(BTN_BACK); | 470 | dev1->keybit[LONG(BTN_BACK)] |= BIT(BTN_BACK); |
471 | } | 471 | } |
472 | 472 | ||
473 | sprintf(priv->phys, "%s/input1", psmouse->ps2dev.serio->phys); | 473 | snprintf(priv->phys, sizeof(priv->phys), "%s/input1", psmouse->ps2dev.serio->phys); |
474 | dev2->phys = priv->phys; | 474 | dev2->phys = priv->phys; |
475 | dev2->name = (priv->i->flags & ALPS_DUALPOINT) ? "DualPoint Stick" : "PS/2 Mouse"; | 475 | dev2->name = (priv->i->flags & ALPS_DUALPOINT) ? "DualPoint Stick" : "PS/2 Mouse"; |
476 | dev2->id.bustype = BUS_I8042; | 476 | dev2->id.bustype = BUS_I8042; |
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index 136321a2cfdb..8bc9f51ae6c2 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c | |||
@@ -150,9 +150,20 @@ static psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse, struct pt_reg | |||
150 | */ | 150 | */ |
151 | 151 | ||
152 | if (psmouse->type == PSMOUSE_IMEX) { | 152 | if (psmouse->type == PSMOUSE_IMEX) { |
153 | input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 8) - (int) (packet[3] & 7)); | 153 | switch (packet[3] & 0xC0) { |
154 | input_report_key(dev, BTN_SIDE, (packet[3] >> 4) & 1); | 154 | case 0x80: /* vertical scroll on IntelliMouse Explorer 4.0 */ |
155 | input_report_key(dev, BTN_EXTRA, (packet[3] >> 5) & 1); | 155 | input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 32) - (int) (packet[3] & 31)); |
156 | break; | ||
157 | case 0x40: /* horizontal scroll on IntelliMouse Explorer 4.0 */ | ||
158 | input_report_rel(dev, REL_HWHEEL, (int) (packet[3] & 32) - (int) (packet[3] & 31)); | ||
159 | break; | ||
160 | case 0x00: | ||
161 | case 0xC0: | ||
162 | input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 8) - (int) (packet[3] & 7)); | ||
163 | input_report_key(dev, BTN_SIDE, (packet[3] >> 4) & 1); | ||
164 | input_report_key(dev, BTN_EXTRA, (packet[3] >> 5) & 1); | ||
165 | break; | ||
166 | } | ||
156 | } | 167 | } |
157 | 168 | ||
158 | /* | 169 | /* |
@@ -466,9 +477,25 @@ static int im_explorer_detect(struct psmouse *psmouse, int set_properties) | |||
466 | if (param[0] != 4) | 477 | if (param[0] != 4) |
467 | return -1; | 478 | return -1; |
468 | 479 | ||
480 | /* Magic to enable horizontal scrolling on IntelliMouse 4.0 */ | ||
481 | param[0] = 200; | ||
482 | ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); | ||
483 | param[0] = 80; | ||
484 | ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); | ||
485 | param[0] = 40; | ||
486 | ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); | ||
487 | |||
488 | param[0] = 200; | ||
489 | ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); | ||
490 | param[0] = 200; | ||
491 | ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); | ||
492 | param[0] = 60; | ||
493 | ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); | ||
494 | |||
469 | if (set_properties) { | 495 | if (set_properties) { |
470 | set_bit(BTN_MIDDLE, psmouse->dev->keybit); | 496 | set_bit(BTN_MIDDLE, psmouse->dev->keybit); |
471 | set_bit(REL_WHEEL, psmouse->dev->relbit); | 497 | set_bit(REL_WHEEL, psmouse->dev->relbit); |
498 | set_bit(REL_HWHEEL, psmouse->dev->relbit); | ||
472 | set_bit(BTN_SIDE, psmouse->dev->keybit); | 499 | set_bit(BTN_SIDE, psmouse->dev->keybit); |
473 | set_bit(BTN_EXTRA, psmouse->dev->keybit); | 500 | set_bit(BTN_EXTRA, psmouse->dev->keybit); |
474 | 501 | ||
@@ -1057,8 +1084,8 @@ static int psmouse_switch_protocol(struct psmouse *psmouse, struct psmouse_proto | |||
1057 | if (psmouse->resync_time && psmouse->poll(psmouse)) | 1084 | if (psmouse->resync_time && psmouse->poll(psmouse)) |
1058 | psmouse->resync_time = 0; | 1085 | psmouse->resync_time = 0; |
1059 | 1086 | ||
1060 | sprintf(psmouse->devname, "%s %s %s", | 1087 | snprintf(psmouse->devname, sizeof(psmouse->devname), "%s %s %s", |
1061 | psmouse_protocol_by_type(psmouse->type)->name, psmouse->vendor, psmouse->name); | 1088 | psmouse_protocol_by_type(psmouse->type)->name, psmouse->vendor, psmouse->name); |
1062 | 1089 | ||
1063 | input_dev->name = psmouse->devname; | 1090 | input_dev->name = psmouse->devname; |
1064 | input_dev->phys = psmouse->phys; | 1091 | input_dev->phys = psmouse->phys; |
@@ -1099,7 +1126,7 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) | |||
1099 | ps2_init(&psmouse->ps2dev, serio); | 1126 | ps2_init(&psmouse->ps2dev, serio); |
1100 | INIT_WORK(&psmouse->resync_work, psmouse_resync, psmouse); | 1127 | INIT_WORK(&psmouse->resync_work, psmouse_resync, psmouse); |
1101 | psmouse->dev = input_dev; | 1128 | psmouse->dev = input_dev; |
1102 | sprintf(psmouse->phys, "%s/input0", serio->phys); | 1129 | snprintf(psmouse->phys, sizeof(psmouse->phys), "%s/input0", serio->phys); |
1103 | 1130 | ||
1104 | psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); | 1131 | psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); |
1105 | 1132 | ||
diff --git a/drivers/input/mouse/sermouse.c b/drivers/input/mouse/sermouse.c index 2f9a04ae725f..a89742431717 100644 --- a/drivers/input/mouse/sermouse.c +++ b/drivers/input/mouse/sermouse.c | |||
@@ -254,7 +254,7 @@ static int sermouse_connect(struct serio *serio, struct serio_driver *drv) | |||
254 | goto fail; | 254 | goto fail; |
255 | 255 | ||
256 | sermouse->dev = input_dev; | 256 | sermouse->dev = input_dev; |
257 | sprintf(sermouse->phys, "%s/input0", serio->phys); | 257 | snprintf(sermouse->phys, sizeof(sermouse->phys), "%s/input0", serio->phys); |
258 | sermouse->type = serio->id.proto; | 258 | sermouse->type = serio->id.proto; |
259 | 259 | ||
260 | input_dev->name = sermouse_protocols[sermouse->type]; | 260 | input_dev->name = sermouse_protocols[sermouse->type]; |
diff --git a/drivers/input/mouse/vsxxxaa.c b/drivers/input/mouse/vsxxxaa.c index 36e9442a16b2..7b85bc21ae4a 100644 --- a/drivers/input/mouse/vsxxxaa.c +++ b/drivers/input/mouse/vsxxxaa.c | |||
@@ -153,22 +153,25 @@ vsxxxaa_detection_done (struct vsxxxaa *mouse) | |||
153 | { | 153 | { |
154 | switch (mouse->type) { | 154 | switch (mouse->type) { |
155 | case 0x02: | 155 | case 0x02: |
156 | sprintf (mouse->name, "DEC VSXXX-AA/-GA mouse"); | 156 | strlcpy (mouse->name, "DEC VSXXX-AA/-GA mouse", |
157 | sizeof (mouse->name)); | ||
157 | break; | 158 | break; |
158 | 159 | ||
159 | case 0x04: | 160 | case 0x04: |
160 | sprintf (mouse->name, "DEC VSXXX-AB digitizer"); | 161 | strlcpy (mouse->name, "DEC VSXXX-AB digitizer", |
162 | sizeof (mouse->name)); | ||
161 | break; | 163 | break; |
162 | 164 | ||
163 | default: | 165 | default: |
164 | sprintf (mouse->name, "unknown DEC pointer device " | 166 | snprintf (mouse->name, sizeof (mouse->name), |
165 | "(type = 0x%02x)", mouse->type); | 167 | "unknown DEC pointer device (type = 0x%02x)", |
168 | mouse->type); | ||
166 | break; | 169 | break; |
167 | } | 170 | } |
168 | 171 | ||
169 | printk (KERN_INFO "Found %s version 0x%02x from country 0x%02x " | 172 | printk (KERN_INFO |
170 | "on port %s\n", mouse->name, mouse->version, | 173 | "Found %s version 0x%02x from country 0x%02x on port %s\n", |
171 | mouse->country, mouse->phys); | 174 | mouse->name, mouse->version, mouse->country, mouse->phys); |
172 | } | 175 | } |
173 | 176 | ||
174 | /* | 177 | /* |
@@ -503,8 +506,9 @@ vsxxxaa_connect (struct serio *serio, struct serio_driver *drv) | |||
503 | 506 | ||
504 | mouse->dev = input_dev; | 507 | mouse->dev = input_dev; |
505 | mouse->serio = serio; | 508 | mouse->serio = serio; |
506 | sprintf (mouse->name, "DEC VSXXX-AA/-GA mouse or VSXXX-AB digitizer"); | 509 | strlcat (mouse->name, "DEC VSXXX-AA/-GA mouse or VSXXX-AB digitizer", |
507 | sprintf (mouse->phys, "%s/input0", serio->phys); | 510 | sizeof (mouse->name)); |
511 | snprintf (mouse->phys, sizeof (mouse->phys), "%s/input0", serio->phys); | ||
508 | 512 | ||
509 | input_dev->name = mouse->name; | 513 | input_dev->name = mouse->name; |
510 | input_dev->phys = mouse->phys; | 514 | input_dev->phys = mouse->phys; |
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index b685a507955d..eb721b11ff37 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c | |||
@@ -123,7 +123,9 @@ static void mousedev_touchpad_event(struct input_dev *dev, struct mousedev *mous | |||
123 | 123 | ||
124 | if (mousedev->touch) { | 124 | if (mousedev->touch) { |
125 | size = dev->absmax[ABS_X] - dev->absmin[ABS_X]; | 125 | size = dev->absmax[ABS_X] - dev->absmin[ABS_X]; |
126 | if (size == 0) size = 256 * 2; | 126 | if (size == 0) |
127 | size = 256 * 2; | ||
128 | |||
127 | switch (code) { | 129 | switch (code) { |
128 | case ABS_X: | 130 | case ABS_X: |
129 | fx(0) = value; | 131 | fx(0) = value; |
@@ -155,18 +157,24 @@ static void mousedev_abs_event(struct input_dev *dev, struct mousedev *mousedev, | |||
155 | switch (code) { | 157 | switch (code) { |
156 | case ABS_X: | 158 | case ABS_X: |
157 | size = dev->absmax[ABS_X] - dev->absmin[ABS_X]; | 159 | size = dev->absmax[ABS_X] - dev->absmin[ABS_X]; |
158 | if (size == 0) size = xres ? : 1; | 160 | if (size == 0) |
159 | if (value > dev->absmax[ABS_X]) value = dev->absmax[ABS_X]; | 161 | size = xres ? : 1; |
160 | if (value < dev->absmin[ABS_X]) value = dev->absmin[ABS_X]; | 162 | if (value > dev->absmax[ABS_X]) |
163 | value = dev->absmax[ABS_X]; | ||
164 | if (value < dev->absmin[ABS_X]) | ||
165 | value = dev->absmin[ABS_X]; | ||
161 | mousedev->packet.x = ((value - dev->absmin[ABS_X]) * xres) / size; | 166 | mousedev->packet.x = ((value - dev->absmin[ABS_X]) * xres) / size; |
162 | mousedev->packet.abs_event = 1; | 167 | mousedev->packet.abs_event = 1; |
163 | break; | 168 | break; |
164 | 169 | ||
165 | case ABS_Y: | 170 | case ABS_Y: |
166 | size = dev->absmax[ABS_Y] - dev->absmin[ABS_Y]; | 171 | size = dev->absmax[ABS_Y] - dev->absmin[ABS_Y]; |
167 | if (size == 0) size = yres ? : 1; | 172 | if (size == 0) |
168 | if (value > dev->absmax[ABS_Y]) value = dev->absmax[ABS_Y]; | 173 | size = yres ? : 1; |
169 | if (value < dev->absmin[ABS_Y]) value = dev->absmin[ABS_Y]; | 174 | if (value > dev->absmax[ABS_Y]) |
175 | value = dev->absmax[ABS_Y]; | ||
176 | if (value < dev->absmin[ABS_Y]) | ||
177 | value = dev->absmin[ABS_Y]; | ||
170 | mousedev->packet.y = yres - ((value - dev->absmin[ABS_Y]) * yres) / size; | 178 | mousedev->packet.y = yres - ((value - dev->absmin[ABS_Y]) * yres) / size; |
171 | mousedev->packet.abs_event = 1; | 179 | mousedev->packet.abs_event = 1; |
172 | break; | 180 | break; |
@@ -202,7 +210,7 @@ static void mousedev_key_event(struct mousedev *mousedev, unsigned int code, int | |||
202 | case BTN_SIDE: index = 3; break; | 210 | case BTN_SIDE: index = 3; break; |
203 | case BTN_4: | 211 | case BTN_4: |
204 | case BTN_EXTRA: index = 4; break; | 212 | case BTN_EXTRA: index = 4; break; |
205 | default: return; | 213 | default: return; |
206 | } | 214 | } |
207 | 215 | ||
208 | if (value) { | 216 | if (value) { |
@@ -285,10 +293,9 @@ static void mousedev_touchpad_touch(struct mousedev *mousedev, int value) | |||
285 | mousedev->touch = mousedev->pkt_count = 0; | 293 | mousedev->touch = mousedev->pkt_count = 0; |
286 | mousedev->frac_dx = 0; | 294 | mousedev->frac_dx = 0; |
287 | mousedev->frac_dy = 0; | 295 | mousedev->frac_dy = 0; |
288 | } | 296 | |
289 | else | 297 | } else if (!mousedev->touch) |
290 | if (!mousedev->touch) | 298 | mousedev->touch = jiffies; |
291 | mousedev->touch = jiffies; | ||
292 | } | 299 | } |
293 | 300 | ||
294 | static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) | 301 | static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) |
@@ -327,7 +334,7 @@ static void mousedev_event(struct input_handle *handle, unsigned int type, unsig | |||
327 | mousedev->pkt_count++; | 334 | mousedev->pkt_count++; |
328 | /* Input system eats duplicate events, but we need all of them | 335 | /* Input system eats duplicate events, but we need all of them |
329 | * to do correct averaging so apply present one forward | 336 | * to do correct averaging so apply present one forward |
330 | */ | 337 | */ |
331 | fx(0) = fx(1); | 338 | fx(0) = fx(1); |
332 | fy(0) = fy(1); | 339 | fy(0) = fy(1); |
333 | } | 340 | } |
@@ -346,7 +353,9 @@ static int mousedev_fasync(int fd, struct file *file, int on) | |||
346 | { | 353 | { |
347 | int retval; | 354 | int retval; |
348 | struct mousedev_list *list = file->private_data; | 355 | struct mousedev_list *list = file->private_data; |
356 | |||
349 | retval = fasync_helper(fd, file, on, &list->fasync); | 357 | retval = fasync_helper(fd, file, on, &list->fasync); |
358 | |||
350 | return retval < 0 ? retval : 0; | 359 | return retval < 0 ? retval : 0; |
351 | } | 360 | } |
352 | 361 | ||
@@ -507,14 +516,16 @@ static ssize_t mousedev_write(struct file * file, const char __user * buffer, si | |||
507 | list->imexseq = 0; | 516 | list->imexseq = 0; |
508 | list->mode = MOUSEDEV_EMUL_EXPS; | 517 | list->mode = MOUSEDEV_EMUL_EXPS; |
509 | } | 518 | } |
510 | } else list->imexseq = 0; | 519 | } else |
520 | list->imexseq = 0; | ||
511 | 521 | ||
512 | if (c == mousedev_imps_seq[list->impsseq]) { | 522 | if (c == mousedev_imps_seq[list->impsseq]) { |
513 | if (++list->impsseq == MOUSEDEV_SEQ_LEN) { | 523 | if (++list->impsseq == MOUSEDEV_SEQ_LEN) { |
514 | list->impsseq = 0; | 524 | list->impsseq = 0; |
515 | list->mode = MOUSEDEV_EMUL_IMPS; | 525 | list->mode = MOUSEDEV_EMUL_IMPS; |
516 | } | 526 | } |
517 | } else list->impsseq = 0; | 527 | } else |
528 | list->impsseq = 0; | ||
518 | 529 | ||
519 | list->ps2[0] = 0xfa; | 530 | list->ps2[0] = 0xfa; |
520 | 531 | ||
@@ -598,6 +609,7 @@ static ssize_t mousedev_read(struct file * file, char __user * buffer, size_t co | |||
598 | static unsigned int mousedev_poll(struct file *file, poll_table *wait) | 609 | static unsigned int mousedev_poll(struct file *file, poll_table *wait) |
599 | { | 610 | { |
600 | struct mousedev_list *list = file->private_data; | 611 | struct mousedev_list *list = file->private_data; |
612 | |||
601 | poll_wait(file, &list->mousedev->wait, wait); | 613 | poll_wait(file, &list->mousedev->wait, wait); |
602 | return ((list->ready || list->buffer) ? (POLLIN | POLLRDNORM) : 0) | | 614 | return ((list->ready || list->buffer) ? (POLLIN | POLLRDNORM) : 0) | |
603 | (list->mousedev->exist ? 0 : (POLLHUP | POLLERR)); | 615 | (list->mousedev->exist ? 0 : (POLLHUP | POLLERR)); |
diff --git a/drivers/input/touchscreen/gunze.c b/drivers/input/touchscreen/gunze.c index 466da190ceec..b769b21973b7 100644 --- a/drivers/input/touchscreen/gunze.c +++ b/drivers/input/touchscreen/gunze.c | |||
@@ -129,7 +129,7 @@ static int gunze_connect(struct serio *serio, struct serio_driver *drv) | |||
129 | 129 | ||
130 | gunze->serio = serio; | 130 | gunze->serio = serio; |
131 | gunze->dev = input_dev; | 131 | gunze->dev = input_dev; |
132 | sprintf(gunze->phys, "%s/input0", serio->phys); | 132 | snprintf(gunze->phys, sizeof(serio->phys), "%s/input0", serio->phys); |
133 | 133 | ||
134 | input_dev->private = gunze; | 134 | input_dev->private = gunze; |
135 | input_dev->name = "Gunze AHL-51S TouchScreen"; | 135 | input_dev->name = "Gunze AHL-51S TouchScreen"; |
diff --git a/drivers/input/touchscreen/h3600_ts_input.c b/drivers/input/touchscreen/h3600_ts_input.c index a595d386312f..2de2139f2fed 100644 --- a/drivers/input/touchscreen/h3600_ts_input.c +++ b/drivers/input/touchscreen/h3600_ts_input.c | |||
@@ -363,7 +363,7 @@ static int h3600ts_connect(struct serio *serio, struct serio_driver *drv) | |||
363 | 363 | ||
364 | ts->serio = serio; | 364 | ts->serio = serio; |
365 | ts->dev = input_dev; | 365 | ts->dev = input_dev; |
366 | sprintf(ts->phys, "%s/input0", serio->phys); | 366 | snprintf(ts->phys, sizeof(ts->phys), "%s/input0", serio->phys); |
367 | 367 | ||
368 | input_dev->name = "H3600 TouchScreen"; | 368 | input_dev->name = "H3600 TouchScreen"; |
369 | input_dev->phys = ts->phys; | 369 | input_dev->phys = ts->phys; |
diff --git a/drivers/input/touchscreen/mtouch.c b/drivers/input/touchscreen/mtouch.c index 1d0d37eeef6e..8647a905df80 100644 --- a/drivers/input/touchscreen/mtouch.c +++ b/drivers/input/touchscreen/mtouch.c | |||
@@ -143,7 +143,7 @@ static int mtouch_connect(struct serio *serio, struct serio_driver *drv) | |||
143 | 143 | ||
144 | mtouch->serio = serio; | 144 | mtouch->serio = serio; |
145 | mtouch->dev = input_dev; | 145 | mtouch->dev = input_dev; |
146 | sprintf(mtouch->phys, "%s/input0", serio->phys); | 146 | snprintf(mtouch->phys, sizeof(mtouch->phys), "%s/input0", serio->phys); |
147 | 147 | ||
148 | input_dev->private = mtouch; | 148 | input_dev->private = mtouch; |
149 | input_dev->name = "MicroTouch Serial TouchScreen"; | 149 | input_dev->name = "MicroTouch Serial TouchScreen"; |
diff --git a/drivers/input/tsdev.c b/drivers/input/tsdev.c index d678d144bbf8..5f9ecad2ca75 100644 --- a/drivers/input/tsdev.c +++ b/drivers/input/tsdev.c | |||
@@ -35,7 +35,7 @@ | |||
35 | * e-mail - mail your message to <jsimmons@infradead.org>. | 35 | * e-mail - mail your message to <jsimmons@infradead.org>. |
36 | */ | 36 | */ |
37 | 37 | ||
38 | #define TSDEV_MINOR_BASE 128 | 38 | #define TSDEV_MINOR_BASE 128 |
39 | #define TSDEV_MINORS 32 | 39 | #define TSDEV_MINORS 32 |
40 | /* First 16 devices are h3600_ts compatible; second 16 are h3600_tsraw */ | 40 | /* First 16 devices are h3600_ts compatible; second 16 are h3600_tsraw */ |
41 | #define TSDEV_MINOR_MASK 15 | 41 | #define TSDEV_MINOR_MASK 15 |
@@ -230,6 +230,7 @@ static ssize_t tsdev_read(struct file *file, char __user *buffer, size_t count, | |||
230 | static unsigned int tsdev_poll(struct file *file, poll_table * wait) | 230 | static unsigned int tsdev_poll(struct file *file, poll_table * wait) |
231 | { | 231 | { |
232 | struct tsdev_list *list = file->private_data; | 232 | struct tsdev_list *list = file->private_data; |
233 | |||
233 | poll_wait(file, &list->tsdev->wait, wait); | 234 | poll_wait(file, &list->tsdev->wait, wait); |
234 | return ((list->head == list->tail) ? 0 : (POLLIN | POLLRDNORM)) | | 235 | return ((list->head == list->tail) ? 0 : (POLLIN | POLLRDNORM)) | |
235 | (list->tsdev->exist ? 0 : (POLLHUP | POLLERR)); | 236 | (list->tsdev->exist ? 0 : (POLLHUP | POLLERR)); |
@@ -248,11 +249,13 @@ static int tsdev_ioctl(struct inode *inode, struct file *file, | |||
248 | sizeof (struct ts_calibration))) | 249 | sizeof (struct ts_calibration))) |
249 | retval = -EFAULT; | 250 | retval = -EFAULT; |
250 | break; | 251 | break; |
252 | |||
251 | case TS_SET_CAL: | 253 | case TS_SET_CAL: |
252 | if (copy_from_user (&tsdev->cal, (void __user *)arg, | 254 | if (copy_from_user (&tsdev->cal, (void __user *)arg, |
253 | sizeof (struct ts_calibration))) | 255 | sizeof (struct ts_calibration))) |
254 | retval = -EFAULT; | 256 | retval = -EFAULT; |
255 | break; | 257 | break; |
258 | |||
256 | default: | 259 | default: |
257 | retval = -EINVAL; | 260 | retval = -EINVAL; |
258 | break; | 261 | break; |
@@ -284,9 +287,11 @@ static void tsdev_event(struct input_handle *handle, unsigned int type, | |||
284 | case ABS_X: | 287 | case ABS_X: |
285 | tsdev->x = value; | 288 | tsdev->x = value; |
286 | break; | 289 | break; |
290 | |||
287 | case ABS_Y: | 291 | case ABS_Y: |
288 | tsdev->y = value; | 292 | tsdev->y = value; |
289 | break; | 293 | break; |
294 | |||
290 | case ABS_PRESSURE: | 295 | case ABS_PRESSURE: |
291 | if (value > handle->dev->absmax[ABS_PRESSURE]) | 296 | if (value > handle->dev->absmax[ABS_PRESSURE]) |
292 | value = handle->dev->absmax[ABS_PRESSURE]; | 297 | value = handle->dev->absmax[ABS_PRESSURE]; |
@@ -307,6 +312,7 @@ static void tsdev_event(struct input_handle *handle, unsigned int type, | |||
307 | else if (tsdev->x > xres) | 312 | else if (tsdev->x > xres) |
308 | tsdev->x = xres; | 313 | tsdev->x = xres; |
309 | break; | 314 | break; |
315 | |||
310 | case REL_Y: | 316 | case REL_Y: |
311 | tsdev->y += value; | 317 | tsdev->y += value; |
312 | if (tsdev->y < 0) | 318 | if (tsdev->y < 0) |
@@ -323,6 +329,7 @@ static void tsdev_event(struct input_handle *handle, unsigned int type, | |||
323 | case 0: | 329 | case 0: |
324 | tsdev->pressure = 0; | 330 | tsdev->pressure = 0; |
325 | break; | 331 | break; |
332 | |||
326 | case 1: | 333 | case 1: |
327 | if (!tsdev->pressure) | 334 | if (!tsdev->pressure) |
328 | tsdev->pressure = 1; | 335 | tsdev->pressure = 1; |
@@ -370,9 +377,8 @@ static struct input_handle *tsdev_connect(struct input_handler *handler, | |||
370 | struct class_device *cdev; | 377 | struct class_device *cdev; |
371 | int minor, delta; | 378 | int minor, delta; |
372 | 379 | ||
373 | for (minor = 0; minor < TSDEV_MINORS/2 && tsdev_table[minor]; | 380 | for (minor = 0; minor < TSDEV_MINORS / 2 && tsdev_table[minor]; minor++); |
374 | minor++); | 381 | if (minor >= TSDEV_MINORS / 2) { |
375 | if (minor >= TSDEV_MINORS/2) { | ||
376 | printk(KERN_ERR | 382 | printk(KERN_ERR |
377 | "tsdev: You have way too many touchscreens\n"); | 383 | "tsdev: You have way too many touchscreens\n"); |
378 | return NULL; | 384 | return NULL; |
@@ -444,22 +450,22 @@ static struct input_device_id tsdev_ids[] = { | |||
444 | .evbit = { BIT(EV_KEY) | BIT(EV_REL) }, | 450 | .evbit = { BIT(EV_KEY) | BIT(EV_REL) }, |
445 | .keybit = { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) }, | 451 | .keybit = { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) }, |
446 | .relbit = { BIT(REL_X) | BIT(REL_Y) }, | 452 | .relbit = { BIT(REL_X) | BIT(REL_Y) }, |
447 | },/* A mouse like device, at least one button, two relative axes */ | 453 | }, /* A mouse like device, at least one button, two relative axes */ |
448 | 454 | ||
449 | { | 455 | { |
450 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, | 456 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, |
451 | .evbit = { BIT(EV_KEY) | BIT(EV_ABS) }, | 457 | .evbit = { BIT(EV_KEY) | BIT(EV_ABS) }, |
452 | .keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) }, | 458 | .keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) }, |
453 | .absbit = { BIT(ABS_X) | BIT(ABS_Y) }, | 459 | .absbit = { BIT(ABS_X) | BIT(ABS_Y) }, |
454 | },/* A tablet like device, at least touch detection, two absolute axes */ | 460 | }, /* A tablet like device, at least touch detection, two absolute axes */ |
455 | 461 | ||
456 | { | 462 | { |
457 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, | 463 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, |
458 | .evbit = { BIT(EV_ABS) }, | 464 | .evbit = { BIT(EV_ABS) }, |
459 | .absbit = { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) }, | 465 | .absbit = { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) }, |
460 | },/* A tablet like device with several gradations of pressure */ | 466 | }, /* A tablet like device with several gradations of pressure */ |
461 | 467 | ||
462 | {},/* Terminating entry */ | 468 | {} /* Terminating entry */ |
463 | }; | 469 | }; |
464 | 470 | ||
465 | MODULE_DEVICE_TABLE(input, tsdev_ids); | 471 | MODULE_DEVICE_TABLE(input, tsdev_ids); |
diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c index 173c899a1fb4..2e541fa02024 100644 --- a/drivers/isdn/capi/capi.c +++ b/drivers/isdn/capi/capi.c | |||
@@ -87,6 +87,11 @@ struct capincci; | |||
87 | #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE | 87 | #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE |
88 | struct capiminor; | 88 | struct capiminor; |
89 | 89 | ||
90 | struct datahandle_queue { | ||
91 | struct list_head list; | ||
92 | u16 datahandle; | ||
93 | }; | ||
94 | |||
90 | struct capiminor { | 95 | struct capiminor { |
91 | struct list_head list; | 96 | struct list_head list; |
92 | struct capincci *nccip; | 97 | struct capincci *nccip; |
@@ -109,12 +114,9 @@ struct capiminor { | |||
109 | int outbytes; | 114 | int outbytes; |
110 | 115 | ||
111 | /* transmit path */ | 116 | /* transmit path */ |
112 | struct datahandle_queue { | 117 | struct list_head ackqueue; |
113 | struct datahandle_queue *next; | ||
114 | u16 datahandle; | ||
115 | } *ackqueue; | ||
116 | int nack; | 118 | int nack; |
117 | 119 | spinlock_t ackqlock; | |
118 | }; | 120 | }; |
119 | #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ | 121 | #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ |
120 | 122 | ||
@@ -156,48 +158,54 @@ static LIST_HEAD(capiminor_list); | |||
156 | 158 | ||
157 | static int capincci_add_ack(struct capiminor *mp, u16 datahandle) | 159 | static int capincci_add_ack(struct capiminor *mp, u16 datahandle) |
158 | { | 160 | { |
159 | struct datahandle_queue *n, **pp; | 161 | struct datahandle_queue *n; |
162 | unsigned long flags; | ||
160 | 163 | ||
161 | n = kmalloc(sizeof(*n), GFP_ATOMIC); | 164 | n = kmalloc(sizeof(*n), GFP_ATOMIC); |
162 | if (!n) { | 165 | if (unlikely(!n)) { |
163 | printk(KERN_ERR "capi: alloc datahandle failed\n"); | 166 | printk(KERN_ERR "capi: alloc datahandle failed\n"); |
164 | return -1; | 167 | return -1; |
165 | } | 168 | } |
166 | n->next = NULL; | ||
167 | n->datahandle = datahandle; | 169 | n->datahandle = datahandle; |
168 | for (pp = &mp->ackqueue; *pp; pp = &(*pp)->next) ; | 170 | INIT_LIST_HEAD(&n->list); |
169 | *pp = n; | 171 | spin_lock_irqsave(&mp->ackqlock, flags); |
172 | list_add_tail(&n->list, &mp->ackqueue); | ||
170 | mp->nack++; | 173 | mp->nack++; |
174 | spin_unlock_irqrestore(&mp->ackqlock, flags); | ||
171 | return 0; | 175 | return 0; |
172 | } | 176 | } |
173 | 177 | ||
174 | static int capiminor_del_ack(struct capiminor *mp, u16 datahandle) | 178 | static int capiminor_del_ack(struct capiminor *mp, u16 datahandle) |
175 | { | 179 | { |
176 | struct datahandle_queue **pp, *p; | 180 | struct datahandle_queue *p, *tmp; |
181 | unsigned long flags; | ||
177 | 182 | ||
178 | for (pp = &mp->ackqueue; *pp; pp = &(*pp)->next) { | 183 | spin_lock_irqsave(&mp->ackqlock, flags); |
179 | if ((*pp)->datahandle == datahandle) { | 184 | list_for_each_entry_safe(p, tmp, &mp->ackqueue, list) { |
180 | p = *pp; | 185 | if (p->datahandle == datahandle) { |
181 | *pp = (*pp)->next; | 186 | list_del(&p->list); |
182 | kfree(p); | 187 | kfree(p); |
183 | mp->nack--; | 188 | mp->nack--; |
189 | spin_unlock_irqrestore(&mp->ackqlock, flags); | ||
184 | return 0; | 190 | return 0; |
185 | } | 191 | } |
186 | } | 192 | } |
193 | spin_unlock_irqrestore(&mp->ackqlock, flags); | ||
187 | return -1; | 194 | return -1; |
188 | } | 195 | } |
189 | 196 | ||
190 | static void capiminor_del_all_ack(struct capiminor *mp) | 197 | static void capiminor_del_all_ack(struct capiminor *mp) |
191 | { | 198 | { |
192 | struct datahandle_queue **pp, *p; | 199 | struct datahandle_queue *p, *tmp; |
200 | unsigned long flags; | ||
193 | 201 | ||
194 | pp = &mp->ackqueue; | 202 | spin_lock_irqsave(&mp->ackqlock, flags); |
195 | while (*pp) { | 203 | list_for_each_entry_safe(p, tmp, &mp->ackqueue, list) { |
196 | p = *pp; | 204 | list_del(&p->list); |
197 | *pp = (*pp)->next; | ||
198 | kfree(p); | 205 | kfree(p); |
199 | mp->nack--; | 206 | mp->nack--; |
200 | } | 207 | } |
208 | spin_unlock_irqrestore(&mp->ackqlock, flags); | ||
201 | } | 209 | } |
202 | 210 | ||
203 | 211 | ||
@@ -220,6 +228,8 @@ static struct capiminor *capiminor_alloc(struct capi20_appl *ap, u32 ncci) | |||
220 | mp->ncci = ncci; | 228 | mp->ncci = ncci; |
221 | mp->msgid = 0; | 229 | mp->msgid = 0; |
222 | atomic_set(&mp->ttyopencount,0); | 230 | atomic_set(&mp->ttyopencount,0); |
231 | INIT_LIST_HEAD(&mp->ackqueue); | ||
232 | spin_lock_init(&mp->ackqlock); | ||
223 | 233 | ||
224 | skb_queue_head_init(&mp->inqueue); | 234 | skb_queue_head_init(&mp->inqueue); |
225 | skb_queue_head_init(&mp->outqueue); | 235 | skb_queue_head_init(&mp->outqueue); |
diff --git a/drivers/isdn/divert/isdn_divert.c b/drivers/isdn/divert/isdn_divert.c index f1a1f9a9b88e..1f5ebe9ee72c 100644 --- a/drivers/isdn/divert/isdn_divert.c +++ b/drivers/isdn/divert/isdn_divert.c | |||
@@ -592,7 +592,7 @@ static int put_address(char *st, u_char *p, int len) | |||
592 | } /* put_address */ | 592 | } /* put_address */ |
593 | 593 | ||
594 | /*************************************/ | 594 | /*************************************/ |
595 | /* report a succesfull interrogation */ | 595 | /* report a successful interrogation */ |
596 | /*************************************/ | 596 | /*************************************/ |
597 | static int interrogate_success(isdn_ctrl *ic, struct call_struc *cs) | 597 | static int interrogate_success(isdn_ctrl *ic, struct call_struc *cs) |
598 | { char *src = ic->parm.dss1_io.data; | 598 | { char *src = ic->parm.dss1_io.data; |
diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c index eb41aba3ddef..8a45715dd4c1 100644 --- a/drivers/isdn/gigaset/bas-gigaset.c +++ b/drivers/isdn/gigaset/bas-gigaset.c | |||
@@ -65,23 +65,22 @@ static struct usb_device_id gigaset_table [] = { | |||
65 | 65 | ||
66 | MODULE_DEVICE_TABLE(usb, gigaset_table); | 66 | MODULE_DEVICE_TABLE(usb, gigaset_table); |
67 | 67 | ||
68 | /*======================= local function prototypes =============================*/ | 68 | /*======================= local function prototypes ==========================*/ |
69 | 69 | ||
70 | /* This function is called if a new device is connected to the USB port. It | 70 | /* function called if a new device belonging to this driver is connected */ |
71 | * checks whether this new device belongs to this driver. | ||
72 | */ | ||
73 | static int gigaset_probe(struct usb_interface *interface, | 71 | static int gigaset_probe(struct usb_interface *interface, |
74 | const struct usb_device_id *id); | 72 | const struct usb_device_id *id); |
75 | 73 | ||
76 | /* Function will be called if the device is unplugged */ | 74 | /* Function will be called if the device is unplugged */ |
77 | static void gigaset_disconnect(struct usb_interface *interface); | 75 | static void gigaset_disconnect(struct usb_interface *interface); |
78 | 76 | ||
79 | static void read_ctrl_callback(struct urb *, struct pt_regs *); | 77 | static int atread_submit(struct cardstate *, int); |
80 | static void stopurbs(struct bas_bc_state *); | 78 | static void stopurbs(struct bas_bc_state *); |
79 | static int req_submit(struct bc_state *, int, int, int); | ||
81 | static int atwrite_submit(struct cardstate *, unsigned char *, int); | 80 | static int atwrite_submit(struct cardstate *, unsigned char *, int); |
82 | static int start_cbsend(struct cardstate *); | 81 | static int start_cbsend(struct cardstate *); |
83 | 82 | ||
84 | /*==============================================================================*/ | 83 | /*============================================================================*/ |
85 | 84 | ||
86 | struct bas_cardstate { | 85 | struct bas_cardstate { |
87 | struct usb_device *udev; /* USB device pointer */ | 86 | struct usb_device *udev; /* USB device pointer */ |
@@ -91,6 +90,7 @@ struct bas_cardstate { | |||
91 | struct urb *urb_ctrl; /* control pipe default URB */ | 90 | struct urb *urb_ctrl; /* control pipe default URB */ |
92 | struct usb_ctrlrequest dr_ctrl; | 91 | struct usb_ctrlrequest dr_ctrl; |
93 | struct timer_list timer_ctrl; /* control request timeout */ | 92 | struct timer_list timer_ctrl; /* control request timeout */ |
93 | int retry_ctrl; | ||
94 | 94 | ||
95 | struct timer_list timer_atrdy; /* AT command ready timeout */ | 95 | struct timer_list timer_atrdy; /* AT command ready timeout */ |
96 | struct urb *urb_cmd_out; /* for sending AT commands */ | 96 | struct urb *urb_cmd_out; /* for sending AT commands */ |
@@ -307,6 +307,7 @@ static int gigaset_set_line_ctrl(struct cardstate *cs, unsigned cflag) | |||
307 | * hang up any existing connection because of an unrecoverable error | 307 | * hang up any existing connection because of an unrecoverable error |
308 | * This function may be called from any context and takes care of scheduling | 308 | * This function may be called from any context and takes care of scheduling |
309 | * the necessary actions for execution outside of interrupt context. | 309 | * the necessary actions for execution outside of interrupt context. |
310 | * cs->lock must not be held. | ||
310 | * argument: | 311 | * argument: |
311 | * B channel control structure | 312 | * B channel control structure |
312 | */ | 313 | */ |
@@ -325,14 +326,17 @@ static inline void error_hangup(struct bc_state *bcs) | |||
325 | 326 | ||
326 | /* error_reset | 327 | /* error_reset |
327 | * reset Gigaset device because of an unrecoverable error | 328 | * reset Gigaset device because of an unrecoverable error |
328 | * This function may be called from any context, and should take care of | 329 | * This function may be called from any context, and takes care of |
329 | * scheduling the necessary actions for execution outside of interrupt context. | 330 | * scheduling the necessary actions for execution outside of interrupt context. |
330 | * Right now, it just generates a kernel message calling for help. | 331 | * cs->lock must not be held. |
331 | * argument: | 332 | * argument: |
332 | * controller state structure | 333 | * controller state structure |
333 | */ | 334 | */ |
334 | static inline void error_reset(struct cardstate *cs) | 335 | static inline void error_reset(struct cardstate *cs) |
335 | { | 336 | { |
337 | /* close AT command channel to recover (ignore errors) */ | ||
338 | req_submit(cs->bcs, HD_CLOSE_ATCHANNEL, 0, BAS_TIMEOUT); | ||
339 | |||
336 | //FIXME try to recover without bothering the user | 340 | //FIXME try to recover without bothering the user |
337 | dev_err(cs->dev, | 341 | dev_err(cs->dev, |
338 | "unrecoverable error - please disconnect Gigaset base to reset\n"); | 342 | "unrecoverable error - please disconnect Gigaset base to reset\n"); |
@@ -403,14 +407,30 @@ static void cmd_in_timeout(unsigned long data) | |||
403 | { | 407 | { |
404 | struct cardstate *cs = (struct cardstate *) data; | 408 | struct cardstate *cs = (struct cardstate *) data; |
405 | struct bas_cardstate *ucs = cs->hw.bas; | 409 | struct bas_cardstate *ucs = cs->hw.bas; |
410 | int rc; | ||
406 | 411 | ||
407 | if (!ucs->rcvbuf_size) { | 412 | if (!ucs->rcvbuf_size) { |
408 | gig_dbg(DEBUG_USBREQ, "%s: no receive in progress", __func__); | 413 | gig_dbg(DEBUG_USBREQ, "%s: no receive in progress", __func__); |
409 | return; | 414 | return; |
410 | } | 415 | } |
411 | 416 | ||
412 | dev_err(cs->dev, "timeout reading AT response\n"); | 417 | if (ucs->retry_cmd_in++ < BAS_RETRY) { |
413 | error_reset(cs); //FIXME retry? | 418 | dev_notice(cs->dev, "control read: timeout, retry %d\n", |
419 | ucs->retry_cmd_in); | ||
420 | rc = atread_submit(cs, BAS_TIMEOUT); | ||
421 | if (rc >= 0 || rc == -ENODEV) | ||
422 | /* resubmitted or disconnected */ | ||
423 | /* - bypass regular exit block */ | ||
424 | return; | ||
425 | } else { | ||
426 | dev_err(cs->dev, | ||
427 | "control read: timeout, giving up after %d tries\n", | ||
428 | ucs->retry_cmd_in); | ||
429 | } | ||
430 | kfree(ucs->rcvbuf); | ||
431 | ucs->rcvbuf = NULL; | ||
432 | ucs->rcvbuf_size = 0; | ||
433 | error_reset(cs); | ||
414 | } | 434 | } |
415 | 435 | ||
416 | /* set/clear bits in base connection state, return previous state | 436 | /* set/clear bits in base connection state, return previous state |
@@ -428,6 +448,96 @@ inline static int update_basstate(struct bas_cardstate *ucs, | |||
428 | return state; | 448 | return state; |
429 | } | 449 | } |
430 | 450 | ||
451 | /* read_ctrl_callback | ||
452 | * USB completion handler for control pipe input | ||
453 | * called by the USB subsystem in interrupt context | ||
454 | * parameter: | ||
455 | * urb USB request block | ||
456 | * urb->context = inbuf structure for controller state | ||
457 | */ | ||
458 | static void read_ctrl_callback(struct urb *urb, struct pt_regs *regs) | ||
459 | { | ||
460 | struct inbuf_t *inbuf = urb->context; | ||
461 | struct cardstate *cs = inbuf->cs; | ||
462 | struct bas_cardstate *ucs = cs->hw.bas; | ||
463 | int have_data = 0; | ||
464 | unsigned numbytes; | ||
465 | int rc; | ||
466 | |||
467 | update_basstate(ucs, 0, BS_ATRDPEND); | ||
468 | |||
469 | if (!ucs->rcvbuf_size) { | ||
470 | dev_warn(cs->dev, "%s: no receive in progress\n", __func__); | ||
471 | return; | ||
472 | } | ||
473 | |||
474 | del_timer(&ucs->timer_cmd_in); | ||
475 | |||
476 | switch (urb->status) { | ||
477 | case 0: /* normal completion */ | ||
478 | numbytes = urb->actual_length; | ||
479 | if (unlikely(numbytes != ucs->rcvbuf_size)) { | ||
480 | dev_warn(cs->dev, | ||
481 | "control read: received %d chars, expected %d\n", | ||
482 | numbytes, ucs->rcvbuf_size); | ||
483 | if (numbytes > ucs->rcvbuf_size) | ||
484 | numbytes = ucs->rcvbuf_size; | ||
485 | } | ||
486 | |||
487 | /* copy received bytes to inbuf */ | ||
488 | have_data = gigaset_fill_inbuf(inbuf, ucs->rcvbuf, numbytes); | ||
489 | |||
490 | if (unlikely(numbytes < ucs->rcvbuf_size)) { | ||
491 | /* incomplete - resubmit for remaining bytes */ | ||
492 | ucs->rcvbuf_size -= numbytes; | ||
493 | ucs->retry_cmd_in = 0; | ||
494 | rc = atread_submit(cs, BAS_TIMEOUT); | ||
495 | if (rc >= 0 || rc == -ENODEV) | ||
496 | /* resubmitted or disconnected */ | ||
497 | /* - bypass regular exit block */ | ||
498 | return; | ||
499 | error_reset(cs); | ||
500 | } | ||
501 | break; | ||
502 | |||
503 | case -ENOENT: /* cancelled */ | ||
504 | case -ECONNRESET: /* cancelled (async) */ | ||
505 | case -EINPROGRESS: /* pending */ | ||
506 | case -ENODEV: /* device removed */ | ||
507 | case -ESHUTDOWN: /* device shut down */ | ||
508 | /* no action necessary */ | ||
509 | gig_dbg(DEBUG_USBREQ, "%s: %s", | ||
510 | __func__, get_usb_statmsg(urb->status)); | ||
511 | break; | ||
512 | |||
513 | default: /* severe trouble */ | ||
514 | dev_warn(cs->dev, "control read: %s\n", | ||
515 | get_usb_statmsg(urb->status)); | ||
516 | if (ucs->retry_cmd_in++ < BAS_RETRY) { | ||
517 | dev_notice(cs->dev, "control read: retry %d\n", | ||
518 | ucs->retry_cmd_in); | ||
519 | rc = atread_submit(cs, BAS_TIMEOUT); | ||
520 | if (rc >= 0 || rc == -ENODEV) | ||
521 | /* resubmitted or disconnected */ | ||
522 | /* - bypass regular exit block */ | ||
523 | return; | ||
524 | } else { | ||
525 | dev_err(cs->dev, | ||
526 | "control read: giving up after %d tries\n", | ||
527 | ucs->retry_cmd_in); | ||
528 | } | ||
529 | error_reset(cs); | ||
530 | } | ||
531 | |||
532 | kfree(ucs->rcvbuf); | ||
533 | ucs->rcvbuf = NULL; | ||
534 | ucs->rcvbuf_size = 0; | ||
535 | if (have_data) { | ||
536 | gig_dbg(DEBUG_INTR, "%s-->BH", __func__); | ||
537 | gigaset_schedule_event(cs); | ||
538 | } | ||
539 | } | ||
540 | |||
431 | /* atread_submit | 541 | /* atread_submit |
432 | * submit an HD_READ_ATMESSAGE command URB and optionally start a timeout | 542 | * submit an HD_READ_ATMESSAGE command URB and optionally start a timeout |
433 | * parameters: | 543 | * parameters: |
@@ -466,7 +576,7 @@ static int atread_submit(struct cardstate *cs, int timeout) | |||
466 | if ((ret = usb_submit_urb(ucs->urb_cmd_in, SLAB_ATOMIC)) != 0) { | 576 | if ((ret = usb_submit_urb(ucs->urb_cmd_in, SLAB_ATOMIC)) != 0) { |
467 | update_basstate(ucs, 0, BS_ATRDPEND); | 577 | update_basstate(ucs, 0, BS_ATRDPEND); |
468 | dev_err(cs->dev, "could not submit HD_READ_ATMESSAGE: %s\n", | 578 | dev_err(cs->dev, "could not submit HD_READ_ATMESSAGE: %s\n", |
469 | get_usb_statmsg(ret)); | 579 | get_usb_rcmsg(ret)); |
470 | return ret; | 580 | return ret; |
471 | } | 581 | } |
472 | 582 | ||
@@ -611,9 +721,12 @@ static void read_int_callback(struct urb *urb, struct pt_regs *regs) | |||
611 | kfree(ucs->rcvbuf); | 721 | kfree(ucs->rcvbuf); |
612 | ucs->rcvbuf = NULL; | 722 | ucs->rcvbuf = NULL; |
613 | ucs->rcvbuf_size = 0; | 723 | ucs->rcvbuf_size = 0; |
614 | if (rc != -ENODEV) | 724 | if (rc != -ENODEV) { |
615 | //FIXME corrective action? | 725 | //FIXME corrective action? |
726 | spin_unlock_irqrestore(&cs->lock, flags); | ||
616 | error_reset(cs); | 727 | error_reset(cs); |
728 | break; | ||
729 | } | ||
617 | } | 730 | } |
618 | spin_unlock_irqrestore(&cs->lock, flags); | 731 | spin_unlock_irqrestore(&cs->lock, flags); |
619 | break; | 732 | break; |
@@ -643,97 +756,6 @@ resubmit: | |||
643 | } | 756 | } |
644 | } | 757 | } |
645 | 758 | ||
646 | /* read_ctrl_callback | ||
647 | * USB completion handler for control pipe input | ||
648 | * called by the USB subsystem in interrupt context | ||
649 | * parameter: | ||
650 | * urb USB request block | ||
651 | * urb->context = inbuf structure for controller state | ||
652 | */ | ||
653 | static void read_ctrl_callback(struct urb *urb, struct pt_regs *regs) | ||
654 | { | ||
655 | struct inbuf_t *inbuf = urb->context; | ||
656 | struct cardstate *cs = inbuf->cs; | ||
657 | struct bas_cardstate *ucs = cs->hw.bas; | ||
658 | int have_data = 0; | ||
659 | unsigned numbytes; | ||
660 | int rc; | ||
661 | |||
662 | update_basstate(ucs, 0, BS_ATRDPEND); | ||
663 | |||
664 | if (!ucs->rcvbuf_size) { | ||
665 | dev_warn(cs->dev, "%s: no receive in progress\n", __func__); | ||
666 | return; | ||
667 | } | ||
668 | |||
669 | del_timer(&ucs->timer_cmd_in); | ||
670 | |||
671 | switch (urb->status) { | ||
672 | case 0: /* normal completion */ | ||
673 | numbytes = urb->actual_length; | ||
674 | if (unlikely(numbytes == 0)) { | ||
675 | dev_warn(cs->dev, | ||
676 | "control read: empty block received\n"); | ||
677 | goto retry; | ||
678 | } | ||
679 | if (unlikely(numbytes != ucs->rcvbuf_size)) { | ||
680 | dev_warn(cs->dev, | ||
681 | "control read: received %d chars, expected %d\n", | ||
682 | numbytes, ucs->rcvbuf_size); | ||
683 | if (numbytes > ucs->rcvbuf_size) | ||
684 | numbytes = ucs->rcvbuf_size; | ||
685 | } | ||
686 | |||
687 | /* copy received bytes to inbuf */ | ||
688 | have_data = gigaset_fill_inbuf(inbuf, ucs->rcvbuf, numbytes); | ||
689 | |||
690 | if (unlikely(numbytes < ucs->rcvbuf_size)) { | ||
691 | /* incomplete - resubmit for remaining bytes */ | ||
692 | ucs->rcvbuf_size -= numbytes; | ||
693 | ucs->retry_cmd_in = 0; | ||
694 | goto retry; | ||
695 | } | ||
696 | break; | ||
697 | |||
698 | case -ENOENT: /* cancelled */ | ||
699 | case -ECONNRESET: /* cancelled (async) */ | ||
700 | case -EINPROGRESS: /* pending */ | ||
701 | case -ENODEV: /* device removed */ | ||
702 | case -ESHUTDOWN: /* device shut down */ | ||
703 | /* no action necessary */ | ||
704 | gig_dbg(DEBUG_USBREQ, "%s: %s", | ||
705 | __func__, get_usb_statmsg(urb->status)); | ||
706 | break; | ||
707 | |||
708 | default: /* severe trouble */ | ||
709 | dev_warn(cs->dev, "control read: %s\n", | ||
710 | get_usb_statmsg(urb->status)); | ||
711 | retry: | ||
712 | if (ucs->retry_cmd_in++ < BAS_RETRY) { | ||
713 | dev_notice(cs->dev, "control read: retry %d\n", | ||
714 | ucs->retry_cmd_in); | ||
715 | rc = atread_submit(cs, BAS_TIMEOUT); | ||
716 | if (rc >= 0 || rc == -ENODEV) | ||
717 | /* resubmitted or disconnected */ | ||
718 | /* - bypass regular exit block */ | ||
719 | return; | ||
720 | } else { | ||
721 | dev_err(cs->dev, | ||
722 | "control read: giving up after %d tries\n", | ||
723 | ucs->retry_cmd_in); | ||
724 | } | ||
725 | error_reset(cs); | ||
726 | } | ||
727 | |||
728 | kfree(ucs->rcvbuf); | ||
729 | ucs->rcvbuf = NULL; | ||
730 | ucs->rcvbuf_size = 0; | ||
731 | if (have_data) { | ||
732 | gig_dbg(DEBUG_INTR, "%s-->BH", __func__); | ||
733 | gigaset_schedule_event(cs); | ||
734 | } | ||
735 | } | ||
736 | |||
737 | /* read_iso_callback | 759 | /* read_iso_callback |
738 | * USB completion handler for B channel isochronous input | 760 | * USB completion handler for B channel isochronous input |
739 | * called by the USB subsystem in interrupt context | 761 | * called by the USB subsystem in interrupt context |
@@ -1378,6 +1400,7 @@ static void req_timeout(unsigned long data) | |||
1378 | case HD_CLOSE_B1CHANNEL: | 1400 | case HD_CLOSE_B1CHANNEL: |
1379 | dev_err(bcs->cs->dev, "timeout closing channel %d\n", | 1401 | dev_err(bcs->cs->dev, "timeout closing channel %d\n", |
1380 | bcs->channel + 1); | 1402 | bcs->channel + 1); |
1403 | error_reset(bcs->cs); | ||
1381 | break; | 1404 | break; |
1382 | 1405 | ||
1383 | default: | 1406 | default: |
@@ -1396,22 +1419,61 @@ static void req_timeout(unsigned long data) | |||
1396 | static void write_ctrl_callback(struct urb *urb, struct pt_regs *regs) | 1419 | static void write_ctrl_callback(struct urb *urb, struct pt_regs *regs) |
1397 | { | 1420 | { |
1398 | struct bas_cardstate *ucs = urb->context; | 1421 | struct bas_cardstate *ucs = urb->context; |
1422 | int rc; | ||
1399 | unsigned long flags; | 1423 | unsigned long flags; |
1400 | 1424 | ||
1401 | spin_lock_irqsave(&ucs->lock, flags); | 1425 | /* check status */ |
1402 | if (urb->status && ucs->pending) { | 1426 | switch (urb->status) { |
1403 | dev_err(&ucs->interface->dev, | 1427 | case 0: /* normal completion */ |
1404 | "control request 0x%02x failed: %s\n", | 1428 | spin_lock_irqsave(&ucs->lock, flags); |
1405 | ucs->pending, get_usb_statmsg(urb->status)); | 1429 | switch (ucs->pending) { |
1406 | del_timer(&ucs->timer_ctrl); | 1430 | case HD_DEVICE_INIT_ACK: /* no reply expected */ |
1407 | ucs->pending = 0; | 1431 | del_timer(&ucs->timer_ctrl); |
1408 | } | 1432 | ucs->pending = 0; |
1409 | /* individual handling of specific request types */ | 1433 | break; |
1410 | switch (ucs->pending) { | 1434 | } |
1411 | case HD_DEVICE_INIT_ACK: /* no reply expected */ | 1435 | spin_unlock_irqrestore(&ucs->lock, flags); |
1412 | ucs->pending = 0; | 1436 | return; |
1437 | |||
1438 | case -ENOENT: /* cancelled */ | ||
1439 | case -ECONNRESET: /* cancelled (async) */ | ||
1440 | case -EINPROGRESS: /* pending */ | ||
1441 | case -ENODEV: /* device removed */ | ||
1442 | case -ESHUTDOWN: /* device shut down */ | ||
1443 | /* ignore silently */ | ||
1444 | gig_dbg(DEBUG_USBREQ, "%s: %s", | ||
1445 | __func__, get_usb_statmsg(urb->status)); | ||
1413 | break; | 1446 | break; |
1447 | |||
1448 | default: /* any failure */ | ||
1449 | if (++ucs->retry_ctrl > BAS_RETRY) { | ||
1450 | dev_err(&ucs->interface->dev, | ||
1451 | "control request 0x%02x failed: %s\n", | ||
1452 | ucs->dr_ctrl.bRequest, | ||
1453 | get_usb_statmsg(urb->status)); | ||
1454 | break; /* give up */ | ||
1455 | } | ||
1456 | dev_notice(&ucs->interface->dev, | ||
1457 | "control request 0x%02x: %s, retry %d\n", | ||
1458 | ucs->dr_ctrl.bRequest, get_usb_statmsg(urb->status), | ||
1459 | ucs->retry_ctrl); | ||
1460 | /* urb->dev is clobbered by USB subsystem */ | ||
1461 | urb->dev = ucs->udev; | ||
1462 | rc = usb_submit_urb(urb, SLAB_ATOMIC); | ||
1463 | if (unlikely(rc)) { | ||
1464 | dev_err(&ucs->interface->dev, | ||
1465 | "could not resubmit request 0x%02x: %s\n", | ||
1466 | ucs->dr_ctrl.bRequest, get_usb_rcmsg(rc)); | ||
1467 | break; | ||
1468 | } | ||
1469 | /* resubmitted */ | ||
1470 | return; | ||
1414 | } | 1471 | } |
1472 | |||
1473 | /* failed, clear pending request */ | ||
1474 | spin_lock_irqsave(&ucs->lock, flags); | ||
1475 | del_timer(&ucs->timer_ctrl); | ||
1476 | ucs->pending = 0; | ||
1415 | spin_unlock_irqrestore(&ucs->lock, flags); | 1477 | spin_unlock_irqrestore(&ucs->lock, flags); |
1416 | } | 1478 | } |
1417 | 1479 | ||
@@ -1455,9 +1517,11 @@ static int req_submit(struct bc_state *bcs, int req, int val, int timeout) | |||
1455 | usb_sndctrlpipe(ucs->udev, 0), | 1517 | usb_sndctrlpipe(ucs->udev, 0), |
1456 | (unsigned char*) &ucs->dr_ctrl, NULL, 0, | 1518 | (unsigned char*) &ucs->dr_ctrl, NULL, 0, |
1457 | write_ctrl_callback, ucs); | 1519 | write_ctrl_callback, ucs); |
1458 | if ((ret = usb_submit_urb(ucs->urb_ctrl, SLAB_ATOMIC)) != 0) { | 1520 | ucs->retry_ctrl = 0; |
1521 | ret = usb_submit_urb(ucs->urb_ctrl, SLAB_ATOMIC); | ||
1522 | if (unlikely(ret)) { | ||
1459 | dev_err(bcs->cs->dev, "could not submit request 0x%02x: %s\n", | 1523 | dev_err(bcs->cs->dev, "could not submit request 0x%02x: %s\n", |
1460 | req, get_usb_statmsg(ret)); | 1524 | req, get_usb_rcmsg(ret)); |
1461 | spin_unlock_irqrestore(&ucs->lock, flags); | 1525 | spin_unlock_irqrestore(&ucs->lock, flags); |
1462 | return ret; | 1526 | return ret; |
1463 | } | 1527 | } |
diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c index acb7e2656780..2a56bf33a673 100644 --- a/drivers/isdn/gigaset/common.c +++ b/drivers/isdn/gigaset/common.c | |||
@@ -981,7 +981,7 @@ exit: | |||
981 | EXPORT_SYMBOL_GPL(gigaset_stop); | 981 | EXPORT_SYMBOL_GPL(gigaset_stop); |
982 | 982 | ||
983 | static LIST_HEAD(drivers); | 983 | static LIST_HEAD(drivers); |
984 | static spinlock_t driver_lock = SPIN_LOCK_UNLOCKED; | 984 | static DEFINE_SPINLOCK(driver_lock); |
985 | 985 | ||
986 | struct cardstate *gigaset_get_cs_by_id(int id) | 986 | struct cardstate *gigaset_get_cs_by_id(int id) |
987 | { | 987 | { |
diff --git a/drivers/isdn/gigaset/ev-layer.c b/drivers/isdn/gigaset/ev-layer.c index 18e05c09b71c..44f02dbd1111 100644 --- a/drivers/isdn/gigaset/ev-layer.c +++ b/drivers/isdn/gigaset/ev-layer.c | |||
@@ -1262,7 +1262,8 @@ static void do_action(int action, struct cardstate *cs, | |||
1262 | break; | 1262 | break; |
1263 | case ACT_HUPMODEM: | 1263 | case ACT_HUPMODEM: |
1264 | /* send "+++" (hangup in unimodem mode) */ | 1264 | /* send "+++" (hangup in unimodem mode) */ |
1265 | cs->ops->write_cmd(cs, "+++", 3, NULL); | 1265 | if (cs->connected) |
1266 | cs->ops->write_cmd(cs, "+++", 3, NULL); | ||
1266 | break; | 1267 | break; |
1267 | case ACT_RING: | 1268 | case ACT_RING: |
1268 | /* get fresh AT state structure for new CID */ | 1269 | /* get fresh AT state structure for new CID */ |
@@ -1294,7 +1295,6 @@ static void do_action(int action, struct cardstate *cs, | |||
1294 | break; | 1295 | break; |
1295 | case ACT_ICALL: | 1296 | case ACT_ICALL: |
1296 | handle_icall(cs, bcs, p_at_state); | 1297 | handle_icall(cs, bcs, p_at_state); |
1297 | at_state = *p_at_state; | ||
1298 | break; | 1298 | break; |
1299 | case ACT_FAILSDOWN: | 1299 | case ACT_FAILSDOWN: |
1300 | dev_warn(cs->dev, "Could not shut down the device.\n"); | 1300 | dev_warn(cs->dev, "Could not shut down the device.\n"); |
@@ -1334,10 +1334,8 @@ static void do_action(int action, struct cardstate *cs, | |||
1334 | */ | 1334 | */ |
1335 | at_state->pending_commands |= PC_DLE0; | 1335 | at_state->pending_commands |= PC_DLE0; |
1336 | atomic_set(&cs->commands_pending, 1); | 1336 | atomic_set(&cs->commands_pending, 1); |
1337 | } else { | 1337 | } else |
1338 | disconnect(p_at_state); | 1338 | disconnect(p_at_state); |
1339 | at_state = *p_at_state; | ||
1340 | } | ||
1341 | break; | 1339 | break; |
1342 | case ACT_FAKEDLE0: | 1340 | case ACT_FAKEDLE0: |
1343 | at_state->int_var[VAR_ZDLE] = 0; | 1341 | at_state->int_var[VAR_ZDLE] = 0; |
@@ -1354,10 +1352,8 @@ static void do_action(int action, struct cardstate *cs, | |||
1354 | at_state->cid = -1; | 1352 | at_state->cid = -1; |
1355 | if (bcs && cs->onechannel) | 1353 | if (bcs && cs->onechannel) |
1356 | at_state->pending_commands |= PC_DLE0; | 1354 | at_state->pending_commands |= PC_DLE0; |
1357 | else { | 1355 | else |
1358 | disconnect(p_at_state); | 1356 | disconnect(p_at_state); |
1359 | at_state = *p_at_state; | ||
1360 | } | ||
1361 | schedule_init(cs, MS_RECOVER); | 1357 | schedule_init(cs, MS_RECOVER); |
1362 | break; | 1358 | break; |
1363 | case ACT_FAILDLE0: | 1359 | case ACT_FAILDLE0: |
@@ -1410,7 +1406,6 @@ static void do_action(int action, struct cardstate *cs, | |||
1410 | 1406 | ||
1411 | case ACT_ABORTACCEPT: /* hangup/error/timeout during ICALL processing */ | 1407 | case ACT_ABORTACCEPT: /* hangup/error/timeout during ICALL processing */ |
1412 | disconnect(p_at_state); | 1408 | disconnect(p_at_state); |
1413 | at_state = *p_at_state; | ||
1414 | break; | 1409 | break; |
1415 | 1410 | ||
1416 | case ACT_ABORTDIAL: /* error/timeout during dial preparation */ | 1411 | case ACT_ABORTDIAL: /* error/timeout during dial preparation */ |
diff --git a/drivers/isdn/hisax/q931.c b/drivers/isdn/hisax/q931.c index abecabf8c271..aacbf0d14b64 100644 --- a/drivers/isdn/hisax/q931.c +++ b/drivers/isdn/hisax/q931.c | |||
@@ -1402,12 +1402,12 @@ dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir) | |||
1402 | } | 1402 | } |
1403 | /* No, locate it in the table */ | 1403 | /* No, locate it in the table */ |
1404 | if (cset == 0) { | 1404 | if (cset == 0) { |
1405 | for (i = 0; i < IESIZE; i++) | 1405 | for (i = 0; i < IESIZE_NI1; i++) |
1406 | if (*buf == ielist_ni1[i].nr) | 1406 | if (*buf == ielist_ni1[i].nr) |
1407 | break; | 1407 | break; |
1408 | 1408 | ||
1409 | /* When not found, give appropriate msg */ | 1409 | /* When not found, give appropriate msg */ |
1410 | if (i != IESIZE) { | 1410 | if (i != IESIZE_NI1) { |
1411 | dp += sprintf(dp, " %s\n", ielist_ni1[i].descr); | 1411 | dp += sprintf(dp, " %s\n", ielist_ni1[i].descr); |
1412 | dp += ielist_ni1[i].f(dp, buf); | 1412 | dp += ielist_ni1[i].f(dp, buf); |
1413 | } else | 1413 | } else |
diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c index 81accdf35168..b26e509ec759 100644 --- a/drivers/isdn/i4l/isdn_common.c +++ b/drivers/isdn/i4l/isdn_common.c | |||
@@ -933,7 +933,7 @@ isdn_readbchan_tty(int di, int channel, struct tty_struct *tty, int cisco_hack) | |||
933 | count_put = count_pull; | 933 | count_put = count_pull; |
934 | if(count_put > 1) | 934 | if(count_put > 1) |
935 | tty_insert_flip_string(tty, skb->data, count_put - 1); | 935 | tty_insert_flip_string(tty, skb->data, count_put - 1); |
936 | last = skb->data[count_put] - 1; | 936 | last = skb->data[count_put - 1]; |
937 | len -= count_put; | 937 | len -= count_put; |
938 | #ifdef CONFIG_ISDN_AUDIO | 938 | #ifdef CONFIG_ISDN_AUDIO |
939 | } | 939 | } |
diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c index 2ac90242d263..433389daedb2 100644 --- a/drivers/isdn/i4l/isdn_tty.c +++ b/drivers/isdn/i4l/isdn_tty.c | |||
@@ -82,7 +82,7 @@ isdn_tty_try_read(modem_info * info, struct sk_buff *skb) | |||
82 | int l = skb->len; | 82 | int l = skb->len; |
83 | unsigned char *dp = skb->data; | 83 | unsigned char *dp = skb->data; |
84 | while (--l) { | 84 | while (--l) { |
85 | if (*skb->data == DLE) | 85 | if (*dp == DLE) |
86 | tty_insert_flip_char(tty, DLE, 0); | 86 | tty_insert_flip_char(tty, DLE, 0); |
87 | tty_insert_flip_char(tty, *dp++, 0); | 87 | tty_insert_flip_char(tty, *dp++, 0); |
88 | } | 88 | } |
diff --git a/drivers/leds/led-core.c b/drivers/leds/led-core.c index fe6541326c71..9b015f9af351 100644 --- a/drivers/leds/led-core.c +++ b/drivers/leds/led-core.c | |||
@@ -18,7 +18,7 @@ | |||
18 | #include <linux/leds.h> | 18 | #include <linux/leds.h> |
19 | #include "leds.h" | 19 | #include "leds.h" |
20 | 20 | ||
21 | rwlock_t leds_list_lock = RW_LOCK_UNLOCKED; | 21 | DEFINE_RWLOCK(leds_list_lock); |
22 | LIST_HEAD(leds_list); | 22 | LIST_HEAD(leds_list); |
23 | 23 | ||
24 | EXPORT_SYMBOL_GPL(leds_list); | 24 | EXPORT_SYMBOL_GPL(leds_list); |
diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c index 5e2cd8be1191..1b1ce6523960 100644 --- a/drivers/leds/led-triggers.c +++ b/drivers/leds/led-triggers.c | |||
@@ -26,7 +26,7 @@ | |||
26 | /* | 26 | /* |
27 | * Nests outside led_cdev->trigger_lock | 27 | * Nests outside led_cdev->trigger_lock |
28 | */ | 28 | */ |
29 | static rwlock_t triggers_list_lock = RW_LOCK_UNLOCKED; | 29 | static DEFINE_RWLOCK(triggers_list_lock); |
30 | static LIST_HEAD(trigger_list); | 30 | static LIST_HEAD(trigger_list); |
31 | 31 | ||
32 | ssize_t led_trigger_store(struct class_device *dev, const char *buf, | 32 | ssize_t led_trigger_store(struct class_device *dev, const char *buf, |
diff --git a/drivers/macintosh/Makefile b/drivers/macintosh/Makefile index 8972e53d2dcb..45a268f8047e 100644 --- a/drivers/macintosh/Makefile +++ b/drivers/macintosh/Makefile | |||
@@ -11,7 +11,7 @@ obj-$(CONFIG_MAC_EMUMOUSEBTN) += mac_hid.o | |||
11 | obj-$(CONFIG_INPUT_ADBHID) += adbhid.o | 11 | obj-$(CONFIG_INPUT_ADBHID) += adbhid.o |
12 | obj-$(CONFIG_ANSLCD) += ans-lcd.o | 12 | obj-$(CONFIG_ANSLCD) += ans-lcd.o |
13 | 13 | ||
14 | obj-$(CONFIG_ADB_PMU) += via-pmu.o | 14 | obj-$(CONFIG_ADB_PMU) += via-pmu.o via-pmu-event.o |
15 | obj-$(CONFIG_PMAC_BACKLIGHT) += via-pmu-backlight.o | 15 | obj-$(CONFIG_PMAC_BACKLIGHT) += via-pmu-backlight.o |
16 | obj-$(CONFIG_ADB_CUDA) += via-cuda.o | 16 | obj-$(CONFIG_ADB_CUDA) += via-cuda.o |
17 | obj-$(CONFIG_PMAC_APM_EMU) += apm_emu.o | 17 | obj-$(CONFIG_PMAC_APM_EMU) += apm_emu.o |
diff --git a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c index c26e1236b275..cbfbbe2b150a 100644 --- a/drivers/macintosh/adbhid.c +++ b/drivers/macintosh/adbhid.c | |||
@@ -179,7 +179,7 @@ u8 adb_to_linux_keycodes[128] = { | |||
179 | /* 0x65 */ KEY_F9, /* 67 */ | 179 | /* 0x65 */ KEY_F9, /* 67 */ |
180 | /* 0x66 */ KEY_HANJA, /* 123 */ | 180 | /* 0x66 */ KEY_HANJA, /* 123 */ |
181 | /* 0x67 */ KEY_F11, /* 87 */ | 181 | /* 0x67 */ KEY_F11, /* 87 */ |
182 | /* 0x68 */ KEY_HANGUEL, /* 122 */ | 182 | /* 0x68 */ KEY_HANGEUL, /* 122 */ |
183 | /* 0x69 */ KEY_SYSRQ, /* 99 */ | 183 | /* 0x69 */ KEY_SYSRQ, /* 99 */ |
184 | /* 0x6a */ 0, | 184 | /* 0x6a */ 0, |
185 | /* 0x6b */ KEY_SCROLLLOCK, /* 70 */ | 185 | /* 0x6b */ KEY_SCROLLLOCK, /* 70 */ |
diff --git a/drivers/macintosh/via-pmu-event.c b/drivers/macintosh/via-pmu-event.c new file mode 100644 index 000000000000..25cd56542328 --- /dev/null +++ b/drivers/macintosh/via-pmu-event.c | |||
@@ -0,0 +1,80 @@ | |||
1 | /* | ||
2 | * via-pmu event device for reporting some events that come through the PMU | ||
3 | * | ||
4 | * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> | ||
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 as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | ||
14 | * NON INFRINGEMENT. See the GNU General Public License for more | ||
15 | * details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | #include <linux/input.h> | ||
24 | #include <linux/adb.h> | ||
25 | #include <linux/pmu.h> | ||
26 | #include "via-pmu-event.h" | ||
27 | |||
28 | static struct input_dev *pmu_input_dev; | ||
29 | |||
30 | static int __init via_pmu_event_init(void) | ||
31 | { | ||
32 | int err; | ||
33 | |||
34 | /* do other models report button/lid status? */ | ||
35 | if (pmu_get_model() != PMU_KEYLARGO_BASED) | ||
36 | return -ENODEV; | ||
37 | |||
38 | pmu_input_dev = input_allocate_device(); | ||
39 | if (!pmu_input_dev) | ||
40 | return -ENOMEM; | ||
41 | |||
42 | pmu_input_dev->name = "PMU"; | ||
43 | pmu_input_dev->id.bustype = BUS_HOST; | ||
44 | pmu_input_dev->id.vendor = 0x0001; | ||
45 | pmu_input_dev->id.product = 0x0001; | ||
46 | pmu_input_dev->id.version = 0x0100; | ||
47 | |||
48 | set_bit(EV_KEY, pmu_input_dev->evbit); | ||
49 | set_bit(EV_SW, pmu_input_dev->evbit); | ||
50 | set_bit(KEY_POWER, pmu_input_dev->keybit); | ||
51 | set_bit(SW_LID, pmu_input_dev->swbit); | ||
52 | |||
53 | err = input_register_device(pmu_input_dev); | ||
54 | if (err) | ||
55 | input_free_device(pmu_input_dev); | ||
56 | return err; | ||
57 | } | ||
58 | |||
59 | void via_pmu_event(int key, int down) | ||
60 | { | ||
61 | |||
62 | if (unlikely(!pmu_input_dev)) | ||
63 | return; | ||
64 | |||
65 | switch (key) { | ||
66 | case PMU_EVT_POWER: | ||
67 | input_report_key(pmu_input_dev, KEY_POWER, down); | ||
68 | break; | ||
69 | case PMU_EVT_LID: | ||
70 | input_report_switch(pmu_input_dev, SW_LID, down); | ||
71 | break; | ||
72 | default: | ||
73 | /* no such key handled */ | ||
74 | return; | ||
75 | } | ||
76 | |||
77 | input_sync(pmu_input_dev); | ||
78 | } | ||
79 | |||
80 | late_initcall(via_pmu_event_init); | ||
diff --git a/drivers/macintosh/via-pmu-event.h b/drivers/macintosh/via-pmu-event.h new file mode 100644 index 000000000000..72c54de408e8 --- /dev/null +++ b/drivers/macintosh/via-pmu-event.h | |||
@@ -0,0 +1,8 @@ | |||
1 | #ifndef __VIA_PMU_EVENT_H | ||
2 | #define __VIA_PMU_EVENT_H | ||
3 | |||
4 | #define PMU_EVT_POWER 0 | ||
5 | #define PMU_EVT_LID 1 | ||
6 | extern void via_pmu_event(int key, int down); | ||
7 | |||
8 | #endif /* __VIA_PMU_EVENT_H */ | ||
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index 2a355ae59562..1ab4f16c08b9 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c | |||
@@ -69,6 +69,8 @@ | |||
69 | #include <asm/open_pic.h> | 69 | #include <asm/open_pic.h> |
70 | #endif | 70 | #endif |
71 | 71 | ||
72 | #include "via-pmu-event.h" | ||
73 | |||
72 | /* Some compile options */ | 74 | /* Some compile options */ |
73 | #undef SUSPEND_USES_PMU | 75 | #undef SUSPEND_USES_PMU |
74 | #define DEBUG_SLEEP | 76 | #define DEBUG_SLEEP |
@@ -1427,6 +1429,12 @@ next: | |||
1427 | if (pmu_battery_count) | 1429 | if (pmu_battery_count) |
1428 | query_battery_state(); | 1430 | query_battery_state(); |
1429 | pmu_pass_intr(data, len); | 1431 | pmu_pass_intr(data, len); |
1432 | /* len == 6 is probably a bad check. But how do I | ||
1433 | * know what PMU versions send what events here? */ | ||
1434 | if (len == 6) { | ||
1435 | via_pmu_event(PMU_EVT_POWER, !!(data[1]&8)); | ||
1436 | via_pmu_event(PMU_EVT_LID, data[1]&1); | ||
1437 | } | ||
1430 | } else { | 1438 | } else { |
1431 | pmu_pass_intr(data, len); | 1439 | pmu_pass_intr(data, len); |
1432 | } | 1440 | } |
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig index ac25a48362ac..bf869ed03eed 100644 --- a/drivers/md/Kconfig +++ b/drivers/md/Kconfig | |||
@@ -90,7 +90,7 @@ config MD_RAID10 | |||
90 | depends on BLK_DEV_MD && EXPERIMENTAL | 90 | depends on BLK_DEV_MD && EXPERIMENTAL |
91 | ---help--- | 91 | ---help--- |
92 | RAID-10 provides a combination of striping (RAID-0) and | 92 | RAID-10 provides a combination of striping (RAID-0) and |
93 | mirroring (RAID-1) with easier configuration and more flexable | 93 | mirroring (RAID-1) with easier configuration and more flexible |
94 | layout. | 94 | layout. |
95 | Unlike RAID-0, but like RAID-1, RAID-10 requires all devices to | 95 | Unlike RAID-0, but like RAID-1, RAID-10 requires all devices to |
96 | be the same size (or at least, only as much as the smallest device | 96 | be the same size (or at least, only as much as the smallest device |
@@ -104,8 +104,8 @@ config MD_RAID10 | |||
104 | 104 | ||
105 | If unsure, say Y. | 105 | If unsure, say Y. |
106 | 106 | ||
107 | config MD_RAID5 | 107 | config MD_RAID456 |
108 | tristate "RAID-4/RAID-5 mode" | 108 | tristate "RAID-4/RAID-5/RAID-6 mode" |
109 | depends on BLK_DEV_MD | 109 | depends on BLK_DEV_MD |
110 | ---help--- | 110 | ---help--- |
111 | A RAID-5 set of N drives with a capacity of C MB per drive provides | 111 | A RAID-5 set of N drives with a capacity of C MB per drive provides |
@@ -116,20 +116,28 @@ config MD_RAID5 | |||
116 | while a RAID-5 set distributes the parity across the drives in one | 116 | while a RAID-5 set distributes the parity across the drives in one |
117 | of the available parity distribution methods. | 117 | of the available parity distribution methods. |
118 | 118 | ||
119 | A RAID-6 set of N drives with a capacity of C MB per drive | ||
120 | provides the capacity of C * (N - 2) MB, and protects | ||
121 | against a failure of any two drives. For a given sector | ||
122 | (row) number, (N - 2) drives contain data sectors, and two | ||
123 | drives contains two independent redundancy syndromes. Like | ||
124 | RAID-5, RAID-6 distributes the syndromes across the drives | ||
125 | in one of the available parity distribution methods. | ||
126 | |||
119 | Information about Software RAID on Linux is contained in the | 127 | Information about Software RAID on Linux is contained in the |
120 | Software-RAID mini-HOWTO, available from | 128 | Software-RAID mini-HOWTO, available from |
121 | <http://www.tldp.org/docs.html#howto>. There you will also | 129 | <http://www.tldp.org/docs.html#howto>. There you will also |
122 | learn where to get the supporting user space utilities raidtools. | 130 | learn where to get the supporting user space utilities raidtools. |
123 | 131 | ||
124 | If you want to use such a RAID-4/RAID-5 set, say Y. To | 132 | If you want to use such a RAID-4/RAID-5/RAID-6 set, say Y. To |
125 | compile this code as a module, choose M here: the module | 133 | compile this code as a module, choose M here: the module |
126 | will be called raid5. | 134 | will be called raid456. |
127 | 135 | ||
128 | If unsure, say Y. | 136 | If unsure, say Y. |
129 | 137 | ||
130 | config MD_RAID5_RESHAPE | 138 | config MD_RAID5_RESHAPE |
131 | bool "Support adding drives to a raid-5 array (experimental)" | 139 | bool "Support adding drives to a raid-5 array (experimental)" |
132 | depends on MD_RAID5 && EXPERIMENTAL | 140 | depends on MD_RAID456 && EXPERIMENTAL |
133 | ---help--- | 141 | ---help--- |
134 | A RAID-5 set can be expanded by adding extra drives. This | 142 | A RAID-5 set can be expanded by adding extra drives. This |
135 | requires "restriping" the array which means (almost) every | 143 | requires "restriping" the array which means (almost) every |
@@ -139,7 +147,7 @@ config MD_RAID5_RESHAPE | |||
139 | is online. However it is still EXPERIMENTAL code. It should | 147 | is online. However it is still EXPERIMENTAL code. It should |
140 | work, but please be sure that you have backups. | 148 | work, but please be sure that you have backups. |
141 | 149 | ||
142 | You will need mdadm verion 2.4.1 or later to use this | 150 | You will need mdadm version 2.4.1 or later to use this |
143 | feature safely. During the early stage of reshape there is | 151 | feature safely. During the early stage of reshape there is |
144 | a critical section where live data is being over-written. A | 152 | a critical section where live data is being over-written. A |
145 | crash during this time needs extra care for recovery. The | 153 | crash during this time needs extra care for recovery. The |
@@ -154,28 +162,6 @@ config MD_RAID5_RESHAPE | |||
154 | There should be enough spares already present to make the new | 162 | There should be enough spares already present to make the new |
155 | array workable. | 163 | array workable. |
156 | 164 | ||
157 | config MD_RAID6 | ||
158 | tristate "RAID-6 mode" | ||
159 | depends on BLK_DEV_MD | ||
160 | ---help--- | ||
161 | A RAID-6 set of N drives with a capacity of C MB per drive | ||
162 | provides the capacity of C * (N - 2) MB, and protects | ||
163 | against a failure of any two drives. For a given sector | ||
164 | (row) number, (N - 2) drives contain data sectors, and two | ||
165 | drives contains two independent redundancy syndromes. Like | ||
166 | RAID-5, RAID-6 distributes the syndromes across the drives | ||
167 | in one of the available parity distribution methods. | ||
168 | |||
169 | RAID-6 requires mdadm-1.5.0 or later, available at: | ||
170 | |||
171 | ftp://ftp.kernel.org/pub/linux/utils/raid/mdadm/ | ||
172 | |||
173 | If you want to use such a RAID-6 set, say Y. To compile | ||
174 | this code as a module, choose M here: the module will be | ||
175 | called raid6. | ||
176 | |||
177 | If unsure, say Y. | ||
178 | |||
179 | config MD_MULTIPATH | 165 | config MD_MULTIPATH |
180 | tristate "Multipath I/O support" | 166 | tristate "Multipath I/O support" |
181 | depends on BLK_DEV_MD | 167 | depends on BLK_DEV_MD |
@@ -235,7 +221,7 @@ config DM_SNAPSHOT | |||
235 | tristate "Snapshot target (EXPERIMENTAL)" | 221 | tristate "Snapshot target (EXPERIMENTAL)" |
236 | depends on BLK_DEV_DM && EXPERIMENTAL | 222 | depends on BLK_DEV_DM && EXPERIMENTAL |
237 | ---help--- | 223 | ---help--- |
238 | Allow volume managers to take writeable snapshots of a device. | 224 | Allow volume managers to take writable snapshots of a device. |
239 | 225 | ||
240 | config DM_MIRROR | 226 | config DM_MIRROR |
241 | tristate "Mirror target (EXPERIMENTAL)" | 227 | tristate "Mirror target (EXPERIMENTAL)" |
diff --git a/drivers/md/Makefile b/drivers/md/Makefile index d3efedf6a6ad..34957a68d921 100644 --- a/drivers/md/Makefile +++ b/drivers/md/Makefile | |||
@@ -8,7 +8,7 @@ dm-multipath-objs := dm-hw-handler.o dm-path-selector.o dm-mpath.o | |||
8 | dm-snapshot-objs := dm-snap.o dm-exception-store.o | 8 | dm-snapshot-objs := dm-snap.o dm-exception-store.o |
9 | dm-mirror-objs := dm-log.o dm-raid1.o | 9 | dm-mirror-objs := dm-log.o dm-raid1.o |
10 | md-mod-objs := md.o bitmap.o | 10 | md-mod-objs := md.o bitmap.o |
11 | raid6-objs := raid6main.o raid6algos.o raid6recov.o raid6tables.o \ | 11 | raid456-objs := raid5.o raid6algos.o raid6recov.o raid6tables.o \ |
12 | raid6int1.o raid6int2.o raid6int4.o \ | 12 | raid6int1.o raid6int2.o raid6int4.o \ |
13 | raid6int8.o raid6int16.o raid6int32.o \ | 13 | raid6int8.o raid6int16.o raid6int32.o \ |
14 | raid6altivec1.o raid6altivec2.o raid6altivec4.o \ | 14 | raid6altivec1.o raid6altivec2.o raid6altivec4.o \ |
@@ -25,8 +25,7 @@ obj-$(CONFIG_MD_LINEAR) += linear.o | |||
25 | obj-$(CONFIG_MD_RAID0) += raid0.o | 25 | obj-$(CONFIG_MD_RAID0) += raid0.o |
26 | obj-$(CONFIG_MD_RAID1) += raid1.o | 26 | obj-$(CONFIG_MD_RAID1) += raid1.o |
27 | obj-$(CONFIG_MD_RAID10) += raid10.o | 27 | obj-$(CONFIG_MD_RAID10) += raid10.o |
28 | obj-$(CONFIG_MD_RAID5) += raid5.o xor.o | 28 | obj-$(CONFIG_MD_RAID456) += raid456.o xor.o |
29 | obj-$(CONFIG_MD_RAID6) += raid6.o xor.o | ||
30 | obj-$(CONFIG_MD_MULTIPATH) += multipath.o | 29 | obj-$(CONFIG_MD_MULTIPATH) += multipath.o |
31 | obj-$(CONFIG_MD_FAULTY) += faulty.o | 30 | obj-$(CONFIG_MD_FAULTY) += faulty.o |
32 | obj-$(CONFIG_BLK_DEV_MD) += md-mod.o | 31 | obj-$(CONFIG_BLK_DEV_MD) += md-mod.o |
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index f8ffaee20ff8..ebbd2d856256 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c | |||
@@ -7,7 +7,6 @@ | |||
7 | * additions, Copyright (C) 2003-2004, Paul Clements, SteelEye Technology, Inc.: | 7 | * additions, Copyright (C) 2003-2004, Paul Clements, SteelEye Technology, Inc.: |
8 | * - added disk storage for bitmap | 8 | * - added disk storage for bitmap |
9 | * - changes to allow various bitmap chunk sizes | 9 | * - changes to allow various bitmap chunk sizes |
10 | * - added bitmap daemon (to asynchronously clear bitmap bits from disk) | ||
11 | */ | 10 | */ |
12 | 11 | ||
13 | /* | 12 | /* |
@@ -15,9 +14,6 @@ | |||
15 | * | 14 | * |
16 | * flush after percent set rather than just time based. (maybe both). | 15 | * flush after percent set rather than just time based. (maybe both). |
17 | * wait if count gets too high, wake when it drops to half. | 16 | * wait if count gets too high, wake when it drops to half. |
18 | * allow bitmap to be mirrored with superblock (before or after...) | ||
19 | * allow hot-add to re-instate a current device. | ||
20 | * allow hot-add of bitmap after quiessing device | ||
21 | */ | 17 | */ |
22 | 18 | ||
23 | #include <linux/module.h> | 19 | #include <linux/module.h> |
@@ -73,24 +69,6 @@ static inline char * bmname(struct bitmap *bitmap) | |||
73 | 69 | ||
74 | 70 | ||
75 | /* | 71 | /* |
76 | * test if the bitmap is active | ||
77 | */ | ||
78 | int bitmap_active(struct bitmap *bitmap) | ||
79 | { | ||
80 | unsigned long flags; | ||
81 | int res = 0; | ||
82 | |||
83 | if (!bitmap) | ||
84 | return res; | ||
85 | spin_lock_irqsave(&bitmap->lock, flags); | ||
86 | res = bitmap->flags & BITMAP_ACTIVE; | ||
87 | spin_unlock_irqrestore(&bitmap->lock, flags); | ||
88 | return res; | ||
89 | } | ||
90 | |||
91 | #define WRITE_POOL_SIZE 256 | ||
92 | |||
93 | /* | ||
94 | * just a placeholder - calls kmalloc for bitmap pages | 72 | * just a placeholder - calls kmalloc for bitmap pages |
95 | */ | 73 | */ |
96 | static unsigned char *bitmap_alloc_page(struct bitmap *bitmap) | 74 | static unsigned char *bitmap_alloc_page(struct bitmap *bitmap) |
@@ -269,6 +247,8 @@ static struct page *read_sb_page(mddev_t *mddev, long offset, unsigned long inde | |||
269 | 247 | ||
270 | if (sync_page_io(rdev->bdev, target, PAGE_SIZE, page, READ)) { | 248 | if (sync_page_io(rdev->bdev, target, PAGE_SIZE, page, READ)) { |
271 | page->index = index; | 249 | page->index = index; |
250 | attach_page_buffers(page, NULL); /* so that free_buffer will | ||
251 | * quietly no-op */ | ||
272 | return page; | 252 | return page; |
273 | } | 253 | } |
274 | } | 254 | } |
@@ -300,77 +280,132 @@ static int write_sb_page(mddev_t *mddev, long offset, struct page *page, int wai | |||
300 | */ | 280 | */ |
301 | static int write_page(struct bitmap *bitmap, struct page *page, int wait) | 281 | static int write_page(struct bitmap *bitmap, struct page *page, int wait) |
302 | { | 282 | { |
303 | int ret = -ENOMEM; | 283 | struct buffer_head *bh; |
304 | 284 | ||
305 | if (bitmap->file == NULL) | 285 | if (bitmap->file == NULL) |
306 | return write_sb_page(bitmap->mddev, bitmap->offset, page, wait); | 286 | return write_sb_page(bitmap->mddev, bitmap->offset, page, wait); |
307 | 287 | ||
308 | flush_dcache_page(page); /* make sure visible to anyone reading the file */ | 288 | bh = page_buffers(page); |
309 | 289 | ||
310 | if (wait) | 290 | while (bh && bh->b_blocknr) { |
311 | lock_page(page); | 291 | atomic_inc(&bitmap->pending_writes); |
312 | else { | 292 | set_buffer_locked(bh); |
313 | if (TestSetPageLocked(page)) | 293 | set_buffer_mapped(bh); |
314 | return -EAGAIN; /* already locked */ | 294 | submit_bh(WRITE, bh); |
315 | if (PageWriteback(page)) { | 295 | bh = bh->b_this_page; |
316 | unlock_page(page); | ||
317 | return -EAGAIN; | ||
318 | } | ||
319 | } | 296 | } |
320 | 297 | ||
321 | ret = page->mapping->a_ops->prepare_write(bitmap->file, page, 0, PAGE_SIZE); | 298 | if (wait) { |
322 | if (!ret) | 299 | wait_event(bitmap->write_wait, |
323 | ret = page->mapping->a_ops->commit_write(bitmap->file, page, 0, | 300 | atomic_read(&bitmap->pending_writes)==0); |
324 | PAGE_SIZE); | 301 | return (bitmap->flags & BITMAP_WRITE_ERROR) ? -EIO : 0; |
325 | if (ret) { | ||
326 | unlock_page(page); | ||
327 | return ret; | ||
328 | } | 302 | } |
303 | return 0; | ||
304 | } | ||
329 | 305 | ||
330 | set_page_dirty(page); /* force it to be written out */ | 306 | static void end_bitmap_write(struct buffer_head *bh, int uptodate) |
331 | 307 | { | |
332 | if (!wait) { | 308 | struct bitmap *bitmap = bh->b_private; |
333 | /* add to list to be waited for by daemon */ | 309 | unsigned long flags; |
334 | struct page_list *item = mempool_alloc(bitmap->write_pool, GFP_NOIO); | 310 | |
335 | item->page = page; | 311 | if (!uptodate) { |
336 | get_page(page); | 312 | spin_lock_irqsave(&bitmap->lock, flags); |
337 | spin_lock(&bitmap->write_lock); | 313 | bitmap->flags |= BITMAP_WRITE_ERROR; |
338 | list_add(&item->list, &bitmap->complete_pages); | 314 | spin_unlock_irqrestore(&bitmap->lock, flags); |
339 | spin_unlock(&bitmap->write_lock); | 315 | } |
340 | md_wakeup_thread(bitmap->writeback_daemon); | 316 | if (atomic_dec_and_test(&bitmap->pending_writes)) |
317 | wake_up(&bitmap->write_wait); | ||
318 | } | ||
319 | |||
320 | /* copied from buffer.c */ | ||
321 | static void | ||
322 | __clear_page_buffers(struct page *page) | ||
323 | { | ||
324 | ClearPagePrivate(page); | ||
325 | set_page_private(page, 0); | ||
326 | page_cache_release(page); | ||
327 | } | ||
328 | static void free_buffers(struct page *page) | ||
329 | { | ||
330 | struct buffer_head *bh = page_buffers(page); | ||
331 | |||
332 | while (bh) { | ||
333 | struct buffer_head *next = bh->b_this_page; | ||
334 | free_buffer_head(bh); | ||
335 | bh = next; | ||
341 | } | 336 | } |
342 | return write_one_page(page, wait); | 337 | __clear_page_buffers(page); |
338 | put_page(page); | ||
343 | } | 339 | } |
344 | 340 | ||
345 | /* read a page from a file, pinning it into cache, and return bytes_read */ | 341 | /* read a page from a file. |
342 | * We both read the page, and attach buffers to the page to record the | ||
343 | * address of each block (using bmap). These addresses will be used | ||
344 | * to write the block later, completely bypassing the filesystem. | ||
345 | * This usage is similar to how swap files are handled, and allows us | ||
346 | * to write to a file with no concerns of memory allocation failing. | ||
347 | */ | ||
346 | static struct page *read_page(struct file *file, unsigned long index, | 348 | static struct page *read_page(struct file *file, unsigned long index, |
347 | unsigned long *bytes_read) | 349 | struct bitmap *bitmap, |
350 | unsigned long count) | ||
348 | { | 351 | { |
349 | struct inode *inode = file->f_mapping->host; | ||
350 | struct page *page = NULL; | 352 | struct page *page = NULL; |
351 | loff_t isize = i_size_read(inode); | 353 | struct inode *inode = file->f_dentry->d_inode; |
352 | unsigned long end_index = isize >> PAGE_SHIFT; | 354 | struct buffer_head *bh; |
355 | sector_t block; | ||
353 | 356 | ||
354 | PRINTK("read bitmap file (%dB @ %Lu)\n", (int)PAGE_SIZE, | 357 | PRINTK("read bitmap file (%dB @ %Lu)\n", (int)PAGE_SIZE, |
355 | (unsigned long long)index << PAGE_SHIFT); | 358 | (unsigned long long)index << PAGE_SHIFT); |
356 | 359 | ||
357 | page = read_cache_page(inode->i_mapping, index, | 360 | page = alloc_page(GFP_KERNEL); |
358 | (filler_t *)inode->i_mapping->a_ops->readpage, file); | 361 | if (!page) |
362 | page = ERR_PTR(-ENOMEM); | ||
359 | if (IS_ERR(page)) | 363 | if (IS_ERR(page)) |
360 | goto out; | 364 | goto out; |
361 | wait_on_page_locked(page); | 365 | |
362 | if (!PageUptodate(page) || PageError(page)) { | 366 | bh = alloc_page_buffers(page, 1<<inode->i_blkbits, 0); |
367 | if (!bh) { | ||
363 | put_page(page); | 368 | put_page(page); |
364 | page = ERR_PTR(-EIO); | 369 | page = ERR_PTR(-ENOMEM); |
365 | goto out; | 370 | goto out; |
366 | } | 371 | } |
372 | attach_page_buffers(page, bh); | ||
373 | block = index << (PAGE_SHIFT - inode->i_blkbits); | ||
374 | while (bh) { | ||
375 | if (count == 0) | ||
376 | bh->b_blocknr = 0; | ||
377 | else { | ||
378 | bh->b_blocknr = bmap(inode, block); | ||
379 | if (bh->b_blocknr == 0) { | ||
380 | /* Cannot use this file! */ | ||
381 | free_buffers(page); | ||
382 | page = ERR_PTR(-EINVAL); | ||
383 | goto out; | ||
384 | } | ||
385 | bh->b_bdev = inode->i_sb->s_bdev; | ||
386 | if (count < (1<<inode->i_blkbits)) | ||
387 | count = 0; | ||
388 | else | ||
389 | count -= (1<<inode->i_blkbits); | ||
390 | |||
391 | bh->b_end_io = end_bitmap_write; | ||
392 | bh->b_private = bitmap; | ||
393 | atomic_inc(&bitmap->pending_writes); | ||
394 | set_buffer_locked(bh); | ||
395 | set_buffer_mapped(bh); | ||
396 | submit_bh(READ, bh); | ||
397 | } | ||
398 | block++; | ||
399 | bh = bh->b_this_page; | ||
400 | } | ||
401 | page->index = index; | ||
367 | 402 | ||
368 | if (index > end_index) /* we have read beyond EOF */ | 403 | wait_event(bitmap->write_wait, |
369 | *bytes_read = 0; | 404 | atomic_read(&bitmap->pending_writes)==0); |
370 | else if (index == end_index) /* possible short read */ | 405 | if (bitmap->flags & BITMAP_WRITE_ERROR) { |
371 | *bytes_read = isize & ~PAGE_MASK; | 406 | free_buffers(page); |
372 | else | 407 | page = ERR_PTR(-EIO); |
373 | *bytes_read = PAGE_SIZE; /* got a full page */ | 408 | } |
374 | out: | 409 | out: |
375 | if (IS_ERR(page)) | 410 | if (IS_ERR(page)) |
376 | printk(KERN_ALERT "md: bitmap read error: (%dB @ %Lu): %ld\n", | 411 | printk(KERN_ALERT "md: bitmap read error: (%dB @ %Lu): %ld\n", |
@@ -441,16 +476,14 @@ static int bitmap_read_sb(struct bitmap *bitmap) | |||
441 | char *reason = NULL; | 476 | char *reason = NULL; |
442 | bitmap_super_t *sb; | 477 | bitmap_super_t *sb; |
443 | unsigned long chunksize, daemon_sleep, write_behind; | 478 | unsigned long chunksize, daemon_sleep, write_behind; |
444 | unsigned long bytes_read; | ||
445 | unsigned long long events; | 479 | unsigned long long events; |
446 | int err = -EINVAL; | 480 | int err = -EINVAL; |
447 | 481 | ||
448 | /* page 0 is the superblock, read it... */ | 482 | /* page 0 is the superblock, read it... */ |
449 | if (bitmap->file) | 483 | if (bitmap->file) |
450 | bitmap->sb_page = read_page(bitmap->file, 0, &bytes_read); | 484 | bitmap->sb_page = read_page(bitmap->file, 0, bitmap, PAGE_SIZE); |
451 | else { | 485 | else { |
452 | bitmap->sb_page = read_sb_page(bitmap->mddev, bitmap->offset, 0); | 486 | bitmap->sb_page = read_sb_page(bitmap->mddev, bitmap->offset, 0); |
453 | bytes_read = PAGE_SIZE; | ||
454 | } | 487 | } |
455 | if (IS_ERR(bitmap->sb_page)) { | 488 | if (IS_ERR(bitmap->sb_page)) { |
456 | err = PTR_ERR(bitmap->sb_page); | 489 | err = PTR_ERR(bitmap->sb_page); |
@@ -460,13 +493,6 @@ static int bitmap_read_sb(struct bitmap *bitmap) | |||
460 | 493 | ||
461 | sb = (bitmap_super_t *)kmap_atomic(bitmap->sb_page, KM_USER0); | 494 | sb = (bitmap_super_t *)kmap_atomic(bitmap->sb_page, KM_USER0); |
462 | 495 | ||
463 | if (bytes_read < sizeof(*sb)) { /* short read */ | ||
464 | printk(KERN_INFO "%s: bitmap file superblock truncated\n", | ||
465 | bmname(bitmap)); | ||
466 | err = -ENOSPC; | ||
467 | goto out; | ||
468 | } | ||
469 | |||
470 | chunksize = le32_to_cpu(sb->chunksize); | 496 | chunksize = le32_to_cpu(sb->chunksize); |
471 | daemon_sleep = le32_to_cpu(sb->daemon_sleep); | 497 | daemon_sleep = le32_to_cpu(sb->daemon_sleep); |
472 | write_behind = le32_to_cpu(sb->write_behind); | 498 | write_behind = le32_to_cpu(sb->write_behind); |
@@ -550,7 +576,6 @@ static void bitmap_mask_state(struct bitmap *bitmap, enum bitmap_state bits, | |||
550 | spin_unlock_irqrestore(&bitmap->lock, flags); | 576 | spin_unlock_irqrestore(&bitmap->lock, flags); |
551 | return; | 577 | return; |
552 | } | 578 | } |
553 | get_page(bitmap->sb_page); | ||
554 | spin_unlock_irqrestore(&bitmap->lock, flags); | 579 | spin_unlock_irqrestore(&bitmap->lock, flags); |
555 | sb = (bitmap_super_t *)kmap_atomic(bitmap->sb_page, KM_USER0); | 580 | sb = (bitmap_super_t *)kmap_atomic(bitmap->sb_page, KM_USER0); |
556 | switch (op) { | 581 | switch (op) { |
@@ -561,7 +586,6 @@ static void bitmap_mask_state(struct bitmap *bitmap, enum bitmap_state bits, | |||
561 | default: BUG(); | 586 | default: BUG(); |
562 | } | 587 | } |
563 | kunmap_atomic(sb, KM_USER0); | 588 | kunmap_atomic(sb, KM_USER0); |
564 | put_page(bitmap->sb_page); | ||
565 | } | 589 | } |
566 | 590 | ||
567 | /* | 591 | /* |
@@ -614,48 +638,17 @@ static void bitmap_file_unmap(struct bitmap *bitmap) | |||
614 | 638 | ||
615 | while (pages--) | 639 | while (pages--) |
616 | if (map[pages]->index != 0) /* 0 is sb_page, release it below */ | 640 | if (map[pages]->index != 0) /* 0 is sb_page, release it below */ |
617 | put_page(map[pages]); | 641 | free_buffers(map[pages]); |
618 | kfree(map); | 642 | kfree(map); |
619 | kfree(attr); | 643 | kfree(attr); |
620 | 644 | ||
621 | safe_put_page(sb_page); | 645 | if (sb_page) |
622 | } | 646 | free_buffers(sb_page); |
623 | |||
624 | static void bitmap_stop_daemon(struct bitmap *bitmap); | ||
625 | |||
626 | /* dequeue the next item in a page list -- don't call from irq context */ | ||
627 | static struct page_list *dequeue_page(struct bitmap *bitmap) | ||
628 | { | ||
629 | struct page_list *item = NULL; | ||
630 | struct list_head *head = &bitmap->complete_pages; | ||
631 | |||
632 | spin_lock(&bitmap->write_lock); | ||
633 | if (list_empty(head)) | ||
634 | goto out; | ||
635 | item = list_entry(head->prev, struct page_list, list); | ||
636 | list_del(head->prev); | ||
637 | out: | ||
638 | spin_unlock(&bitmap->write_lock); | ||
639 | return item; | ||
640 | } | ||
641 | |||
642 | static void drain_write_queues(struct bitmap *bitmap) | ||
643 | { | ||
644 | struct page_list *item; | ||
645 | |||
646 | while ((item = dequeue_page(bitmap))) { | ||
647 | /* don't bother to wait */ | ||
648 | put_page(item->page); | ||
649 | mempool_free(item, bitmap->write_pool); | ||
650 | } | ||
651 | |||
652 | wake_up(&bitmap->write_wait); | ||
653 | } | 647 | } |
654 | 648 | ||
655 | static void bitmap_file_put(struct bitmap *bitmap) | 649 | static void bitmap_file_put(struct bitmap *bitmap) |
656 | { | 650 | { |
657 | struct file *file; | 651 | struct file *file; |
658 | struct inode *inode; | ||
659 | unsigned long flags; | 652 | unsigned long flags; |
660 | 653 | ||
661 | spin_lock_irqsave(&bitmap->lock, flags); | 654 | spin_lock_irqsave(&bitmap->lock, flags); |
@@ -663,17 +656,14 @@ static void bitmap_file_put(struct bitmap *bitmap) | |||
663 | bitmap->file = NULL; | 656 | bitmap->file = NULL; |
664 | spin_unlock_irqrestore(&bitmap->lock, flags); | 657 | spin_unlock_irqrestore(&bitmap->lock, flags); |
665 | 658 | ||
666 | bitmap_stop_daemon(bitmap); | 659 | if (file) |
667 | 660 | wait_event(bitmap->write_wait, | |
668 | drain_write_queues(bitmap); | 661 | atomic_read(&bitmap->pending_writes)==0); |
669 | |||
670 | bitmap_file_unmap(bitmap); | 662 | bitmap_file_unmap(bitmap); |
671 | 663 | ||
672 | if (file) { | 664 | if (file) { |
673 | inode = file->f_mapping->host; | 665 | struct inode *inode = file->f_dentry->d_inode; |
674 | spin_lock(&inode->i_lock); | 666 | invalidate_inode_pages(inode->i_mapping); |
675 | atomic_set(&inode->i_writecount, 1); /* allow writes again */ | ||
676 | spin_unlock(&inode->i_lock); | ||
677 | fput(file); | 667 | fput(file); |
678 | } | 668 | } |
679 | } | 669 | } |
@@ -708,26 +698,27 @@ static void bitmap_file_kick(struct bitmap *bitmap) | |||
708 | } | 698 | } |
709 | 699 | ||
710 | enum bitmap_page_attr { | 700 | enum bitmap_page_attr { |
711 | BITMAP_PAGE_DIRTY = 1, // there are set bits that need to be synced | 701 | BITMAP_PAGE_DIRTY = 0, // there are set bits that need to be synced |
712 | BITMAP_PAGE_CLEAN = 2, // there are bits that might need to be cleared | 702 | BITMAP_PAGE_CLEAN = 1, // there are bits that might need to be cleared |
713 | BITMAP_PAGE_NEEDWRITE=4, // there are cleared bits that need to be synced | 703 | BITMAP_PAGE_NEEDWRITE=2, // there are cleared bits that need to be synced |
714 | }; | 704 | }; |
715 | 705 | ||
716 | static inline void set_page_attr(struct bitmap *bitmap, struct page *page, | 706 | static inline void set_page_attr(struct bitmap *bitmap, struct page *page, |
717 | enum bitmap_page_attr attr) | 707 | enum bitmap_page_attr attr) |
718 | { | 708 | { |
719 | bitmap->filemap_attr[page->index] |= attr; | 709 | __set_bit((page->index<<2) + attr, bitmap->filemap_attr); |
720 | } | 710 | } |
721 | 711 | ||
722 | static inline void clear_page_attr(struct bitmap *bitmap, struct page *page, | 712 | static inline void clear_page_attr(struct bitmap *bitmap, struct page *page, |
723 | enum bitmap_page_attr attr) | 713 | enum bitmap_page_attr attr) |
724 | { | 714 | { |
725 | bitmap->filemap_attr[page->index] &= ~attr; | 715 | __clear_bit((page->index<<2) + attr, bitmap->filemap_attr); |
726 | } | 716 | } |
727 | 717 | ||
728 | static inline unsigned long get_page_attr(struct bitmap *bitmap, struct page *page) | 718 | static inline unsigned long test_page_attr(struct bitmap *bitmap, struct page *page, |
719 | enum bitmap_page_attr attr) | ||
729 | { | 720 | { |
730 | return bitmap->filemap_attr[page->index]; | 721 | return test_bit((page->index<<2) + attr, bitmap->filemap_attr); |
731 | } | 722 | } |
732 | 723 | ||
733 | /* | 724 | /* |
@@ -751,11 +742,6 @@ static void bitmap_file_set_bit(struct bitmap *bitmap, sector_t block) | |||
751 | page = filemap_get_page(bitmap, chunk); | 742 | page = filemap_get_page(bitmap, chunk); |
752 | bit = file_page_offset(chunk); | 743 | bit = file_page_offset(chunk); |
753 | 744 | ||
754 | |||
755 | /* make sure the page stays cached until it gets written out */ | ||
756 | if (! (get_page_attr(bitmap, page) & BITMAP_PAGE_DIRTY)) | ||
757 | get_page(page); | ||
758 | |||
759 | /* set the bit */ | 745 | /* set the bit */ |
760 | kaddr = kmap_atomic(page, KM_USER0); | 746 | kaddr = kmap_atomic(page, KM_USER0); |
761 | if (bitmap->flags & BITMAP_HOSTENDIAN) | 747 | if (bitmap->flags & BITMAP_HOSTENDIAN) |
@@ -775,7 +761,8 @@ static void bitmap_file_set_bit(struct bitmap *bitmap, sector_t block) | |||
775 | * sync the dirty pages of the bitmap file to disk */ | 761 | * sync the dirty pages of the bitmap file to disk */ |
776 | int bitmap_unplug(struct bitmap *bitmap) | 762 | int bitmap_unplug(struct bitmap *bitmap) |
777 | { | 763 | { |
778 | unsigned long i, attr, flags; | 764 | unsigned long i, flags; |
765 | int dirty, need_write; | ||
779 | struct page *page; | 766 | struct page *page; |
780 | int wait = 0; | 767 | int wait = 0; |
781 | int err; | 768 | int err; |
@@ -792,35 +779,26 @@ int bitmap_unplug(struct bitmap *bitmap) | |||
792 | return 0; | 779 | return 0; |
793 | } | 780 | } |
794 | page = bitmap->filemap[i]; | 781 | page = bitmap->filemap[i]; |
795 | attr = get_page_attr(bitmap, page); | 782 | dirty = test_page_attr(bitmap, page, BITMAP_PAGE_DIRTY); |
783 | need_write = test_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE); | ||
796 | clear_page_attr(bitmap, page, BITMAP_PAGE_DIRTY); | 784 | clear_page_attr(bitmap, page, BITMAP_PAGE_DIRTY); |
797 | clear_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE); | 785 | clear_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE); |
798 | if ((attr & BITMAP_PAGE_DIRTY)) | 786 | if (dirty) |
799 | wait = 1; | 787 | wait = 1; |
800 | spin_unlock_irqrestore(&bitmap->lock, flags); | 788 | spin_unlock_irqrestore(&bitmap->lock, flags); |
801 | 789 | ||
802 | if (attr & (BITMAP_PAGE_DIRTY | BITMAP_PAGE_NEEDWRITE)) { | 790 | if (dirty | need_write) |
803 | err = write_page(bitmap, page, 0); | 791 | err = write_page(bitmap, page, 0); |
804 | if (err == -EAGAIN) { | ||
805 | if (attr & BITMAP_PAGE_DIRTY) | ||
806 | err = write_page(bitmap, page, 1); | ||
807 | else | ||
808 | err = 0; | ||
809 | } | ||
810 | if (err) | ||
811 | return 1; | ||
812 | } | ||
813 | } | 792 | } |
814 | if (wait) { /* if any writes were performed, we need to wait on them */ | 793 | if (wait) { /* if any writes were performed, we need to wait on them */ |
815 | if (bitmap->file) { | 794 | if (bitmap->file) |
816 | spin_lock_irq(&bitmap->write_lock); | 795 | wait_event(bitmap->write_wait, |
817 | wait_event_lock_irq(bitmap->write_wait, | 796 | atomic_read(&bitmap->pending_writes)==0); |
818 | list_empty(&bitmap->complete_pages), bitmap->write_lock, | 797 | else |
819 | wake_up_process(bitmap->writeback_daemon->tsk)); | ||
820 | spin_unlock_irq(&bitmap->write_lock); | ||
821 | } else | ||
822 | md_super_wait(bitmap->mddev); | 798 | md_super_wait(bitmap->mddev); |
823 | } | 799 | } |
800 | if (bitmap->flags & BITMAP_WRITE_ERROR) | ||
801 | bitmap_file_kick(bitmap); | ||
824 | return 0; | 802 | return 0; |
825 | } | 803 | } |
826 | 804 | ||
@@ -842,7 +820,7 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start) | |||
842 | struct page *page = NULL, *oldpage = NULL; | 820 | struct page *page = NULL, *oldpage = NULL; |
843 | unsigned long num_pages, bit_cnt = 0; | 821 | unsigned long num_pages, bit_cnt = 0; |
844 | struct file *file; | 822 | struct file *file; |
845 | unsigned long bytes, offset, dummy; | 823 | unsigned long bytes, offset; |
846 | int outofdate; | 824 | int outofdate; |
847 | int ret = -ENOSPC; | 825 | int ret = -ENOSPC; |
848 | void *paddr; | 826 | void *paddr; |
@@ -879,7 +857,12 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start) | |||
879 | if (!bitmap->filemap) | 857 | if (!bitmap->filemap) |
880 | goto out; | 858 | goto out; |
881 | 859 | ||
882 | bitmap->filemap_attr = kzalloc(sizeof(long) * num_pages, GFP_KERNEL); | 860 | /* We need 4 bits per page, rounded up to a multiple of sizeof(unsigned long) */ |
861 | bitmap->filemap_attr = kzalloc( | ||
862 | (((num_pages*4/8)+sizeof(unsigned long)-1) | ||
863 | /sizeof(unsigned long)) | ||
864 | *sizeof(unsigned long), | ||
865 | GFP_KERNEL); | ||
883 | if (!bitmap->filemap_attr) | 866 | if (!bitmap->filemap_attr) |
884 | goto out; | 867 | goto out; |
885 | 868 | ||
@@ -890,7 +873,12 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start) | |||
890 | index = file_page_index(i); | 873 | index = file_page_index(i); |
891 | bit = file_page_offset(i); | 874 | bit = file_page_offset(i); |
892 | if (index != oldindex) { /* this is a new page, read it in */ | 875 | if (index != oldindex) { /* this is a new page, read it in */ |
876 | int count; | ||
893 | /* unmap the old page, we're done with it */ | 877 | /* unmap the old page, we're done with it */ |
878 | if (index == num_pages-1) | ||
879 | count = bytes - index * PAGE_SIZE; | ||
880 | else | ||
881 | count = PAGE_SIZE; | ||
894 | if (index == 0) { | 882 | if (index == 0) { |
895 | /* | 883 | /* |
896 | * if we're here then the superblock page | 884 | * if we're here then the superblock page |
@@ -900,7 +888,7 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start) | |||
900 | page = bitmap->sb_page; | 888 | page = bitmap->sb_page; |
901 | offset = sizeof(bitmap_super_t); | 889 | offset = sizeof(bitmap_super_t); |
902 | } else if (file) { | 890 | } else if (file) { |
903 | page = read_page(file, index, &dummy); | 891 | page = read_page(file, index, bitmap, count); |
904 | offset = 0; | 892 | offset = 0; |
905 | } else { | 893 | } else { |
906 | page = read_sb_page(bitmap->mddev, bitmap->offset, index); | 894 | page = read_sb_page(bitmap->mddev, bitmap->offset, index); |
@@ -971,12 +959,11 @@ void bitmap_write_all(struct bitmap *bitmap) | |||
971 | /* We don't actually write all bitmap blocks here, | 959 | /* We don't actually write all bitmap blocks here, |
972 | * just flag them as needing to be written | 960 | * just flag them as needing to be written |
973 | */ | 961 | */ |
962 | int i; | ||
974 | 963 | ||
975 | unsigned long chunks = bitmap->chunks; | 964 | for (i=0; i < bitmap->file_pages; i++) |
976 | unsigned long bytes = (chunks+7)/8 + sizeof(bitmap_super_t); | 965 | set_page_attr(bitmap, bitmap->filemap[i], |
977 | unsigned long num_pages = (bytes + PAGE_SIZE-1) / PAGE_SIZE; | 966 | BITMAP_PAGE_NEEDWRITE); |
978 | while (num_pages--) | ||
979 | bitmap->filemap_attr[num_pages] |= BITMAP_PAGE_NEEDWRITE; | ||
980 | } | 967 | } |
981 | 968 | ||
982 | 969 | ||
@@ -1007,7 +994,6 @@ int bitmap_daemon_work(struct bitmap *bitmap) | |||
1007 | struct page *page = NULL, *lastpage = NULL; | 994 | struct page *page = NULL, *lastpage = NULL; |
1008 | int err = 0; | 995 | int err = 0; |
1009 | int blocks; | 996 | int blocks; |
1010 | int attr; | ||
1011 | void *paddr; | 997 | void *paddr; |
1012 | 998 | ||
1013 | if (bitmap == NULL) | 999 | if (bitmap == NULL) |
@@ -1029,43 +1015,34 @@ int bitmap_daemon_work(struct bitmap *bitmap) | |||
1029 | 1015 | ||
1030 | if (page != lastpage) { | 1016 | if (page != lastpage) { |
1031 | /* skip this page unless it's marked as needing cleaning */ | 1017 | /* skip this page unless it's marked as needing cleaning */ |
1032 | if (!((attr=get_page_attr(bitmap, page)) & BITMAP_PAGE_CLEAN)) { | 1018 | if (!test_page_attr(bitmap, page, BITMAP_PAGE_CLEAN)) { |
1033 | if (attr & BITMAP_PAGE_NEEDWRITE) { | 1019 | int need_write = test_page_attr(bitmap, page, |
1034 | get_page(page); | 1020 | BITMAP_PAGE_NEEDWRITE); |
1021 | if (need_write) | ||
1035 | clear_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE); | 1022 | clear_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE); |
1036 | } | 1023 | |
1037 | spin_unlock_irqrestore(&bitmap->lock, flags); | 1024 | spin_unlock_irqrestore(&bitmap->lock, flags); |
1038 | if (attr & BITMAP_PAGE_NEEDWRITE) { | 1025 | if (need_write) { |
1039 | switch (write_page(bitmap, page, 0)) { | 1026 | switch (write_page(bitmap, page, 0)) { |
1040 | case -EAGAIN: | ||
1041 | set_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE); | ||
1042 | break; | ||
1043 | case 0: | 1027 | case 0: |
1044 | break; | 1028 | break; |
1045 | default: | 1029 | default: |
1046 | bitmap_file_kick(bitmap); | 1030 | bitmap_file_kick(bitmap); |
1047 | } | 1031 | } |
1048 | put_page(page); | ||
1049 | } | 1032 | } |
1050 | continue; | 1033 | continue; |
1051 | } | 1034 | } |
1052 | 1035 | ||
1053 | /* grab the new page, sync and release the old */ | 1036 | /* grab the new page, sync and release the old */ |
1054 | get_page(page); | ||
1055 | if (lastpage != NULL) { | 1037 | if (lastpage != NULL) { |
1056 | if (get_page_attr(bitmap, lastpage) & BITMAP_PAGE_NEEDWRITE) { | 1038 | if (test_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE)) { |
1057 | clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); | 1039 | clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); |
1058 | spin_unlock_irqrestore(&bitmap->lock, flags); | 1040 | spin_unlock_irqrestore(&bitmap->lock, flags); |
1059 | err = write_page(bitmap, lastpage, 0); | 1041 | err = write_page(bitmap, lastpage, 0); |
1060 | if (err == -EAGAIN) { | ||
1061 | err = 0; | ||
1062 | set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); | ||
1063 | } | ||
1064 | } else { | 1042 | } else { |
1065 | set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); | 1043 | set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); |
1066 | spin_unlock_irqrestore(&bitmap->lock, flags); | 1044 | spin_unlock_irqrestore(&bitmap->lock, flags); |
1067 | } | 1045 | } |
1068 | put_page(lastpage); | ||
1069 | if (err) | 1046 | if (err) |
1070 | bitmap_file_kick(bitmap); | 1047 | bitmap_file_kick(bitmap); |
1071 | } else | 1048 | } else |
@@ -1107,131 +1084,19 @@ int bitmap_daemon_work(struct bitmap *bitmap) | |||
1107 | /* now sync the final page */ | 1084 | /* now sync the final page */ |
1108 | if (lastpage != NULL) { | 1085 | if (lastpage != NULL) { |
1109 | spin_lock_irqsave(&bitmap->lock, flags); | 1086 | spin_lock_irqsave(&bitmap->lock, flags); |
1110 | if (get_page_attr(bitmap, lastpage) &BITMAP_PAGE_NEEDWRITE) { | 1087 | if (test_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE)) { |
1111 | clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); | 1088 | clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); |
1112 | spin_unlock_irqrestore(&bitmap->lock, flags); | 1089 | spin_unlock_irqrestore(&bitmap->lock, flags); |
1113 | err = write_page(bitmap, lastpage, 0); | 1090 | err = write_page(bitmap, lastpage, 0); |
1114 | if (err == -EAGAIN) { | ||
1115 | set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); | ||
1116 | err = 0; | ||
1117 | } | ||
1118 | } else { | 1091 | } else { |
1119 | set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); | 1092 | set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); |
1120 | spin_unlock_irqrestore(&bitmap->lock, flags); | 1093 | spin_unlock_irqrestore(&bitmap->lock, flags); |
1121 | } | 1094 | } |
1122 | |||
1123 | put_page(lastpage); | ||
1124 | } | 1095 | } |
1125 | 1096 | ||
1126 | return err; | 1097 | return err; |
1127 | } | 1098 | } |
1128 | 1099 | ||
1129 | static void daemon_exit(struct bitmap *bitmap, mdk_thread_t **daemon) | ||
1130 | { | ||
1131 | mdk_thread_t *dmn; | ||
1132 | unsigned long flags; | ||
1133 | |||
1134 | /* if no one is waiting on us, we'll free the md thread struct | ||
1135 | * and exit, otherwise we let the waiter clean things up */ | ||
1136 | spin_lock_irqsave(&bitmap->lock, flags); | ||
1137 | if ((dmn = *daemon)) { /* no one is waiting, cleanup and exit */ | ||
1138 | *daemon = NULL; | ||
1139 | spin_unlock_irqrestore(&bitmap->lock, flags); | ||
1140 | kfree(dmn); | ||
1141 | complete_and_exit(NULL, 0); /* do_exit not exported */ | ||
1142 | } | ||
1143 | spin_unlock_irqrestore(&bitmap->lock, flags); | ||
1144 | } | ||
1145 | |||
1146 | static void bitmap_writeback_daemon(mddev_t *mddev) | ||
1147 | { | ||
1148 | struct bitmap *bitmap = mddev->bitmap; | ||
1149 | struct page *page; | ||
1150 | struct page_list *item; | ||
1151 | int err = 0; | ||
1152 | |||
1153 | if (signal_pending(current)) { | ||
1154 | printk(KERN_INFO | ||
1155 | "%s: bitmap writeback daemon got signal, exiting...\n", | ||
1156 | bmname(bitmap)); | ||
1157 | err = -EINTR; | ||
1158 | goto out; | ||
1159 | } | ||
1160 | if (bitmap == NULL) | ||
1161 | /* about to be stopped. */ | ||
1162 | return; | ||
1163 | |||
1164 | PRINTK("%s: bitmap writeback daemon woke up...\n", bmname(bitmap)); | ||
1165 | /* wait on bitmap page writebacks */ | ||
1166 | while ((item = dequeue_page(bitmap))) { | ||
1167 | page = item->page; | ||
1168 | mempool_free(item, bitmap->write_pool); | ||
1169 | PRINTK("wait on page writeback: %p\n", page); | ||
1170 | wait_on_page_writeback(page); | ||
1171 | PRINTK("finished page writeback: %p\n", page); | ||
1172 | |||
1173 | err = PageError(page); | ||
1174 | put_page(page); | ||
1175 | if (err) { | ||
1176 | printk(KERN_WARNING "%s: bitmap file writeback " | ||
1177 | "failed (page %lu): %d\n", | ||
1178 | bmname(bitmap), page->index, err); | ||
1179 | bitmap_file_kick(bitmap); | ||
1180 | goto out; | ||
1181 | } | ||
1182 | } | ||
1183 | out: | ||
1184 | wake_up(&bitmap->write_wait); | ||
1185 | if (err) { | ||
1186 | printk(KERN_INFO "%s: bitmap writeback daemon exiting (%d)\n", | ||
1187 | bmname(bitmap), err); | ||
1188 | daemon_exit(bitmap, &bitmap->writeback_daemon); | ||
1189 | } | ||
1190 | } | ||
1191 | |||
1192 | static mdk_thread_t *bitmap_start_daemon(struct bitmap *bitmap, | ||
1193 | void (*func)(mddev_t *), char *name) | ||
1194 | { | ||
1195 | mdk_thread_t *daemon; | ||
1196 | char namebuf[32]; | ||
1197 | |||
1198 | #ifdef INJECT_FATAL_FAULT_2 | ||
1199 | daemon = NULL; | ||
1200 | #else | ||
1201 | sprintf(namebuf, "%%s_%s", name); | ||
1202 | daemon = md_register_thread(func, bitmap->mddev, namebuf); | ||
1203 | #endif | ||
1204 | if (!daemon) { | ||
1205 | printk(KERN_ERR "%s: failed to start bitmap daemon\n", | ||
1206 | bmname(bitmap)); | ||
1207 | return ERR_PTR(-ECHILD); | ||
1208 | } | ||
1209 | |||
1210 | md_wakeup_thread(daemon); /* start it running */ | ||
1211 | |||
1212 | PRINTK("%s: %s daemon (pid %d) started...\n", | ||
1213 | bmname(bitmap), name, daemon->tsk->pid); | ||
1214 | |||
1215 | return daemon; | ||
1216 | } | ||
1217 | |||
1218 | static void bitmap_stop_daemon(struct bitmap *bitmap) | ||
1219 | { | ||
1220 | /* the daemon can't stop itself... it'll just exit instead... */ | ||
1221 | if (bitmap->writeback_daemon && ! IS_ERR(bitmap->writeback_daemon) && | ||
1222 | current->pid != bitmap->writeback_daemon->tsk->pid) { | ||
1223 | mdk_thread_t *daemon; | ||
1224 | unsigned long flags; | ||
1225 | |||
1226 | spin_lock_irqsave(&bitmap->lock, flags); | ||
1227 | daemon = bitmap->writeback_daemon; | ||
1228 | bitmap->writeback_daemon = NULL; | ||
1229 | spin_unlock_irqrestore(&bitmap->lock, flags); | ||
1230 | if (daemon && ! IS_ERR(daemon)) | ||
1231 | md_unregister_thread(daemon); /* destroy the thread */ | ||
1232 | } | ||
1233 | } | ||
1234 | |||
1235 | static bitmap_counter_t *bitmap_get_counter(struct bitmap *bitmap, | 1100 | static bitmap_counter_t *bitmap_get_counter(struct bitmap *bitmap, |
1236 | sector_t offset, int *blocks, | 1101 | sector_t offset, int *blocks, |
1237 | int create) | 1102 | int create) |
@@ -1500,8 +1365,6 @@ static void bitmap_free(struct bitmap *bitmap) | |||
1500 | 1365 | ||
1501 | /* free all allocated memory */ | 1366 | /* free all allocated memory */ |
1502 | 1367 | ||
1503 | mempool_destroy(bitmap->write_pool); | ||
1504 | |||
1505 | if (bp) /* deallocate the page memory */ | 1368 | if (bp) /* deallocate the page memory */ |
1506 | for (k = 0; k < pages; k++) | 1369 | for (k = 0; k < pages; k++) |
1507 | if (bp[k].map && !bp[k].hijacked) | 1370 | if (bp[k].map && !bp[k].hijacked) |
@@ -1549,20 +1412,20 @@ int bitmap_create(mddev_t *mddev) | |||
1549 | return -ENOMEM; | 1412 | return -ENOMEM; |
1550 | 1413 | ||
1551 | spin_lock_init(&bitmap->lock); | 1414 | spin_lock_init(&bitmap->lock); |
1552 | bitmap->mddev = mddev; | 1415 | atomic_set(&bitmap->pending_writes, 0); |
1553 | |||
1554 | spin_lock_init(&bitmap->write_lock); | ||
1555 | INIT_LIST_HEAD(&bitmap->complete_pages); | ||
1556 | init_waitqueue_head(&bitmap->write_wait); | 1416 | init_waitqueue_head(&bitmap->write_wait); |
1557 | bitmap->write_pool = mempool_create_kmalloc_pool(WRITE_POOL_SIZE, | 1417 | |
1558 | sizeof(struct page_list)); | 1418 | bitmap->mddev = mddev; |
1559 | err = -ENOMEM; | ||
1560 | if (!bitmap->write_pool) | ||
1561 | goto error; | ||
1562 | 1419 | ||
1563 | bitmap->file = file; | 1420 | bitmap->file = file; |
1564 | bitmap->offset = mddev->bitmap_offset; | 1421 | bitmap->offset = mddev->bitmap_offset; |
1565 | if (file) get_file(file); | 1422 | if (file) { |
1423 | get_file(file); | ||
1424 | do_sync_file_range(file, 0, LLONG_MAX, | ||
1425 | SYNC_FILE_RANGE_WAIT_BEFORE | | ||
1426 | SYNC_FILE_RANGE_WRITE | | ||
1427 | SYNC_FILE_RANGE_WAIT_AFTER); | ||
1428 | } | ||
1566 | /* read superblock from bitmap file (this sets bitmap->chunksize) */ | 1429 | /* read superblock from bitmap file (this sets bitmap->chunksize) */ |
1567 | err = bitmap_read_sb(bitmap); | 1430 | err = bitmap_read_sb(bitmap); |
1568 | if (err) | 1431 | if (err) |
@@ -1594,8 +1457,6 @@ int bitmap_create(mddev_t *mddev) | |||
1594 | if (!bitmap->bp) | 1457 | if (!bitmap->bp) |
1595 | goto error; | 1458 | goto error; |
1596 | 1459 | ||
1597 | bitmap->flags |= BITMAP_ACTIVE; | ||
1598 | |||
1599 | /* now that we have some pages available, initialize the in-memory | 1460 | /* now that we have some pages available, initialize the in-memory |
1600 | * bitmap from the on-disk bitmap */ | 1461 | * bitmap from the on-disk bitmap */ |
1601 | start = 0; | 1462 | start = 0; |
@@ -1613,15 +1474,6 @@ int bitmap_create(mddev_t *mddev) | |||
1613 | 1474 | ||
1614 | mddev->bitmap = bitmap; | 1475 | mddev->bitmap = bitmap; |
1615 | 1476 | ||
1616 | if (file) | ||
1617 | /* kick off the bitmap writeback daemon */ | ||
1618 | bitmap->writeback_daemon = | ||
1619 | bitmap_start_daemon(bitmap, | ||
1620 | bitmap_writeback_daemon, | ||
1621 | "bitmap_wb"); | ||
1622 | |||
1623 | if (IS_ERR(bitmap->writeback_daemon)) | ||
1624 | return PTR_ERR(bitmap->writeback_daemon); | ||
1625 | mddev->thread->timeout = bitmap->daemon_sleep * HZ; | 1477 | mddev->thread->timeout = bitmap->daemon_sleep * HZ; |
1626 | 1478 | ||
1627 | return bitmap_update_sb(bitmap); | 1479 | return bitmap_update_sb(bitmap); |
@@ -1638,4 +1490,3 @@ EXPORT_SYMBOL(bitmap_start_sync); | |||
1638 | EXPORT_SYMBOL(bitmap_end_sync); | 1490 | EXPORT_SYMBOL(bitmap_end_sync); |
1639 | EXPORT_SYMBOL(bitmap_unplug); | 1491 | EXPORT_SYMBOL(bitmap_unplug); |
1640 | EXPORT_SYMBOL(bitmap_close_sync); | 1492 | EXPORT_SYMBOL(bitmap_close_sync); |
1641 | EXPORT_SYMBOL(bitmap_daemon_work); | ||
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 61a590bb6241..6022ed12a795 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c | |||
@@ -20,7 +20,7 @@ | |||
20 | 20 | ||
21 | #include "dm.h" | 21 | #include "dm.h" |
22 | 22 | ||
23 | #define PFX "crypt: " | 23 | #define DM_MSG_PREFIX "crypt" |
24 | 24 | ||
25 | /* | 25 | /* |
26 | * per bio private data | 26 | * per bio private data |
@@ -125,19 +125,19 @@ static int crypt_iv_essiv_ctr(struct crypt_config *cc, struct dm_target *ti, | |||
125 | u8 *salt; | 125 | u8 *salt; |
126 | 126 | ||
127 | if (opts == NULL) { | 127 | if (opts == NULL) { |
128 | ti->error = PFX "Digest algorithm missing for ESSIV mode"; | 128 | ti->error = "Digest algorithm missing for ESSIV mode"; |
129 | return -EINVAL; | 129 | return -EINVAL; |
130 | } | 130 | } |
131 | 131 | ||
132 | /* Hash the cipher key with the given hash algorithm */ | 132 | /* Hash the cipher key with the given hash algorithm */ |
133 | hash_tfm = crypto_alloc_tfm(opts, CRYPTO_TFM_REQ_MAY_SLEEP); | 133 | hash_tfm = crypto_alloc_tfm(opts, CRYPTO_TFM_REQ_MAY_SLEEP); |
134 | if (hash_tfm == NULL) { | 134 | if (hash_tfm == NULL) { |
135 | ti->error = PFX "Error initializing ESSIV hash"; | 135 | ti->error = "Error initializing ESSIV hash"; |
136 | return -EINVAL; | 136 | return -EINVAL; |
137 | } | 137 | } |
138 | 138 | ||
139 | if (crypto_tfm_alg_type(hash_tfm) != CRYPTO_ALG_TYPE_DIGEST) { | 139 | if (crypto_tfm_alg_type(hash_tfm) != CRYPTO_ALG_TYPE_DIGEST) { |
140 | ti->error = PFX "Expected digest algorithm for ESSIV hash"; | 140 | ti->error = "Expected digest algorithm for ESSIV hash"; |
141 | crypto_free_tfm(hash_tfm); | 141 | crypto_free_tfm(hash_tfm); |
142 | return -EINVAL; | 142 | return -EINVAL; |
143 | } | 143 | } |
@@ -145,7 +145,7 @@ static int crypt_iv_essiv_ctr(struct crypt_config *cc, struct dm_target *ti, | |||
145 | saltsize = crypto_tfm_alg_digestsize(hash_tfm); | 145 | saltsize = crypto_tfm_alg_digestsize(hash_tfm); |
146 | salt = kmalloc(saltsize, GFP_KERNEL); | 146 | salt = kmalloc(saltsize, GFP_KERNEL); |
147 | if (salt == NULL) { | 147 | if (salt == NULL) { |
148 | ti->error = PFX "Error kmallocing salt storage in ESSIV"; | 148 | ti->error = "Error kmallocing salt storage in ESSIV"; |
149 | crypto_free_tfm(hash_tfm); | 149 | crypto_free_tfm(hash_tfm); |
150 | return -ENOMEM; | 150 | return -ENOMEM; |
151 | } | 151 | } |
@@ -159,20 +159,20 @@ static int crypt_iv_essiv_ctr(struct crypt_config *cc, struct dm_target *ti, | |||
159 | CRYPTO_TFM_MODE_ECB | | 159 | CRYPTO_TFM_MODE_ECB | |
160 | CRYPTO_TFM_REQ_MAY_SLEEP); | 160 | CRYPTO_TFM_REQ_MAY_SLEEP); |
161 | if (essiv_tfm == NULL) { | 161 | if (essiv_tfm == NULL) { |
162 | ti->error = PFX "Error allocating crypto tfm for ESSIV"; | 162 | ti->error = "Error allocating crypto tfm for ESSIV"; |
163 | kfree(salt); | 163 | kfree(salt); |
164 | return -EINVAL; | 164 | return -EINVAL; |
165 | } | 165 | } |
166 | if (crypto_tfm_alg_blocksize(essiv_tfm) | 166 | if (crypto_tfm_alg_blocksize(essiv_tfm) |
167 | != crypto_tfm_alg_ivsize(cc->tfm)) { | 167 | != crypto_tfm_alg_ivsize(cc->tfm)) { |
168 | ti->error = PFX "Block size of ESSIV cipher does " | 168 | ti->error = "Block size of ESSIV cipher does " |
169 | "not match IV size of block cipher"; | 169 | "not match IV size of block cipher"; |
170 | crypto_free_tfm(essiv_tfm); | 170 | crypto_free_tfm(essiv_tfm); |
171 | kfree(salt); | 171 | kfree(salt); |
172 | return -EINVAL; | 172 | return -EINVAL; |
173 | } | 173 | } |
174 | if (crypto_cipher_setkey(essiv_tfm, salt, saltsize) < 0) { | 174 | if (crypto_cipher_setkey(essiv_tfm, salt, saltsize) < 0) { |
175 | ti->error = PFX "Failed to set key for ESSIV cipher"; | 175 | ti->error = "Failed to set key for ESSIV cipher"; |
176 | crypto_free_tfm(essiv_tfm); | 176 | crypto_free_tfm(essiv_tfm); |
177 | kfree(salt); | 177 | kfree(salt); |
178 | return -EINVAL; | 178 | return -EINVAL; |
@@ -521,7 +521,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
521 | unsigned long long tmpll; | 521 | unsigned long long tmpll; |
522 | 522 | ||
523 | if (argc != 5) { | 523 | if (argc != 5) { |
524 | ti->error = PFX "Not enough arguments"; | 524 | ti->error = "Not enough arguments"; |
525 | return -EINVAL; | 525 | return -EINVAL; |
526 | } | 526 | } |
527 | 527 | ||
@@ -532,21 +532,21 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
532 | ivmode = strsep(&ivopts, ":"); | 532 | ivmode = strsep(&ivopts, ":"); |
533 | 533 | ||
534 | if (tmp) | 534 | if (tmp) |
535 | DMWARN(PFX "Unexpected additional cipher options"); | 535 | DMWARN("Unexpected additional cipher options"); |
536 | 536 | ||
537 | key_size = strlen(argv[1]) >> 1; | 537 | key_size = strlen(argv[1]) >> 1; |
538 | 538 | ||
539 | cc = kmalloc(sizeof(*cc) + key_size * sizeof(u8), GFP_KERNEL); | 539 | cc = kmalloc(sizeof(*cc) + key_size * sizeof(u8), GFP_KERNEL); |
540 | if (cc == NULL) { | 540 | if (cc == NULL) { |
541 | ti->error = | 541 | ti->error = |
542 | PFX "Cannot allocate transparent encryption context"; | 542 | "Cannot allocate transparent encryption context"; |
543 | return -ENOMEM; | 543 | return -ENOMEM; |
544 | } | 544 | } |
545 | 545 | ||
546 | cc->key_size = key_size; | 546 | cc->key_size = key_size; |
547 | if ((!key_size && strcmp(argv[1], "-") != 0) || | 547 | if ((!key_size && strcmp(argv[1], "-") != 0) || |
548 | (key_size && crypt_decode_key(cc->key, argv[1], key_size) < 0)) { | 548 | (key_size && crypt_decode_key(cc->key, argv[1], key_size) < 0)) { |
549 | ti->error = PFX "Error decoding key"; | 549 | ti->error = "Error decoding key"; |
550 | goto bad1; | 550 | goto bad1; |
551 | } | 551 | } |
552 | 552 | ||
@@ -562,22 +562,22 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
562 | else if (strcmp(chainmode, "ecb") == 0) | 562 | else if (strcmp(chainmode, "ecb") == 0) |
563 | crypto_flags = CRYPTO_TFM_MODE_ECB; | 563 | crypto_flags = CRYPTO_TFM_MODE_ECB; |
564 | else { | 564 | else { |
565 | ti->error = PFX "Unknown chaining mode"; | 565 | ti->error = "Unknown chaining mode"; |
566 | goto bad1; | 566 | goto bad1; |
567 | } | 567 | } |
568 | 568 | ||
569 | if (crypto_flags != CRYPTO_TFM_MODE_ECB && !ivmode) { | 569 | if (crypto_flags != CRYPTO_TFM_MODE_ECB && !ivmode) { |
570 | ti->error = PFX "This chaining mode requires an IV mechanism"; | 570 | ti->error = "This chaining mode requires an IV mechanism"; |
571 | goto bad1; | 571 | goto bad1; |
572 | } | 572 | } |
573 | 573 | ||
574 | tfm = crypto_alloc_tfm(cipher, crypto_flags | CRYPTO_TFM_REQ_MAY_SLEEP); | 574 | tfm = crypto_alloc_tfm(cipher, crypto_flags | CRYPTO_TFM_REQ_MAY_SLEEP); |
575 | if (!tfm) { | 575 | if (!tfm) { |
576 | ti->error = PFX "Error allocating crypto tfm"; | 576 | ti->error = "Error allocating crypto tfm"; |
577 | goto bad1; | 577 | goto bad1; |
578 | } | 578 | } |
579 | if (crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER) { | 579 | if (crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER) { |
580 | ti->error = PFX "Expected cipher algorithm"; | 580 | ti->error = "Expected cipher algorithm"; |
581 | goto bad2; | 581 | goto bad2; |
582 | } | 582 | } |
583 | 583 | ||
@@ -595,7 +595,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
595 | else if (strcmp(ivmode, "essiv") == 0) | 595 | else if (strcmp(ivmode, "essiv") == 0) |
596 | cc->iv_gen_ops = &crypt_iv_essiv_ops; | 596 | cc->iv_gen_ops = &crypt_iv_essiv_ops; |
597 | else { | 597 | else { |
598 | ti->error = PFX "Invalid IV mode"; | 598 | ti->error = "Invalid IV mode"; |
599 | goto bad2; | 599 | goto bad2; |
600 | } | 600 | } |
601 | 601 | ||
@@ -610,7 +610,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
610 | else { | 610 | else { |
611 | cc->iv_size = 0; | 611 | cc->iv_size = 0; |
612 | if (cc->iv_gen_ops) { | 612 | if (cc->iv_gen_ops) { |
613 | DMWARN(PFX "Selected cipher does not support IVs"); | 613 | DMWARN("Selected cipher does not support IVs"); |
614 | if (cc->iv_gen_ops->dtr) | 614 | if (cc->iv_gen_ops->dtr) |
615 | cc->iv_gen_ops->dtr(cc); | 615 | cc->iv_gen_ops->dtr(cc); |
616 | cc->iv_gen_ops = NULL; | 616 | cc->iv_gen_ops = NULL; |
@@ -619,36 +619,36 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
619 | 619 | ||
620 | cc->io_pool = mempool_create_slab_pool(MIN_IOS, _crypt_io_pool); | 620 | cc->io_pool = mempool_create_slab_pool(MIN_IOS, _crypt_io_pool); |
621 | if (!cc->io_pool) { | 621 | if (!cc->io_pool) { |
622 | ti->error = PFX "Cannot allocate crypt io mempool"; | 622 | ti->error = "Cannot allocate crypt io mempool"; |
623 | goto bad3; | 623 | goto bad3; |
624 | } | 624 | } |
625 | 625 | ||
626 | cc->page_pool = mempool_create_page_pool(MIN_POOL_PAGES, 0); | 626 | cc->page_pool = mempool_create_page_pool(MIN_POOL_PAGES, 0); |
627 | if (!cc->page_pool) { | 627 | if (!cc->page_pool) { |
628 | ti->error = PFX "Cannot allocate page mempool"; | 628 | ti->error = "Cannot allocate page mempool"; |
629 | goto bad4; | 629 | goto bad4; |
630 | } | 630 | } |
631 | 631 | ||
632 | if (tfm->crt_cipher.cit_setkey(tfm, cc->key, key_size) < 0) { | 632 | if (tfm->crt_cipher.cit_setkey(tfm, cc->key, key_size) < 0) { |
633 | ti->error = PFX "Error setting key"; | 633 | ti->error = "Error setting key"; |
634 | goto bad5; | 634 | goto bad5; |
635 | } | 635 | } |
636 | 636 | ||
637 | if (sscanf(argv[2], "%llu", &tmpll) != 1) { | 637 | if (sscanf(argv[2], "%llu", &tmpll) != 1) { |
638 | ti->error = PFX "Invalid iv_offset sector"; | 638 | ti->error = "Invalid iv_offset sector"; |
639 | goto bad5; | 639 | goto bad5; |
640 | } | 640 | } |
641 | cc->iv_offset = tmpll; | 641 | cc->iv_offset = tmpll; |
642 | 642 | ||
643 | if (sscanf(argv[4], "%llu", &tmpll) != 1) { | 643 | if (sscanf(argv[4], "%llu", &tmpll) != 1) { |
644 | ti->error = PFX "Invalid device sector"; | 644 | ti->error = "Invalid device sector"; |
645 | goto bad5; | 645 | goto bad5; |
646 | } | 646 | } |
647 | cc->start = tmpll; | 647 | cc->start = tmpll; |
648 | 648 | ||
649 | if (dm_get_device(ti, argv[3], cc->start, ti->len, | 649 | if (dm_get_device(ti, argv[3], cc->start, ti->len, |
650 | dm_table_get_mode(ti->table), &cc->dev)) { | 650 | dm_table_get_mode(ti->table), &cc->dev)) { |
651 | ti->error = PFX "Device lookup failed"; | 651 | ti->error = "Device lookup failed"; |
652 | goto bad5; | 652 | goto bad5; |
653 | } | 653 | } |
654 | 654 | ||
@@ -657,7 +657,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
657 | *(ivopts - 1) = ':'; | 657 | *(ivopts - 1) = ':'; |
658 | cc->iv_mode = kmalloc(strlen(ivmode) + 1, GFP_KERNEL); | 658 | cc->iv_mode = kmalloc(strlen(ivmode) + 1, GFP_KERNEL); |
659 | if (!cc->iv_mode) { | 659 | if (!cc->iv_mode) { |
660 | ti->error = PFX "Error kmallocing iv_mode string"; | 660 | ti->error = "Error kmallocing iv_mode string"; |
661 | goto bad5; | 661 | goto bad5; |
662 | } | 662 | } |
663 | strcpy(cc->iv_mode, ivmode); | 663 | strcpy(cc->iv_mode, ivmode); |
@@ -918,13 +918,13 @@ static int __init dm_crypt_init(void) | |||
918 | _kcryptd_workqueue = create_workqueue("kcryptd"); | 918 | _kcryptd_workqueue = create_workqueue("kcryptd"); |
919 | if (!_kcryptd_workqueue) { | 919 | if (!_kcryptd_workqueue) { |
920 | r = -ENOMEM; | 920 | r = -ENOMEM; |
921 | DMERR(PFX "couldn't create kcryptd"); | 921 | DMERR("couldn't create kcryptd"); |
922 | goto bad1; | 922 | goto bad1; |
923 | } | 923 | } |
924 | 924 | ||
925 | r = dm_register_target(&crypt_target); | 925 | r = dm_register_target(&crypt_target); |
926 | if (r < 0) { | 926 | if (r < 0) { |
927 | DMERR(PFX "register failed %d", r); | 927 | DMERR("register failed %d", r); |
928 | goto bad2; | 928 | goto bad2; |
929 | } | 929 | } |
930 | 930 | ||
@@ -942,7 +942,7 @@ static void __exit dm_crypt_exit(void) | |||
942 | int r = dm_unregister_target(&crypt_target); | 942 | int r = dm_unregister_target(&crypt_target); |
943 | 943 | ||
944 | if (r < 0) | 944 | if (r < 0) |
945 | DMERR(PFX "unregister failed %d", r); | 945 | DMERR("unregister failed %d", r); |
946 | 946 | ||
947 | destroy_workqueue(_kcryptd_workqueue); | 947 | destroy_workqueue(_kcryptd_workqueue); |
948 | kmem_cache_destroy(_crypt_io_pool); | 948 | kmem_cache_destroy(_crypt_io_pool); |
diff --git a/drivers/md/dm-emc.c b/drivers/md/dm-emc.c index c7067674dcb7..2a374ccb30dd 100644 --- a/drivers/md/dm-emc.c +++ b/drivers/md/dm-emc.c | |||
@@ -12,6 +12,8 @@ | |||
12 | #include <scsi/scsi.h> | 12 | #include <scsi/scsi.h> |
13 | #include <scsi/scsi_cmnd.h> | 13 | #include <scsi/scsi_cmnd.h> |
14 | 14 | ||
15 | #define DM_MSG_PREFIX "multipath emc" | ||
16 | |||
15 | struct emc_handler { | 17 | struct emc_handler { |
16 | spinlock_t lock; | 18 | spinlock_t lock; |
17 | 19 | ||
@@ -66,7 +68,7 @@ static struct bio *get_failover_bio(struct path *path, unsigned data_size) | |||
66 | 68 | ||
67 | bio = bio_alloc(GFP_ATOMIC, 1); | 69 | bio = bio_alloc(GFP_ATOMIC, 1); |
68 | if (!bio) { | 70 | if (!bio) { |
69 | DMERR("dm-emc: get_failover_bio: bio_alloc() failed."); | 71 | DMERR("get_failover_bio: bio_alloc() failed."); |
70 | return NULL; | 72 | return NULL; |
71 | } | 73 | } |
72 | 74 | ||
@@ -78,13 +80,13 @@ static struct bio *get_failover_bio(struct path *path, unsigned data_size) | |||
78 | 80 | ||
79 | page = alloc_page(GFP_ATOMIC); | 81 | page = alloc_page(GFP_ATOMIC); |
80 | if (!page) { | 82 | if (!page) { |
81 | DMERR("dm-emc: get_failover_bio: alloc_page() failed."); | 83 | DMERR("get_failover_bio: alloc_page() failed."); |
82 | bio_put(bio); | 84 | bio_put(bio); |
83 | return NULL; | 85 | return NULL; |
84 | } | 86 | } |
85 | 87 | ||
86 | if (bio_add_page(bio, page, data_size, 0) != data_size) { | 88 | if (bio_add_page(bio, page, data_size, 0) != data_size) { |
87 | DMERR("dm-emc: get_failover_bio: alloc_page() failed."); | 89 | DMERR("get_failover_bio: alloc_page() failed."); |
88 | __free_page(page); | 90 | __free_page(page); |
89 | bio_put(bio); | 91 | bio_put(bio); |
90 | return NULL; | 92 | return NULL; |
@@ -103,7 +105,7 @@ static struct request *get_failover_req(struct emc_handler *h, | |||
103 | /* FIXME: Figure out why it fails with GFP_ATOMIC. */ | 105 | /* FIXME: Figure out why it fails with GFP_ATOMIC. */ |
104 | rq = blk_get_request(q, WRITE, __GFP_WAIT); | 106 | rq = blk_get_request(q, WRITE, __GFP_WAIT); |
105 | if (!rq) { | 107 | if (!rq) { |
106 | DMERR("dm-emc: get_failover_req: blk_get_request failed"); | 108 | DMERR("get_failover_req: blk_get_request failed"); |
107 | return NULL; | 109 | return NULL; |
108 | } | 110 | } |
109 | 111 | ||
@@ -160,7 +162,7 @@ static struct request *emc_trespass_get(struct emc_handler *h, | |||
160 | 162 | ||
161 | bio = get_failover_bio(path, data_size); | 163 | bio = get_failover_bio(path, data_size); |
162 | if (!bio) { | 164 | if (!bio) { |
163 | DMERR("dm-emc: emc_trespass_get: no bio"); | 165 | DMERR("emc_trespass_get: no bio"); |
164 | return NULL; | 166 | return NULL; |
165 | } | 167 | } |
166 | 168 | ||
@@ -173,7 +175,7 @@ static struct request *emc_trespass_get(struct emc_handler *h, | |||
173 | /* get request for block layer packet command */ | 175 | /* get request for block layer packet command */ |
174 | rq = get_failover_req(h, bio, path); | 176 | rq = get_failover_req(h, bio, path); |
175 | if (!rq) { | 177 | if (!rq) { |
176 | DMERR("dm-emc: emc_trespass_get: no rq"); | 178 | DMERR("emc_trespass_get: no rq"); |
177 | free_bio(bio); | 179 | free_bio(bio); |
178 | return NULL; | 180 | return NULL; |
179 | } | 181 | } |
@@ -200,18 +202,18 @@ static void emc_pg_init(struct hw_handler *hwh, unsigned bypassed, | |||
200 | * initial state passed into us and then get an update here. | 202 | * initial state passed into us and then get an update here. |
201 | */ | 203 | */ |
202 | if (!q) { | 204 | if (!q) { |
203 | DMINFO("dm-emc: emc_pg_init: no queue"); | 205 | DMINFO("emc_pg_init: no queue"); |
204 | goto fail_path; | 206 | goto fail_path; |
205 | } | 207 | } |
206 | 208 | ||
207 | /* FIXME: The request should be pre-allocated. */ | 209 | /* FIXME: The request should be pre-allocated. */ |
208 | rq = emc_trespass_get(hwh->context, path); | 210 | rq = emc_trespass_get(hwh->context, path); |
209 | if (!rq) { | 211 | if (!rq) { |
210 | DMERR("dm-emc: emc_pg_init: no rq"); | 212 | DMERR("emc_pg_init: no rq"); |
211 | goto fail_path; | 213 | goto fail_path; |
212 | } | 214 | } |
213 | 215 | ||
214 | DMINFO("dm-emc: emc_pg_init: sending switch-over command"); | 216 | DMINFO("emc_pg_init: sending switch-over command"); |
215 | elv_add_request(q, rq, ELEVATOR_INSERT_FRONT, 1); | 217 | elv_add_request(q, rq, ELEVATOR_INSERT_FRONT, 1); |
216 | return; | 218 | return; |
217 | 219 | ||
@@ -241,18 +243,18 @@ static int emc_create(struct hw_handler *hwh, unsigned argc, char **argv) | |||
241 | hr = 0; | 243 | hr = 0; |
242 | short_trespass = 0; | 244 | short_trespass = 0; |
243 | } else if (argc != 2) { | 245 | } else if (argc != 2) { |
244 | DMWARN("dm-emc hwhandler: incorrect number of arguments"); | 246 | DMWARN("incorrect number of arguments"); |
245 | return -EINVAL; | 247 | return -EINVAL; |
246 | } else { | 248 | } else { |
247 | if ((sscanf(argv[0], "%u", &short_trespass) != 1) | 249 | if ((sscanf(argv[0], "%u", &short_trespass) != 1) |
248 | || (short_trespass > 1)) { | 250 | || (short_trespass > 1)) { |
249 | DMWARN("dm-emc: invalid trespass mode selected"); | 251 | DMWARN("invalid trespass mode selected"); |
250 | return -EINVAL; | 252 | return -EINVAL; |
251 | } | 253 | } |
252 | 254 | ||
253 | if ((sscanf(argv[1], "%u", &hr) != 1) | 255 | if ((sscanf(argv[1], "%u", &hr) != 1) |
254 | || (hr > 1)) { | 256 | || (hr > 1)) { |
255 | DMWARN("dm-emc: invalid honor reservation flag selected"); | 257 | DMWARN("invalid honor reservation flag selected"); |
256 | return -EINVAL; | 258 | return -EINVAL; |
257 | } | 259 | } |
258 | } | 260 | } |
@@ -264,14 +266,14 @@ static int emc_create(struct hw_handler *hwh, unsigned argc, char **argv) | |||
264 | hwh->context = h; | 266 | hwh->context = h; |
265 | 267 | ||
266 | if ((h->short_trespass = short_trespass)) | 268 | if ((h->short_trespass = short_trespass)) |
267 | DMWARN("dm-emc: short trespass command will be send"); | 269 | DMWARN("short trespass command will be send"); |
268 | else | 270 | else |
269 | DMWARN("dm-emc: long trespass command will be send"); | 271 | DMWARN("long trespass command will be send"); |
270 | 272 | ||
271 | if ((h->hr = hr)) | 273 | if ((h->hr = hr)) |
272 | DMWARN("dm-emc: honor reservation bit will be set"); | 274 | DMWARN("honor reservation bit will be set"); |
273 | else | 275 | else |
274 | DMWARN("dm-emc: honor reservation bit will not be set (default)"); | 276 | DMWARN("honor reservation bit will not be set (default)"); |
275 | 277 | ||
276 | return 0; | 278 | return 0; |
277 | } | 279 | } |
@@ -336,9 +338,9 @@ static int __init dm_emc_init(void) | |||
336 | int r = dm_register_hw_handler(&emc_hwh); | 338 | int r = dm_register_hw_handler(&emc_hwh); |
337 | 339 | ||
338 | if (r < 0) | 340 | if (r < 0) |
339 | DMERR("emc: register failed %d", r); | 341 | DMERR("register failed %d", r); |
340 | 342 | ||
341 | DMINFO("dm-emc version 0.0.3 loaded"); | 343 | DMINFO("version 0.0.3 loaded"); |
342 | 344 | ||
343 | return r; | 345 | return r; |
344 | } | 346 | } |
@@ -348,7 +350,7 @@ static void __exit dm_emc_exit(void) | |||
348 | int r = dm_unregister_hw_handler(&emc_hwh); | 350 | int r = dm_unregister_hw_handler(&emc_hwh); |
349 | 351 | ||
350 | if (r < 0) | 352 | if (r < 0) |
351 | DMERR("emc: unregister failed %d", r); | 353 | DMERR("unregister failed %d", r); |
352 | } | 354 | } |
353 | 355 | ||
354 | module_init(dm_emc_init); | 356 | module_init(dm_emc_init); |
diff --git a/drivers/md/dm-exception-store.c b/drivers/md/dm-exception-store.c index cc07bbebbb16..d12379b5cdb5 100644 --- a/drivers/md/dm-exception-store.c +++ b/drivers/md/dm-exception-store.c | |||
@@ -16,6 +16,8 @@ | |||
16 | #include <linux/vmalloc.h> | 16 | #include <linux/vmalloc.h> |
17 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
18 | 18 | ||
19 | #define DM_MSG_PREFIX "snapshots" | ||
20 | |||
19 | /*----------------------------------------------------------------- | 21 | /*----------------------------------------------------------------- |
20 | * Persistent snapshots, by persistent we mean that the snapshot | 22 | * Persistent snapshots, by persistent we mean that the snapshot |
21 | * will survive a reboot. | 23 | * will survive a reboot. |
@@ -91,7 +93,6 @@ struct pstore { | |||
91 | struct dm_snapshot *snap; /* up pointer to my snapshot */ | 93 | struct dm_snapshot *snap; /* up pointer to my snapshot */ |
92 | int version; | 94 | int version; |
93 | int valid; | 95 | int valid; |
94 | uint32_t chunk_size; | ||
95 | uint32_t exceptions_per_area; | 96 | uint32_t exceptions_per_area; |
96 | 97 | ||
97 | /* | 98 | /* |
@@ -133,7 +134,7 @@ static int alloc_area(struct pstore *ps) | |||
133 | int r = -ENOMEM; | 134 | int r = -ENOMEM; |
134 | size_t len; | 135 | size_t len; |
135 | 136 | ||
136 | len = ps->chunk_size << SECTOR_SHIFT; | 137 | len = ps->snap->chunk_size << SECTOR_SHIFT; |
137 | 138 | ||
138 | /* | 139 | /* |
139 | * Allocate the chunk_size block of memory that will hold | 140 | * Allocate the chunk_size block of memory that will hold |
@@ -160,8 +161,8 @@ static int chunk_io(struct pstore *ps, uint32_t chunk, int rw) | |||
160 | unsigned long bits; | 161 | unsigned long bits; |
161 | 162 | ||
162 | where.bdev = ps->snap->cow->bdev; | 163 | where.bdev = ps->snap->cow->bdev; |
163 | where.sector = ps->chunk_size * chunk; | 164 | where.sector = ps->snap->chunk_size * chunk; |
164 | where.count = ps->chunk_size; | 165 | where.count = ps->snap->chunk_size; |
165 | 166 | ||
166 | return dm_io_sync_vm(1, &where, rw, ps->area, &bits); | 167 | return dm_io_sync_vm(1, &where, rw, ps->area, &bits); |
167 | } | 168 | } |
@@ -188,7 +189,7 @@ static int area_io(struct pstore *ps, uint32_t area, int rw) | |||
188 | 189 | ||
189 | static int zero_area(struct pstore *ps, uint32_t area) | 190 | static int zero_area(struct pstore *ps, uint32_t area) |
190 | { | 191 | { |
191 | memset(ps->area, 0, ps->chunk_size << SECTOR_SHIFT); | 192 | memset(ps->area, 0, ps->snap->chunk_size << SECTOR_SHIFT); |
192 | return area_io(ps, area, WRITE); | 193 | return area_io(ps, area, WRITE); |
193 | } | 194 | } |
194 | 195 | ||
@@ -196,6 +197,7 @@ static int read_header(struct pstore *ps, int *new_snapshot) | |||
196 | { | 197 | { |
197 | int r; | 198 | int r; |
198 | struct disk_header *dh; | 199 | struct disk_header *dh; |
200 | chunk_t chunk_size; | ||
199 | 201 | ||
200 | r = chunk_io(ps, 0, READ); | 202 | r = chunk_io(ps, 0, READ); |
201 | if (r) | 203 | if (r) |
@@ -210,8 +212,29 @@ static int read_header(struct pstore *ps, int *new_snapshot) | |||
210 | *new_snapshot = 0; | 212 | *new_snapshot = 0; |
211 | ps->valid = le32_to_cpu(dh->valid); | 213 | ps->valid = le32_to_cpu(dh->valid); |
212 | ps->version = le32_to_cpu(dh->version); | 214 | ps->version = le32_to_cpu(dh->version); |
213 | ps->chunk_size = le32_to_cpu(dh->chunk_size); | 215 | chunk_size = le32_to_cpu(dh->chunk_size); |
214 | 216 | if (ps->snap->chunk_size != chunk_size) { | |
217 | DMWARN("chunk size %llu in device metadata overrides " | ||
218 | "table chunk size of %llu.", | ||
219 | (unsigned long long)chunk_size, | ||
220 | (unsigned long long)ps->snap->chunk_size); | ||
221 | |||
222 | /* We had a bogus chunk_size. Fix stuff up. */ | ||
223 | dm_io_put(sectors_to_pages(ps->snap->chunk_size)); | ||
224 | free_area(ps); | ||
225 | |||
226 | ps->snap->chunk_size = chunk_size; | ||
227 | ps->snap->chunk_mask = chunk_size - 1; | ||
228 | ps->snap->chunk_shift = ffs(chunk_size) - 1; | ||
229 | |||
230 | r = alloc_area(ps); | ||
231 | if (r) | ||
232 | return r; | ||
233 | |||
234 | r = dm_io_get(sectors_to_pages(chunk_size)); | ||
235 | if (r) | ||
236 | return r; | ||
237 | } | ||
215 | } else { | 238 | } else { |
216 | DMWARN("Invalid/corrupt snapshot"); | 239 | DMWARN("Invalid/corrupt snapshot"); |
217 | r = -ENXIO; | 240 | r = -ENXIO; |
@@ -224,13 +247,13 @@ static int write_header(struct pstore *ps) | |||
224 | { | 247 | { |
225 | struct disk_header *dh; | 248 | struct disk_header *dh; |
226 | 249 | ||
227 | memset(ps->area, 0, ps->chunk_size << SECTOR_SHIFT); | 250 | memset(ps->area, 0, ps->snap->chunk_size << SECTOR_SHIFT); |
228 | 251 | ||
229 | dh = (struct disk_header *) ps->area; | 252 | dh = (struct disk_header *) ps->area; |
230 | dh->magic = cpu_to_le32(SNAP_MAGIC); | 253 | dh->magic = cpu_to_le32(SNAP_MAGIC); |
231 | dh->valid = cpu_to_le32(ps->valid); | 254 | dh->valid = cpu_to_le32(ps->valid); |
232 | dh->version = cpu_to_le32(ps->version); | 255 | dh->version = cpu_to_le32(ps->version); |
233 | dh->chunk_size = cpu_to_le32(ps->chunk_size); | 256 | dh->chunk_size = cpu_to_le32(ps->snap->chunk_size); |
234 | 257 | ||
235 | return chunk_io(ps, 0, WRITE); | 258 | return chunk_io(ps, 0, WRITE); |
236 | } | 259 | } |
@@ -365,7 +388,7 @@ static void persistent_destroy(struct exception_store *store) | |||
365 | { | 388 | { |
366 | struct pstore *ps = get_info(store); | 389 | struct pstore *ps = get_info(store); |
367 | 390 | ||
368 | dm_io_put(sectors_to_pages(ps->chunk_size)); | 391 | dm_io_put(sectors_to_pages(ps->snap->chunk_size)); |
369 | vfree(ps->callbacks); | 392 | vfree(ps->callbacks); |
370 | free_area(ps); | 393 | free_area(ps); |
371 | kfree(ps); | 394 | kfree(ps); |
@@ -384,6 +407,16 @@ static int persistent_read_metadata(struct exception_store *store) | |||
384 | return r; | 407 | return r; |
385 | 408 | ||
386 | /* | 409 | /* |
410 | * Now we know correct chunk_size, complete the initialisation. | ||
411 | */ | ||
412 | ps->exceptions_per_area = (ps->snap->chunk_size << SECTOR_SHIFT) / | ||
413 | sizeof(struct disk_exception); | ||
414 | ps->callbacks = dm_vcalloc(ps->exceptions_per_area, | ||
415 | sizeof(*ps->callbacks)); | ||
416 | if (!ps->callbacks) | ||
417 | return -ENOMEM; | ||
418 | |||
419 | /* | ||
387 | * Do we need to setup a new snapshot ? | 420 | * Do we need to setup a new snapshot ? |
388 | */ | 421 | */ |
389 | if (new_snapshot) { | 422 | if (new_snapshot) { |
@@ -533,9 +566,6 @@ int dm_create_persistent(struct exception_store *store, uint32_t chunk_size) | |||
533 | ps->snap = store->snap; | 566 | ps->snap = store->snap; |
534 | ps->valid = 1; | 567 | ps->valid = 1; |
535 | ps->version = SNAPSHOT_DISK_VERSION; | 568 | ps->version = SNAPSHOT_DISK_VERSION; |
536 | ps->chunk_size = chunk_size; | ||
537 | ps->exceptions_per_area = (chunk_size << SECTOR_SHIFT) / | ||
538 | sizeof(struct disk_exception); | ||
539 | ps->next_free = 2; /* skipping the header and first area */ | 569 | ps->next_free = 2; /* skipping the header and first area */ |
540 | ps->current_committed = 0; | 570 | ps->current_committed = 0; |
541 | 571 | ||
@@ -543,18 +573,9 @@ int dm_create_persistent(struct exception_store *store, uint32_t chunk_size) | |||
543 | if (r) | 573 | if (r) |
544 | goto bad; | 574 | goto bad; |
545 | 575 | ||
546 | /* | ||
547 | * Allocate space for all the callbacks. | ||
548 | */ | ||
549 | ps->callback_count = 0; | 576 | ps->callback_count = 0; |
550 | atomic_set(&ps->pending_count, 0); | 577 | atomic_set(&ps->pending_count, 0); |
551 | ps->callbacks = dm_vcalloc(ps->exceptions_per_area, | 578 | ps->callbacks = NULL; |
552 | sizeof(*ps->callbacks)); | ||
553 | |||
554 | if (!ps->callbacks) { | ||
555 | r = -ENOMEM; | ||
556 | goto bad; | ||
557 | } | ||
558 | 579 | ||
559 | store->destroy = persistent_destroy; | 580 | store->destroy = persistent_destroy; |
560 | store->read_metadata = persistent_read_metadata; | 581 | store->read_metadata = persistent_read_metadata; |
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c index 8edd6435414d..3edb3477f987 100644 --- a/drivers/md/dm-ioctl.c +++ b/drivers/md/dm-ioctl.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2001, 2002 Sistina Software (UK) Limited. | 2 | * Copyright (C) 2001, 2002 Sistina Software (UK) Limited. |
3 | * Copyright (C) 2004 - 2005 Red Hat, Inc. All rights reserved. | 3 | * Copyright (C) 2004 - 2006 Red Hat, Inc. All rights reserved. |
4 | * | 4 | * |
5 | * This file is released under the GPL. | 5 | * This file is released under the GPL. |
6 | */ | 6 | */ |
@@ -19,6 +19,7 @@ | |||
19 | 19 | ||
20 | #include <asm/uaccess.h> | 20 | #include <asm/uaccess.h> |
21 | 21 | ||
22 | #define DM_MSG_PREFIX "ioctl" | ||
22 | #define DM_DRIVER_EMAIL "dm-devel@redhat.com" | 23 | #define DM_DRIVER_EMAIL "dm-devel@redhat.com" |
23 | 24 | ||
24 | /*----------------------------------------------------------------- | 25 | /*----------------------------------------------------------------- |
@@ -48,7 +49,7 @@ struct vers_iter { | |||
48 | static struct list_head _name_buckets[NUM_BUCKETS]; | 49 | static struct list_head _name_buckets[NUM_BUCKETS]; |
49 | static struct list_head _uuid_buckets[NUM_BUCKETS]; | 50 | static struct list_head _uuid_buckets[NUM_BUCKETS]; |
50 | 51 | ||
51 | static void dm_hash_remove_all(void); | 52 | static void dm_hash_remove_all(int keep_open_devices); |
52 | 53 | ||
53 | /* | 54 | /* |
54 | * Guards access to both hash tables. | 55 | * Guards access to both hash tables. |
@@ -73,7 +74,7 @@ static int dm_hash_init(void) | |||
73 | 74 | ||
74 | static void dm_hash_exit(void) | 75 | static void dm_hash_exit(void) |
75 | { | 76 | { |
76 | dm_hash_remove_all(); | 77 | dm_hash_remove_all(0); |
77 | devfs_remove(DM_DIR); | 78 | devfs_remove(DM_DIR); |
78 | } | 79 | } |
79 | 80 | ||
@@ -102,8 +103,10 @@ static struct hash_cell *__get_name_cell(const char *str) | |||
102 | unsigned int h = hash_str(str); | 103 | unsigned int h = hash_str(str); |
103 | 104 | ||
104 | list_for_each_entry (hc, _name_buckets + h, name_list) | 105 | list_for_each_entry (hc, _name_buckets + h, name_list) |
105 | if (!strcmp(hc->name, str)) | 106 | if (!strcmp(hc->name, str)) { |
107 | dm_get(hc->md); | ||
106 | return hc; | 108 | return hc; |
109 | } | ||
107 | 110 | ||
108 | return NULL; | 111 | return NULL; |
109 | } | 112 | } |
@@ -114,8 +117,10 @@ static struct hash_cell *__get_uuid_cell(const char *str) | |||
114 | unsigned int h = hash_str(str); | 117 | unsigned int h = hash_str(str); |
115 | 118 | ||
116 | list_for_each_entry (hc, _uuid_buckets + h, uuid_list) | 119 | list_for_each_entry (hc, _uuid_buckets + h, uuid_list) |
117 | if (!strcmp(hc->uuid, str)) | 120 | if (!strcmp(hc->uuid, str)) { |
121 | dm_get(hc->md); | ||
118 | return hc; | 122 | return hc; |
123 | } | ||
119 | 124 | ||
120 | return NULL; | 125 | return NULL; |
121 | } | 126 | } |
@@ -191,7 +196,7 @@ static int unregister_with_devfs(struct hash_cell *hc) | |||
191 | */ | 196 | */ |
192 | static int dm_hash_insert(const char *name, const char *uuid, struct mapped_device *md) | 197 | static int dm_hash_insert(const char *name, const char *uuid, struct mapped_device *md) |
193 | { | 198 | { |
194 | struct hash_cell *cell; | 199 | struct hash_cell *cell, *hc; |
195 | 200 | ||
196 | /* | 201 | /* |
197 | * Allocate the new cells. | 202 | * Allocate the new cells. |
@@ -204,14 +209,19 @@ static int dm_hash_insert(const char *name, const char *uuid, struct mapped_devi | |||
204 | * Insert the cell into both hash tables. | 209 | * Insert the cell into both hash tables. |
205 | */ | 210 | */ |
206 | down_write(&_hash_lock); | 211 | down_write(&_hash_lock); |
207 | if (__get_name_cell(name)) | 212 | hc = __get_name_cell(name); |
213 | if (hc) { | ||
214 | dm_put(hc->md); | ||
208 | goto bad; | 215 | goto bad; |
216 | } | ||
209 | 217 | ||
210 | list_add(&cell->name_list, _name_buckets + hash_str(name)); | 218 | list_add(&cell->name_list, _name_buckets + hash_str(name)); |
211 | 219 | ||
212 | if (uuid) { | 220 | if (uuid) { |
213 | if (__get_uuid_cell(uuid)) { | 221 | hc = __get_uuid_cell(uuid); |
222 | if (hc) { | ||
214 | list_del(&cell->name_list); | 223 | list_del(&cell->name_list); |
224 | dm_put(hc->md); | ||
215 | goto bad; | 225 | goto bad; |
216 | } | 226 | } |
217 | list_add(&cell->uuid_list, _uuid_buckets + hash_str(uuid)); | 227 | list_add(&cell->uuid_list, _uuid_buckets + hash_str(uuid)); |
@@ -251,19 +261,41 @@ static void __hash_remove(struct hash_cell *hc) | |||
251 | free_cell(hc); | 261 | free_cell(hc); |
252 | } | 262 | } |
253 | 263 | ||
254 | static void dm_hash_remove_all(void) | 264 | static void dm_hash_remove_all(int keep_open_devices) |
255 | { | 265 | { |
256 | int i; | 266 | int i, dev_skipped, dev_removed; |
257 | struct hash_cell *hc; | 267 | struct hash_cell *hc; |
258 | struct list_head *tmp, *n; | 268 | struct list_head *tmp, *n; |
259 | 269 | ||
260 | down_write(&_hash_lock); | 270 | down_write(&_hash_lock); |
271 | |||
272 | retry: | ||
273 | dev_skipped = dev_removed = 0; | ||
261 | for (i = 0; i < NUM_BUCKETS; i++) { | 274 | for (i = 0; i < NUM_BUCKETS; i++) { |
262 | list_for_each_safe (tmp, n, _name_buckets + i) { | 275 | list_for_each_safe (tmp, n, _name_buckets + i) { |
263 | hc = list_entry(tmp, struct hash_cell, name_list); | 276 | hc = list_entry(tmp, struct hash_cell, name_list); |
277 | |||
278 | if (keep_open_devices && | ||
279 | dm_lock_for_deletion(hc->md)) { | ||
280 | dev_skipped++; | ||
281 | continue; | ||
282 | } | ||
264 | __hash_remove(hc); | 283 | __hash_remove(hc); |
284 | dev_removed = 1; | ||
265 | } | 285 | } |
266 | } | 286 | } |
287 | |||
288 | /* | ||
289 | * Some mapped devices may be using other mapped devices, so if any | ||
290 | * still exist, repeat until we make no further progress. | ||
291 | */ | ||
292 | if (dev_skipped) { | ||
293 | if (dev_removed) | ||
294 | goto retry; | ||
295 | |||
296 | DMWARN("remove_all left %d open device(s)", dev_skipped); | ||
297 | } | ||
298 | |||
267 | up_write(&_hash_lock); | 299 | up_write(&_hash_lock); |
268 | } | 300 | } |
269 | 301 | ||
@@ -289,6 +321,7 @@ static int dm_hash_rename(const char *old, const char *new) | |||
289 | if (hc) { | 321 | if (hc) { |
290 | DMWARN("asked to rename to an already existing name %s -> %s", | 322 | DMWARN("asked to rename to an already existing name %s -> %s", |
291 | old, new); | 323 | old, new); |
324 | dm_put(hc->md); | ||
292 | up_write(&_hash_lock); | 325 | up_write(&_hash_lock); |
293 | kfree(new_name); | 326 | kfree(new_name); |
294 | return -EBUSY; | 327 | return -EBUSY; |
@@ -328,6 +361,7 @@ static int dm_hash_rename(const char *old, const char *new) | |||
328 | dm_table_put(table); | 361 | dm_table_put(table); |
329 | } | 362 | } |
330 | 363 | ||
364 | dm_put(hc->md); | ||
331 | up_write(&_hash_lock); | 365 | up_write(&_hash_lock); |
332 | kfree(old_name); | 366 | kfree(old_name); |
333 | return 0; | 367 | return 0; |
@@ -344,7 +378,7 @@ typedef int (*ioctl_fn)(struct dm_ioctl *param, size_t param_size); | |||
344 | 378 | ||
345 | static int remove_all(struct dm_ioctl *param, size_t param_size) | 379 | static int remove_all(struct dm_ioctl *param, size_t param_size) |
346 | { | 380 | { |
347 | dm_hash_remove_all(); | 381 | dm_hash_remove_all(1); |
348 | param->data_size = 0; | 382 | param->data_size = 0; |
349 | return 0; | 383 | return 0; |
350 | } | 384 | } |
@@ -524,7 +558,6 @@ static int __dev_status(struct mapped_device *md, struct dm_ioctl *param) | |||
524 | { | 558 | { |
525 | struct gendisk *disk = dm_disk(md); | 559 | struct gendisk *disk = dm_disk(md); |
526 | struct dm_table *table; | 560 | struct dm_table *table; |
527 | struct block_device *bdev; | ||
528 | 561 | ||
529 | param->flags &= ~(DM_SUSPEND_FLAG | DM_READONLY_FLAG | | 562 | param->flags &= ~(DM_SUSPEND_FLAG | DM_READONLY_FLAG | |
530 | DM_ACTIVE_PRESENT_FLAG); | 563 | DM_ACTIVE_PRESENT_FLAG); |
@@ -534,20 +567,12 @@ static int __dev_status(struct mapped_device *md, struct dm_ioctl *param) | |||
534 | 567 | ||
535 | param->dev = huge_encode_dev(MKDEV(disk->major, disk->first_minor)); | 568 | param->dev = huge_encode_dev(MKDEV(disk->major, disk->first_minor)); |
536 | 569 | ||
537 | if (!(param->flags & DM_SKIP_BDGET_FLAG)) { | 570 | /* |
538 | bdev = bdget_disk(disk, 0); | 571 | * Yes, this will be out of date by the time it gets back |
539 | if (!bdev) | 572 | * to userland, but it is still very useful for |
540 | return -ENXIO; | 573 | * debugging. |
541 | 574 | */ | |
542 | /* | 575 | param->open_count = dm_open_count(md); |
543 | * Yes, this will be out of date by the time it gets back | ||
544 | * to userland, but it is still very useful for | ||
545 | * debugging. | ||
546 | */ | ||
547 | param->open_count = bdev->bd_openers; | ||
548 | bdput(bdev); | ||
549 | } else | ||
550 | param->open_count = -1; | ||
551 | 576 | ||
552 | if (disk->policy) | 577 | if (disk->policy) |
553 | param->flags |= DM_READONLY_FLAG; | 578 | param->flags |= DM_READONLY_FLAG; |
@@ -567,7 +592,7 @@ static int __dev_status(struct mapped_device *md, struct dm_ioctl *param) | |||
567 | 592 | ||
568 | static int dev_create(struct dm_ioctl *param, size_t param_size) | 593 | static int dev_create(struct dm_ioctl *param, size_t param_size) |
569 | { | 594 | { |
570 | int r; | 595 | int r, m = DM_ANY_MINOR; |
571 | struct mapped_device *md; | 596 | struct mapped_device *md; |
572 | 597 | ||
573 | r = check_name(param->name); | 598 | r = check_name(param->name); |
@@ -575,10 +600,9 @@ static int dev_create(struct dm_ioctl *param, size_t param_size) | |||
575 | return r; | 600 | return r; |
576 | 601 | ||
577 | if (param->flags & DM_PERSISTENT_DEV_FLAG) | 602 | if (param->flags & DM_PERSISTENT_DEV_FLAG) |
578 | r = dm_create_with_minor(MINOR(huge_decode_dev(param->dev)), &md); | 603 | m = MINOR(huge_decode_dev(param->dev)); |
579 | else | ||
580 | r = dm_create(&md); | ||
581 | 604 | ||
605 | r = dm_create(m, &md); | ||
582 | if (r) | 606 | if (r) |
583 | return r; | 607 | return r; |
584 | 608 | ||
@@ -611,10 +635,8 @@ static struct hash_cell *__find_device_hash_cell(struct dm_ioctl *param) | |||
611 | return __get_name_cell(param->name); | 635 | return __get_name_cell(param->name); |
612 | 636 | ||
613 | md = dm_get_md(huge_decode_dev(param->dev)); | 637 | md = dm_get_md(huge_decode_dev(param->dev)); |
614 | if (md) { | 638 | if (md) |
615 | mdptr = dm_get_mdptr(md); | 639 | mdptr = dm_get_mdptr(md); |
616 | dm_put(md); | ||
617 | } | ||
618 | 640 | ||
619 | return mdptr; | 641 | return mdptr; |
620 | } | 642 | } |
@@ -628,7 +650,6 @@ static struct mapped_device *find_device(struct dm_ioctl *param) | |||
628 | hc = __find_device_hash_cell(param); | 650 | hc = __find_device_hash_cell(param); |
629 | if (hc) { | 651 | if (hc) { |
630 | md = hc->md; | 652 | md = hc->md; |
631 | dm_get(md); | ||
632 | 653 | ||
633 | /* | 654 | /* |
634 | * Sneakily write in both the name and the uuid | 655 | * Sneakily write in both the name and the uuid |
@@ -653,6 +674,8 @@ static struct mapped_device *find_device(struct dm_ioctl *param) | |||
653 | static int dev_remove(struct dm_ioctl *param, size_t param_size) | 674 | static int dev_remove(struct dm_ioctl *param, size_t param_size) |
654 | { | 675 | { |
655 | struct hash_cell *hc; | 676 | struct hash_cell *hc; |
677 | struct mapped_device *md; | ||
678 | int r; | ||
656 | 679 | ||
657 | down_write(&_hash_lock); | 680 | down_write(&_hash_lock); |
658 | hc = __find_device_hash_cell(param); | 681 | hc = __find_device_hash_cell(param); |
@@ -663,8 +686,22 @@ static int dev_remove(struct dm_ioctl *param, size_t param_size) | |||
663 | return -ENXIO; | 686 | return -ENXIO; |
664 | } | 687 | } |
665 | 688 | ||
689 | md = hc->md; | ||
690 | |||
691 | /* | ||
692 | * Ensure the device is not open and nothing further can open it. | ||
693 | */ | ||
694 | r = dm_lock_for_deletion(md); | ||
695 | if (r) { | ||
696 | DMWARN("unable to remove open device %s", hc->name); | ||
697 | up_write(&_hash_lock); | ||
698 | dm_put(md); | ||
699 | return r; | ||
700 | } | ||
701 | |||
666 | __hash_remove(hc); | 702 | __hash_remove(hc); |
667 | up_write(&_hash_lock); | 703 | up_write(&_hash_lock); |
704 | dm_put(md); | ||
668 | param->data_size = 0; | 705 | param->data_size = 0; |
669 | return 0; | 706 | return 0; |
670 | } | 707 | } |
@@ -790,7 +827,6 @@ static int do_resume(struct dm_ioctl *param) | |||
790 | } | 827 | } |
791 | 828 | ||
792 | md = hc->md; | 829 | md = hc->md; |
793 | dm_get(md); | ||
794 | 830 | ||
795 | new_map = hc->new_map; | 831 | new_map = hc->new_map; |
796 | hc->new_map = NULL; | 832 | hc->new_map = NULL; |
@@ -1078,6 +1114,7 @@ static int table_clear(struct dm_ioctl *param, size_t param_size) | |||
1078 | { | 1114 | { |
1079 | int r; | 1115 | int r; |
1080 | struct hash_cell *hc; | 1116 | struct hash_cell *hc; |
1117 | struct mapped_device *md; | ||
1081 | 1118 | ||
1082 | down_write(&_hash_lock); | 1119 | down_write(&_hash_lock); |
1083 | 1120 | ||
@@ -1096,7 +1133,9 @@ static int table_clear(struct dm_ioctl *param, size_t param_size) | |||
1096 | param->flags &= ~DM_INACTIVE_PRESENT_FLAG; | 1133 | param->flags &= ~DM_INACTIVE_PRESENT_FLAG; |
1097 | 1134 | ||
1098 | r = __dev_status(hc->md, param); | 1135 | r = __dev_status(hc->md, param); |
1136 | md = hc->md; | ||
1099 | up_write(&_hash_lock); | 1137 | up_write(&_hash_lock); |
1138 | dm_put(md); | ||
1100 | return r; | 1139 | return r; |
1101 | } | 1140 | } |
1102 | 1141 | ||
diff --git a/drivers/md/dm-linear.c b/drivers/md/dm-linear.c index daf586c0898d..47b3c62bbdb8 100644 --- a/drivers/md/dm-linear.c +++ b/drivers/md/dm-linear.c | |||
@@ -12,6 +12,8 @@ | |||
12 | #include <linux/bio.h> | 12 | #include <linux/bio.h> |
13 | #include <linux/slab.h> | 13 | #include <linux/slab.h> |
14 | 14 | ||
15 | #define DM_MSG_PREFIX "linear" | ||
16 | |||
15 | /* | 17 | /* |
16 | * Linear: maps a linear range of a device. | 18 | * Linear: maps a linear range of a device. |
17 | */ | 19 | */ |
@@ -29,7 +31,7 @@ static int linear_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
29 | unsigned long long tmp; | 31 | unsigned long long tmp; |
30 | 32 | ||
31 | if (argc != 2) { | 33 | if (argc != 2) { |
32 | ti->error = "dm-linear: Invalid argument count"; | 34 | ti->error = "Invalid argument count"; |
33 | return -EINVAL; | 35 | return -EINVAL; |
34 | } | 36 | } |
35 | 37 | ||
@@ -111,7 +113,7 @@ int __init dm_linear_init(void) | |||
111 | int r = dm_register_target(&linear_target); | 113 | int r = dm_register_target(&linear_target); |
112 | 114 | ||
113 | if (r < 0) | 115 | if (r < 0) |
114 | DMERR("linear: register failed %d", r); | 116 | DMERR("register failed %d", r); |
115 | 117 | ||
116 | return r; | 118 | return r; |
117 | } | 119 | } |
@@ -121,5 +123,5 @@ void dm_linear_exit(void) | |||
121 | int r = dm_unregister_target(&linear_target); | 123 | int r = dm_unregister_target(&linear_target); |
122 | 124 | ||
123 | if (r < 0) | 125 | if (r < 0) |
124 | DMERR("linear: unregister failed %d", r); | 126 | DMERR("unregister failed %d", r); |
125 | } | 127 | } |
diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c index d73779a42417..64b764bd02cc 100644 --- a/drivers/md/dm-log.c +++ b/drivers/md/dm-log.c | |||
@@ -12,6 +12,8 @@ | |||
12 | #include "dm-log.h" | 12 | #include "dm-log.h" |
13 | #include "dm-io.h" | 13 | #include "dm-io.h" |
14 | 14 | ||
15 | #define DM_MSG_PREFIX "mirror log" | ||
16 | |||
15 | static LIST_HEAD(_log_types); | 17 | static LIST_HEAD(_log_types); |
16 | static DEFINE_SPINLOCK(_lock); | 18 | static DEFINE_SPINLOCK(_lock); |
17 | 19 | ||
@@ -155,8 +157,6 @@ struct log_c { | |||
155 | 157 | ||
156 | struct io_region header_location; | 158 | struct io_region header_location; |
157 | struct log_header *disk_header; | 159 | struct log_header *disk_header; |
158 | |||
159 | struct io_region bits_location; | ||
160 | }; | 160 | }; |
161 | 161 | ||
162 | /* | 162 | /* |
@@ -241,43 +241,21 @@ static inline int write_header(struct log_c *log) | |||
241 | } | 241 | } |
242 | 242 | ||
243 | /*---------------------------------------------------------------- | 243 | /*---------------------------------------------------------------- |
244 | * Bits IO | ||
245 | *--------------------------------------------------------------*/ | ||
246 | static int read_bits(struct log_c *log) | ||
247 | { | ||
248 | int r; | ||
249 | unsigned long ebits; | ||
250 | |||
251 | r = dm_io_sync_vm(1, &log->bits_location, READ, | ||
252 | log->clean_bits, &ebits); | ||
253 | if (r) | ||
254 | return r; | ||
255 | |||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | static int write_bits(struct log_c *log) | ||
260 | { | ||
261 | unsigned long ebits; | ||
262 | return dm_io_sync_vm(1, &log->bits_location, WRITE, | ||
263 | log->clean_bits, &ebits); | ||
264 | } | ||
265 | |||
266 | /*---------------------------------------------------------------- | ||
267 | * core log constructor/destructor | 244 | * core log constructor/destructor |
268 | * | 245 | * |
269 | * argv contains region_size followed optionally by [no]sync | 246 | * argv contains region_size followed optionally by [no]sync |
270 | *--------------------------------------------------------------*/ | 247 | *--------------------------------------------------------------*/ |
271 | #define BYTE_SHIFT 3 | 248 | #define BYTE_SHIFT 3 |
272 | static int core_ctr(struct dirty_log *log, struct dm_target *ti, | 249 | static int create_log_context(struct dirty_log *log, struct dm_target *ti, |
273 | unsigned int argc, char **argv) | 250 | unsigned int argc, char **argv, |
251 | struct dm_dev *dev) | ||
274 | { | 252 | { |
275 | enum sync sync = DEFAULTSYNC; | 253 | enum sync sync = DEFAULTSYNC; |
276 | 254 | ||
277 | struct log_c *lc; | 255 | struct log_c *lc; |
278 | uint32_t region_size; | 256 | uint32_t region_size; |
279 | unsigned int region_count; | 257 | unsigned int region_count; |
280 | size_t bitset_size; | 258 | size_t bitset_size, buf_size; |
281 | 259 | ||
282 | if (argc < 1 || argc > 2) { | 260 | if (argc < 1 || argc > 2) { |
283 | DMWARN("wrong number of arguments to mirror log"); | 261 | DMWARN("wrong number of arguments to mirror log"); |
@@ -319,22 +297,53 @@ static int core_ctr(struct dirty_log *log, struct dm_target *ti, | |||
319 | * Work out how many "unsigned long"s we need to hold the bitset. | 297 | * Work out how many "unsigned long"s we need to hold the bitset. |
320 | */ | 298 | */ |
321 | bitset_size = dm_round_up(region_count, | 299 | bitset_size = dm_round_up(region_count, |
322 | sizeof(unsigned long) << BYTE_SHIFT); | 300 | sizeof(*lc->clean_bits) << BYTE_SHIFT); |
323 | bitset_size >>= BYTE_SHIFT; | 301 | bitset_size >>= BYTE_SHIFT; |
324 | 302 | ||
325 | lc->bitset_uint32_count = bitset_size / 4; | 303 | lc->bitset_uint32_count = bitset_size / sizeof(*lc->clean_bits); |
326 | lc->clean_bits = vmalloc(bitset_size); | 304 | |
327 | if (!lc->clean_bits) { | 305 | /* |
328 | DMWARN("couldn't allocate clean bitset"); | 306 | * Disk log? |
329 | kfree(lc); | 307 | */ |
330 | return -ENOMEM; | 308 | if (!dev) { |
309 | lc->clean_bits = vmalloc(bitset_size); | ||
310 | if (!lc->clean_bits) { | ||
311 | DMWARN("couldn't allocate clean bitset"); | ||
312 | kfree(lc); | ||
313 | return -ENOMEM; | ||
314 | } | ||
315 | lc->disk_header = NULL; | ||
316 | } else { | ||
317 | lc->log_dev = dev; | ||
318 | lc->header_location.bdev = lc->log_dev->bdev; | ||
319 | lc->header_location.sector = 0; | ||
320 | |||
321 | /* | ||
322 | * Buffer holds both header and bitset. | ||
323 | */ | ||
324 | buf_size = dm_round_up((LOG_OFFSET << SECTOR_SHIFT) + | ||
325 | bitset_size, ti->limits.hardsect_size); | ||
326 | lc->header_location.count = buf_size >> SECTOR_SHIFT; | ||
327 | |||
328 | lc->disk_header = vmalloc(buf_size); | ||
329 | if (!lc->disk_header) { | ||
330 | DMWARN("couldn't allocate disk log buffer"); | ||
331 | kfree(lc); | ||
332 | return -ENOMEM; | ||
333 | } | ||
334 | |||
335 | lc->clean_bits = (void *)lc->disk_header + | ||
336 | (LOG_OFFSET << SECTOR_SHIFT); | ||
331 | } | 337 | } |
338 | |||
332 | memset(lc->clean_bits, -1, bitset_size); | 339 | memset(lc->clean_bits, -1, bitset_size); |
333 | 340 | ||
334 | lc->sync_bits = vmalloc(bitset_size); | 341 | lc->sync_bits = vmalloc(bitset_size); |
335 | if (!lc->sync_bits) { | 342 | if (!lc->sync_bits) { |
336 | DMWARN("couldn't allocate sync bitset"); | 343 | DMWARN("couldn't allocate sync bitset"); |
337 | vfree(lc->clean_bits); | 344 | if (!dev) |
345 | vfree(lc->clean_bits); | ||
346 | vfree(lc->disk_header); | ||
338 | kfree(lc); | 347 | kfree(lc); |
339 | return -ENOMEM; | 348 | return -ENOMEM; |
340 | } | 349 | } |
@@ -345,25 +354,40 @@ static int core_ctr(struct dirty_log *log, struct dm_target *ti, | |||
345 | if (!lc->recovering_bits) { | 354 | if (!lc->recovering_bits) { |
346 | DMWARN("couldn't allocate sync bitset"); | 355 | DMWARN("couldn't allocate sync bitset"); |
347 | vfree(lc->sync_bits); | 356 | vfree(lc->sync_bits); |
348 | vfree(lc->clean_bits); | 357 | if (!dev) |
358 | vfree(lc->clean_bits); | ||
359 | vfree(lc->disk_header); | ||
349 | kfree(lc); | 360 | kfree(lc); |
350 | return -ENOMEM; | 361 | return -ENOMEM; |
351 | } | 362 | } |
352 | memset(lc->recovering_bits, 0, bitset_size); | 363 | memset(lc->recovering_bits, 0, bitset_size); |
353 | lc->sync_search = 0; | 364 | lc->sync_search = 0; |
354 | log->context = lc; | 365 | log->context = lc; |
366 | |||
355 | return 0; | 367 | return 0; |
356 | } | 368 | } |
357 | 369 | ||
358 | static void core_dtr(struct dirty_log *log) | 370 | static int core_ctr(struct dirty_log *log, struct dm_target *ti, |
371 | unsigned int argc, char **argv) | ||
372 | { | ||
373 | return create_log_context(log, ti, argc, argv, NULL); | ||
374 | } | ||
375 | |||
376 | static void destroy_log_context(struct log_c *lc) | ||
359 | { | 377 | { |
360 | struct log_c *lc = (struct log_c *) log->context; | ||
361 | vfree(lc->clean_bits); | ||
362 | vfree(lc->sync_bits); | 378 | vfree(lc->sync_bits); |
363 | vfree(lc->recovering_bits); | 379 | vfree(lc->recovering_bits); |
364 | kfree(lc); | 380 | kfree(lc); |
365 | } | 381 | } |
366 | 382 | ||
383 | static void core_dtr(struct dirty_log *log) | ||
384 | { | ||
385 | struct log_c *lc = (struct log_c *) log->context; | ||
386 | |||
387 | vfree(lc->clean_bits); | ||
388 | destroy_log_context(lc); | ||
389 | } | ||
390 | |||
367 | /*---------------------------------------------------------------- | 391 | /*---------------------------------------------------------------- |
368 | * disk log constructor/destructor | 392 | * disk log constructor/destructor |
369 | * | 393 | * |
@@ -373,8 +397,6 @@ static int disk_ctr(struct dirty_log *log, struct dm_target *ti, | |||
373 | unsigned int argc, char **argv) | 397 | unsigned int argc, char **argv) |
374 | { | 398 | { |
375 | int r; | 399 | int r; |
376 | size_t size; | ||
377 | struct log_c *lc; | ||
378 | struct dm_dev *dev; | 400 | struct dm_dev *dev; |
379 | 401 | ||
380 | if (argc < 2 || argc > 3) { | 402 | if (argc < 2 || argc > 3) { |
@@ -387,49 +409,22 @@ static int disk_ctr(struct dirty_log *log, struct dm_target *ti, | |||
387 | if (r) | 409 | if (r) |
388 | return r; | 410 | return r; |
389 | 411 | ||
390 | r = core_ctr(log, ti, argc - 1, argv + 1); | 412 | r = create_log_context(log, ti, argc - 1, argv + 1, dev); |
391 | if (r) { | 413 | if (r) { |
392 | dm_put_device(ti, dev); | 414 | dm_put_device(ti, dev); |
393 | return r; | 415 | return r; |
394 | } | 416 | } |
395 | 417 | ||
396 | lc = (struct log_c *) log->context; | ||
397 | lc->log_dev = dev; | ||
398 | |||
399 | /* setup the disk header fields */ | ||
400 | lc->header_location.bdev = lc->log_dev->bdev; | ||
401 | lc->header_location.sector = 0; | ||
402 | lc->header_location.count = 1; | ||
403 | |||
404 | /* | ||
405 | * We can't read less than this amount, even though we'll | ||
406 | * not be using most of this space. | ||
407 | */ | ||
408 | lc->disk_header = vmalloc(1 << SECTOR_SHIFT); | ||
409 | if (!lc->disk_header) | ||
410 | goto bad; | ||
411 | |||
412 | /* setup the disk bitset fields */ | ||
413 | lc->bits_location.bdev = lc->log_dev->bdev; | ||
414 | lc->bits_location.sector = LOG_OFFSET; | ||
415 | |||
416 | size = dm_round_up(lc->bitset_uint32_count * sizeof(uint32_t), | ||
417 | 1 << SECTOR_SHIFT); | ||
418 | lc->bits_location.count = size >> SECTOR_SHIFT; | ||
419 | return 0; | 418 | return 0; |
420 | |||
421 | bad: | ||
422 | dm_put_device(ti, lc->log_dev); | ||
423 | core_dtr(log); | ||
424 | return -ENOMEM; | ||
425 | } | 419 | } |
426 | 420 | ||
427 | static void disk_dtr(struct dirty_log *log) | 421 | static void disk_dtr(struct dirty_log *log) |
428 | { | 422 | { |
429 | struct log_c *lc = (struct log_c *) log->context; | 423 | struct log_c *lc = (struct log_c *) log->context; |
424 | |||
430 | dm_put_device(lc->ti, lc->log_dev); | 425 | dm_put_device(lc->ti, lc->log_dev); |
431 | vfree(lc->disk_header); | 426 | vfree(lc->disk_header); |
432 | core_dtr(log); | 427 | destroy_log_context(lc); |
433 | } | 428 | } |
434 | 429 | ||
435 | static int count_bits32(uint32_t *addr, unsigned size) | 430 | static int count_bits32(uint32_t *addr, unsigned size) |
@@ -454,12 +449,7 @@ static int disk_resume(struct dirty_log *log) | |||
454 | if (r) | 449 | if (r) |
455 | return r; | 450 | return r; |
456 | 451 | ||
457 | /* read the bits */ | 452 | /* set or clear any new bits -- device has grown */ |
458 | r = read_bits(lc); | ||
459 | if (r) | ||
460 | return r; | ||
461 | |||
462 | /* set or clear any new bits */ | ||
463 | if (lc->sync == NOSYNC) | 453 | if (lc->sync == NOSYNC) |
464 | for (i = lc->header.nr_regions; i < lc->region_count; i++) | 454 | for (i = lc->header.nr_regions; i < lc->region_count; i++) |
465 | /* FIXME: amazingly inefficient */ | 455 | /* FIXME: amazingly inefficient */ |
@@ -469,15 +459,14 @@ static int disk_resume(struct dirty_log *log) | |||
469 | /* FIXME: amazingly inefficient */ | 459 | /* FIXME: amazingly inefficient */ |
470 | log_clear_bit(lc, lc->clean_bits, i); | 460 | log_clear_bit(lc, lc->clean_bits, i); |
471 | 461 | ||
462 | /* clear any old bits -- device has shrunk */ | ||
463 | for (i = lc->region_count; i % (sizeof(*lc->clean_bits) << BYTE_SHIFT); i++) | ||
464 | log_clear_bit(lc, lc->clean_bits, i); | ||
465 | |||
472 | /* copy clean across to sync */ | 466 | /* copy clean across to sync */ |
473 | memcpy(lc->sync_bits, lc->clean_bits, size); | 467 | memcpy(lc->sync_bits, lc->clean_bits, size); |
474 | lc->sync_count = count_bits32(lc->clean_bits, lc->bitset_uint32_count); | 468 | lc->sync_count = count_bits32(lc->clean_bits, lc->bitset_uint32_count); |
475 | 469 | ||
476 | /* write the bits */ | ||
477 | r = write_bits(lc); | ||
478 | if (r) | ||
479 | return r; | ||
480 | |||
481 | /* set the correct number of regions in the header */ | 470 | /* set the correct number of regions in the header */ |
482 | lc->header.nr_regions = lc->region_count; | 471 | lc->header.nr_regions = lc->region_count; |
483 | 472 | ||
@@ -518,7 +507,7 @@ static int disk_flush(struct dirty_log *log) | |||
518 | if (!lc->touched) | 507 | if (!lc->touched) |
519 | return 0; | 508 | return 0; |
520 | 509 | ||
521 | r = write_bits(lc); | 510 | r = write_header(lc); |
522 | if (!r) | 511 | if (!r) |
523 | lc->touched = 0; | 512 | lc->touched = 0; |
524 | 513 | ||
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index 1816f30678ed..217615b33223 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/workqueue.h> | 21 | #include <linux/workqueue.h> |
22 | #include <asm/atomic.h> | 22 | #include <asm/atomic.h> |
23 | 23 | ||
24 | #define DM_MSG_PREFIX "multipath" | ||
24 | #define MESG_STR(x) x, sizeof(x) | 25 | #define MESG_STR(x) x, sizeof(x) |
25 | 26 | ||
26 | /* Path properties */ | 27 | /* Path properties */ |
@@ -446,8 +447,6 @@ struct param { | |||
446 | char *error; | 447 | char *error; |
447 | }; | 448 | }; |
448 | 449 | ||
449 | #define ESTR(s) ("dm-multipath: " s) | ||
450 | |||
451 | static int read_param(struct param *param, char *str, unsigned *v, char **error) | 450 | static int read_param(struct param *param, char *str, unsigned *v, char **error) |
452 | { | 451 | { |
453 | if (!str || | 452 | if (!str || |
@@ -495,12 +494,12 @@ static int parse_path_selector(struct arg_set *as, struct priority_group *pg, | |||
495 | unsigned ps_argc; | 494 | unsigned ps_argc; |
496 | 495 | ||
497 | static struct param _params[] = { | 496 | static struct param _params[] = { |
498 | {0, 1024, ESTR("invalid number of path selector args")}, | 497 | {0, 1024, "invalid number of path selector args"}, |
499 | }; | 498 | }; |
500 | 499 | ||
501 | pst = dm_get_path_selector(shift(as)); | 500 | pst = dm_get_path_selector(shift(as)); |
502 | if (!pst) { | 501 | if (!pst) { |
503 | ti->error = ESTR("unknown path selector type"); | 502 | ti->error = "unknown path selector type"; |
504 | return -EINVAL; | 503 | return -EINVAL; |
505 | } | 504 | } |
506 | 505 | ||
@@ -511,7 +510,7 @@ static int parse_path_selector(struct arg_set *as, struct priority_group *pg, | |||
511 | r = pst->create(&pg->ps, ps_argc, as->argv); | 510 | r = pst->create(&pg->ps, ps_argc, as->argv); |
512 | if (r) { | 511 | if (r) { |
513 | dm_put_path_selector(pst); | 512 | dm_put_path_selector(pst); |
514 | ti->error = ESTR("path selector constructor failed"); | 513 | ti->error = "path selector constructor failed"; |
515 | return r; | 514 | return r; |
516 | } | 515 | } |
517 | 516 | ||
@@ -529,7 +528,7 @@ static struct pgpath *parse_path(struct arg_set *as, struct path_selector *ps, | |||
529 | 528 | ||
530 | /* we need at least a path arg */ | 529 | /* we need at least a path arg */ |
531 | if (as->argc < 1) { | 530 | if (as->argc < 1) { |
532 | ti->error = ESTR("no device given"); | 531 | ti->error = "no device given"; |
533 | return NULL; | 532 | return NULL; |
534 | } | 533 | } |
535 | 534 | ||
@@ -540,7 +539,7 @@ static struct pgpath *parse_path(struct arg_set *as, struct path_selector *ps, | |||
540 | r = dm_get_device(ti, shift(as), ti->begin, ti->len, | 539 | r = dm_get_device(ti, shift(as), ti->begin, ti->len, |
541 | dm_table_get_mode(ti->table), &p->path.dev); | 540 | dm_table_get_mode(ti->table), &p->path.dev); |
542 | if (r) { | 541 | if (r) { |
543 | ti->error = ESTR("error getting device"); | 542 | ti->error = "error getting device"; |
544 | goto bad; | 543 | goto bad; |
545 | } | 544 | } |
546 | 545 | ||
@@ -562,8 +561,8 @@ static struct priority_group *parse_priority_group(struct arg_set *as, | |||
562 | struct dm_target *ti) | 561 | struct dm_target *ti) |
563 | { | 562 | { |
564 | static struct param _params[] = { | 563 | static struct param _params[] = { |
565 | {1, 1024, ESTR("invalid number of paths")}, | 564 | {1, 1024, "invalid number of paths"}, |
566 | {0, 1024, ESTR("invalid number of selector args")} | 565 | {0, 1024, "invalid number of selector args"} |
567 | }; | 566 | }; |
568 | 567 | ||
569 | int r; | 568 | int r; |
@@ -572,13 +571,13 @@ static struct priority_group *parse_priority_group(struct arg_set *as, | |||
572 | 571 | ||
573 | if (as->argc < 2) { | 572 | if (as->argc < 2) { |
574 | as->argc = 0; | 573 | as->argc = 0; |
575 | ti->error = ESTR("not enough priority group aruments"); | 574 | ti->error = "not enough priority group aruments"; |
576 | return NULL; | 575 | return NULL; |
577 | } | 576 | } |
578 | 577 | ||
579 | pg = alloc_priority_group(); | 578 | pg = alloc_priority_group(); |
580 | if (!pg) { | 579 | if (!pg) { |
581 | ti->error = ESTR("couldn't allocate priority group"); | 580 | ti->error = "couldn't allocate priority group"; |
582 | return NULL; | 581 | return NULL; |
583 | } | 582 | } |
584 | pg->m = m; | 583 | pg->m = m; |
@@ -633,7 +632,7 @@ static int parse_hw_handler(struct arg_set *as, struct multipath *m, | |||
633 | unsigned hw_argc; | 632 | unsigned hw_argc; |
634 | 633 | ||
635 | static struct param _params[] = { | 634 | static struct param _params[] = { |
636 | {0, 1024, ESTR("invalid number of hardware handler args")}, | 635 | {0, 1024, "invalid number of hardware handler args"}, |
637 | }; | 636 | }; |
638 | 637 | ||
639 | r = read_param(_params, shift(as), &hw_argc, &ti->error); | 638 | r = read_param(_params, shift(as), &hw_argc, &ti->error); |
@@ -645,14 +644,14 @@ static int parse_hw_handler(struct arg_set *as, struct multipath *m, | |||
645 | 644 | ||
646 | hwht = dm_get_hw_handler(shift(as)); | 645 | hwht = dm_get_hw_handler(shift(as)); |
647 | if (!hwht) { | 646 | if (!hwht) { |
648 | ti->error = ESTR("unknown hardware handler type"); | 647 | ti->error = "unknown hardware handler type"; |
649 | return -EINVAL; | 648 | return -EINVAL; |
650 | } | 649 | } |
651 | 650 | ||
652 | r = hwht->create(&m->hw_handler, hw_argc - 1, as->argv); | 651 | r = hwht->create(&m->hw_handler, hw_argc - 1, as->argv); |
653 | if (r) { | 652 | if (r) { |
654 | dm_put_hw_handler(hwht); | 653 | dm_put_hw_handler(hwht); |
655 | ti->error = ESTR("hardware handler constructor failed"); | 654 | ti->error = "hardware handler constructor failed"; |
656 | return r; | 655 | return r; |
657 | } | 656 | } |
658 | 657 | ||
@@ -669,7 +668,7 @@ static int parse_features(struct arg_set *as, struct multipath *m, | |||
669 | unsigned argc; | 668 | unsigned argc; |
670 | 669 | ||
671 | static struct param _params[] = { | 670 | static struct param _params[] = { |
672 | {0, 1, ESTR("invalid number of feature args")}, | 671 | {0, 1, "invalid number of feature args"}, |
673 | }; | 672 | }; |
674 | 673 | ||
675 | r = read_param(_params, shift(as), &argc, &ti->error); | 674 | r = read_param(_params, shift(as), &argc, &ti->error); |
@@ -692,8 +691,8 @@ static int multipath_ctr(struct dm_target *ti, unsigned int argc, | |||
692 | { | 691 | { |
693 | /* target parameters */ | 692 | /* target parameters */ |
694 | static struct param _params[] = { | 693 | static struct param _params[] = { |
695 | {1, 1024, ESTR("invalid number of priority groups")}, | 694 | {1, 1024, "invalid number of priority groups"}, |
696 | {1, 1024, ESTR("invalid initial priority group number")}, | 695 | {1, 1024, "invalid initial priority group number"}, |
697 | }; | 696 | }; |
698 | 697 | ||
699 | int r; | 698 | int r; |
@@ -707,7 +706,7 @@ static int multipath_ctr(struct dm_target *ti, unsigned int argc, | |||
707 | 706 | ||
708 | m = alloc_multipath(); | 707 | m = alloc_multipath(); |
709 | if (!m) { | 708 | if (!m) { |
710 | ti->error = ESTR("can't allocate multipath"); | 709 | ti->error = "can't allocate multipath"; |
711 | return -EINVAL; | 710 | return -EINVAL; |
712 | } | 711 | } |
713 | 712 | ||
@@ -746,7 +745,7 @@ static int multipath_ctr(struct dm_target *ti, unsigned int argc, | |||
746 | } | 745 | } |
747 | 746 | ||
748 | if (pg_count != m->nr_priority_groups) { | 747 | if (pg_count != m->nr_priority_groups) { |
749 | ti->error = ESTR("priority group count mismatch"); | 748 | ti->error = "priority group count mismatch"; |
750 | r = -EINVAL; | 749 | r = -EINVAL; |
751 | goto bad; | 750 | goto bad; |
752 | } | 751 | } |
@@ -807,7 +806,7 @@ static int fail_path(struct pgpath *pgpath) | |||
807 | if (!pgpath->path.is_active) | 806 | if (!pgpath->path.is_active) |
808 | goto out; | 807 | goto out; |
809 | 808 | ||
810 | DMWARN("dm-multipath: Failing path %s.", pgpath->path.dev->name); | 809 | DMWARN("Failing path %s.", pgpath->path.dev->name); |
811 | 810 | ||
812 | pgpath->pg->ps.type->fail_path(&pgpath->pg->ps, &pgpath->path); | 811 | pgpath->pg->ps.type->fail_path(&pgpath->pg->ps, &pgpath->path); |
813 | pgpath->path.is_active = 0; | 812 | pgpath->path.is_active = 0; |
@@ -1250,7 +1249,7 @@ static int multipath_message(struct dm_target *ti, unsigned argc, char **argv) | |||
1250 | r = dm_get_device(ti, argv[1], ti->begin, ti->len, | 1249 | r = dm_get_device(ti, argv[1], ti->begin, ti->len, |
1251 | dm_table_get_mode(ti->table), &dev); | 1250 | dm_table_get_mode(ti->table), &dev); |
1252 | if (r) { | 1251 | if (r) { |
1253 | DMWARN("dm-multipath message: error getting device %s", | 1252 | DMWARN("message: error getting device %s", |
1254 | argv[1]); | 1253 | argv[1]); |
1255 | return -EINVAL; | 1254 | return -EINVAL; |
1256 | } | 1255 | } |
@@ -1309,7 +1308,7 @@ static int __init dm_multipath_init(void) | |||
1309 | return -ENOMEM; | 1308 | return -ENOMEM; |
1310 | } | 1309 | } |
1311 | 1310 | ||
1312 | DMINFO("dm-multipath version %u.%u.%u loaded", | 1311 | DMINFO("version %u.%u.%u loaded", |
1313 | multipath_target.version[0], multipath_target.version[1], | 1312 | multipath_target.version[0], multipath_target.version[1], |
1314 | multipath_target.version[2]); | 1313 | multipath_target.version[2]); |
1315 | 1314 | ||
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index d12cf3e5e076..be48cedf986b 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c | |||
@@ -20,6 +20,8 @@ | |||
20 | #include <linux/vmalloc.h> | 20 | #include <linux/vmalloc.h> |
21 | #include <linux/workqueue.h> | 21 | #include <linux/workqueue.h> |
22 | 22 | ||
23 | #define DM_MSG_PREFIX "raid1" | ||
24 | |||
23 | static struct workqueue_struct *_kmirrord_wq; | 25 | static struct workqueue_struct *_kmirrord_wq; |
24 | static struct work_struct _kmirrord_work; | 26 | static struct work_struct _kmirrord_work; |
25 | 27 | ||
@@ -106,12 +108,42 @@ struct region { | |||
106 | struct bio_list delayed_bios; | 108 | struct bio_list delayed_bios; |
107 | }; | 109 | }; |
108 | 110 | ||
111 | |||
112 | /*----------------------------------------------------------------- | ||
113 | * Mirror set structures. | ||
114 | *---------------------------------------------------------------*/ | ||
115 | struct mirror { | ||
116 | atomic_t error_count; | ||
117 | struct dm_dev *dev; | ||
118 | sector_t offset; | ||
119 | }; | ||
120 | |||
121 | struct mirror_set { | ||
122 | struct dm_target *ti; | ||
123 | struct list_head list; | ||
124 | struct region_hash rh; | ||
125 | struct kcopyd_client *kcopyd_client; | ||
126 | |||
127 | spinlock_t lock; /* protects the next two lists */ | ||
128 | struct bio_list reads; | ||
129 | struct bio_list writes; | ||
130 | |||
131 | /* recovery */ | ||
132 | region_t nr_regions; | ||
133 | int in_sync; | ||
134 | |||
135 | struct mirror *default_mirror; /* Default mirror */ | ||
136 | |||
137 | unsigned int nr_mirrors; | ||
138 | struct mirror mirror[0]; | ||
139 | }; | ||
140 | |||
109 | /* | 141 | /* |
110 | * Conversion fns | 142 | * Conversion fns |
111 | */ | 143 | */ |
112 | static inline region_t bio_to_region(struct region_hash *rh, struct bio *bio) | 144 | static inline region_t bio_to_region(struct region_hash *rh, struct bio *bio) |
113 | { | 145 | { |
114 | return bio->bi_sector >> rh->region_shift; | 146 | return (bio->bi_sector - rh->ms->ti->begin) >> rh->region_shift; |
115 | } | 147 | } |
116 | 148 | ||
117 | static inline sector_t region_to_sector(struct region_hash *rh, region_t region) | 149 | static inline sector_t region_to_sector(struct region_hash *rh, region_t region) |
@@ -458,11 +490,9 @@ static int __rh_recovery_prepare(struct region_hash *rh) | |||
458 | /* Already quiesced ? */ | 490 | /* Already quiesced ? */ |
459 | if (atomic_read(®->pending)) | 491 | if (atomic_read(®->pending)) |
460 | list_del_init(®->list); | 492 | list_del_init(®->list); |
493 | else | ||
494 | list_move(®->list, &rh->quiesced_regions); | ||
461 | 495 | ||
462 | else { | ||
463 | list_del_init(®->list); | ||
464 | list_add(®->list, &rh->quiesced_regions); | ||
465 | } | ||
466 | spin_unlock_irq(&rh->region_lock); | 496 | spin_unlock_irq(&rh->region_lock); |
467 | 497 | ||
468 | return 1; | 498 | return 1; |
@@ -541,35 +571,6 @@ static void rh_start_recovery(struct region_hash *rh) | |||
541 | wake(); | 571 | wake(); |
542 | } | 572 | } |
543 | 573 | ||
544 | /*----------------------------------------------------------------- | ||
545 | * Mirror set structures. | ||
546 | *---------------------------------------------------------------*/ | ||
547 | struct mirror { | ||
548 | atomic_t error_count; | ||
549 | struct dm_dev *dev; | ||
550 | sector_t offset; | ||
551 | }; | ||
552 | |||
553 | struct mirror_set { | ||
554 | struct dm_target *ti; | ||
555 | struct list_head list; | ||
556 | struct region_hash rh; | ||
557 | struct kcopyd_client *kcopyd_client; | ||
558 | |||
559 | spinlock_t lock; /* protects the next two lists */ | ||
560 | struct bio_list reads; | ||
561 | struct bio_list writes; | ||
562 | |||
563 | /* recovery */ | ||
564 | region_t nr_regions; | ||
565 | int in_sync; | ||
566 | |||
567 | struct mirror *default_mirror; /* Default mirror */ | ||
568 | |||
569 | unsigned int nr_mirrors; | ||
570 | struct mirror mirror[0]; | ||
571 | }; | ||
572 | |||
573 | /* | 574 | /* |
574 | * Every mirror should look like this one. | 575 | * Every mirror should look like this one. |
575 | */ | 576 | */ |
@@ -603,7 +604,7 @@ static void recovery_complete(int read_err, unsigned int write_err, | |||
603 | struct region *reg = (struct region *) context; | 604 | struct region *reg = (struct region *) context; |
604 | 605 | ||
605 | /* FIXME: better error handling */ | 606 | /* FIXME: better error handling */ |
606 | rh_recovery_end(reg, read_err || write_err); | 607 | rh_recovery_end(reg, !(read_err || write_err)); |
607 | } | 608 | } |
608 | 609 | ||
609 | static int recover(struct mirror_set *ms, struct region *reg) | 610 | static int recover(struct mirror_set *ms, struct region *reg) |
@@ -893,7 +894,7 @@ static struct mirror_set *alloc_context(unsigned int nr_mirrors, | |||
893 | 894 | ||
894 | ms = kmalloc(len, GFP_KERNEL); | 895 | ms = kmalloc(len, GFP_KERNEL); |
895 | if (!ms) { | 896 | if (!ms) { |
896 | ti->error = "dm-mirror: Cannot allocate mirror context"; | 897 | ti->error = "Cannot allocate mirror context"; |
897 | return NULL; | 898 | return NULL; |
898 | } | 899 | } |
899 | 900 | ||
@@ -907,7 +908,7 @@ static struct mirror_set *alloc_context(unsigned int nr_mirrors, | |||
907 | ms->default_mirror = &ms->mirror[DEFAULT_MIRROR]; | 908 | ms->default_mirror = &ms->mirror[DEFAULT_MIRROR]; |
908 | 909 | ||
909 | if (rh_init(&ms->rh, ms, dl, region_size, ms->nr_regions)) { | 910 | if (rh_init(&ms->rh, ms, dl, region_size, ms->nr_regions)) { |
910 | ti->error = "dm-mirror: Error creating dirty region hash"; | 911 | ti->error = "Error creating dirty region hash"; |
911 | kfree(ms); | 912 | kfree(ms); |
912 | return NULL; | 913 | return NULL; |
913 | } | 914 | } |
@@ -937,14 +938,14 @@ static int get_mirror(struct mirror_set *ms, struct dm_target *ti, | |||
937 | unsigned long long offset; | 938 | unsigned long long offset; |
938 | 939 | ||
939 | if (sscanf(argv[1], "%llu", &offset) != 1) { | 940 | if (sscanf(argv[1], "%llu", &offset) != 1) { |
940 | ti->error = "dm-mirror: Invalid offset"; | 941 | ti->error = "Invalid offset"; |
941 | return -EINVAL; | 942 | return -EINVAL; |
942 | } | 943 | } |
943 | 944 | ||
944 | if (dm_get_device(ti, argv[0], offset, ti->len, | 945 | if (dm_get_device(ti, argv[0], offset, ti->len, |
945 | dm_table_get_mode(ti->table), | 946 | dm_table_get_mode(ti->table), |
946 | &ms->mirror[mirror].dev)) { | 947 | &ms->mirror[mirror].dev)) { |
947 | ti->error = "dm-mirror: Device lookup failure"; | 948 | ti->error = "Device lookup failure"; |
948 | return -ENXIO; | 949 | return -ENXIO; |
949 | } | 950 | } |
950 | 951 | ||
@@ -981,30 +982,30 @@ static struct dirty_log *create_dirty_log(struct dm_target *ti, | |||
981 | struct dirty_log *dl; | 982 | struct dirty_log *dl; |
982 | 983 | ||
983 | if (argc < 2) { | 984 | if (argc < 2) { |
984 | ti->error = "dm-mirror: Insufficient mirror log arguments"; | 985 | ti->error = "Insufficient mirror log arguments"; |
985 | return NULL; | 986 | return NULL; |
986 | } | 987 | } |
987 | 988 | ||
988 | if (sscanf(argv[1], "%u", ¶m_count) != 1) { | 989 | if (sscanf(argv[1], "%u", ¶m_count) != 1) { |
989 | ti->error = "dm-mirror: Invalid mirror log argument count"; | 990 | ti->error = "Invalid mirror log argument count"; |
990 | return NULL; | 991 | return NULL; |
991 | } | 992 | } |
992 | 993 | ||
993 | *args_used = 2 + param_count; | 994 | *args_used = 2 + param_count; |
994 | 995 | ||
995 | if (argc < *args_used) { | 996 | if (argc < *args_used) { |
996 | ti->error = "dm-mirror: Insufficient mirror log arguments"; | 997 | ti->error = "Insufficient mirror log arguments"; |
997 | return NULL; | 998 | return NULL; |
998 | } | 999 | } |
999 | 1000 | ||
1000 | dl = dm_create_dirty_log(argv[0], ti, param_count, argv + 2); | 1001 | dl = dm_create_dirty_log(argv[0], ti, param_count, argv + 2); |
1001 | if (!dl) { | 1002 | if (!dl) { |
1002 | ti->error = "dm-mirror: Error creating mirror dirty log"; | 1003 | ti->error = "Error creating mirror dirty log"; |
1003 | return NULL; | 1004 | return NULL; |
1004 | } | 1005 | } |
1005 | 1006 | ||
1006 | if (!_check_region_size(ti, dl->type->get_region_size(dl))) { | 1007 | if (!_check_region_size(ti, dl->type->get_region_size(dl))) { |
1007 | ti->error = "dm-mirror: Invalid region size"; | 1008 | ti->error = "Invalid region size"; |
1008 | dm_destroy_dirty_log(dl); | 1009 | dm_destroy_dirty_log(dl); |
1009 | return NULL; | 1010 | return NULL; |
1010 | } | 1011 | } |
@@ -1038,7 +1039,7 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
1038 | 1039 | ||
1039 | if (!argc || sscanf(argv[0], "%u", &nr_mirrors) != 1 || | 1040 | if (!argc || sscanf(argv[0], "%u", &nr_mirrors) != 1 || |
1040 | nr_mirrors < 2 || nr_mirrors > KCOPYD_MAX_REGIONS + 1) { | 1041 | nr_mirrors < 2 || nr_mirrors > KCOPYD_MAX_REGIONS + 1) { |
1041 | ti->error = "dm-mirror: Invalid number of mirrors"; | 1042 | ti->error = "Invalid number of mirrors"; |
1042 | dm_destroy_dirty_log(dl); | 1043 | dm_destroy_dirty_log(dl); |
1043 | return -EINVAL; | 1044 | return -EINVAL; |
1044 | } | 1045 | } |
@@ -1046,7 +1047,7 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
1046 | argv++, argc--; | 1047 | argv++, argc--; |
1047 | 1048 | ||
1048 | if (argc != nr_mirrors * 2) { | 1049 | if (argc != nr_mirrors * 2) { |
1049 | ti->error = "dm-mirror: Wrong number of mirror arguments"; | 1050 | ti->error = "Wrong number of mirror arguments"; |
1050 | dm_destroy_dirty_log(dl); | 1051 | dm_destroy_dirty_log(dl); |
1051 | return -EINVAL; | 1052 | return -EINVAL; |
1052 | } | 1053 | } |
@@ -1115,7 +1116,7 @@ static int mirror_map(struct dm_target *ti, struct bio *bio, | |||
1115 | struct mirror *m; | 1116 | struct mirror *m; |
1116 | struct mirror_set *ms = ti->private; | 1117 | struct mirror_set *ms = ti->private; |
1117 | 1118 | ||
1118 | map_context->ll = bio->bi_sector >> ms->rh.region_shift; | 1119 | map_context->ll = bio_to_region(&ms->rh, bio); |
1119 | 1120 | ||
1120 | if (rw == WRITE) { | 1121 | if (rw == WRITE) { |
1121 | queue_bio(ms, bio, rw); | 1122 | queue_bio(ms, bio, rw); |
@@ -1221,7 +1222,7 @@ static int mirror_status(struct dm_target *ti, status_type_t type, | |||
1221 | 1222 | ||
1222 | static struct target_type mirror_target = { | 1223 | static struct target_type mirror_target = { |
1223 | .name = "mirror", | 1224 | .name = "mirror", |
1224 | .version = {1, 0, 1}, | 1225 | .version = {1, 0, 2}, |
1225 | .module = THIS_MODULE, | 1226 | .module = THIS_MODULE, |
1226 | .ctr = mirror_ctr, | 1227 | .ctr = mirror_ctr, |
1227 | .dtr = mirror_dtr, | 1228 | .dtr = mirror_dtr, |
diff --git a/drivers/md/dm-round-robin.c b/drivers/md/dm-round-robin.c index d0024865a789..c5a16c550122 100644 --- a/drivers/md/dm-round-robin.c +++ b/drivers/md/dm-round-robin.c | |||
@@ -14,6 +14,8 @@ | |||
14 | 14 | ||
15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
16 | 16 | ||
17 | #define DM_MSG_PREFIX "multipath round-robin" | ||
18 | |||
17 | /*----------------------------------------------------------------- | 19 | /*----------------------------------------------------------------- |
18 | * Path-handling code, paths are held in lists | 20 | * Path-handling code, paths are held in lists |
19 | *---------------------------------------------------------------*/ | 21 | *---------------------------------------------------------------*/ |
@@ -191,9 +193,9 @@ static int __init dm_rr_init(void) | |||
191 | int r = dm_register_path_selector(&rr_ps); | 193 | int r = dm_register_path_selector(&rr_ps); |
192 | 194 | ||
193 | if (r < 0) | 195 | if (r < 0) |
194 | DMERR("round-robin: register failed %d", r); | 196 | DMERR("register failed %d", r); |
195 | 197 | ||
196 | DMINFO("dm-round-robin version 1.0.0 loaded"); | 198 | DMINFO("version 1.0.0 loaded"); |
197 | 199 | ||
198 | return r; | 200 | return r; |
199 | } | 201 | } |
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index 08312b46463a..8eea0ddbf5ec 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c | |||
@@ -23,6 +23,8 @@ | |||
23 | #include "dm-bio-list.h" | 23 | #include "dm-bio-list.h" |
24 | #include "kcopyd.h" | 24 | #include "kcopyd.h" |
25 | 25 | ||
26 | #define DM_MSG_PREFIX "snapshots" | ||
27 | |||
26 | /* | 28 | /* |
27 | * The percentage increment we will wake up users at | 29 | * The percentage increment we will wake up users at |
28 | */ | 30 | */ |
@@ -117,7 +119,7 @@ static int init_origin_hash(void) | |||
117 | _origins = kmalloc(ORIGIN_HASH_SIZE * sizeof(struct list_head), | 119 | _origins = kmalloc(ORIGIN_HASH_SIZE * sizeof(struct list_head), |
118 | GFP_KERNEL); | 120 | GFP_KERNEL); |
119 | if (!_origins) { | 121 | if (!_origins) { |
120 | DMERR("Device mapper: Snapshot: unable to allocate memory"); | 122 | DMERR("unable to allocate memory"); |
121 | return -ENOMEM; | 123 | return -ENOMEM; |
122 | } | 124 | } |
123 | 125 | ||
@@ -412,7 +414,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
412 | int blocksize; | 414 | int blocksize; |
413 | 415 | ||
414 | if (argc < 4) { | 416 | if (argc < 4) { |
415 | ti->error = "dm-snapshot: requires exactly 4 arguments"; | 417 | ti->error = "requires exactly 4 arguments"; |
416 | r = -EINVAL; | 418 | r = -EINVAL; |
417 | goto bad1; | 419 | goto bad1; |
418 | } | 420 | } |
@@ -530,7 +532,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
530 | } | 532 | } |
531 | 533 | ||
532 | ti->private = s; | 534 | ti->private = s; |
533 | ti->split_io = chunk_size; | 535 | ti->split_io = s->chunk_size; |
534 | 536 | ||
535 | return 0; | 537 | return 0; |
536 | 538 | ||
@@ -1127,7 +1129,7 @@ static int origin_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
1127 | struct dm_dev *dev; | 1129 | struct dm_dev *dev; |
1128 | 1130 | ||
1129 | if (argc != 1) { | 1131 | if (argc != 1) { |
1130 | ti->error = "dm-origin: incorrect number of arguments"; | 1132 | ti->error = "origin: incorrect number of arguments"; |
1131 | return -EINVAL; | 1133 | return -EINVAL; |
1132 | } | 1134 | } |
1133 | 1135 | ||
@@ -1204,7 +1206,7 @@ static int origin_status(struct dm_target *ti, status_type_t type, char *result, | |||
1204 | 1206 | ||
1205 | static struct target_type origin_target = { | 1207 | static struct target_type origin_target = { |
1206 | .name = "snapshot-origin", | 1208 | .name = "snapshot-origin", |
1207 | .version = {1, 1, 0}, | 1209 | .version = {1, 4, 0}, |
1208 | .module = THIS_MODULE, | 1210 | .module = THIS_MODULE, |
1209 | .ctr = origin_ctr, | 1211 | .ctr = origin_ctr, |
1210 | .dtr = origin_dtr, | 1212 | .dtr = origin_dtr, |
@@ -1215,7 +1217,7 @@ static struct target_type origin_target = { | |||
1215 | 1217 | ||
1216 | static struct target_type snapshot_target = { | 1218 | static struct target_type snapshot_target = { |
1217 | .name = "snapshot", | 1219 | .name = "snapshot", |
1218 | .version = {1, 1, 0}, | 1220 | .version = {1, 4, 0}, |
1219 | .module = THIS_MODULE, | 1221 | .module = THIS_MODULE, |
1220 | .ctr = snapshot_ctr, | 1222 | .ctr = snapshot_ctr, |
1221 | .dtr = snapshot_dtr, | 1223 | .dtr = snapshot_dtr, |
@@ -1236,7 +1238,7 @@ static int __init dm_snapshot_init(void) | |||
1236 | 1238 | ||
1237 | r = dm_register_target(&origin_target); | 1239 | r = dm_register_target(&origin_target); |
1238 | if (r < 0) { | 1240 | if (r < 0) { |
1239 | DMERR("Device mapper: Origin: register failed %d\n", r); | 1241 | DMERR("Origin target register failed %d", r); |
1240 | goto bad1; | 1242 | goto bad1; |
1241 | } | 1243 | } |
1242 | 1244 | ||
diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c index 08328a8f5a3c..6c29fcecd892 100644 --- a/drivers/md/dm-stripe.c +++ b/drivers/md/dm-stripe.c | |||
@@ -12,6 +12,8 @@ | |||
12 | #include <linux/bio.h> | 12 | #include <linux/bio.h> |
13 | #include <linux/slab.h> | 13 | #include <linux/slab.h> |
14 | 14 | ||
15 | #define DM_MSG_PREFIX "striped" | ||
16 | |||
15 | struct stripe { | 17 | struct stripe { |
16 | struct dm_dev *dev; | 18 | struct dm_dev *dev; |
17 | sector_t physical_start; | 19 | sector_t physical_start; |
@@ -78,19 +80,19 @@ static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
78 | unsigned int i; | 80 | unsigned int i; |
79 | 81 | ||
80 | if (argc < 2) { | 82 | if (argc < 2) { |
81 | ti->error = "dm-stripe: Not enough arguments"; | 83 | ti->error = "Not enough arguments"; |
82 | return -EINVAL; | 84 | return -EINVAL; |
83 | } | 85 | } |
84 | 86 | ||
85 | stripes = simple_strtoul(argv[0], &end, 10); | 87 | stripes = simple_strtoul(argv[0], &end, 10); |
86 | if (*end) { | 88 | if (*end) { |
87 | ti->error = "dm-stripe: Invalid stripe count"; | 89 | ti->error = "Invalid stripe count"; |
88 | return -EINVAL; | 90 | return -EINVAL; |
89 | } | 91 | } |
90 | 92 | ||
91 | chunk_size = simple_strtoul(argv[1], &end, 10); | 93 | chunk_size = simple_strtoul(argv[1], &end, 10); |
92 | if (*end) { | 94 | if (*end) { |
93 | ti->error = "dm-stripe: Invalid chunk_size"; | 95 | ti->error = "Invalid chunk_size"; |
94 | return -EINVAL; | 96 | return -EINVAL; |
95 | } | 97 | } |
96 | 98 | ||
@@ -99,19 +101,19 @@ static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
99 | */ | 101 | */ |
100 | if (!chunk_size || (chunk_size & (chunk_size - 1)) || | 102 | if (!chunk_size || (chunk_size & (chunk_size - 1)) || |
101 | (chunk_size < (PAGE_SIZE >> SECTOR_SHIFT))) { | 103 | (chunk_size < (PAGE_SIZE >> SECTOR_SHIFT))) { |
102 | ti->error = "dm-stripe: Invalid chunk size"; | 104 | ti->error = "Invalid chunk size"; |
103 | return -EINVAL; | 105 | return -EINVAL; |
104 | } | 106 | } |
105 | 107 | ||
106 | if (ti->len & (chunk_size - 1)) { | 108 | if (ti->len & (chunk_size - 1)) { |
107 | ti->error = "dm-stripe: Target length not divisible by " | 109 | ti->error = "Target length not divisible by " |
108 | "chunk size"; | 110 | "chunk size"; |
109 | return -EINVAL; | 111 | return -EINVAL; |
110 | } | 112 | } |
111 | 113 | ||
112 | width = ti->len; | 114 | width = ti->len; |
113 | if (sector_div(width, stripes)) { | 115 | if (sector_div(width, stripes)) { |
114 | ti->error = "dm-stripe: Target length not divisible by " | 116 | ti->error = "Target length not divisible by " |
115 | "number of stripes"; | 117 | "number of stripes"; |
116 | return -EINVAL; | 118 | return -EINVAL; |
117 | } | 119 | } |
@@ -120,14 +122,14 @@ static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
120 | * Do we have enough arguments for that many stripes ? | 122 | * Do we have enough arguments for that many stripes ? |
121 | */ | 123 | */ |
122 | if (argc != (2 + 2 * stripes)) { | 124 | if (argc != (2 + 2 * stripes)) { |
123 | ti->error = "dm-stripe: Not enough destinations " | 125 | ti->error = "Not enough destinations " |
124 | "specified"; | 126 | "specified"; |
125 | return -EINVAL; | 127 | return -EINVAL; |
126 | } | 128 | } |
127 | 129 | ||
128 | sc = alloc_context(stripes); | 130 | sc = alloc_context(stripes); |
129 | if (!sc) { | 131 | if (!sc) { |
130 | ti->error = "dm-stripe: Memory allocation for striped context " | 132 | ti->error = "Memory allocation for striped context " |
131 | "failed"; | 133 | "failed"; |
132 | return -ENOMEM; | 134 | return -ENOMEM; |
133 | } | 135 | } |
@@ -149,8 +151,7 @@ static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
149 | 151 | ||
150 | r = get_stripe(ti, sc, i, argv); | 152 | r = get_stripe(ti, sc, i, argv); |
151 | if (r < 0) { | 153 | if (r < 0) { |
152 | ti->error = "dm-stripe: Couldn't parse stripe " | 154 | ti->error = "Couldn't parse stripe destination"; |
153 | "destination"; | ||
154 | while (i--) | 155 | while (i--) |
155 | dm_put_device(ti, sc->stripe[i].dev); | 156 | dm_put_device(ti, sc->stripe[i].dev); |
156 | kfree(sc); | 157 | kfree(sc); |
@@ -227,7 +228,7 @@ int __init dm_stripe_init(void) | |||
227 | 228 | ||
228 | r = dm_register_target(&stripe_target); | 229 | r = dm_register_target(&stripe_target); |
229 | if (r < 0) | 230 | if (r < 0) |
230 | DMWARN("striped target registration failed"); | 231 | DMWARN("target registration failed"); |
231 | 232 | ||
232 | return r; | 233 | return r; |
233 | } | 234 | } |
@@ -235,7 +236,7 @@ int __init dm_stripe_init(void) | |||
235 | void dm_stripe_exit(void) | 236 | void dm_stripe_exit(void) |
236 | { | 237 | { |
237 | if (dm_unregister_target(&stripe_target)) | 238 | if (dm_unregister_target(&stripe_target)) |
238 | DMWARN("striped target unregistration failed"); | 239 | DMWARN("target unregistration failed"); |
239 | 240 | ||
240 | return; | 241 | return; |
241 | } | 242 | } |
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 8f56a54cf0ce..75fe9493e6af 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c | |||
@@ -17,6 +17,8 @@ | |||
17 | #include <linux/mutex.h> | 17 | #include <linux/mutex.h> |
18 | #include <asm/atomic.h> | 18 | #include <asm/atomic.h> |
19 | 19 | ||
20 | #define DM_MSG_PREFIX "table" | ||
21 | |||
20 | #define MAX_DEPTH 16 | 22 | #define MAX_DEPTH 16 |
21 | #define NODE_SIZE L1_CACHE_BYTES | 23 | #define NODE_SIZE L1_CACHE_BYTES |
22 | #define KEYS_PER_NODE (NODE_SIZE / sizeof(sector_t)) | 24 | #define KEYS_PER_NODE (NODE_SIZE / sizeof(sector_t)) |
@@ -237,6 +239,44 @@ int dm_table_create(struct dm_table **result, int mode, | |||
237 | return 0; | 239 | return 0; |
238 | } | 240 | } |
239 | 241 | ||
242 | int dm_create_error_table(struct dm_table **result, struct mapped_device *md) | ||
243 | { | ||
244 | struct dm_table *t; | ||
245 | sector_t dev_size = 1; | ||
246 | int r; | ||
247 | |||
248 | /* | ||
249 | * Find current size of device. | ||
250 | * Default to 1 sector if inactive. | ||
251 | */ | ||
252 | t = dm_get_table(md); | ||
253 | if (t) { | ||
254 | dev_size = dm_table_get_size(t); | ||
255 | dm_table_put(t); | ||
256 | } | ||
257 | |||
258 | r = dm_table_create(&t, FMODE_READ, 1, md); | ||
259 | if (r) | ||
260 | return r; | ||
261 | |||
262 | r = dm_table_add_target(t, "error", 0, dev_size, NULL); | ||
263 | if (r) | ||
264 | goto out; | ||
265 | |||
266 | r = dm_table_complete(t); | ||
267 | if (r) | ||
268 | goto out; | ||
269 | |||
270 | *result = t; | ||
271 | |||
272 | out: | ||
273 | if (r) | ||
274 | dm_table_put(t); | ||
275 | |||
276 | return r; | ||
277 | } | ||
278 | EXPORT_SYMBOL_GPL(dm_create_error_table); | ||
279 | |||
240 | static void free_devices(struct list_head *devices) | 280 | static void free_devices(struct list_head *devices) |
241 | { | 281 | { |
242 | struct list_head *tmp, *next; | 282 | struct list_head *tmp, *next; |
@@ -590,6 +630,12 @@ int dm_split_args(int *argc, char ***argvp, char *input) | |||
590 | unsigned array_size = 0; | 630 | unsigned array_size = 0; |
591 | 631 | ||
592 | *argc = 0; | 632 | *argc = 0; |
633 | |||
634 | if (!input) { | ||
635 | *argvp = NULL; | ||
636 | return 0; | ||
637 | } | ||
638 | |||
593 | argv = realloc_argv(&array_size, argv); | 639 | argv = realloc_argv(&array_size, argv); |
594 | if (!argv) | 640 | if (!argv) |
595 | return -ENOMEM; | 641 | return -ENOMEM; |
@@ -671,15 +717,14 @@ int dm_table_add_target(struct dm_table *t, const char *type, | |||
671 | memset(tgt, 0, sizeof(*tgt)); | 717 | memset(tgt, 0, sizeof(*tgt)); |
672 | 718 | ||
673 | if (!len) { | 719 | if (!len) { |
674 | tgt->error = "zero-length target"; | 720 | DMERR("%s: zero-length target", dm_device_name(t->md)); |
675 | DMERR("%s", tgt->error); | ||
676 | return -EINVAL; | 721 | return -EINVAL; |
677 | } | 722 | } |
678 | 723 | ||
679 | tgt->type = dm_get_target_type(type); | 724 | tgt->type = dm_get_target_type(type); |
680 | if (!tgt->type) { | 725 | if (!tgt->type) { |
681 | tgt->error = "unknown target type"; | 726 | DMERR("%s: %s: unknown target type", dm_device_name(t->md), |
682 | DMERR("%s", tgt->error); | 727 | type); |
683 | return -EINVAL; | 728 | return -EINVAL; |
684 | } | 729 | } |
685 | 730 | ||
@@ -716,7 +761,7 @@ int dm_table_add_target(struct dm_table *t, const char *type, | |||
716 | return 0; | 761 | return 0; |
717 | 762 | ||
718 | bad: | 763 | bad: |
719 | DMERR("%s", tgt->error); | 764 | DMERR("%s: %s: %s", dm_device_name(t->md), type, tgt->error); |
720 | dm_put_target_type(tgt->type); | 765 | dm_put_target_type(tgt->type); |
721 | return r; | 766 | return r; |
722 | } | 767 | } |
@@ -802,7 +847,7 @@ sector_t dm_table_get_size(struct dm_table *t) | |||
802 | 847 | ||
803 | struct dm_target *dm_table_get_target(struct dm_table *t, unsigned int index) | 848 | struct dm_target *dm_table_get_target(struct dm_table *t, unsigned int index) |
804 | { | 849 | { |
805 | if (index > t->num_targets) | 850 | if (index >= t->num_targets) |
806 | return NULL; | 851 | return NULL; |
807 | 852 | ||
808 | return t->targets + index; | 853 | return t->targets + index; |
diff --git a/drivers/md/dm-target.c b/drivers/md/dm-target.c index 64fd8e79ea4c..477a041a41cf 100644 --- a/drivers/md/dm-target.c +++ b/drivers/md/dm-target.c | |||
@@ -12,6 +12,8 @@ | |||
12 | #include <linux/bio.h> | 12 | #include <linux/bio.h> |
13 | #include <linux/slab.h> | 13 | #include <linux/slab.h> |
14 | 14 | ||
15 | #define DM_MSG_PREFIX "target" | ||
16 | |||
15 | struct tt_internal { | 17 | struct tt_internal { |
16 | struct target_type tt; | 18 | struct target_type tt; |
17 | 19 | ||
diff --git a/drivers/md/dm-zero.c b/drivers/md/dm-zero.c index 51c0639b2487..ea569f7348d2 100644 --- a/drivers/md/dm-zero.c +++ b/drivers/md/dm-zero.c | |||
@@ -10,13 +10,15 @@ | |||
10 | #include <linux/init.h> | 10 | #include <linux/init.h> |
11 | #include <linux/bio.h> | 11 | #include <linux/bio.h> |
12 | 12 | ||
13 | #define DM_MSG_PREFIX "zero" | ||
14 | |||
13 | /* | 15 | /* |
14 | * Construct a dummy mapping that only returns zeros | 16 | * Construct a dummy mapping that only returns zeros |
15 | */ | 17 | */ |
16 | static int zero_ctr(struct dm_target *ti, unsigned int argc, char **argv) | 18 | static int zero_ctr(struct dm_target *ti, unsigned int argc, char **argv) |
17 | { | 19 | { |
18 | if (argc != 0) { | 20 | if (argc != 0) { |
19 | ti->error = "dm-zero: No arguments required"; | 21 | ti->error = "No arguments required"; |
20 | return -EINVAL; | 22 | return -EINVAL; |
21 | } | 23 | } |
22 | 24 | ||
@@ -60,7 +62,7 @@ static int __init dm_zero_init(void) | |||
60 | int r = dm_register_target(&zero_target); | 62 | int r = dm_register_target(&zero_target); |
61 | 63 | ||
62 | if (r < 0) | 64 | if (r < 0) |
63 | DMERR("zero: register failed %d", r); | 65 | DMERR("register failed %d", r); |
64 | 66 | ||
65 | return r; | 67 | return r; |
66 | } | 68 | } |
@@ -70,7 +72,7 @@ static void __exit dm_zero_exit(void) | |||
70 | int r = dm_unregister_target(&zero_target); | 72 | int r = dm_unregister_target(&zero_target); |
71 | 73 | ||
72 | if (r < 0) | 74 | if (r < 0) |
73 | DMERR("zero: unregister failed %d", r); | 75 | DMERR("unregister failed %d", r); |
74 | } | 76 | } |
75 | 77 | ||
76 | module_init(dm_zero_init) | 78 | module_init(dm_zero_init) |
diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 4d710b7a133b..3ed2e53b9eb6 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2001, 2002 Sistina Software (UK) Limited. | 2 | * Copyright (C) 2001, 2002 Sistina Software (UK) Limited. |
3 | * Copyright (C) 2004 Red Hat, Inc. All rights reserved. | 3 | * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. |
4 | * | 4 | * |
5 | * This file is released under the GPL. | 5 | * This file is released under the GPL. |
6 | */ | 6 | */ |
@@ -21,11 +21,14 @@ | |||
21 | #include <linux/hdreg.h> | 21 | #include <linux/hdreg.h> |
22 | #include <linux/blktrace_api.h> | 22 | #include <linux/blktrace_api.h> |
23 | 23 | ||
24 | #define DM_MSG_PREFIX "core" | ||
25 | |||
24 | static const char *_name = DM_NAME; | 26 | static const char *_name = DM_NAME; |
25 | 27 | ||
26 | static unsigned int major = 0; | 28 | static unsigned int major = 0; |
27 | static unsigned int _major = 0; | 29 | static unsigned int _major = 0; |
28 | 30 | ||
31 | static DEFINE_SPINLOCK(_minor_lock); | ||
29 | /* | 32 | /* |
30 | * One of these is allocated per bio. | 33 | * One of these is allocated per bio. |
31 | */ | 34 | */ |
@@ -49,23 +52,28 @@ struct target_io { | |||
49 | 52 | ||
50 | union map_info *dm_get_mapinfo(struct bio *bio) | 53 | union map_info *dm_get_mapinfo(struct bio *bio) |
51 | { | 54 | { |
52 | if (bio && bio->bi_private) | 55 | if (bio && bio->bi_private) |
53 | return &((struct target_io *)bio->bi_private)->info; | 56 | return &((struct target_io *)bio->bi_private)->info; |
54 | return NULL; | 57 | return NULL; |
55 | } | 58 | } |
56 | 59 | ||
60 | #define MINOR_ALLOCED ((void *)-1) | ||
61 | |||
57 | /* | 62 | /* |
58 | * Bits for the md->flags field. | 63 | * Bits for the md->flags field. |
59 | */ | 64 | */ |
60 | #define DMF_BLOCK_IO 0 | 65 | #define DMF_BLOCK_IO 0 |
61 | #define DMF_SUSPENDED 1 | 66 | #define DMF_SUSPENDED 1 |
62 | #define DMF_FROZEN 2 | 67 | #define DMF_FROZEN 2 |
68 | #define DMF_FREEING 3 | ||
69 | #define DMF_DELETING 4 | ||
63 | 70 | ||
64 | struct mapped_device { | 71 | struct mapped_device { |
65 | struct rw_semaphore io_lock; | 72 | struct rw_semaphore io_lock; |
66 | struct semaphore suspend_lock; | 73 | struct semaphore suspend_lock; |
67 | rwlock_t map_lock; | 74 | rwlock_t map_lock; |
68 | atomic_t holders; | 75 | atomic_t holders; |
76 | atomic_t open_count; | ||
69 | 77 | ||
70 | unsigned long flags; | 78 | unsigned long flags; |
71 | 79 | ||
@@ -218,9 +226,25 @@ static int dm_blk_open(struct inode *inode, struct file *file) | |||
218 | { | 226 | { |
219 | struct mapped_device *md; | 227 | struct mapped_device *md; |
220 | 228 | ||
229 | spin_lock(&_minor_lock); | ||
230 | |||
221 | md = inode->i_bdev->bd_disk->private_data; | 231 | md = inode->i_bdev->bd_disk->private_data; |
232 | if (!md) | ||
233 | goto out; | ||
234 | |||
235 | if (test_bit(DMF_FREEING, &md->flags) || | ||
236 | test_bit(DMF_DELETING, &md->flags)) { | ||
237 | md = NULL; | ||
238 | goto out; | ||
239 | } | ||
240 | |||
222 | dm_get(md); | 241 | dm_get(md); |
223 | return 0; | 242 | atomic_inc(&md->open_count); |
243 | |||
244 | out: | ||
245 | spin_unlock(&_minor_lock); | ||
246 | |||
247 | return md ? 0 : -ENXIO; | ||
224 | } | 248 | } |
225 | 249 | ||
226 | static int dm_blk_close(struct inode *inode, struct file *file) | 250 | static int dm_blk_close(struct inode *inode, struct file *file) |
@@ -228,10 +252,35 @@ static int dm_blk_close(struct inode *inode, struct file *file) | |||
228 | struct mapped_device *md; | 252 | struct mapped_device *md; |
229 | 253 | ||
230 | md = inode->i_bdev->bd_disk->private_data; | 254 | md = inode->i_bdev->bd_disk->private_data; |
255 | atomic_dec(&md->open_count); | ||
231 | dm_put(md); | 256 | dm_put(md); |
232 | return 0; | 257 | return 0; |
233 | } | 258 | } |
234 | 259 | ||
260 | int dm_open_count(struct mapped_device *md) | ||
261 | { | ||
262 | return atomic_read(&md->open_count); | ||
263 | } | ||
264 | |||
265 | /* | ||
266 | * Guarantees nothing is using the device before it's deleted. | ||
267 | */ | ||
268 | int dm_lock_for_deletion(struct mapped_device *md) | ||
269 | { | ||
270 | int r = 0; | ||
271 | |||
272 | spin_lock(&_minor_lock); | ||
273 | |||
274 | if (dm_open_count(md)) | ||
275 | r = -EBUSY; | ||
276 | else | ||
277 | set_bit(DMF_DELETING, &md->flags); | ||
278 | |||
279 | spin_unlock(&_minor_lock); | ||
280 | |||
281 | return r; | ||
282 | } | ||
283 | |||
235 | static int dm_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo) | 284 | static int dm_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo) |
236 | { | 285 | { |
237 | struct mapped_device *md = bdev->bd_disk->private_data; | 286 | struct mapped_device *md = bdev->bd_disk->private_data; |
@@ -456,8 +505,8 @@ static void __map_bio(struct dm_target *ti, struct bio *clone, | |||
456 | if (r > 0) { | 505 | if (r > 0) { |
457 | /* the bio has been remapped so dispatch it */ | 506 | /* the bio has been remapped so dispatch it */ |
458 | 507 | ||
459 | blk_add_trace_remap(bdev_get_queue(clone->bi_bdev), clone, | 508 | blk_add_trace_remap(bdev_get_queue(clone->bi_bdev), clone, |
460 | tio->io->bio->bi_bdev->bd_dev, sector, | 509 | tio->io->bio->bi_bdev->bd_dev, sector, |
461 | clone->bi_sector); | 510 | clone->bi_sector); |
462 | 511 | ||
463 | generic_make_request(clone); | 512 | generic_make_request(clone); |
@@ -744,43 +793,39 @@ static int dm_any_congested(void *congested_data, int bdi_bits) | |||
744 | /*----------------------------------------------------------------- | 793 | /*----------------------------------------------------------------- |
745 | * An IDR is used to keep track of allocated minor numbers. | 794 | * An IDR is used to keep track of allocated minor numbers. |
746 | *---------------------------------------------------------------*/ | 795 | *---------------------------------------------------------------*/ |
747 | static DEFINE_MUTEX(_minor_lock); | ||
748 | static DEFINE_IDR(_minor_idr); | 796 | static DEFINE_IDR(_minor_idr); |
749 | 797 | ||
750 | static void free_minor(unsigned int minor) | 798 | static void free_minor(int minor) |
751 | { | 799 | { |
752 | mutex_lock(&_minor_lock); | 800 | spin_lock(&_minor_lock); |
753 | idr_remove(&_minor_idr, minor); | 801 | idr_remove(&_minor_idr, minor); |
754 | mutex_unlock(&_minor_lock); | 802 | spin_unlock(&_minor_lock); |
755 | } | 803 | } |
756 | 804 | ||
757 | /* | 805 | /* |
758 | * See if the device with a specific minor # is free. | 806 | * See if the device with a specific minor # is free. |
759 | */ | 807 | */ |
760 | static int specific_minor(struct mapped_device *md, unsigned int minor) | 808 | static int specific_minor(struct mapped_device *md, int minor) |
761 | { | 809 | { |
762 | int r, m; | 810 | int r, m; |
763 | 811 | ||
764 | if (minor >= (1 << MINORBITS)) | 812 | if (minor >= (1 << MINORBITS)) |
765 | return -EINVAL; | 813 | return -EINVAL; |
766 | 814 | ||
767 | mutex_lock(&_minor_lock); | 815 | r = idr_pre_get(&_minor_idr, GFP_KERNEL); |
816 | if (!r) | ||
817 | return -ENOMEM; | ||
818 | |||
819 | spin_lock(&_minor_lock); | ||
768 | 820 | ||
769 | if (idr_find(&_minor_idr, minor)) { | 821 | if (idr_find(&_minor_idr, minor)) { |
770 | r = -EBUSY; | 822 | r = -EBUSY; |
771 | goto out; | 823 | goto out; |
772 | } | 824 | } |
773 | 825 | ||
774 | r = idr_pre_get(&_minor_idr, GFP_KERNEL); | 826 | r = idr_get_new_above(&_minor_idr, MINOR_ALLOCED, minor, &m); |
775 | if (!r) { | 827 | if (r) |
776 | r = -ENOMEM; | ||
777 | goto out; | ||
778 | } | ||
779 | |||
780 | r = idr_get_new_above(&_minor_idr, md, minor, &m); | ||
781 | if (r) { | ||
782 | goto out; | 828 | goto out; |
783 | } | ||
784 | 829 | ||
785 | if (m != minor) { | 830 | if (m != minor) { |
786 | idr_remove(&_minor_idr, m); | 831 | idr_remove(&_minor_idr, m); |
@@ -789,24 +834,21 @@ static int specific_minor(struct mapped_device *md, unsigned int minor) | |||
789 | } | 834 | } |
790 | 835 | ||
791 | out: | 836 | out: |
792 | mutex_unlock(&_minor_lock); | 837 | spin_unlock(&_minor_lock); |
793 | return r; | 838 | return r; |
794 | } | 839 | } |
795 | 840 | ||
796 | static int next_free_minor(struct mapped_device *md, unsigned int *minor) | 841 | static int next_free_minor(struct mapped_device *md, int *minor) |
797 | { | 842 | { |
798 | int r; | 843 | int r, m; |
799 | unsigned int m; | ||
800 | |||
801 | mutex_lock(&_minor_lock); | ||
802 | 844 | ||
803 | r = idr_pre_get(&_minor_idr, GFP_KERNEL); | 845 | r = idr_pre_get(&_minor_idr, GFP_KERNEL); |
804 | if (!r) { | 846 | if (!r) |
805 | r = -ENOMEM; | 847 | return -ENOMEM; |
806 | goto out; | 848 | |
807 | } | 849 | spin_lock(&_minor_lock); |
808 | 850 | ||
809 | r = idr_get_new(&_minor_idr, md, &m); | 851 | r = idr_get_new(&_minor_idr, MINOR_ALLOCED, &m); |
810 | if (r) { | 852 | if (r) { |
811 | goto out; | 853 | goto out; |
812 | } | 854 | } |
@@ -820,7 +862,7 @@ static int next_free_minor(struct mapped_device *md, unsigned int *minor) | |||
820 | *minor = m; | 862 | *minor = m; |
821 | 863 | ||
822 | out: | 864 | out: |
823 | mutex_unlock(&_minor_lock); | 865 | spin_unlock(&_minor_lock); |
824 | return r; | 866 | return r; |
825 | } | 867 | } |
826 | 868 | ||
@@ -829,18 +871,25 @@ static struct block_device_operations dm_blk_dops; | |||
829 | /* | 871 | /* |
830 | * Allocate and initialise a blank device with a given minor. | 872 | * Allocate and initialise a blank device with a given minor. |
831 | */ | 873 | */ |
832 | static struct mapped_device *alloc_dev(unsigned int minor, int persistent) | 874 | static struct mapped_device *alloc_dev(int minor) |
833 | { | 875 | { |
834 | int r; | 876 | int r; |
835 | struct mapped_device *md = kmalloc(sizeof(*md), GFP_KERNEL); | 877 | struct mapped_device *md = kmalloc(sizeof(*md), GFP_KERNEL); |
878 | void *old_md; | ||
836 | 879 | ||
837 | if (!md) { | 880 | if (!md) { |
838 | DMWARN("unable to allocate device, out of memory."); | 881 | DMWARN("unable to allocate device, out of memory."); |
839 | return NULL; | 882 | return NULL; |
840 | } | 883 | } |
841 | 884 | ||
885 | if (!try_module_get(THIS_MODULE)) | ||
886 | goto bad0; | ||
887 | |||
842 | /* get a minor number for the dev */ | 888 | /* get a minor number for the dev */ |
843 | r = persistent ? specific_minor(md, minor) : next_free_minor(md, &minor); | 889 | if (minor == DM_ANY_MINOR) |
890 | r = next_free_minor(md, &minor); | ||
891 | else | ||
892 | r = specific_minor(md, minor); | ||
844 | if (r < 0) | 893 | if (r < 0) |
845 | goto bad1; | 894 | goto bad1; |
846 | 895 | ||
@@ -849,6 +898,7 @@ static struct mapped_device *alloc_dev(unsigned int minor, int persistent) | |||
849 | init_MUTEX(&md->suspend_lock); | 898 | init_MUTEX(&md->suspend_lock); |
850 | rwlock_init(&md->map_lock); | 899 | rwlock_init(&md->map_lock); |
851 | atomic_set(&md->holders, 1); | 900 | atomic_set(&md->holders, 1); |
901 | atomic_set(&md->open_count, 0); | ||
852 | atomic_set(&md->event_nr, 0); | 902 | atomic_set(&md->event_nr, 0); |
853 | 903 | ||
854 | md->queue = blk_alloc_queue(GFP_KERNEL); | 904 | md->queue = blk_alloc_queue(GFP_KERNEL); |
@@ -875,6 +925,10 @@ static struct mapped_device *alloc_dev(unsigned int minor, int persistent) | |||
875 | if (!md->disk) | 925 | if (!md->disk) |
876 | goto bad4; | 926 | goto bad4; |
877 | 927 | ||
928 | atomic_set(&md->pending, 0); | ||
929 | init_waitqueue_head(&md->wait); | ||
930 | init_waitqueue_head(&md->eventq); | ||
931 | |||
878 | md->disk->major = _major; | 932 | md->disk->major = _major; |
879 | md->disk->first_minor = minor; | 933 | md->disk->first_minor = minor; |
880 | md->disk->fops = &dm_blk_dops; | 934 | md->disk->fops = &dm_blk_dops; |
@@ -884,9 +938,12 @@ static struct mapped_device *alloc_dev(unsigned int minor, int persistent) | |||
884 | add_disk(md->disk); | 938 | add_disk(md->disk); |
885 | format_dev_t(md->name, MKDEV(_major, minor)); | 939 | format_dev_t(md->name, MKDEV(_major, minor)); |
886 | 940 | ||
887 | atomic_set(&md->pending, 0); | 941 | /* Populate the mapping, nobody knows we exist yet */ |
888 | init_waitqueue_head(&md->wait); | 942 | spin_lock(&_minor_lock); |
889 | init_waitqueue_head(&md->eventq); | 943 | old_md = idr_replace(&_minor_idr, md, minor); |
944 | spin_unlock(&_minor_lock); | ||
945 | |||
946 | BUG_ON(old_md != MINOR_ALLOCED); | ||
890 | 947 | ||
891 | return md; | 948 | return md; |
892 | 949 | ||
@@ -898,13 +955,15 @@ static struct mapped_device *alloc_dev(unsigned int minor, int persistent) | |||
898 | blk_cleanup_queue(md->queue); | 955 | blk_cleanup_queue(md->queue); |
899 | free_minor(minor); | 956 | free_minor(minor); |
900 | bad1: | 957 | bad1: |
958 | module_put(THIS_MODULE); | ||
959 | bad0: | ||
901 | kfree(md); | 960 | kfree(md); |
902 | return NULL; | 961 | return NULL; |
903 | } | 962 | } |
904 | 963 | ||
905 | static void free_dev(struct mapped_device *md) | 964 | static void free_dev(struct mapped_device *md) |
906 | { | 965 | { |
907 | unsigned int minor = md->disk->first_minor; | 966 | int minor = md->disk->first_minor; |
908 | 967 | ||
909 | if (md->suspended_bdev) { | 968 | if (md->suspended_bdev) { |
910 | thaw_bdev(md->suspended_bdev, NULL); | 969 | thaw_bdev(md->suspended_bdev, NULL); |
@@ -914,8 +973,14 @@ static void free_dev(struct mapped_device *md) | |||
914 | mempool_destroy(md->io_pool); | 973 | mempool_destroy(md->io_pool); |
915 | del_gendisk(md->disk); | 974 | del_gendisk(md->disk); |
916 | free_minor(minor); | 975 | free_minor(minor); |
976 | |||
977 | spin_lock(&_minor_lock); | ||
978 | md->disk->private_data = NULL; | ||
979 | spin_unlock(&_minor_lock); | ||
980 | |||
917 | put_disk(md->disk); | 981 | put_disk(md->disk); |
918 | blk_cleanup_queue(md->queue); | 982 | blk_cleanup_queue(md->queue); |
983 | module_put(THIS_MODULE); | ||
919 | kfree(md); | 984 | kfree(md); |
920 | } | 985 | } |
921 | 986 | ||
@@ -984,12 +1049,11 @@ static void __unbind(struct mapped_device *md) | |||
984 | /* | 1049 | /* |
985 | * Constructor for a new device. | 1050 | * Constructor for a new device. |
986 | */ | 1051 | */ |
987 | static int create_aux(unsigned int minor, int persistent, | 1052 | int dm_create(int minor, struct mapped_device **result) |
988 | struct mapped_device **result) | ||
989 | { | 1053 | { |
990 | struct mapped_device *md; | 1054 | struct mapped_device *md; |
991 | 1055 | ||
992 | md = alloc_dev(minor, persistent); | 1056 | md = alloc_dev(minor); |
993 | if (!md) | 1057 | if (!md) |
994 | return -ENXIO; | 1058 | return -ENXIO; |
995 | 1059 | ||
@@ -997,16 +1061,6 @@ static int create_aux(unsigned int minor, int persistent, | |||
997 | return 0; | 1061 | return 0; |
998 | } | 1062 | } |
999 | 1063 | ||
1000 | int dm_create(struct mapped_device **result) | ||
1001 | { | ||
1002 | return create_aux(0, 0, result); | ||
1003 | } | ||
1004 | |||
1005 | int dm_create_with_minor(unsigned int minor, struct mapped_device **result) | ||
1006 | { | ||
1007 | return create_aux(minor, 1, result); | ||
1008 | } | ||
1009 | |||
1010 | static struct mapped_device *dm_find_md(dev_t dev) | 1064 | static struct mapped_device *dm_find_md(dev_t dev) |
1011 | { | 1065 | { |
1012 | struct mapped_device *md; | 1066 | struct mapped_device *md; |
@@ -1015,13 +1069,18 @@ static struct mapped_device *dm_find_md(dev_t dev) | |||
1015 | if (MAJOR(dev) != _major || minor >= (1 << MINORBITS)) | 1069 | if (MAJOR(dev) != _major || minor >= (1 << MINORBITS)) |
1016 | return NULL; | 1070 | return NULL; |
1017 | 1071 | ||
1018 | mutex_lock(&_minor_lock); | 1072 | spin_lock(&_minor_lock); |
1019 | 1073 | ||
1020 | md = idr_find(&_minor_idr, minor); | 1074 | md = idr_find(&_minor_idr, minor); |
1021 | if (!md || (dm_disk(md)->first_minor != minor)) | 1075 | if (md && (md == MINOR_ALLOCED || |
1076 | (dm_disk(md)->first_minor != minor) || | ||
1077 | test_bit(DMF_FREEING, &md->flags))) { | ||
1022 | md = NULL; | 1078 | md = NULL; |
1079 | goto out; | ||
1080 | } | ||
1023 | 1081 | ||
1024 | mutex_unlock(&_minor_lock); | 1082 | out: |
1083 | spin_unlock(&_minor_lock); | ||
1025 | 1084 | ||
1026 | return md; | 1085 | return md; |
1027 | } | 1086 | } |
@@ -1051,12 +1110,23 @@ void dm_get(struct mapped_device *md) | |||
1051 | atomic_inc(&md->holders); | 1110 | atomic_inc(&md->holders); |
1052 | } | 1111 | } |
1053 | 1112 | ||
1113 | const char *dm_device_name(struct mapped_device *md) | ||
1114 | { | ||
1115 | return md->name; | ||
1116 | } | ||
1117 | EXPORT_SYMBOL_GPL(dm_device_name); | ||
1118 | |||
1054 | void dm_put(struct mapped_device *md) | 1119 | void dm_put(struct mapped_device *md) |
1055 | { | 1120 | { |
1056 | struct dm_table *map; | 1121 | struct dm_table *map; |
1057 | 1122 | ||
1058 | if (atomic_dec_and_test(&md->holders)) { | 1123 | BUG_ON(test_bit(DMF_FREEING, &md->flags)); |
1124 | |||
1125 | if (atomic_dec_and_lock(&md->holders, &_minor_lock)) { | ||
1059 | map = dm_get_table(md); | 1126 | map = dm_get_table(md); |
1127 | idr_replace(&_minor_idr, MINOR_ALLOCED, dm_disk(md)->first_minor); | ||
1128 | set_bit(DMF_FREEING, &md->flags); | ||
1129 | spin_unlock(&_minor_lock); | ||
1060 | if (!dm_suspended(md)) { | 1130 | if (!dm_suspended(md)) { |
1061 | dm_table_presuspend_targets(map); | 1131 | dm_table_presuspend_targets(map); |
1062 | dm_table_postsuspend_targets(map); | 1132 | dm_table_postsuspend_targets(map); |
diff --git a/drivers/md/dm.h b/drivers/md/dm.h index fd90bc8f9e45..3c03c0ecab7e 100644 --- a/drivers/md/dm.h +++ b/drivers/md/dm.h | |||
@@ -2,7 +2,7 @@ | |||
2 | * Internal header file for device mapper | 2 | * Internal header file for device mapper |
3 | * | 3 | * |
4 | * Copyright (C) 2001, 2002 Sistina Software | 4 | * Copyright (C) 2001, 2002 Sistina Software |
5 | * Copyright (C) 2004 Red Hat, Inc. All rights reserved. | 5 | * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. |
6 | * | 6 | * |
7 | * This file is released under the LGPL. | 7 | * This file is released under the LGPL. |
8 | */ | 8 | */ |
@@ -17,9 +17,10 @@ | |||
17 | #include <linux/hdreg.h> | 17 | #include <linux/hdreg.h> |
18 | 18 | ||
19 | #define DM_NAME "device-mapper" | 19 | #define DM_NAME "device-mapper" |
20 | #define DMWARN(f, x...) printk(KERN_WARNING DM_NAME ": " f "\n" , ## x) | 20 | |
21 | #define DMERR(f, x...) printk(KERN_ERR DM_NAME ": " f "\n" , ## x) | 21 | #define DMERR(f, arg...) printk(KERN_ERR DM_NAME ": " DM_MSG_PREFIX ": " f "\n", ## arg) |
22 | #define DMINFO(f, x...) printk(KERN_INFO DM_NAME ": " f "\n" , ## x) | 22 | #define DMWARN(f, arg...) printk(KERN_WARNING DM_NAME ": " DM_MSG_PREFIX ": " f "\n", ## arg) |
23 | #define DMINFO(f, arg...) printk(KERN_INFO DM_NAME ": " DM_MSG_PREFIX ": " f "\n", ## arg) | ||
23 | 24 | ||
24 | #define DMEMIT(x...) sz += ((sz >= maxlen) ? \ | 25 | #define DMEMIT(x...) sz += ((sz >= maxlen) ? \ |
25 | 0 : scnprintf(result + sz, maxlen - sz, x)) | 26 | 0 : scnprintf(result + sz, maxlen - sz, x)) |
@@ -39,83 +40,16 @@ struct dm_dev { | |||
39 | }; | 40 | }; |
40 | 41 | ||
41 | struct dm_table; | 42 | struct dm_table; |
42 | struct mapped_device; | ||
43 | |||
44 | /*----------------------------------------------------------------- | ||
45 | * Functions for manipulating a struct mapped_device. | ||
46 | * Drop the reference with dm_put when you finish with the object. | ||
47 | *---------------------------------------------------------------*/ | ||
48 | int dm_create(struct mapped_device **md); | ||
49 | int dm_create_with_minor(unsigned int minor, struct mapped_device **md); | ||
50 | void dm_set_mdptr(struct mapped_device *md, void *ptr); | ||
51 | void *dm_get_mdptr(struct mapped_device *md); | ||
52 | struct mapped_device *dm_get_md(dev_t dev); | ||
53 | |||
54 | /* | ||
55 | * Reference counting for md. | ||
56 | */ | ||
57 | void dm_get(struct mapped_device *md); | ||
58 | void dm_put(struct mapped_device *md); | ||
59 | |||
60 | /* | ||
61 | * A device can still be used while suspended, but I/O is deferred. | ||
62 | */ | ||
63 | int dm_suspend(struct mapped_device *md, int with_lockfs); | ||
64 | int dm_resume(struct mapped_device *md); | ||
65 | |||
66 | /* | ||
67 | * The device must be suspended before calling this method. | ||
68 | */ | ||
69 | int dm_swap_table(struct mapped_device *md, struct dm_table *t); | ||
70 | |||
71 | /* | ||
72 | * Drop a reference on the table when you've finished with the | ||
73 | * result. | ||
74 | */ | ||
75 | struct dm_table *dm_get_table(struct mapped_device *md); | ||
76 | |||
77 | /* | ||
78 | * Event functions. | ||
79 | */ | ||
80 | uint32_t dm_get_event_nr(struct mapped_device *md); | ||
81 | int dm_wait_event(struct mapped_device *md, int event_nr); | ||
82 | |||
83 | /* | ||
84 | * Info functions. | ||
85 | */ | ||
86 | struct gendisk *dm_disk(struct mapped_device *md); | ||
87 | int dm_suspended(struct mapped_device *md); | ||
88 | |||
89 | /* | ||
90 | * Geometry functions. | ||
91 | */ | ||
92 | int dm_get_geometry(struct mapped_device *md, struct hd_geometry *geo); | ||
93 | int dm_set_geometry(struct mapped_device *md, struct hd_geometry *geo); | ||
94 | 43 | ||
95 | /*----------------------------------------------------------------- | 44 | /*----------------------------------------------------------------- |
96 | * Functions for manipulating a table. Tables are also reference | 45 | * Internal table functions. |
97 | * counted. | ||
98 | *---------------------------------------------------------------*/ | 46 | *---------------------------------------------------------------*/ |
99 | int dm_table_create(struct dm_table **result, int mode, | ||
100 | unsigned num_targets, struct mapped_device *md); | ||
101 | |||
102 | void dm_table_get(struct dm_table *t); | ||
103 | void dm_table_put(struct dm_table *t); | ||
104 | |||
105 | int dm_table_add_target(struct dm_table *t, const char *type, | ||
106 | sector_t start, sector_t len, char *params); | ||
107 | int dm_table_complete(struct dm_table *t); | ||
108 | void dm_table_event_callback(struct dm_table *t, | 47 | void dm_table_event_callback(struct dm_table *t, |
109 | void (*fn)(void *), void *context); | 48 | void (*fn)(void *), void *context); |
110 | void dm_table_event(struct dm_table *t); | ||
111 | sector_t dm_table_get_size(struct dm_table *t); | ||
112 | struct dm_target *dm_table_get_target(struct dm_table *t, unsigned int index); | 49 | struct dm_target *dm_table_get_target(struct dm_table *t, unsigned int index); |
113 | struct dm_target *dm_table_find_target(struct dm_table *t, sector_t sector); | 50 | struct dm_target *dm_table_find_target(struct dm_table *t, sector_t sector); |
114 | void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q); | 51 | void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q); |
115 | unsigned int dm_table_get_num_targets(struct dm_table *t); | ||
116 | struct list_head *dm_table_get_devices(struct dm_table *t); | 52 | struct list_head *dm_table_get_devices(struct dm_table *t); |
117 | int dm_table_get_mode(struct dm_table *t); | ||
118 | struct mapped_device *dm_table_get_md(struct dm_table *t); | ||
119 | void dm_table_presuspend_targets(struct dm_table *t); | 53 | void dm_table_presuspend_targets(struct dm_table *t); |
120 | void dm_table_postsuspend_targets(struct dm_table *t); | 54 | void dm_table_postsuspend_targets(struct dm_table *t); |
121 | void dm_table_resume_targets(struct dm_table *t); | 55 | void dm_table_resume_targets(struct dm_table *t); |
@@ -133,7 +67,6 @@ void dm_put_target_type(struct target_type *t); | |||
133 | int dm_target_iterate(void (*iter_func)(struct target_type *tt, | 67 | int dm_target_iterate(void (*iter_func)(struct target_type *tt, |
134 | void *param), void *param); | 68 | void *param), void *param); |
135 | 69 | ||
136 | |||
137 | /*----------------------------------------------------------------- | 70 | /*----------------------------------------------------------------- |
138 | * Useful inlines. | 71 | * Useful inlines. |
139 | *---------------------------------------------------------------*/ | 72 | *---------------------------------------------------------------*/ |
@@ -191,5 +124,7 @@ void dm_stripe_exit(void); | |||
191 | 124 | ||
192 | void *dm_vcalloc(unsigned long nmemb, unsigned long elem_size); | 125 | void *dm_vcalloc(unsigned long nmemb, unsigned long elem_size); |
193 | union map_info *dm_get_mapinfo(struct bio *bio); | 126 | union map_info *dm_get_mapinfo(struct bio *bio); |
127 | int dm_open_count(struct mapped_device *md); | ||
128 | int dm_lock_for_deletion(struct mapped_device *md); | ||
194 | 129 | ||
195 | #endif | 130 | #endif |
diff --git a/drivers/md/kcopyd.c b/drivers/md/kcopyd.c index 72480a48d88b..73ab875fb158 100644 --- a/drivers/md/kcopyd.c +++ b/drivers/md/kcopyd.c | |||
@@ -314,7 +314,7 @@ static void complete_io(unsigned long error, void *context) | |||
314 | 314 | ||
315 | if (error) { | 315 | if (error) { |
316 | if (job->rw == WRITE) | 316 | if (job->rw == WRITE) |
317 | job->write_err &= error; | 317 | job->write_err |= error; |
318 | else | 318 | else |
319 | job->read_err = 1; | 319 | job->read_err = 1; |
320 | 320 | ||
@@ -460,7 +460,7 @@ static void segment_complete(int read_err, | |||
460 | job->read_err = 1; | 460 | job->read_err = 1; |
461 | 461 | ||
462 | if (write_err) | 462 | if (write_err) |
463 | job->write_err &= write_err; | 463 | job->write_err |= write_err; |
464 | 464 | ||
465 | /* | 465 | /* |
466 | * Only dispatch more work if there hasn't been an error. | 466 | * Only dispatch more work if there hasn't been an error. |
diff --git a/drivers/md/linear.c b/drivers/md/linear.c index 777585458c85..ff83c9b5979e 100644 --- a/drivers/md/linear.c +++ b/drivers/md/linear.c | |||
@@ -111,7 +111,7 @@ static int linear_issue_flush(request_queue_t *q, struct gendisk *disk, | |||
111 | return ret; | 111 | return ret; |
112 | } | 112 | } |
113 | 113 | ||
114 | static int linear_run (mddev_t *mddev) | 114 | static linear_conf_t *linear_conf(mddev_t *mddev, int raid_disks) |
115 | { | 115 | { |
116 | linear_conf_t *conf; | 116 | linear_conf_t *conf; |
117 | dev_info_t **table; | 117 | dev_info_t **table; |
@@ -121,20 +121,21 @@ static int linear_run (mddev_t *mddev) | |||
121 | sector_t curr_offset; | 121 | sector_t curr_offset; |
122 | struct list_head *tmp; | 122 | struct list_head *tmp; |
123 | 123 | ||
124 | conf = kzalloc (sizeof (*conf) + mddev->raid_disks*sizeof(dev_info_t), | 124 | conf = kzalloc (sizeof (*conf) + raid_disks*sizeof(dev_info_t), |
125 | GFP_KERNEL); | 125 | GFP_KERNEL); |
126 | if (!conf) | 126 | if (!conf) |
127 | goto out; | 127 | return NULL; |
128 | |||
128 | mddev->private = conf; | 129 | mddev->private = conf; |
129 | 130 | ||
130 | cnt = 0; | 131 | cnt = 0; |
131 | mddev->array_size = 0; | 132 | conf->array_size = 0; |
132 | 133 | ||
133 | ITERATE_RDEV(mddev,rdev,tmp) { | 134 | ITERATE_RDEV(mddev,rdev,tmp) { |
134 | int j = rdev->raid_disk; | 135 | int j = rdev->raid_disk; |
135 | dev_info_t *disk = conf->disks + j; | 136 | dev_info_t *disk = conf->disks + j; |
136 | 137 | ||
137 | if (j < 0 || j > mddev->raid_disks || disk->rdev) { | 138 | if (j < 0 || j > raid_disks || disk->rdev) { |
138 | printk("linear: disk numbering problem. Aborting!\n"); | 139 | printk("linear: disk numbering problem. Aborting!\n"); |
139 | goto out; | 140 | goto out; |
140 | } | 141 | } |
@@ -152,11 +153,11 @@ static int linear_run (mddev_t *mddev) | |||
152 | blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9); | 153 | blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9); |
153 | 154 | ||
154 | disk->size = rdev->size; | 155 | disk->size = rdev->size; |
155 | mddev->array_size += rdev->size; | 156 | conf->array_size += rdev->size; |
156 | 157 | ||
157 | cnt++; | 158 | cnt++; |
158 | } | 159 | } |
159 | if (cnt != mddev->raid_disks) { | 160 | if (cnt != raid_disks) { |
160 | printk("linear: not enough drives present. Aborting!\n"); | 161 | printk("linear: not enough drives present. Aborting!\n"); |
161 | goto out; | 162 | goto out; |
162 | } | 163 | } |
@@ -200,7 +201,7 @@ static int linear_run (mddev_t *mddev) | |||
200 | unsigned round; | 201 | unsigned round; |
201 | unsigned long base; | 202 | unsigned long base; |
202 | 203 | ||
203 | sz = mddev->array_size >> conf->preshift; | 204 | sz = conf->array_size >> conf->preshift; |
204 | sz += 1; /* force round-up */ | 205 | sz += 1; /* force round-up */ |
205 | base = conf->hash_spacing >> conf->preshift; | 206 | base = conf->hash_spacing >> conf->preshift; |
206 | round = sector_div(sz, base); | 207 | round = sector_div(sz, base); |
@@ -247,14 +248,56 @@ static int linear_run (mddev_t *mddev) | |||
247 | 248 | ||
248 | BUG_ON(table - conf->hash_table > nb_zone); | 249 | BUG_ON(table - conf->hash_table > nb_zone); |
249 | 250 | ||
251 | return conf; | ||
252 | |||
253 | out: | ||
254 | kfree(conf); | ||
255 | return NULL; | ||
256 | } | ||
257 | |||
258 | static int linear_run (mddev_t *mddev) | ||
259 | { | ||
260 | linear_conf_t *conf; | ||
261 | |||
262 | conf = linear_conf(mddev, mddev->raid_disks); | ||
263 | |||
264 | if (!conf) | ||
265 | return 1; | ||
266 | mddev->private = conf; | ||
267 | mddev->array_size = conf->array_size; | ||
268 | |||
250 | blk_queue_merge_bvec(mddev->queue, linear_mergeable_bvec); | 269 | blk_queue_merge_bvec(mddev->queue, linear_mergeable_bvec); |
251 | mddev->queue->unplug_fn = linear_unplug; | 270 | mddev->queue->unplug_fn = linear_unplug; |
252 | mddev->queue->issue_flush_fn = linear_issue_flush; | 271 | mddev->queue->issue_flush_fn = linear_issue_flush; |
253 | return 0; | 272 | return 0; |
273 | } | ||
254 | 274 | ||
255 | out: | 275 | static int linear_add(mddev_t *mddev, mdk_rdev_t *rdev) |
256 | kfree(conf); | 276 | { |
257 | return 1; | 277 | /* Adding a drive to a linear array allows the array to grow. |
278 | * It is permitted if the new drive has a matching superblock | ||
279 | * already on it, with raid_disk equal to raid_disks. | ||
280 | * It is achieved by creating a new linear_private_data structure | ||
281 | * and swapping it in in-place of the current one. | ||
282 | * The current one is never freed until the array is stopped. | ||
283 | * This avoids races. | ||
284 | */ | ||
285 | linear_conf_t *newconf; | ||
286 | |||
287 | if (rdev->raid_disk != mddev->raid_disks) | ||
288 | return -EINVAL; | ||
289 | |||
290 | newconf = linear_conf(mddev,mddev->raid_disks+1); | ||
291 | |||
292 | if (!newconf) | ||
293 | return -ENOMEM; | ||
294 | |||
295 | newconf->prev = mddev_to_conf(mddev); | ||
296 | mddev->private = newconf; | ||
297 | mddev->raid_disks++; | ||
298 | mddev->array_size = newconf->array_size; | ||
299 | set_capacity(mddev->gendisk, mddev->array_size << 1); | ||
300 | return 0; | ||
258 | } | 301 | } |
259 | 302 | ||
260 | static int linear_stop (mddev_t *mddev) | 303 | static int linear_stop (mddev_t *mddev) |
@@ -262,8 +305,12 @@ static int linear_stop (mddev_t *mddev) | |||
262 | linear_conf_t *conf = mddev_to_conf(mddev); | 305 | linear_conf_t *conf = mddev_to_conf(mddev); |
263 | 306 | ||
264 | blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/ | 307 | blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/ |
265 | kfree(conf->hash_table); | 308 | do { |
266 | kfree(conf); | 309 | linear_conf_t *t = conf->prev; |
310 | kfree(conf->hash_table); | ||
311 | kfree(conf); | ||
312 | conf = t; | ||
313 | } while (conf); | ||
267 | 314 | ||
268 | return 0; | 315 | return 0; |
269 | } | 316 | } |
@@ -360,6 +407,7 @@ static struct mdk_personality linear_personality = | |||
360 | .run = linear_run, | 407 | .run = linear_run, |
361 | .stop = linear_stop, | 408 | .stop = linear_stop, |
362 | .status = linear_status, | 409 | .status = linear_status, |
410 | .hot_add_disk = linear_add, | ||
363 | }; | 411 | }; |
364 | 412 | ||
365 | static int __init linear_init (void) | 413 | static int __init linear_init (void) |
diff --git a/drivers/md/md.c b/drivers/md/md.c index f19b874753a9..306268ec99ff 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c | |||
@@ -44,6 +44,7 @@ | |||
44 | #include <linux/suspend.h> | 44 | #include <linux/suspend.h> |
45 | #include <linux/poll.h> | 45 | #include <linux/poll.h> |
46 | #include <linux/mutex.h> | 46 | #include <linux/mutex.h> |
47 | #include <linux/ctype.h> | ||
47 | 48 | ||
48 | #include <linux/init.h> | 49 | #include <linux/init.h> |
49 | 50 | ||
@@ -72,6 +73,10 @@ static void autostart_arrays (int part); | |||
72 | static LIST_HEAD(pers_list); | 73 | static LIST_HEAD(pers_list); |
73 | static DEFINE_SPINLOCK(pers_lock); | 74 | static DEFINE_SPINLOCK(pers_lock); |
74 | 75 | ||
76 | static void md_print_devices(void); | ||
77 | |||
78 | #define MD_BUG(x...) { printk("md: bug in file %s, line %d\n", __FILE__, __LINE__); md_print_devices(); } | ||
79 | |||
75 | /* | 80 | /* |
76 | * Current RAID-1,4,5 parallel reconstruction 'guaranteed speed limit' | 81 | * Current RAID-1,4,5 parallel reconstruction 'guaranteed speed limit' |
77 | * is 1000 KB/sec, so the extra system load does not show up that much. | 82 | * is 1000 KB/sec, so the extra system load does not show up that much. |
@@ -170,7 +175,7 @@ EXPORT_SYMBOL_GPL(md_new_event); | |||
170 | /* Alternate version that can be called from interrupts | 175 | /* Alternate version that can be called from interrupts |
171 | * when calling sysfs_notify isn't needed. | 176 | * when calling sysfs_notify isn't needed. |
172 | */ | 177 | */ |
173 | void md_new_event_inintr(mddev_t *mddev) | 178 | static void md_new_event_inintr(mddev_t *mddev) |
174 | { | 179 | { |
175 | atomic_inc(&md_event_count); | 180 | atomic_inc(&md_event_count); |
176 | wake_up(&md_event_waiters); | 181 | wake_up(&md_event_waiters); |
@@ -732,6 +737,7 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev) | |||
732 | { | 737 | { |
733 | mdp_disk_t *desc; | 738 | mdp_disk_t *desc; |
734 | mdp_super_t *sb = (mdp_super_t *)page_address(rdev->sb_page); | 739 | mdp_super_t *sb = (mdp_super_t *)page_address(rdev->sb_page); |
740 | __u64 ev1 = md_event(sb); | ||
735 | 741 | ||
736 | rdev->raid_disk = -1; | 742 | rdev->raid_disk = -1; |
737 | rdev->flags = 0; | 743 | rdev->flags = 0; |
@@ -748,7 +754,7 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev) | |||
748 | mddev->layout = sb->layout; | 754 | mddev->layout = sb->layout; |
749 | mddev->raid_disks = sb->raid_disks; | 755 | mddev->raid_disks = sb->raid_disks; |
750 | mddev->size = sb->size; | 756 | mddev->size = sb->size; |
751 | mddev->events = md_event(sb); | 757 | mddev->events = ev1; |
752 | mddev->bitmap_offset = 0; | 758 | mddev->bitmap_offset = 0; |
753 | mddev->default_bitmap_offset = MD_SB_BYTES >> 9; | 759 | mddev->default_bitmap_offset = MD_SB_BYTES >> 9; |
754 | 760 | ||
@@ -797,7 +803,6 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev) | |||
797 | 803 | ||
798 | } else if (mddev->pers == NULL) { | 804 | } else if (mddev->pers == NULL) { |
799 | /* Insist on good event counter while assembling */ | 805 | /* Insist on good event counter while assembling */ |
800 | __u64 ev1 = md_event(sb); | ||
801 | ++ev1; | 806 | ++ev1; |
802 | if (ev1 < mddev->events) | 807 | if (ev1 < mddev->events) |
803 | return -EINVAL; | 808 | return -EINVAL; |
@@ -805,19 +810,21 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev) | |||
805 | /* if adding to array with a bitmap, then we can accept an | 810 | /* if adding to array with a bitmap, then we can accept an |
806 | * older device ... but not too old. | 811 | * older device ... but not too old. |
807 | */ | 812 | */ |
808 | __u64 ev1 = md_event(sb); | ||
809 | if (ev1 < mddev->bitmap->events_cleared) | 813 | if (ev1 < mddev->bitmap->events_cleared) |
810 | return 0; | 814 | return 0; |
811 | } else /* just a hot-add of a new device, leave raid_disk at -1 */ | 815 | } else { |
812 | return 0; | 816 | if (ev1 < mddev->events) |
817 | /* just a hot-add of a new device, leave raid_disk at -1 */ | ||
818 | return 0; | ||
819 | } | ||
813 | 820 | ||
814 | if (mddev->level != LEVEL_MULTIPATH) { | 821 | if (mddev->level != LEVEL_MULTIPATH) { |
815 | desc = sb->disks + rdev->desc_nr; | 822 | desc = sb->disks + rdev->desc_nr; |
816 | 823 | ||
817 | if (desc->state & (1<<MD_DISK_FAULTY)) | 824 | if (desc->state & (1<<MD_DISK_FAULTY)) |
818 | set_bit(Faulty, &rdev->flags); | 825 | set_bit(Faulty, &rdev->flags); |
819 | else if (desc->state & (1<<MD_DISK_SYNC) && | 826 | else if (desc->state & (1<<MD_DISK_SYNC) /* && |
820 | desc->raid_disk < mddev->raid_disks) { | 827 | desc->raid_disk < mddev->raid_disks */) { |
821 | set_bit(In_sync, &rdev->flags); | 828 | set_bit(In_sync, &rdev->flags); |
822 | rdev->raid_disk = desc->raid_disk; | 829 | rdev->raid_disk = desc->raid_disk; |
823 | } | 830 | } |
@@ -1100,6 +1107,7 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version) | |||
1100 | static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev) | 1107 | static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev) |
1101 | { | 1108 | { |
1102 | struct mdp_superblock_1 *sb = (struct mdp_superblock_1*)page_address(rdev->sb_page); | 1109 | struct mdp_superblock_1 *sb = (struct mdp_superblock_1*)page_address(rdev->sb_page); |
1110 | __u64 ev1 = le64_to_cpu(sb->events); | ||
1103 | 1111 | ||
1104 | rdev->raid_disk = -1; | 1112 | rdev->raid_disk = -1; |
1105 | rdev->flags = 0; | 1113 | rdev->flags = 0; |
@@ -1115,7 +1123,7 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev) | |||
1115 | mddev->layout = le32_to_cpu(sb->layout); | 1123 | mddev->layout = le32_to_cpu(sb->layout); |
1116 | mddev->raid_disks = le32_to_cpu(sb->raid_disks); | 1124 | mddev->raid_disks = le32_to_cpu(sb->raid_disks); |
1117 | mddev->size = le64_to_cpu(sb->size)/2; | 1125 | mddev->size = le64_to_cpu(sb->size)/2; |
1118 | mddev->events = le64_to_cpu(sb->events); | 1126 | mddev->events = ev1; |
1119 | mddev->bitmap_offset = 0; | 1127 | mddev->bitmap_offset = 0; |
1120 | mddev->default_bitmap_offset = 1024 >> 9; | 1128 | mddev->default_bitmap_offset = 1024 >> 9; |
1121 | 1129 | ||
@@ -1149,7 +1157,6 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev) | |||
1149 | 1157 | ||
1150 | } else if (mddev->pers == NULL) { | 1158 | } else if (mddev->pers == NULL) { |
1151 | /* Insist of good event counter while assembling */ | 1159 | /* Insist of good event counter while assembling */ |
1152 | __u64 ev1 = le64_to_cpu(sb->events); | ||
1153 | ++ev1; | 1160 | ++ev1; |
1154 | if (ev1 < mddev->events) | 1161 | if (ev1 < mddev->events) |
1155 | return -EINVAL; | 1162 | return -EINVAL; |
@@ -1157,12 +1164,13 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev) | |||
1157 | /* If adding to array with a bitmap, then we can accept an | 1164 | /* If adding to array with a bitmap, then we can accept an |
1158 | * older device, but not too old. | 1165 | * older device, but not too old. |
1159 | */ | 1166 | */ |
1160 | __u64 ev1 = le64_to_cpu(sb->events); | ||
1161 | if (ev1 < mddev->bitmap->events_cleared) | 1167 | if (ev1 < mddev->bitmap->events_cleared) |
1162 | return 0; | 1168 | return 0; |
1163 | } else /* just a hot-add of a new device, leave raid_disk at -1 */ | 1169 | } else { |
1164 | return 0; | 1170 | if (ev1 < mddev->events) |
1165 | 1171 | /* just a hot-add of a new device, leave raid_disk at -1 */ | |
1172 | return 0; | ||
1173 | } | ||
1166 | if (mddev->level != LEVEL_MULTIPATH) { | 1174 | if (mddev->level != LEVEL_MULTIPATH) { |
1167 | int role; | 1175 | int role; |
1168 | rdev->desc_nr = le32_to_cpu(sb->dev_number); | 1176 | rdev->desc_nr = le32_to_cpu(sb->dev_number); |
@@ -1174,7 +1182,11 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev) | |||
1174 | set_bit(Faulty, &rdev->flags); | 1182 | set_bit(Faulty, &rdev->flags); |
1175 | break; | 1183 | break; |
1176 | default: | 1184 | default: |
1177 | set_bit(In_sync, &rdev->flags); | 1185 | if ((le32_to_cpu(sb->feature_map) & |
1186 | MD_FEATURE_RECOVERY_OFFSET)) | ||
1187 | rdev->recovery_offset = le64_to_cpu(sb->recovery_offset); | ||
1188 | else | ||
1189 | set_bit(In_sync, &rdev->flags); | ||
1178 | rdev->raid_disk = role; | 1190 | rdev->raid_disk = role; |
1179 | break; | 1191 | break; |
1180 | } | 1192 | } |
@@ -1198,6 +1210,7 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev) | |||
1198 | 1210 | ||
1199 | sb->feature_map = 0; | 1211 | sb->feature_map = 0; |
1200 | sb->pad0 = 0; | 1212 | sb->pad0 = 0; |
1213 | sb->recovery_offset = cpu_to_le64(0); | ||
1201 | memset(sb->pad1, 0, sizeof(sb->pad1)); | 1214 | memset(sb->pad1, 0, sizeof(sb->pad1)); |
1202 | memset(sb->pad2, 0, sizeof(sb->pad2)); | 1215 | memset(sb->pad2, 0, sizeof(sb->pad2)); |
1203 | memset(sb->pad3, 0, sizeof(sb->pad3)); | 1216 | memset(sb->pad3, 0, sizeof(sb->pad3)); |
@@ -1218,6 +1231,14 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev) | |||
1218 | sb->bitmap_offset = cpu_to_le32((__u32)mddev->bitmap_offset); | 1231 | sb->bitmap_offset = cpu_to_le32((__u32)mddev->bitmap_offset); |
1219 | sb->feature_map = cpu_to_le32(MD_FEATURE_BITMAP_OFFSET); | 1232 | sb->feature_map = cpu_to_le32(MD_FEATURE_BITMAP_OFFSET); |
1220 | } | 1233 | } |
1234 | |||
1235 | if (rdev->raid_disk >= 0 && | ||
1236 | !test_bit(In_sync, &rdev->flags) && | ||
1237 | rdev->recovery_offset > 0) { | ||
1238 | sb->feature_map |= cpu_to_le32(MD_FEATURE_RECOVERY_OFFSET); | ||
1239 | sb->recovery_offset = cpu_to_le64(rdev->recovery_offset); | ||
1240 | } | ||
1241 | |||
1221 | if (mddev->reshape_position != MaxSector) { | 1242 | if (mddev->reshape_position != MaxSector) { |
1222 | sb->feature_map |= cpu_to_le32(MD_FEATURE_RESHAPE_ACTIVE); | 1243 | sb->feature_map |= cpu_to_le32(MD_FEATURE_RESHAPE_ACTIVE); |
1223 | sb->reshape_position = cpu_to_le64(mddev->reshape_position); | 1244 | sb->reshape_position = cpu_to_le64(mddev->reshape_position); |
@@ -1242,11 +1263,12 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev) | |||
1242 | sb->dev_roles[i] = cpu_to_le16(0xfffe); | 1263 | sb->dev_roles[i] = cpu_to_le16(0xfffe); |
1243 | else if (test_bit(In_sync, &rdev2->flags)) | 1264 | else if (test_bit(In_sync, &rdev2->flags)) |
1244 | sb->dev_roles[i] = cpu_to_le16(rdev2->raid_disk); | 1265 | sb->dev_roles[i] = cpu_to_le16(rdev2->raid_disk); |
1266 | else if (rdev2->raid_disk >= 0 && rdev2->recovery_offset > 0) | ||
1267 | sb->dev_roles[i] = cpu_to_le16(rdev2->raid_disk); | ||
1245 | else | 1268 | else |
1246 | sb->dev_roles[i] = cpu_to_le16(0xffff); | 1269 | sb->dev_roles[i] = cpu_to_le16(0xffff); |
1247 | } | 1270 | } |
1248 | 1271 | ||
1249 | sb->recovery_offset = cpu_to_le64(0); /* not supported yet */ | ||
1250 | sb->sb_csum = calc_sb_1_csum(sb); | 1272 | sb->sb_csum = calc_sb_1_csum(sb); |
1251 | } | 1273 | } |
1252 | 1274 | ||
@@ -1507,7 +1529,7 @@ static void print_rdev(mdk_rdev_t *rdev) | |||
1507 | printk(KERN_INFO "md: no rdev superblock!\n"); | 1529 | printk(KERN_INFO "md: no rdev superblock!\n"); |
1508 | } | 1530 | } |
1509 | 1531 | ||
1510 | void md_print_devices(void) | 1532 | static void md_print_devices(void) |
1511 | { | 1533 | { |
1512 | struct list_head *tmp, *tmp2; | 1534 | struct list_head *tmp, *tmp2; |
1513 | mdk_rdev_t *rdev; | 1535 | mdk_rdev_t *rdev; |
@@ -1536,15 +1558,30 @@ void md_print_devices(void) | |||
1536 | } | 1558 | } |
1537 | 1559 | ||
1538 | 1560 | ||
1539 | static void sync_sbs(mddev_t * mddev) | 1561 | static void sync_sbs(mddev_t * mddev, int nospares) |
1540 | { | 1562 | { |
1563 | /* Update each superblock (in-memory image), but | ||
1564 | * if we are allowed to, skip spares which already | ||
1565 | * have the right event counter, or have one earlier | ||
1566 | * (which would mean they aren't being marked as dirty | ||
1567 | * with the rest of the array) | ||
1568 | */ | ||
1541 | mdk_rdev_t *rdev; | 1569 | mdk_rdev_t *rdev; |
1542 | struct list_head *tmp; | 1570 | struct list_head *tmp; |
1543 | 1571 | ||
1544 | ITERATE_RDEV(mddev,rdev,tmp) { | 1572 | ITERATE_RDEV(mddev,rdev,tmp) { |
1545 | super_types[mddev->major_version]. | 1573 | if (rdev->sb_events == mddev->events || |
1546 | sync_super(mddev, rdev); | 1574 | (nospares && |
1547 | rdev->sb_loaded = 1; | 1575 | rdev->raid_disk < 0 && |
1576 | (rdev->sb_events&1)==0 && | ||
1577 | rdev->sb_events+1 == mddev->events)) { | ||
1578 | /* Don't update this superblock */ | ||
1579 | rdev->sb_loaded = 2; | ||
1580 | } else { | ||
1581 | super_types[mddev->major_version]. | ||
1582 | sync_super(mddev, rdev); | ||
1583 | rdev->sb_loaded = 1; | ||
1584 | } | ||
1548 | } | 1585 | } |
1549 | } | 1586 | } |
1550 | 1587 | ||
@@ -1554,12 +1591,42 @@ void md_update_sb(mddev_t * mddev) | |||
1554 | struct list_head *tmp; | 1591 | struct list_head *tmp; |
1555 | mdk_rdev_t *rdev; | 1592 | mdk_rdev_t *rdev; |
1556 | int sync_req; | 1593 | int sync_req; |
1594 | int nospares = 0; | ||
1557 | 1595 | ||
1558 | repeat: | 1596 | repeat: |
1559 | spin_lock_irq(&mddev->write_lock); | 1597 | spin_lock_irq(&mddev->write_lock); |
1560 | sync_req = mddev->in_sync; | 1598 | sync_req = mddev->in_sync; |
1561 | mddev->utime = get_seconds(); | 1599 | mddev->utime = get_seconds(); |
1562 | mddev->events ++; | 1600 | if (mddev->sb_dirty == 3) |
1601 | /* just a clean<-> dirty transition, possibly leave spares alone, | ||
1602 | * though if events isn't the right even/odd, we will have to do | ||
1603 | * spares after all | ||
1604 | */ | ||
1605 | nospares = 1; | ||
1606 | |||
1607 | /* If this is just a dirty<->clean transition, and the array is clean | ||
1608 | * and 'events' is odd, we can roll back to the previous clean state */ | ||
1609 | if (mddev->sb_dirty == 3 | ||
1610 | && (mddev->in_sync && mddev->recovery_cp == MaxSector) | ||
1611 | && (mddev->events & 1)) | ||
1612 | mddev->events--; | ||
1613 | else { | ||
1614 | /* otherwise we have to go forward and ... */ | ||
1615 | mddev->events ++; | ||
1616 | if (!mddev->in_sync || mddev->recovery_cp != MaxSector) { /* not clean */ | ||
1617 | /* .. if the array isn't clean, insist on an odd 'events' */ | ||
1618 | if ((mddev->events&1)==0) { | ||
1619 | mddev->events++; | ||
1620 | nospares = 0; | ||
1621 | } | ||
1622 | } else { | ||
1623 | /* otherwise insist on an even 'events' (for clean states) */ | ||
1624 | if ((mddev->events&1)) { | ||
1625 | mddev->events++; | ||
1626 | nospares = 0; | ||
1627 | } | ||
1628 | } | ||
1629 | } | ||
1563 | 1630 | ||
1564 | if (!mddev->events) { | 1631 | if (!mddev->events) { |
1565 | /* | 1632 | /* |
@@ -1571,7 +1638,7 @@ repeat: | |||
1571 | mddev->events --; | 1638 | mddev->events --; |
1572 | } | 1639 | } |
1573 | mddev->sb_dirty = 2; | 1640 | mddev->sb_dirty = 2; |
1574 | sync_sbs(mddev); | 1641 | sync_sbs(mddev, nospares); |
1575 | 1642 | ||
1576 | /* | 1643 | /* |
1577 | * do not write anything to disk if using | 1644 | * do not write anything to disk if using |
@@ -1593,6 +1660,8 @@ repeat: | |||
1593 | ITERATE_RDEV(mddev,rdev,tmp) { | 1660 | ITERATE_RDEV(mddev,rdev,tmp) { |
1594 | char b[BDEVNAME_SIZE]; | 1661 | char b[BDEVNAME_SIZE]; |
1595 | dprintk(KERN_INFO "md: "); | 1662 | dprintk(KERN_INFO "md: "); |
1663 | if (rdev->sb_loaded != 1) | ||
1664 | continue; /* no noise on spare devices */ | ||
1596 | if (test_bit(Faulty, &rdev->flags)) | 1665 | if (test_bit(Faulty, &rdev->flags)) |
1597 | dprintk("(skipping faulty "); | 1666 | dprintk("(skipping faulty "); |
1598 | 1667 | ||
@@ -1604,6 +1673,7 @@ repeat: | |||
1604 | dprintk(KERN_INFO "(write) %s's sb offset: %llu\n", | 1673 | dprintk(KERN_INFO "(write) %s's sb offset: %llu\n", |
1605 | bdevname(rdev->bdev,b), | 1674 | bdevname(rdev->bdev,b), |
1606 | (unsigned long long)rdev->sb_offset); | 1675 | (unsigned long long)rdev->sb_offset); |
1676 | rdev->sb_events = mddev->events; | ||
1607 | 1677 | ||
1608 | } else | 1678 | } else |
1609 | dprintk(")\n"); | 1679 | dprintk(")\n"); |
@@ -1667,6 +1737,10 @@ state_show(mdk_rdev_t *rdev, char *page) | |||
1667 | len += sprintf(page+len, "%sin_sync",sep); | 1737 | len += sprintf(page+len, "%sin_sync",sep); |
1668 | sep = ","; | 1738 | sep = ","; |
1669 | } | 1739 | } |
1740 | if (test_bit(WriteMostly, &rdev->flags)) { | ||
1741 | len += sprintf(page+len, "%swrite_mostly",sep); | ||
1742 | sep = ","; | ||
1743 | } | ||
1670 | if (!test_bit(Faulty, &rdev->flags) && | 1744 | if (!test_bit(Faulty, &rdev->flags) && |
1671 | !test_bit(In_sync, &rdev->flags)) { | 1745 | !test_bit(In_sync, &rdev->flags)) { |
1672 | len += sprintf(page+len, "%sspare", sep); | 1746 | len += sprintf(page+len, "%sspare", sep); |
@@ -1675,8 +1749,40 @@ state_show(mdk_rdev_t *rdev, char *page) | |||
1675 | return len+sprintf(page+len, "\n"); | 1749 | return len+sprintf(page+len, "\n"); |
1676 | } | 1750 | } |
1677 | 1751 | ||
1752 | static ssize_t | ||
1753 | state_store(mdk_rdev_t *rdev, const char *buf, size_t len) | ||
1754 | { | ||
1755 | /* can write | ||
1756 | * faulty - simulates and error | ||
1757 | * remove - disconnects the device | ||
1758 | * writemostly - sets write_mostly | ||
1759 | * -writemostly - clears write_mostly | ||
1760 | */ | ||
1761 | int err = -EINVAL; | ||
1762 | if (cmd_match(buf, "faulty") && rdev->mddev->pers) { | ||
1763 | md_error(rdev->mddev, rdev); | ||
1764 | err = 0; | ||
1765 | } else if (cmd_match(buf, "remove")) { | ||
1766 | if (rdev->raid_disk >= 0) | ||
1767 | err = -EBUSY; | ||
1768 | else { | ||
1769 | mddev_t *mddev = rdev->mddev; | ||
1770 | kick_rdev_from_array(rdev); | ||
1771 | md_update_sb(mddev); | ||
1772 | md_new_event(mddev); | ||
1773 | err = 0; | ||
1774 | } | ||
1775 | } else if (cmd_match(buf, "writemostly")) { | ||
1776 | set_bit(WriteMostly, &rdev->flags); | ||
1777 | err = 0; | ||
1778 | } else if (cmd_match(buf, "-writemostly")) { | ||
1779 | clear_bit(WriteMostly, &rdev->flags); | ||
1780 | err = 0; | ||
1781 | } | ||
1782 | return err ? err : len; | ||
1783 | } | ||
1678 | static struct rdev_sysfs_entry | 1784 | static struct rdev_sysfs_entry |
1679 | rdev_state = __ATTR_RO(state); | 1785 | rdev_state = __ATTR(state, 0644, state_show, state_store); |
1680 | 1786 | ||
1681 | static ssize_t | 1787 | static ssize_t |
1682 | super_show(mdk_rdev_t *rdev, char *page) | 1788 | super_show(mdk_rdev_t *rdev, char *page) |
@@ -1873,6 +1979,7 @@ static mdk_rdev_t *md_import_device(dev_t newdev, int super_format, int super_mi | |||
1873 | rdev->desc_nr = -1; | 1979 | rdev->desc_nr = -1; |
1874 | rdev->flags = 0; | 1980 | rdev->flags = 0; |
1875 | rdev->data_offset = 0; | 1981 | rdev->data_offset = 0; |
1982 | rdev->sb_events = 0; | ||
1876 | atomic_set(&rdev->nr_pending, 0); | 1983 | atomic_set(&rdev->nr_pending, 0); |
1877 | atomic_set(&rdev->read_errors, 0); | 1984 | atomic_set(&rdev->read_errors, 0); |
1878 | atomic_set(&rdev->corrected_errors, 0); | 1985 | atomic_set(&rdev->corrected_errors, 0); |
@@ -1978,6 +2085,54 @@ static void analyze_sbs(mddev_t * mddev) | |||
1978 | } | 2085 | } |
1979 | 2086 | ||
1980 | static ssize_t | 2087 | static ssize_t |
2088 | safe_delay_show(mddev_t *mddev, char *page) | ||
2089 | { | ||
2090 | int msec = (mddev->safemode_delay*1000)/HZ; | ||
2091 | return sprintf(page, "%d.%03d\n", msec/1000, msec%1000); | ||
2092 | } | ||
2093 | static ssize_t | ||
2094 | safe_delay_store(mddev_t *mddev, const char *cbuf, size_t len) | ||
2095 | { | ||
2096 | int scale=1; | ||
2097 | int dot=0; | ||
2098 | int i; | ||
2099 | unsigned long msec; | ||
2100 | char buf[30]; | ||
2101 | char *e; | ||
2102 | /* remove a period, and count digits after it */ | ||
2103 | if (len >= sizeof(buf)) | ||
2104 | return -EINVAL; | ||
2105 | strlcpy(buf, cbuf, len); | ||
2106 | buf[len] = 0; | ||
2107 | for (i=0; i<len; i++) { | ||
2108 | if (dot) { | ||
2109 | if (isdigit(buf[i])) { | ||
2110 | buf[i-1] = buf[i]; | ||
2111 | scale *= 10; | ||
2112 | } | ||
2113 | buf[i] = 0; | ||
2114 | } else if (buf[i] == '.') { | ||
2115 | dot=1; | ||
2116 | buf[i] = 0; | ||
2117 | } | ||
2118 | } | ||
2119 | msec = simple_strtoul(buf, &e, 10); | ||
2120 | if (e == buf || (*e && *e != '\n')) | ||
2121 | return -EINVAL; | ||
2122 | msec = (msec * 1000) / scale; | ||
2123 | if (msec == 0) | ||
2124 | mddev->safemode_delay = 0; | ||
2125 | else { | ||
2126 | mddev->safemode_delay = (msec*HZ)/1000; | ||
2127 | if (mddev->safemode_delay == 0) | ||
2128 | mddev->safemode_delay = 1; | ||
2129 | } | ||
2130 | return len; | ||
2131 | } | ||
2132 | static struct md_sysfs_entry md_safe_delay = | ||
2133 | __ATTR(safe_mode_delay, 0644,safe_delay_show, safe_delay_store); | ||
2134 | |||
2135 | static ssize_t | ||
1981 | level_show(mddev_t *mddev, char *page) | 2136 | level_show(mddev_t *mddev, char *page) |
1982 | { | 2137 | { |
1983 | struct mdk_personality *p = mddev->pers; | 2138 | struct mdk_personality *p = mddev->pers; |
@@ -2012,6 +2167,32 @@ level_store(mddev_t *mddev, const char *buf, size_t len) | |||
2012 | static struct md_sysfs_entry md_level = | 2167 | static struct md_sysfs_entry md_level = |
2013 | __ATTR(level, 0644, level_show, level_store); | 2168 | __ATTR(level, 0644, level_show, level_store); |
2014 | 2169 | ||
2170 | |||
2171 | static ssize_t | ||
2172 | layout_show(mddev_t *mddev, char *page) | ||
2173 | { | ||
2174 | /* just a number, not meaningful for all levels */ | ||
2175 | return sprintf(page, "%d\n", mddev->layout); | ||
2176 | } | ||
2177 | |||
2178 | static ssize_t | ||
2179 | layout_store(mddev_t *mddev, const char *buf, size_t len) | ||
2180 | { | ||
2181 | char *e; | ||
2182 | unsigned long n = simple_strtoul(buf, &e, 10); | ||
2183 | if (mddev->pers) | ||
2184 | return -EBUSY; | ||
2185 | |||
2186 | if (!*buf || (*e && *e != '\n')) | ||
2187 | return -EINVAL; | ||
2188 | |||
2189 | mddev->layout = n; | ||
2190 | return len; | ||
2191 | } | ||
2192 | static struct md_sysfs_entry md_layout = | ||
2193 | __ATTR(layout, 0655, layout_show, layout_store); | ||
2194 | |||
2195 | |||
2015 | static ssize_t | 2196 | static ssize_t |
2016 | raid_disks_show(mddev_t *mddev, char *page) | 2197 | raid_disks_show(mddev_t *mddev, char *page) |
2017 | { | 2198 | { |
@@ -2067,6 +2248,200 @@ static struct md_sysfs_entry md_chunk_size = | |||
2067 | __ATTR(chunk_size, 0644, chunk_size_show, chunk_size_store); | 2248 | __ATTR(chunk_size, 0644, chunk_size_show, chunk_size_store); |
2068 | 2249 | ||
2069 | static ssize_t | 2250 | static ssize_t |
2251 | resync_start_show(mddev_t *mddev, char *page) | ||
2252 | { | ||
2253 | return sprintf(page, "%llu\n", (unsigned long long)mddev->recovery_cp); | ||
2254 | } | ||
2255 | |||
2256 | static ssize_t | ||
2257 | resync_start_store(mddev_t *mddev, const char *buf, size_t len) | ||
2258 | { | ||
2259 | /* can only set chunk_size if array is not yet active */ | ||
2260 | char *e; | ||
2261 | unsigned long long n = simple_strtoull(buf, &e, 10); | ||
2262 | |||
2263 | if (mddev->pers) | ||
2264 | return -EBUSY; | ||
2265 | if (!*buf || (*e && *e != '\n')) | ||
2266 | return -EINVAL; | ||
2267 | |||
2268 | mddev->recovery_cp = n; | ||
2269 | return len; | ||
2270 | } | ||
2271 | static struct md_sysfs_entry md_resync_start = | ||
2272 | __ATTR(resync_start, 0644, resync_start_show, resync_start_store); | ||
2273 | |||
2274 | /* | ||
2275 | * The array state can be: | ||
2276 | * | ||
2277 | * clear | ||
2278 | * No devices, no size, no level | ||
2279 | * Equivalent to STOP_ARRAY ioctl | ||
2280 | * inactive | ||
2281 | * May have some settings, but array is not active | ||
2282 | * all IO results in error | ||
2283 | * When written, doesn't tear down array, but just stops it | ||
2284 | * suspended (not supported yet) | ||
2285 | * All IO requests will block. The array can be reconfigured. | ||
2286 | * Writing this, if accepted, will block until array is quiessent | ||
2287 | * readonly | ||
2288 | * no resync can happen. no superblocks get written. | ||
2289 | * write requests fail | ||
2290 | * read-auto | ||
2291 | * like readonly, but behaves like 'clean' on a write request. | ||
2292 | * | ||
2293 | * clean - no pending writes, but otherwise active. | ||
2294 | * When written to inactive array, starts without resync | ||
2295 | * If a write request arrives then | ||
2296 | * if metadata is known, mark 'dirty' and switch to 'active'. | ||
2297 | * if not known, block and switch to write-pending | ||
2298 | * If written to an active array that has pending writes, then fails. | ||
2299 | * active | ||
2300 | * fully active: IO and resync can be happening. | ||
2301 | * When written to inactive array, starts with resync | ||
2302 | * | ||
2303 | * write-pending | ||
2304 | * clean, but writes are blocked waiting for 'active' to be written. | ||
2305 | * | ||
2306 | * active-idle | ||
2307 | * like active, but no writes have been seen for a while (100msec). | ||
2308 | * | ||
2309 | */ | ||
2310 | enum array_state { clear, inactive, suspended, readonly, read_auto, clean, active, | ||
2311 | write_pending, active_idle, bad_word}; | ||
2312 | static char *array_states[] = { | ||
2313 | "clear", "inactive", "suspended", "readonly", "read-auto", "clean", "active", | ||
2314 | "write-pending", "active-idle", NULL }; | ||
2315 | |||
2316 | static int match_word(const char *word, char **list) | ||
2317 | { | ||
2318 | int n; | ||
2319 | for (n=0; list[n]; n++) | ||
2320 | if (cmd_match(word, list[n])) | ||
2321 | break; | ||
2322 | return n; | ||
2323 | } | ||
2324 | |||
2325 | static ssize_t | ||
2326 | array_state_show(mddev_t *mddev, char *page) | ||
2327 | { | ||
2328 | enum array_state st = inactive; | ||
2329 | |||
2330 | if (mddev->pers) | ||
2331 | switch(mddev->ro) { | ||
2332 | case 1: | ||
2333 | st = readonly; | ||
2334 | break; | ||
2335 | case 2: | ||
2336 | st = read_auto; | ||
2337 | break; | ||
2338 | case 0: | ||
2339 | if (mddev->in_sync) | ||
2340 | st = clean; | ||
2341 | else if (mddev->safemode) | ||
2342 | st = active_idle; | ||
2343 | else | ||
2344 | st = active; | ||
2345 | } | ||
2346 | else { | ||
2347 | if (list_empty(&mddev->disks) && | ||
2348 | mddev->raid_disks == 0 && | ||
2349 | mddev->size == 0) | ||
2350 | st = clear; | ||
2351 | else | ||
2352 | st = inactive; | ||
2353 | } | ||
2354 | return sprintf(page, "%s\n", array_states[st]); | ||
2355 | } | ||
2356 | |||
2357 | static int do_md_stop(mddev_t * mddev, int ro); | ||
2358 | static int do_md_run(mddev_t * mddev); | ||
2359 | static int restart_array(mddev_t *mddev); | ||
2360 | |||
2361 | static ssize_t | ||
2362 | array_state_store(mddev_t *mddev, const char *buf, size_t len) | ||
2363 | { | ||
2364 | int err = -EINVAL; | ||
2365 | enum array_state st = match_word(buf, array_states); | ||
2366 | switch(st) { | ||
2367 | case bad_word: | ||
2368 | break; | ||
2369 | case clear: | ||
2370 | /* stopping an active array */ | ||
2371 | if (mddev->pers) { | ||
2372 | if (atomic_read(&mddev->active) > 1) | ||
2373 | return -EBUSY; | ||
2374 | err = do_md_stop(mddev, 0); | ||
2375 | } | ||
2376 | break; | ||
2377 | case inactive: | ||
2378 | /* stopping an active array */ | ||
2379 | if (mddev->pers) { | ||
2380 | if (atomic_read(&mddev->active) > 1) | ||
2381 | return -EBUSY; | ||
2382 | err = do_md_stop(mddev, 2); | ||
2383 | } | ||
2384 | break; | ||
2385 | case suspended: | ||
2386 | break; /* not supported yet */ | ||
2387 | case readonly: | ||
2388 | if (mddev->pers) | ||
2389 | err = do_md_stop(mddev, 1); | ||
2390 | else { | ||
2391 | mddev->ro = 1; | ||
2392 | err = do_md_run(mddev); | ||
2393 | } | ||
2394 | break; | ||
2395 | case read_auto: | ||
2396 | /* stopping an active array */ | ||
2397 | if (mddev->pers) { | ||
2398 | err = do_md_stop(mddev, 1); | ||
2399 | if (err == 0) | ||
2400 | mddev->ro = 2; /* FIXME mark devices writable */ | ||
2401 | } else { | ||
2402 | mddev->ro = 2; | ||
2403 | err = do_md_run(mddev); | ||
2404 | } | ||
2405 | break; | ||
2406 | case clean: | ||
2407 | if (mddev->pers) { | ||
2408 | restart_array(mddev); | ||
2409 | spin_lock_irq(&mddev->write_lock); | ||
2410 | if (atomic_read(&mddev->writes_pending) == 0) { | ||
2411 | mddev->in_sync = 1; | ||
2412 | mddev->sb_dirty = 1; | ||
2413 | } | ||
2414 | spin_unlock_irq(&mddev->write_lock); | ||
2415 | } else { | ||
2416 | mddev->ro = 0; | ||
2417 | mddev->recovery_cp = MaxSector; | ||
2418 | err = do_md_run(mddev); | ||
2419 | } | ||
2420 | break; | ||
2421 | case active: | ||
2422 | if (mddev->pers) { | ||
2423 | restart_array(mddev); | ||
2424 | mddev->sb_dirty = 0; | ||
2425 | wake_up(&mddev->sb_wait); | ||
2426 | err = 0; | ||
2427 | } else { | ||
2428 | mddev->ro = 0; | ||
2429 | err = do_md_run(mddev); | ||
2430 | } | ||
2431 | break; | ||
2432 | case write_pending: | ||
2433 | case active_idle: | ||
2434 | /* these cannot be set */ | ||
2435 | break; | ||
2436 | } | ||
2437 | if (err) | ||
2438 | return err; | ||
2439 | else | ||
2440 | return len; | ||
2441 | } | ||
2442 | static struct md_sysfs_entry md_array_state = __ATTR(array_state, 0644, array_state_show, array_state_store); | ||
2443 | |||
2444 | static ssize_t | ||
2070 | null_show(mddev_t *mddev, char *page) | 2445 | null_show(mddev_t *mddev, char *page) |
2071 | { | 2446 | { |
2072 | return -EINVAL; | 2447 | return -EINVAL; |
@@ -2428,11 +2803,15 @@ __ATTR(suspend_hi, S_IRUGO|S_IWUSR, suspend_hi_show, suspend_hi_store); | |||
2428 | 2803 | ||
2429 | static struct attribute *md_default_attrs[] = { | 2804 | static struct attribute *md_default_attrs[] = { |
2430 | &md_level.attr, | 2805 | &md_level.attr, |
2806 | &md_layout.attr, | ||
2431 | &md_raid_disks.attr, | 2807 | &md_raid_disks.attr, |
2432 | &md_chunk_size.attr, | 2808 | &md_chunk_size.attr, |
2433 | &md_size.attr, | 2809 | &md_size.attr, |
2810 | &md_resync_start.attr, | ||
2434 | &md_metadata.attr, | 2811 | &md_metadata.attr, |
2435 | &md_new_device.attr, | 2812 | &md_new_device.attr, |
2813 | &md_safe_delay.attr, | ||
2814 | &md_array_state.attr, | ||
2436 | NULL, | 2815 | NULL, |
2437 | }; | 2816 | }; |
2438 | 2817 | ||
@@ -2553,8 +2932,6 @@ static struct kobject *md_probe(dev_t dev, int *part, void *data) | |||
2553 | return NULL; | 2932 | return NULL; |
2554 | } | 2933 | } |
2555 | 2934 | ||
2556 | void md_wakeup_thread(mdk_thread_t *thread); | ||
2557 | |||
2558 | static void md_safemode_timeout(unsigned long data) | 2935 | static void md_safemode_timeout(unsigned long data) |
2559 | { | 2936 | { |
2560 | mddev_t *mddev = (mddev_t *) data; | 2937 | mddev_t *mddev = (mddev_t *) data; |
@@ -2708,7 +3085,7 @@ static int do_md_run(mddev_t * mddev) | |||
2708 | mddev->safemode = 0; | 3085 | mddev->safemode = 0; |
2709 | mddev->safemode_timer.function = md_safemode_timeout; | 3086 | mddev->safemode_timer.function = md_safemode_timeout; |
2710 | mddev->safemode_timer.data = (unsigned long) mddev; | 3087 | mddev->safemode_timer.data = (unsigned long) mddev; |
2711 | mddev->safemode_delay = (20 * HZ)/1000 +1; /* 20 msec delay */ | 3088 | mddev->safemode_delay = (200 * HZ)/1000 +1; /* 200 msec delay */ |
2712 | mddev->in_sync = 1; | 3089 | mddev->in_sync = 1; |
2713 | 3090 | ||
2714 | ITERATE_RDEV(mddev,rdev,tmp) | 3091 | ITERATE_RDEV(mddev,rdev,tmp) |
@@ -2736,6 +3113,36 @@ static int do_md_run(mddev_t * mddev) | |||
2736 | mddev->queue->queuedata = mddev; | 3113 | mddev->queue->queuedata = mddev; |
2737 | mddev->queue->make_request_fn = mddev->pers->make_request; | 3114 | mddev->queue->make_request_fn = mddev->pers->make_request; |
2738 | 3115 | ||
3116 | /* If there is a partially-recovered drive we need to | ||
3117 | * start recovery here. If we leave it to md_check_recovery, | ||
3118 | * it will remove the drives and not do the right thing | ||
3119 | */ | ||
3120 | if (mddev->degraded) { | ||
3121 | struct list_head *rtmp; | ||
3122 | int spares = 0; | ||
3123 | ITERATE_RDEV(mddev,rdev,rtmp) | ||
3124 | if (rdev->raid_disk >= 0 && | ||
3125 | !test_bit(In_sync, &rdev->flags) && | ||
3126 | !test_bit(Faulty, &rdev->flags)) | ||
3127 | /* complete an interrupted recovery */ | ||
3128 | spares++; | ||
3129 | if (spares && mddev->pers->sync_request) { | ||
3130 | mddev->recovery = 0; | ||
3131 | set_bit(MD_RECOVERY_RUNNING, &mddev->recovery); | ||
3132 | mddev->sync_thread = md_register_thread(md_do_sync, | ||
3133 | mddev, | ||
3134 | "%s_resync"); | ||
3135 | if (!mddev->sync_thread) { | ||
3136 | printk(KERN_ERR "%s: could not start resync" | ||
3137 | " thread...\n", | ||
3138 | mdname(mddev)); | ||
3139 | /* leave the spares where they are, it shouldn't hurt */ | ||
3140 | mddev->recovery = 0; | ||
3141 | } else | ||
3142 | md_wakeup_thread(mddev->sync_thread); | ||
3143 | } | ||
3144 | } | ||
3145 | |||
2739 | mddev->changed = 1; | 3146 | mddev->changed = 1; |
2740 | md_new_event(mddev); | 3147 | md_new_event(mddev); |
2741 | return 0; | 3148 | return 0; |
@@ -2769,18 +3176,47 @@ static int restart_array(mddev_t *mddev) | |||
2769 | */ | 3176 | */ |
2770 | set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); | 3177 | set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); |
2771 | md_wakeup_thread(mddev->thread); | 3178 | md_wakeup_thread(mddev->thread); |
3179 | md_wakeup_thread(mddev->sync_thread); | ||
2772 | err = 0; | 3180 | err = 0; |
2773 | } else { | 3181 | } else |
2774 | printk(KERN_ERR "md: %s has no personality assigned.\n", | ||
2775 | mdname(mddev)); | ||
2776 | err = -EINVAL; | 3182 | err = -EINVAL; |
2777 | } | ||
2778 | 3183 | ||
2779 | out: | 3184 | out: |
2780 | return err; | 3185 | return err; |
2781 | } | 3186 | } |
2782 | 3187 | ||
2783 | static int do_md_stop(mddev_t * mddev, int ro) | 3188 | /* similar to deny_write_access, but accounts for our holding a reference |
3189 | * to the file ourselves */ | ||
3190 | static int deny_bitmap_write_access(struct file * file) | ||
3191 | { | ||
3192 | struct inode *inode = file->f_mapping->host; | ||
3193 | |||
3194 | spin_lock(&inode->i_lock); | ||
3195 | if (atomic_read(&inode->i_writecount) > 1) { | ||
3196 | spin_unlock(&inode->i_lock); | ||
3197 | return -ETXTBSY; | ||
3198 | } | ||
3199 | atomic_set(&inode->i_writecount, -1); | ||
3200 | spin_unlock(&inode->i_lock); | ||
3201 | |||
3202 | return 0; | ||
3203 | } | ||
3204 | |||
3205 | static void restore_bitmap_write_access(struct file *file) | ||
3206 | { | ||
3207 | struct inode *inode = file->f_mapping->host; | ||
3208 | |||
3209 | spin_lock(&inode->i_lock); | ||
3210 | atomic_set(&inode->i_writecount, 1); | ||
3211 | spin_unlock(&inode->i_lock); | ||
3212 | } | ||
3213 | |||
3214 | /* mode: | ||
3215 | * 0 - completely stop and dis-assemble array | ||
3216 | * 1 - switch to readonly | ||
3217 | * 2 - stop but do not disassemble array | ||
3218 | */ | ||
3219 | static int do_md_stop(mddev_t * mddev, int mode) | ||
2784 | { | 3220 | { |
2785 | int err = 0; | 3221 | int err = 0; |
2786 | struct gendisk *disk = mddev->gendisk; | 3222 | struct gendisk *disk = mddev->gendisk; |
@@ -2792,6 +3228,7 @@ static int do_md_stop(mddev_t * mddev, int ro) | |||
2792 | } | 3228 | } |
2793 | 3229 | ||
2794 | if (mddev->sync_thread) { | 3230 | if (mddev->sync_thread) { |
3231 | set_bit(MD_RECOVERY_FROZEN, &mddev->recovery); | ||
2795 | set_bit(MD_RECOVERY_INTR, &mddev->recovery); | 3232 | set_bit(MD_RECOVERY_INTR, &mddev->recovery); |
2796 | md_unregister_thread(mddev->sync_thread); | 3233 | md_unregister_thread(mddev->sync_thread); |
2797 | mddev->sync_thread = NULL; | 3234 | mddev->sync_thread = NULL; |
@@ -2801,12 +3238,15 @@ static int do_md_stop(mddev_t * mddev, int ro) | |||
2801 | 3238 | ||
2802 | invalidate_partition(disk, 0); | 3239 | invalidate_partition(disk, 0); |
2803 | 3240 | ||
2804 | if (ro) { | 3241 | switch(mode) { |
3242 | case 1: /* readonly */ | ||
2805 | err = -ENXIO; | 3243 | err = -ENXIO; |
2806 | if (mddev->ro==1) | 3244 | if (mddev->ro==1) |
2807 | goto out; | 3245 | goto out; |
2808 | mddev->ro = 1; | 3246 | mddev->ro = 1; |
2809 | } else { | 3247 | break; |
3248 | case 0: /* disassemble */ | ||
3249 | case 2: /* stop */ | ||
2810 | bitmap_flush(mddev); | 3250 | bitmap_flush(mddev); |
2811 | md_super_wait(mddev); | 3251 | md_super_wait(mddev); |
2812 | if (mddev->ro) | 3252 | if (mddev->ro) |
@@ -2821,19 +3261,20 @@ static int do_md_stop(mddev_t * mddev, int ro) | |||
2821 | if (mddev->ro) | 3261 | if (mddev->ro) |
2822 | mddev->ro = 0; | 3262 | mddev->ro = 0; |
2823 | } | 3263 | } |
2824 | if (!mddev->in_sync) { | 3264 | if (!mddev->in_sync || mddev->sb_dirty) { |
2825 | /* mark array as shutdown cleanly */ | 3265 | /* mark array as shutdown cleanly */ |
2826 | mddev->in_sync = 1; | 3266 | mddev->in_sync = 1; |
2827 | md_update_sb(mddev); | 3267 | md_update_sb(mddev); |
2828 | } | 3268 | } |
2829 | if (ro) | 3269 | if (mode == 1) |
2830 | set_disk_ro(disk, 1); | 3270 | set_disk_ro(disk, 1); |
3271 | clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery); | ||
2831 | } | 3272 | } |
2832 | 3273 | ||
2833 | /* | 3274 | /* |
2834 | * Free resources if final stop | 3275 | * Free resources if final stop |
2835 | */ | 3276 | */ |
2836 | if (!ro) { | 3277 | if (mode == 0) { |
2837 | mdk_rdev_t *rdev; | 3278 | mdk_rdev_t *rdev; |
2838 | struct list_head *tmp; | 3279 | struct list_head *tmp; |
2839 | struct gendisk *disk; | 3280 | struct gendisk *disk; |
@@ -2841,7 +3282,7 @@ static int do_md_stop(mddev_t * mddev, int ro) | |||
2841 | 3282 | ||
2842 | bitmap_destroy(mddev); | 3283 | bitmap_destroy(mddev); |
2843 | if (mddev->bitmap_file) { | 3284 | if (mddev->bitmap_file) { |
2844 | atomic_set(&mddev->bitmap_file->f_dentry->d_inode->i_writecount, 1); | 3285 | restore_bitmap_write_access(mddev->bitmap_file); |
2845 | fput(mddev->bitmap_file); | 3286 | fput(mddev->bitmap_file); |
2846 | mddev->bitmap_file = NULL; | 3287 | mddev->bitmap_file = NULL; |
2847 | } | 3288 | } |
@@ -2857,11 +3298,15 @@ static int do_md_stop(mddev_t * mddev, int ro) | |||
2857 | export_array(mddev); | 3298 | export_array(mddev); |
2858 | 3299 | ||
2859 | mddev->array_size = 0; | 3300 | mddev->array_size = 0; |
3301 | mddev->size = 0; | ||
3302 | mddev->raid_disks = 0; | ||
3303 | mddev->recovery_cp = 0; | ||
3304 | |||
2860 | disk = mddev->gendisk; | 3305 | disk = mddev->gendisk; |
2861 | if (disk) | 3306 | if (disk) |
2862 | set_capacity(disk, 0); | 3307 | set_capacity(disk, 0); |
2863 | mddev->changed = 1; | 3308 | mddev->changed = 1; |
2864 | } else | 3309 | } else if (mddev->pers) |
2865 | printk(KERN_INFO "md: %s switched to read-only mode.\n", | 3310 | printk(KERN_INFO "md: %s switched to read-only mode.\n", |
2866 | mdname(mddev)); | 3311 | mdname(mddev)); |
2867 | err = 0; | 3312 | err = 0; |
@@ -3264,6 +3709,17 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info) | |||
3264 | 3709 | ||
3265 | rdev->raid_disk = -1; | 3710 | rdev->raid_disk = -1; |
3266 | err = bind_rdev_to_array(rdev, mddev); | 3711 | err = bind_rdev_to_array(rdev, mddev); |
3712 | if (!err && !mddev->pers->hot_remove_disk) { | ||
3713 | /* If there is hot_add_disk but no hot_remove_disk | ||
3714 | * then added disks for geometry changes, | ||
3715 | * and should be added immediately. | ||
3716 | */ | ||
3717 | super_types[mddev->major_version]. | ||
3718 | validate_super(mddev, rdev); | ||
3719 | err = mddev->pers->hot_add_disk(mddev, rdev); | ||
3720 | if (err) | ||
3721 | unbind_rdev_from_array(rdev); | ||
3722 | } | ||
3267 | if (err) | 3723 | if (err) |
3268 | export_rdev(rdev); | 3724 | export_rdev(rdev); |
3269 | 3725 | ||
@@ -3434,23 +3890,6 @@ abort_export: | |||
3434 | return err; | 3890 | return err; |
3435 | } | 3891 | } |
3436 | 3892 | ||
3437 | /* similar to deny_write_access, but accounts for our holding a reference | ||
3438 | * to the file ourselves */ | ||
3439 | static int deny_bitmap_write_access(struct file * file) | ||
3440 | { | ||
3441 | struct inode *inode = file->f_mapping->host; | ||
3442 | |||
3443 | spin_lock(&inode->i_lock); | ||
3444 | if (atomic_read(&inode->i_writecount) > 1) { | ||
3445 | spin_unlock(&inode->i_lock); | ||
3446 | return -ETXTBSY; | ||
3447 | } | ||
3448 | atomic_set(&inode->i_writecount, -1); | ||
3449 | spin_unlock(&inode->i_lock); | ||
3450 | |||
3451 | return 0; | ||
3452 | } | ||
3453 | |||
3454 | static int set_bitmap_file(mddev_t *mddev, int fd) | 3893 | static int set_bitmap_file(mddev_t *mddev, int fd) |
3455 | { | 3894 | { |
3456 | int err; | 3895 | int err; |
@@ -3491,12 +3930,17 @@ static int set_bitmap_file(mddev_t *mddev, int fd) | |||
3491 | mddev->pers->quiesce(mddev, 1); | 3930 | mddev->pers->quiesce(mddev, 1); |
3492 | if (fd >= 0) | 3931 | if (fd >= 0) |
3493 | err = bitmap_create(mddev); | 3932 | err = bitmap_create(mddev); |
3494 | if (fd < 0 || err) | 3933 | if (fd < 0 || err) { |
3495 | bitmap_destroy(mddev); | 3934 | bitmap_destroy(mddev); |
3935 | fd = -1; /* make sure to put the file */ | ||
3936 | } | ||
3496 | mddev->pers->quiesce(mddev, 0); | 3937 | mddev->pers->quiesce(mddev, 0); |
3497 | } else if (fd < 0) { | 3938 | } |
3498 | if (mddev->bitmap_file) | 3939 | if (fd < 0) { |
3940 | if (mddev->bitmap_file) { | ||
3941 | restore_bitmap_write_access(mddev->bitmap_file); | ||
3499 | fput(mddev->bitmap_file); | 3942 | fput(mddev->bitmap_file); |
3943 | } | ||
3500 | mddev->bitmap_file = NULL; | 3944 | mddev->bitmap_file = NULL; |
3501 | } | 3945 | } |
3502 | 3946 | ||
@@ -3977,11 +4421,6 @@ static int md_ioctl(struct inode *inode, struct file *file, | |||
3977 | goto done_unlock; | 4421 | goto done_unlock; |
3978 | 4422 | ||
3979 | default: | 4423 | default: |
3980 | if (_IOC_TYPE(cmd) == MD_MAJOR) | ||
3981 | printk(KERN_WARNING "md: %s(pid %d) used" | ||
3982 | " obsolete MD ioctl, upgrade your" | ||
3983 | " software to use new ictls.\n", | ||
3984 | current->comm, current->pid); | ||
3985 | err = -EINVAL; | 4424 | err = -EINVAL; |
3986 | goto abort_unlock; | 4425 | goto abort_unlock; |
3987 | } | 4426 | } |
@@ -4586,7 +5025,7 @@ void md_write_start(mddev_t *mddev, struct bio *bi) | |||
4586 | spin_lock_irq(&mddev->write_lock); | 5025 | spin_lock_irq(&mddev->write_lock); |
4587 | if (mddev->in_sync) { | 5026 | if (mddev->in_sync) { |
4588 | mddev->in_sync = 0; | 5027 | mddev->in_sync = 0; |
4589 | mddev->sb_dirty = 1; | 5028 | mddev->sb_dirty = 3; |
4590 | md_wakeup_thread(mddev->thread); | 5029 | md_wakeup_thread(mddev->thread); |
4591 | } | 5030 | } |
4592 | spin_unlock_irq(&mddev->write_lock); | 5031 | spin_unlock_irq(&mddev->write_lock); |
@@ -4599,7 +5038,7 @@ void md_write_end(mddev_t *mddev) | |||
4599 | if (atomic_dec_and_test(&mddev->writes_pending)) { | 5038 | if (atomic_dec_and_test(&mddev->writes_pending)) { |
4600 | if (mddev->safemode == 2) | 5039 | if (mddev->safemode == 2) |
4601 | md_wakeup_thread(mddev->thread); | 5040 | md_wakeup_thread(mddev->thread); |
4602 | else | 5041 | else if (mddev->safemode_delay) |
4603 | mod_timer(&mddev->safemode_timer, jiffies + mddev->safemode_delay); | 5042 | mod_timer(&mddev->safemode_timer, jiffies + mddev->safemode_delay); |
4604 | } | 5043 | } |
4605 | } | 5044 | } |
@@ -4620,10 +5059,14 @@ void md_do_sync(mddev_t *mddev) | |||
4620 | struct list_head *tmp; | 5059 | struct list_head *tmp; |
4621 | sector_t last_check; | 5060 | sector_t last_check; |
4622 | int skipped = 0; | 5061 | int skipped = 0; |
5062 | struct list_head *rtmp; | ||
5063 | mdk_rdev_t *rdev; | ||
4623 | 5064 | ||
4624 | /* just incase thread restarts... */ | 5065 | /* just incase thread restarts... */ |
4625 | if (test_bit(MD_RECOVERY_DONE, &mddev->recovery)) | 5066 | if (test_bit(MD_RECOVERY_DONE, &mddev->recovery)) |
4626 | return; | 5067 | return; |
5068 | if (mddev->ro) /* never try to sync a read-only array */ | ||
5069 | return; | ||
4627 | 5070 | ||
4628 | /* we overload curr_resync somewhat here. | 5071 | /* we overload curr_resync somewhat here. |
4629 | * 0 == not engaged in resync at all | 5072 | * 0 == not engaged in resync at all |
@@ -4682,17 +5125,30 @@ void md_do_sync(mddev_t *mddev) | |||
4682 | } | 5125 | } |
4683 | } while (mddev->curr_resync < 2); | 5126 | } while (mddev->curr_resync < 2); |
4684 | 5127 | ||
5128 | j = 0; | ||
4685 | if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) { | 5129 | if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) { |
4686 | /* resync follows the size requested by the personality, | 5130 | /* resync follows the size requested by the personality, |
4687 | * which defaults to physical size, but can be virtual size | 5131 | * which defaults to physical size, but can be virtual size |
4688 | */ | 5132 | */ |
4689 | max_sectors = mddev->resync_max_sectors; | 5133 | max_sectors = mddev->resync_max_sectors; |
4690 | mddev->resync_mismatches = 0; | 5134 | mddev->resync_mismatches = 0; |
5135 | /* we don't use the checkpoint if there's a bitmap */ | ||
5136 | if (!mddev->bitmap && | ||
5137 | !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) | ||
5138 | j = mddev->recovery_cp; | ||
4691 | } else if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)) | 5139 | } else if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)) |
4692 | max_sectors = mddev->size << 1; | 5140 | max_sectors = mddev->size << 1; |
4693 | else | 5141 | else { |
4694 | /* recovery follows the physical size of devices */ | 5142 | /* recovery follows the physical size of devices */ |
4695 | max_sectors = mddev->size << 1; | 5143 | max_sectors = mddev->size << 1; |
5144 | j = MaxSector; | ||
5145 | ITERATE_RDEV(mddev,rdev,rtmp) | ||
5146 | if (rdev->raid_disk >= 0 && | ||
5147 | !test_bit(Faulty, &rdev->flags) && | ||
5148 | !test_bit(In_sync, &rdev->flags) && | ||
5149 | rdev->recovery_offset < j) | ||
5150 | j = rdev->recovery_offset; | ||
5151 | } | ||
4696 | 5152 | ||
4697 | printk(KERN_INFO "md: syncing RAID array %s\n", mdname(mddev)); | 5153 | printk(KERN_INFO "md: syncing RAID array %s\n", mdname(mddev)); |
4698 | printk(KERN_INFO "md: minimum _guaranteed_ reconstruction speed:" | 5154 | printk(KERN_INFO "md: minimum _guaranteed_ reconstruction speed:" |
@@ -4702,12 +5158,7 @@ void md_do_sync(mddev_t *mddev) | |||
4702 | speed_max(mddev)); | 5158 | speed_max(mddev)); |
4703 | 5159 | ||
4704 | is_mddev_idle(mddev); /* this also initializes IO event counters */ | 5160 | is_mddev_idle(mddev); /* this also initializes IO event counters */ |
4705 | /* we don't use the checkpoint if there's a bitmap */ | 5161 | |
4706 | if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery) && !mddev->bitmap | ||
4707 | && ! test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) | ||
4708 | j = mddev->recovery_cp; | ||
4709 | else | ||
4710 | j = 0; | ||
4711 | io_sectors = 0; | 5162 | io_sectors = 0; |
4712 | for (m = 0; m < SYNC_MARKS; m++) { | 5163 | for (m = 0; m < SYNC_MARKS; m++) { |
4713 | mark[m] = jiffies; | 5164 | mark[m] = jiffies; |
@@ -4828,15 +5279,28 @@ void md_do_sync(mddev_t *mddev) | |||
4828 | if (!test_bit(MD_RECOVERY_ERR, &mddev->recovery) && | 5279 | if (!test_bit(MD_RECOVERY_ERR, &mddev->recovery) && |
4829 | test_bit(MD_RECOVERY_SYNC, &mddev->recovery) && | 5280 | test_bit(MD_RECOVERY_SYNC, &mddev->recovery) && |
4830 | !test_bit(MD_RECOVERY_CHECK, &mddev->recovery) && | 5281 | !test_bit(MD_RECOVERY_CHECK, &mddev->recovery) && |
4831 | mddev->curr_resync > 2 && | 5282 | mddev->curr_resync > 2) { |
4832 | mddev->curr_resync >= mddev->recovery_cp) { | 5283 | if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) { |
4833 | if (test_bit(MD_RECOVERY_INTR, &mddev->recovery)) { | 5284 | if (test_bit(MD_RECOVERY_INTR, &mddev->recovery)) { |
4834 | printk(KERN_INFO | 5285 | if (mddev->curr_resync >= mddev->recovery_cp) { |
4835 | "md: checkpointing recovery of %s.\n", | 5286 | printk(KERN_INFO |
4836 | mdname(mddev)); | 5287 | "md: checkpointing recovery of %s.\n", |
4837 | mddev->recovery_cp = mddev->curr_resync; | 5288 | mdname(mddev)); |
4838 | } else | 5289 | mddev->recovery_cp = mddev->curr_resync; |
4839 | mddev->recovery_cp = MaxSector; | 5290 | } |
5291 | } else | ||
5292 | mddev->recovery_cp = MaxSector; | ||
5293 | } else { | ||
5294 | if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery)) | ||
5295 | mddev->curr_resync = MaxSector; | ||
5296 | ITERATE_RDEV(mddev,rdev,rtmp) | ||
5297 | if (rdev->raid_disk >= 0 && | ||
5298 | !test_bit(Faulty, &rdev->flags) && | ||
5299 | !test_bit(In_sync, &rdev->flags) && | ||
5300 | rdev->recovery_offset < mddev->curr_resync) | ||
5301 | rdev->recovery_offset = mddev->curr_resync; | ||
5302 | mddev->sb_dirty = 1; | ||
5303 | } | ||
4840 | } | 5304 | } |
4841 | 5305 | ||
4842 | skip: | 5306 | skip: |
@@ -4908,7 +5372,7 @@ void md_check_recovery(mddev_t *mddev) | |||
4908 | if (mddev->safemode && !atomic_read(&mddev->writes_pending) && | 5372 | if (mddev->safemode && !atomic_read(&mddev->writes_pending) && |
4909 | !mddev->in_sync && mddev->recovery_cp == MaxSector) { | 5373 | !mddev->in_sync && mddev->recovery_cp == MaxSector) { |
4910 | mddev->in_sync = 1; | 5374 | mddev->in_sync = 1; |
4911 | mddev->sb_dirty = 1; | 5375 | mddev->sb_dirty = 3; |
4912 | } | 5376 | } |
4913 | if (mddev->safemode == 1) | 5377 | if (mddev->safemode == 1) |
4914 | mddev->safemode = 0; | 5378 | mddev->safemode = 0; |
@@ -4957,6 +5421,8 @@ void md_check_recovery(mddev_t *mddev) | |||
4957 | clear_bit(MD_RECOVERY_INTR, &mddev->recovery); | 5421 | clear_bit(MD_RECOVERY_INTR, &mddev->recovery); |
4958 | clear_bit(MD_RECOVERY_DONE, &mddev->recovery); | 5422 | clear_bit(MD_RECOVERY_DONE, &mddev->recovery); |
4959 | 5423 | ||
5424 | if (test_bit(MD_RECOVERY_FROZEN, &mddev->recovery)) | ||
5425 | goto unlock; | ||
4960 | /* no recovery is running. | 5426 | /* no recovery is running. |
4961 | * remove any failed drives, then | 5427 | * remove any failed drives, then |
4962 | * add spares if possible. | 5428 | * add spares if possible. |
@@ -4979,6 +5445,7 @@ void md_check_recovery(mddev_t *mddev) | |||
4979 | ITERATE_RDEV(mddev,rdev,rtmp) | 5445 | ITERATE_RDEV(mddev,rdev,rtmp) |
4980 | if (rdev->raid_disk < 0 | 5446 | if (rdev->raid_disk < 0 |
4981 | && !test_bit(Faulty, &rdev->flags)) { | 5447 | && !test_bit(Faulty, &rdev->flags)) { |
5448 | rdev->recovery_offset = 0; | ||
4982 | if (mddev->pers->hot_add_disk(mddev,rdev)) { | 5449 | if (mddev->pers->hot_add_disk(mddev,rdev)) { |
4983 | char nm[20]; | 5450 | char nm[20]; |
4984 | sprintf(nm, "rd%d", rdev->raid_disk); | 5451 | sprintf(nm, "rd%d", rdev->raid_disk); |
@@ -5216,7 +5683,6 @@ EXPORT_SYMBOL(md_write_end); | |||
5216 | EXPORT_SYMBOL(md_register_thread); | 5683 | EXPORT_SYMBOL(md_register_thread); |
5217 | EXPORT_SYMBOL(md_unregister_thread); | 5684 | EXPORT_SYMBOL(md_unregister_thread); |
5218 | EXPORT_SYMBOL(md_wakeup_thread); | 5685 | EXPORT_SYMBOL(md_wakeup_thread); |
5219 | EXPORT_SYMBOL(md_print_devices); | ||
5220 | EXPORT_SYMBOL(md_check_recovery); | 5686 | EXPORT_SYMBOL(md_check_recovery); |
5221 | MODULE_LICENSE("GPL"); | 5687 | MODULE_LICENSE("GPL"); |
5222 | MODULE_ALIAS("md"); | 5688 | MODULE_ALIAS("md"); |
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 4070eff6f0f8..cead918578a7 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c | |||
@@ -374,26 +374,26 @@ static int raid1_end_write_request(struct bio *bio, unsigned int bytes_done, int | |||
374 | * already. | 374 | * already. |
375 | */ | 375 | */ |
376 | if (atomic_dec_and_test(&r1_bio->remaining)) { | 376 | if (atomic_dec_and_test(&r1_bio->remaining)) { |
377 | if (test_bit(R1BIO_BarrierRetry, &r1_bio->state)) { | 377 | if (test_bit(R1BIO_BarrierRetry, &r1_bio->state)) |
378 | reschedule_retry(r1_bio); | 378 | reschedule_retry(r1_bio); |
379 | goto out; | 379 | else { |
380 | } | 380 | /* it really is the end of this request */ |
381 | /* it really is the end of this request */ | 381 | if (test_bit(R1BIO_BehindIO, &r1_bio->state)) { |
382 | if (test_bit(R1BIO_BehindIO, &r1_bio->state)) { | 382 | /* free extra copy of the data pages */ |
383 | /* free extra copy of the data pages */ | 383 | int i = bio->bi_vcnt; |
384 | int i = bio->bi_vcnt; | 384 | while (i--) |
385 | while (i--) | 385 | safe_put_page(bio->bi_io_vec[i].bv_page); |
386 | safe_put_page(bio->bi_io_vec[i].bv_page); | 386 | } |
387 | /* clear the bitmap if all writes complete successfully */ | ||
388 | bitmap_endwrite(r1_bio->mddev->bitmap, r1_bio->sector, | ||
389 | r1_bio->sectors, | ||
390 | !test_bit(R1BIO_Degraded, &r1_bio->state), | ||
391 | behind); | ||
392 | md_write_end(r1_bio->mddev); | ||
393 | raid_end_bio_io(r1_bio); | ||
387 | } | 394 | } |
388 | /* clear the bitmap if all writes complete successfully */ | ||
389 | bitmap_endwrite(r1_bio->mddev->bitmap, r1_bio->sector, | ||
390 | r1_bio->sectors, | ||
391 | !test_bit(R1BIO_Degraded, &r1_bio->state), | ||
392 | behind); | ||
393 | md_write_end(r1_bio->mddev); | ||
394 | raid_end_bio_io(r1_bio); | ||
395 | } | 395 | } |
396 | out: | 396 | |
397 | if (to_put) | 397 | if (to_put) |
398 | bio_put(to_put); | 398 | bio_put(to_put); |
399 | 399 | ||
@@ -1625,6 +1625,12 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i | |||
1625 | /* before building a request, check if we can skip these blocks.. | 1625 | /* before building a request, check if we can skip these blocks.. |
1626 | * This call the bitmap_start_sync doesn't actually record anything | 1626 | * This call the bitmap_start_sync doesn't actually record anything |
1627 | */ | 1627 | */ |
1628 | if (mddev->bitmap == NULL && | ||
1629 | mddev->recovery_cp == MaxSector && | ||
1630 | conf->fullsync == 0) { | ||
1631 | *skipped = 1; | ||
1632 | return max_sector - sector_nr; | ||
1633 | } | ||
1628 | if (!bitmap_start_sync(mddev->bitmap, sector_nr, &sync_blocks, 1) && | 1634 | if (!bitmap_start_sync(mddev->bitmap, sector_nr, &sync_blocks, 1) && |
1629 | !conf->fullsync && !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) { | 1635 | !conf->fullsync && !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) { |
1630 | /* We can skip this block, and probably several more */ | 1636 | /* We can skip this block, and probably several more */ |
@@ -1888,7 +1894,8 @@ static int run(mddev_t *mddev) | |||
1888 | 1894 | ||
1889 | disk = conf->mirrors + i; | 1895 | disk = conf->mirrors + i; |
1890 | 1896 | ||
1891 | if (!disk->rdev) { | 1897 | if (!disk->rdev || |
1898 | !test_bit(In_sync, &disk->rdev->flags)) { | ||
1892 | disk->head_position = 0; | 1899 | disk->head_position = 0; |
1893 | mddev->degraded++; | 1900 | mddev->degraded++; |
1894 | } | 1901 | } |
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 1440935414e6..7f636283a1ba 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c | |||
@@ -29,6 +29,7 @@ | |||
29 | * raid_disks | 29 | * raid_disks |
30 | * near_copies (stored in low byte of layout) | 30 | * near_copies (stored in low byte of layout) |
31 | * far_copies (stored in second byte of layout) | 31 | * far_copies (stored in second byte of layout) |
32 | * far_offset (stored in bit 16 of layout ) | ||
32 | * | 33 | * |
33 | * The data to be stored is divided into chunks using chunksize. | 34 | * The data to be stored is divided into chunks using chunksize. |
34 | * Each device is divided into far_copies sections. | 35 | * Each device is divided into far_copies sections. |
@@ -36,10 +37,14 @@ | |||
36 | * near_copies copies of each chunk is stored (each on a different drive). | 37 | * near_copies copies of each chunk is stored (each on a different drive). |
37 | * The starting device for each section is offset near_copies from the starting | 38 | * The starting device for each section is offset near_copies from the starting |
38 | * device of the previous section. | 39 | * device of the previous section. |
39 | * Thus there are (near_copies*far_copies) of each chunk, and each is on a different | 40 | * Thus they are (near_copies*far_copies) of each chunk, and each is on a different |
40 | * drive. | 41 | * drive. |
41 | * near_copies and far_copies must be at least one, and their product is at most | 42 | * near_copies and far_copies must be at least one, and their product is at most |
42 | * raid_disks. | 43 | * raid_disks. |
44 | * | ||
45 | * If far_offset is true, then the far_copies are handled a bit differently. | ||
46 | * The copies are still in different stripes, but instead of be very far apart | ||
47 | * on disk, there are adjacent stripes. | ||
43 | */ | 48 | */ |
44 | 49 | ||
45 | /* | 50 | /* |
@@ -357,8 +362,7 @@ static int raid10_end_write_request(struct bio *bio, unsigned int bytes_done, in | |||
357 | * With this layout, and block is never stored twice on the one device. | 362 | * With this layout, and block is never stored twice on the one device. |
358 | * | 363 | * |
359 | * raid10_find_phys finds the sector offset of a given virtual sector | 364 | * raid10_find_phys finds the sector offset of a given virtual sector |
360 | * on each device that it is on. If a block isn't on a device, | 365 | * on each device that it is on. |
361 | * that entry in the array is set to MaxSector. | ||
362 | * | 366 | * |
363 | * raid10_find_virt does the reverse mapping, from a device and a | 367 | * raid10_find_virt does the reverse mapping, from a device and a |
364 | * sector offset to a virtual address | 368 | * sector offset to a virtual address |
@@ -381,6 +385,8 @@ static void raid10_find_phys(conf_t *conf, r10bio_t *r10bio) | |||
381 | chunk *= conf->near_copies; | 385 | chunk *= conf->near_copies; |
382 | stripe = chunk; | 386 | stripe = chunk; |
383 | dev = sector_div(stripe, conf->raid_disks); | 387 | dev = sector_div(stripe, conf->raid_disks); |
388 | if (conf->far_offset) | ||
389 | stripe *= conf->far_copies; | ||
384 | 390 | ||
385 | sector += stripe << conf->chunk_shift; | 391 | sector += stripe << conf->chunk_shift; |
386 | 392 | ||
@@ -414,16 +420,24 @@ static sector_t raid10_find_virt(conf_t *conf, sector_t sector, int dev) | |||
414 | { | 420 | { |
415 | sector_t offset, chunk, vchunk; | 421 | sector_t offset, chunk, vchunk; |
416 | 422 | ||
417 | while (sector > conf->stride) { | ||
418 | sector -= conf->stride; | ||
419 | if (dev < conf->near_copies) | ||
420 | dev += conf->raid_disks - conf->near_copies; | ||
421 | else | ||
422 | dev -= conf->near_copies; | ||
423 | } | ||
424 | |||
425 | offset = sector & conf->chunk_mask; | 423 | offset = sector & conf->chunk_mask; |
426 | chunk = sector >> conf->chunk_shift; | 424 | if (conf->far_offset) { |
425 | int fc; | ||
426 | chunk = sector >> conf->chunk_shift; | ||
427 | fc = sector_div(chunk, conf->far_copies); | ||
428 | dev -= fc * conf->near_copies; | ||
429 | if (dev < 0) | ||
430 | dev += conf->raid_disks; | ||
431 | } else { | ||
432 | while (sector > conf->stride) { | ||
433 | sector -= conf->stride; | ||
434 | if (dev < conf->near_copies) | ||
435 | dev += conf->raid_disks - conf->near_copies; | ||
436 | else | ||
437 | dev -= conf->near_copies; | ||
438 | } | ||
439 | chunk = sector >> conf->chunk_shift; | ||
440 | } | ||
427 | vchunk = chunk * conf->raid_disks + dev; | 441 | vchunk = chunk * conf->raid_disks + dev; |
428 | sector_div(vchunk, conf->near_copies); | 442 | sector_div(vchunk, conf->near_copies); |
429 | return (vchunk << conf->chunk_shift) + offset; | 443 | return (vchunk << conf->chunk_shift) + offset; |
@@ -900,9 +914,12 @@ static void status(struct seq_file *seq, mddev_t *mddev) | |||
900 | seq_printf(seq, " %dK chunks", mddev->chunk_size/1024); | 914 | seq_printf(seq, " %dK chunks", mddev->chunk_size/1024); |
901 | if (conf->near_copies > 1) | 915 | if (conf->near_copies > 1) |
902 | seq_printf(seq, " %d near-copies", conf->near_copies); | 916 | seq_printf(seq, " %d near-copies", conf->near_copies); |
903 | if (conf->far_copies > 1) | 917 | if (conf->far_copies > 1) { |
904 | seq_printf(seq, " %d far-copies", conf->far_copies); | 918 | if (conf->far_offset) |
905 | 919 | seq_printf(seq, " %d offset-copies", conf->far_copies); | |
920 | else | ||
921 | seq_printf(seq, " %d far-copies", conf->far_copies); | ||
922 | } | ||
906 | seq_printf(seq, " [%d/%d] [", conf->raid_disks, | 923 | seq_printf(seq, " [%d/%d] [", conf->raid_disks, |
907 | conf->working_disks); | 924 | conf->working_disks); |
908 | for (i = 0; i < conf->raid_disks; i++) | 925 | for (i = 0; i < conf->raid_disks; i++) |
@@ -1915,7 +1932,7 @@ static int run(mddev_t *mddev) | |||
1915 | mirror_info_t *disk; | 1932 | mirror_info_t *disk; |
1916 | mdk_rdev_t *rdev; | 1933 | mdk_rdev_t *rdev; |
1917 | struct list_head *tmp; | 1934 | struct list_head *tmp; |
1918 | int nc, fc; | 1935 | int nc, fc, fo; |
1919 | sector_t stride, size; | 1936 | sector_t stride, size; |
1920 | 1937 | ||
1921 | if (mddev->chunk_size == 0) { | 1938 | if (mddev->chunk_size == 0) { |
@@ -1925,8 +1942,9 @@ static int run(mddev_t *mddev) | |||
1925 | 1942 | ||
1926 | nc = mddev->layout & 255; | 1943 | nc = mddev->layout & 255; |
1927 | fc = (mddev->layout >> 8) & 255; | 1944 | fc = (mddev->layout >> 8) & 255; |
1945 | fo = mddev->layout & (1<<16); | ||
1928 | if ((nc*fc) <2 || (nc*fc) > mddev->raid_disks || | 1946 | if ((nc*fc) <2 || (nc*fc) > mddev->raid_disks || |
1929 | (mddev->layout >> 16)) { | 1947 | (mddev->layout >> 17)) { |
1930 | printk(KERN_ERR "raid10: %s: unsupported raid10 layout: 0x%8x\n", | 1948 | printk(KERN_ERR "raid10: %s: unsupported raid10 layout: 0x%8x\n", |
1931 | mdname(mddev), mddev->layout); | 1949 | mdname(mddev), mddev->layout); |
1932 | goto out; | 1950 | goto out; |
@@ -1958,12 +1976,16 @@ static int run(mddev_t *mddev) | |||
1958 | conf->near_copies = nc; | 1976 | conf->near_copies = nc; |
1959 | conf->far_copies = fc; | 1977 | conf->far_copies = fc; |
1960 | conf->copies = nc*fc; | 1978 | conf->copies = nc*fc; |
1979 | conf->far_offset = fo; | ||
1961 | conf->chunk_mask = (sector_t)(mddev->chunk_size>>9)-1; | 1980 | conf->chunk_mask = (sector_t)(mddev->chunk_size>>9)-1; |
1962 | conf->chunk_shift = ffz(~mddev->chunk_size) - 9; | 1981 | conf->chunk_shift = ffz(~mddev->chunk_size) - 9; |
1963 | stride = mddev->size >> (conf->chunk_shift-1); | 1982 | if (fo) |
1964 | sector_div(stride, fc); | 1983 | conf->stride = 1 << conf->chunk_shift; |
1965 | conf->stride = stride << conf->chunk_shift; | 1984 | else { |
1966 | 1985 | stride = mddev->size >> (conf->chunk_shift-1); | |
1986 | sector_div(stride, fc); | ||
1987 | conf->stride = stride << conf->chunk_shift; | ||
1988 | } | ||
1967 | conf->r10bio_pool = mempool_create(NR_RAID10_BIOS, r10bio_pool_alloc, | 1989 | conf->r10bio_pool = mempool_create(NR_RAID10_BIOS, r10bio_pool_alloc, |
1968 | r10bio_pool_free, conf); | 1990 | r10bio_pool_free, conf); |
1969 | if (!conf->r10bio_pool) { | 1991 | if (!conf->r10bio_pool) { |
@@ -2015,7 +2037,8 @@ static int run(mddev_t *mddev) | |||
2015 | 2037 | ||
2016 | disk = conf->mirrors + i; | 2038 | disk = conf->mirrors + i; |
2017 | 2039 | ||
2018 | if (!disk->rdev) { | 2040 | if (!disk->rdev || |
2041 | !test_bit(In_sync, &rdev->flags)) { | ||
2019 | disk->head_position = 0; | 2042 | disk->head_position = 0; |
2020 | mddev->degraded++; | 2043 | mddev->degraded++; |
2021 | } | 2044 | } |
@@ -2037,7 +2060,13 @@ static int run(mddev_t *mddev) | |||
2037 | /* | 2060 | /* |
2038 | * Ok, everything is just fine now | 2061 | * Ok, everything is just fine now |
2039 | */ | 2062 | */ |
2040 | size = conf->stride * conf->raid_disks; | 2063 | if (conf->far_offset) { |
2064 | size = mddev->size >> (conf->chunk_shift-1); | ||
2065 | size *= conf->raid_disks; | ||
2066 | size <<= conf->chunk_shift; | ||
2067 | sector_div(size, conf->far_copies); | ||
2068 | } else | ||
2069 | size = conf->stride * conf->raid_disks; | ||
2041 | sector_div(size, conf->near_copies); | 2070 | sector_div(size, conf->near_copies); |
2042 | mddev->array_size = size/2; | 2071 | mddev->array_size = size/2; |
2043 | mddev->resync_max_sectors = size; | 2072 | mddev->resync_max_sectors = size; |
@@ -2050,7 +2079,7 @@ static int run(mddev_t *mddev) | |||
2050 | * maybe... | 2079 | * maybe... |
2051 | */ | 2080 | */ |
2052 | { | 2081 | { |
2053 | int stripe = conf->raid_disks * mddev->chunk_size / PAGE_SIZE; | 2082 | int stripe = conf->raid_disks * (mddev->chunk_size / PAGE_SIZE); |
2054 | stripe /= conf->near_copies; | 2083 | stripe /= conf->near_copies; |
2055 | if (mddev->queue->backing_dev_info.ra_pages < 2* stripe) | 2084 | if (mddev->queue->backing_dev_info.ra_pages < 2* stripe) |
2056 | mddev->queue->backing_dev_info.ra_pages = 2* stripe; | 2085 | mddev->queue->backing_dev_info.ra_pages = 2* stripe; |
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 31843604049c..f920e50ea124 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c | |||
@@ -2,8 +2,11 @@ | |||
2 | * raid5.c : Multiple Devices driver for Linux | 2 | * raid5.c : Multiple Devices driver for Linux |
3 | * Copyright (C) 1996, 1997 Ingo Molnar, Miguel de Icaza, Gadi Oxman | 3 | * Copyright (C) 1996, 1997 Ingo Molnar, Miguel de Icaza, Gadi Oxman |
4 | * Copyright (C) 1999, 2000 Ingo Molnar | 4 | * Copyright (C) 1999, 2000 Ingo Molnar |
5 | * Copyright (C) 2002, 2003 H. Peter Anvin | ||
5 | * | 6 | * |
6 | * RAID-5 management functions. | 7 | * RAID-4/5/6 management functions. |
8 | * Thanks to Penguin Computing for making the RAID-6 development possible | ||
9 | * by donating a test server! | ||
7 | * | 10 | * |
8 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License as published by | 12 | * it under the terms of the GNU General Public License as published by |
@@ -19,11 +22,11 @@ | |||
19 | #include <linux/config.h> | 22 | #include <linux/config.h> |
20 | #include <linux/module.h> | 23 | #include <linux/module.h> |
21 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
22 | #include <linux/raid/raid5.h> | ||
23 | #include <linux/highmem.h> | 25 | #include <linux/highmem.h> |
24 | #include <linux/bitops.h> | 26 | #include <linux/bitops.h> |
25 | #include <linux/kthread.h> | 27 | #include <linux/kthread.h> |
26 | #include <asm/atomic.h> | 28 | #include <asm/atomic.h> |
29 | #include "raid6.h" | ||
27 | 30 | ||
28 | #include <linux/raid/bitmap.h> | 31 | #include <linux/raid/bitmap.h> |
29 | 32 | ||
@@ -68,6 +71,16 @@ | |||
68 | #define __inline__ | 71 | #define __inline__ |
69 | #endif | 72 | #endif |
70 | 73 | ||
74 | #if !RAID6_USE_EMPTY_ZERO_PAGE | ||
75 | /* In .bss so it's zeroed */ | ||
76 | const char raid6_empty_zero_page[PAGE_SIZE] __attribute__((aligned(256))); | ||
77 | #endif | ||
78 | |||
79 | static inline int raid6_next_disk(int disk, int raid_disks) | ||
80 | { | ||
81 | disk++; | ||
82 | return (disk < raid_disks) ? disk : 0; | ||
83 | } | ||
71 | static void print_raid5_conf (raid5_conf_t *conf); | 84 | static void print_raid5_conf (raid5_conf_t *conf); |
72 | 85 | ||
73 | static void __release_stripe(raid5_conf_t *conf, struct stripe_head *sh) | 86 | static void __release_stripe(raid5_conf_t *conf, struct stripe_head *sh) |
@@ -104,7 +117,7 @@ static void release_stripe(struct stripe_head *sh) | |||
104 | { | 117 | { |
105 | raid5_conf_t *conf = sh->raid_conf; | 118 | raid5_conf_t *conf = sh->raid_conf; |
106 | unsigned long flags; | 119 | unsigned long flags; |
107 | 120 | ||
108 | spin_lock_irqsave(&conf->device_lock, flags); | 121 | spin_lock_irqsave(&conf->device_lock, flags); |
109 | __release_stripe(conf, sh); | 122 | __release_stripe(conf, sh); |
110 | spin_unlock_irqrestore(&conf->device_lock, flags); | 123 | spin_unlock_irqrestore(&conf->device_lock, flags); |
@@ -117,7 +130,7 @@ static inline void remove_hash(struct stripe_head *sh) | |||
117 | hlist_del_init(&sh->hash); | 130 | hlist_del_init(&sh->hash); |
118 | } | 131 | } |
119 | 132 | ||
120 | static void insert_hash(raid5_conf_t *conf, struct stripe_head *sh) | 133 | static inline void insert_hash(raid5_conf_t *conf, struct stripe_head *sh) |
121 | { | 134 | { |
122 | struct hlist_head *hp = stripe_hash(conf, sh->sector); | 135 | struct hlist_head *hp = stripe_hash(conf, sh->sector); |
123 | 136 | ||
@@ -190,7 +203,7 @@ static void init_stripe(struct stripe_head *sh, sector_t sector, int pd_idx, int | |||
190 | (unsigned long long)sh->sector); | 203 | (unsigned long long)sh->sector); |
191 | 204 | ||
192 | remove_hash(sh); | 205 | remove_hash(sh); |
193 | 206 | ||
194 | sh->sector = sector; | 207 | sh->sector = sector; |
195 | sh->pd_idx = pd_idx; | 208 | sh->pd_idx = pd_idx; |
196 | sh->state = 0; | 209 | sh->state = 0; |
@@ -269,8 +282,9 @@ static struct stripe_head *get_active_stripe(raid5_conf_t *conf, sector_t sector | |||
269 | } else { | 282 | } else { |
270 | if (!test_bit(STRIPE_HANDLE, &sh->state)) | 283 | if (!test_bit(STRIPE_HANDLE, &sh->state)) |
271 | atomic_inc(&conf->active_stripes); | 284 | atomic_inc(&conf->active_stripes); |
272 | if (!list_empty(&sh->lru)) | 285 | if (list_empty(&sh->lru)) |
273 | list_del_init(&sh->lru); | 286 | BUG(); |
287 | list_del_init(&sh->lru); | ||
274 | } | 288 | } |
275 | } | 289 | } |
276 | } while (sh == NULL); | 290 | } while (sh == NULL); |
@@ -321,10 +335,9 @@ static int grow_stripes(raid5_conf_t *conf, int num) | |||
321 | return 1; | 335 | return 1; |
322 | conf->slab_cache = sc; | 336 | conf->slab_cache = sc; |
323 | conf->pool_size = devs; | 337 | conf->pool_size = devs; |
324 | while (num--) { | 338 | while (num--) |
325 | if (!grow_one_stripe(conf)) | 339 | if (!grow_one_stripe(conf)) |
326 | return 1; | 340 | return 1; |
327 | } | ||
328 | return 0; | 341 | return 0; |
329 | } | 342 | } |
330 | 343 | ||
@@ -631,8 +644,7 @@ static void raid5_build_block (struct stripe_head *sh, int i) | |||
631 | dev->req.bi_private = sh; | 644 | dev->req.bi_private = sh; |
632 | 645 | ||
633 | dev->flags = 0; | 646 | dev->flags = 0; |
634 | if (i != sh->pd_idx) | 647 | dev->sector = compute_blocknr(sh, i); |
635 | dev->sector = compute_blocknr(sh, i); | ||
636 | } | 648 | } |
637 | 649 | ||
638 | static void error(mddev_t *mddev, mdk_rdev_t *rdev) | 650 | static void error(mddev_t *mddev, mdk_rdev_t *rdev) |
@@ -659,7 +671,7 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev) | |||
659 | " Operation continuing on %d devices\n", | 671 | " Operation continuing on %d devices\n", |
660 | bdevname(rdev->bdev,b), conf->working_disks); | 672 | bdevname(rdev->bdev,b), conf->working_disks); |
661 | } | 673 | } |
662 | } | 674 | } |
663 | 675 | ||
664 | /* | 676 | /* |
665 | * Input: a 'big' sector number, | 677 | * Input: a 'big' sector number, |
@@ -697,9 +709,12 @@ static sector_t raid5_compute_sector(sector_t r_sector, unsigned int raid_disks, | |||
697 | /* | 709 | /* |
698 | * Select the parity disk based on the user selected algorithm. | 710 | * Select the parity disk based on the user selected algorithm. |
699 | */ | 711 | */ |
700 | if (conf->level == 4) | 712 | switch(conf->level) { |
713 | case 4: | ||
701 | *pd_idx = data_disks; | 714 | *pd_idx = data_disks; |
702 | else switch (conf->algorithm) { | 715 | break; |
716 | case 5: | ||
717 | switch (conf->algorithm) { | ||
703 | case ALGORITHM_LEFT_ASYMMETRIC: | 718 | case ALGORITHM_LEFT_ASYMMETRIC: |
704 | *pd_idx = data_disks - stripe % raid_disks; | 719 | *pd_idx = data_disks - stripe % raid_disks; |
705 | if (*dd_idx >= *pd_idx) | 720 | if (*dd_idx >= *pd_idx) |
@@ -721,6 +736,39 @@ static sector_t raid5_compute_sector(sector_t r_sector, unsigned int raid_disks, | |||
721 | default: | 736 | default: |
722 | printk(KERN_ERR "raid5: unsupported algorithm %d\n", | 737 | printk(KERN_ERR "raid5: unsupported algorithm %d\n", |
723 | conf->algorithm); | 738 | conf->algorithm); |
739 | } | ||
740 | break; | ||
741 | case 6: | ||
742 | |||
743 | /**** FIX THIS ****/ | ||
744 | switch (conf->algorithm) { | ||
745 | case ALGORITHM_LEFT_ASYMMETRIC: | ||
746 | *pd_idx = raid_disks - 1 - (stripe % raid_disks); | ||
747 | if (*pd_idx == raid_disks-1) | ||
748 | (*dd_idx)++; /* Q D D D P */ | ||
749 | else if (*dd_idx >= *pd_idx) | ||
750 | (*dd_idx) += 2; /* D D P Q D */ | ||
751 | break; | ||
752 | case ALGORITHM_RIGHT_ASYMMETRIC: | ||
753 | *pd_idx = stripe % raid_disks; | ||
754 | if (*pd_idx == raid_disks-1) | ||
755 | (*dd_idx)++; /* Q D D D P */ | ||
756 | else if (*dd_idx >= *pd_idx) | ||
757 | (*dd_idx) += 2; /* D D P Q D */ | ||
758 | break; | ||
759 | case ALGORITHM_LEFT_SYMMETRIC: | ||
760 | *pd_idx = raid_disks - 1 - (stripe % raid_disks); | ||
761 | *dd_idx = (*pd_idx + 2 + *dd_idx) % raid_disks; | ||
762 | break; | ||
763 | case ALGORITHM_RIGHT_SYMMETRIC: | ||
764 | *pd_idx = stripe % raid_disks; | ||
765 | *dd_idx = (*pd_idx + 2 + *dd_idx) % raid_disks; | ||
766 | break; | ||
767 | default: | ||
768 | printk (KERN_CRIT "raid6: unsupported algorithm %d\n", | ||
769 | conf->algorithm); | ||
770 | } | ||
771 | break; | ||
724 | } | 772 | } |
725 | 773 | ||
726 | /* | 774 | /* |
@@ -742,12 +790,17 @@ static sector_t compute_blocknr(struct stripe_head *sh, int i) | |||
742 | int chunk_number, dummy1, dummy2, dd_idx = i; | 790 | int chunk_number, dummy1, dummy2, dd_idx = i; |
743 | sector_t r_sector; | 791 | sector_t r_sector; |
744 | 792 | ||
793 | |||
745 | chunk_offset = sector_div(new_sector, sectors_per_chunk); | 794 | chunk_offset = sector_div(new_sector, sectors_per_chunk); |
746 | stripe = new_sector; | 795 | stripe = new_sector; |
747 | BUG_ON(new_sector != stripe); | 796 | BUG_ON(new_sector != stripe); |
748 | 797 | ||
749 | 798 | if (i == sh->pd_idx) | |
750 | switch (conf->algorithm) { | 799 | return 0; |
800 | switch(conf->level) { | ||
801 | case 4: break; | ||
802 | case 5: | ||
803 | switch (conf->algorithm) { | ||
751 | case ALGORITHM_LEFT_ASYMMETRIC: | 804 | case ALGORITHM_LEFT_ASYMMETRIC: |
752 | case ALGORITHM_RIGHT_ASYMMETRIC: | 805 | case ALGORITHM_RIGHT_ASYMMETRIC: |
753 | if (i > sh->pd_idx) | 806 | if (i > sh->pd_idx) |
@@ -761,7 +814,37 @@ static sector_t compute_blocknr(struct stripe_head *sh, int i) | |||
761 | break; | 814 | break; |
762 | default: | 815 | default: |
763 | printk(KERN_ERR "raid5: unsupported algorithm %d\n", | 816 | printk(KERN_ERR "raid5: unsupported algorithm %d\n", |
817 | conf->algorithm); | ||
818 | } | ||
819 | break; | ||
820 | case 6: | ||
821 | data_disks = raid_disks - 2; | ||
822 | if (i == raid6_next_disk(sh->pd_idx, raid_disks)) | ||
823 | return 0; /* It is the Q disk */ | ||
824 | switch (conf->algorithm) { | ||
825 | case ALGORITHM_LEFT_ASYMMETRIC: | ||
826 | case ALGORITHM_RIGHT_ASYMMETRIC: | ||
827 | if (sh->pd_idx == raid_disks-1) | ||
828 | i--; /* Q D D D P */ | ||
829 | else if (i > sh->pd_idx) | ||
830 | i -= 2; /* D D P Q D */ | ||
831 | break; | ||
832 | case ALGORITHM_LEFT_SYMMETRIC: | ||
833 | case ALGORITHM_RIGHT_SYMMETRIC: | ||
834 | if (sh->pd_idx == raid_disks-1) | ||
835 | i--; /* Q D D D P */ | ||
836 | else { | ||
837 | /* D D P Q D */ | ||
838 | if (i < sh->pd_idx) | ||
839 | i += raid_disks; | ||
840 | i -= (sh->pd_idx + 2); | ||
841 | } | ||
842 | break; | ||
843 | default: | ||
844 | printk (KERN_CRIT "raid6: unsupported algorithm %d\n", | ||
764 | conf->algorithm); | 845 | conf->algorithm); |
846 | } | ||
847 | break; | ||
765 | } | 848 | } |
766 | 849 | ||
767 | chunk_number = stripe * data_disks + i; | 850 | chunk_number = stripe * data_disks + i; |
@@ -778,10 +861,11 @@ static sector_t compute_blocknr(struct stripe_head *sh, int i) | |||
778 | 861 | ||
779 | 862 | ||
780 | /* | 863 | /* |
781 | * Copy data between a page in the stripe cache, and a bio. | 864 | * Copy data between a page in the stripe cache, and one or more bion |
782 | * There are no alignment or size guarantees between the page or the | 865 | * The page could align with the middle of the bio, or there could be |
783 | * bio except that there is some overlap. | 866 | * several bion, each with several bio_vecs, which cover part of the page |
784 | * All iovecs in the bio must be considered. | 867 | * Multiple bion are linked together on bi_next. There may be extras |
868 | * at the end of this list. We ignore them. | ||
785 | */ | 869 | */ |
786 | static void copy_data(int frombio, struct bio *bio, | 870 | static void copy_data(int frombio, struct bio *bio, |
787 | struct page *page, | 871 | struct page *page, |
@@ -810,7 +894,7 @@ static void copy_data(int frombio, struct bio *bio, | |||
810 | if (len > 0 && page_offset + len > STRIPE_SIZE) | 894 | if (len > 0 && page_offset + len > STRIPE_SIZE) |
811 | clen = STRIPE_SIZE - page_offset; | 895 | clen = STRIPE_SIZE - page_offset; |
812 | else clen = len; | 896 | else clen = len; |
813 | 897 | ||
814 | if (clen > 0) { | 898 | if (clen > 0) { |
815 | char *ba = __bio_kmap_atomic(bio, i, KM_USER0); | 899 | char *ba = __bio_kmap_atomic(bio, i, KM_USER0); |
816 | if (frombio) | 900 | if (frombio) |
@@ -862,14 +946,14 @@ static void compute_block(struct stripe_head *sh, int dd_idx) | |||
862 | set_bit(R5_UPTODATE, &sh->dev[dd_idx].flags); | 946 | set_bit(R5_UPTODATE, &sh->dev[dd_idx].flags); |
863 | } | 947 | } |
864 | 948 | ||
865 | static void compute_parity(struct stripe_head *sh, int method) | 949 | static void compute_parity5(struct stripe_head *sh, int method) |
866 | { | 950 | { |
867 | raid5_conf_t *conf = sh->raid_conf; | 951 | raid5_conf_t *conf = sh->raid_conf; |
868 | int i, pd_idx = sh->pd_idx, disks = sh->disks, count; | 952 | int i, pd_idx = sh->pd_idx, disks = sh->disks, count; |
869 | void *ptr[MAX_XOR_BLOCKS]; | 953 | void *ptr[MAX_XOR_BLOCKS]; |
870 | struct bio *chosen; | 954 | struct bio *chosen; |
871 | 955 | ||
872 | PRINTK("compute_parity, stripe %llu, method %d\n", | 956 | PRINTK("compute_parity5, stripe %llu, method %d\n", |
873 | (unsigned long long)sh->sector, method); | 957 | (unsigned long long)sh->sector, method); |
874 | 958 | ||
875 | count = 1; | 959 | count = 1; |
@@ -956,9 +1040,195 @@ static void compute_parity(struct stripe_head *sh, int method) | |||
956 | clear_bit(R5_UPTODATE, &sh->dev[pd_idx].flags); | 1040 | clear_bit(R5_UPTODATE, &sh->dev[pd_idx].flags); |
957 | } | 1041 | } |
958 | 1042 | ||
1043 | static void compute_parity6(struct stripe_head *sh, int method) | ||
1044 | { | ||
1045 | raid6_conf_t *conf = sh->raid_conf; | ||
1046 | int i, pd_idx = sh->pd_idx, qd_idx, d0_idx, disks = conf->raid_disks, count; | ||
1047 | struct bio *chosen; | ||
1048 | /**** FIX THIS: This could be very bad if disks is close to 256 ****/ | ||
1049 | void *ptrs[disks]; | ||
1050 | |||
1051 | qd_idx = raid6_next_disk(pd_idx, disks); | ||
1052 | d0_idx = raid6_next_disk(qd_idx, disks); | ||
1053 | |||
1054 | PRINTK("compute_parity, stripe %llu, method %d\n", | ||
1055 | (unsigned long long)sh->sector, method); | ||
1056 | |||
1057 | switch(method) { | ||
1058 | case READ_MODIFY_WRITE: | ||
1059 | BUG(); /* READ_MODIFY_WRITE N/A for RAID-6 */ | ||
1060 | case RECONSTRUCT_WRITE: | ||
1061 | for (i= disks; i-- ;) | ||
1062 | if ( i != pd_idx && i != qd_idx && sh->dev[i].towrite ) { | ||
1063 | chosen = sh->dev[i].towrite; | ||
1064 | sh->dev[i].towrite = NULL; | ||
1065 | |||
1066 | if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags)) | ||
1067 | wake_up(&conf->wait_for_overlap); | ||
1068 | |||
1069 | if (sh->dev[i].written) BUG(); | ||
1070 | sh->dev[i].written = chosen; | ||
1071 | } | ||
1072 | break; | ||
1073 | case CHECK_PARITY: | ||
1074 | BUG(); /* Not implemented yet */ | ||
1075 | } | ||
1076 | |||
1077 | for (i = disks; i--;) | ||
1078 | if (sh->dev[i].written) { | ||
1079 | sector_t sector = sh->dev[i].sector; | ||
1080 | struct bio *wbi = sh->dev[i].written; | ||
1081 | while (wbi && wbi->bi_sector < sector + STRIPE_SECTORS) { | ||
1082 | copy_data(1, wbi, sh->dev[i].page, sector); | ||
1083 | wbi = r5_next_bio(wbi, sector); | ||
1084 | } | ||
1085 | |||
1086 | set_bit(R5_LOCKED, &sh->dev[i].flags); | ||
1087 | set_bit(R5_UPTODATE, &sh->dev[i].flags); | ||
1088 | } | ||
1089 | |||
1090 | // switch(method) { | ||
1091 | // case RECONSTRUCT_WRITE: | ||
1092 | // case CHECK_PARITY: | ||
1093 | // case UPDATE_PARITY: | ||
1094 | /* Note that unlike RAID-5, the ordering of the disks matters greatly. */ | ||
1095 | /* FIX: Is this ordering of drives even remotely optimal? */ | ||
1096 | count = 0; | ||
1097 | i = d0_idx; | ||
1098 | do { | ||
1099 | ptrs[count++] = page_address(sh->dev[i].page); | ||
1100 | if (count <= disks-2 && !test_bit(R5_UPTODATE, &sh->dev[i].flags)) | ||
1101 | printk("block %d/%d not uptodate on parity calc\n", i,count); | ||
1102 | i = raid6_next_disk(i, disks); | ||
1103 | } while ( i != d0_idx ); | ||
1104 | // break; | ||
1105 | // } | ||
1106 | |||
1107 | raid6_call.gen_syndrome(disks, STRIPE_SIZE, ptrs); | ||
1108 | |||
1109 | switch(method) { | ||
1110 | case RECONSTRUCT_WRITE: | ||
1111 | set_bit(R5_UPTODATE, &sh->dev[pd_idx].flags); | ||
1112 | set_bit(R5_UPTODATE, &sh->dev[qd_idx].flags); | ||
1113 | set_bit(R5_LOCKED, &sh->dev[pd_idx].flags); | ||
1114 | set_bit(R5_LOCKED, &sh->dev[qd_idx].flags); | ||
1115 | break; | ||
1116 | case UPDATE_PARITY: | ||
1117 | set_bit(R5_UPTODATE, &sh->dev[pd_idx].flags); | ||
1118 | set_bit(R5_UPTODATE, &sh->dev[qd_idx].flags); | ||
1119 | break; | ||
1120 | } | ||
1121 | } | ||
1122 | |||
1123 | |||
1124 | /* Compute one missing block */ | ||
1125 | static void compute_block_1(struct stripe_head *sh, int dd_idx, int nozero) | ||
1126 | { | ||
1127 | raid6_conf_t *conf = sh->raid_conf; | ||
1128 | int i, count, disks = conf->raid_disks; | ||
1129 | void *ptr[MAX_XOR_BLOCKS], *p; | ||
1130 | int pd_idx = sh->pd_idx; | ||
1131 | int qd_idx = raid6_next_disk(pd_idx, disks); | ||
1132 | |||
1133 | PRINTK("compute_block_1, stripe %llu, idx %d\n", | ||
1134 | (unsigned long long)sh->sector, dd_idx); | ||
1135 | |||
1136 | if ( dd_idx == qd_idx ) { | ||
1137 | /* We're actually computing the Q drive */ | ||
1138 | compute_parity6(sh, UPDATE_PARITY); | ||
1139 | } else { | ||
1140 | ptr[0] = page_address(sh->dev[dd_idx].page); | ||
1141 | if (!nozero) memset(ptr[0], 0, STRIPE_SIZE); | ||
1142 | count = 1; | ||
1143 | for (i = disks ; i--; ) { | ||
1144 | if (i == dd_idx || i == qd_idx) | ||
1145 | continue; | ||
1146 | p = page_address(sh->dev[i].page); | ||
1147 | if (test_bit(R5_UPTODATE, &sh->dev[i].flags)) | ||
1148 | ptr[count++] = p; | ||
1149 | else | ||
1150 | printk("compute_block() %d, stripe %llu, %d" | ||
1151 | " not present\n", dd_idx, | ||
1152 | (unsigned long long)sh->sector, i); | ||
1153 | |||
1154 | check_xor(); | ||
1155 | } | ||
1156 | if (count != 1) | ||
1157 | xor_block(count, STRIPE_SIZE, ptr); | ||
1158 | if (!nozero) set_bit(R5_UPTODATE, &sh->dev[dd_idx].flags); | ||
1159 | else clear_bit(R5_UPTODATE, &sh->dev[dd_idx].flags); | ||
1160 | } | ||
1161 | } | ||
1162 | |||
1163 | /* Compute two missing blocks */ | ||
1164 | static void compute_block_2(struct stripe_head *sh, int dd_idx1, int dd_idx2) | ||
1165 | { | ||
1166 | raid6_conf_t *conf = sh->raid_conf; | ||
1167 | int i, count, disks = conf->raid_disks; | ||
1168 | int pd_idx = sh->pd_idx; | ||
1169 | int qd_idx = raid6_next_disk(pd_idx, disks); | ||
1170 | int d0_idx = raid6_next_disk(qd_idx, disks); | ||
1171 | int faila, failb; | ||
1172 | |||
1173 | /* faila and failb are disk numbers relative to d0_idx */ | ||
1174 | /* pd_idx become disks-2 and qd_idx become disks-1 */ | ||
1175 | faila = (dd_idx1 < d0_idx) ? dd_idx1+(disks-d0_idx) : dd_idx1-d0_idx; | ||
1176 | failb = (dd_idx2 < d0_idx) ? dd_idx2+(disks-d0_idx) : dd_idx2-d0_idx; | ||
1177 | |||
1178 | BUG_ON(faila == failb); | ||
1179 | if ( failb < faila ) { int tmp = faila; faila = failb; failb = tmp; } | ||
1180 | |||
1181 | PRINTK("compute_block_2, stripe %llu, idx %d,%d (%d,%d)\n", | ||
1182 | (unsigned long long)sh->sector, dd_idx1, dd_idx2, faila, failb); | ||
1183 | |||
1184 | if ( failb == disks-1 ) { | ||
1185 | /* Q disk is one of the missing disks */ | ||
1186 | if ( faila == disks-2 ) { | ||
1187 | /* Missing P+Q, just recompute */ | ||
1188 | compute_parity6(sh, UPDATE_PARITY); | ||
1189 | return; | ||
1190 | } else { | ||
1191 | /* We're missing D+Q; recompute D from P */ | ||
1192 | compute_block_1(sh, (dd_idx1 == qd_idx) ? dd_idx2 : dd_idx1, 0); | ||
1193 | compute_parity6(sh, UPDATE_PARITY); /* Is this necessary? */ | ||
1194 | return; | ||
1195 | } | ||
1196 | } | ||
1197 | |||
1198 | /* We're missing D+P or D+D; build pointer table */ | ||
1199 | { | ||
1200 | /**** FIX THIS: This could be very bad if disks is close to 256 ****/ | ||
1201 | void *ptrs[disks]; | ||
1202 | |||
1203 | count = 0; | ||
1204 | i = d0_idx; | ||
1205 | do { | ||
1206 | ptrs[count++] = page_address(sh->dev[i].page); | ||
1207 | i = raid6_next_disk(i, disks); | ||
1208 | if (i != dd_idx1 && i != dd_idx2 && | ||
1209 | !test_bit(R5_UPTODATE, &sh->dev[i].flags)) | ||
1210 | printk("compute_2 with missing block %d/%d\n", count, i); | ||
1211 | } while ( i != d0_idx ); | ||
1212 | |||
1213 | if ( failb == disks-2 ) { | ||
1214 | /* We're missing D+P. */ | ||
1215 | raid6_datap_recov(disks, STRIPE_SIZE, faila, ptrs); | ||
1216 | } else { | ||
1217 | /* We're missing D+D. */ | ||
1218 | raid6_2data_recov(disks, STRIPE_SIZE, faila, failb, ptrs); | ||
1219 | } | ||
1220 | |||
1221 | /* Both the above update both missing blocks */ | ||
1222 | set_bit(R5_UPTODATE, &sh->dev[dd_idx1].flags); | ||
1223 | set_bit(R5_UPTODATE, &sh->dev[dd_idx2].flags); | ||
1224 | } | ||
1225 | } | ||
1226 | |||
1227 | |||
1228 | |||
959 | /* | 1229 | /* |
960 | * Each stripe/dev can have one or more bion attached. | 1230 | * Each stripe/dev can have one or more bion attached. |
961 | * toread/towrite point to the first in a chain. | 1231 | * toread/towrite point to the first in a chain. |
962 | * The bi_next chain must be in order. | 1232 | * The bi_next chain must be in order. |
963 | */ | 1233 | */ |
964 | static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, int forwrite) | 1234 | static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, int forwrite) |
@@ -1031,6 +1301,13 @@ static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in | |||
1031 | 1301 | ||
1032 | static void end_reshape(raid5_conf_t *conf); | 1302 | static void end_reshape(raid5_conf_t *conf); |
1033 | 1303 | ||
1304 | static int page_is_zero(struct page *p) | ||
1305 | { | ||
1306 | char *a = page_address(p); | ||
1307 | return ((*(u32*)a) == 0 && | ||
1308 | memcmp(a, a+4, STRIPE_SIZE-4)==0); | ||
1309 | } | ||
1310 | |||
1034 | static int stripe_to_pdidx(sector_t stripe, raid5_conf_t *conf, int disks) | 1311 | static int stripe_to_pdidx(sector_t stripe, raid5_conf_t *conf, int disks) |
1035 | { | 1312 | { |
1036 | int sectors_per_chunk = conf->chunk_size >> 9; | 1313 | int sectors_per_chunk = conf->chunk_size >> 9; |
@@ -1062,7 +1339,7 @@ static int stripe_to_pdidx(sector_t stripe, raid5_conf_t *conf, int disks) | |||
1062 | * | 1339 | * |
1063 | */ | 1340 | */ |
1064 | 1341 | ||
1065 | static void handle_stripe(struct stripe_head *sh) | 1342 | static void handle_stripe5(struct stripe_head *sh) |
1066 | { | 1343 | { |
1067 | raid5_conf_t *conf = sh->raid_conf; | 1344 | raid5_conf_t *conf = sh->raid_conf; |
1068 | int disks = sh->disks; | 1345 | int disks = sh->disks; |
@@ -1394,7 +1671,7 @@ static void handle_stripe(struct stripe_head *sh) | |||
1394 | if (locked == 0 && (rcw == 0 ||rmw == 0) && | 1671 | if (locked == 0 && (rcw == 0 ||rmw == 0) && |
1395 | !test_bit(STRIPE_BIT_DELAY, &sh->state)) { | 1672 | !test_bit(STRIPE_BIT_DELAY, &sh->state)) { |
1396 | PRINTK("Computing parity...\n"); | 1673 | PRINTK("Computing parity...\n"); |
1397 | compute_parity(sh, rcw==0 ? RECONSTRUCT_WRITE : READ_MODIFY_WRITE); | 1674 | compute_parity5(sh, rcw==0 ? RECONSTRUCT_WRITE : READ_MODIFY_WRITE); |
1398 | /* now every locked buffer is ready to be written */ | 1675 | /* now every locked buffer is ready to be written */ |
1399 | for (i=disks; i--;) | 1676 | for (i=disks; i--;) |
1400 | if (test_bit(R5_LOCKED, &sh->dev[i].flags)) { | 1677 | if (test_bit(R5_LOCKED, &sh->dev[i].flags)) { |
@@ -1421,13 +1698,10 @@ static void handle_stripe(struct stripe_head *sh) | |||
1421 | !test_bit(STRIPE_INSYNC, &sh->state)) { | 1698 | !test_bit(STRIPE_INSYNC, &sh->state)) { |
1422 | set_bit(STRIPE_HANDLE, &sh->state); | 1699 | set_bit(STRIPE_HANDLE, &sh->state); |
1423 | if (failed == 0) { | 1700 | if (failed == 0) { |
1424 | char *pagea; | ||
1425 | BUG_ON(uptodate != disks); | 1701 | BUG_ON(uptodate != disks); |
1426 | compute_parity(sh, CHECK_PARITY); | 1702 | compute_parity5(sh, CHECK_PARITY); |
1427 | uptodate--; | 1703 | uptodate--; |
1428 | pagea = page_address(sh->dev[sh->pd_idx].page); | 1704 | if (page_is_zero(sh->dev[sh->pd_idx].page)) { |
1429 | if ((*(u32*)pagea) == 0 && | ||
1430 | !memcmp(pagea, pagea+4, STRIPE_SIZE-4)) { | ||
1431 | /* parity is correct (on disc, not in buffer any more) */ | 1705 | /* parity is correct (on disc, not in buffer any more) */ |
1432 | set_bit(STRIPE_INSYNC, &sh->state); | 1706 | set_bit(STRIPE_INSYNC, &sh->state); |
1433 | } else { | 1707 | } else { |
@@ -1487,7 +1761,7 @@ static void handle_stripe(struct stripe_head *sh) | |||
1487 | /* Need to write out all blocks after computing parity */ | 1761 | /* Need to write out all blocks after computing parity */ |
1488 | sh->disks = conf->raid_disks; | 1762 | sh->disks = conf->raid_disks; |
1489 | sh->pd_idx = stripe_to_pdidx(sh->sector, conf, conf->raid_disks); | 1763 | sh->pd_idx = stripe_to_pdidx(sh->sector, conf, conf->raid_disks); |
1490 | compute_parity(sh, RECONSTRUCT_WRITE); | 1764 | compute_parity5(sh, RECONSTRUCT_WRITE); |
1491 | for (i= conf->raid_disks; i--;) { | 1765 | for (i= conf->raid_disks; i--;) { |
1492 | set_bit(R5_LOCKED, &sh->dev[i].flags); | 1766 | set_bit(R5_LOCKED, &sh->dev[i].flags); |
1493 | locked++; | 1767 | locked++; |
@@ -1615,6 +1889,569 @@ static void handle_stripe(struct stripe_head *sh) | |||
1615 | } | 1889 | } |
1616 | } | 1890 | } |
1617 | 1891 | ||
1892 | static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page) | ||
1893 | { | ||
1894 | raid6_conf_t *conf = sh->raid_conf; | ||
1895 | int disks = conf->raid_disks; | ||
1896 | struct bio *return_bi= NULL; | ||
1897 | struct bio *bi; | ||
1898 | int i; | ||
1899 | int syncing; | ||
1900 | int locked=0, uptodate=0, to_read=0, to_write=0, failed=0, written=0; | ||
1901 | int non_overwrite = 0; | ||
1902 | int failed_num[2] = {0, 0}; | ||
1903 | struct r5dev *dev, *pdev, *qdev; | ||
1904 | int pd_idx = sh->pd_idx; | ||
1905 | int qd_idx = raid6_next_disk(pd_idx, disks); | ||
1906 | int p_failed, q_failed; | ||
1907 | |||
1908 | PRINTK("handling stripe %llu, state=%#lx cnt=%d, pd_idx=%d, qd_idx=%d\n", | ||
1909 | (unsigned long long)sh->sector, sh->state, atomic_read(&sh->count), | ||
1910 | pd_idx, qd_idx); | ||
1911 | |||
1912 | spin_lock(&sh->lock); | ||
1913 | clear_bit(STRIPE_HANDLE, &sh->state); | ||
1914 | clear_bit(STRIPE_DELAYED, &sh->state); | ||
1915 | |||
1916 | syncing = test_bit(STRIPE_SYNCING, &sh->state); | ||
1917 | /* Now to look around and see what can be done */ | ||
1918 | |||
1919 | rcu_read_lock(); | ||
1920 | for (i=disks; i--; ) { | ||
1921 | mdk_rdev_t *rdev; | ||
1922 | dev = &sh->dev[i]; | ||
1923 | clear_bit(R5_Insync, &dev->flags); | ||
1924 | |||
1925 | PRINTK("check %d: state 0x%lx read %p write %p written %p\n", | ||
1926 | i, dev->flags, dev->toread, dev->towrite, dev->written); | ||
1927 | /* maybe we can reply to a read */ | ||
1928 | if (test_bit(R5_UPTODATE, &dev->flags) && dev->toread) { | ||
1929 | struct bio *rbi, *rbi2; | ||
1930 | PRINTK("Return read for disc %d\n", i); | ||
1931 | spin_lock_irq(&conf->device_lock); | ||
1932 | rbi = dev->toread; | ||
1933 | dev->toread = NULL; | ||
1934 | if (test_and_clear_bit(R5_Overlap, &dev->flags)) | ||
1935 | wake_up(&conf->wait_for_overlap); | ||
1936 | spin_unlock_irq(&conf->device_lock); | ||
1937 | while (rbi && rbi->bi_sector < dev->sector + STRIPE_SECTORS) { | ||
1938 | copy_data(0, rbi, dev->page, dev->sector); | ||
1939 | rbi2 = r5_next_bio(rbi, dev->sector); | ||
1940 | spin_lock_irq(&conf->device_lock); | ||
1941 | if (--rbi->bi_phys_segments == 0) { | ||
1942 | rbi->bi_next = return_bi; | ||
1943 | return_bi = rbi; | ||
1944 | } | ||
1945 | spin_unlock_irq(&conf->device_lock); | ||
1946 | rbi = rbi2; | ||
1947 | } | ||
1948 | } | ||
1949 | |||
1950 | /* now count some things */ | ||
1951 | if (test_bit(R5_LOCKED, &dev->flags)) locked++; | ||
1952 | if (test_bit(R5_UPTODATE, &dev->flags)) uptodate++; | ||
1953 | |||
1954 | |||
1955 | if (dev->toread) to_read++; | ||
1956 | if (dev->towrite) { | ||
1957 | to_write++; | ||
1958 | if (!test_bit(R5_OVERWRITE, &dev->flags)) | ||
1959 | non_overwrite++; | ||
1960 | } | ||
1961 | if (dev->written) written++; | ||
1962 | rdev = rcu_dereference(conf->disks[i].rdev); | ||
1963 | if (!rdev || !test_bit(In_sync, &rdev->flags)) { | ||
1964 | /* The ReadError flag will just be confusing now */ | ||
1965 | clear_bit(R5_ReadError, &dev->flags); | ||
1966 | clear_bit(R5_ReWrite, &dev->flags); | ||
1967 | } | ||
1968 | if (!rdev || !test_bit(In_sync, &rdev->flags) | ||
1969 | || test_bit(R5_ReadError, &dev->flags)) { | ||
1970 | if ( failed < 2 ) | ||
1971 | failed_num[failed] = i; | ||
1972 | failed++; | ||
1973 | } else | ||
1974 | set_bit(R5_Insync, &dev->flags); | ||
1975 | } | ||
1976 | rcu_read_unlock(); | ||
1977 | PRINTK("locked=%d uptodate=%d to_read=%d" | ||
1978 | " to_write=%d failed=%d failed_num=%d,%d\n", | ||
1979 | locked, uptodate, to_read, to_write, failed, | ||
1980 | failed_num[0], failed_num[1]); | ||
1981 | /* check if the array has lost >2 devices and, if so, some requests might | ||
1982 | * need to be failed | ||
1983 | */ | ||
1984 | if (failed > 2 && to_read+to_write+written) { | ||
1985 | for (i=disks; i--; ) { | ||
1986 | int bitmap_end = 0; | ||
1987 | |||
1988 | if (test_bit(R5_ReadError, &sh->dev[i].flags)) { | ||
1989 | mdk_rdev_t *rdev; | ||
1990 | rcu_read_lock(); | ||
1991 | rdev = rcu_dereference(conf->disks[i].rdev); | ||
1992 | if (rdev && test_bit(In_sync, &rdev->flags)) | ||
1993 | /* multiple read failures in one stripe */ | ||
1994 | md_error(conf->mddev, rdev); | ||
1995 | rcu_read_unlock(); | ||
1996 | } | ||
1997 | |||
1998 | spin_lock_irq(&conf->device_lock); | ||
1999 | /* fail all writes first */ | ||
2000 | bi = sh->dev[i].towrite; | ||
2001 | sh->dev[i].towrite = NULL; | ||
2002 | if (bi) { to_write--; bitmap_end = 1; } | ||
2003 | |||
2004 | if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags)) | ||
2005 | wake_up(&conf->wait_for_overlap); | ||
2006 | |||
2007 | while (bi && bi->bi_sector < sh->dev[i].sector + STRIPE_SECTORS){ | ||
2008 | struct bio *nextbi = r5_next_bio(bi, sh->dev[i].sector); | ||
2009 | clear_bit(BIO_UPTODATE, &bi->bi_flags); | ||
2010 | if (--bi->bi_phys_segments == 0) { | ||
2011 | md_write_end(conf->mddev); | ||
2012 | bi->bi_next = return_bi; | ||
2013 | return_bi = bi; | ||
2014 | } | ||
2015 | bi = nextbi; | ||
2016 | } | ||
2017 | /* and fail all 'written' */ | ||
2018 | bi = sh->dev[i].written; | ||
2019 | sh->dev[i].written = NULL; | ||
2020 | if (bi) bitmap_end = 1; | ||
2021 | while (bi && bi->bi_sector < sh->dev[i].sector + STRIPE_SECTORS) { | ||
2022 | struct bio *bi2 = r5_next_bio(bi, sh->dev[i].sector); | ||
2023 | clear_bit(BIO_UPTODATE, &bi->bi_flags); | ||
2024 | if (--bi->bi_phys_segments == 0) { | ||
2025 | md_write_end(conf->mddev); | ||
2026 | bi->bi_next = return_bi; | ||
2027 | return_bi = bi; | ||
2028 | } | ||
2029 | bi = bi2; | ||
2030 | } | ||
2031 | |||
2032 | /* fail any reads if this device is non-operational */ | ||
2033 | if (!test_bit(R5_Insync, &sh->dev[i].flags) || | ||
2034 | test_bit(R5_ReadError, &sh->dev[i].flags)) { | ||
2035 | bi = sh->dev[i].toread; | ||
2036 | sh->dev[i].toread = NULL; | ||
2037 | if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags)) | ||
2038 | wake_up(&conf->wait_for_overlap); | ||
2039 | if (bi) to_read--; | ||
2040 | while (bi && bi->bi_sector < sh->dev[i].sector + STRIPE_SECTORS){ | ||
2041 | struct bio *nextbi = r5_next_bio(bi, sh->dev[i].sector); | ||
2042 | clear_bit(BIO_UPTODATE, &bi->bi_flags); | ||
2043 | if (--bi->bi_phys_segments == 0) { | ||
2044 | bi->bi_next = return_bi; | ||
2045 | return_bi = bi; | ||
2046 | } | ||
2047 | bi = nextbi; | ||
2048 | } | ||
2049 | } | ||
2050 | spin_unlock_irq(&conf->device_lock); | ||
2051 | if (bitmap_end) | ||
2052 | bitmap_endwrite(conf->mddev->bitmap, sh->sector, | ||
2053 | STRIPE_SECTORS, 0, 0); | ||
2054 | } | ||
2055 | } | ||
2056 | if (failed > 2 && syncing) { | ||
2057 | md_done_sync(conf->mddev, STRIPE_SECTORS,0); | ||
2058 | clear_bit(STRIPE_SYNCING, &sh->state); | ||
2059 | syncing = 0; | ||
2060 | } | ||
2061 | |||
2062 | /* | ||
2063 | * might be able to return some write requests if the parity blocks | ||
2064 | * are safe, or on a failed drive | ||
2065 | */ | ||
2066 | pdev = &sh->dev[pd_idx]; | ||
2067 | p_failed = (failed >= 1 && failed_num[0] == pd_idx) | ||
2068 | || (failed >= 2 && failed_num[1] == pd_idx); | ||
2069 | qdev = &sh->dev[qd_idx]; | ||
2070 | q_failed = (failed >= 1 && failed_num[0] == qd_idx) | ||
2071 | || (failed >= 2 && failed_num[1] == qd_idx); | ||
2072 | |||
2073 | if ( written && | ||
2074 | ( p_failed || ((test_bit(R5_Insync, &pdev->flags) | ||
2075 | && !test_bit(R5_LOCKED, &pdev->flags) | ||
2076 | && test_bit(R5_UPTODATE, &pdev->flags))) ) && | ||
2077 | ( q_failed || ((test_bit(R5_Insync, &qdev->flags) | ||
2078 | && !test_bit(R5_LOCKED, &qdev->flags) | ||
2079 | && test_bit(R5_UPTODATE, &qdev->flags))) ) ) { | ||
2080 | /* any written block on an uptodate or failed drive can be | ||
2081 | * returned. Note that if we 'wrote' to a failed drive, | ||
2082 | * it will be UPTODATE, but never LOCKED, so we don't need | ||
2083 | * to test 'failed' directly. | ||
2084 | */ | ||
2085 | for (i=disks; i--; ) | ||
2086 | if (sh->dev[i].written) { | ||
2087 | dev = &sh->dev[i]; | ||
2088 | if (!test_bit(R5_LOCKED, &dev->flags) && | ||
2089 | test_bit(R5_UPTODATE, &dev->flags) ) { | ||
2090 | /* We can return any write requests */ | ||
2091 | int bitmap_end = 0; | ||
2092 | struct bio *wbi, *wbi2; | ||
2093 | PRINTK("Return write for stripe %llu disc %d\n", | ||
2094 | (unsigned long long)sh->sector, i); | ||
2095 | spin_lock_irq(&conf->device_lock); | ||
2096 | wbi = dev->written; | ||
2097 | dev->written = NULL; | ||
2098 | while (wbi && wbi->bi_sector < dev->sector + STRIPE_SECTORS) { | ||
2099 | wbi2 = r5_next_bio(wbi, dev->sector); | ||
2100 | if (--wbi->bi_phys_segments == 0) { | ||
2101 | md_write_end(conf->mddev); | ||
2102 | wbi->bi_next = return_bi; | ||
2103 | return_bi = wbi; | ||
2104 | } | ||
2105 | wbi = wbi2; | ||
2106 | } | ||
2107 | if (dev->towrite == NULL) | ||
2108 | bitmap_end = 1; | ||
2109 | spin_unlock_irq(&conf->device_lock); | ||
2110 | if (bitmap_end) | ||
2111 | bitmap_endwrite(conf->mddev->bitmap, sh->sector, | ||
2112 | STRIPE_SECTORS, | ||
2113 | !test_bit(STRIPE_DEGRADED, &sh->state), 0); | ||
2114 | } | ||
2115 | } | ||
2116 | } | ||
2117 | |||
2118 | /* Now we might consider reading some blocks, either to check/generate | ||
2119 | * parity, or to satisfy requests | ||
2120 | * or to load a block that is being partially written. | ||
2121 | */ | ||
2122 | if (to_read || non_overwrite || (to_write && failed) || (syncing && (uptodate < disks))) { | ||
2123 | for (i=disks; i--;) { | ||
2124 | dev = &sh->dev[i]; | ||
2125 | if (!test_bit(R5_LOCKED, &dev->flags) && !test_bit(R5_UPTODATE, &dev->flags) && | ||
2126 | (dev->toread || | ||
2127 | (dev->towrite && !test_bit(R5_OVERWRITE, &dev->flags)) || | ||
2128 | syncing || | ||
2129 | (failed >= 1 && (sh->dev[failed_num[0]].toread || to_write)) || | ||
2130 | (failed >= 2 && (sh->dev[failed_num[1]].toread || to_write)) | ||
2131 | ) | ||
2132 | ) { | ||
2133 | /* we would like to get this block, possibly | ||
2134 | * by computing it, but we might not be able to | ||
2135 | */ | ||
2136 | if (uptodate == disks-1) { | ||
2137 | PRINTK("Computing stripe %llu block %d\n", | ||
2138 | (unsigned long long)sh->sector, i); | ||
2139 | compute_block_1(sh, i, 0); | ||
2140 | uptodate++; | ||
2141 | } else if ( uptodate == disks-2 && failed >= 2 ) { | ||
2142 | /* Computing 2-failure is *very* expensive; only do it if failed >= 2 */ | ||
2143 | int other; | ||
2144 | for (other=disks; other--;) { | ||
2145 | if ( other == i ) | ||
2146 | continue; | ||
2147 | if ( !test_bit(R5_UPTODATE, &sh->dev[other].flags) ) | ||
2148 | break; | ||
2149 | } | ||
2150 | BUG_ON(other < 0); | ||
2151 | PRINTK("Computing stripe %llu blocks %d,%d\n", | ||
2152 | (unsigned long long)sh->sector, i, other); | ||
2153 | compute_block_2(sh, i, other); | ||
2154 | uptodate += 2; | ||
2155 | } else if (test_bit(R5_Insync, &dev->flags)) { | ||
2156 | set_bit(R5_LOCKED, &dev->flags); | ||
2157 | set_bit(R5_Wantread, &dev->flags); | ||
2158 | #if 0 | ||
2159 | /* if I am just reading this block and we don't have | ||
2160 | a failed drive, or any pending writes then sidestep the cache */ | ||
2161 | if (sh->bh_read[i] && !sh->bh_read[i]->b_reqnext && | ||
2162 | ! syncing && !failed && !to_write) { | ||
2163 | sh->bh_cache[i]->b_page = sh->bh_read[i]->b_page; | ||
2164 | sh->bh_cache[i]->b_data = sh->bh_read[i]->b_data; | ||
2165 | } | ||
2166 | #endif | ||
2167 | locked++; | ||
2168 | PRINTK("Reading block %d (sync=%d)\n", | ||
2169 | i, syncing); | ||
2170 | } | ||
2171 | } | ||
2172 | } | ||
2173 | set_bit(STRIPE_HANDLE, &sh->state); | ||
2174 | } | ||
2175 | |||
2176 | /* now to consider writing and what else, if anything should be read */ | ||
2177 | if (to_write) { | ||
2178 | int rcw=0, must_compute=0; | ||
2179 | for (i=disks ; i--;) { | ||
2180 | dev = &sh->dev[i]; | ||
2181 | /* Would I have to read this buffer for reconstruct_write */ | ||
2182 | if (!test_bit(R5_OVERWRITE, &dev->flags) | ||
2183 | && i != pd_idx && i != qd_idx | ||
2184 | && (!test_bit(R5_LOCKED, &dev->flags) | ||
2185 | #if 0 | ||
2186 | || sh->bh_page[i] != bh->b_page | ||
2187 | #endif | ||
2188 | ) && | ||
2189 | !test_bit(R5_UPTODATE, &dev->flags)) { | ||
2190 | if (test_bit(R5_Insync, &dev->flags)) rcw++; | ||
2191 | else { | ||
2192 | PRINTK("raid6: must_compute: disk %d flags=%#lx\n", i, dev->flags); | ||
2193 | must_compute++; | ||
2194 | } | ||
2195 | } | ||
2196 | } | ||
2197 | PRINTK("for sector %llu, rcw=%d, must_compute=%d\n", | ||
2198 | (unsigned long long)sh->sector, rcw, must_compute); | ||
2199 | set_bit(STRIPE_HANDLE, &sh->state); | ||
2200 | |||
2201 | if (rcw > 0) | ||
2202 | /* want reconstruct write, but need to get some data */ | ||
2203 | for (i=disks; i--;) { | ||
2204 | dev = &sh->dev[i]; | ||
2205 | if (!test_bit(R5_OVERWRITE, &dev->flags) | ||
2206 | && !(failed == 0 && (i == pd_idx || i == qd_idx)) | ||
2207 | && !test_bit(R5_LOCKED, &dev->flags) && !test_bit(R5_UPTODATE, &dev->flags) && | ||
2208 | test_bit(R5_Insync, &dev->flags)) { | ||
2209 | if (test_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) | ||
2210 | { | ||
2211 | PRINTK("Read_old stripe %llu block %d for Reconstruct\n", | ||
2212 | (unsigned long long)sh->sector, i); | ||
2213 | set_bit(R5_LOCKED, &dev->flags); | ||
2214 | set_bit(R5_Wantread, &dev->flags); | ||
2215 | locked++; | ||
2216 | } else { | ||
2217 | PRINTK("Request delayed stripe %llu block %d for Reconstruct\n", | ||
2218 | (unsigned long long)sh->sector, i); | ||
2219 | set_bit(STRIPE_DELAYED, &sh->state); | ||
2220 | set_bit(STRIPE_HANDLE, &sh->state); | ||
2221 | } | ||
2222 | } | ||
2223 | } | ||
2224 | /* now if nothing is locked, and if we have enough data, we can start a write request */ | ||
2225 | if (locked == 0 && rcw == 0 && | ||
2226 | !test_bit(STRIPE_BIT_DELAY, &sh->state)) { | ||
2227 | if ( must_compute > 0 ) { | ||
2228 | /* We have failed blocks and need to compute them */ | ||
2229 | switch ( failed ) { | ||
2230 | case 0: BUG(); | ||
2231 | case 1: compute_block_1(sh, failed_num[0], 0); break; | ||
2232 | case 2: compute_block_2(sh, failed_num[0], failed_num[1]); break; | ||
2233 | default: BUG(); /* This request should have been failed? */ | ||
2234 | } | ||
2235 | } | ||
2236 | |||
2237 | PRINTK("Computing parity for stripe %llu\n", (unsigned long long)sh->sector); | ||
2238 | compute_parity6(sh, RECONSTRUCT_WRITE); | ||
2239 | /* now every locked buffer is ready to be written */ | ||
2240 | for (i=disks; i--;) | ||
2241 | if (test_bit(R5_LOCKED, &sh->dev[i].flags)) { | ||
2242 | PRINTK("Writing stripe %llu block %d\n", | ||
2243 | (unsigned long long)sh->sector, i); | ||
2244 | locked++; | ||
2245 | set_bit(R5_Wantwrite, &sh->dev[i].flags); | ||
2246 | } | ||
2247 | /* after a RECONSTRUCT_WRITE, the stripe MUST be in-sync */ | ||
2248 | set_bit(STRIPE_INSYNC, &sh->state); | ||
2249 | |||
2250 | if (test_and_clear_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) { | ||
2251 | atomic_dec(&conf->preread_active_stripes); | ||
2252 | if (atomic_read(&conf->preread_active_stripes) < IO_THRESHOLD) | ||
2253 | md_wakeup_thread(conf->mddev->thread); | ||
2254 | } | ||
2255 | } | ||
2256 | } | ||
2257 | |||
2258 | /* maybe we need to check and possibly fix the parity for this stripe | ||
2259 | * Any reads will already have been scheduled, so we just see if enough data | ||
2260 | * is available | ||
2261 | */ | ||
2262 | if (syncing && locked == 0 && !test_bit(STRIPE_INSYNC, &sh->state)) { | ||
2263 | int update_p = 0, update_q = 0; | ||
2264 | struct r5dev *dev; | ||
2265 | |||
2266 | set_bit(STRIPE_HANDLE, &sh->state); | ||
2267 | |||
2268 | BUG_ON(failed>2); | ||
2269 | BUG_ON(uptodate < disks); | ||
2270 | /* Want to check and possibly repair P and Q. | ||
2271 | * However there could be one 'failed' device, in which | ||
2272 | * case we can only check one of them, possibly using the | ||
2273 | * other to generate missing data | ||
2274 | */ | ||
2275 | |||
2276 | /* If !tmp_page, we cannot do the calculations, | ||
2277 | * but as we have set STRIPE_HANDLE, we will soon be called | ||
2278 | * by stripe_handle with a tmp_page - just wait until then. | ||
2279 | */ | ||
2280 | if (tmp_page) { | ||
2281 | if (failed == q_failed) { | ||
2282 | /* The only possible failed device holds 'Q', so it makes | ||
2283 | * sense to check P (If anything else were failed, we would | ||
2284 | * have used P to recreate it). | ||
2285 | */ | ||
2286 | compute_block_1(sh, pd_idx, 1); | ||
2287 | if (!page_is_zero(sh->dev[pd_idx].page)) { | ||
2288 | compute_block_1(sh,pd_idx,0); | ||
2289 | update_p = 1; | ||
2290 | } | ||
2291 | } | ||
2292 | if (!q_failed && failed < 2) { | ||
2293 | /* q is not failed, and we didn't use it to generate | ||
2294 | * anything, so it makes sense to check it | ||
2295 | */ | ||
2296 | memcpy(page_address(tmp_page), | ||
2297 | page_address(sh->dev[qd_idx].page), | ||
2298 | STRIPE_SIZE); | ||
2299 | compute_parity6(sh, UPDATE_PARITY); | ||
2300 | if (memcmp(page_address(tmp_page), | ||
2301 | page_address(sh->dev[qd_idx].page), | ||
2302 | STRIPE_SIZE)!= 0) { | ||
2303 | clear_bit(STRIPE_INSYNC, &sh->state); | ||
2304 | update_q = 1; | ||
2305 | } | ||
2306 | } | ||
2307 | if (update_p || update_q) { | ||
2308 | conf->mddev->resync_mismatches += STRIPE_SECTORS; | ||
2309 | if (test_bit(MD_RECOVERY_CHECK, &conf->mddev->recovery)) | ||
2310 | /* don't try to repair!! */ | ||
2311 | update_p = update_q = 0; | ||
2312 | } | ||
2313 | |||
2314 | /* now write out any block on a failed drive, | ||
2315 | * or P or Q if they need it | ||
2316 | */ | ||
2317 | |||
2318 | if (failed == 2) { | ||
2319 | dev = &sh->dev[failed_num[1]]; | ||
2320 | locked++; | ||
2321 | set_bit(R5_LOCKED, &dev->flags); | ||
2322 | set_bit(R5_Wantwrite, &dev->flags); | ||
2323 | } | ||
2324 | if (failed >= 1) { | ||
2325 | dev = &sh->dev[failed_num[0]]; | ||
2326 | locked++; | ||
2327 | set_bit(R5_LOCKED, &dev->flags); | ||
2328 | set_bit(R5_Wantwrite, &dev->flags); | ||
2329 | } | ||
2330 | |||
2331 | if (update_p) { | ||
2332 | dev = &sh->dev[pd_idx]; | ||
2333 | locked ++; | ||
2334 | set_bit(R5_LOCKED, &dev->flags); | ||
2335 | set_bit(R5_Wantwrite, &dev->flags); | ||
2336 | } | ||
2337 | if (update_q) { | ||
2338 | dev = &sh->dev[qd_idx]; | ||
2339 | locked++; | ||
2340 | set_bit(R5_LOCKED, &dev->flags); | ||
2341 | set_bit(R5_Wantwrite, &dev->flags); | ||
2342 | } | ||
2343 | clear_bit(STRIPE_DEGRADED, &sh->state); | ||
2344 | |||
2345 | set_bit(STRIPE_INSYNC, &sh->state); | ||
2346 | } | ||
2347 | } | ||
2348 | |||
2349 | if (syncing && locked == 0 && test_bit(STRIPE_INSYNC, &sh->state)) { | ||
2350 | md_done_sync(conf->mddev, STRIPE_SECTORS,1); | ||
2351 | clear_bit(STRIPE_SYNCING, &sh->state); | ||
2352 | } | ||
2353 | |||
2354 | /* If the failed drives are just a ReadError, then we might need | ||
2355 | * to progress the repair/check process | ||
2356 | */ | ||
2357 | if (failed <= 2 && ! conf->mddev->ro) | ||
2358 | for (i=0; i<failed;i++) { | ||
2359 | dev = &sh->dev[failed_num[i]]; | ||
2360 | if (test_bit(R5_ReadError, &dev->flags) | ||
2361 | && !test_bit(R5_LOCKED, &dev->flags) | ||
2362 | && test_bit(R5_UPTODATE, &dev->flags) | ||
2363 | ) { | ||
2364 | if (!test_bit(R5_ReWrite, &dev->flags)) { | ||
2365 | set_bit(R5_Wantwrite, &dev->flags); | ||
2366 | set_bit(R5_ReWrite, &dev->flags); | ||
2367 | set_bit(R5_LOCKED, &dev->flags); | ||
2368 | } else { | ||
2369 | /* let's read it back */ | ||
2370 | set_bit(R5_Wantread, &dev->flags); | ||
2371 | set_bit(R5_LOCKED, &dev->flags); | ||
2372 | } | ||
2373 | } | ||
2374 | } | ||
2375 | spin_unlock(&sh->lock); | ||
2376 | |||
2377 | while ((bi=return_bi)) { | ||
2378 | int bytes = bi->bi_size; | ||
2379 | |||
2380 | return_bi = bi->bi_next; | ||
2381 | bi->bi_next = NULL; | ||
2382 | bi->bi_size = 0; | ||
2383 | bi->bi_end_io(bi, bytes, 0); | ||
2384 | } | ||
2385 | for (i=disks; i-- ;) { | ||
2386 | int rw; | ||
2387 | struct bio *bi; | ||
2388 | mdk_rdev_t *rdev; | ||
2389 | if (test_and_clear_bit(R5_Wantwrite, &sh->dev[i].flags)) | ||
2390 | rw = 1; | ||
2391 | else if (test_and_clear_bit(R5_Wantread, &sh->dev[i].flags)) | ||
2392 | rw = 0; | ||
2393 | else | ||
2394 | continue; | ||
2395 | |||
2396 | bi = &sh->dev[i].req; | ||
2397 | |||
2398 | bi->bi_rw = rw; | ||
2399 | if (rw) | ||
2400 | bi->bi_end_io = raid5_end_write_request; | ||
2401 | else | ||
2402 | bi->bi_end_io = raid5_end_read_request; | ||
2403 | |||
2404 | rcu_read_lock(); | ||
2405 | rdev = rcu_dereference(conf->disks[i].rdev); | ||
2406 | if (rdev && test_bit(Faulty, &rdev->flags)) | ||
2407 | rdev = NULL; | ||
2408 | if (rdev) | ||
2409 | atomic_inc(&rdev->nr_pending); | ||
2410 | rcu_read_unlock(); | ||
2411 | |||
2412 | if (rdev) { | ||
2413 | if (syncing) | ||
2414 | md_sync_acct(rdev->bdev, STRIPE_SECTORS); | ||
2415 | |||
2416 | bi->bi_bdev = rdev->bdev; | ||
2417 | PRINTK("for %llu schedule op %ld on disc %d\n", | ||
2418 | (unsigned long long)sh->sector, bi->bi_rw, i); | ||
2419 | atomic_inc(&sh->count); | ||
2420 | bi->bi_sector = sh->sector + rdev->data_offset; | ||
2421 | bi->bi_flags = 1 << BIO_UPTODATE; | ||
2422 | bi->bi_vcnt = 1; | ||
2423 | bi->bi_max_vecs = 1; | ||
2424 | bi->bi_idx = 0; | ||
2425 | bi->bi_io_vec = &sh->dev[i].vec; | ||
2426 | bi->bi_io_vec[0].bv_len = STRIPE_SIZE; | ||
2427 | bi->bi_io_vec[0].bv_offset = 0; | ||
2428 | bi->bi_size = STRIPE_SIZE; | ||
2429 | bi->bi_next = NULL; | ||
2430 | if (rw == WRITE && | ||
2431 | test_bit(R5_ReWrite, &sh->dev[i].flags)) | ||
2432 | atomic_add(STRIPE_SECTORS, &rdev->corrected_errors); | ||
2433 | generic_make_request(bi); | ||
2434 | } else { | ||
2435 | if (rw == 1) | ||
2436 | set_bit(STRIPE_DEGRADED, &sh->state); | ||
2437 | PRINTK("skip op %ld on disc %d for sector %llu\n", | ||
2438 | bi->bi_rw, i, (unsigned long long)sh->sector); | ||
2439 | clear_bit(R5_LOCKED, &sh->dev[i].flags); | ||
2440 | set_bit(STRIPE_HANDLE, &sh->state); | ||
2441 | } | ||
2442 | } | ||
2443 | } | ||
2444 | |||
2445 | static void handle_stripe(struct stripe_head *sh, struct page *tmp_page) | ||
2446 | { | ||
2447 | if (sh->raid_conf->level == 6) | ||
2448 | handle_stripe6(sh, tmp_page); | ||
2449 | else | ||
2450 | handle_stripe5(sh); | ||
2451 | } | ||
2452 | |||
2453 | |||
2454 | |||
1618 | static void raid5_activate_delayed(raid5_conf_t *conf) | 2455 | static void raid5_activate_delayed(raid5_conf_t *conf) |
1619 | { | 2456 | { |
1620 | if (atomic_read(&conf->preread_active_stripes) < IO_THRESHOLD) { | 2457 | if (atomic_read(&conf->preread_active_stripes) < IO_THRESHOLD) { |
@@ -1753,7 +2590,7 @@ static int make_request(request_queue_t *q, struct bio * bi) | |||
1753 | 2590 | ||
1754 | for (;logical_sector < last_sector; logical_sector += STRIPE_SECTORS) { | 2591 | for (;logical_sector < last_sector; logical_sector += STRIPE_SECTORS) { |
1755 | DEFINE_WAIT(w); | 2592 | DEFINE_WAIT(w); |
1756 | int disks; | 2593 | int disks, data_disks; |
1757 | 2594 | ||
1758 | retry: | 2595 | retry: |
1759 | prepare_to_wait(&conf->wait_for_overlap, &w, TASK_UNINTERRUPTIBLE); | 2596 | prepare_to_wait(&conf->wait_for_overlap, &w, TASK_UNINTERRUPTIBLE); |
@@ -1781,7 +2618,9 @@ static int make_request(request_queue_t *q, struct bio * bi) | |||
1781 | } | 2618 | } |
1782 | spin_unlock_irq(&conf->device_lock); | 2619 | spin_unlock_irq(&conf->device_lock); |
1783 | } | 2620 | } |
1784 | new_sector = raid5_compute_sector(logical_sector, disks, disks - 1, | 2621 | data_disks = disks - conf->max_degraded; |
2622 | |||
2623 | new_sector = raid5_compute_sector(logical_sector, disks, data_disks, | ||
1785 | &dd_idx, &pd_idx, conf); | 2624 | &dd_idx, &pd_idx, conf); |
1786 | PRINTK("raid5: make_request, sector %llu logical %llu\n", | 2625 | PRINTK("raid5: make_request, sector %llu logical %llu\n", |
1787 | (unsigned long long)new_sector, | 2626 | (unsigned long long)new_sector, |
@@ -1833,7 +2672,7 @@ static int make_request(request_queue_t *q, struct bio * bi) | |||
1833 | } | 2672 | } |
1834 | finish_wait(&conf->wait_for_overlap, &w); | 2673 | finish_wait(&conf->wait_for_overlap, &w); |
1835 | raid5_plug_device(conf); | 2674 | raid5_plug_device(conf); |
1836 | handle_stripe(sh); | 2675 | handle_stripe(sh, NULL); |
1837 | release_stripe(sh); | 2676 | release_stripe(sh); |
1838 | } else { | 2677 | } else { |
1839 | /* cannot get stripe for read-ahead, just give-up */ | 2678 | /* cannot get stripe for read-ahead, just give-up */ |
@@ -1849,7 +2688,7 @@ static int make_request(request_queue_t *q, struct bio * bi) | |||
1849 | if (remaining == 0) { | 2688 | if (remaining == 0) { |
1850 | int bytes = bi->bi_size; | 2689 | int bytes = bi->bi_size; |
1851 | 2690 | ||
1852 | if ( bio_data_dir(bi) == WRITE ) | 2691 | if ( rw == WRITE ) |
1853 | md_write_end(mddev); | 2692 | md_write_end(mddev); |
1854 | bi->bi_size = 0; | 2693 | bi->bi_size = 0; |
1855 | bi->bi_end_io(bi, bytes, 0); | 2694 | bi->bi_end_io(bi, bytes, 0); |
@@ -1857,17 +2696,142 @@ static int make_request(request_queue_t *q, struct bio * bi) | |||
1857 | return 0; | 2696 | return 0; |
1858 | } | 2697 | } |
1859 | 2698 | ||
1860 | /* FIXME go_faster isn't used */ | 2699 | static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped) |
1861 | static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, int go_faster) | ||
1862 | { | 2700 | { |
2701 | /* reshaping is quite different to recovery/resync so it is | ||
2702 | * handled quite separately ... here. | ||
2703 | * | ||
2704 | * On each call to sync_request, we gather one chunk worth of | ||
2705 | * destination stripes and flag them as expanding. | ||
2706 | * Then we find all the source stripes and request reads. | ||
2707 | * As the reads complete, handle_stripe will copy the data | ||
2708 | * into the destination stripe and release that stripe. | ||
2709 | */ | ||
1863 | raid5_conf_t *conf = (raid5_conf_t *) mddev->private; | 2710 | raid5_conf_t *conf = (raid5_conf_t *) mddev->private; |
1864 | struct stripe_head *sh; | 2711 | struct stripe_head *sh; |
1865 | int pd_idx; | 2712 | int pd_idx; |
1866 | sector_t first_sector, last_sector; | 2713 | sector_t first_sector, last_sector; |
2714 | int raid_disks; | ||
2715 | int data_disks; | ||
2716 | int i; | ||
2717 | int dd_idx; | ||
2718 | sector_t writepos, safepos, gap; | ||
2719 | |||
2720 | if (sector_nr == 0 && | ||
2721 | conf->expand_progress != 0) { | ||
2722 | /* restarting in the middle, skip the initial sectors */ | ||
2723 | sector_nr = conf->expand_progress; | ||
2724 | sector_div(sector_nr, conf->raid_disks-1); | ||
2725 | *skipped = 1; | ||
2726 | return sector_nr; | ||
2727 | } | ||
2728 | |||
2729 | /* we update the metadata when there is more than 3Meg | ||
2730 | * in the block range (that is rather arbitrary, should | ||
2731 | * probably be time based) or when the data about to be | ||
2732 | * copied would over-write the source of the data at | ||
2733 | * the front of the range. | ||
2734 | * i.e. one new_stripe forward from expand_progress new_maps | ||
2735 | * to after where expand_lo old_maps to | ||
2736 | */ | ||
2737 | writepos = conf->expand_progress + | ||
2738 | conf->chunk_size/512*(conf->raid_disks-1); | ||
2739 | sector_div(writepos, conf->raid_disks-1); | ||
2740 | safepos = conf->expand_lo; | ||
2741 | sector_div(safepos, conf->previous_raid_disks-1); | ||
2742 | gap = conf->expand_progress - conf->expand_lo; | ||
2743 | |||
2744 | if (writepos >= safepos || | ||
2745 | gap > (conf->raid_disks-1)*3000*2 /*3Meg*/) { | ||
2746 | /* Cannot proceed until we've updated the superblock... */ | ||
2747 | wait_event(conf->wait_for_overlap, | ||
2748 | atomic_read(&conf->reshape_stripes)==0); | ||
2749 | mddev->reshape_position = conf->expand_progress; | ||
2750 | mddev->sb_dirty = 1; | ||
2751 | md_wakeup_thread(mddev->thread); | ||
2752 | wait_event(mddev->sb_wait, mddev->sb_dirty == 0 || | ||
2753 | kthread_should_stop()); | ||
2754 | spin_lock_irq(&conf->device_lock); | ||
2755 | conf->expand_lo = mddev->reshape_position; | ||
2756 | spin_unlock_irq(&conf->device_lock); | ||
2757 | wake_up(&conf->wait_for_overlap); | ||
2758 | } | ||
2759 | |||
2760 | for (i=0; i < conf->chunk_size/512; i+= STRIPE_SECTORS) { | ||
2761 | int j; | ||
2762 | int skipped = 0; | ||
2763 | pd_idx = stripe_to_pdidx(sector_nr+i, conf, conf->raid_disks); | ||
2764 | sh = get_active_stripe(conf, sector_nr+i, | ||
2765 | conf->raid_disks, pd_idx, 0); | ||
2766 | set_bit(STRIPE_EXPANDING, &sh->state); | ||
2767 | atomic_inc(&conf->reshape_stripes); | ||
2768 | /* If any of this stripe is beyond the end of the old | ||
2769 | * array, then we need to zero those blocks | ||
2770 | */ | ||
2771 | for (j=sh->disks; j--;) { | ||
2772 | sector_t s; | ||
2773 | if (j == sh->pd_idx) | ||
2774 | continue; | ||
2775 | s = compute_blocknr(sh, j); | ||
2776 | if (s < (mddev->array_size<<1)) { | ||
2777 | skipped = 1; | ||
2778 | continue; | ||
2779 | } | ||
2780 | memset(page_address(sh->dev[j].page), 0, STRIPE_SIZE); | ||
2781 | set_bit(R5_Expanded, &sh->dev[j].flags); | ||
2782 | set_bit(R5_UPTODATE, &sh->dev[j].flags); | ||
2783 | } | ||
2784 | if (!skipped) { | ||
2785 | set_bit(STRIPE_EXPAND_READY, &sh->state); | ||
2786 | set_bit(STRIPE_HANDLE, &sh->state); | ||
2787 | } | ||
2788 | release_stripe(sh); | ||
2789 | } | ||
2790 | spin_lock_irq(&conf->device_lock); | ||
2791 | conf->expand_progress = (sector_nr + i)*(conf->raid_disks-1); | ||
2792 | spin_unlock_irq(&conf->device_lock); | ||
2793 | /* Ok, those stripe are ready. We can start scheduling | ||
2794 | * reads on the source stripes. | ||
2795 | * The source stripes are determined by mapping the first and last | ||
2796 | * block on the destination stripes. | ||
2797 | */ | ||
2798 | raid_disks = conf->previous_raid_disks; | ||
2799 | data_disks = raid_disks - 1; | ||
2800 | first_sector = | ||
2801 | raid5_compute_sector(sector_nr*(conf->raid_disks-1), | ||
2802 | raid_disks, data_disks, | ||
2803 | &dd_idx, &pd_idx, conf); | ||
2804 | last_sector = | ||
2805 | raid5_compute_sector((sector_nr+conf->chunk_size/512) | ||
2806 | *(conf->raid_disks-1) -1, | ||
2807 | raid_disks, data_disks, | ||
2808 | &dd_idx, &pd_idx, conf); | ||
2809 | if (last_sector >= (mddev->size<<1)) | ||
2810 | last_sector = (mddev->size<<1)-1; | ||
2811 | while (first_sector <= last_sector) { | ||
2812 | pd_idx = stripe_to_pdidx(first_sector, conf, conf->previous_raid_disks); | ||
2813 | sh = get_active_stripe(conf, first_sector, | ||
2814 | conf->previous_raid_disks, pd_idx, 0); | ||
2815 | set_bit(STRIPE_EXPAND_SOURCE, &sh->state); | ||
2816 | set_bit(STRIPE_HANDLE, &sh->state); | ||
2817 | release_stripe(sh); | ||
2818 | first_sector += STRIPE_SECTORS; | ||
2819 | } | ||
2820 | return conf->chunk_size>>9; | ||
2821 | } | ||
2822 | |||
2823 | /* FIXME go_faster isn't used */ | ||
2824 | static inline sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, int go_faster) | ||
2825 | { | ||
2826 | raid5_conf_t *conf = (raid5_conf_t *) mddev->private; | ||
2827 | struct stripe_head *sh; | ||
2828 | int pd_idx; | ||
1867 | int raid_disks = conf->raid_disks; | 2829 | int raid_disks = conf->raid_disks; |
1868 | int data_disks = raid_disks-1; | 2830 | int data_disks = raid_disks - conf->max_degraded; |
1869 | sector_t max_sector = mddev->size << 1; | 2831 | sector_t max_sector = mddev->size << 1; |
1870 | int sync_blocks; | 2832 | int sync_blocks; |
2833 | int still_degraded = 0; | ||
2834 | int i; | ||
1871 | 2835 | ||
1872 | if (sector_nr >= max_sector) { | 2836 | if (sector_nr >= max_sector) { |
1873 | /* just being told to finish up .. nothing much to do */ | 2837 | /* just being told to finish up .. nothing much to do */ |
@@ -1880,134 +2844,22 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i | |||
1880 | if (mddev->curr_resync < max_sector) /* aborted */ | 2844 | if (mddev->curr_resync < max_sector) /* aborted */ |
1881 | bitmap_end_sync(mddev->bitmap, mddev->curr_resync, | 2845 | bitmap_end_sync(mddev->bitmap, mddev->curr_resync, |
1882 | &sync_blocks, 1); | 2846 | &sync_blocks, 1); |
1883 | else /* compelted sync */ | 2847 | else /* completed sync */ |
1884 | conf->fullsync = 0; | 2848 | conf->fullsync = 0; |
1885 | bitmap_close_sync(mddev->bitmap); | 2849 | bitmap_close_sync(mddev->bitmap); |
1886 | 2850 | ||
1887 | return 0; | 2851 | return 0; |
1888 | } | 2852 | } |
1889 | 2853 | ||
1890 | if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)) { | 2854 | if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)) |
1891 | /* reshaping is quite different to recovery/resync so it is | 2855 | return reshape_request(mddev, sector_nr, skipped); |
1892 | * handled quite separately ... here. | 2856 | |
1893 | * | 2857 | /* if there is too many failed drives and we are trying |
1894 | * On each call to sync_request, we gather one chunk worth of | ||
1895 | * destination stripes and flag them as expanding. | ||
1896 | * Then we find all the source stripes and request reads. | ||
1897 | * As the reads complete, handle_stripe will copy the data | ||
1898 | * into the destination stripe and release that stripe. | ||
1899 | */ | ||
1900 | int i; | ||
1901 | int dd_idx; | ||
1902 | sector_t writepos, safepos, gap; | ||
1903 | |||
1904 | if (sector_nr == 0 && | ||
1905 | conf->expand_progress != 0) { | ||
1906 | /* restarting in the middle, skip the initial sectors */ | ||
1907 | sector_nr = conf->expand_progress; | ||
1908 | sector_div(sector_nr, conf->raid_disks-1); | ||
1909 | *skipped = 1; | ||
1910 | return sector_nr; | ||
1911 | } | ||
1912 | |||
1913 | /* we update the metadata when there is more than 3Meg | ||
1914 | * in the block range (that is rather arbitrary, should | ||
1915 | * probably be time based) or when the data about to be | ||
1916 | * copied would over-write the source of the data at | ||
1917 | * the front of the range. | ||
1918 | * i.e. one new_stripe forward from expand_progress new_maps | ||
1919 | * to after where expand_lo old_maps to | ||
1920 | */ | ||
1921 | writepos = conf->expand_progress + | ||
1922 | conf->chunk_size/512*(conf->raid_disks-1); | ||
1923 | sector_div(writepos, conf->raid_disks-1); | ||
1924 | safepos = conf->expand_lo; | ||
1925 | sector_div(safepos, conf->previous_raid_disks-1); | ||
1926 | gap = conf->expand_progress - conf->expand_lo; | ||
1927 | |||
1928 | if (writepos >= safepos || | ||
1929 | gap > (conf->raid_disks-1)*3000*2 /*3Meg*/) { | ||
1930 | /* Cannot proceed until we've updated the superblock... */ | ||
1931 | wait_event(conf->wait_for_overlap, | ||
1932 | atomic_read(&conf->reshape_stripes)==0); | ||
1933 | mddev->reshape_position = conf->expand_progress; | ||
1934 | mddev->sb_dirty = 1; | ||
1935 | md_wakeup_thread(mddev->thread); | ||
1936 | wait_event(mddev->sb_wait, mddev->sb_dirty == 0 || | ||
1937 | kthread_should_stop()); | ||
1938 | spin_lock_irq(&conf->device_lock); | ||
1939 | conf->expand_lo = mddev->reshape_position; | ||
1940 | spin_unlock_irq(&conf->device_lock); | ||
1941 | wake_up(&conf->wait_for_overlap); | ||
1942 | } | ||
1943 | |||
1944 | for (i=0; i < conf->chunk_size/512; i+= STRIPE_SECTORS) { | ||
1945 | int j; | ||
1946 | int skipped = 0; | ||
1947 | pd_idx = stripe_to_pdidx(sector_nr+i, conf, conf->raid_disks); | ||
1948 | sh = get_active_stripe(conf, sector_nr+i, | ||
1949 | conf->raid_disks, pd_idx, 0); | ||
1950 | set_bit(STRIPE_EXPANDING, &sh->state); | ||
1951 | atomic_inc(&conf->reshape_stripes); | ||
1952 | /* If any of this stripe is beyond the end of the old | ||
1953 | * array, then we need to zero those blocks | ||
1954 | */ | ||
1955 | for (j=sh->disks; j--;) { | ||
1956 | sector_t s; | ||
1957 | if (j == sh->pd_idx) | ||
1958 | continue; | ||
1959 | s = compute_blocknr(sh, j); | ||
1960 | if (s < (mddev->array_size<<1)) { | ||
1961 | skipped = 1; | ||
1962 | continue; | ||
1963 | } | ||
1964 | memset(page_address(sh->dev[j].page), 0, STRIPE_SIZE); | ||
1965 | set_bit(R5_Expanded, &sh->dev[j].flags); | ||
1966 | set_bit(R5_UPTODATE, &sh->dev[j].flags); | ||
1967 | } | ||
1968 | if (!skipped) { | ||
1969 | set_bit(STRIPE_EXPAND_READY, &sh->state); | ||
1970 | set_bit(STRIPE_HANDLE, &sh->state); | ||
1971 | } | ||
1972 | release_stripe(sh); | ||
1973 | } | ||
1974 | spin_lock_irq(&conf->device_lock); | ||
1975 | conf->expand_progress = (sector_nr + i)*(conf->raid_disks-1); | ||
1976 | spin_unlock_irq(&conf->device_lock); | ||
1977 | /* Ok, those stripe are ready. We can start scheduling | ||
1978 | * reads on the source stripes. | ||
1979 | * The source stripes are determined by mapping the first and last | ||
1980 | * block on the destination stripes. | ||
1981 | */ | ||
1982 | raid_disks = conf->previous_raid_disks; | ||
1983 | data_disks = raid_disks - 1; | ||
1984 | first_sector = | ||
1985 | raid5_compute_sector(sector_nr*(conf->raid_disks-1), | ||
1986 | raid_disks, data_disks, | ||
1987 | &dd_idx, &pd_idx, conf); | ||
1988 | last_sector = | ||
1989 | raid5_compute_sector((sector_nr+conf->chunk_size/512) | ||
1990 | *(conf->raid_disks-1) -1, | ||
1991 | raid_disks, data_disks, | ||
1992 | &dd_idx, &pd_idx, conf); | ||
1993 | if (last_sector >= (mddev->size<<1)) | ||
1994 | last_sector = (mddev->size<<1)-1; | ||
1995 | while (first_sector <= last_sector) { | ||
1996 | pd_idx = stripe_to_pdidx(first_sector, conf, conf->previous_raid_disks); | ||
1997 | sh = get_active_stripe(conf, first_sector, | ||
1998 | conf->previous_raid_disks, pd_idx, 0); | ||
1999 | set_bit(STRIPE_EXPAND_SOURCE, &sh->state); | ||
2000 | set_bit(STRIPE_HANDLE, &sh->state); | ||
2001 | release_stripe(sh); | ||
2002 | first_sector += STRIPE_SECTORS; | ||
2003 | } | ||
2004 | return conf->chunk_size>>9; | ||
2005 | } | ||
2006 | /* if there is 1 or more failed drives and we are trying | ||
2007 | * to resync, then assert that we are finished, because there is | 2858 | * to resync, then assert that we are finished, because there is |
2008 | * nothing we can do. | 2859 | * nothing we can do. |
2009 | */ | 2860 | */ |
2010 | if (mddev->degraded >= 1 && test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) { | 2861 | if (mddev->degraded >= conf->max_degraded && |
2862 | test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) { | ||
2011 | sector_t rv = (mddev->size << 1) - sector_nr; | 2863 | sector_t rv = (mddev->size << 1) - sector_nr; |
2012 | *skipped = 1; | 2864 | *skipped = 1; |
2013 | return rv; | 2865 | return rv; |
@@ -2026,17 +2878,26 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i | |||
2026 | if (sh == NULL) { | 2878 | if (sh == NULL) { |
2027 | sh = get_active_stripe(conf, sector_nr, raid_disks, pd_idx, 0); | 2879 | sh = get_active_stripe(conf, sector_nr, raid_disks, pd_idx, 0); |
2028 | /* make sure we don't swamp the stripe cache if someone else | 2880 | /* make sure we don't swamp the stripe cache if someone else |
2029 | * is trying to get access | 2881 | * is trying to get access |
2030 | */ | 2882 | */ |
2031 | schedule_timeout_uninterruptible(1); | 2883 | schedule_timeout_uninterruptible(1); |
2032 | } | 2884 | } |
2033 | bitmap_start_sync(mddev->bitmap, sector_nr, &sync_blocks, 0); | 2885 | /* Need to check if array will still be degraded after recovery/resync |
2034 | spin_lock(&sh->lock); | 2886 | * We don't need to check the 'failed' flag as when that gets set, |
2887 | * recovery aborts. | ||
2888 | */ | ||
2889 | for (i=0; i<mddev->raid_disks; i++) | ||
2890 | if (conf->disks[i].rdev == NULL) | ||
2891 | still_degraded = 1; | ||
2892 | |||
2893 | bitmap_start_sync(mddev->bitmap, sector_nr, &sync_blocks, still_degraded); | ||
2894 | |||
2895 | spin_lock(&sh->lock); | ||
2035 | set_bit(STRIPE_SYNCING, &sh->state); | 2896 | set_bit(STRIPE_SYNCING, &sh->state); |
2036 | clear_bit(STRIPE_INSYNC, &sh->state); | 2897 | clear_bit(STRIPE_INSYNC, &sh->state); |
2037 | spin_unlock(&sh->lock); | 2898 | spin_unlock(&sh->lock); |
2038 | 2899 | ||
2039 | handle_stripe(sh); | 2900 | handle_stripe(sh, NULL); |
2040 | release_stripe(sh); | 2901 | release_stripe(sh); |
2041 | 2902 | ||
2042 | return STRIPE_SECTORS; | 2903 | return STRIPE_SECTORS; |
@@ -2091,7 +2952,7 @@ static void raid5d (mddev_t *mddev) | |||
2091 | spin_unlock_irq(&conf->device_lock); | 2952 | spin_unlock_irq(&conf->device_lock); |
2092 | 2953 | ||
2093 | handled++; | 2954 | handled++; |
2094 | handle_stripe(sh); | 2955 | handle_stripe(sh, conf->spare_page); |
2095 | release_stripe(sh); | 2956 | release_stripe(sh); |
2096 | 2957 | ||
2097 | spin_lock_irq(&conf->device_lock); | 2958 | spin_lock_irq(&conf->device_lock); |
@@ -2181,8 +3042,8 @@ static int run(mddev_t *mddev) | |||
2181 | struct disk_info *disk; | 3042 | struct disk_info *disk; |
2182 | struct list_head *tmp; | 3043 | struct list_head *tmp; |
2183 | 3044 | ||
2184 | if (mddev->level != 5 && mddev->level != 4) { | 3045 | if (mddev->level != 5 && mddev->level != 4 && mddev->level != 6) { |
2185 | printk(KERN_ERR "raid5: %s: raid level not set to 4/5 (%d)\n", | 3046 | printk(KERN_ERR "raid5: %s: raid level not set to 4/5/6 (%d)\n", |
2186 | mdname(mddev), mddev->level); | 3047 | mdname(mddev), mddev->level); |
2187 | return -EIO; | 3048 | return -EIO; |
2188 | } | 3049 | } |
@@ -2251,6 +3112,11 @@ static int run(mddev_t *mddev) | |||
2251 | if ((conf->stripe_hashtbl = kzalloc(PAGE_SIZE, GFP_KERNEL)) == NULL) | 3112 | if ((conf->stripe_hashtbl = kzalloc(PAGE_SIZE, GFP_KERNEL)) == NULL) |
2252 | goto abort; | 3113 | goto abort; |
2253 | 3114 | ||
3115 | if (mddev->level == 6) { | ||
3116 | conf->spare_page = alloc_page(GFP_KERNEL); | ||
3117 | if (!conf->spare_page) | ||
3118 | goto abort; | ||
3119 | } | ||
2254 | spin_lock_init(&conf->device_lock); | 3120 | spin_lock_init(&conf->device_lock); |
2255 | init_waitqueue_head(&conf->wait_for_stripe); | 3121 | init_waitqueue_head(&conf->wait_for_stripe); |
2256 | init_waitqueue_head(&conf->wait_for_overlap); | 3122 | init_waitqueue_head(&conf->wait_for_overlap); |
@@ -2282,12 +3148,16 @@ static int run(mddev_t *mddev) | |||
2282 | } | 3148 | } |
2283 | 3149 | ||
2284 | /* | 3150 | /* |
2285 | * 0 for a fully functional array, 1 for a degraded array. | 3151 | * 0 for a fully functional array, 1 or 2 for a degraded array. |
2286 | */ | 3152 | */ |
2287 | mddev->degraded = conf->failed_disks = conf->raid_disks - conf->working_disks; | 3153 | mddev->degraded = conf->failed_disks = conf->raid_disks - conf->working_disks; |
2288 | conf->mddev = mddev; | 3154 | conf->mddev = mddev; |
2289 | conf->chunk_size = mddev->chunk_size; | 3155 | conf->chunk_size = mddev->chunk_size; |
2290 | conf->level = mddev->level; | 3156 | conf->level = mddev->level; |
3157 | if (conf->level == 6) | ||
3158 | conf->max_degraded = 2; | ||
3159 | else | ||
3160 | conf->max_degraded = 1; | ||
2291 | conf->algorithm = mddev->layout; | 3161 | conf->algorithm = mddev->layout; |
2292 | conf->max_nr_stripes = NR_STRIPES; | 3162 | conf->max_nr_stripes = NR_STRIPES; |
2293 | conf->expand_progress = mddev->reshape_position; | 3163 | conf->expand_progress = mddev->reshape_position; |
@@ -2296,6 +3166,11 @@ static int run(mddev_t *mddev) | |||
2296 | mddev->size &= ~(mddev->chunk_size/1024 -1); | 3166 | mddev->size &= ~(mddev->chunk_size/1024 -1); |
2297 | mddev->resync_max_sectors = mddev->size << 1; | 3167 | mddev->resync_max_sectors = mddev->size << 1; |
2298 | 3168 | ||
3169 | if (conf->level == 6 && conf->raid_disks < 4) { | ||
3170 | printk(KERN_ERR "raid6: not enough configured devices for %s (%d, minimum 4)\n", | ||
3171 | mdname(mddev), conf->raid_disks); | ||
3172 | goto abort; | ||
3173 | } | ||
2299 | if (!conf->chunk_size || conf->chunk_size % 4) { | 3174 | if (!conf->chunk_size || conf->chunk_size % 4) { |
2300 | printk(KERN_ERR "raid5: invalid chunk size %d for %s\n", | 3175 | printk(KERN_ERR "raid5: invalid chunk size %d for %s\n", |
2301 | conf->chunk_size, mdname(mddev)); | 3176 | conf->chunk_size, mdname(mddev)); |
@@ -2307,14 +3182,14 @@ static int run(mddev_t *mddev) | |||
2307 | conf->algorithm, mdname(mddev)); | 3182 | conf->algorithm, mdname(mddev)); |
2308 | goto abort; | 3183 | goto abort; |
2309 | } | 3184 | } |
2310 | if (mddev->degraded > 1) { | 3185 | if (mddev->degraded > conf->max_degraded) { |
2311 | printk(KERN_ERR "raid5: not enough operational devices for %s" | 3186 | printk(KERN_ERR "raid5: not enough operational devices for %s" |
2312 | " (%d/%d failed)\n", | 3187 | " (%d/%d failed)\n", |
2313 | mdname(mddev), conf->failed_disks, conf->raid_disks); | 3188 | mdname(mddev), conf->failed_disks, conf->raid_disks); |
2314 | goto abort; | 3189 | goto abort; |
2315 | } | 3190 | } |
2316 | 3191 | ||
2317 | if (mddev->degraded == 1 && | 3192 | if (mddev->degraded > 0 && |
2318 | mddev->recovery_cp != MaxSector) { | 3193 | mddev->recovery_cp != MaxSector) { |
2319 | if (mddev->ok_start_degraded) | 3194 | if (mddev->ok_start_degraded) |
2320 | printk(KERN_WARNING | 3195 | printk(KERN_WARNING |
@@ -2379,11 +3254,12 @@ static int run(mddev_t *mddev) | |||
2379 | } | 3254 | } |
2380 | 3255 | ||
2381 | /* read-ahead size must cover two whole stripes, which is | 3256 | /* read-ahead size must cover two whole stripes, which is |
2382 | * 2 * (n-1) * chunksize where 'n' is the number of raid devices | 3257 | * 2 * (datadisks) * chunksize where 'n' is the number of raid devices |
2383 | */ | 3258 | */ |
2384 | { | 3259 | { |
2385 | int stripe = (mddev->raid_disks-1) * mddev->chunk_size | 3260 | int data_disks = conf->previous_raid_disks - conf->max_degraded; |
2386 | / PAGE_SIZE; | 3261 | int stripe = data_disks * |
3262 | (mddev->chunk_size / PAGE_SIZE); | ||
2387 | if (mddev->queue->backing_dev_info.ra_pages < 2 * stripe) | 3263 | if (mddev->queue->backing_dev_info.ra_pages < 2 * stripe) |
2388 | mddev->queue->backing_dev_info.ra_pages = 2 * stripe; | 3264 | mddev->queue->backing_dev_info.ra_pages = 2 * stripe; |
2389 | } | 3265 | } |
@@ -2393,12 +3269,14 @@ static int run(mddev_t *mddev) | |||
2393 | 3269 | ||
2394 | mddev->queue->unplug_fn = raid5_unplug_device; | 3270 | mddev->queue->unplug_fn = raid5_unplug_device; |
2395 | mddev->queue->issue_flush_fn = raid5_issue_flush; | 3271 | mddev->queue->issue_flush_fn = raid5_issue_flush; |
2396 | mddev->array_size = mddev->size * (conf->previous_raid_disks - 1); | 3272 | mddev->array_size = mddev->size * (conf->previous_raid_disks - |
3273 | conf->max_degraded); | ||
2397 | 3274 | ||
2398 | return 0; | 3275 | return 0; |
2399 | abort: | 3276 | abort: |
2400 | if (conf) { | 3277 | if (conf) { |
2401 | print_raid5_conf(conf); | 3278 | print_raid5_conf(conf); |
3279 | safe_put_page(conf->spare_page); | ||
2402 | kfree(conf->disks); | 3280 | kfree(conf->disks); |
2403 | kfree(conf->stripe_hashtbl); | 3281 | kfree(conf->stripe_hashtbl); |
2404 | kfree(conf); | 3282 | kfree(conf); |
@@ -2427,23 +3305,23 @@ static int stop(mddev_t *mddev) | |||
2427 | } | 3305 | } |
2428 | 3306 | ||
2429 | #if RAID5_DEBUG | 3307 | #if RAID5_DEBUG |
2430 | static void print_sh (struct stripe_head *sh) | 3308 | static void print_sh (struct seq_file *seq, struct stripe_head *sh) |
2431 | { | 3309 | { |
2432 | int i; | 3310 | int i; |
2433 | 3311 | ||
2434 | printk("sh %llu, pd_idx %d, state %ld.\n", | 3312 | seq_printf(seq, "sh %llu, pd_idx %d, state %ld.\n", |
2435 | (unsigned long long)sh->sector, sh->pd_idx, sh->state); | 3313 | (unsigned long long)sh->sector, sh->pd_idx, sh->state); |
2436 | printk("sh %llu, count %d.\n", | 3314 | seq_printf(seq, "sh %llu, count %d.\n", |
2437 | (unsigned long long)sh->sector, atomic_read(&sh->count)); | 3315 | (unsigned long long)sh->sector, atomic_read(&sh->count)); |
2438 | printk("sh %llu, ", (unsigned long long)sh->sector); | 3316 | seq_printf(seq, "sh %llu, ", (unsigned long long)sh->sector); |
2439 | for (i = 0; i < sh->disks; i++) { | 3317 | for (i = 0; i < sh->disks; i++) { |
2440 | printk("(cache%d: %p %ld) ", | 3318 | seq_printf(seq, "(cache%d: %p %ld) ", |
2441 | i, sh->dev[i].page, sh->dev[i].flags); | 3319 | i, sh->dev[i].page, sh->dev[i].flags); |
2442 | } | 3320 | } |
2443 | printk("\n"); | 3321 | seq_printf(seq, "\n"); |
2444 | } | 3322 | } |
2445 | 3323 | ||
2446 | static void printall (raid5_conf_t *conf) | 3324 | static void printall (struct seq_file *seq, raid5_conf_t *conf) |
2447 | { | 3325 | { |
2448 | struct stripe_head *sh; | 3326 | struct stripe_head *sh; |
2449 | struct hlist_node *hn; | 3327 | struct hlist_node *hn; |
@@ -2454,7 +3332,7 @@ static void printall (raid5_conf_t *conf) | |||
2454 | hlist_for_each_entry(sh, hn, &conf->stripe_hashtbl[i], hash) { | 3332 | hlist_for_each_entry(sh, hn, &conf->stripe_hashtbl[i], hash) { |
2455 | if (sh->raid_conf != conf) | 3333 | if (sh->raid_conf != conf) |
2456 | continue; | 3334 | continue; |
2457 | print_sh(sh); | 3335 | print_sh(seq, sh); |
2458 | } | 3336 | } |
2459 | } | 3337 | } |
2460 | spin_unlock_irq(&conf->device_lock); | 3338 | spin_unlock_irq(&conf->device_lock); |
@@ -2474,9 +3352,8 @@ static void status (struct seq_file *seq, mddev_t *mddev) | |||
2474 | test_bit(In_sync, &conf->disks[i].rdev->flags) ? "U" : "_"); | 3352 | test_bit(In_sync, &conf->disks[i].rdev->flags) ? "U" : "_"); |
2475 | seq_printf (seq, "]"); | 3353 | seq_printf (seq, "]"); |
2476 | #if RAID5_DEBUG | 3354 | #if RAID5_DEBUG |
2477 | #define D(x) \ | 3355 | seq_printf (seq, "\n"); |
2478 | seq_printf (seq, "<"#x":%d>", atomic_read(&conf->x)) | 3356 | printall(seq, conf); |
2479 | printall(conf); | ||
2480 | #endif | 3357 | #endif |
2481 | } | 3358 | } |
2482 | 3359 | ||
@@ -2560,14 +3437,20 @@ static int raid5_add_disk(mddev_t *mddev, mdk_rdev_t *rdev) | |||
2560 | int disk; | 3437 | int disk; |
2561 | struct disk_info *p; | 3438 | struct disk_info *p; |
2562 | 3439 | ||
2563 | if (mddev->degraded > 1) | 3440 | if (mddev->degraded > conf->max_degraded) |
2564 | /* no point adding a device */ | 3441 | /* no point adding a device */ |
2565 | return 0; | 3442 | return 0; |
2566 | 3443 | ||
2567 | /* | 3444 | /* |
2568 | * find the disk ... | 3445 | * find the disk ... but prefer rdev->saved_raid_disk |
3446 | * if possible. | ||
2569 | */ | 3447 | */ |
2570 | for (disk=0; disk < conf->raid_disks; disk++) | 3448 | if (rdev->saved_raid_disk >= 0 && |
3449 | conf->disks[rdev->saved_raid_disk].rdev == NULL) | ||
3450 | disk = rdev->saved_raid_disk; | ||
3451 | else | ||
3452 | disk = 0; | ||
3453 | for ( ; disk < conf->raid_disks; disk++) | ||
2571 | if ((p=conf->disks + disk)->rdev == NULL) { | 3454 | if ((p=conf->disks + disk)->rdev == NULL) { |
2572 | clear_bit(In_sync, &rdev->flags); | 3455 | clear_bit(In_sync, &rdev->flags); |
2573 | rdev->raid_disk = disk; | 3456 | rdev->raid_disk = disk; |
@@ -2590,8 +3473,10 @@ static int raid5_resize(mddev_t *mddev, sector_t sectors) | |||
2590 | * any io in the removed space completes, but it hardly seems | 3473 | * any io in the removed space completes, but it hardly seems |
2591 | * worth it. | 3474 | * worth it. |
2592 | */ | 3475 | */ |
3476 | raid5_conf_t *conf = mddev_to_conf(mddev); | ||
3477 | |||
2593 | sectors &= ~((sector_t)mddev->chunk_size/512 - 1); | 3478 | sectors &= ~((sector_t)mddev->chunk_size/512 - 1); |
2594 | mddev->array_size = (sectors * (mddev->raid_disks-1))>>1; | 3479 | mddev->array_size = (sectors * (mddev->raid_disks-conf->max_degraded))>>1; |
2595 | set_capacity(mddev->gendisk, mddev->array_size << 1); | 3480 | set_capacity(mddev->gendisk, mddev->array_size << 1); |
2596 | mddev->changed = 1; | 3481 | mddev->changed = 1; |
2597 | if (sectors/2 > mddev->size && mddev->recovery_cp == MaxSector) { | 3482 | if (sectors/2 > mddev->size && mddev->recovery_cp == MaxSector) { |
@@ -2680,6 +3565,7 @@ static int raid5_start_reshape(mddev_t *mddev) | |||
2680 | set_bit(In_sync, &rdev->flags); | 3565 | set_bit(In_sync, &rdev->flags); |
2681 | conf->working_disks++; | 3566 | conf->working_disks++; |
2682 | added_devices++; | 3567 | added_devices++; |
3568 | rdev->recovery_offset = 0; | ||
2683 | sprintf(nm, "rd%d", rdev->raid_disk); | 3569 | sprintf(nm, "rd%d", rdev->raid_disk); |
2684 | sysfs_create_link(&mddev->kobj, &rdev->kobj, nm); | 3570 | sysfs_create_link(&mddev->kobj, &rdev->kobj, nm); |
2685 | } else | 3571 | } else |
@@ -2731,6 +3617,17 @@ static void end_reshape(raid5_conf_t *conf) | |||
2731 | conf->expand_progress = MaxSector; | 3617 | conf->expand_progress = MaxSector; |
2732 | spin_unlock_irq(&conf->device_lock); | 3618 | spin_unlock_irq(&conf->device_lock); |
2733 | conf->mddev->reshape_position = MaxSector; | 3619 | conf->mddev->reshape_position = MaxSector; |
3620 | |||
3621 | /* read-ahead size must cover two whole stripes, which is | ||
3622 | * 2 * (datadisks) * chunksize where 'n' is the number of raid devices | ||
3623 | */ | ||
3624 | { | ||
3625 | int data_disks = conf->previous_raid_disks - conf->max_degraded; | ||
3626 | int stripe = data_disks * | ||
3627 | (conf->mddev->chunk_size / PAGE_SIZE); | ||
3628 | if (conf->mddev->queue->backing_dev_info.ra_pages < 2 * stripe) | ||
3629 | conf->mddev->queue->backing_dev_info.ra_pages = 2 * stripe; | ||
3630 | } | ||
2734 | } | 3631 | } |
2735 | } | 3632 | } |
2736 | 3633 | ||
@@ -2762,6 +3659,23 @@ static void raid5_quiesce(mddev_t *mddev, int state) | |||
2762 | } | 3659 | } |
2763 | } | 3660 | } |
2764 | 3661 | ||
3662 | static struct mdk_personality raid6_personality = | ||
3663 | { | ||
3664 | .name = "raid6", | ||
3665 | .level = 6, | ||
3666 | .owner = THIS_MODULE, | ||
3667 | .make_request = make_request, | ||
3668 | .run = run, | ||
3669 | .stop = stop, | ||
3670 | .status = status, | ||
3671 | .error_handler = error, | ||
3672 | .hot_add_disk = raid5_add_disk, | ||
3673 | .hot_remove_disk= raid5_remove_disk, | ||
3674 | .spare_active = raid5_spare_active, | ||
3675 | .sync_request = sync_request, | ||
3676 | .resize = raid5_resize, | ||
3677 | .quiesce = raid5_quiesce, | ||
3678 | }; | ||
2765 | static struct mdk_personality raid5_personality = | 3679 | static struct mdk_personality raid5_personality = |
2766 | { | 3680 | { |
2767 | .name = "raid5", | 3681 | .name = "raid5", |
@@ -2804,6 +3718,12 @@ static struct mdk_personality raid4_personality = | |||
2804 | 3718 | ||
2805 | static int __init raid5_init(void) | 3719 | static int __init raid5_init(void) |
2806 | { | 3720 | { |
3721 | int e; | ||
3722 | |||
3723 | e = raid6_select_algo(); | ||
3724 | if ( e ) | ||
3725 | return e; | ||
3726 | register_md_personality(&raid6_personality); | ||
2807 | register_md_personality(&raid5_personality); | 3727 | register_md_personality(&raid5_personality); |
2808 | register_md_personality(&raid4_personality); | 3728 | register_md_personality(&raid4_personality); |
2809 | return 0; | 3729 | return 0; |
@@ -2811,6 +3731,7 @@ static int __init raid5_init(void) | |||
2811 | 3731 | ||
2812 | static void raid5_exit(void) | 3732 | static void raid5_exit(void) |
2813 | { | 3733 | { |
3734 | unregister_md_personality(&raid6_personality); | ||
2814 | unregister_md_personality(&raid5_personality); | 3735 | unregister_md_personality(&raid5_personality); |
2815 | unregister_md_personality(&raid4_personality); | 3736 | unregister_md_personality(&raid4_personality); |
2816 | } | 3737 | } |
@@ -2823,3 +3744,10 @@ MODULE_ALIAS("md-raid5"); | |||
2823 | MODULE_ALIAS("md-raid4"); | 3744 | MODULE_ALIAS("md-raid4"); |
2824 | MODULE_ALIAS("md-level-5"); | 3745 | MODULE_ALIAS("md-level-5"); |
2825 | MODULE_ALIAS("md-level-4"); | 3746 | MODULE_ALIAS("md-level-4"); |
3747 | MODULE_ALIAS("md-personality-8"); /* RAID6 */ | ||
3748 | MODULE_ALIAS("md-raid6"); | ||
3749 | MODULE_ALIAS("md-level-6"); | ||
3750 | |||
3751 | /* This used to be two separate modules, they were: */ | ||
3752 | MODULE_ALIAS("raid5"); | ||
3753 | MODULE_ALIAS("raid6"); | ||
diff --git a/drivers/md/raid6main.c b/drivers/md/raid6main.c deleted file mode 100644 index bc69355e0100..000000000000 --- a/drivers/md/raid6main.c +++ /dev/null | |||
@@ -1,2427 +0,0 @@ | |||
1 | /* | ||
2 | * raid6main.c : Multiple Devices driver for Linux | ||
3 | * Copyright (C) 1996, 1997 Ingo Molnar, Miguel de Icaza, Gadi Oxman | ||
4 | * Copyright (C) 1999, 2000 Ingo Molnar | ||
5 | * Copyright (C) 2002, 2003 H. Peter Anvin | ||
6 | * | ||
7 | * RAID-6 management functions. This code is derived from raid5.c. | ||
8 | * Last merge from raid5.c bkcvs version 1.79 (kernel 2.6.1). | ||
9 | * | ||
10 | * Thanks to Penguin Computing for making the RAID-6 development possible | ||
11 | * by donating a test server! | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License as published by | ||
15 | * the Free Software Foundation; either version 2, or (at your option) | ||
16 | * any later version. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * (for example /usr/src/linux/COPYING); if not, write to the Free | ||
20 | * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | */ | ||
22 | |||
23 | |||
24 | #include <linux/config.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/highmem.h> | ||
28 | #include <linux/bitops.h> | ||
29 | #include <asm/atomic.h> | ||
30 | #include "raid6.h" | ||
31 | |||
32 | #include <linux/raid/bitmap.h> | ||
33 | |||
34 | /* | ||
35 | * Stripe cache | ||
36 | */ | ||
37 | |||
38 | #define NR_STRIPES 256 | ||
39 | #define STRIPE_SIZE PAGE_SIZE | ||
40 | #define STRIPE_SHIFT (PAGE_SHIFT - 9) | ||
41 | #define STRIPE_SECTORS (STRIPE_SIZE>>9) | ||
42 | #define IO_THRESHOLD 1 | ||
43 | #define NR_HASH (PAGE_SIZE / sizeof(struct hlist_head)) | ||
44 | #define HASH_MASK (NR_HASH - 1) | ||
45 | |||
46 | #define stripe_hash(conf, sect) (&((conf)->stripe_hashtbl[((sect) >> STRIPE_SHIFT) & HASH_MASK])) | ||
47 | |||
48 | /* bio's attached to a stripe+device for I/O are linked together in bi_sector | ||
49 | * order without overlap. There may be several bio's per stripe+device, and | ||
50 | * a bio could span several devices. | ||
51 | * When walking this list for a particular stripe+device, we must never proceed | ||
52 | * beyond a bio that extends past this device, as the next bio might no longer | ||
53 | * be valid. | ||
54 | * This macro is used to determine the 'next' bio in the list, given the sector | ||
55 | * of the current stripe+device | ||
56 | */ | ||
57 | #define r5_next_bio(bio, sect) ( ( (bio)->bi_sector + ((bio)->bi_size>>9) < sect + STRIPE_SECTORS) ? (bio)->bi_next : NULL) | ||
58 | /* | ||
59 | * The following can be used to debug the driver | ||
60 | */ | ||
61 | #define RAID6_DEBUG 0 /* Extremely verbose printk */ | ||
62 | #define RAID6_PARANOIA 1 /* Check spinlocks */ | ||
63 | #define RAID6_DUMPSTATE 0 /* Include stripe cache state in /proc/mdstat */ | ||
64 | #if RAID6_PARANOIA && defined(CONFIG_SMP) | ||
65 | # define CHECK_DEVLOCK() assert_spin_locked(&conf->device_lock) | ||
66 | #else | ||
67 | # define CHECK_DEVLOCK() | ||
68 | #endif | ||
69 | |||
70 | #define PRINTK(x...) ((void)(RAID6_DEBUG && printk(KERN_DEBUG x))) | ||
71 | #if RAID6_DEBUG | ||
72 | #undef inline | ||
73 | #undef __inline__ | ||
74 | #define inline | ||
75 | #define __inline__ | ||
76 | #endif | ||
77 | |||
78 | #if !RAID6_USE_EMPTY_ZERO_PAGE | ||
79 | /* In .bss so it's zeroed */ | ||
80 | const char raid6_empty_zero_page[PAGE_SIZE] __attribute__((aligned(256))); | ||
81 | #endif | ||
82 | |||
83 | static inline int raid6_next_disk(int disk, int raid_disks) | ||
84 | { | ||
85 | disk++; | ||
86 | return (disk < raid_disks) ? disk : 0; | ||
87 | } | ||
88 | |||
89 | static void print_raid6_conf (raid6_conf_t *conf); | ||
90 | |||
91 | static void __release_stripe(raid6_conf_t *conf, struct stripe_head *sh) | ||
92 | { | ||
93 | if (atomic_dec_and_test(&sh->count)) { | ||
94 | BUG_ON(!list_empty(&sh->lru)); | ||
95 | BUG_ON(atomic_read(&conf->active_stripes)==0); | ||
96 | if (test_bit(STRIPE_HANDLE, &sh->state)) { | ||
97 | if (test_bit(STRIPE_DELAYED, &sh->state)) | ||
98 | list_add_tail(&sh->lru, &conf->delayed_list); | ||
99 | else if (test_bit(STRIPE_BIT_DELAY, &sh->state) && | ||
100 | conf->seq_write == sh->bm_seq) | ||
101 | list_add_tail(&sh->lru, &conf->bitmap_list); | ||
102 | else { | ||
103 | clear_bit(STRIPE_BIT_DELAY, &sh->state); | ||
104 | list_add_tail(&sh->lru, &conf->handle_list); | ||
105 | } | ||
106 | md_wakeup_thread(conf->mddev->thread); | ||
107 | } else { | ||
108 | if (test_and_clear_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) { | ||
109 | atomic_dec(&conf->preread_active_stripes); | ||
110 | if (atomic_read(&conf->preread_active_stripes) < IO_THRESHOLD) | ||
111 | md_wakeup_thread(conf->mddev->thread); | ||
112 | } | ||
113 | list_add_tail(&sh->lru, &conf->inactive_list); | ||
114 | atomic_dec(&conf->active_stripes); | ||
115 | if (!conf->inactive_blocked || | ||
116 | atomic_read(&conf->active_stripes) < (conf->max_nr_stripes*3/4)) | ||
117 | wake_up(&conf->wait_for_stripe); | ||
118 | } | ||
119 | } | ||
120 | } | ||
121 | static void release_stripe(struct stripe_head *sh) | ||
122 | { | ||
123 | raid6_conf_t *conf = sh->raid_conf; | ||
124 | unsigned long flags; | ||
125 | |||
126 | spin_lock_irqsave(&conf->device_lock, flags); | ||
127 | __release_stripe(conf, sh); | ||
128 | spin_unlock_irqrestore(&conf->device_lock, flags); | ||
129 | } | ||
130 | |||
131 | static inline void remove_hash(struct stripe_head *sh) | ||
132 | { | ||
133 | PRINTK("remove_hash(), stripe %llu\n", (unsigned long long)sh->sector); | ||
134 | |||
135 | hlist_del_init(&sh->hash); | ||
136 | } | ||
137 | |||
138 | static inline void insert_hash(raid6_conf_t *conf, struct stripe_head *sh) | ||
139 | { | ||
140 | struct hlist_head *hp = stripe_hash(conf, sh->sector); | ||
141 | |||
142 | PRINTK("insert_hash(), stripe %llu\n", (unsigned long long)sh->sector); | ||
143 | |||
144 | CHECK_DEVLOCK(); | ||
145 | hlist_add_head(&sh->hash, hp); | ||
146 | } | ||
147 | |||
148 | |||
149 | /* find an idle stripe, make sure it is unhashed, and return it. */ | ||
150 | static struct stripe_head *get_free_stripe(raid6_conf_t *conf) | ||
151 | { | ||
152 | struct stripe_head *sh = NULL; | ||
153 | struct list_head *first; | ||
154 | |||
155 | CHECK_DEVLOCK(); | ||
156 | if (list_empty(&conf->inactive_list)) | ||
157 | goto out; | ||
158 | first = conf->inactive_list.next; | ||
159 | sh = list_entry(first, struct stripe_head, lru); | ||
160 | list_del_init(first); | ||
161 | remove_hash(sh); | ||
162 | atomic_inc(&conf->active_stripes); | ||
163 | out: | ||
164 | return sh; | ||
165 | } | ||
166 | |||
167 | static void shrink_buffers(struct stripe_head *sh, int num) | ||
168 | { | ||
169 | struct page *p; | ||
170 | int i; | ||
171 | |||
172 | for (i=0; i<num ; i++) { | ||
173 | p = sh->dev[i].page; | ||
174 | if (!p) | ||
175 | continue; | ||
176 | sh->dev[i].page = NULL; | ||
177 | put_page(p); | ||
178 | } | ||
179 | } | ||
180 | |||
181 | static int grow_buffers(struct stripe_head *sh, int num) | ||
182 | { | ||
183 | int i; | ||
184 | |||
185 | for (i=0; i<num; i++) { | ||
186 | struct page *page; | ||
187 | |||
188 | if (!(page = alloc_page(GFP_KERNEL))) { | ||
189 | return 1; | ||
190 | } | ||
191 | sh->dev[i].page = page; | ||
192 | } | ||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | static void raid6_build_block (struct stripe_head *sh, int i); | ||
197 | |||
198 | static void init_stripe(struct stripe_head *sh, sector_t sector, int pd_idx) | ||
199 | { | ||
200 | raid6_conf_t *conf = sh->raid_conf; | ||
201 | int disks = conf->raid_disks, i; | ||
202 | |||
203 | BUG_ON(atomic_read(&sh->count) != 0); | ||
204 | BUG_ON(test_bit(STRIPE_HANDLE, &sh->state)); | ||
205 | |||
206 | CHECK_DEVLOCK(); | ||
207 | PRINTK("init_stripe called, stripe %llu\n", | ||
208 | (unsigned long long)sh->sector); | ||
209 | |||
210 | remove_hash(sh); | ||
211 | |||
212 | sh->sector = sector; | ||
213 | sh->pd_idx = pd_idx; | ||
214 | sh->state = 0; | ||
215 | |||
216 | for (i=disks; i--; ) { | ||
217 | struct r5dev *dev = &sh->dev[i]; | ||
218 | |||
219 | if (dev->toread || dev->towrite || dev->written || | ||
220 | test_bit(R5_LOCKED, &dev->flags)) { | ||
221 | PRINTK("sector=%llx i=%d %p %p %p %d\n", | ||
222 | (unsigned long long)sh->sector, i, dev->toread, | ||
223 | dev->towrite, dev->written, | ||
224 | test_bit(R5_LOCKED, &dev->flags)); | ||
225 | BUG(); | ||
226 | } | ||
227 | dev->flags = 0; | ||
228 | raid6_build_block(sh, i); | ||
229 | } | ||
230 | insert_hash(conf, sh); | ||
231 | } | ||
232 | |||
233 | static struct stripe_head *__find_stripe(raid6_conf_t *conf, sector_t sector) | ||
234 | { | ||
235 | struct stripe_head *sh; | ||
236 | struct hlist_node *hn; | ||
237 | |||
238 | CHECK_DEVLOCK(); | ||
239 | PRINTK("__find_stripe, sector %llu\n", (unsigned long long)sector); | ||
240 | hlist_for_each_entry (sh, hn, stripe_hash(conf, sector), hash) | ||
241 | if (sh->sector == sector) | ||
242 | return sh; | ||
243 | PRINTK("__stripe %llu not in cache\n", (unsigned long long)sector); | ||
244 | return NULL; | ||
245 | } | ||
246 | |||
247 | static void unplug_slaves(mddev_t *mddev); | ||
248 | |||
249 | static struct stripe_head *get_active_stripe(raid6_conf_t *conf, sector_t sector, | ||
250 | int pd_idx, int noblock) | ||
251 | { | ||
252 | struct stripe_head *sh; | ||
253 | |||
254 | PRINTK("get_stripe, sector %llu\n", (unsigned long long)sector); | ||
255 | |||
256 | spin_lock_irq(&conf->device_lock); | ||
257 | |||
258 | do { | ||
259 | wait_event_lock_irq(conf->wait_for_stripe, | ||
260 | conf->quiesce == 0, | ||
261 | conf->device_lock, /* nothing */); | ||
262 | sh = __find_stripe(conf, sector); | ||
263 | if (!sh) { | ||
264 | if (!conf->inactive_blocked) | ||
265 | sh = get_free_stripe(conf); | ||
266 | if (noblock && sh == NULL) | ||
267 | break; | ||
268 | if (!sh) { | ||
269 | conf->inactive_blocked = 1; | ||
270 | wait_event_lock_irq(conf->wait_for_stripe, | ||
271 | !list_empty(&conf->inactive_list) && | ||
272 | (atomic_read(&conf->active_stripes) | ||
273 | < (conf->max_nr_stripes *3/4) | ||
274 | || !conf->inactive_blocked), | ||
275 | conf->device_lock, | ||
276 | unplug_slaves(conf->mddev); | ||
277 | ); | ||
278 | conf->inactive_blocked = 0; | ||
279 | } else | ||
280 | init_stripe(sh, sector, pd_idx); | ||
281 | } else { | ||
282 | if (atomic_read(&sh->count)) { | ||
283 | BUG_ON(!list_empty(&sh->lru)); | ||
284 | } else { | ||
285 | if (!test_bit(STRIPE_HANDLE, &sh->state)) | ||
286 | atomic_inc(&conf->active_stripes); | ||
287 | BUG_ON(list_empty(&sh->lru)); | ||
288 | list_del_init(&sh->lru); | ||
289 | } | ||
290 | } | ||
291 | } while (sh == NULL); | ||
292 | |||
293 | if (sh) | ||
294 | atomic_inc(&sh->count); | ||
295 | |||
296 | spin_unlock_irq(&conf->device_lock); | ||
297 | return sh; | ||
298 | } | ||
299 | |||
300 | static int grow_one_stripe(raid6_conf_t *conf) | ||
301 | { | ||
302 | struct stripe_head *sh; | ||
303 | sh = kmem_cache_alloc(conf->slab_cache, GFP_KERNEL); | ||
304 | if (!sh) | ||
305 | return 0; | ||
306 | memset(sh, 0, sizeof(*sh) + (conf->raid_disks-1)*sizeof(struct r5dev)); | ||
307 | sh->raid_conf = conf; | ||
308 | spin_lock_init(&sh->lock); | ||
309 | |||
310 | if (grow_buffers(sh, conf->raid_disks)) { | ||
311 | shrink_buffers(sh, conf->raid_disks); | ||
312 | kmem_cache_free(conf->slab_cache, sh); | ||
313 | return 0; | ||
314 | } | ||
315 | /* we just created an active stripe so... */ | ||
316 | atomic_set(&sh->count, 1); | ||
317 | atomic_inc(&conf->active_stripes); | ||
318 | INIT_LIST_HEAD(&sh->lru); | ||
319 | release_stripe(sh); | ||
320 | return 1; | ||
321 | } | ||
322 | |||
323 | static int grow_stripes(raid6_conf_t *conf, int num) | ||
324 | { | ||
325 | kmem_cache_t *sc; | ||
326 | int devs = conf->raid_disks; | ||
327 | |||
328 | sprintf(conf->cache_name[0], "raid6/%s", mdname(conf->mddev)); | ||
329 | |||
330 | sc = kmem_cache_create(conf->cache_name[0], | ||
331 | sizeof(struct stripe_head)+(devs-1)*sizeof(struct r5dev), | ||
332 | 0, 0, NULL, NULL); | ||
333 | if (!sc) | ||
334 | return 1; | ||
335 | conf->slab_cache = sc; | ||
336 | while (num--) | ||
337 | if (!grow_one_stripe(conf)) | ||
338 | return 1; | ||
339 | return 0; | ||
340 | } | ||
341 | |||
342 | static int drop_one_stripe(raid6_conf_t *conf) | ||
343 | { | ||
344 | struct stripe_head *sh; | ||
345 | spin_lock_irq(&conf->device_lock); | ||
346 | sh = get_free_stripe(conf); | ||
347 | spin_unlock_irq(&conf->device_lock); | ||
348 | if (!sh) | ||
349 | return 0; | ||
350 | BUG_ON(atomic_read(&sh->count)); | ||
351 | shrink_buffers(sh, conf->raid_disks); | ||
352 | kmem_cache_free(conf->slab_cache, sh); | ||
353 | atomic_dec(&conf->active_stripes); | ||
354 | return 1; | ||
355 | } | ||
356 | |||
357 | static void shrink_stripes(raid6_conf_t *conf) | ||
358 | { | ||
359 | while (drop_one_stripe(conf)) | ||
360 | ; | ||
361 | |||
362 | if (conf->slab_cache) | ||
363 | kmem_cache_destroy(conf->slab_cache); | ||
364 | conf->slab_cache = NULL; | ||
365 | } | ||
366 | |||
367 | static int raid6_end_read_request(struct bio * bi, unsigned int bytes_done, | ||
368 | int error) | ||
369 | { | ||
370 | struct stripe_head *sh = bi->bi_private; | ||
371 | raid6_conf_t *conf = sh->raid_conf; | ||
372 | int disks = conf->raid_disks, i; | ||
373 | int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags); | ||
374 | |||
375 | if (bi->bi_size) | ||
376 | return 1; | ||
377 | |||
378 | for (i=0 ; i<disks; i++) | ||
379 | if (bi == &sh->dev[i].req) | ||
380 | break; | ||
381 | |||
382 | PRINTK("end_read_request %llu/%d, count: %d, uptodate %d.\n", | ||
383 | (unsigned long long)sh->sector, i, atomic_read(&sh->count), | ||
384 | uptodate); | ||
385 | if (i == disks) { | ||
386 | BUG(); | ||
387 | return 0; | ||
388 | } | ||
389 | |||
390 | if (uptodate) { | ||
391 | #if 0 | ||
392 | struct bio *bio; | ||
393 | unsigned long flags; | ||
394 | spin_lock_irqsave(&conf->device_lock, flags); | ||
395 | /* we can return a buffer if we bypassed the cache or | ||
396 | * if the top buffer is not in highmem. If there are | ||
397 | * multiple buffers, leave the extra work to | ||
398 | * handle_stripe | ||
399 | */ | ||
400 | buffer = sh->bh_read[i]; | ||
401 | if (buffer && | ||
402 | (!PageHighMem(buffer->b_page) | ||
403 | || buffer->b_page == bh->b_page ) | ||
404 | ) { | ||
405 | sh->bh_read[i] = buffer->b_reqnext; | ||
406 | buffer->b_reqnext = NULL; | ||
407 | } else | ||
408 | buffer = NULL; | ||
409 | spin_unlock_irqrestore(&conf->device_lock, flags); | ||
410 | if (sh->bh_page[i]==bh->b_page) | ||
411 | set_buffer_uptodate(bh); | ||
412 | if (buffer) { | ||
413 | if (buffer->b_page != bh->b_page) | ||
414 | memcpy(buffer->b_data, bh->b_data, bh->b_size); | ||
415 | buffer->b_end_io(buffer, 1); | ||
416 | } | ||
417 | #else | ||
418 | set_bit(R5_UPTODATE, &sh->dev[i].flags); | ||
419 | #endif | ||
420 | if (test_bit(R5_ReadError, &sh->dev[i].flags)) { | ||
421 | printk(KERN_INFO "raid6: read error corrected!!\n"); | ||
422 | clear_bit(R5_ReadError, &sh->dev[i].flags); | ||
423 | clear_bit(R5_ReWrite, &sh->dev[i].flags); | ||
424 | } | ||
425 | if (atomic_read(&conf->disks[i].rdev->read_errors)) | ||
426 | atomic_set(&conf->disks[i].rdev->read_errors, 0); | ||
427 | } else { | ||
428 | int retry = 0; | ||
429 | clear_bit(R5_UPTODATE, &sh->dev[i].flags); | ||
430 | atomic_inc(&conf->disks[i].rdev->read_errors); | ||
431 | if (conf->mddev->degraded) | ||
432 | printk(KERN_WARNING "raid6: read error not correctable.\n"); | ||
433 | else if (test_bit(R5_ReWrite, &sh->dev[i].flags)) | ||
434 | /* Oh, no!!! */ | ||
435 | printk(KERN_WARNING "raid6: read error NOT corrected!!\n"); | ||
436 | else if (atomic_read(&conf->disks[i].rdev->read_errors) | ||
437 | > conf->max_nr_stripes) | ||
438 | printk(KERN_WARNING | ||
439 | "raid6: Too many read errors, failing device.\n"); | ||
440 | else | ||
441 | retry = 1; | ||
442 | if (retry) | ||
443 | set_bit(R5_ReadError, &sh->dev[i].flags); | ||
444 | else { | ||
445 | clear_bit(R5_ReadError, &sh->dev[i].flags); | ||
446 | clear_bit(R5_ReWrite, &sh->dev[i].flags); | ||
447 | md_error(conf->mddev, conf->disks[i].rdev); | ||
448 | } | ||
449 | } | ||
450 | rdev_dec_pending(conf->disks[i].rdev, conf->mddev); | ||
451 | #if 0 | ||
452 | /* must restore b_page before unlocking buffer... */ | ||
453 | if (sh->bh_page[i] != bh->b_page) { | ||
454 | bh->b_page = sh->bh_page[i]; | ||
455 | bh->b_data = page_address(bh->b_page); | ||
456 | clear_buffer_uptodate(bh); | ||
457 | } | ||
458 | #endif | ||
459 | clear_bit(R5_LOCKED, &sh->dev[i].flags); | ||
460 | set_bit(STRIPE_HANDLE, &sh->state); | ||
461 | release_stripe(sh); | ||
462 | return 0; | ||
463 | } | ||
464 | |||
465 | static int raid6_end_write_request (struct bio *bi, unsigned int bytes_done, | ||
466 | int error) | ||
467 | { | ||
468 | struct stripe_head *sh = bi->bi_private; | ||
469 | raid6_conf_t *conf = sh->raid_conf; | ||
470 | int disks = conf->raid_disks, i; | ||
471 | unsigned long flags; | ||
472 | int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags); | ||
473 | |||
474 | if (bi->bi_size) | ||
475 | return 1; | ||
476 | |||
477 | for (i=0 ; i<disks; i++) | ||
478 | if (bi == &sh->dev[i].req) | ||
479 | break; | ||
480 | |||
481 | PRINTK("end_write_request %llu/%d, count %d, uptodate: %d.\n", | ||
482 | (unsigned long long)sh->sector, i, atomic_read(&sh->count), | ||
483 | uptodate); | ||
484 | if (i == disks) { | ||
485 | BUG(); | ||
486 | return 0; | ||
487 | } | ||
488 | |||
489 | spin_lock_irqsave(&conf->device_lock, flags); | ||
490 | if (!uptodate) | ||
491 | md_error(conf->mddev, conf->disks[i].rdev); | ||
492 | |||
493 | rdev_dec_pending(conf->disks[i].rdev, conf->mddev); | ||
494 | |||
495 | clear_bit(R5_LOCKED, &sh->dev[i].flags); | ||
496 | set_bit(STRIPE_HANDLE, &sh->state); | ||
497 | __release_stripe(conf, sh); | ||
498 | spin_unlock_irqrestore(&conf->device_lock, flags); | ||
499 | return 0; | ||
500 | } | ||
501 | |||
502 | |||
503 | static sector_t compute_blocknr(struct stripe_head *sh, int i); | ||
504 | |||
505 | static void raid6_build_block (struct stripe_head *sh, int i) | ||
506 | { | ||
507 | struct r5dev *dev = &sh->dev[i]; | ||
508 | int pd_idx = sh->pd_idx; | ||
509 | int qd_idx = raid6_next_disk(pd_idx, sh->raid_conf->raid_disks); | ||
510 | |||
511 | bio_init(&dev->req); | ||
512 | dev->req.bi_io_vec = &dev->vec; | ||
513 | dev->req.bi_vcnt++; | ||
514 | dev->req.bi_max_vecs++; | ||
515 | dev->vec.bv_page = dev->page; | ||
516 | dev->vec.bv_len = STRIPE_SIZE; | ||
517 | dev->vec.bv_offset = 0; | ||
518 | |||
519 | dev->req.bi_sector = sh->sector; | ||
520 | dev->req.bi_private = sh; | ||
521 | |||
522 | dev->flags = 0; | ||
523 | if (i != pd_idx && i != qd_idx) | ||
524 | dev->sector = compute_blocknr(sh, i); | ||
525 | } | ||
526 | |||
527 | static void error(mddev_t *mddev, mdk_rdev_t *rdev) | ||
528 | { | ||
529 | char b[BDEVNAME_SIZE]; | ||
530 | raid6_conf_t *conf = (raid6_conf_t *) mddev->private; | ||
531 | PRINTK("raid6: error called\n"); | ||
532 | |||
533 | if (!test_bit(Faulty, &rdev->flags)) { | ||
534 | mddev->sb_dirty = 1; | ||
535 | if (test_bit(In_sync, &rdev->flags)) { | ||
536 | conf->working_disks--; | ||
537 | mddev->degraded++; | ||
538 | conf->failed_disks++; | ||
539 | clear_bit(In_sync, &rdev->flags); | ||
540 | /* | ||
541 | * if recovery was running, make sure it aborts. | ||
542 | */ | ||
543 | set_bit(MD_RECOVERY_ERR, &mddev->recovery); | ||
544 | } | ||
545 | set_bit(Faulty, &rdev->flags); | ||
546 | printk (KERN_ALERT | ||
547 | "raid6: Disk failure on %s, disabling device." | ||
548 | " Operation continuing on %d devices\n", | ||
549 | bdevname(rdev->bdev,b), conf->working_disks); | ||
550 | } | ||
551 | } | ||
552 | |||
553 | /* | ||
554 | * Input: a 'big' sector number, | ||
555 | * Output: index of the data and parity disk, and the sector # in them. | ||
556 | */ | ||
557 | static sector_t raid6_compute_sector(sector_t r_sector, unsigned int raid_disks, | ||
558 | unsigned int data_disks, unsigned int * dd_idx, | ||
559 | unsigned int * pd_idx, raid6_conf_t *conf) | ||
560 | { | ||
561 | long stripe; | ||
562 | unsigned long chunk_number; | ||
563 | unsigned int chunk_offset; | ||
564 | sector_t new_sector; | ||
565 | int sectors_per_chunk = conf->chunk_size >> 9; | ||
566 | |||
567 | /* First compute the information on this sector */ | ||
568 | |||
569 | /* | ||
570 | * Compute the chunk number and the sector offset inside the chunk | ||
571 | */ | ||
572 | chunk_offset = sector_div(r_sector, sectors_per_chunk); | ||
573 | chunk_number = r_sector; | ||
574 | if ( r_sector != chunk_number ) { | ||
575 | printk(KERN_CRIT "raid6: ERROR: r_sector = %llu, chunk_number = %lu\n", | ||
576 | (unsigned long long)r_sector, (unsigned long)chunk_number); | ||
577 | BUG(); | ||
578 | } | ||
579 | |||
580 | /* | ||
581 | * Compute the stripe number | ||
582 | */ | ||
583 | stripe = chunk_number / data_disks; | ||
584 | |||
585 | /* | ||
586 | * Compute the data disk and parity disk indexes inside the stripe | ||
587 | */ | ||
588 | *dd_idx = chunk_number % data_disks; | ||
589 | |||
590 | /* | ||
591 | * Select the parity disk based on the user selected algorithm. | ||
592 | */ | ||
593 | |||
594 | /**** FIX THIS ****/ | ||
595 | switch (conf->algorithm) { | ||
596 | case ALGORITHM_LEFT_ASYMMETRIC: | ||
597 | *pd_idx = raid_disks - 1 - (stripe % raid_disks); | ||
598 | if (*pd_idx == raid_disks-1) | ||
599 | (*dd_idx)++; /* Q D D D P */ | ||
600 | else if (*dd_idx >= *pd_idx) | ||
601 | (*dd_idx) += 2; /* D D P Q D */ | ||
602 | break; | ||
603 | case ALGORITHM_RIGHT_ASYMMETRIC: | ||
604 | *pd_idx = stripe % raid_disks; | ||
605 | if (*pd_idx == raid_disks-1) | ||
606 | (*dd_idx)++; /* Q D D D P */ | ||
607 | else if (*dd_idx >= *pd_idx) | ||
608 | (*dd_idx) += 2; /* D D P Q D */ | ||
609 | break; | ||
610 | case ALGORITHM_LEFT_SYMMETRIC: | ||
611 | *pd_idx = raid_disks - 1 - (stripe % raid_disks); | ||
612 | *dd_idx = (*pd_idx + 2 + *dd_idx) % raid_disks; | ||
613 | break; | ||
614 | case ALGORITHM_RIGHT_SYMMETRIC: | ||
615 | *pd_idx = stripe % raid_disks; | ||
616 | *dd_idx = (*pd_idx + 2 + *dd_idx) % raid_disks; | ||
617 | break; | ||
618 | default: | ||
619 | printk (KERN_CRIT "raid6: unsupported algorithm %d\n", | ||
620 | conf->algorithm); | ||
621 | } | ||
622 | |||
623 | PRINTK("raid6: chunk_number = %lu, pd_idx = %u, dd_idx = %u\n", | ||
624 | chunk_number, *pd_idx, *dd_idx); | ||
625 | |||
626 | /* | ||
627 | * Finally, compute the new sector number | ||
628 | */ | ||
629 | new_sector = (sector_t) stripe * sectors_per_chunk + chunk_offset; | ||
630 | return new_sector; | ||
631 | } | ||
632 | |||
633 | |||
634 | static sector_t compute_blocknr(struct stripe_head *sh, int i) | ||
635 | { | ||
636 | raid6_conf_t *conf = sh->raid_conf; | ||
637 | int raid_disks = conf->raid_disks, data_disks = raid_disks - 2; | ||
638 | sector_t new_sector = sh->sector, check; | ||
639 | int sectors_per_chunk = conf->chunk_size >> 9; | ||
640 | sector_t stripe; | ||
641 | int chunk_offset; | ||
642 | int chunk_number, dummy1, dummy2, dd_idx = i; | ||
643 | sector_t r_sector; | ||
644 | int i0 = i; | ||
645 | |||
646 | chunk_offset = sector_div(new_sector, sectors_per_chunk); | ||
647 | stripe = new_sector; | ||
648 | if ( new_sector != stripe ) { | ||
649 | printk(KERN_CRIT "raid6: ERROR: new_sector = %llu, stripe = %lu\n", | ||
650 | (unsigned long long)new_sector, (unsigned long)stripe); | ||
651 | BUG(); | ||
652 | } | ||
653 | |||
654 | switch (conf->algorithm) { | ||
655 | case ALGORITHM_LEFT_ASYMMETRIC: | ||
656 | case ALGORITHM_RIGHT_ASYMMETRIC: | ||
657 | if (sh->pd_idx == raid_disks-1) | ||
658 | i--; /* Q D D D P */ | ||
659 | else if (i > sh->pd_idx) | ||
660 | i -= 2; /* D D P Q D */ | ||
661 | break; | ||
662 | case ALGORITHM_LEFT_SYMMETRIC: | ||
663 | case ALGORITHM_RIGHT_SYMMETRIC: | ||
664 | if (sh->pd_idx == raid_disks-1) | ||
665 | i--; /* Q D D D P */ | ||
666 | else { | ||
667 | /* D D P Q D */ | ||
668 | if (i < sh->pd_idx) | ||
669 | i += raid_disks; | ||
670 | i -= (sh->pd_idx + 2); | ||
671 | } | ||
672 | break; | ||
673 | default: | ||
674 | printk (KERN_CRIT "raid6: unsupported algorithm %d\n", | ||
675 | conf->algorithm); | ||
676 | } | ||
677 | |||
678 | PRINTK("raid6: compute_blocknr: pd_idx = %u, i0 = %u, i = %u\n", sh->pd_idx, i0, i); | ||
679 | |||
680 | chunk_number = stripe * data_disks + i; | ||
681 | r_sector = (sector_t)chunk_number * sectors_per_chunk + chunk_offset; | ||
682 | |||
683 | check = raid6_compute_sector (r_sector, raid_disks, data_disks, &dummy1, &dummy2, conf); | ||
684 | if (check != sh->sector || dummy1 != dd_idx || dummy2 != sh->pd_idx) { | ||
685 | printk(KERN_CRIT "raid6: compute_blocknr: map not correct\n"); | ||
686 | return 0; | ||
687 | } | ||
688 | return r_sector; | ||
689 | } | ||
690 | |||
691 | |||
692 | |||
693 | /* | ||
694 | * Copy data between a page in the stripe cache, and one or more bion | ||
695 | * The page could align with the middle of the bio, or there could be | ||
696 | * several bion, each with several bio_vecs, which cover part of the page | ||
697 | * Multiple bion are linked together on bi_next. There may be extras | ||
698 | * at the end of this list. We ignore them. | ||
699 | */ | ||
700 | static void copy_data(int frombio, struct bio *bio, | ||
701 | struct page *page, | ||
702 | sector_t sector) | ||
703 | { | ||
704 | char *pa = page_address(page); | ||
705 | struct bio_vec *bvl; | ||
706 | int i; | ||
707 | int page_offset; | ||
708 | |||
709 | if (bio->bi_sector >= sector) | ||
710 | page_offset = (signed)(bio->bi_sector - sector) * 512; | ||
711 | else | ||
712 | page_offset = (signed)(sector - bio->bi_sector) * -512; | ||
713 | bio_for_each_segment(bvl, bio, i) { | ||
714 | int len = bio_iovec_idx(bio,i)->bv_len; | ||
715 | int clen; | ||
716 | int b_offset = 0; | ||
717 | |||
718 | if (page_offset < 0) { | ||
719 | b_offset = -page_offset; | ||
720 | page_offset += b_offset; | ||
721 | len -= b_offset; | ||
722 | } | ||
723 | |||
724 | if (len > 0 && page_offset + len > STRIPE_SIZE) | ||
725 | clen = STRIPE_SIZE - page_offset; | ||
726 | else clen = len; | ||
727 | |||
728 | if (clen > 0) { | ||
729 | char *ba = __bio_kmap_atomic(bio, i, KM_USER0); | ||
730 | if (frombio) | ||
731 | memcpy(pa+page_offset, ba+b_offset, clen); | ||
732 | else | ||
733 | memcpy(ba+b_offset, pa+page_offset, clen); | ||
734 | __bio_kunmap_atomic(ba, KM_USER0); | ||
735 | } | ||
736 | if (clen < len) /* hit end of page */ | ||
737 | break; | ||
738 | page_offset += len; | ||
739 | } | ||
740 | } | ||
741 | |||
742 | #define check_xor() do { \ | ||
743 | if (count == MAX_XOR_BLOCKS) { \ | ||
744 | xor_block(count, STRIPE_SIZE, ptr); \ | ||
745 | count = 1; \ | ||
746 | } \ | ||
747 | } while(0) | ||
748 | |||
749 | /* Compute P and Q syndromes */ | ||
750 | static void compute_parity(struct stripe_head *sh, int method) | ||
751 | { | ||
752 | raid6_conf_t *conf = sh->raid_conf; | ||
753 | int i, pd_idx = sh->pd_idx, qd_idx, d0_idx, disks = conf->raid_disks, count; | ||
754 | struct bio *chosen; | ||
755 | /**** FIX THIS: This could be very bad if disks is close to 256 ****/ | ||
756 | void *ptrs[disks]; | ||
757 | |||
758 | qd_idx = raid6_next_disk(pd_idx, disks); | ||
759 | d0_idx = raid6_next_disk(qd_idx, disks); | ||
760 | |||
761 | PRINTK("compute_parity, stripe %llu, method %d\n", | ||
762 | (unsigned long long)sh->sector, method); | ||
763 | |||
764 | switch(method) { | ||
765 | case READ_MODIFY_WRITE: | ||
766 | BUG(); /* READ_MODIFY_WRITE N/A for RAID-6 */ | ||
767 | case RECONSTRUCT_WRITE: | ||
768 | for (i= disks; i-- ;) | ||
769 | if ( i != pd_idx && i != qd_idx && sh->dev[i].towrite ) { | ||
770 | chosen = sh->dev[i].towrite; | ||
771 | sh->dev[i].towrite = NULL; | ||
772 | |||
773 | if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags)) | ||
774 | wake_up(&conf->wait_for_overlap); | ||
775 | |||
776 | BUG_ON(sh->dev[i].written); | ||
777 | sh->dev[i].written = chosen; | ||
778 | } | ||
779 | break; | ||
780 | case CHECK_PARITY: | ||
781 | BUG(); /* Not implemented yet */ | ||
782 | } | ||
783 | |||
784 | for (i = disks; i--;) | ||
785 | if (sh->dev[i].written) { | ||
786 | sector_t sector = sh->dev[i].sector; | ||
787 | struct bio *wbi = sh->dev[i].written; | ||
788 | while (wbi && wbi->bi_sector < sector + STRIPE_SECTORS) { | ||
789 | copy_data(1, wbi, sh->dev[i].page, sector); | ||
790 | wbi = r5_next_bio(wbi, sector); | ||
791 | } | ||
792 | |||
793 | set_bit(R5_LOCKED, &sh->dev[i].flags); | ||
794 | set_bit(R5_UPTODATE, &sh->dev[i].flags); | ||
795 | } | ||
796 | |||
797 | // switch(method) { | ||
798 | // case RECONSTRUCT_WRITE: | ||
799 | // case CHECK_PARITY: | ||
800 | // case UPDATE_PARITY: | ||
801 | /* Note that unlike RAID-5, the ordering of the disks matters greatly. */ | ||
802 | /* FIX: Is this ordering of drives even remotely optimal? */ | ||
803 | count = 0; | ||
804 | i = d0_idx; | ||
805 | do { | ||
806 | ptrs[count++] = page_address(sh->dev[i].page); | ||
807 | if (count <= disks-2 && !test_bit(R5_UPTODATE, &sh->dev[i].flags)) | ||
808 | printk("block %d/%d not uptodate on parity calc\n", i,count); | ||
809 | i = raid6_next_disk(i, disks); | ||
810 | } while ( i != d0_idx ); | ||
811 | // break; | ||
812 | // } | ||
813 | |||
814 | raid6_call.gen_syndrome(disks, STRIPE_SIZE, ptrs); | ||
815 | |||
816 | switch(method) { | ||
817 | case RECONSTRUCT_WRITE: | ||
818 | set_bit(R5_UPTODATE, &sh->dev[pd_idx].flags); | ||
819 | set_bit(R5_UPTODATE, &sh->dev[qd_idx].flags); | ||
820 | set_bit(R5_LOCKED, &sh->dev[pd_idx].flags); | ||
821 | set_bit(R5_LOCKED, &sh->dev[qd_idx].flags); | ||
822 | break; | ||
823 | case UPDATE_PARITY: | ||
824 | set_bit(R5_UPTODATE, &sh->dev[pd_idx].flags); | ||
825 | set_bit(R5_UPTODATE, &sh->dev[qd_idx].flags); | ||
826 | break; | ||
827 | } | ||
828 | } | ||
829 | |||
830 | /* Compute one missing block */ | ||
831 | static void compute_block_1(struct stripe_head *sh, int dd_idx, int nozero) | ||
832 | { | ||
833 | raid6_conf_t *conf = sh->raid_conf; | ||
834 | int i, count, disks = conf->raid_disks; | ||
835 | void *ptr[MAX_XOR_BLOCKS], *p; | ||
836 | int pd_idx = sh->pd_idx; | ||
837 | int qd_idx = raid6_next_disk(pd_idx, disks); | ||
838 | |||
839 | PRINTK("compute_block_1, stripe %llu, idx %d\n", | ||
840 | (unsigned long long)sh->sector, dd_idx); | ||
841 | |||
842 | if ( dd_idx == qd_idx ) { | ||
843 | /* We're actually computing the Q drive */ | ||
844 | compute_parity(sh, UPDATE_PARITY); | ||
845 | } else { | ||
846 | ptr[0] = page_address(sh->dev[dd_idx].page); | ||
847 | if (!nozero) memset(ptr[0], 0, STRIPE_SIZE); | ||
848 | count = 1; | ||
849 | for (i = disks ; i--; ) { | ||
850 | if (i == dd_idx || i == qd_idx) | ||
851 | continue; | ||
852 | p = page_address(sh->dev[i].page); | ||
853 | if (test_bit(R5_UPTODATE, &sh->dev[i].flags)) | ||
854 | ptr[count++] = p; | ||
855 | else | ||
856 | printk("compute_block() %d, stripe %llu, %d" | ||
857 | " not present\n", dd_idx, | ||
858 | (unsigned long long)sh->sector, i); | ||
859 | |||
860 | check_xor(); | ||
861 | } | ||
862 | if (count != 1) | ||
863 | xor_block(count, STRIPE_SIZE, ptr); | ||
864 | if (!nozero) set_bit(R5_UPTODATE, &sh->dev[dd_idx].flags); | ||
865 | else clear_bit(R5_UPTODATE, &sh->dev[dd_idx].flags); | ||
866 | } | ||
867 | } | ||
868 | |||
869 | /* Compute two missing blocks */ | ||
870 | static void compute_block_2(struct stripe_head *sh, int dd_idx1, int dd_idx2) | ||
871 | { | ||
872 | raid6_conf_t *conf = sh->raid_conf; | ||
873 | int i, count, disks = conf->raid_disks; | ||
874 | int pd_idx = sh->pd_idx; | ||
875 | int qd_idx = raid6_next_disk(pd_idx, disks); | ||
876 | int d0_idx = raid6_next_disk(qd_idx, disks); | ||
877 | int faila, failb; | ||
878 | |||
879 | /* faila and failb are disk numbers relative to d0_idx */ | ||
880 | /* pd_idx become disks-2 and qd_idx become disks-1 */ | ||
881 | faila = (dd_idx1 < d0_idx) ? dd_idx1+(disks-d0_idx) : dd_idx1-d0_idx; | ||
882 | failb = (dd_idx2 < d0_idx) ? dd_idx2+(disks-d0_idx) : dd_idx2-d0_idx; | ||
883 | |||
884 | BUG_ON(faila == failb); | ||
885 | if ( failb < faila ) { int tmp = faila; faila = failb; failb = tmp; } | ||
886 | |||
887 | PRINTK("compute_block_2, stripe %llu, idx %d,%d (%d,%d)\n", | ||
888 | (unsigned long long)sh->sector, dd_idx1, dd_idx2, faila, failb); | ||
889 | |||
890 | if ( failb == disks-1 ) { | ||
891 | /* Q disk is one of the missing disks */ | ||
892 | if ( faila == disks-2 ) { | ||
893 | /* Missing P+Q, just recompute */ | ||
894 | compute_parity(sh, UPDATE_PARITY); | ||
895 | return; | ||
896 | } else { | ||
897 | /* We're missing D+Q; recompute D from P */ | ||
898 | compute_block_1(sh, (dd_idx1 == qd_idx) ? dd_idx2 : dd_idx1, 0); | ||
899 | compute_parity(sh, UPDATE_PARITY); /* Is this necessary? */ | ||
900 | return; | ||
901 | } | ||
902 | } | ||
903 | |||
904 | /* We're missing D+P or D+D; build pointer table */ | ||
905 | { | ||
906 | /**** FIX THIS: This could be very bad if disks is close to 256 ****/ | ||
907 | void *ptrs[disks]; | ||
908 | |||
909 | count = 0; | ||
910 | i = d0_idx; | ||
911 | do { | ||
912 | ptrs[count++] = page_address(sh->dev[i].page); | ||
913 | i = raid6_next_disk(i, disks); | ||
914 | if (i != dd_idx1 && i != dd_idx2 && | ||
915 | !test_bit(R5_UPTODATE, &sh->dev[i].flags)) | ||
916 | printk("compute_2 with missing block %d/%d\n", count, i); | ||
917 | } while ( i != d0_idx ); | ||
918 | |||
919 | if ( failb == disks-2 ) { | ||
920 | /* We're missing D+P. */ | ||
921 | raid6_datap_recov(disks, STRIPE_SIZE, faila, ptrs); | ||
922 | } else { | ||
923 | /* We're missing D+D. */ | ||
924 | raid6_2data_recov(disks, STRIPE_SIZE, faila, failb, ptrs); | ||
925 | } | ||
926 | |||
927 | /* Both the above update both missing blocks */ | ||
928 | set_bit(R5_UPTODATE, &sh->dev[dd_idx1].flags); | ||
929 | set_bit(R5_UPTODATE, &sh->dev[dd_idx2].flags); | ||
930 | } | ||
931 | } | ||
932 | |||
933 | |||
934 | /* | ||
935 | * Each stripe/dev can have one or more bion attached. | ||
936 | * toread/towrite point to the first in a chain. | ||
937 | * The bi_next chain must be in order. | ||
938 | */ | ||
939 | static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, int forwrite) | ||
940 | { | ||
941 | struct bio **bip; | ||
942 | raid6_conf_t *conf = sh->raid_conf; | ||
943 | int firstwrite=0; | ||
944 | |||
945 | PRINTK("adding bh b#%llu to stripe s#%llu\n", | ||
946 | (unsigned long long)bi->bi_sector, | ||
947 | (unsigned long long)sh->sector); | ||
948 | |||
949 | |||
950 | spin_lock(&sh->lock); | ||
951 | spin_lock_irq(&conf->device_lock); | ||
952 | if (forwrite) { | ||
953 | bip = &sh->dev[dd_idx].towrite; | ||
954 | if (*bip == NULL && sh->dev[dd_idx].written == NULL) | ||
955 | firstwrite = 1; | ||
956 | } else | ||
957 | bip = &sh->dev[dd_idx].toread; | ||
958 | while (*bip && (*bip)->bi_sector < bi->bi_sector) { | ||
959 | if ((*bip)->bi_sector + ((*bip)->bi_size >> 9) > bi->bi_sector) | ||
960 | goto overlap; | ||
961 | bip = &(*bip)->bi_next; | ||
962 | } | ||
963 | if (*bip && (*bip)->bi_sector < bi->bi_sector + ((bi->bi_size)>>9)) | ||
964 | goto overlap; | ||
965 | |||
966 | BUG_ON(*bip && bi->bi_next && (*bip) != bi->bi_next); | ||
967 | if (*bip) | ||
968 | bi->bi_next = *bip; | ||
969 | *bip = bi; | ||
970 | bi->bi_phys_segments ++; | ||
971 | spin_unlock_irq(&conf->device_lock); | ||
972 | spin_unlock(&sh->lock); | ||
973 | |||
974 | PRINTK("added bi b#%llu to stripe s#%llu, disk %d.\n", | ||
975 | (unsigned long long)bi->bi_sector, | ||
976 | (unsigned long long)sh->sector, dd_idx); | ||
977 | |||
978 | if (conf->mddev->bitmap && firstwrite) { | ||
979 | sh->bm_seq = conf->seq_write; | ||
980 | bitmap_startwrite(conf->mddev->bitmap, sh->sector, | ||
981 | STRIPE_SECTORS, 0); | ||
982 | set_bit(STRIPE_BIT_DELAY, &sh->state); | ||
983 | } | ||
984 | |||
985 | if (forwrite) { | ||
986 | /* check if page is covered */ | ||
987 | sector_t sector = sh->dev[dd_idx].sector; | ||
988 | for (bi=sh->dev[dd_idx].towrite; | ||
989 | sector < sh->dev[dd_idx].sector + STRIPE_SECTORS && | ||
990 | bi && bi->bi_sector <= sector; | ||
991 | bi = r5_next_bio(bi, sh->dev[dd_idx].sector)) { | ||
992 | if (bi->bi_sector + (bi->bi_size>>9) >= sector) | ||
993 | sector = bi->bi_sector + (bi->bi_size>>9); | ||
994 | } | ||
995 | if (sector >= sh->dev[dd_idx].sector + STRIPE_SECTORS) | ||
996 | set_bit(R5_OVERWRITE, &sh->dev[dd_idx].flags); | ||
997 | } | ||
998 | return 1; | ||
999 | |||
1000 | overlap: | ||
1001 | set_bit(R5_Overlap, &sh->dev[dd_idx].flags); | ||
1002 | spin_unlock_irq(&conf->device_lock); | ||
1003 | spin_unlock(&sh->lock); | ||
1004 | return 0; | ||
1005 | } | ||
1006 | |||
1007 | |||
1008 | static int page_is_zero(struct page *p) | ||
1009 | { | ||
1010 | char *a = page_address(p); | ||
1011 | return ((*(u32*)a) == 0 && | ||
1012 | memcmp(a, a+4, STRIPE_SIZE-4)==0); | ||
1013 | } | ||
1014 | /* | ||
1015 | * handle_stripe - do things to a stripe. | ||
1016 | * | ||
1017 | * We lock the stripe and then examine the state of various bits | ||
1018 | * to see what needs to be done. | ||
1019 | * Possible results: | ||
1020 | * return some read request which now have data | ||
1021 | * return some write requests which are safely on disc | ||
1022 | * schedule a read on some buffers | ||
1023 | * schedule a write of some buffers | ||
1024 | * return confirmation of parity correctness | ||
1025 | * | ||
1026 | * Parity calculations are done inside the stripe lock | ||
1027 | * buffers are taken off read_list or write_list, and bh_cache buffers | ||
1028 | * get BH_Lock set before the stripe lock is released. | ||
1029 | * | ||
1030 | */ | ||
1031 | |||
1032 | static void handle_stripe(struct stripe_head *sh, struct page *tmp_page) | ||
1033 | { | ||
1034 | raid6_conf_t *conf = sh->raid_conf; | ||
1035 | int disks = conf->raid_disks; | ||
1036 | struct bio *return_bi= NULL; | ||
1037 | struct bio *bi; | ||
1038 | int i; | ||
1039 | int syncing; | ||
1040 | int locked=0, uptodate=0, to_read=0, to_write=0, failed=0, written=0; | ||
1041 | int non_overwrite = 0; | ||
1042 | int failed_num[2] = {0, 0}; | ||
1043 | struct r5dev *dev, *pdev, *qdev; | ||
1044 | int pd_idx = sh->pd_idx; | ||
1045 | int qd_idx = raid6_next_disk(pd_idx, disks); | ||
1046 | int p_failed, q_failed; | ||
1047 | |||
1048 | PRINTK("handling stripe %llu, state=%#lx cnt=%d, pd_idx=%d, qd_idx=%d\n", | ||
1049 | (unsigned long long)sh->sector, sh->state, atomic_read(&sh->count), | ||
1050 | pd_idx, qd_idx); | ||
1051 | |||
1052 | spin_lock(&sh->lock); | ||
1053 | clear_bit(STRIPE_HANDLE, &sh->state); | ||
1054 | clear_bit(STRIPE_DELAYED, &sh->state); | ||
1055 | |||
1056 | syncing = test_bit(STRIPE_SYNCING, &sh->state); | ||
1057 | /* Now to look around and see what can be done */ | ||
1058 | |||
1059 | rcu_read_lock(); | ||
1060 | for (i=disks; i--; ) { | ||
1061 | mdk_rdev_t *rdev; | ||
1062 | dev = &sh->dev[i]; | ||
1063 | clear_bit(R5_Insync, &dev->flags); | ||
1064 | |||
1065 | PRINTK("check %d: state 0x%lx read %p write %p written %p\n", | ||
1066 | i, dev->flags, dev->toread, dev->towrite, dev->written); | ||
1067 | /* maybe we can reply to a read */ | ||
1068 | if (test_bit(R5_UPTODATE, &dev->flags) && dev->toread) { | ||
1069 | struct bio *rbi, *rbi2; | ||
1070 | PRINTK("Return read for disc %d\n", i); | ||
1071 | spin_lock_irq(&conf->device_lock); | ||
1072 | rbi = dev->toread; | ||
1073 | dev->toread = NULL; | ||
1074 | if (test_and_clear_bit(R5_Overlap, &dev->flags)) | ||
1075 | wake_up(&conf->wait_for_overlap); | ||
1076 | spin_unlock_irq(&conf->device_lock); | ||
1077 | while (rbi && rbi->bi_sector < dev->sector + STRIPE_SECTORS) { | ||
1078 | copy_data(0, rbi, dev->page, dev->sector); | ||
1079 | rbi2 = r5_next_bio(rbi, dev->sector); | ||
1080 | spin_lock_irq(&conf->device_lock); | ||
1081 | if (--rbi->bi_phys_segments == 0) { | ||
1082 | rbi->bi_next = return_bi; | ||
1083 | return_bi = rbi; | ||
1084 | } | ||
1085 | spin_unlock_irq(&conf->device_lock); | ||
1086 | rbi = rbi2; | ||
1087 | } | ||
1088 | } | ||
1089 | |||
1090 | /* now count some things */ | ||
1091 | if (test_bit(R5_LOCKED, &dev->flags)) locked++; | ||
1092 | if (test_bit(R5_UPTODATE, &dev->flags)) uptodate++; | ||
1093 | |||
1094 | |||
1095 | if (dev->toread) to_read++; | ||
1096 | if (dev->towrite) { | ||
1097 | to_write++; | ||
1098 | if (!test_bit(R5_OVERWRITE, &dev->flags)) | ||
1099 | non_overwrite++; | ||
1100 | } | ||
1101 | if (dev->written) written++; | ||
1102 | rdev = rcu_dereference(conf->disks[i].rdev); | ||
1103 | if (!rdev || !test_bit(In_sync, &rdev->flags)) { | ||
1104 | /* The ReadError flag will just be confusing now */ | ||
1105 | clear_bit(R5_ReadError, &dev->flags); | ||
1106 | clear_bit(R5_ReWrite, &dev->flags); | ||
1107 | } | ||
1108 | if (!rdev || !test_bit(In_sync, &rdev->flags) | ||
1109 | || test_bit(R5_ReadError, &dev->flags)) { | ||
1110 | if ( failed < 2 ) | ||
1111 | failed_num[failed] = i; | ||
1112 | failed++; | ||
1113 | } else | ||
1114 | set_bit(R5_Insync, &dev->flags); | ||
1115 | } | ||
1116 | rcu_read_unlock(); | ||
1117 | PRINTK("locked=%d uptodate=%d to_read=%d" | ||
1118 | " to_write=%d failed=%d failed_num=%d,%d\n", | ||
1119 | locked, uptodate, to_read, to_write, failed, | ||
1120 | failed_num[0], failed_num[1]); | ||
1121 | /* check if the array has lost >2 devices and, if so, some requests might | ||
1122 | * need to be failed | ||
1123 | */ | ||
1124 | if (failed > 2 && to_read+to_write+written) { | ||
1125 | for (i=disks; i--; ) { | ||
1126 | int bitmap_end = 0; | ||
1127 | |||
1128 | if (test_bit(R5_ReadError, &sh->dev[i].flags)) { | ||
1129 | mdk_rdev_t *rdev; | ||
1130 | rcu_read_lock(); | ||
1131 | rdev = rcu_dereference(conf->disks[i].rdev); | ||
1132 | if (rdev && test_bit(In_sync, &rdev->flags)) | ||
1133 | /* multiple read failures in one stripe */ | ||
1134 | md_error(conf->mddev, rdev); | ||
1135 | rcu_read_unlock(); | ||
1136 | } | ||
1137 | |||
1138 | spin_lock_irq(&conf->device_lock); | ||
1139 | /* fail all writes first */ | ||
1140 | bi = sh->dev[i].towrite; | ||
1141 | sh->dev[i].towrite = NULL; | ||
1142 | if (bi) { to_write--; bitmap_end = 1; } | ||
1143 | |||
1144 | if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags)) | ||
1145 | wake_up(&conf->wait_for_overlap); | ||
1146 | |||
1147 | while (bi && bi->bi_sector < sh->dev[i].sector + STRIPE_SECTORS){ | ||
1148 | struct bio *nextbi = r5_next_bio(bi, sh->dev[i].sector); | ||
1149 | clear_bit(BIO_UPTODATE, &bi->bi_flags); | ||
1150 | if (--bi->bi_phys_segments == 0) { | ||
1151 | md_write_end(conf->mddev); | ||
1152 | bi->bi_next = return_bi; | ||
1153 | return_bi = bi; | ||
1154 | } | ||
1155 | bi = nextbi; | ||
1156 | } | ||
1157 | /* and fail all 'written' */ | ||
1158 | bi = sh->dev[i].written; | ||
1159 | sh->dev[i].written = NULL; | ||
1160 | if (bi) bitmap_end = 1; | ||
1161 | while (bi && bi->bi_sector < sh->dev[i].sector + STRIPE_SECTORS) { | ||
1162 | struct bio *bi2 = r5_next_bio(bi, sh->dev[i].sector); | ||
1163 | clear_bit(BIO_UPTODATE, &bi->bi_flags); | ||
1164 | if (--bi->bi_phys_segments == 0) { | ||
1165 | md_write_end(conf->mddev); | ||
1166 | bi->bi_next = return_bi; | ||
1167 | return_bi = bi; | ||
1168 | } | ||
1169 | bi = bi2; | ||
1170 | } | ||
1171 | |||
1172 | /* fail any reads if this device is non-operational */ | ||
1173 | if (!test_bit(R5_Insync, &sh->dev[i].flags) || | ||
1174 | test_bit(R5_ReadError, &sh->dev[i].flags)) { | ||
1175 | bi = sh->dev[i].toread; | ||
1176 | sh->dev[i].toread = NULL; | ||
1177 | if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags)) | ||
1178 | wake_up(&conf->wait_for_overlap); | ||
1179 | if (bi) to_read--; | ||
1180 | while (bi && bi->bi_sector < sh->dev[i].sector + STRIPE_SECTORS){ | ||
1181 | struct bio *nextbi = r5_next_bio(bi, sh->dev[i].sector); | ||
1182 | clear_bit(BIO_UPTODATE, &bi->bi_flags); | ||
1183 | if (--bi->bi_phys_segments == 0) { | ||
1184 | bi->bi_next = return_bi; | ||
1185 | return_bi = bi; | ||
1186 | } | ||
1187 | bi = nextbi; | ||
1188 | } | ||
1189 | } | ||
1190 | spin_unlock_irq(&conf->device_lock); | ||
1191 | if (bitmap_end) | ||
1192 | bitmap_endwrite(conf->mddev->bitmap, sh->sector, | ||
1193 | STRIPE_SECTORS, 0, 0); | ||
1194 | } | ||
1195 | } | ||
1196 | if (failed > 2 && syncing) { | ||
1197 | md_done_sync(conf->mddev, STRIPE_SECTORS,0); | ||
1198 | clear_bit(STRIPE_SYNCING, &sh->state); | ||
1199 | syncing = 0; | ||
1200 | } | ||
1201 | |||
1202 | /* | ||
1203 | * might be able to return some write requests if the parity blocks | ||
1204 | * are safe, or on a failed drive | ||
1205 | */ | ||
1206 | pdev = &sh->dev[pd_idx]; | ||
1207 | p_failed = (failed >= 1 && failed_num[0] == pd_idx) | ||
1208 | || (failed >= 2 && failed_num[1] == pd_idx); | ||
1209 | qdev = &sh->dev[qd_idx]; | ||
1210 | q_failed = (failed >= 1 && failed_num[0] == qd_idx) | ||
1211 | || (failed >= 2 && failed_num[1] == qd_idx); | ||
1212 | |||
1213 | if ( written && | ||
1214 | ( p_failed || ((test_bit(R5_Insync, &pdev->flags) | ||
1215 | && !test_bit(R5_LOCKED, &pdev->flags) | ||
1216 | && test_bit(R5_UPTODATE, &pdev->flags))) ) && | ||
1217 | ( q_failed || ((test_bit(R5_Insync, &qdev->flags) | ||
1218 | && !test_bit(R5_LOCKED, &qdev->flags) | ||
1219 | && test_bit(R5_UPTODATE, &qdev->flags))) ) ) { | ||
1220 | /* any written block on an uptodate or failed drive can be | ||
1221 | * returned. Note that if we 'wrote' to a failed drive, | ||
1222 | * it will be UPTODATE, but never LOCKED, so we don't need | ||
1223 | * to test 'failed' directly. | ||
1224 | */ | ||
1225 | for (i=disks; i--; ) | ||
1226 | if (sh->dev[i].written) { | ||
1227 | dev = &sh->dev[i]; | ||
1228 | if (!test_bit(R5_LOCKED, &dev->flags) && | ||
1229 | test_bit(R5_UPTODATE, &dev->flags) ) { | ||
1230 | /* We can return any write requests */ | ||
1231 | int bitmap_end = 0; | ||
1232 | struct bio *wbi, *wbi2; | ||
1233 | PRINTK("Return write for stripe %llu disc %d\n", | ||
1234 | (unsigned long long)sh->sector, i); | ||
1235 | spin_lock_irq(&conf->device_lock); | ||
1236 | wbi = dev->written; | ||
1237 | dev->written = NULL; | ||
1238 | while (wbi && wbi->bi_sector < dev->sector + STRIPE_SECTORS) { | ||
1239 | wbi2 = r5_next_bio(wbi, dev->sector); | ||
1240 | if (--wbi->bi_phys_segments == 0) { | ||
1241 | md_write_end(conf->mddev); | ||
1242 | wbi->bi_next = return_bi; | ||
1243 | return_bi = wbi; | ||
1244 | } | ||
1245 | wbi = wbi2; | ||
1246 | } | ||
1247 | if (dev->towrite == NULL) | ||
1248 | bitmap_end = 1; | ||
1249 | spin_unlock_irq(&conf->device_lock); | ||
1250 | if (bitmap_end) | ||
1251 | bitmap_endwrite(conf->mddev->bitmap, sh->sector, | ||
1252 | STRIPE_SECTORS, | ||
1253 | !test_bit(STRIPE_DEGRADED, &sh->state), 0); | ||
1254 | } | ||
1255 | } | ||
1256 | } | ||
1257 | |||
1258 | /* Now we might consider reading some blocks, either to check/generate | ||
1259 | * parity, or to satisfy requests | ||
1260 | * or to load a block that is being partially written. | ||
1261 | */ | ||
1262 | if (to_read || non_overwrite || (to_write && failed) || (syncing && (uptodate < disks))) { | ||
1263 | for (i=disks; i--;) { | ||
1264 | dev = &sh->dev[i]; | ||
1265 | if (!test_bit(R5_LOCKED, &dev->flags) && !test_bit(R5_UPTODATE, &dev->flags) && | ||
1266 | (dev->toread || | ||
1267 | (dev->towrite && !test_bit(R5_OVERWRITE, &dev->flags)) || | ||
1268 | syncing || | ||
1269 | (failed >= 1 && (sh->dev[failed_num[0]].toread || to_write)) || | ||
1270 | (failed >= 2 && (sh->dev[failed_num[1]].toread || to_write)) | ||
1271 | ) | ||
1272 | ) { | ||
1273 | /* we would like to get this block, possibly | ||
1274 | * by computing it, but we might not be able to | ||
1275 | */ | ||
1276 | if (uptodate == disks-1) { | ||
1277 | PRINTK("Computing stripe %llu block %d\n", | ||
1278 | (unsigned long long)sh->sector, i); | ||
1279 | compute_block_1(sh, i, 0); | ||
1280 | uptodate++; | ||
1281 | } else if ( uptodate == disks-2 && failed >= 2 ) { | ||
1282 | /* Computing 2-failure is *very* expensive; only do it if failed >= 2 */ | ||
1283 | int other; | ||
1284 | for (other=disks; other--;) { | ||
1285 | if ( other == i ) | ||
1286 | continue; | ||
1287 | if ( !test_bit(R5_UPTODATE, &sh->dev[other].flags) ) | ||
1288 | break; | ||
1289 | } | ||
1290 | BUG_ON(other < 0); | ||
1291 | PRINTK("Computing stripe %llu blocks %d,%d\n", | ||
1292 | (unsigned long long)sh->sector, i, other); | ||
1293 | compute_block_2(sh, i, other); | ||
1294 | uptodate += 2; | ||
1295 | } else if (test_bit(R5_Insync, &dev->flags)) { | ||
1296 | set_bit(R5_LOCKED, &dev->flags); | ||
1297 | set_bit(R5_Wantread, &dev->flags); | ||
1298 | #if 0 | ||
1299 | /* if I am just reading this block and we don't have | ||
1300 | a failed drive, or any pending writes then sidestep the cache */ | ||
1301 | if (sh->bh_read[i] && !sh->bh_read[i]->b_reqnext && | ||
1302 | ! syncing && !failed && !to_write) { | ||
1303 | sh->bh_cache[i]->b_page = sh->bh_read[i]->b_page; | ||
1304 | sh->bh_cache[i]->b_data = sh->bh_read[i]->b_data; | ||
1305 | } | ||
1306 | #endif | ||
1307 | locked++; | ||
1308 | PRINTK("Reading block %d (sync=%d)\n", | ||
1309 | i, syncing); | ||
1310 | } | ||
1311 | } | ||
1312 | } | ||
1313 | set_bit(STRIPE_HANDLE, &sh->state); | ||
1314 | } | ||
1315 | |||
1316 | /* now to consider writing and what else, if anything should be read */ | ||
1317 | if (to_write) { | ||
1318 | int rcw=0, must_compute=0; | ||
1319 | for (i=disks ; i--;) { | ||
1320 | dev = &sh->dev[i]; | ||
1321 | /* Would I have to read this buffer for reconstruct_write */ | ||
1322 | if (!test_bit(R5_OVERWRITE, &dev->flags) | ||
1323 | && i != pd_idx && i != qd_idx | ||
1324 | && (!test_bit(R5_LOCKED, &dev->flags) | ||
1325 | #if 0 | ||
1326 | || sh->bh_page[i] != bh->b_page | ||
1327 | #endif | ||
1328 | ) && | ||
1329 | !test_bit(R5_UPTODATE, &dev->flags)) { | ||
1330 | if (test_bit(R5_Insync, &dev->flags)) rcw++; | ||
1331 | else { | ||
1332 | PRINTK("raid6: must_compute: disk %d flags=%#lx\n", i, dev->flags); | ||
1333 | must_compute++; | ||
1334 | } | ||
1335 | } | ||
1336 | } | ||
1337 | PRINTK("for sector %llu, rcw=%d, must_compute=%d\n", | ||
1338 | (unsigned long long)sh->sector, rcw, must_compute); | ||
1339 | set_bit(STRIPE_HANDLE, &sh->state); | ||
1340 | |||
1341 | if (rcw > 0) | ||
1342 | /* want reconstruct write, but need to get some data */ | ||
1343 | for (i=disks; i--;) { | ||
1344 | dev = &sh->dev[i]; | ||
1345 | if (!test_bit(R5_OVERWRITE, &dev->flags) | ||
1346 | && !(failed == 0 && (i == pd_idx || i == qd_idx)) | ||
1347 | && !test_bit(R5_LOCKED, &dev->flags) && !test_bit(R5_UPTODATE, &dev->flags) && | ||
1348 | test_bit(R5_Insync, &dev->flags)) { | ||
1349 | if (test_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) | ||
1350 | { | ||
1351 | PRINTK("Read_old stripe %llu block %d for Reconstruct\n", | ||
1352 | (unsigned long long)sh->sector, i); | ||
1353 | set_bit(R5_LOCKED, &dev->flags); | ||
1354 | set_bit(R5_Wantread, &dev->flags); | ||
1355 | locked++; | ||
1356 | } else { | ||
1357 | PRINTK("Request delayed stripe %llu block %d for Reconstruct\n", | ||
1358 | (unsigned long long)sh->sector, i); | ||
1359 | set_bit(STRIPE_DELAYED, &sh->state); | ||
1360 | set_bit(STRIPE_HANDLE, &sh->state); | ||
1361 | } | ||
1362 | } | ||
1363 | } | ||
1364 | /* now if nothing is locked, and if we have enough data, we can start a write request */ | ||
1365 | if (locked == 0 && rcw == 0 && | ||
1366 | !test_bit(STRIPE_BIT_DELAY, &sh->state)) { | ||
1367 | if ( must_compute > 0 ) { | ||
1368 | /* We have failed blocks and need to compute them */ | ||
1369 | switch ( failed ) { | ||
1370 | case 0: BUG(); | ||
1371 | case 1: compute_block_1(sh, failed_num[0], 0); break; | ||
1372 | case 2: compute_block_2(sh, failed_num[0], failed_num[1]); break; | ||
1373 | default: BUG(); /* This request should have been failed? */ | ||
1374 | } | ||
1375 | } | ||
1376 | |||
1377 | PRINTK("Computing parity for stripe %llu\n", (unsigned long long)sh->sector); | ||
1378 | compute_parity(sh, RECONSTRUCT_WRITE); | ||
1379 | /* now every locked buffer is ready to be written */ | ||
1380 | for (i=disks; i--;) | ||
1381 | if (test_bit(R5_LOCKED, &sh->dev[i].flags)) { | ||
1382 | PRINTK("Writing stripe %llu block %d\n", | ||
1383 | (unsigned long long)sh->sector, i); | ||
1384 | locked++; | ||
1385 | set_bit(R5_Wantwrite, &sh->dev[i].flags); | ||
1386 | } | ||
1387 | /* after a RECONSTRUCT_WRITE, the stripe MUST be in-sync */ | ||
1388 | set_bit(STRIPE_INSYNC, &sh->state); | ||
1389 | |||
1390 | if (test_and_clear_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) { | ||
1391 | atomic_dec(&conf->preread_active_stripes); | ||
1392 | if (atomic_read(&conf->preread_active_stripes) < IO_THRESHOLD) | ||
1393 | md_wakeup_thread(conf->mddev->thread); | ||
1394 | } | ||
1395 | } | ||
1396 | } | ||
1397 | |||
1398 | /* maybe we need to check and possibly fix the parity for this stripe | ||
1399 | * Any reads will already have been scheduled, so we just see if enough data | ||
1400 | * is available | ||
1401 | */ | ||
1402 | if (syncing && locked == 0 && !test_bit(STRIPE_INSYNC, &sh->state)) { | ||
1403 | int update_p = 0, update_q = 0; | ||
1404 | struct r5dev *dev; | ||
1405 | |||
1406 | set_bit(STRIPE_HANDLE, &sh->state); | ||
1407 | |||
1408 | BUG_ON(failed>2); | ||
1409 | BUG_ON(uptodate < disks); | ||
1410 | /* Want to check and possibly repair P and Q. | ||
1411 | * However there could be one 'failed' device, in which | ||
1412 | * case we can only check one of them, possibly using the | ||
1413 | * other to generate missing data | ||
1414 | */ | ||
1415 | |||
1416 | /* If !tmp_page, we cannot do the calculations, | ||
1417 | * but as we have set STRIPE_HANDLE, we will soon be called | ||
1418 | * by stripe_handle with a tmp_page - just wait until then. | ||
1419 | */ | ||
1420 | if (tmp_page) { | ||
1421 | if (failed == q_failed) { | ||
1422 | /* The only possible failed device holds 'Q', so it makes | ||
1423 | * sense to check P (If anything else were failed, we would | ||
1424 | * have used P to recreate it). | ||
1425 | */ | ||
1426 | compute_block_1(sh, pd_idx, 1); | ||
1427 | if (!page_is_zero(sh->dev[pd_idx].page)) { | ||
1428 | compute_block_1(sh,pd_idx,0); | ||
1429 | update_p = 1; | ||
1430 | } | ||
1431 | } | ||
1432 | if (!q_failed && failed < 2) { | ||
1433 | /* q is not failed, and we didn't use it to generate | ||
1434 | * anything, so it makes sense to check it | ||
1435 | */ | ||
1436 | memcpy(page_address(tmp_page), | ||
1437 | page_address(sh->dev[qd_idx].page), | ||
1438 | STRIPE_SIZE); | ||
1439 | compute_parity(sh, UPDATE_PARITY); | ||
1440 | if (memcmp(page_address(tmp_page), | ||
1441 | page_address(sh->dev[qd_idx].page), | ||
1442 | STRIPE_SIZE)!= 0) { | ||
1443 | clear_bit(STRIPE_INSYNC, &sh->state); | ||
1444 | update_q = 1; | ||
1445 | } | ||
1446 | } | ||
1447 | if (update_p || update_q) { | ||
1448 | conf->mddev->resync_mismatches += STRIPE_SECTORS; | ||
1449 | if (test_bit(MD_RECOVERY_CHECK, &conf->mddev->recovery)) | ||
1450 | /* don't try to repair!! */ | ||
1451 | update_p = update_q = 0; | ||
1452 | } | ||
1453 | |||
1454 | /* now write out any block on a failed drive, | ||
1455 | * or P or Q if they need it | ||
1456 | */ | ||
1457 | |||
1458 | if (failed == 2) { | ||
1459 | dev = &sh->dev[failed_num[1]]; | ||
1460 | locked++; | ||
1461 | set_bit(R5_LOCKED, &dev->flags); | ||
1462 | set_bit(R5_Wantwrite, &dev->flags); | ||
1463 | } | ||
1464 | if (failed >= 1) { | ||
1465 | dev = &sh->dev[failed_num[0]]; | ||
1466 | locked++; | ||
1467 | set_bit(R5_LOCKED, &dev->flags); | ||
1468 | set_bit(R5_Wantwrite, &dev->flags); | ||
1469 | } | ||
1470 | |||
1471 | if (update_p) { | ||
1472 | dev = &sh->dev[pd_idx]; | ||
1473 | locked ++; | ||
1474 | set_bit(R5_LOCKED, &dev->flags); | ||
1475 | set_bit(R5_Wantwrite, &dev->flags); | ||
1476 | } | ||
1477 | if (update_q) { | ||
1478 | dev = &sh->dev[qd_idx]; | ||
1479 | locked++; | ||
1480 | set_bit(R5_LOCKED, &dev->flags); | ||
1481 | set_bit(R5_Wantwrite, &dev->flags); | ||
1482 | } | ||
1483 | clear_bit(STRIPE_DEGRADED, &sh->state); | ||
1484 | |||
1485 | set_bit(STRIPE_INSYNC, &sh->state); | ||
1486 | } | ||
1487 | } | ||
1488 | |||
1489 | if (syncing && locked == 0 && test_bit(STRIPE_INSYNC, &sh->state)) { | ||
1490 | md_done_sync(conf->mddev, STRIPE_SECTORS,1); | ||
1491 | clear_bit(STRIPE_SYNCING, &sh->state); | ||
1492 | } | ||
1493 | |||
1494 | /* If the failed drives are just a ReadError, then we might need | ||
1495 | * to progress the repair/check process | ||
1496 | */ | ||
1497 | if (failed <= 2 && ! conf->mddev->ro) | ||
1498 | for (i=0; i<failed;i++) { | ||
1499 | dev = &sh->dev[failed_num[i]]; | ||
1500 | if (test_bit(R5_ReadError, &dev->flags) | ||
1501 | && !test_bit(R5_LOCKED, &dev->flags) | ||
1502 | && test_bit(R5_UPTODATE, &dev->flags) | ||
1503 | ) { | ||
1504 | if (!test_bit(R5_ReWrite, &dev->flags)) { | ||
1505 | set_bit(R5_Wantwrite, &dev->flags); | ||
1506 | set_bit(R5_ReWrite, &dev->flags); | ||
1507 | set_bit(R5_LOCKED, &dev->flags); | ||
1508 | } else { | ||
1509 | /* let's read it back */ | ||
1510 | set_bit(R5_Wantread, &dev->flags); | ||
1511 | set_bit(R5_LOCKED, &dev->flags); | ||
1512 | } | ||
1513 | } | ||
1514 | } | ||
1515 | spin_unlock(&sh->lock); | ||
1516 | |||
1517 | while ((bi=return_bi)) { | ||
1518 | int bytes = bi->bi_size; | ||
1519 | |||
1520 | return_bi = bi->bi_next; | ||
1521 | bi->bi_next = NULL; | ||
1522 | bi->bi_size = 0; | ||
1523 | bi->bi_end_io(bi, bytes, 0); | ||
1524 | } | ||
1525 | for (i=disks; i-- ;) { | ||
1526 | int rw; | ||
1527 | struct bio *bi; | ||
1528 | mdk_rdev_t *rdev; | ||
1529 | if (test_and_clear_bit(R5_Wantwrite, &sh->dev[i].flags)) | ||
1530 | rw = 1; | ||
1531 | else if (test_and_clear_bit(R5_Wantread, &sh->dev[i].flags)) | ||
1532 | rw = 0; | ||
1533 | else | ||
1534 | continue; | ||
1535 | |||
1536 | bi = &sh->dev[i].req; | ||
1537 | |||
1538 | bi->bi_rw = rw; | ||
1539 | if (rw) | ||
1540 | bi->bi_end_io = raid6_end_write_request; | ||
1541 | else | ||
1542 | bi->bi_end_io = raid6_end_read_request; | ||
1543 | |||
1544 | rcu_read_lock(); | ||
1545 | rdev = rcu_dereference(conf->disks[i].rdev); | ||
1546 | if (rdev && test_bit(Faulty, &rdev->flags)) | ||
1547 | rdev = NULL; | ||
1548 | if (rdev) | ||
1549 | atomic_inc(&rdev->nr_pending); | ||
1550 | rcu_read_unlock(); | ||
1551 | |||
1552 | if (rdev) { | ||
1553 | if (syncing) | ||
1554 | md_sync_acct(rdev->bdev, STRIPE_SECTORS); | ||
1555 | |||
1556 | bi->bi_bdev = rdev->bdev; | ||
1557 | PRINTK("for %llu schedule op %ld on disc %d\n", | ||
1558 | (unsigned long long)sh->sector, bi->bi_rw, i); | ||
1559 | atomic_inc(&sh->count); | ||
1560 | bi->bi_sector = sh->sector + rdev->data_offset; | ||
1561 | bi->bi_flags = 1 << BIO_UPTODATE; | ||
1562 | bi->bi_vcnt = 1; | ||
1563 | bi->bi_max_vecs = 1; | ||
1564 | bi->bi_idx = 0; | ||
1565 | bi->bi_io_vec = &sh->dev[i].vec; | ||
1566 | bi->bi_io_vec[0].bv_len = STRIPE_SIZE; | ||
1567 | bi->bi_io_vec[0].bv_offset = 0; | ||
1568 | bi->bi_size = STRIPE_SIZE; | ||
1569 | bi->bi_next = NULL; | ||
1570 | if (rw == WRITE && | ||
1571 | test_bit(R5_ReWrite, &sh->dev[i].flags)) | ||
1572 | atomic_add(STRIPE_SECTORS, &rdev->corrected_errors); | ||
1573 | generic_make_request(bi); | ||
1574 | } else { | ||
1575 | if (rw == 1) | ||
1576 | set_bit(STRIPE_DEGRADED, &sh->state); | ||
1577 | PRINTK("skip op %ld on disc %d for sector %llu\n", | ||
1578 | bi->bi_rw, i, (unsigned long long)sh->sector); | ||
1579 | clear_bit(R5_LOCKED, &sh->dev[i].flags); | ||
1580 | set_bit(STRIPE_HANDLE, &sh->state); | ||
1581 | } | ||
1582 | } | ||
1583 | } | ||
1584 | |||
1585 | static void raid6_activate_delayed(raid6_conf_t *conf) | ||
1586 | { | ||
1587 | if (atomic_read(&conf->preread_active_stripes) < IO_THRESHOLD) { | ||
1588 | while (!list_empty(&conf->delayed_list)) { | ||
1589 | struct list_head *l = conf->delayed_list.next; | ||
1590 | struct stripe_head *sh; | ||
1591 | sh = list_entry(l, struct stripe_head, lru); | ||
1592 | list_del_init(l); | ||
1593 | clear_bit(STRIPE_DELAYED, &sh->state); | ||
1594 | if (!test_and_set_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) | ||
1595 | atomic_inc(&conf->preread_active_stripes); | ||
1596 | list_add_tail(&sh->lru, &conf->handle_list); | ||
1597 | } | ||
1598 | } | ||
1599 | } | ||
1600 | |||
1601 | static void activate_bit_delay(raid6_conf_t *conf) | ||
1602 | { | ||
1603 | /* device_lock is held */ | ||
1604 | struct list_head head; | ||
1605 | list_add(&head, &conf->bitmap_list); | ||
1606 | list_del_init(&conf->bitmap_list); | ||
1607 | while (!list_empty(&head)) { | ||
1608 | struct stripe_head *sh = list_entry(head.next, struct stripe_head, lru); | ||
1609 | list_del_init(&sh->lru); | ||
1610 | atomic_inc(&sh->count); | ||
1611 | __release_stripe(conf, sh); | ||
1612 | } | ||
1613 | } | ||
1614 | |||
1615 | static void unplug_slaves(mddev_t *mddev) | ||
1616 | { | ||
1617 | raid6_conf_t *conf = mddev_to_conf(mddev); | ||
1618 | int i; | ||
1619 | |||
1620 | rcu_read_lock(); | ||
1621 | for (i=0; i<mddev->raid_disks; i++) { | ||
1622 | mdk_rdev_t *rdev = rcu_dereference(conf->disks[i].rdev); | ||
1623 | if (rdev && !test_bit(Faulty, &rdev->flags) && atomic_read(&rdev->nr_pending)) { | ||
1624 | request_queue_t *r_queue = bdev_get_queue(rdev->bdev); | ||
1625 | |||
1626 | atomic_inc(&rdev->nr_pending); | ||
1627 | rcu_read_unlock(); | ||
1628 | |||
1629 | if (r_queue->unplug_fn) | ||
1630 | r_queue->unplug_fn(r_queue); | ||
1631 | |||
1632 | rdev_dec_pending(rdev, mddev); | ||
1633 | rcu_read_lock(); | ||
1634 | } | ||
1635 | } | ||
1636 | rcu_read_unlock(); | ||
1637 | } | ||
1638 | |||
1639 | static void raid6_unplug_device(request_queue_t *q) | ||
1640 | { | ||
1641 | mddev_t *mddev = q->queuedata; | ||
1642 | raid6_conf_t *conf = mddev_to_conf(mddev); | ||
1643 | unsigned long flags; | ||
1644 | |||
1645 | spin_lock_irqsave(&conf->device_lock, flags); | ||
1646 | |||
1647 | if (blk_remove_plug(q)) { | ||
1648 | conf->seq_flush++; | ||
1649 | raid6_activate_delayed(conf); | ||
1650 | } | ||
1651 | md_wakeup_thread(mddev->thread); | ||
1652 | |||
1653 | spin_unlock_irqrestore(&conf->device_lock, flags); | ||
1654 | |||
1655 | unplug_slaves(mddev); | ||
1656 | } | ||
1657 | |||
1658 | static int raid6_issue_flush(request_queue_t *q, struct gendisk *disk, | ||
1659 | sector_t *error_sector) | ||
1660 | { | ||
1661 | mddev_t *mddev = q->queuedata; | ||
1662 | raid6_conf_t *conf = mddev_to_conf(mddev); | ||
1663 | int i, ret = 0; | ||
1664 | |||
1665 | rcu_read_lock(); | ||
1666 | for (i=0; i<mddev->raid_disks && ret == 0; i++) { | ||
1667 | mdk_rdev_t *rdev = rcu_dereference(conf->disks[i].rdev); | ||
1668 | if (rdev && !test_bit(Faulty, &rdev->flags)) { | ||
1669 | struct block_device *bdev = rdev->bdev; | ||
1670 | request_queue_t *r_queue = bdev_get_queue(bdev); | ||
1671 | |||
1672 | if (!r_queue->issue_flush_fn) | ||
1673 | ret = -EOPNOTSUPP; | ||
1674 | else { | ||
1675 | atomic_inc(&rdev->nr_pending); | ||
1676 | rcu_read_unlock(); | ||
1677 | ret = r_queue->issue_flush_fn(r_queue, bdev->bd_disk, | ||
1678 | error_sector); | ||
1679 | rdev_dec_pending(rdev, mddev); | ||
1680 | rcu_read_lock(); | ||
1681 | } | ||
1682 | } | ||
1683 | } | ||
1684 | rcu_read_unlock(); | ||
1685 | return ret; | ||
1686 | } | ||
1687 | |||
1688 | static inline void raid6_plug_device(raid6_conf_t *conf) | ||
1689 | { | ||
1690 | spin_lock_irq(&conf->device_lock); | ||
1691 | blk_plug_device(conf->mddev->queue); | ||
1692 | spin_unlock_irq(&conf->device_lock); | ||
1693 | } | ||
1694 | |||
1695 | static int make_request (request_queue_t *q, struct bio * bi) | ||
1696 | { | ||
1697 | mddev_t *mddev = q->queuedata; | ||
1698 | raid6_conf_t *conf = mddev_to_conf(mddev); | ||
1699 | const unsigned int raid_disks = conf->raid_disks; | ||
1700 | const unsigned int data_disks = raid_disks - 2; | ||
1701 | unsigned int dd_idx, pd_idx; | ||
1702 | sector_t new_sector; | ||
1703 | sector_t logical_sector, last_sector; | ||
1704 | struct stripe_head *sh; | ||
1705 | const int rw = bio_data_dir(bi); | ||
1706 | |||
1707 | if (unlikely(bio_barrier(bi))) { | ||
1708 | bio_endio(bi, bi->bi_size, -EOPNOTSUPP); | ||
1709 | return 0; | ||
1710 | } | ||
1711 | |||
1712 | md_write_start(mddev, bi); | ||
1713 | |||
1714 | disk_stat_inc(mddev->gendisk, ios[rw]); | ||
1715 | disk_stat_add(mddev->gendisk, sectors[rw], bio_sectors(bi)); | ||
1716 | |||
1717 | logical_sector = bi->bi_sector & ~((sector_t)STRIPE_SECTORS-1); | ||
1718 | last_sector = bi->bi_sector + (bi->bi_size>>9); | ||
1719 | |||
1720 | bi->bi_next = NULL; | ||
1721 | bi->bi_phys_segments = 1; /* over-loaded to count active stripes */ | ||
1722 | |||
1723 | for (;logical_sector < last_sector; logical_sector += STRIPE_SECTORS) { | ||
1724 | DEFINE_WAIT(w); | ||
1725 | |||
1726 | new_sector = raid6_compute_sector(logical_sector, | ||
1727 | raid_disks, data_disks, &dd_idx, &pd_idx, conf); | ||
1728 | |||
1729 | PRINTK("raid6: make_request, sector %llu logical %llu\n", | ||
1730 | (unsigned long long)new_sector, | ||
1731 | (unsigned long long)logical_sector); | ||
1732 | |||
1733 | retry: | ||
1734 | prepare_to_wait(&conf->wait_for_overlap, &w, TASK_UNINTERRUPTIBLE); | ||
1735 | sh = get_active_stripe(conf, new_sector, pd_idx, (bi->bi_rw&RWA_MASK)); | ||
1736 | if (sh) { | ||
1737 | if (!add_stripe_bio(sh, bi, dd_idx, (bi->bi_rw&RW_MASK))) { | ||
1738 | /* Add failed due to overlap. Flush everything | ||
1739 | * and wait a while | ||
1740 | */ | ||
1741 | raid6_unplug_device(mddev->queue); | ||
1742 | release_stripe(sh); | ||
1743 | schedule(); | ||
1744 | goto retry; | ||
1745 | } | ||
1746 | finish_wait(&conf->wait_for_overlap, &w); | ||
1747 | raid6_plug_device(conf); | ||
1748 | handle_stripe(sh, NULL); | ||
1749 | release_stripe(sh); | ||
1750 | } else { | ||
1751 | /* cannot get stripe for read-ahead, just give-up */ | ||
1752 | clear_bit(BIO_UPTODATE, &bi->bi_flags); | ||
1753 | finish_wait(&conf->wait_for_overlap, &w); | ||
1754 | break; | ||
1755 | } | ||
1756 | |||
1757 | } | ||
1758 | spin_lock_irq(&conf->device_lock); | ||
1759 | if (--bi->bi_phys_segments == 0) { | ||
1760 | int bytes = bi->bi_size; | ||
1761 | |||
1762 | if (rw == WRITE ) | ||
1763 | md_write_end(mddev); | ||
1764 | bi->bi_size = 0; | ||
1765 | bi->bi_end_io(bi, bytes, 0); | ||
1766 | } | ||
1767 | spin_unlock_irq(&conf->device_lock); | ||
1768 | return 0; | ||
1769 | } | ||
1770 | |||
1771 | /* FIXME go_faster isn't used */ | ||
1772 | static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, int go_faster) | ||
1773 | { | ||
1774 | raid6_conf_t *conf = (raid6_conf_t *) mddev->private; | ||
1775 | struct stripe_head *sh; | ||
1776 | int sectors_per_chunk = conf->chunk_size >> 9; | ||
1777 | sector_t x; | ||
1778 | unsigned long stripe; | ||
1779 | int chunk_offset; | ||
1780 | int dd_idx, pd_idx; | ||
1781 | sector_t first_sector; | ||
1782 | int raid_disks = conf->raid_disks; | ||
1783 | int data_disks = raid_disks - 2; | ||
1784 | sector_t max_sector = mddev->size << 1; | ||
1785 | int sync_blocks; | ||
1786 | int still_degraded = 0; | ||
1787 | int i; | ||
1788 | |||
1789 | if (sector_nr >= max_sector) { | ||
1790 | /* just being told to finish up .. nothing much to do */ | ||
1791 | unplug_slaves(mddev); | ||
1792 | |||
1793 | if (mddev->curr_resync < max_sector) /* aborted */ | ||
1794 | bitmap_end_sync(mddev->bitmap, mddev->curr_resync, | ||
1795 | &sync_blocks, 1); | ||
1796 | else /* completed sync */ | ||
1797 | conf->fullsync = 0; | ||
1798 | bitmap_close_sync(mddev->bitmap); | ||
1799 | |||
1800 | return 0; | ||
1801 | } | ||
1802 | /* if there are 2 or more failed drives and we are trying | ||
1803 | * to resync, then assert that we are finished, because there is | ||
1804 | * nothing we can do. | ||
1805 | */ | ||
1806 | if (mddev->degraded >= 2 && test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) { | ||
1807 | sector_t rv = (mddev->size << 1) - sector_nr; | ||
1808 | *skipped = 1; | ||
1809 | return rv; | ||
1810 | } | ||
1811 | if (!bitmap_start_sync(mddev->bitmap, sector_nr, &sync_blocks, 1) && | ||
1812 | !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery) && | ||
1813 | !conf->fullsync && sync_blocks >= STRIPE_SECTORS) { | ||
1814 | /* we can skip this block, and probably more */ | ||
1815 | sync_blocks /= STRIPE_SECTORS; | ||
1816 | *skipped = 1; | ||
1817 | return sync_blocks * STRIPE_SECTORS; /* keep things rounded to whole stripes */ | ||
1818 | } | ||
1819 | |||
1820 | x = sector_nr; | ||
1821 | chunk_offset = sector_div(x, sectors_per_chunk); | ||
1822 | stripe = x; | ||
1823 | BUG_ON(x != stripe); | ||
1824 | |||
1825 | first_sector = raid6_compute_sector((sector_t)stripe*data_disks*sectors_per_chunk | ||
1826 | + chunk_offset, raid_disks, data_disks, &dd_idx, &pd_idx, conf); | ||
1827 | sh = get_active_stripe(conf, sector_nr, pd_idx, 1); | ||
1828 | if (sh == NULL) { | ||
1829 | sh = get_active_stripe(conf, sector_nr, pd_idx, 0); | ||
1830 | /* make sure we don't swamp the stripe cache if someone else | ||
1831 | * is trying to get access | ||
1832 | */ | ||
1833 | schedule_timeout_uninterruptible(1); | ||
1834 | } | ||
1835 | /* Need to check if array will still be degraded after recovery/resync | ||
1836 | * We don't need to check the 'failed' flag as when that gets set, | ||
1837 | * recovery aborts. | ||
1838 | */ | ||
1839 | for (i=0; i<mddev->raid_disks; i++) | ||
1840 | if (conf->disks[i].rdev == NULL) | ||
1841 | still_degraded = 1; | ||
1842 | |||
1843 | bitmap_start_sync(mddev->bitmap, sector_nr, &sync_blocks, still_degraded); | ||
1844 | |||
1845 | spin_lock(&sh->lock); | ||
1846 | set_bit(STRIPE_SYNCING, &sh->state); | ||
1847 | clear_bit(STRIPE_INSYNC, &sh->state); | ||
1848 | spin_unlock(&sh->lock); | ||
1849 | |||
1850 | handle_stripe(sh, NULL); | ||
1851 | release_stripe(sh); | ||
1852 | |||
1853 | return STRIPE_SECTORS; | ||
1854 | } | ||
1855 | |||
1856 | /* | ||
1857 | * This is our raid6 kernel thread. | ||
1858 | * | ||
1859 | * We scan the hash table for stripes which can be handled now. | ||
1860 | * During the scan, completed stripes are saved for us by the interrupt | ||
1861 | * handler, so that they will not have to wait for our next wakeup. | ||
1862 | */ | ||
1863 | static void raid6d (mddev_t *mddev) | ||
1864 | { | ||
1865 | struct stripe_head *sh; | ||
1866 | raid6_conf_t *conf = mddev_to_conf(mddev); | ||
1867 | int handled; | ||
1868 | |||
1869 | PRINTK("+++ raid6d active\n"); | ||
1870 | |||
1871 | md_check_recovery(mddev); | ||
1872 | |||
1873 | handled = 0; | ||
1874 | spin_lock_irq(&conf->device_lock); | ||
1875 | while (1) { | ||
1876 | struct list_head *first; | ||
1877 | |||
1878 | if (conf->seq_flush - conf->seq_write > 0) { | ||
1879 | int seq = conf->seq_flush; | ||
1880 | spin_unlock_irq(&conf->device_lock); | ||
1881 | bitmap_unplug(mddev->bitmap); | ||
1882 | spin_lock_irq(&conf->device_lock); | ||
1883 | conf->seq_write = seq; | ||
1884 | activate_bit_delay(conf); | ||
1885 | } | ||
1886 | |||
1887 | if (list_empty(&conf->handle_list) && | ||
1888 | atomic_read(&conf->preread_active_stripes) < IO_THRESHOLD && | ||
1889 | !blk_queue_plugged(mddev->queue) && | ||
1890 | !list_empty(&conf->delayed_list)) | ||
1891 | raid6_activate_delayed(conf); | ||
1892 | |||
1893 | if (list_empty(&conf->handle_list)) | ||
1894 | break; | ||
1895 | |||
1896 | first = conf->handle_list.next; | ||
1897 | sh = list_entry(first, struct stripe_head, lru); | ||
1898 | |||
1899 | list_del_init(first); | ||
1900 | atomic_inc(&sh->count); | ||
1901 | BUG_ON(atomic_read(&sh->count)!= 1); | ||
1902 | spin_unlock_irq(&conf->device_lock); | ||
1903 | |||
1904 | handled++; | ||
1905 | handle_stripe(sh, conf->spare_page); | ||
1906 | release_stripe(sh); | ||
1907 | |||
1908 | spin_lock_irq(&conf->device_lock); | ||
1909 | } | ||
1910 | PRINTK("%d stripes handled\n", handled); | ||
1911 | |||
1912 | spin_unlock_irq(&conf->device_lock); | ||
1913 | |||
1914 | unplug_slaves(mddev); | ||
1915 | |||
1916 | PRINTK("--- raid6d inactive\n"); | ||
1917 | } | ||
1918 | |||
1919 | static ssize_t | ||
1920 | raid6_show_stripe_cache_size(mddev_t *mddev, char *page) | ||
1921 | { | ||
1922 | raid6_conf_t *conf = mddev_to_conf(mddev); | ||
1923 | if (conf) | ||
1924 | return sprintf(page, "%d\n", conf->max_nr_stripes); | ||
1925 | else | ||
1926 | return 0; | ||
1927 | } | ||
1928 | |||
1929 | static ssize_t | ||
1930 | raid6_store_stripe_cache_size(mddev_t *mddev, const char *page, size_t len) | ||
1931 | { | ||
1932 | raid6_conf_t *conf = mddev_to_conf(mddev); | ||
1933 | char *end; | ||
1934 | int new; | ||
1935 | if (len >= PAGE_SIZE) | ||
1936 | return -EINVAL; | ||
1937 | if (!conf) | ||
1938 | return -ENODEV; | ||
1939 | |||
1940 | new = simple_strtoul(page, &end, 10); | ||
1941 | if (!*page || (*end && *end != '\n') ) | ||
1942 | return -EINVAL; | ||
1943 | if (new <= 16 || new > 32768) | ||
1944 | return -EINVAL; | ||
1945 | while (new < conf->max_nr_stripes) { | ||
1946 | if (drop_one_stripe(conf)) | ||
1947 | conf->max_nr_stripes--; | ||
1948 | else | ||
1949 | break; | ||
1950 | } | ||
1951 | while (new > conf->max_nr_stripes) { | ||
1952 | if (grow_one_stripe(conf)) | ||
1953 | conf->max_nr_stripes++; | ||
1954 | else break; | ||
1955 | } | ||
1956 | return len; | ||
1957 | } | ||
1958 | |||
1959 | static struct md_sysfs_entry | ||
1960 | raid6_stripecache_size = __ATTR(stripe_cache_size, S_IRUGO | S_IWUSR, | ||
1961 | raid6_show_stripe_cache_size, | ||
1962 | raid6_store_stripe_cache_size); | ||
1963 | |||
1964 | static ssize_t | ||
1965 | stripe_cache_active_show(mddev_t *mddev, char *page) | ||
1966 | { | ||
1967 | raid6_conf_t *conf = mddev_to_conf(mddev); | ||
1968 | if (conf) | ||
1969 | return sprintf(page, "%d\n", atomic_read(&conf->active_stripes)); | ||
1970 | else | ||
1971 | return 0; | ||
1972 | } | ||
1973 | |||
1974 | static struct md_sysfs_entry | ||
1975 | raid6_stripecache_active = __ATTR_RO(stripe_cache_active); | ||
1976 | |||
1977 | static struct attribute *raid6_attrs[] = { | ||
1978 | &raid6_stripecache_size.attr, | ||
1979 | &raid6_stripecache_active.attr, | ||
1980 | NULL, | ||
1981 | }; | ||
1982 | static struct attribute_group raid6_attrs_group = { | ||
1983 | .name = NULL, | ||
1984 | .attrs = raid6_attrs, | ||
1985 | }; | ||
1986 | |||
1987 | static int run(mddev_t *mddev) | ||
1988 | { | ||
1989 | raid6_conf_t *conf; | ||
1990 | int raid_disk, memory; | ||
1991 | mdk_rdev_t *rdev; | ||
1992 | struct disk_info *disk; | ||
1993 | struct list_head *tmp; | ||
1994 | |||
1995 | if (mddev->level != 6) { | ||
1996 | PRINTK("raid6: %s: raid level not set to 6 (%d)\n", mdname(mddev), mddev->level); | ||
1997 | return -EIO; | ||
1998 | } | ||
1999 | |||
2000 | mddev->private = kzalloc(sizeof (raid6_conf_t), GFP_KERNEL); | ||
2001 | if ((conf = mddev->private) == NULL) | ||
2002 | goto abort; | ||
2003 | conf->disks = kzalloc(mddev->raid_disks * sizeof(struct disk_info), | ||
2004 | GFP_KERNEL); | ||
2005 | if (!conf->disks) | ||
2006 | goto abort; | ||
2007 | |||
2008 | conf->mddev = mddev; | ||
2009 | |||
2010 | if ((conf->stripe_hashtbl = kzalloc(PAGE_SIZE, GFP_KERNEL)) == NULL) | ||
2011 | goto abort; | ||
2012 | |||
2013 | conf->spare_page = alloc_page(GFP_KERNEL); | ||
2014 | if (!conf->spare_page) | ||
2015 | goto abort; | ||
2016 | |||
2017 | spin_lock_init(&conf->device_lock); | ||
2018 | init_waitqueue_head(&conf->wait_for_stripe); | ||
2019 | init_waitqueue_head(&conf->wait_for_overlap); | ||
2020 | INIT_LIST_HEAD(&conf->handle_list); | ||
2021 | INIT_LIST_HEAD(&conf->delayed_list); | ||
2022 | INIT_LIST_HEAD(&conf->bitmap_list); | ||
2023 | INIT_LIST_HEAD(&conf->inactive_list); | ||
2024 | atomic_set(&conf->active_stripes, 0); | ||
2025 | atomic_set(&conf->preread_active_stripes, 0); | ||
2026 | |||
2027 | PRINTK("raid6: run(%s) called.\n", mdname(mddev)); | ||
2028 | |||
2029 | ITERATE_RDEV(mddev,rdev,tmp) { | ||
2030 | raid_disk = rdev->raid_disk; | ||
2031 | if (raid_disk >= mddev->raid_disks | ||
2032 | || raid_disk < 0) | ||
2033 | continue; | ||
2034 | disk = conf->disks + raid_disk; | ||
2035 | |||
2036 | disk->rdev = rdev; | ||
2037 | |||
2038 | if (test_bit(In_sync, &rdev->flags)) { | ||
2039 | char b[BDEVNAME_SIZE]; | ||
2040 | printk(KERN_INFO "raid6: device %s operational as raid" | ||
2041 | " disk %d\n", bdevname(rdev->bdev,b), | ||
2042 | raid_disk); | ||
2043 | conf->working_disks++; | ||
2044 | } | ||
2045 | } | ||
2046 | |||
2047 | conf->raid_disks = mddev->raid_disks; | ||
2048 | |||
2049 | /* | ||
2050 | * 0 for a fully functional array, 1 or 2 for a degraded array. | ||
2051 | */ | ||
2052 | mddev->degraded = conf->failed_disks = conf->raid_disks - conf->working_disks; | ||
2053 | conf->mddev = mddev; | ||
2054 | conf->chunk_size = mddev->chunk_size; | ||
2055 | conf->level = mddev->level; | ||
2056 | conf->algorithm = mddev->layout; | ||
2057 | conf->max_nr_stripes = NR_STRIPES; | ||
2058 | |||
2059 | /* device size must be a multiple of chunk size */ | ||
2060 | mddev->size &= ~(mddev->chunk_size/1024 -1); | ||
2061 | mddev->resync_max_sectors = mddev->size << 1; | ||
2062 | |||
2063 | if (conf->raid_disks < 4) { | ||
2064 | printk(KERN_ERR "raid6: not enough configured devices for %s (%d, minimum 4)\n", | ||
2065 | mdname(mddev), conf->raid_disks); | ||
2066 | goto abort; | ||
2067 | } | ||
2068 | if (!conf->chunk_size || conf->chunk_size % 4) { | ||
2069 | printk(KERN_ERR "raid6: invalid chunk size %d for %s\n", | ||
2070 | conf->chunk_size, mdname(mddev)); | ||
2071 | goto abort; | ||
2072 | } | ||
2073 | if (conf->algorithm > ALGORITHM_RIGHT_SYMMETRIC) { | ||
2074 | printk(KERN_ERR | ||
2075 | "raid6: unsupported parity algorithm %d for %s\n", | ||
2076 | conf->algorithm, mdname(mddev)); | ||
2077 | goto abort; | ||
2078 | } | ||
2079 | if (mddev->degraded > 2) { | ||
2080 | printk(KERN_ERR "raid6: not enough operational devices for %s" | ||
2081 | " (%d/%d failed)\n", | ||
2082 | mdname(mddev), conf->failed_disks, conf->raid_disks); | ||
2083 | goto abort; | ||
2084 | } | ||
2085 | |||
2086 | if (mddev->degraded > 0 && | ||
2087 | mddev->recovery_cp != MaxSector) { | ||
2088 | if (mddev->ok_start_degraded) | ||
2089 | printk(KERN_WARNING "raid6: starting dirty degraded array:%s" | ||
2090 | "- data corruption possible.\n", | ||
2091 | mdname(mddev)); | ||
2092 | else { | ||
2093 | printk(KERN_ERR "raid6: cannot start dirty degraded array" | ||
2094 | " for %s\n", mdname(mddev)); | ||
2095 | goto abort; | ||
2096 | } | ||
2097 | } | ||
2098 | |||
2099 | { | ||
2100 | mddev->thread = md_register_thread(raid6d, mddev, "%s_raid6"); | ||
2101 | if (!mddev->thread) { | ||
2102 | printk(KERN_ERR | ||
2103 | "raid6: couldn't allocate thread for %s\n", | ||
2104 | mdname(mddev)); | ||
2105 | goto abort; | ||
2106 | } | ||
2107 | } | ||
2108 | |||
2109 | memory = conf->max_nr_stripes * (sizeof(struct stripe_head) + | ||
2110 | conf->raid_disks * ((sizeof(struct bio) + PAGE_SIZE))) / 1024; | ||
2111 | if (grow_stripes(conf, conf->max_nr_stripes)) { | ||
2112 | printk(KERN_ERR | ||
2113 | "raid6: couldn't allocate %dkB for buffers\n", memory); | ||
2114 | shrink_stripes(conf); | ||
2115 | md_unregister_thread(mddev->thread); | ||
2116 | goto abort; | ||
2117 | } else | ||
2118 | printk(KERN_INFO "raid6: allocated %dkB for %s\n", | ||
2119 | memory, mdname(mddev)); | ||
2120 | |||
2121 | if (mddev->degraded == 0) | ||
2122 | printk(KERN_INFO "raid6: raid level %d set %s active with %d out of %d" | ||
2123 | " devices, algorithm %d\n", conf->level, mdname(mddev), | ||
2124 | mddev->raid_disks-mddev->degraded, mddev->raid_disks, | ||
2125 | conf->algorithm); | ||
2126 | else | ||
2127 | printk(KERN_ALERT "raid6: raid level %d set %s active with %d" | ||
2128 | " out of %d devices, algorithm %d\n", conf->level, | ||
2129 | mdname(mddev), mddev->raid_disks - mddev->degraded, | ||
2130 | mddev->raid_disks, conf->algorithm); | ||
2131 | |||
2132 | print_raid6_conf(conf); | ||
2133 | |||
2134 | /* read-ahead size must cover two whole stripes, which is | ||
2135 | * 2 * (n-2) * chunksize where 'n' is the number of raid devices | ||
2136 | */ | ||
2137 | { | ||
2138 | int stripe = (mddev->raid_disks-2) * mddev->chunk_size | ||
2139 | / PAGE_SIZE; | ||
2140 | if (mddev->queue->backing_dev_info.ra_pages < 2 * stripe) | ||
2141 | mddev->queue->backing_dev_info.ra_pages = 2 * stripe; | ||
2142 | } | ||
2143 | |||
2144 | /* Ok, everything is just fine now */ | ||
2145 | sysfs_create_group(&mddev->kobj, &raid6_attrs_group); | ||
2146 | |||
2147 | mddev->array_size = mddev->size * (mddev->raid_disks - 2); | ||
2148 | |||
2149 | mddev->queue->unplug_fn = raid6_unplug_device; | ||
2150 | mddev->queue->issue_flush_fn = raid6_issue_flush; | ||
2151 | return 0; | ||
2152 | abort: | ||
2153 | if (conf) { | ||
2154 | print_raid6_conf(conf); | ||
2155 | safe_put_page(conf->spare_page); | ||
2156 | kfree(conf->stripe_hashtbl); | ||
2157 | kfree(conf->disks); | ||
2158 | kfree(conf); | ||
2159 | } | ||
2160 | mddev->private = NULL; | ||
2161 | printk(KERN_ALERT "raid6: failed to run raid set %s\n", mdname(mddev)); | ||
2162 | return -EIO; | ||
2163 | } | ||
2164 | |||
2165 | |||
2166 | |||
2167 | static int stop (mddev_t *mddev) | ||
2168 | { | ||
2169 | raid6_conf_t *conf = (raid6_conf_t *) mddev->private; | ||
2170 | |||
2171 | md_unregister_thread(mddev->thread); | ||
2172 | mddev->thread = NULL; | ||
2173 | shrink_stripes(conf); | ||
2174 | kfree(conf->stripe_hashtbl); | ||
2175 | blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/ | ||
2176 | sysfs_remove_group(&mddev->kobj, &raid6_attrs_group); | ||
2177 | kfree(conf); | ||
2178 | mddev->private = NULL; | ||
2179 | return 0; | ||
2180 | } | ||
2181 | |||
2182 | #if RAID6_DUMPSTATE | ||
2183 | static void print_sh (struct seq_file *seq, struct stripe_head *sh) | ||
2184 | { | ||
2185 | int i; | ||
2186 | |||
2187 | seq_printf(seq, "sh %llu, pd_idx %d, state %ld.\n", | ||
2188 | (unsigned long long)sh->sector, sh->pd_idx, sh->state); | ||
2189 | seq_printf(seq, "sh %llu, count %d.\n", | ||
2190 | (unsigned long long)sh->sector, atomic_read(&sh->count)); | ||
2191 | seq_printf(seq, "sh %llu, ", (unsigned long long)sh->sector); | ||
2192 | for (i = 0; i < sh->raid_conf->raid_disks; i++) { | ||
2193 | seq_printf(seq, "(cache%d: %p %ld) ", | ||
2194 | i, sh->dev[i].page, sh->dev[i].flags); | ||
2195 | } | ||
2196 | seq_printf(seq, "\n"); | ||
2197 | } | ||
2198 | |||
2199 | static void printall (struct seq_file *seq, raid6_conf_t *conf) | ||
2200 | { | ||
2201 | struct stripe_head *sh; | ||
2202 | struct hlist_node *hn; | ||
2203 | int i; | ||
2204 | |||
2205 | spin_lock_irq(&conf->device_lock); | ||
2206 | for (i = 0; i < NR_HASH; i++) { | ||
2207 | sh = conf->stripe_hashtbl[i]; | ||
2208 | hlist_for_each_entry(sh, hn, &conf->stripe_hashtbl[i], hash) { | ||
2209 | if (sh->raid_conf != conf) | ||
2210 | continue; | ||
2211 | print_sh(seq, sh); | ||
2212 | } | ||
2213 | } | ||
2214 | spin_unlock_irq(&conf->device_lock); | ||
2215 | } | ||
2216 | #endif | ||
2217 | |||
2218 | static void status (struct seq_file *seq, mddev_t *mddev) | ||
2219 | { | ||
2220 | raid6_conf_t *conf = (raid6_conf_t *) mddev->private; | ||
2221 | int i; | ||
2222 | |||
2223 | seq_printf (seq, " level %d, %dk chunk, algorithm %d", mddev->level, mddev->chunk_size >> 10, mddev->layout); | ||
2224 | seq_printf (seq, " [%d/%d] [", conf->raid_disks, conf->working_disks); | ||
2225 | for (i = 0; i < conf->raid_disks; i++) | ||
2226 | seq_printf (seq, "%s", | ||
2227 | conf->disks[i].rdev && | ||
2228 | test_bit(In_sync, &conf->disks[i].rdev->flags) ? "U" : "_"); | ||
2229 | seq_printf (seq, "]"); | ||
2230 | #if RAID6_DUMPSTATE | ||
2231 | seq_printf (seq, "\n"); | ||
2232 | printall(seq, conf); | ||
2233 | #endif | ||
2234 | } | ||
2235 | |||
2236 | static void print_raid6_conf (raid6_conf_t *conf) | ||
2237 | { | ||
2238 | int i; | ||
2239 | struct disk_info *tmp; | ||
2240 | |||
2241 | printk("RAID6 conf printout:\n"); | ||
2242 | if (!conf) { | ||
2243 | printk("(conf==NULL)\n"); | ||
2244 | return; | ||
2245 | } | ||
2246 | printk(" --- rd:%d wd:%d fd:%d\n", conf->raid_disks, | ||
2247 | conf->working_disks, conf->failed_disks); | ||
2248 | |||
2249 | for (i = 0; i < conf->raid_disks; i++) { | ||
2250 | char b[BDEVNAME_SIZE]; | ||
2251 | tmp = conf->disks + i; | ||
2252 | if (tmp->rdev) | ||
2253 | printk(" disk %d, o:%d, dev:%s\n", | ||
2254 | i, !test_bit(Faulty, &tmp->rdev->flags), | ||
2255 | bdevname(tmp->rdev->bdev,b)); | ||
2256 | } | ||
2257 | } | ||
2258 | |||
2259 | static int raid6_spare_active(mddev_t *mddev) | ||
2260 | { | ||
2261 | int i; | ||
2262 | raid6_conf_t *conf = mddev->private; | ||
2263 | struct disk_info *tmp; | ||
2264 | |||
2265 | for (i = 0; i < conf->raid_disks; i++) { | ||
2266 | tmp = conf->disks + i; | ||
2267 | if (tmp->rdev | ||
2268 | && !test_bit(Faulty, &tmp->rdev->flags) | ||
2269 | && !test_bit(In_sync, &tmp->rdev->flags)) { | ||
2270 | mddev->degraded--; | ||
2271 | conf->failed_disks--; | ||
2272 | conf->working_disks++; | ||
2273 | set_bit(In_sync, &tmp->rdev->flags); | ||
2274 | } | ||
2275 | } | ||
2276 | print_raid6_conf(conf); | ||
2277 | return 0; | ||
2278 | } | ||
2279 | |||
2280 | static int raid6_remove_disk(mddev_t *mddev, int number) | ||
2281 | { | ||
2282 | raid6_conf_t *conf = mddev->private; | ||
2283 | int err = 0; | ||
2284 | mdk_rdev_t *rdev; | ||
2285 | struct disk_info *p = conf->disks + number; | ||
2286 | |||
2287 | print_raid6_conf(conf); | ||
2288 | rdev = p->rdev; | ||
2289 | if (rdev) { | ||
2290 | if (test_bit(In_sync, &rdev->flags) || | ||
2291 | atomic_read(&rdev->nr_pending)) { | ||
2292 | err = -EBUSY; | ||
2293 | goto abort; | ||
2294 | } | ||
2295 | p->rdev = NULL; | ||
2296 | synchronize_rcu(); | ||
2297 | if (atomic_read(&rdev->nr_pending)) { | ||
2298 | /* lost the race, try later */ | ||
2299 | err = -EBUSY; | ||
2300 | p->rdev = rdev; | ||
2301 | } | ||
2302 | } | ||
2303 | |||
2304 | abort: | ||
2305 | |||
2306 | print_raid6_conf(conf); | ||
2307 | return err; | ||
2308 | } | ||
2309 | |||
2310 | static int raid6_add_disk(mddev_t *mddev, mdk_rdev_t *rdev) | ||
2311 | { | ||
2312 | raid6_conf_t *conf = mddev->private; | ||
2313 | int found = 0; | ||
2314 | int disk; | ||
2315 | struct disk_info *p; | ||
2316 | |||
2317 | if (mddev->degraded > 2) | ||
2318 | /* no point adding a device */ | ||
2319 | return 0; | ||
2320 | /* | ||
2321 | * find the disk ... but prefer rdev->saved_raid_disk | ||
2322 | * if possible. | ||
2323 | */ | ||
2324 | if (rdev->saved_raid_disk >= 0 && | ||
2325 | conf->disks[rdev->saved_raid_disk].rdev == NULL) | ||
2326 | disk = rdev->saved_raid_disk; | ||
2327 | else | ||
2328 | disk = 0; | ||
2329 | for ( ; disk < mddev->raid_disks; disk++) | ||
2330 | if ((p=conf->disks + disk)->rdev == NULL) { | ||
2331 | clear_bit(In_sync, &rdev->flags); | ||
2332 | rdev->raid_disk = disk; | ||
2333 | found = 1; | ||
2334 | if (rdev->saved_raid_disk != disk) | ||
2335 | conf->fullsync = 1; | ||
2336 | rcu_assign_pointer(p->rdev, rdev); | ||
2337 | break; | ||
2338 | } | ||
2339 | print_raid6_conf(conf); | ||
2340 | return found; | ||
2341 | } | ||
2342 | |||
2343 | static int raid6_resize(mddev_t *mddev, sector_t sectors) | ||
2344 | { | ||
2345 | /* no resync is happening, and there is enough space | ||
2346 | * on all devices, so we can resize. | ||
2347 | * We need to make sure resync covers any new space. | ||
2348 | * If the array is shrinking we should possibly wait until | ||
2349 | * any io in the removed space completes, but it hardly seems | ||
2350 | * worth it. | ||
2351 | */ | ||
2352 | sectors &= ~((sector_t)mddev->chunk_size/512 - 1); | ||
2353 | mddev->array_size = (sectors * (mddev->raid_disks-2))>>1; | ||
2354 | set_capacity(mddev->gendisk, mddev->array_size << 1); | ||
2355 | mddev->changed = 1; | ||
2356 | if (sectors/2 > mddev->size && mddev->recovery_cp == MaxSector) { | ||
2357 | mddev->recovery_cp = mddev->size << 1; | ||
2358 | set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); | ||
2359 | } | ||
2360 | mddev->size = sectors /2; | ||
2361 | mddev->resync_max_sectors = sectors; | ||
2362 | return 0; | ||
2363 | } | ||
2364 | |||
2365 | static void raid6_quiesce(mddev_t *mddev, int state) | ||
2366 | { | ||
2367 | raid6_conf_t *conf = mddev_to_conf(mddev); | ||
2368 | |||
2369 | switch(state) { | ||
2370 | case 1: /* stop all writes */ | ||
2371 | spin_lock_irq(&conf->device_lock); | ||
2372 | conf->quiesce = 1; | ||
2373 | wait_event_lock_irq(conf->wait_for_stripe, | ||
2374 | atomic_read(&conf->active_stripes) == 0, | ||
2375 | conf->device_lock, /* nothing */); | ||
2376 | spin_unlock_irq(&conf->device_lock); | ||
2377 | break; | ||
2378 | |||
2379 | case 0: /* re-enable writes */ | ||
2380 | spin_lock_irq(&conf->device_lock); | ||
2381 | conf->quiesce = 0; | ||
2382 | wake_up(&conf->wait_for_stripe); | ||
2383 | spin_unlock_irq(&conf->device_lock); | ||
2384 | break; | ||
2385 | } | ||
2386 | } | ||
2387 | |||
2388 | static struct mdk_personality raid6_personality = | ||
2389 | { | ||
2390 | .name = "raid6", | ||
2391 | .level = 6, | ||
2392 | .owner = THIS_MODULE, | ||
2393 | .make_request = make_request, | ||
2394 | .run = run, | ||
2395 | .stop = stop, | ||
2396 | .status = status, | ||
2397 | .error_handler = error, | ||
2398 | .hot_add_disk = raid6_add_disk, | ||
2399 | .hot_remove_disk= raid6_remove_disk, | ||
2400 | .spare_active = raid6_spare_active, | ||
2401 | .sync_request = sync_request, | ||
2402 | .resize = raid6_resize, | ||
2403 | .quiesce = raid6_quiesce, | ||
2404 | }; | ||
2405 | |||
2406 | static int __init raid6_init(void) | ||
2407 | { | ||
2408 | int e; | ||
2409 | |||
2410 | e = raid6_select_algo(); | ||
2411 | if ( e ) | ||
2412 | return e; | ||
2413 | |||
2414 | return register_md_personality(&raid6_personality); | ||
2415 | } | ||
2416 | |||
2417 | static void raid6_exit (void) | ||
2418 | { | ||
2419 | unregister_md_personality(&raid6_personality); | ||
2420 | } | ||
2421 | |||
2422 | module_init(raid6_init); | ||
2423 | module_exit(raid6_exit); | ||
2424 | MODULE_LICENSE("GPL"); | ||
2425 | MODULE_ALIAS("md-personality-8"); /* RAID6 */ | ||
2426 | MODULE_ALIAS("md-raid6"); | ||
2427 | MODULE_ALIAS("md-level-6"); | ||
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 583d151b7486..ef52e6da01ed 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig | |||
@@ -82,9 +82,6 @@ config VIDEO_IR | |||
82 | config VIDEO_TVEEPROM | 82 | config VIDEO_TVEEPROM |
83 | tristate | 83 | tristate |
84 | 84 | ||
85 | config VIDEO_CX2341X | ||
86 | tristate | ||
87 | |||
88 | config USB_DABUSB | 85 | config USB_DABUSB |
89 | tristate "DABUSB driver" | 86 | tristate "DABUSB driver" |
90 | depends on USB | 87 | depends on USB |
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 3152a54a2539..5e8bb41a088b 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c | |||
@@ -556,22 +556,23 @@ static int dvb_frontend_thread(void *data) | |||
556 | } | 556 | } |
557 | 557 | ||
558 | /* do an iteration of the tuning loop */ | 558 | /* do an iteration of the tuning loop */ |
559 | if (fe->ops.get_frontend_algo(fe) == FE_ALGO_HW) { | 559 | if (fe->ops.get_frontend_algo) { |
560 | /* have we been asked to retune? */ | 560 | if (fe->ops.get_frontend_algo(fe) == FE_ALGO_HW) { |
561 | params = NULL; | 561 | /* have we been asked to retune? */ |
562 | if (fepriv->state & FESTATE_RETUNE) { | 562 | params = NULL; |
563 | params = &fepriv->parameters; | 563 | if (fepriv->state & FESTATE_RETUNE) { |
564 | fepriv->state = FESTATE_TUNED; | 564 | params = &fepriv->parameters; |
565 | } | 565 | fepriv->state = FESTATE_TUNED; |
566 | } | ||
566 | 567 | ||
567 | fe->ops.tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s); | 568 | fe->ops.tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s); |
568 | if (s != fepriv->status) { | 569 | if (s != fepriv->status) { |
569 | dvb_frontend_add_event(fe, s); | 570 | dvb_frontend_add_event(fe, s); |
570 | fepriv->status = s; | 571 | fepriv->status = s; |
572 | } | ||
571 | } | 573 | } |
572 | } else { | 574 | } else |
573 | dvb_frontend_swzigzag(fe); | 575 | dvb_frontend_swzigzag(fe); |
574 | } | ||
575 | } | 576 | } |
576 | 577 | ||
577 | if (dvb_shutdown_timeout) { | 578 | if (dvb_shutdown_timeout) { |
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index 8832f80c05f7..7a5c99c200e8 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c | |||
@@ -152,13 +152,9 @@ static void init_av7110_av(struct av7110 *av7110) | |||
152 | /* remaining inits according to card and frontend type */ | 152 | /* remaining inits according to card and frontend type */ |
153 | av7110->analog_tuner_flags = 0; | 153 | av7110->analog_tuner_flags = 0; |
154 | av7110->current_input = 0; | 154 | av7110->current_input = 0; |
155 | if (dev->pci->subsystem_vendor == 0x13c2 && dev->pci->subsystem_device == 0x000a) { | 155 | if (dev->pci->subsystem_vendor == 0x13c2 && dev->pci->subsystem_device == 0x000a) |
156 | printk("dvb-ttpci: MSP3415 audio DAC @ card %d\n", | ||
157 | av7110->dvb_adapter.num); | ||
158 | av7110->adac_type = DVB_ADAC_MSP34x5; | ||
159 | av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, 0); // SPDIF on | 156 | av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, 0); // SPDIF on |
160 | } | 157 | if (i2c_writereg(av7110, 0x20, 0x00, 0x00) == 1) { |
161 | else if (i2c_writereg(av7110, 0x20, 0x00, 0x00) == 1) { | ||
162 | printk ("dvb-ttpci: Crystal audio DAC @ card %d detected\n", | 158 | printk ("dvb-ttpci: Crystal audio DAC @ card %d detected\n", |
163 | av7110->dvb_adapter.num); | 159 | av7110->dvb_adapter.num); |
164 | av7110->adac_type = DVB_ADAC_CRYSTAL; | 160 | av7110->adac_type = DVB_ADAC_CRYSTAL; |
diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c index 2eff09f638d3..0f3a044aeb17 100644 --- a/drivers/media/dvb/ttpci/av7110_av.c +++ b/drivers/media/dvb/ttpci/av7110_av.c | |||
@@ -318,7 +318,17 @@ int av7110_set_volume(struct av7110 *av7110, int volleft, int volright) | |||
318 | msp_writereg(av7110, MSP_WR_DSP, 0x0000, val); /* loudspeaker */ | 318 | msp_writereg(av7110, MSP_WR_DSP, 0x0000, val); /* loudspeaker */ |
319 | msp_writereg(av7110, MSP_WR_DSP, 0x0006, val); /* headphonesr */ | 319 | msp_writereg(av7110, MSP_WR_DSP, 0x0006, val); /* headphonesr */ |
320 | return 0; | 320 | return 0; |
321 | |||
322 | case DVB_ADAC_MSP34x5: | ||
323 | vol = (volleft > volright) ? volleft : volright; | ||
324 | val = (vol * 0x73 / 255) << 8; | ||
325 | if (vol > 0) | ||
326 | balance = ((volright - volleft) * 127) / vol; | ||
327 | msp_writereg(av7110, MSP_WR_DSP, 0x0001, balance << 8); | ||
328 | msp_writereg(av7110, MSP_WR_DSP, 0x0000, val); /* loudspeaker */ | ||
329 | return 0; | ||
321 | } | 330 | } |
331 | |||
322 | return 0; | 332 | return 0; |
323 | } | 333 | } |
324 | 334 | ||
@@ -1267,23 +1277,32 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file, | |||
1267 | switch(av7110->audiostate.channel_select) { | 1277 | switch(av7110->audiostate.channel_select) { |
1268 | case AUDIO_STEREO: | 1278 | case AUDIO_STEREO: |
1269 | ret = audcom(av7110, AUDIO_CMD_STEREO); | 1279 | ret = audcom(av7110, AUDIO_CMD_STEREO); |
1270 | if (!ret) | 1280 | if (!ret) { |
1271 | if (av7110->adac_type == DVB_ADAC_CRYSTAL) | 1281 | if (av7110->adac_type == DVB_ADAC_CRYSTAL) |
1272 | i2c_writereg(av7110, 0x20, 0x02, 0x49); | 1282 | i2c_writereg(av7110, 0x20, 0x02, 0x49); |
1283 | else if (av7110->adac_type == DVB_ADAC_MSP34x5) | ||
1284 | msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0220); | ||
1285 | } | ||
1273 | break; | 1286 | break; |
1274 | 1287 | ||
1275 | case AUDIO_MONO_LEFT: | 1288 | case AUDIO_MONO_LEFT: |
1276 | ret = audcom(av7110, AUDIO_CMD_MONO_L); | 1289 | ret = audcom(av7110, AUDIO_CMD_MONO_L); |
1277 | if (!ret) | 1290 | if (!ret) { |
1278 | if (av7110->adac_type == DVB_ADAC_CRYSTAL) | 1291 | if (av7110->adac_type == DVB_ADAC_CRYSTAL) |
1279 | i2c_writereg(av7110, 0x20, 0x02, 0x4a); | 1292 | i2c_writereg(av7110, 0x20, 0x02, 0x4a); |
1293 | else if (av7110->adac_type == DVB_ADAC_MSP34x5) | ||
1294 | msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0200); | ||
1295 | } | ||
1280 | break; | 1296 | break; |
1281 | 1297 | ||
1282 | case AUDIO_MONO_RIGHT: | 1298 | case AUDIO_MONO_RIGHT: |
1283 | ret = audcom(av7110, AUDIO_CMD_MONO_R); | 1299 | ret = audcom(av7110, AUDIO_CMD_MONO_R); |
1284 | if (!ret) | 1300 | if (!ret) { |
1285 | if (av7110->adac_type == DVB_ADAC_CRYSTAL) | 1301 | if (av7110->adac_type == DVB_ADAC_CRYSTAL) |
1286 | i2c_writereg(av7110, 0x20, 0x02, 0x45); | 1302 | i2c_writereg(av7110, 0x20, 0x02, 0x45); |
1303 | else if (av7110->adac_type == DVB_ADAC_MSP34x5) | ||
1304 | msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0210); | ||
1305 | } | ||
1287 | break; | 1306 | break; |
1288 | 1307 | ||
1289 | default: | 1308 | default: |
diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c index 603a22e4bfe2..64055461559d 100644 --- a/drivers/media/dvb/ttpci/av7110_v4l.c +++ b/drivers/media/dvb/ttpci/av7110_v4l.c | |||
@@ -42,7 +42,18 @@ | |||
42 | int msp_writereg(struct av7110 *av7110, u8 dev, u16 reg, u16 val) | 42 | int msp_writereg(struct av7110 *av7110, u8 dev, u16 reg, u16 val) |
43 | { | 43 | { |
44 | u8 msg[5] = { dev, reg >> 8, reg & 0xff, val >> 8 , val & 0xff }; | 44 | u8 msg[5] = { dev, reg >> 8, reg & 0xff, val >> 8 , val & 0xff }; |
45 | struct i2c_msg msgs = { .flags = 0, .addr = 0x40, .len = 5, .buf = msg }; | 45 | struct i2c_msg msgs = { .flags = 0, .len = 5, .buf = msg }; |
46 | |||
47 | switch (av7110->adac_type) { | ||
48 | case DVB_ADAC_MSP34x0: | ||
49 | msgs.addr = 0x40; | ||
50 | break; | ||
51 | case DVB_ADAC_MSP34x5: | ||
52 | msgs.addr = 0x42; | ||
53 | break; | ||
54 | default: | ||
55 | return 0; | ||
56 | } | ||
46 | 57 | ||
47 | if (i2c_transfer(&av7110->i2c_adap, &msgs, 1) != 1) { | 58 | if (i2c_transfer(&av7110->i2c_adap, &msgs, 1) != 1) { |
48 | dprintk(1, "dvb-ttpci: failed @ card %d, %u = %u\n", | 59 | dprintk(1, "dvb-ttpci: failed @ card %d, %u = %u\n", |
@@ -57,10 +68,23 @@ static int msp_readreg(struct av7110 *av7110, u8 dev, u16 reg, u16 *val) | |||
57 | u8 msg1[3] = { dev, reg >> 8, reg & 0xff }; | 68 | u8 msg1[3] = { dev, reg >> 8, reg & 0xff }; |
58 | u8 msg2[2]; | 69 | u8 msg2[2]; |
59 | struct i2c_msg msgs[2] = { | 70 | struct i2c_msg msgs[2] = { |
60 | { .flags = 0, .addr = 0x40, .len = 3, .buf = msg1 }, | 71 | { .flags = 0 , .len = 3, .buf = msg1 }, |
61 | { .flags = I2C_M_RD, .addr = 0x40, .len = 2, .buf = msg2 } | 72 | { .flags = I2C_M_RD, .len = 2, .buf = msg2 } |
62 | }; | 73 | }; |
63 | 74 | ||
75 | switch (av7110->adac_type) { | ||
76 | case DVB_ADAC_MSP34x0: | ||
77 | msgs[0].addr = 0x40; | ||
78 | msgs[1].addr = 0x40; | ||
79 | break; | ||
80 | case DVB_ADAC_MSP34x5: | ||
81 | msgs[0].addr = 0x42; | ||
82 | msgs[1].addr = 0x42; | ||
83 | break; | ||
84 | default: | ||
85 | return 0; | ||
86 | } | ||
87 | |||
64 | if (i2c_transfer(&av7110->i2c_adap, &msgs[0], 2) != 2) { | 88 | if (i2c_transfer(&av7110->i2c_adap, &msgs[0], 2) != 2) { |
65 | dprintk(1, "dvb-ttpci: failed @ card %d, %u\n", | 89 | dprintk(1, "dvb-ttpci: failed @ card %d, %u\n", |
66 | av7110->dvb_adapter.num, reg); | 90 | av7110->dvb_adapter.num, reg); |
@@ -678,17 +702,23 @@ int av7110_init_analog_module(struct av7110 *av7110) | |||
678 | { | 702 | { |
679 | u16 version1, version2; | 703 | u16 version1, version2; |
680 | 704 | ||
681 | if (i2c_writereg(av7110, 0x80, 0x0, 0x80) != 1 | 705 | if (i2c_writereg(av7110, 0x80, 0x0, 0x80) == 1 && |
682 | || i2c_writereg(av7110, 0x80, 0x0, 0) != 1) | 706 | i2c_writereg(av7110, 0x80, 0x0, 0) == 1) { |
707 | printk("dvb-ttpci: DVB-C analog module @ card %d detected, initializing MSP3400\n", | ||
708 | av7110->dvb_adapter.num); | ||
709 | av7110->adac_type = DVB_ADAC_MSP34x0; | ||
710 | } else if (i2c_writereg(av7110, 0x84, 0x0, 0x80) == 1 && | ||
711 | i2c_writereg(av7110, 0x84, 0x0, 0) == 1) { | ||
712 | printk("dvb-ttpci: DVB-C analog module @ card %d detected, initializing MSP3415\n", | ||
713 | av7110->dvb_adapter.num); | ||
714 | av7110->adac_type = DVB_ADAC_MSP34x5; | ||
715 | } else | ||
683 | return -ENODEV; | 716 | return -ENODEV; |
684 | 717 | ||
685 | printk("dvb-ttpci: DVB-C analog module @ card %d detected, initializing MSP3400\n", | ||
686 | av7110->dvb_adapter.num); | ||
687 | av7110->adac_type = DVB_ADAC_MSP34x0; | ||
688 | msleep(100); // the probing above resets the msp... | 718 | msleep(100); // the probing above resets the msp... |
689 | msp_readreg(av7110, MSP_RD_DSP, 0x001e, &version1); | 719 | msp_readreg(av7110, MSP_RD_DSP, 0x001e, &version1); |
690 | msp_readreg(av7110, MSP_RD_DSP, 0x001f, &version2); | 720 | msp_readreg(av7110, MSP_RD_DSP, 0x001f, &version2); |
691 | dprintk(1, "dvb-ttpci: @ card %d MSP3400 version 0x%04x 0x%04x\n", | 721 | dprintk(1, "dvb-ttpci: @ card %d MSP34xx version 0x%04x 0x%04x\n", |
692 | av7110->dvb_adapter.num, version1, version2); | 722 | av7110->dvb_adapter.num, version1, version2); |
693 | msp_writereg(av7110, MSP_WR_DSP, 0x0013, 0x0c00); | 723 | msp_writereg(av7110, MSP_WR_DSP, 0x0013, 0x0c00); |
694 | msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x7f00); // loudspeaker + headphone | 724 | msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x7f00); // loudspeaker + headphone |
@@ -697,7 +727,7 @@ int av7110_init_analog_module(struct av7110 *av7110) | |||
697 | msp_writereg(av7110, MSP_WR_DSP, 0x0004, 0x7f00); // loudspeaker volume | 727 | msp_writereg(av7110, MSP_WR_DSP, 0x0004, 0x7f00); // loudspeaker volume |
698 | msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0220); // SCART 1 source | 728 | msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0220); // SCART 1 source |
699 | msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x7f00); // SCART 1 volume | 729 | msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x7f00); // SCART 1 volume |
700 | msp_writereg(av7110, MSP_WR_DSP, 0x000d, 0x4800); // prescale SCART | 730 | msp_writereg(av7110, MSP_WR_DSP, 0x000d, 0x1900); // prescale SCART |
701 | 731 | ||
702 | if (i2c_writereg(av7110, 0x48, 0x01, 0x00)!=1) { | 732 | if (i2c_writereg(av7110, 0x48, 0x01, 0x00)!=1) { |
703 | INFO(("saa7113 not accessible.\n")); | 733 | INFO(("saa7113 not accessible.\n")); |
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 824a63c92629..6d532f170ce5 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig | |||
@@ -381,6 +381,18 @@ config VIDEO_WM8739 | |||
381 | To compile this driver as a module, choose M here: the | 381 | To compile this driver as a module, choose M here: the |
382 | module will be called wm8739. | 382 | module will be called wm8739. |
383 | 383 | ||
384 | config VIDEO_CX2341X | ||
385 | tristate "Conexant CX2341x MPEG encoders" | ||
386 | depends on VIDEO_V4L2 && EXPERIMENTAL | ||
387 | ---help--- | ||
388 | Support for the Conexant CX23416 MPEG encoders | ||
389 | and CX23415 MPEG encoder/decoders. | ||
390 | |||
391 | This module currently supports the encoding functions only. | ||
392 | |||
393 | To compile this driver as a module, choose M here: the | ||
394 | module will be called cx2341x. | ||
395 | |||
384 | source "drivers/media/video/cx25840/Kconfig" | 396 | source "drivers/media/video/cx25840/Kconfig" |
385 | 397 | ||
386 | config VIDEO_SAA711X | 398 | config VIDEO_SAA711X |
@@ -433,6 +445,8 @@ endmenu # encoder / decoder chips | |||
433 | menu "V4L USB devices" | 445 | menu "V4L USB devices" |
434 | depends on USB && VIDEO_DEV | 446 | depends on USB && VIDEO_DEV |
435 | 447 | ||
448 | source "drivers/media/video/pvrusb2/Kconfig" | ||
449 | |||
436 | source "drivers/media/video/em28xx/Kconfig" | 450 | source "drivers/media/video/em28xx/Kconfig" |
437 | 451 | ||
438 | config USB_DSBR | 452 | config USB_DSBR |
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 6c401b46398a..353d61cfac1b 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile | |||
@@ -47,6 +47,7 @@ obj-$(CONFIG_VIDEO_SAA7134) += ir-kbd-i2c.o saa7134/ | |||
47 | obj-$(CONFIG_VIDEO_CX88) += cx88/ | 47 | obj-$(CONFIG_VIDEO_CX88) += cx88/ |
48 | obj-$(CONFIG_VIDEO_EM28XX) += em28xx/ | 48 | obj-$(CONFIG_VIDEO_EM28XX) += em28xx/ |
49 | obj-$(CONFIG_VIDEO_EM28XX) += tvp5150.o | 49 | obj-$(CONFIG_VIDEO_EM28XX) += tvp5150.o |
50 | obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/ | ||
50 | obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o | 51 | obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o |
51 | obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o | 52 | obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o |
52 | obj-$(CONFIG_VIDEO_TLV320AIC23B) += tlv320aic23b.o | 53 | obj-$(CONFIG_VIDEO_TLV320AIC23B) += tlv320aic23b.o |
diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c index 3116345c93b1..e68a6d2fff24 100644 --- a/drivers/media/video/bt8xx/bttv-cards.c +++ b/drivers/media/video/bt8xx/bttv-cards.c | |||
@@ -4848,7 +4848,7 @@ static void picolo_tetra_muxsel (struct bttv* btv, unsigned int input) | |||
4848 | * | 4848 | * |
4849 | * The IVC120G security card has 4 i2c controlled TDA8540 matrix | 4849 | * The IVC120G security card has 4 i2c controlled TDA8540 matrix |
4850 | * swichers to provide 16 channels to MUX0. The TDA8540's have | 4850 | * swichers to provide 16 channels to MUX0. The TDA8540's have |
4851 | * 4 indepedant outputs and as such the IVC120G also has the | 4851 | * 4 independent outputs and as such the IVC120G also has the |
4852 | * optional "Monitor Out" bus. This allows the card to be looking | 4852 | * optional "Monitor Out" bus. This allows the card to be looking |
4853 | * at one input while the monitor is looking at another. | 4853 | * at one input while the monitor is looking at another. |
4854 | * | 4854 | * |
diff --git a/drivers/media/video/cx2341x.c b/drivers/media/video/cx2341x.c index 554813e6f65d..65f00fc08fa9 100644 --- a/drivers/media/video/cx2341x.c +++ b/drivers/media/video/cx2341x.c | |||
@@ -43,6 +43,7 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)"); | |||
43 | const u32 cx2341x_mpeg_ctrls[] = { | 43 | const u32 cx2341x_mpeg_ctrls[] = { |
44 | V4L2_CID_MPEG_CLASS, | 44 | V4L2_CID_MPEG_CLASS, |
45 | V4L2_CID_MPEG_STREAM_TYPE, | 45 | V4L2_CID_MPEG_STREAM_TYPE, |
46 | V4L2_CID_MPEG_STREAM_VBI_FMT, | ||
46 | V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ, | 47 | V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ, |
47 | V4L2_CID_MPEG_AUDIO_ENCODING, | 48 | V4L2_CID_MPEG_AUDIO_ENCODING, |
48 | V4L2_CID_MPEG_AUDIO_L2_BITRATE, | 49 | V4L2_CID_MPEG_AUDIO_L2_BITRATE, |
@@ -135,6 +136,9 @@ static int cx2341x_get_ctrl(struct cx2341x_mpeg_params *params, | |||
135 | case V4L2_CID_MPEG_STREAM_TYPE: | 136 | case V4L2_CID_MPEG_STREAM_TYPE: |
136 | ctrl->value = params->stream_type; | 137 | ctrl->value = params->stream_type; |
137 | break; | 138 | break; |
139 | case V4L2_CID_MPEG_STREAM_VBI_FMT: | ||
140 | ctrl->value = params->stream_vbi_fmt; | ||
141 | break; | ||
138 | case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: | 142 | case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: |
139 | ctrl->value = params->video_spatial_filter_mode; | 143 | ctrl->value = params->video_spatial_filter_mode; |
140 | break; | 144 | break; |
@@ -257,6 +261,9 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, | |||
257 | params->video_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR; | 261 | params->video_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR; |
258 | } | 262 | } |
259 | break; | 263 | break; |
264 | case V4L2_CID_MPEG_STREAM_VBI_FMT: | ||
265 | params->stream_vbi_fmt = ctrl->value; | ||
266 | break; | ||
260 | case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: | 267 | case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: |
261 | params->video_spatial_filter_mode = ctrl->value; | 268 | params->video_spatial_filter_mode = ctrl->value; |
262 | break; | 269 | break; |
@@ -418,6 +425,14 @@ int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl | |||
418 | qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; | 425 | qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; |
419 | return err; | 426 | return err; |
420 | 427 | ||
428 | case V4L2_CID_MPEG_STREAM_VBI_FMT: | ||
429 | if (params->capabilities & CX2341X_CAP_HAS_SLICED_VBI) | ||
430 | return v4l2_ctrl_query_fill_std(qctrl); | ||
431 | return cx2341x_ctrl_query_fill(qctrl, | ||
432 | V4L2_MPEG_STREAM_VBI_FMT_NONE, | ||
433 | V4L2_MPEG_STREAM_VBI_FMT_NONE, 1, | ||
434 | V4L2_MPEG_STREAM_VBI_FMT_NONE); | ||
435 | |||
421 | /* CX23415/6 specific */ | 436 | /* CX23415/6 specific */ |
422 | case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: | 437 | case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: |
423 | return cx2341x_ctrl_query_fill(qctrl, | 438 | return cx2341x_ctrl_query_fill(qctrl, |
@@ -586,7 +601,7 @@ static void cx2341x_calc_audio_properties(struct cx2341x_mpeg_params *params) | |||
586 | } | 601 | } |
587 | 602 | ||
588 | int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, | 603 | int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, |
589 | struct v4l2_ext_controls *ctrls, int cmd) | 604 | struct v4l2_ext_controls *ctrls, unsigned int cmd) |
590 | { | 605 | { |
591 | int err = 0; | 606 | int err = 0; |
592 | int i; | 607 | int i; |
@@ -639,6 +654,7 @@ void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p) | |||
639 | { | 654 | { |
640 | static struct cx2341x_mpeg_params default_params = { | 655 | static struct cx2341x_mpeg_params default_params = { |
641 | /* misc */ | 656 | /* misc */ |
657 | .capabilities = 0, | ||
642 | .port = CX2341X_PORT_MEMORY, | 658 | .port = CX2341X_PORT_MEMORY, |
643 | .width = 720, | 659 | .width = 720, |
644 | .height = 480, | 660 | .height = 480, |
@@ -646,6 +662,7 @@ void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p) | |||
646 | 662 | ||
647 | /* stream */ | 663 | /* stream */ |
648 | .stream_type = V4L2_MPEG_STREAM_TYPE_MPEG2_PS, | 664 | .stream_type = V4L2_MPEG_STREAM_TYPE_MPEG2_PS, |
665 | .stream_vbi_fmt = V4L2_MPEG_STREAM_VBI_FMT_NONE, | ||
649 | 666 | ||
650 | /* audio */ | 667 | /* audio */ |
651 | .audio_sampling_freq = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000, | 668 | .audio_sampling_freq = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000, |
@@ -830,22 +847,22 @@ invalid: | |||
830 | return "<invalid>"; | 847 | return "<invalid>"; |
831 | } | 848 | } |
832 | 849 | ||
833 | void cx2341x_log_status(struct cx2341x_mpeg_params *p, int card_id) | 850 | void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix) |
834 | { | 851 | { |
835 | int is_mpeg1 = p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1; | 852 | int is_mpeg1 = p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1; |
836 | 853 | ||
837 | /* Stream */ | 854 | /* Stream */ |
838 | printk(KERN_INFO "cx2341x-%d: Stream: %s\n", | 855 | printk(KERN_INFO "%s: Stream: %s\n", |
839 | card_id, | 856 | prefix, |
840 | cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_TYPE)); | 857 | cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_TYPE)); |
841 | 858 | ||
842 | /* Video */ | 859 | /* Video */ |
843 | printk(KERN_INFO "cx2341x-%d: Video: %dx%d, %d fps\n", | 860 | printk(KERN_INFO "%s: Video: %dx%d, %d fps\n", |
844 | card_id, | 861 | prefix, |
845 | p->width / (is_mpeg1 ? 2 : 1), p->height / (is_mpeg1 ? 2 : 1), | 862 | p->width / (is_mpeg1 ? 2 : 1), p->height / (is_mpeg1 ? 2 : 1), |
846 | p->is_50hz ? 25 : 30); | 863 | p->is_50hz ? 25 : 30); |
847 | printk(KERN_INFO "cx2341x-%d: Video: %s, %s, %s, %d", | 864 | printk(KERN_INFO "%s: Video: %s, %s, %s, %d", |
848 | card_id, | 865 | prefix, |
849 | cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ENCODING), | 866 | cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ENCODING), |
850 | cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ASPECT), | 867 | cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ASPECT), |
851 | cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_BITRATE_MODE), | 868 | cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_BITRATE_MODE), |
@@ -854,19 +871,19 @@ void cx2341x_log_status(struct cx2341x_mpeg_params *p, int card_id) | |||
854 | printk(", Peak %d", p->video_bitrate_peak); | 871 | printk(", Peak %d", p->video_bitrate_peak); |
855 | } | 872 | } |
856 | printk("\n"); | 873 | printk("\n"); |
857 | printk(KERN_INFO "cx2341x-%d: Video: GOP Size %d, %d B-Frames, %sGOP Closure, %s3:2 Pulldown\n", | 874 | printk(KERN_INFO "%s: Video: GOP Size %d, %d B-Frames, %sGOP Closure, %s3:2 Pulldown\n", |
858 | card_id, | 875 | prefix, |
859 | p->video_gop_size, p->video_b_frames, | 876 | p->video_gop_size, p->video_b_frames, |
860 | p->video_gop_closure ? "" : "No ", | 877 | p->video_gop_closure ? "" : "No ", |
861 | p->video_pulldown ? "" : "No "); | 878 | p->video_pulldown ? "" : "No "); |
862 | if (p->video_temporal_decimation) { | 879 | if (p->video_temporal_decimation) { |
863 | printk(KERN_INFO "cx2341x-%d: Video: Temporal Decimation %d\n", | 880 | printk(KERN_INFO "%s: Video: Temporal Decimation %d\n", |
864 | card_id, p->video_temporal_decimation); | 881 | prefix, p->video_temporal_decimation); |
865 | } | 882 | } |
866 | 883 | ||
867 | /* Audio */ | 884 | /* Audio */ |
868 | printk(KERN_INFO "cx2341x-%d: Audio: %s, %s, %s, %s", | 885 | printk(KERN_INFO "%s: Audio: %s, %s, %s, %s", |
869 | card_id, | 886 | prefix, |
870 | cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ), | 887 | cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ), |
871 | cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_ENCODING), | 888 | cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_ENCODING), |
872 | cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_L2_BITRATE), | 889 | cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_L2_BITRATE), |
@@ -880,18 +897,18 @@ void cx2341x_log_status(struct cx2341x_mpeg_params *p, int card_id) | |||
880 | cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_CRC)); | 897 | cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_CRC)); |
881 | 898 | ||
882 | /* Encoding filters */ | 899 | /* Encoding filters */ |
883 | printk(KERN_INFO "cx2341x-%d: Spatial Filter: %s, Luma %s, Chroma %s, %d\n", | 900 | printk(KERN_INFO "%s: Spatial Filter: %s, Luma %s, Chroma %s, %d\n", |
884 | card_id, | 901 | prefix, |
885 | cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE), | 902 | cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE), |
886 | cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE), | 903 | cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE), |
887 | cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE), | 904 | cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE), |
888 | p->video_spatial_filter); | 905 | p->video_spatial_filter); |
889 | printk(KERN_INFO "cx2341x-%d: Temporal Filter: %s, %d\n", | 906 | printk(KERN_INFO "%s: Temporal Filter: %s, %d\n", |
890 | card_id, | 907 | prefix, |
891 | cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE), | 908 | cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE), |
892 | p->video_temporal_filter); | 909 | p->video_temporal_filter); |
893 | printk(KERN_INFO "cx2341x-%d: Median Filter: %s, Luma [%d, %d], Chroma [%d, %d]\n", | 910 | printk(KERN_INFO "%s: Median Filter: %s, Luma [%d, %d], Chroma [%d, %d]\n", |
894 | card_id, | 911 | prefix, |
895 | cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE), | 912 | cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE), |
896 | p->video_luma_median_filter_bottom, | 913 | p->video_luma_median_filter_bottom, |
897 | p->video_luma_median_filter_top, | 914 | p->video_luma_median_filter_top, |
diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig index 91e1c481a164..80e23ee9801c 100644 --- a/drivers/media/video/cx88/Kconfig +++ b/drivers/media/video/cx88/Kconfig | |||
@@ -11,7 +11,6 @@ config VIDEO_CX88 | |||
11 | select VIDEO_BUF | 11 | select VIDEO_BUF |
12 | select VIDEO_TUNER | 12 | select VIDEO_TUNER |
13 | select VIDEO_TVEEPROM | 13 | select VIDEO_TVEEPROM |
14 | select VIDEO_CX2341X | ||
15 | select VIDEO_IR | 14 | select VIDEO_IR |
16 | ---help--- | 15 | ---help--- |
17 | This is a video4linux driver for Conexant 2388x based | 16 | This is a video4linux driver for Conexant 2388x based |
@@ -36,13 +35,25 @@ config VIDEO_CX88_ALSA | |||
36 | To compile this driver as a module, choose M here: the | 35 | To compile this driver as a module, choose M here: the |
37 | module will be called cx88-alsa. | 36 | module will be called cx88-alsa. |
38 | 37 | ||
38 | config VIDEO_CX88_BLACKBIRD | ||
39 | tristate "Blackbird MPEG encoder support (cx2388x + cx23416)" | ||
40 | depends on VIDEO_CX88 | ||
41 | select VIDEO_CX2341X | ||
42 | ---help--- | ||
43 | This adds support for MPEG encoder cards based on the | ||
44 | Blackbird reference design, using the Conexant 2388x | ||
45 | and 23416 chips. | ||
46 | |||
47 | To compile this driver as a module, choose M here: the | ||
48 | module will be called cx88-blackbird. | ||
49 | |||
39 | config VIDEO_CX88_DVB | 50 | config VIDEO_CX88_DVB |
40 | tristate "DVB/ATSC Support for cx2388x based TV cards" | 51 | tristate "DVB/ATSC Support for cx2388x based TV cards" |
41 | depends on VIDEO_CX88 && DVB_CORE | 52 | depends on VIDEO_CX88 && DVB_CORE |
42 | select VIDEO_BUF_DVB | 53 | select VIDEO_BUF_DVB |
43 | ---help--- | 54 | ---help--- |
44 | This adds support for DVB/ATSC cards based on the | 55 | This adds support for DVB/ATSC cards based on the |
45 | Connexant 2388x chip. | 56 | Conexant 2388x chip. |
46 | 57 | ||
47 | To compile this driver as a module, choose M here: the | 58 | To compile this driver as a module, choose M here: the |
48 | module will be called cx88-dvb. | 59 | module will be called cx88-dvb. |
diff --git a/drivers/media/video/cx88/Makefile b/drivers/media/video/cx88/Makefile index 0dcd09b9b727..352b919f30c4 100644 --- a/drivers/media/video/cx88/Makefile +++ b/drivers/media/video/cx88/Makefile | |||
@@ -3,9 +3,10 @@ cx88xx-objs := cx88-cards.o cx88-core.o cx88-i2c.o cx88-tvaudio.o \ | |||
3 | cx8800-objs := cx88-video.o cx88-vbi.o | 3 | cx8800-objs := cx88-video.o cx88-vbi.o |
4 | cx8802-objs := cx88-mpeg.o | 4 | cx8802-objs := cx88-mpeg.o |
5 | 5 | ||
6 | obj-$(CONFIG_VIDEO_CX88) += cx88xx.o cx8800.o cx8802.o cx88-blackbird.o | 6 | obj-$(CONFIG_VIDEO_CX88) += cx88xx.o cx8800.o cx8802.o |
7 | obj-$(CONFIG_VIDEO_CX88_DVB) += cx88-dvb.o | ||
8 | obj-$(CONFIG_VIDEO_CX88_ALSA) += cx88-alsa.o | 7 | obj-$(CONFIG_VIDEO_CX88_ALSA) += cx88-alsa.o |
8 | obj-$(CONFIG_VIDEO_CX88_BLACKBIRD) += cx88-blackbird.o | ||
9 | obj-$(CONFIG_VIDEO_CX88_DVB) += cx88-dvb.o | ||
9 | obj-$(CONFIG_VIDEO_CX88_VP3054) += cx88-vp3054-i2c.o | 10 | obj-$(CONFIG_VIDEO_CX88_VP3054) += cx88-vp3054-i2c.o |
10 | 11 | ||
11 | EXTRA_CFLAGS += -Idrivers/media/video | 12 | EXTRA_CFLAGS += -Idrivers/media/video |
diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index 67fd3302e8f2..4ff81582ec56 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c | |||
@@ -846,24 +846,33 @@ static int mpeg_do_ioctl(struct inode *inode, struct file *file, | |||
846 | BLACKBIRD_MPEG_CAPTURE, | 846 | BLACKBIRD_MPEG_CAPTURE, |
847 | BLACKBIRD_RAW_BITS_NONE); | 847 | BLACKBIRD_RAW_BITS_NONE); |
848 | 848 | ||
849 | cx88_do_ioctl( inode, file, 0, dev->core, cmd, arg, cx88_ioctl_hook ); | 849 | cx88_do_ioctl(inode, file, 0, dev->core, cmd, arg, mpeg_do_ioctl); |
850 | 850 | ||
851 | blackbird_initialize_codec(dev); | 851 | blackbird_initialize_codec(dev); |
852 | cx88_set_scale(dev->core, dev->width, dev->height, | 852 | cx88_set_scale(dev->core, dev->width, dev->height, |
853 | fh->mpegq.field); | 853 | fh->mpegq.field); |
854 | return 0; | 854 | return 0; |
855 | } | 855 | } |
856 | case VIDIOC_LOG_STATUS: | ||
857 | { | ||
858 | char name[32 + 2]; | ||
859 | |||
860 | snprintf(name, sizeof(name), "%s/2", core->name); | ||
861 | printk("%s/2: ============ START LOG STATUS ============\n", | ||
862 | core->name); | ||
863 | cx88_call_i2c_clients(core, VIDIOC_LOG_STATUS, 0); | ||
864 | cx2341x_log_status(&dev->params, name); | ||
865 | printk("%s/2: ============= END LOG STATUS =============\n", | ||
866 | core->name); | ||
867 | return 0; | ||
868 | } | ||
856 | 869 | ||
857 | default: | 870 | default: |
858 | return cx88_do_ioctl( inode, file, 0, dev->core, cmd, arg, cx88_ioctl_hook ); | 871 | return cx88_do_ioctl(inode, file, 0, dev->core, cmd, arg, mpeg_do_ioctl); |
859 | } | 872 | } |
860 | return 0; | 873 | return 0; |
861 | } | 874 | } |
862 | 875 | ||
863 | int (*cx88_ioctl_hook)(struct inode *inode, struct file *file, | ||
864 | unsigned int cmd, void *arg); | ||
865 | unsigned int (*cx88_ioctl_translator)(unsigned int cmd); | ||
866 | |||
867 | static unsigned int mpeg_translate_ioctl(unsigned int cmd) | 876 | static unsigned int mpeg_translate_ioctl(unsigned int cmd) |
868 | { | 877 | { |
869 | return cmd; | 878 | return cmd; |
@@ -872,8 +881,8 @@ static unsigned int mpeg_translate_ioctl(unsigned int cmd) | |||
872 | static int mpeg_ioctl(struct inode *inode, struct file *file, | 881 | static int mpeg_ioctl(struct inode *inode, struct file *file, |
873 | unsigned int cmd, unsigned long arg) | 882 | unsigned int cmd, unsigned long arg) |
874 | { | 883 | { |
875 | cmd = cx88_ioctl_translator( cmd ); | 884 | cmd = mpeg_translate_ioctl( cmd ); |
876 | return video_usercopy(inode, file, cmd, arg, cx88_ioctl_hook); | 885 | return video_usercopy(inode, file, cmd, arg, mpeg_do_ioctl); |
877 | } | 886 | } |
878 | 887 | ||
879 | static int mpeg_open(struct inode *inode, struct file *file) | 888 | static int mpeg_open(struct inode *inode, struct file *file) |
@@ -1119,8 +1128,6 @@ static int blackbird_init(void) | |||
1119 | printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n", | 1128 | printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n", |
1120 | SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); | 1129 | SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); |
1121 | #endif | 1130 | #endif |
1122 | cx88_ioctl_hook = mpeg_do_ioctl; | ||
1123 | cx88_ioctl_translator = mpeg_translate_ioctl; | ||
1124 | return pci_register_driver(&blackbird_pci_driver); | 1131 | return pci_register_driver(&blackbird_pci_driver); |
1125 | } | 1132 | } |
1126 | 1133 | ||
@@ -1132,9 +1139,6 @@ static void blackbird_fini(void) | |||
1132 | module_init(blackbird_init); | 1139 | module_init(blackbird_init); |
1133 | module_exit(blackbird_fini); | 1140 | module_exit(blackbird_fini); |
1134 | 1141 | ||
1135 | EXPORT_SYMBOL(cx88_ioctl_hook); | ||
1136 | EXPORT_SYMBOL(cx88_ioctl_translator); | ||
1137 | |||
1138 | /* ----------------------------------------------------------- */ | 1142 | /* ----------------------------------------------------------- */ |
1139 | /* | 1143 | /* |
1140 | * Local variables: | 1144 | * Local variables: |
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index 67cdd8270863..f9d68f20dc88 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c | |||
@@ -1700,11 +1700,6 @@ void cx88_card_setup(struct cx88_core *core) | |||
1700 | /* ------------------------------------------------------------------ */ | 1700 | /* ------------------------------------------------------------------ */ |
1701 | 1701 | ||
1702 | EXPORT_SYMBOL(cx88_boards); | 1702 | EXPORT_SYMBOL(cx88_boards); |
1703 | EXPORT_SYMBOL(cx88_bcount); | ||
1704 | EXPORT_SYMBOL(cx88_subids); | ||
1705 | EXPORT_SYMBOL(cx88_idcount); | ||
1706 | EXPORT_SYMBOL(cx88_card_list); | ||
1707 | EXPORT_SYMBOL(cx88_card_setup); | ||
1708 | 1703 | ||
1709 | /* | 1704 | /* |
1710 | * Local variables: | 1705 | * Local variables: |
diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index c56292d8d93b..26f4c0fb8c36 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c | |||
@@ -1181,8 +1181,6 @@ EXPORT_SYMBOL(cx88_set_scale); | |||
1181 | EXPORT_SYMBOL(cx88_vdev_init); | 1181 | EXPORT_SYMBOL(cx88_vdev_init); |
1182 | EXPORT_SYMBOL(cx88_core_get); | 1182 | EXPORT_SYMBOL(cx88_core_get); |
1183 | EXPORT_SYMBOL(cx88_core_put); | 1183 | EXPORT_SYMBOL(cx88_core_put); |
1184 | EXPORT_SYMBOL(cx88_start_audio_dma); | ||
1185 | EXPORT_SYMBOL(cx88_stop_audio_dma); | ||
1186 | 1184 | ||
1187 | /* | 1185 | /* |
1188 | * Local variables: | 1186 | * Local variables: |
diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c index 7efa6def0bde..70663805cc30 100644 --- a/drivers/media/video/cx88/cx88-i2c.c +++ b/drivers/media/video/cx88/cx88-i2c.c | |||
@@ -234,7 +234,6 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci) | |||
234 | /* ----------------------------------------------------------------------- */ | 234 | /* ----------------------------------------------------------------------- */ |
235 | 235 | ||
236 | EXPORT_SYMBOL(cx88_call_i2c_clients); | 236 | EXPORT_SYMBOL(cx88_call_i2c_clients); |
237 | EXPORT_SYMBOL(cx88_i2c_init); | ||
238 | 237 | ||
239 | /* | 238 | /* |
240 | * Local variables: | 239 | * Local variables: |
diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c index 1e4278b588d8..5785c3481579 100644 --- a/drivers/media/video/cx88/cx88-tvaudio.c +++ b/drivers/media/video/cx88/cx88-tvaudio.c | |||
@@ -726,7 +726,7 @@ static void set_audio_standard_FM(struct cx88_core *core, | |||
726 | 726 | ||
727 | /* ----------------------------------------------------------- */ | 727 | /* ----------------------------------------------------------- */ |
728 | 728 | ||
729 | int cx88_detect_nicam(struct cx88_core *core) | 729 | static int cx88_detect_nicam(struct cx88_core *core) |
730 | { | 730 | { |
731 | int i, j = 0; | 731 | int i, j = 0; |
732 | 732 | ||
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index 694d1d80ff3f..dcda5291b990 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c | |||
@@ -494,8 +494,7 @@ static int restart_video_queue(struct cx8800_dev *dev, | |||
494 | return 0; | 494 | return 0; |
495 | buf = list_entry(q->queued.next, struct cx88_buffer, vb.queue); | 495 | buf = list_entry(q->queued.next, struct cx88_buffer, vb.queue); |
496 | if (NULL == prev) { | 496 | if (NULL == prev) { |
497 | list_del(&buf->vb.queue); | 497 | list_move_tail(&buf->vb.queue, &q->active); |
498 | list_add_tail(&buf->vb.queue,&q->active); | ||
499 | start_video_dma(dev, q, buf); | 498 | start_video_dma(dev, q, buf); |
500 | buf->vb.state = STATE_ACTIVE; | 499 | buf->vb.state = STATE_ACTIVE; |
501 | buf->count = q->count++; | 500 | buf->count = q->count++; |
@@ -506,8 +505,7 @@ static int restart_video_queue(struct cx8800_dev *dev, | |||
506 | } else if (prev->vb.width == buf->vb.width && | 505 | } else if (prev->vb.width == buf->vb.width && |
507 | prev->vb.height == buf->vb.height && | 506 | prev->vb.height == buf->vb.height && |
508 | prev->fmt == buf->fmt) { | 507 | prev->fmt == buf->fmt) { |
509 | list_del(&buf->vb.queue); | 508 | list_move_tail(&buf->vb.queue, &q->active); |
510 | list_add_tail(&buf->vb.queue,&q->active); | ||
511 | buf->vb.state = STATE_ACTIVE; | 509 | buf->vb.state = STATE_ACTIVE; |
512 | buf->count = q->count++; | 510 | buf->count = q->count++; |
513 | prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); | 511 | prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); |
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index dc7bc35f18f4..9a9a0fc7a41a 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h | |||
@@ -563,7 +563,6 @@ void cx88_newstation(struct cx88_core *core); | |||
563 | void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t); | 563 | void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t); |
564 | void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual); | 564 | void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual); |
565 | int cx88_audio_thread(void *data); | 565 | int cx88_audio_thread(void *data); |
566 | int cx88_detect_nicam(struct cx88_core *core); | ||
567 | 566 | ||
568 | /* ----------------------------------------------------------- */ | 567 | /* ----------------------------------------------------------- */ |
569 | /* cx88-input.c */ | 568 | /* cx88-input.c */ |
@@ -592,12 +591,6 @@ extern int cx88_do_ioctl(struct inode *inode, struct file *file, int radio, | |||
592 | struct cx88_core *core, unsigned int cmd, | 591 | struct cx88_core *core, unsigned int cmd, |
593 | void *arg, v4l2_kioctl driver_ioctl); | 592 | void *arg, v4l2_kioctl driver_ioctl); |
594 | 593 | ||
595 | /* ----------------------------------------------------------- */ | ||
596 | /* cx88-blackbird.c */ | ||
597 | extern int (*cx88_ioctl_hook)(struct inode *inode, struct file *file, | ||
598 | unsigned int cmd, void *arg); | ||
599 | extern unsigned int (*cx88_ioctl_translator)(unsigned int cmd); | ||
600 | |||
601 | /* | 594 | /* |
602 | * Local variables: | 595 | * Local variables: |
603 | * c-basic-offset: 8 | 596 | * c-basic-offset: 8 |
diff --git a/drivers/media/video/pvrusb2/Kconfig b/drivers/media/video/pvrusb2/Kconfig new file mode 100644 index 000000000000..7e727fe14b32 --- /dev/null +++ b/drivers/media/video/pvrusb2/Kconfig | |||
@@ -0,0 +1,62 @@ | |||
1 | config VIDEO_PVRUSB2 | ||
2 | tristate "Hauppauge WinTV-PVR USB2 support" | ||
3 | depends on VIDEO_V4L2 && USB && I2C && EXPERIMENTAL | ||
4 | select FW_LOADER | ||
5 | select VIDEO_TUNER | ||
6 | select VIDEO_TVEEPROM | ||
7 | select VIDEO_CX2341X | ||
8 | select VIDEO_SAA711X | ||
9 | select VIDEO_MSP3400 | ||
10 | ---help--- | ||
11 | This is a video4linux driver for Conexant 23416 based | ||
12 | usb2 personal video recorder devices. | ||
13 | |||
14 | To compile this driver as a module, choose M here: the | ||
15 | module will be called pvrusb2 | ||
16 | |||
17 | config VIDEO_PVRUSB2_24XXX | ||
18 | bool "Hauppauge WinTV-PVR USB2 support for 24xxx model series" | ||
19 | depends on VIDEO_PVRUSB2 && EXPERIMENTAL | ||
20 | select VIDEO_CX25840 | ||
21 | select VIDEO_WM8775 | ||
22 | ---help--- | ||
23 | This option enables inclusion of additional logic to operate | ||
24 | newer WinTV-PVR USB2 devices whose model number is of the | ||
25 | form "24xxx" (leading prefix of "24" followed by 3 digits). | ||
26 | To see if you may need this option, examine the white | ||
27 | sticker on the underside of your device. Enabling this | ||
28 | option will not harm support for older devices, however it | ||
29 | is a separate option because of the experimental nature of | ||
30 | this new feature. | ||
31 | |||
32 | If you are in doubt, say N. | ||
33 | |||
34 | Note: This feature is _very_ experimental. You have been | ||
35 | warned. | ||
36 | |||
37 | config VIDEO_PVRUSB2_SYSFS | ||
38 | bool "pvrusb2 sysfs support (EXPERIMENTAL)" | ||
39 | default y | ||
40 | depends on VIDEO_PVRUSB2 && SYSFS && EXPERIMENTAL | ||
41 | ---help--- | ||
42 | This option enables the operation of a sysfs based | ||
43 | interface for query and control of the pvrusb2 driver. | ||
44 | |||
45 | This is not generally needed for v4l applications, | ||
46 | although certain applications are optimized to take | ||
47 | advantage of this feature. | ||
48 | |||
49 | If you are in doubt, say Y. | ||
50 | |||
51 | Note: This feature is experimental and subject to change. | ||
52 | |||
53 | config VIDEO_PVRUSB2_DEBUGIFC | ||
54 | bool "pvrusb2 debug interface" | ||
55 | depends on VIDEO_PVRUSB2_SYSFS | ||
56 | ---help--- | ||
57 | This option enables the inclusion of a debug interface | ||
58 | in the pvrusb2 driver, hosted through sysfs. | ||
59 | |||
60 | You do not need to select this option unless you plan | ||
61 | on debugging the driver or performing a manual firmware | ||
62 | extraction. | ||
diff --git a/drivers/media/video/pvrusb2/Makefile b/drivers/media/video/pvrusb2/Makefile new file mode 100644 index 000000000000..fed603ad0a67 --- /dev/null +++ b/drivers/media/video/pvrusb2/Makefile | |||
@@ -0,0 +1,18 @@ | |||
1 | obj-pvrusb2-sysfs-$(CONFIG_VIDEO_PVRUSB2_SYSFS) := pvrusb2-sysfs.o | ||
2 | obj-pvrusb2-debugifc-$(CONFIG_VIDEO_PVRUSB2_DEBUGIFC) := pvrusb2-debugifc.o | ||
3 | |||
4 | obj-pvrusb2-24xxx-$(CONFIG_VIDEO_PVRUSB2_24XXX) := \ | ||
5 | pvrusb2-cx2584x-v4l.o \ | ||
6 | pvrusb2-wm8775.o | ||
7 | |||
8 | pvrusb2-objs := pvrusb2-i2c-core.o pvrusb2-i2c-cmd-v4l2.o \ | ||
9 | pvrusb2-audio.o pvrusb2-i2c-chips-v4l2.o \ | ||
10 | pvrusb2-encoder.o pvrusb2-video-v4l.o \ | ||
11 | pvrusb2-eeprom.o pvrusb2-tuner.o pvrusb2-demod.o \ | ||
12 | pvrusb2-main.o pvrusb2-hdw.o pvrusb2-v4l2.o \ | ||
13 | pvrusb2-ctrl.o pvrusb2-std.o \ | ||
14 | pvrusb2-context.o pvrusb2-io.o pvrusb2-ioread.o \ | ||
15 | $(obj-pvrusb2-24xxx-y) \ | ||
16 | $(obj-pvrusb2-sysfs-y) $(obj-pvrusb2-debugifc-y) | ||
17 | |||
18 | obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2.o | ||
diff --git a/drivers/media/video/pvrusb2/pvrusb2-audio.c b/drivers/media/video/pvrusb2/pvrusb2-audio.c new file mode 100644 index 000000000000..313d2dcf9e4b --- /dev/null +++ b/drivers/media/video/pvrusb2/pvrusb2-audio.c | |||
@@ -0,0 +1,204 @@ | |||
1 | /* | ||
2 | * | ||
3 | * $Id$ | ||
4 | * | ||
5 | * Copyright (C) 2005 Mike Isely <isely@pobox.com> | ||
6 | * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License | ||
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 | |||
23 | #include "pvrusb2-audio.h" | ||
24 | #include "pvrusb2-hdw-internal.h" | ||
25 | #include "pvrusb2-debug.h" | ||
26 | #include <linux/videodev2.h> | ||
27 | #include <media/msp3400.h> | ||
28 | #include <media/v4l2-common.h> | ||
29 | |||
30 | struct pvr2_msp3400_handler { | ||
31 | struct pvr2_hdw *hdw; | ||
32 | struct pvr2_i2c_client *client; | ||
33 | struct pvr2_i2c_handler i2c_handler; | ||
34 | struct pvr2_audio_stat astat; | ||
35 | unsigned long stale_mask; | ||
36 | }; | ||
37 | |||
38 | |||
39 | /* This function selects the correct audio input source */ | ||
40 | static void set_stereo(struct pvr2_msp3400_handler *ctxt) | ||
41 | { | ||
42 | struct pvr2_hdw *hdw = ctxt->hdw; | ||
43 | struct v4l2_routing route; | ||
44 | |||
45 | pvr2_trace(PVR2_TRACE_CHIPS,"i2c msp3400 v4l2 set_stereo"); | ||
46 | |||
47 | if (hdw->input_val == PVR2_CVAL_INPUT_TV) { | ||
48 | struct v4l2_tuner vt; | ||
49 | memset(&vt,0,sizeof(vt)); | ||
50 | vt.audmode = hdw->audiomode_val; | ||
51 | pvr2_i2c_client_cmd(ctxt->client,VIDIOC_S_TUNER,&vt); | ||
52 | } | ||
53 | |||
54 | route.input = MSP_INPUT_DEFAULT; | ||
55 | route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1); | ||
56 | switch (hdw->input_val) { | ||
57 | case PVR2_CVAL_INPUT_TV: | ||
58 | break; | ||
59 | case PVR2_CVAL_INPUT_RADIO: | ||
60 | /* Assume that msp34xx also handle FM decoding, in which case | ||
61 | we're still using the tuner. */ | ||
62 | /* HV: actually it is more likely to be the SCART2 input if | ||
63 | the ivtv experience is any indication. */ | ||
64 | route.input = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1, | ||
65 | MSP_DSP_IN_SCART, MSP_DSP_IN_SCART); | ||
66 | break; | ||
67 | case PVR2_CVAL_INPUT_SVIDEO: | ||
68 | case PVR2_CVAL_INPUT_COMPOSITE: | ||
69 | /* SCART 1 input */ | ||
70 | route.input = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1, | ||
71 | MSP_DSP_IN_SCART, MSP_DSP_IN_SCART); | ||
72 | break; | ||
73 | } | ||
74 | pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_AUDIO_ROUTING,&route); | ||
75 | } | ||
76 | |||
77 | |||
78 | static int check_stereo(struct pvr2_msp3400_handler *ctxt) | ||
79 | { | ||
80 | struct pvr2_hdw *hdw = ctxt->hdw; | ||
81 | return (hdw->input_dirty || | ||
82 | hdw->audiomode_dirty); | ||
83 | } | ||
84 | |||
85 | |||
86 | struct pvr2_msp3400_ops { | ||
87 | void (*update)(struct pvr2_msp3400_handler *); | ||
88 | int (*check)(struct pvr2_msp3400_handler *); | ||
89 | }; | ||
90 | |||
91 | |||
92 | static const struct pvr2_msp3400_ops msp3400_ops[] = { | ||
93 | { .update = set_stereo, .check = check_stereo}, | ||
94 | }; | ||
95 | |||
96 | |||
97 | static int msp3400_check(struct pvr2_msp3400_handler *ctxt) | ||
98 | { | ||
99 | unsigned long msk; | ||
100 | unsigned int idx; | ||
101 | |||
102 | for (idx = 0; idx < sizeof(msp3400_ops)/sizeof(msp3400_ops[0]); | ||
103 | idx++) { | ||
104 | msk = 1 << idx; | ||
105 | if (ctxt->stale_mask & msk) continue; | ||
106 | if (msp3400_ops[idx].check(ctxt)) { | ||
107 | ctxt->stale_mask |= msk; | ||
108 | } | ||
109 | } | ||
110 | return ctxt->stale_mask != 0; | ||
111 | } | ||
112 | |||
113 | |||
114 | static void msp3400_update(struct pvr2_msp3400_handler *ctxt) | ||
115 | { | ||
116 | unsigned long msk; | ||
117 | unsigned int idx; | ||
118 | |||
119 | for (idx = 0; idx < sizeof(msp3400_ops)/sizeof(msp3400_ops[0]); | ||
120 | idx++) { | ||
121 | msk = 1 << idx; | ||
122 | if (!(ctxt->stale_mask & msk)) continue; | ||
123 | ctxt->stale_mask &= ~msk; | ||
124 | msp3400_ops[idx].update(ctxt); | ||
125 | } | ||
126 | } | ||
127 | |||
128 | |||
129 | /* This reads back the current signal type */ | ||
130 | static int get_audio_status(struct pvr2_msp3400_handler *ctxt) | ||
131 | { | ||
132 | struct v4l2_tuner vt; | ||
133 | int stat; | ||
134 | |||
135 | memset(&vt,0,sizeof(vt)); | ||
136 | stat = pvr2_i2c_client_cmd(ctxt->client,VIDIOC_G_TUNER,&vt); | ||
137 | if (stat < 0) return stat; | ||
138 | |||
139 | ctxt->hdw->flag_stereo = (vt.audmode & V4L2_TUNER_MODE_STEREO) != 0; | ||
140 | ctxt->hdw->flag_bilingual = | ||
141 | (vt.audmode & V4L2_TUNER_MODE_LANG2) != 0; | ||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | |||
146 | static void pvr2_msp3400_detach(struct pvr2_msp3400_handler *ctxt) | ||
147 | { | ||
148 | ctxt->client->handler = 0; | ||
149 | ctxt->hdw->audio_stat = 0; | ||
150 | kfree(ctxt); | ||
151 | } | ||
152 | |||
153 | |||
154 | static unsigned int pvr2_msp3400_describe(struct pvr2_msp3400_handler *ctxt, | ||
155 | char *buf,unsigned int cnt) | ||
156 | { | ||
157 | return scnprintf(buf,cnt,"handler: pvrusb2-audio v4l2"); | ||
158 | } | ||
159 | |||
160 | |||
161 | const static struct pvr2_i2c_handler_functions msp3400_funcs = { | ||
162 | .detach = (void (*)(void *))pvr2_msp3400_detach, | ||
163 | .check = (int (*)(void *))msp3400_check, | ||
164 | .update = (void (*)(void *))msp3400_update, | ||
165 | .describe = (unsigned int (*)(void *,char *,unsigned int))pvr2_msp3400_describe, | ||
166 | }; | ||
167 | |||
168 | |||
169 | int pvr2_i2c_msp3400_setup(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp) | ||
170 | { | ||
171 | struct pvr2_msp3400_handler *ctxt; | ||
172 | if (hdw->audio_stat) return 0; | ||
173 | if (cp->handler) return 0; | ||
174 | |||
175 | ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL); | ||
176 | if (!ctxt) return 0; | ||
177 | memset(ctxt,0,sizeof(*ctxt)); | ||
178 | |||
179 | ctxt->i2c_handler.func_data = ctxt; | ||
180 | ctxt->i2c_handler.func_table = &msp3400_funcs; | ||
181 | ctxt->client = cp; | ||
182 | ctxt->hdw = hdw; | ||
183 | ctxt->astat.ctxt = ctxt; | ||
184 | ctxt->astat.status = (int (*)(void *))get_audio_status; | ||
185 | ctxt->astat.detach = (void (*)(void *))pvr2_msp3400_detach; | ||
186 | ctxt->stale_mask = (1 << (sizeof(msp3400_ops)/ | ||
187 | sizeof(msp3400_ops[0]))) - 1; | ||
188 | cp->handler = &ctxt->i2c_handler; | ||
189 | hdw->audio_stat = &ctxt->astat; | ||
190 | pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x msp3400 V4L2 handler set up", | ||
191 | cp->client->addr); | ||
192 | return !0; | ||
193 | } | ||
194 | |||
195 | |||
196 | /* | ||
197 | Stuff for Emacs to see, in order to encourage consistent editing style: | ||
198 | *** Local Variables: *** | ||
199 | *** mode: c *** | ||
200 | *** fill-column: 70 *** | ||
201 | *** tab-width: 8 *** | ||
202 | *** c-basic-offset: 8 *** | ||
203 | *** End: *** | ||
204 | */ | ||
diff --git a/drivers/media/video/pvrusb2/pvrusb2-audio.h b/drivers/media/video/pvrusb2/pvrusb2-audio.h new file mode 100644 index 000000000000..536339b68843 --- /dev/null +++ b/drivers/media/video/pvrusb2/pvrusb2-audio.h | |||
@@ -0,0 +1,40 @@ | |||
1 | /* | ||
2 | * | ||
3 | * $Id$ | ||
4 | * | ||
5 | * Copyright (C) 2005 Mike Isely <isely@pobox.com> | ||
6 | * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License | ||
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 | |||
23 | #ifndef __PVRUSB2_AUDIO_H | ||
24 | #define __PVRUSB2_AUDIO_H | ||
25 | |||
26 | #include "pvrusb2-i2c-core.h" | ||
27 | |||
28 | int pvr2_i2c_msp3400_setup(struct pvr2_hdw *,struct pvr2_i2c_client *); | ||
29 | |||
30 | #endif /* __PVRUSB2_AUDIO_H */ | ||
31 | |||
32 | /* | ||
33 | Stuff for Emacs to see, in order to encourage consistent editing style: | ||
34 | *** Local Variables: *** | ||
35 | *** mode: c *** | ||
36 | *** fill-column: 70 *** | ||
37 | *** tab-width: 8 *** | ||
38 | *** c-basic-offset: 8 *** | ||
39 | *** End: *** | ||
40 | */ | ||
diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.c b/drivers/media/video/pvrusb2/pvrusb2-context.c new file mode 100644 index 000000000000..40dc59871a45 --- /dev/null +++ b/drivers/media/video/pvrusb2/pvrusb2-context.c | |||
@@ -0,0 +1,230 @@ | |||
1 | /* | ||
2 | * $Id$ | ||
3 | * | ||
4 | * Copyright (C) 2005 Mike Isely <isely@pobox.com> | ||
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 as published by | ||
8 | * the Free Software Foundation; either version 2 of the License | ||
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 | |||
21 | #include "pvrusb2-context.h" | ||
22 | #include "pvrusb2-io.h" | ||
23 | #include "pvrusb2-ioread.h" | ||
24 | #include "pvrusb2-hdw.h" | ||
25 | #include "pvrusb2-debug.h" | ||
26 | #include <linux/errno.h> | ||
27 | #include <linux/string.h> | ||
28 | #include <linux/slab.h> | ||
29 | #include <asm/semaphore.h> | ||
30 | |||
31 | |||
32 | static void pvr2_context_destroy(struct pvr2_context *mp) | ||
33 | { | ||
34 | if (mp->hdw) pvr2_hdw_destroy(mp->hdw); | ||
35 | pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr_main id=%p",mp); | ||
36 | flush_workqueue(mp->workqueue); | ||
37 | destroy_workqueue(mp->workqueue); | ||
38 | kfree(mp); | ||
39 | } | ||
40 | |||
41 | |||
42 | static void pvr2_context_trigger_poll(struct pvr2_context *mp) | ||
43 | { | ||
44 | queue_work(mp->workqueue,&mp->workpoll); | ||
45 | } | ||
46 | |||
47 | |||
48 | static void pvr2_context_poll(struct pvr2_context *mp) | ||
49 | { | ||
50 | pvr2_context_enter(mp); do { | ||
51 | pvr2_hdw_poll(mp->hdw); | ||
52 | } while (0); pvr2_context_exit(mp); | ||
53 | } | ||
54 | |||
55 | |||
56 | static void pvr2_context_setup(struct pvr2_context *mp) | ||
57 | { | ||
58 | pvr2_context_enter(mp); do { | ||
59 | if (!pvr2_hdw_dev_ok(mp->hdw)) break; | ||
60 | pvr2_hdw_setup(mp->hdw); | ||
61 | pvr2_hdw_setup_poll_trigger( | ||
62 | mp->hdw, | ||
63 | (void (*)(void *))pvr2_context_trigger_poll, | ||
64 | mp); | ||
65 | if (!pvr2_hdw_dev_ok(mp->hdw)) break; | ||
66 | if (!pvr2_hdw_init_ok(mp->hdw)) break; | ||
67 | mp->video_stream.stream = pvr2_hdw_get_video_stream(mp->hdw); | ||
68 | if (mp->setup_func) { | ||
69 | mp->setup_func(mp); | ||
70 | } | ||
71 | } while (0); pvr2_context_exit(mp); | ||
72 | } | ||
73 | |||
74 | |||
75 | struct pvr2_context *pvr2_context_create( | ||
76 | struct usb_interface *intf, | ||
77 | const struct usb_device_id *devid, | ||
78 | void (*setup_func)(struct pvr2_context *)) | ||
79 | { | ||
80 | struct pvr2_context *mp = 0; | ||
81 | mp = kmalloc(sizeof(*mp),GFP_KERNEL); | ||
82 | if (!mp) goto done; | ||
83 | memset(mp,0,sizeof(*mp)); | ||
84 | pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr_main id=%p",mp); | ||
85 | mp->setup_func = setup_func; | ||
86 | mutex_init(&mp->mutex); | ||
87 | mp->hdw = pvr2_hdw_create(intf,devid); | ||
88 | if (!mp->hdw) { | ||
89 | pvr2_context_destroy(mp); | ||
90 | mp = 0; | ||
91 | goto done; | ||
92 | } | ||
93 | |||
94 | mp->workqueue = create_singlethread_workqueue("pvrusb2"); | ||
95 | INIT_WORK(&mp->workinit,(void (*)(void*))pvr2_context_setup,mp); | ||
96 | INIT_WORK(&mp->workpoll,(void (*)(void*))pvr2_context_poll,mp); | ||
97 | queue_work(mp->workqueue,&mp->workinit); | ||
98 | done: | ||
99 | return mp; | ||
100 | } | ||
101 | |||
102 | |||
103 | void pvr2_context_enter(struct pvr2_context *mp) | ||
104 | { | ||
105 | mutex_lock(&mp->mutex); | ||
106 | pvr2_trace(PVR2_TRACE_CREG,"pvr2_context_enter(id=%p)",mp); | ||
107 | } | ||
108 | |||
109 | |||
110 | void pvr2_context_exit(struct pvr2_context *mp) | ||
111 | { | ||
112 | int destroy_flag = 0; | ||
113 | if (!(mp->mc_first || !mp->disconnect_flag)) { | ||
114 | destroy_flag = !0; | ||
115 | } | ||
116 | pvr2_trace(PVR2_TRACE_CREG,"pvr2_context_exit(id=%p) outside",mp); | ||
117 | mutex_unlock(&mp->mutex); | ||
118 | if (destroy_flag) pvr2_context_destroy(mp); | ||
119 | } | ||
120 | |||
121 | |||
122 | static void pvr2_context_run_checks(struct pvr2_context *mp) | ||
123 | { | ||
124 | struct pvr2_channel *ch1,*ch2; | ||
125 | for (ch1 = mp->mc_first; ch1; ch1 = ch2) { | ||
126 | ch2 = ch1->mc_next; | ||
127 | if (ch1->check_func) { | ||
128 | ch1->check_func(ch1); | ||
129 | } | ||
130 | } | ||
131 | } | ||
132 | |||
133 | |||
134 | void pvr2_context_disconnect(struct pvr2_context *mp) | ||
135 | { | ||
136 | pvr2_context_enter(mp); do { | ||
137 | pvr2_hdw_disconnect(mp->hdw); | ||
138 | mp->disconnect_flag = !0; | ||
139 | pvr2_context_run_checks(mp); | ||
140 | } while (0); pvr2_context_exit(mp); | ||
141 | } | ||
142 | |||
143 | |||
144 | void pvr2_channel_init(struct pvr2_channel *cp,struct pvr2_context *mp) | ||
145 | { | ||
146 | cp->hdw = mp->hdw; | ||
147 | cp->mc_head = mp; | ||
148 | cp->mc_next = 0; | ||
149 | cp->mc_prev = mp->mc_last; | ||
150 | if (mp->mc_last) { | ||
151 | mp->mc_last->mc_next = cp; | ||
152 | } else { | ||
153 | mp->mc_first = cp; | ||
154 | } | ||
155 | mp->mc_last = cp; | ||
156 | } | ||
157 | |||
158 | |||
159 | static void pvr2_channel_disclaim_stream(struct pvr2_channel *cp) | ||
160 | { | ||
161 | if (!cp->stream) return; | ||
162 | pvr2_stream_kill(cp->stream->stream); | ||
163 | cp->stream->user = 0; | ||
164 | cp->stream = 0; | ||
165 | } | ||
166 | |||
167 | |||
168 | void pvr2_channel_done(struct pvr2_channel *cp) | ||
169 | { | ||
170 | struct pvr2_context *mp = cp->mc_head; | ||
171 | pvr2_channel_disclaim_stream(cp); | ||
172 | if (cp->mc_next) { | ||
173 | cp->mc_next->mc_prev = cp->mc_prev; | ||
174 | } else { | ||
175 | mp->mc_last = cp->mc_prev; | ||
176 | } | ||
177 | if (cp->mc_prev) { | ||
178 | cp->mc_prev->mc_next = cp->mc_next; | ||
179 | } else { | ||
180 | mp->mc_first = cp->mc_next; | ||
181 | } | ||
182 | cp->hdw = 0; | ||
183 | } | ||
184 | |||
185 | |||
186 | int pvr2_channel_claim_stream(struct pvr2_channel *cp, | ||
187 | struct pvr2_context_stream *sp) | ||
188 | { | ||
189 | int code = 0; | ||
190 | pvr2_context_enter(cp->mc_head); do { | ||
191 | if (sp == cp->stream) break; | ||
192 | if (sp->user) { | ||
193 | code = -EBUSY; | ||
194 | break; | ||
195 | } | ||
196 | pvr2_channel_disclaim_stream(cp); | ||
197 | if (!sp) break; | ||
198 | sp->user = cp; | ||
199 | cp->stream = sp; | ||
200 | } while (0); pvr2_context_exit(cp->mc_head); | ||
201 | return code; | ||
202 | } | ||
203 | |||
204 | |||
205 | // This is the marker for the real beginning of a legitimate mpeg2 stream. | ||
206 | static char stream_sync_key[] = { | ||
207 | 0x00, 0x00, 0x01, 0xba, | ||
208 | }; | ||
209 | |||
210 | struct pvr2_ioread *pvr2_channel_create_mpeg_stream( | ||
211 | struct pvr2_context_stream *sp) | ||
212 | { | ||
213 | struct pvr2_ioread *cp; | ||
214 | cp = pvr2_ioread_create(); | ||
215 | if (!cp) return 0; | ||
216 | pvr2_ioread_setup(cp,sp->stream); | ||
217 | pvr2_ioread_set_sync_key(cp,stream_sync_key,sizeof(stream_sync_key)); | ||
218 | return cp; | ||
219 | } | ||
220 | |||
221 | |||
222 | /* | ||
223 | Stuff for Emacs to see, in order to encourage consistent editing style: | ||
224 | *** Local Variables: *** | ||
225 | *** mode: c *** | ||
226 | *** fill-column: 75 *** | ||
227 | *** tab-width: 8 *** | ||
228 | *** c-basic-offset: 8 *** | ||
229 | *** End: *** | ||
230 | */ | ||
diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.h b/drivers/media/video/pvrusb2/pvrusb2-context.h new file mode 100644 index 000000000000..6327fa1f7e4f --- /dev/null +++ b/drivers/media/video/pvrusb2/pvrusb2-context.h | |||
@@ -0,0 +1,92 @@ | |||
1 | /* | ||
2 | * $Id$ | ||
3 | * | ||
4 | * Copyright (C) 2005 Mike Isely <isely@pobox.com> | ||
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 as published by | ||
8 | * the Free Software Foundation; either version 2 of the License | ||
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 | #ifndef __PVRUSB2_BASE_H | ||
21 | #define __PVRUSB2_BASE_H | ||
22 | |||
23 | #include <linux/mutex.h> | ||
24 | #include <linux/usb.h> | ||
25 | #include <linux/workqueue.h> | ||
26 | |||
27 | struct pvr2_hdw; /* hardware interface - defined elsewhere */ | ||
28 | struct pvr2_stream; /* stream interface - defined elsewhere */ | ||
29 | |||
30 | struct pvr2_context; /* All central state */ | ||
31 | struct pvr2_channel; /* One I/O pathway to a user */ | ||
32 | struct pvr2_context_stream; /* Wrapper for a stream */ | ||
33 | struct pvr2_crit_reg; /* Critical region pointer */ | ||
34 | struct pvr2_ioread; /* Low level stream structure */ | ||
35 | |||
36 | struct pvr2_context_stream { | ||
37 | struct pvr2_channel *user; | ||
38 | struct pvr2_stream *stream; | ||
39 | }; | ||
40 | |||
41 | struct pvr2_context { | ||
42 | struct pvr2_channel *mc_first; | ||
43 | struct pvr2_channel *mc_last; | ||
44 | struct pvr2_hdw *hdw; | ||
45 | struct pvr2_context_stream video_stream; | ||
46 | struct mutex mutex; | ||
47 | int disconnect_flag; | ||
48 | |||
49 | /* Called after pvr2_context initialization is complete */ | ||
50 | void (*setup_func)(struct pvr2_context *); | ||
51 | |||
52 | /* Work queue overhead for out-of-line processing */ | ||
53 | struct workqueue_struct *workqueue; | ||
54 | struct work_struct workinit; | ||
55 | struct work_struct workpoll; | ||
56 | }; | ||
57 | |||
58 | struct pvr2_channel { | ||
59 | struct pvr2_context *mc_head; | ||
60 | struct pvr2_channel *mc_next; | ||
61 | struct pvr2_channel *mc_prev; | ||
62 | struct pvr2_context_stream *stream; | ||
63 | struct pvr2_hdw *hdw; | ||
64 | void (*check_func)(struct pvr2_channel *); | ||
65 | }; | ||
66 | |||
67 | void pvr2_context_enter(struct pvr2_context *); | ||
68 | void pvr2_context_exit(struct pvr2_context *); | ||
69 | |||
70 | struct pvr2_context *pvr2_context_create(struct usb_interface *intf, | ||
71 | const struct usb_device_id *devid, | ||
72 | void (*setup_func)(struct pvr2_context *)); | ||
73 | void pvr2_context_disconnect(struct pvr2_context *); | ||
74 | |||
75 | void pvr2_channel_init(struct pvr2_channel *,struct pvr2_context *); | ||
76 | void pvr2_channel_done(struct pvr2_channel *); | ||
77 | int pvr2_channel_claim_stream(struct pvr2_channel *, | ||
78 | struct pvr2_context_stream *); | ||
79 | struct pvr2_ioread *pvr2_channel_create_mpeg_stream( | ||
80 | struct pvr2_context_stream *); | ||
81 | |||
82 | |||
83 | #endif /* __PVRUSB2_CONTEXT_H */ | ||
84 | /* | ||
85 | Stuff for Emacs to see, in order to encourage consistent editing style: | ||
86 | *** Local Variables: *** | ||
87 | *** mode: c *** | ||
88 | *** fill-column: 75 *** | ||
89 | *** tab-width: 8 *** | ||
90 | *** c-basic-offset: 8 *** | ||
91 | *** End: *** | ||
92 | */ | ||
diff --git a/drivers/media/video/pvrusb2/pvrusb2-ctrl.c b/drivers/media/video/pvrusb2/pvrusb2-ctrl.c new file mode 100644 index 000000000000..d5df9fbeba2f --- /dev/null +++ b/drivers/media/video/pvrusb2/pvrusb2-ctrl.c | |||
@@ -0,0 +1,593 @@ | |||
1 | /* | ||
2 | * | ||
3 | * $Id$ | ||
4 | * | ||
5 | * Copyright (C) 2005 Mike Isely <isely@pobox.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 | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include "pvrusb2-ctrl.h" | ||
23 | #include "pvrusb2-hdw-internal.h" | ||
24 | #include <linux/errno.h> | ||
25 | #include <linux/string.h> | ||
26 | #include <linux/mutex.h> | ||
27 | |||
28 | |||
29 | /* Set the given control. */ | ||
30 | int pvr2_ctrl_set_value(struct pvr2_ctrl *cptr,int val) | ||
31 | { | ||
32 | return pvr2_ctrl_set_mask_value(cptr,~0,val); | ||
33 | } | ||
34 | |||
35 | |||
36 | /* Set/clear specific bits of the given control. */ | ||
37 | int pvr2_ctrl_set_mask_value(struct pvr2_ctrl *cptr,int mask,int val) | ||
38 | { | ||
39 | int ret = 0; | ||
40 | if (!cptr) return -EINVAL; | ||
41 | LOCK_TAKE(cptr->hdw->big_lock); do { | ||
42 | if (cptr->info->set_value != 0) { | ||
43 | if (cptr->info->type == pvr2_ctl_bitmask) { | ||
44 | mask &= cptr->info->def.type_bitmask.valid_bits; | ||
45 | } else if (cptr->info->type == pvr2_ctl_int) { | ||
46 | if (val < cptr->info->def.type_int.min_value) { | ||
47 | break; | ||
48 | } | ||
49 | if (val > cptr->info->def.type_int.max_value) { | ||
50 | break; | ||
51 | } | ||
52 | } else if (cptr->info->type == pvr2_ctl_enum) { | ||
53 | if (val >= cptr->info->def.type_enum.count) { | ||
54 | break; | ||
55 | } | ||
56 | } else if (cptr->info->type != pvr2_ctl_bool) { | ||
57 | break; | ||
58 | } | ||
59 | ret = cptr->info->set_value(cptr,mask,val); | ||
60 | } else { | ||
61 | ret = -EPERM; | ||
62 | } | ||
63 | } while(0); LOCK_GIVE(cptr->hdw->big_lock); | ||
64 | return ret; | ||
65 | } | ||
66 | |||
67 | |||
68 | /* Get the current value of the given control. */ | ||
69 | int pvr2_ctrl_get_value(struct pvr2_ctrl *cptr,int *valptr) | ||
70 | { | ||
71 | int ret = 0; | ||
72 | if (!cptr) return -EINVAL; | ||
73 | LOCK_TAKE(cptr->hdw->big_lock); do { | ||
74 | ret = cptr->info->get_value(cptr,valptr); | ||
75 | } while(0); LOCK_GIVE(cptr->hdw->big_lock); | ||
76 | return ret; | ||
77 | } | ||
78 | |||
79 | |||
80 | /* Retrieve control's type */ | ||
81 | enum pvr2_ctl_type pvr2_ctrl_get_type(struct pvr2_ctrl *cptr) | ||
82 | { | ||
83 | if (!cptr) return pvr2_ctl_int; | ||
84 | return cptr->info->type; | ||
85 | } | ||
86 | |||
87 | |||
88 | /* Retrieve control's maximum value (int type) */ | ||
89 | int pvr2_ctrl_get_max(struct pvr2_ctrl *cptr) | ||
90 | { | ||
91 | int ret = 0; | ||
92 | if (!cptr) return 0; | ||
93 | LOCK_TAKE(cptr->hdw->big_lock); do { | ||
94 | if (cptr->info->type == pvr2_ctl_int) { | ||
95 | ret = cptr->info->def.type_int.max_value; | ||
96 | } | ||
97 | } while(0); LOCK_GIVE(cptr->hdw->big_lock); | ||
98 | return ret; | ||
99 | } | ||
100 | |||
101 | |||
102 | /* Retrieve control's minimum value (int type) */ | ||
103 | int pvr2_ctrl_get_min(struct pvr2_ctrl *cptr) | ||
104 | { | ||
105 | int ret = 0; | ||
106 | if (!cptr) return 0; | ||
107 | LOCK_TAKE(cptr->hdw->big_lock); do { | ||
108 | if (cptr->info->type == pvr2_ctl_int) { | ||
109 | ret = cptr->info->def.type_int.min_value; | ||
110 | } | ||
111 | } while(0); LOCK_GIVE(cptr->hdw->big_lock); | ||
112 | return ret; | ||
113 | } | ||
114 | |||
115 | |||
116 | /* Retrieve control's default value (any type) */ | ||
117 | int pvr2_ctrl_get_def(struct pvr2_ctrl *cptr) | ||
118 | { | ||
119 | int ret = 0; | ||
120 | if (!cptr) return 0; | ||
121 | LOCK_TAKE(cptr->hdw->big_lock); do { | ||
122 | if (cptr->info->type == pvr2_ctl_int) { | ||
123 | ret = cptr->info->default_value; | ||
124 | } | ||
125 | } while(0); LOCK_GIVE(cptr->hdw->big_lock); | ||
126 | return ret; | ||
127 | } | ||
128 | |||
129 | |||
130 | /* Retrieve control's enumeration count (enum only) */ | ||
131 | int pvr2_ctrl_get_cnt(struct pvr2_ctrl *cptr) | ||
132 | { | ||
133 | int ret = 0; | ||
134 | if (!cptr) return 0; | ||
135 | LOCK_TAKE(cptr->hdw->big_lock); do { | ||
136 | if (cptr->info->type == pvr2_ctl_enum) { | ||
137 | ret = cptr->info->def.type_enum.count; | ||
138 | } | ||
139 | } while(0); LOCK_GIVE(cptr->hdw->big_lock); | ||
140 | return ret; | ||
141 | } | ||
142 | |||
143 | |||
144 | /* Retrieve control's valid mask bits (bit mask only) */ | ||
145 | int pvr2_ctrl_get_mask(struct pvr2_ctrl *cptr) | ||
146 | { | ||
147 | int ret = 0; | ||
148 | if (!cptr) return 0; | ||
149 | LOCK_TAKE(cptr->hdw->big_lock); do { | ||
150 | if (cptr->info->type == pvr2_ctl_bitmask) { | ||
151 | ret = cptr->info->def.type_bitmask.valid_bits; | ||
152 | } | ||
153 | } while(0); LOCK_GIVE(cptr->hdw->big_lock); | ||
154 | return ret; | ||
155 | } | ||
156 | |||
157 | |||
158 | /* Retrieve the control's name */ | ||
159 | const char *pvr2_ctrl_get_name(struct pvr2_ctrl *cptr) | ||
160 | { | ||
161 | if (!cptr) return 0; | ||
162 | return cptr->info->name; | ||
163 | } | ||
164 | |||
165 | |||
166 | /* Retrieve the control's desc */ | ||
167 | const char *pvr2_ctrl_get_desc(struct pvr2_ctrl *cptr) | ||
168 | { | ||
169 | if (!cptr) return 0; | ||
170 | return cptr->info->desc; | ||
171 | } | ||
172 | |||
173 | |||
174 | /* Retrieve a control enumeration or bit mask value */ | ||
175 | int pvr2_ctrl_get_valname(struct pvr2_ctrl *cptr,int val, | ||
176 | char *bptr,unsigned int bmax, | ||
177 | unsigned int *blen) | ||
178 | { | ||
179 | int ret = -EINVAL; | ||
180 | if (!cptr) return 0; | ||
181 | *blen = 0; | ||
182 | LOCK_TAKE(cptr->hdw->big_lock); do { | ||
183 | if (cptr->info->type == pvr2_ctl_enum) { | ||
184 | const char **names; | ||
185 | names = cptr->info->def.type_enum.value_names; | ||
186 | if ((val >= 0) && | ||
187 | (val < cptr->info->def.type_enum.count)) { | ||
188 | if (names[val]) { | ||
189 | *blen = scnprintf( | ||
190 | bptr,bmax,"%s", | ||
191 | names[val]); | ||
192 | } else { | ||
193 | *blen = 0; | ||
194 | } | ||
195 | ret = 0; | ||
196 | } | ||
197 | } else if (cptr->info->type == pvr2_ctl_bitmask) { | ||
198 | const char **names; | ||
199 | unsigned int idx; | ||
200 | int msk; | ||
201 | names = cptr->info->def.type_bitmask.bit_names; | ||
202 | val &= cptr->info->def.type_bitmask.valid_bits; | ||
203 | for (idx = 0, msk = 1; val; idx++, msk <<= 1) { | ||
204 | if (val & msk) { | ||
205 | *blen = scnprintf(bptr,bmax,"%s", | ||
206 | names[idx]); | ||
207 | ret = 0; | ||
208 | break; | ||
209 | } | ||
210 | } | ||
211 | } | ||
212 | } while(0); LOCK_GIVE(cptr->hdw->big_lock); | ||
213 | return ret; | ||
214 | } | ||
215 | |||
216 | |||
217 | /* Return V4L ID for this control or zero if none */ | ||
218 | int pvr2_ctrl_get_v4lid(struct pvr2_ctrl *cptr) | ||
219 | { | ||
220 | if (!cptr) return 0; | ||
221 | return cptr->info->v4l_id; | ||
222 | } | ||
223 | |||
224 | |||
225 | unsigned int pvr2_ctrl_get_v4lflags(struct pvr2_ctrl *cptr) | ||
226 | { | ||
227 | unsigned int flags = 0; | ||
228 | |||
229 | if (cptr->info->get_v4lflags) { | ||
230 | flags = cptr->info->get_v4lflags(cptr); | ||
231 | } | ||
232 | |||
233 | if (cptr->info->set_value) { | ||
234 | flags &= ~V4L2_CTRL_FLAG_READ_ONLY; | ||
235 | } else { | ||
236 | flags |= V4L2_CTRL_FLAG_READ_ONLY; | ||
237 | } | ||
238 | |||
239 | return flags; | ||
240 | } | ||
241 | |||
242 | |||
243 | /* Return true if control is writable */ | ||
244 | int pvr2_ctrl_is_writable(struct pvr2_ctrl *cptr) | ||
245 | { | ||
246 | if (!cptr) return 0; | ||
247 | return cptr->info->set_value != 0; | ||
248 | } | ||
249 | |||
250 | |||
251 | /* Return true if control has custom symbolic representation */ | ||
252 | int pvr2_ctrl_has_custom_symbols(struct pvr2_ctrl *cptr) | ||
253 | { | ||
254 | if (!cptr) return 0; | ||
255 | if (!cptr->info->val_to_sym) return 0; | ||
256 | if (!cptr->info->sym_to_val) return 0; | ||
257 | return !0; | ||
258 | } | ||
259 | |||
260 | |||
261 | /* Convert a given mask/val to a custom symbolic value */ | ||
262 | int pvr2_ctrl_custom_value_to_sym(struct pvr2_ctrl *cptr, | ||
263 | int mask,int val, | ||
264 | char *buf,unsigned int maxlen, | ||
265 | unsigned int *len) | ||
266 | { | ||
267 | if (!cptr) return -EINVAL; | ||
268 | if (!cptr->info->val_to_sym) return -EINVAL; | ||
269 | return cptr->info->val_to_sym(cptr,mask,val,buf,maxlen,len); | ||
270 | } | ||
271 | |||
272 | |||
273 | /* Convert a symbolic value to a mask/value pair */ | ||
274 | int pvr2_ctrl_custom_sym_to_value(struct pvr2_ctrl *cptr, | ||
275 | const char *buf,unsigned int len, | ||
276 | int *maskptr,int *valptr) | ||
277 | { | ||
278 | if (!cptr) return -EINVAL; | ||
279 | if (!cptr->info->sym_to_val) return -EINVAL; | ||
280 | return cptr->info->sym_to_val(cptr,buf,len,maskptr,valptr); | ||
281 | } | ||
282 | |||
283 | |||
284 | static unsigned int gen_bitmask_string(int msk,int val,int msk_only, | ||
285 | const char **names, | ||
286 | char *ptr,unsigned int len) | ||
287 | { | ||
288 | unsigned int idx; | ||
289 | long sm,um; | ||
290 | int spcFl; | ||
291 | unsigned int uc,cnt; | ||
292 | const char *idStr; | ||
293 | |||
294 | spcFl = 0; | ||
295 | uc = 0; | ||
296 | um = 0; | ||
297 | for (idx = 0, sm = 1; msk; idx++, sm <<= 1) { | ||
298 | if (sm & msk) { | ||
299 | msk &= ~sm; | ||
300 | idStr = names[idx]; | ||
301 | if (idStr) { | ||
302 | cnt = scnprintf(ptr,len,"%s%s%s", | ||
303 | (spcFl ? " " : ""), | ||
304 | (msk_only ? "" : | ||
305 | ((val & sm) ? "+" : "-")), | ||
306 | idStr); | ||
307 | ptr += cnt; len -= cnt; uc += cnt; | ||
308 | spcFl = !0; | ||
309 | } else { | ||
310 | um |= sm; | ||
311 | } | ||
312 | } | ||
313 | } | ||
314 | if (um) { | ||
315 | if (msk_only) { | ||
316 | cnt = scnprintf(ptr,len,"%s0x%lx", | ||
317 | (spcFl ? " " : ""), | ||
318 | um); | ||
319 | ptr += cnt; len -= cnt; uc += cnt; | ||
320 | spcFl = !0; | ||
321 | } else if (um & val) { | ||
322 | cnt = scnprintf(ptr,len,"%s+0x%lx", | ||
323 | (spcFl ? " " : ""), | ||
324 | um & val); | ||
325 | ptr += cnt; len -= cnt; uc += cnt; | ||
326 | spcFl = !0; | ||
327 | } else if (um & ~val) { | ||
328 | cnt = scnprintf(ptr,len,"%s+0x%lx", | ||
329 | (spcFl ? " " : ""), | ||
330 | um & ~val); | ||
331 | ptr += cnt; len -= cnt; uc += cnt; | ||
332 | spcFl = !0; | ||
333 | } | ||
334 | } | ||
335 | return uc; | ||
336 | } | ||
337 | |||
338 | |||
339 | static const char *boolNames[] = { | ||
340 | "false", | ||
341 | "true", | ||
342 | "no", | ||
343 | "yes", | ||
344 | }; | ||
345 | |||
346 | |||
347 | static int parse_token(const char *ptr,unsigned int len, | ||
348 | int *valptr, | ||
349 | const char **names,unsigned int namecnt) | ||
350 | { | ||
351 | char buf[33]; | ||
352 | unsigned int slen; | ||
353 | unsigned int idx; | ||
354 | int negfl; | ||
355 | char *p2; | ||
356 | *valptr = 0; | ||
357 | if (!names) namecnt = 0; | ||
358 | for (idx = 0; idx < namecnt; idx++) { | ||
359 | if (!names[idx]) continue; | ||
360 | slen = strlen(names[idx]); | ||
361 | if (slen != len) continue; | ||
362 | if (memcmp(names[idx],ptr,slen)) continue; | ||
363 | *valptr = idx; | ||
364 | return 0; | ||
365 | } | ||
366 | negfl = 0; | ||
367 | if ((*ptr == '-') || (*ptr == '+')) { | ||
368 | negfl = (*ptr == '-'); | ||
369 | ptr++; len--; | ||
370 | } | ||
371 | if (len >= sizeof(buf)) return -EINVAL; | ||
372 | memcpy(buf,ptr,len); | ||
373 | buf[len] = 0; | ||
374 | *valptr = simple_strtol(buf,&p2,0); | ||
375 | if (negfl) *valptr = -(*valptr); | ||
376 | if (*p2) return -EINVAL; | ||
377 | return 1; | ||
378 | } | ||
379 | |||
380 | |||
381 | static int parse_mtoken(const char *ptr,unsigned int len, | ||
382 | int *valptr, | ||
383 | const char **names,int valid_bits) | ||
384 | { | ||
385 | char buf[33]; | ||
386 | unsigned int slen; | ||
387 | unsigned int idx; | ||
388 | char *p2; | ||
389 | int msk; | ||
390 | *valptr = 0; | ||
391 | for (idx = 0, msk = 1; valid_bits; idx++, msk <<= 1) { | ||
392 | if (!msk & valid_bits) continue; | ||
393 | valid_bits &= ~msk; | ||
394 | if (!names[idx]) continue; | ||
395 | slen = strlen(names[idx]); | ||
396 | if (slen != len) continue; | ||
397 | if (memcmp(names[idx],ptr,slen)) continue; | ||
398 | *valptr = msk; | ||
399 | return 0; | ||
400 | } | ||
401 | if (len >= sizeof(buf)) return -EINVAL; | ||
402 | memcpy(buf,ptr,len); | ||
403 | buf[len] = 0; | ||
404 | *valptr = simple_strtol(buf,&p2,0); | ||
405 | if (*p2) return -EINVAL; | ||
406 | return 0; | ||
407 | } | ||
408 | |||
409 | |||
410 | static int parse_tlist(const char *ptr,unsigned int len, | ||
411 | int *maskptr,int *valptr, | ||
412 | const char **names,int valid_bits) | ||
413 | { | ||
414 | unsigned int cnt; | ||
415 | int mask,val,kv,mode,ret; | ||
416 | mask = 0; | ||
417 | val = 0; | ||
418 | ret = 0; | ||
419 | while (len) { | ||
420 | cnt = 0; | ||
421 | while ((cnt < len) && | ||
422 | ((ptr[cnt] <= 32) || | ||
423 | (ptr[cnt] >= 127))) cnt++; | ||
424 | ptr += cnt; | ||
425 | len -= cnt; | ||
426 | mode = 0; | ||
427 | if ((*ptr == '-') || (*ptr == '+')) { | ||
428 | mode = (*ptr == '-') ? -1 : 1; | ||
429 | ptr++; | ||
430 | len--; | ||
431 | } | ||
432 | cnt = 0; | ||
433 | while (cnt < len) { | ||
434 | if (ptr[cnt] <= 32) break; | ||
435 | if (ptr[cnt] >= 127) break; | ||
436 | cnt++; | ||
437 | } | ||
438 | if (!cnt) break; | ||
439 | if (parse_mtoken(ptr,cnt,&kv,names,valid_bits)) { | ||
440 | ret = -EINVAL; | ||
441 | break; | ||
442 | } | ||
443 | ptr += cnt; | ||
444 | len -= cnt; | ||
445 | switch (mode) { | ||
446 | case 0: | ||
447 | mask = valid_bits; | ||
448 | val |= kv; | ||
449 | break; | ||
450 | case -1: | ||
451 | mask |= kv; | ||
452 | val &= ~kv; | ||
453 | break; | ||
454 | case 1: | ||
455 | mask |= kv; | ||
456 | val |= kv; | ||
457 | break; | ||
458 | default: | ||
459 | break; | ||
460 | } | ||
461 | } | ||
462 | *maskptr = mask; | ||
463 | *valptr = val; | ||
464 | return ret; | ||
465 | } | ||
466 | |||
467 | |||
468 | /* Convert a symbolic value to a mask/value pair */ | ||
469 | int pvr2_ctrl_sym_to_value(struct pvr2_ctrl *cptr, | ||
470 | const char *ptr,unsigned int len, | ||
471 | int *maskptr,int *valptr) | ||
472 | { | ||
473 | int ret = -EINVAL; | ||
474 | unsigned int cnt; | ||
475 | |||
476 | *maskptr = 0; | ||
477 | *valptr = 0; | ||
478 | |||
479 | cnt = 0; | ||
480 | while ((cnt < len) && ((ptr[cnt] <= 32) || (ptr[cnt] >= 127))) cnt++; | ||
481 | len -= cnt; ptr += cnt; | ||
482 | cnt = 0; | ||
483 | while ((cnt < len) && ((ptr[len-(cnt+1)] <= 32) || | ||
484 | (ptr[len-(cnt+1)] >= 127))) cnt++; | ||
485 | len -= cnt; | ||
486 | |||
487 | if (!len) return -EINVAL; | ||
488 | |||
489 | LOCK_TAKE(cptr->hdw->big_lock); do { | ||
490 | if (cptr->info->type == pvr2_ctl_int) { | ||
491 | ret = parse_token(ptr,len,valptr,0,0); | ||
492 | if ((ret >= 0) && | ||
493 | ((*valptr < cptr->info->def.type_int.min_value) || | ||
494 | (*valptr > cptr->info->def.type_int.max_value))) { | ||
495 | ret = -ERANGE; | ||
496 | } | ||
497 | if (maskptr) *maskptr = ~0; | ||
498 | } else if (cptr->info->type == pvr2_ctl_bool) { | ||
499 | ret = parse_token( | ||
500 | ptr,len,valptr,boolNames, | ||
501 | sizeof(boolNames)/sizeof(boolNames[0])); | ||
502 | if (ret == 1) { | ||
503 | *valptr = *valptr ? !0 : 0; | ||
504 | } else if (ret == 0) { | ||
505 | *valptr = (*valptr & 1) ? !0 : 0; | ||
506 | } | ||
507 | if (maskptr) *maskptr = 1; | ||
508 | } else if (cptr->info->type == pvr2_ctl_enum) { | ||
509 | ret = parse_token( | ||
510 | ptr,len,valptr, | ||
511 | cptr->info->def.type_enum.value_names, | ||
512 | cptr->info->def.type_enum.count); | ||
513 | if ((ret >= 0) && | ||
514 | ((*valptr < 0) || | ||
515 | (*valptr >= cptr->info->def.type_enum.count))) { | ||
516 | ret = -ERANGE; | ||
517 | } | ||
518 | if (maskptr) *maskptr = ~0; | ||
519 | } else if (cptr->info->type == pvr2_ctl_bitmask) { | ||
520 | ret = parse_tlist( | ||
521 | ptr,len,maskptr,valptr, | ||
522 | cptr->info->def.type_bitmask.bit_names, | ||
523 | cptr->info->def.type_bitmask.valid_bits); | ||
524 | } | ||
525 | } while(0); LOCK_GIVE(cptr->hdw->big_lock); | ||
526 | return ret; | ||
527 | } | ||
528 | |||
529 | |||
530 | /* Convert a given mask/val to a symbolic value */ | ||
531 | int pvr2_ctrl_value_to_sym_internal(struct pvr2_ctrl *cptr, | ||
532 | int mask,int val, | ||
533 | char *buf,unsigned int maxlen, | ||
534 | unsigned int *len) | ||
535 | { | ||
536 | int ret = -EINVAL; | ||
537 | |||
538 | *len = 0; | ||
539 | if (cptr->info->type == pvr2_ctl_int) { | ||
540 | *len = scnprintf(buf,maxlen,"%d",val); | ||
541 | ret = 0; | ||
542 | } else if (cptr->info->type == pvr2_ctl_bool) { | ||
543 | *len = scnprintf(buf,maxlen,"%s",val ? "true" : "false"); | ||
544 | ret = 0; | ||
545 | } else if (cptr->info->type == pvr2_ctl_enum) { | ||
546 | const char **names; | ||
547 | names = cptr->info->def.type_enum.value_names; | ||
548 | if ((val >= 0) && | ||
549 | (val < cptr->info->def.type_enum.count)) { | ||
550 | if (names[val]) { | ||
551 | *len = scnprintf( | ||
552 | buf,maxlen,"%s", | ||
553 | names[val]); | ||
554 | } else { | ||
555 | *len = 0; | ||
556 | } | ||
557 | ret = 0; | ||
558 | } | ||
559 | } else if (cptr->info->type == pvr2_ctl_bitmask) { | ||
560 | *len = gen_bitmask_string( | ||
561 | val & mask & cptr->info->def.type_bitmask.valid_bits, | ||
562 | ~0,!0, | ||
563 | cptr->info->def.type_bitmask.bit_names, | ||
564 | buf,maxlen); | ||
565 | } | ||
566 | return ret; | ||
567 | } | ||
568 | |||
569 | |||
570 | /* Convert a given mask/val to a symbolic value */ | ||
571 | int pvr2_ctrl_value_to_sym(struct pvr2_ctrl *cptr, | ||
572 | int mask,int val, | ||
573 | char *buf,unsigned int maxlen, | ||
574 | unsigned int *len) | ||
575 | { | ||
576 | int ret; | ||
577 | LOCK_TAKE(cptr->hdw->big_lock); do { | ||
578 | ret = pvr2_ctrl_value_to_sym_internal(cptr,mask,val, | ||
579 | buf,maxlen,len); | ||
580 | } while(0); LOCK_GIVE(cptr->hdw->big_lock); | ||
581 | return ret; | ||
582 | } | ||
583 | |||
584 | |||
585 | /* | ||
586 | Stuff for Emacs to see, in order to encourage consistent editing style: | ||
587 | *** Local Variables: *** | ||
588 | *** mode: c *** | ||
589 | *** fill-column: 75 *** | ||
590 | *** tab-width: 8 *** | ||
591 | *** c-basic-offset: 8 *** | ||
592 | *** End: *** | ||
593 | */ | ||
diff --git a/drivers/media/video/pvrusb2/pvrusb2-ctrl.h b/drivers/media/video/pvrusb2/pvrusb2-ctrl.h new file mode 100644 index 000000000000..c1680053cd64 --- /dev/null +++ b/drivers/media/video/pvrusb2/pvrusb2-ctrl.h | |||
@@ -0,0 +1,123 @@ | |||
1 | /* | ||
2 | * | ||
3 | * $Id$ | ||
4 | * | ||
5 | * Copyright (C) 2005 Mike Isely <isely@pobox.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 | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | * | ||
20 | */ | ||
21 | #ifndef __PVRUSB2_CTRL_H | ||
22 | #define __PVRUSB2_CTRL_H | ||
23 | |||
24 | struct pvr2_ctrl; | ||
25 | |||
26 | enum pvr2_ctl_type { | ||
27 | pvr2_ctl_int = 0, | ||
28 | pvr2_ctl_enum = 1, | ||
29 | pvr2_ctl_bitmask = 2, | ||
30 | pvr2_ctl_bool = 3, | ||
31 | }; | ||
32 | |||
33 | |||
34 | /* Set the given control. */ | ||
35 | int pvr2_ctrl_set_value(struct pvr2_ctrl *,int val); | ||
36 | |||
37 | /* Set/clear specific bits of the given control. */ | ||
38 | int pvr2_ctrl_set_mask_value(struct pvr2_ctrl *,int mask,int val); | ||
39 | |||
40 | /* Get the current value of the given control. */ | ||
41 | int pvr2_ctrl_get_value(struct pvr2_ctrl *,int *valptr); | ||
42 | |||
43 | /* Retrieve control's type */ | ||
44 | enum pvr2_ctl_type pvr2_ctrl_get_type(struct pvr2_ctrl *); | ||
45 | |||
46 | /* Retrieve control's maximum value (int type) */ | ||
47 | int pvr2_ctrl_get_max(struct pvr2_ctrl *); | ||
48 | |||
49 | /* Retrieve control's minimum value (int type) */ | ||
50 | int pvr2_ctrl_get_min(struct pvr2_ctrl *); | ||
51 | |||
52 | /* Retrieve control's default value (any type) */ | ||
53 | int pvr2_ctrl_get_def(struct pvr2_ctrl *); | ||
54 | |||
55 | /* Retrieve control's enumeration count (enum only) */ | ||
56 | int pvr2_ctrl_get_cnt(struct pvr2_ctrl *); | ||
57 | |||
58 | /* Retrieve control's valid mask bits (bit mask only) */ | ||
59 | int pvr2_ctrl_get_mask(struct pvr2_ctrl *); | ||
60 | |||
61 | /* Retrieve the control's name */ | ||
62 | const char *pvr2_ctrl_get_name(struct pvr2_ctrl *); | ||
63 | |||
64 | /* Retrieve the control's desc */ | ||
65 | const char *pvr2_ctrl_get_desc(struct pvr2_ctrl *); | ||
66 | |||
67 | /* Retrieve a control enumeration or bit mask value */ | ||
68 | int pvr2_ctrl_get_valname(struct pvr2_ctrl *,int,char *,unsigned int, | ||
69 | unsigned int *); | ||
70 | |||
71 | /* Return true if control is writable */ | ||
72 | int pvr2_ctrl_is_writable(struct pvr2_ctrl *); | ||
73 | |||
74 | /* Return V4L flags value for control (or zero if there is no v4l control | ||
75 | actually under this control) */ | ||
76 | unsigned int pvr2_ctrl_get_v4lflags(struct pvr2_ctrl *); | ||
77 | |||
78 | /* Return V4L ID for this control or zero if none */ | ||
79 | int pvr2_ctrl_get_v4lid(struct pvr2_ctrl *); | ||
80 | |||
81 | /* Return true if control has custom symbolic representation */ | ||
82 | int pvr2_ctrl_has_custom_symbols(struct pvr2_ctrl *); | ||
83 | |||
84 | /* Convert a given mask/val to a custom symbolic value */ | ||
85 | int pvr2_ctrl_custom_value_to_sym(struct pvr2_ctrl *, | ||
86 | int mask,int val, | ||
87 | char *buf,unsigned int maxlen, | ||
88 | unsigned int *len); | ||
89 | |||
90 | /* Convert a symbolic value to a mask/value pair */ | ||
91 | int pvr2_ctrl_custom_sym_to_value(struct pvr2_ctrl *, | ||
92 | const char *buf,unsigned int len, | ||
93 | int *maskptr,int *valptr); | ||
94 | |||
95 | /* Convert a given mask/val to a symbolic value */ | ||
96 | int pvr2_ctrl_value_to_sym(struct pvr2_ctrl *, | ||
97 | int mask,int val, | ||
98 | char *buf,unsigned int maxlen, | ||
99 | unsigned int *len); | ||
100 | |||
101 | /* Convert a symbolic value to a mask/value pair */ | ||
102 | int pvr2_ctrl_sym_to_value(struct pvr2_ctrl *, | ||
103 | const char *buf,unsigned int len, | ||
104 | int *maskptr,int *valptr); | ||
105 | |||
106 | /* Convert a given mask/val to a symbolic value - must already be | ||
107 | inside of critical region. */ | ||
108 | int pvr2_ctrl_value_to_sym_internal(struct pvr2_ctrl *, | ||
109 | int mask,int val, | ||
110 | char *buf,unsigned int maxlen, | ||
111 | unsigned int *len); | ||
112 | |||
113 | #endif /* __PVRUSB2_CTRL_H */ | ||
114 | |||
115 | /* | ||
116 | Stuff for Emacs to see, in order to encourage consistent editing style: | ||
117 | *** Local Variables: *** | ||
118 | *** mode: c *** | ||
119 | *** fill-column: 75 *** | ||
120 | *** tab-width: 8 *** | ||
121 | *** c-basic-offset: 8 *** | ||
122 | *** End: *** | ||
123 | */ | ||
diff --git a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c new file mode 100644 index 000000000000..27eadaff75a0 --- /dev/null +++ b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c | |||
@@ -0,0 +1,279 @@ | |||
1 | /* | ||
2 | * | ||
3 | * $Id$ | ||
4 | * | ||
5 | * Copyright (C) 2005 Mike Isely <isely@pobox.com> | ||
6 | * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License | ||
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 | |||
23 | /* | ||
24 | |||
25 | This source file is specifically designed to interface with the | ||
26 | cx2584x, in kernels 2.6.16 or newer. | ||
27 | |||
28 | */ | ||
29 | |||
30 | #include "pvrusb2-cx2584x-v4l.h" | ||
31 | #include "pvrusb2-video-v4l.h" | ||
32 | #include "pvrusb2-i2c-cmd-v4l2.h" | ||
33 | |||
34 | |||
35 | #include "pvrusb2-hdw-internal.h" | ||
36 | #include "pvrusb2-debug.h" | ||
37 | #include <media/cx25840.h> | ||
38 | #include <linux/videodev2.h> | ||
39 | #include <media/v4l2-common.h> | ||
40 | #include <linux/errno.h> | ||
41 | #include <linux/slab.h> | ||
42 | |||
43 | struct pvr2_v4l_cx2584x { | ||
44 | struct pvr2_i2c_handler handler; | ||
45 | struct pvr2_decoder_ctrl ctrl; | ||
46 | struct pvr2_i2c_client *client; | ||
47 | struct pvr2_hdw *hdw; | ||
48 | unsigned long stale_mask; | ||
49 | }; | ||
50 | |||
51 | |||
52 | static void set_input(struct pvr2_v4l_cx2584x *ctxt) | ||
53 | { | ||
54 | struct pvr2_hdw *hdw = ctxt->hdw; | ||
55 | struct v4l2_routing route; | ||
56 | enum cx25840_video_input vid_input; | ||
57 | enum cx25840_audio_input aud_input; | ||
58 | |||
59 | memset(&route,0,sizeof(route)); | ||
60 | |||
61 | switch(hdw->input_val) { | ||
62 | case PVR2_CVAL_INPUT_TV: | ||
63 | vid_input = CX25840_COMPOSITE7; | ||
64 | aud_input = CX25840_AUDIO8; | ||
65 | break; | ||
66 | case PVR2_CVAL_INPUT_COMPOSITE: | ||
67 | vid_input = CX25840_COMPOSITE3; | ||
68 | aud_input = CX25840_AUDIO_SERIAL; | ||
69 | break; | ||
70 | case PVR2_CVAL_INPUT_SVIDEO: | ||
71 | vid_input = CX25840_SVIDEO1; | ||
72 | aud_input = CX25840_AUDIO_SERIAL; | ||
73 | break; | ||
74 | case PVR2_CVAL_INPUT_RADIO: | ||
75 | default: | ||
76 | // Just set it to be composite input for now... | ||
77 | vid_input = CX25840_COMPOSITE3; | ||
78 | aud_input = CX25840_AUDIO_SERIAL; | ||
79 | break; | ||
80 | } | ||
81 | |||
82 | pvr2_trace(PVR2_TRACE_CHIPS,"i2c cx2584x set_input vid=0x%x aud=0x%x", | ||
83 | vid_input,aud_input); | ||
84 | route.input = (u32)vid_input; | ||
85 | pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_VIDEO_ROUTING,&route); | ||
86 | route.input = (u32)aud_input; | ||
87 | pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_AUDIO_ROUTING,&route); | ||
88 | } | ||
89 | |||
90 | |||
91 | static int check_input(struct pvr2_v4l_cx2584x *ctxt) | ||
92 | { | ||
93 | struct pvr2_hdw *hdw = ctxt->hdw; | ||
94 | return hdw->input_dirty != 0; | ||
95 | } | ||
96 | |||
97 | |||
98 | static void set_audio(struct pvr2_v4l_cx2584x *ctxt) | ||
99 | { | ||
100 | u32 val; | ||
101 | struct pvr2_hdw *hdw = ctxt->hdw; | ||
102 | |||
103 | pvr2_trace(PVR2_TRACE_CHIPS,"i2c cx2584x set_audio %d", | ||
104 | hdw->srate_val); | ||
105 | switch (hdw->srate_val) { | ||
106 | default: | ||
107 | case V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000: | ||
108 | val = 48000; | ||
109 | break; | ||
110 | case V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100: | ||
111 | val = 44100; | ||
112 | break; | ||
113 | case V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000: | ||
114 | val = 32000; | ||
115 | break; | ||
116 | } | ||
117 | pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_AUDIO_CLOCK_FREQ,&val); | ||
118 | } | ||
119 | |||
120 | |||
121 | static int check_audio(struct pvr2_v4l_cx2584x *ctxt) | ||
122 | { | ||
123 | struct pvr2_hdw *hdw = ctxt->hdw; | ||
124 | return hdw->srate_dirty != 0; | ||
125 | } | ||
126 | |||
127 | |||
128 | struct pvr2_v4l_cx2584x_ops { | ||
129 | void (*update)(struct pvr2_v4l_cx2584x *); | ||
130 | int (*check)(struct pvr2_v4l_cx2584x *); | ||
131 | }; | ||
132 | |||
133 | |||
134 | static const struct pvr2_v4l_cx2584x_ops decoder_ops[] = { | ||
135 | { .update = set_input, .check = check_input}, | ||
136 | { .update = set_audio, .check = check_audio}, | ||
137 | }; | ||
138 | |||
139 | |||
140 | static void decoder_detach(struct pvr2_v4l_cx2584x *ctxt) | ||
141 | { | ||
142 | ctxt->client->handler = 0; | ||
143 | ctxt->hdw->decoder_ctrl = 0; | ||
144 | kfree(ctxt); | ||
145 | } | ||
146 | |||
147 | |||
148 | static int decoder_check(struct pvr2_v4l_cx2584x *ctxt) | ||
149 | { | ||
150 | unsigned long msk; | ||
151 | unsigned int idx; | ||
152 | |||
153 | for (idx = 0; idx < sizeof(decoder_ops)/sizeof(decoder_ops[0]); | ||
154 | idx++) { | ||
155 | msk = 1 << idx; | ||
156 | if (ctxt->stale_mask & msk) continue; | ||
157 | if (decoder_ops[idx].check(ctxt)) { | ||
158 | ctxt->stale_mask |= msk; | ||
159 | } | ||
160 | } | ||
161 | return ctxt->stale_mask != 0; | ||
162 | } | ||
163 | |||
164 | |||
165 | static void decoder_update(struct pvr2_v4l_cx2584x *ctxt) | ||
166 | { | ||
167 | unsigned long msk; | ||
168 | unsigned int idx; | ||
169 | |||
170 | for (idx = 0; idx < sizeof(decoder_ops)/sizeof(decoder_ops[0]); | ||
171 | idx++) { | ||
172 | msk = 1 << idx; | ||
173 | if (!(ctxt->stale_mask & msk)) continue; | ||
174 | ctxt->stale_mask &= ~msk; | ||
175 | decoder_ops[idx].update(ctxt); | ||
176 | } | ||
177 | } | ||
178 | |||
179 | |||
180 | static void decoder_enable(struct pvr2_v4l_cx2584x *ctxt,int fl) | ||
181 | { | ||
182 | pvr2_trace(PVR2_TRACE_CHIPS,"i2c cx25840 decoder_enable(%d)",fl); | ||
183 | pvr2_v4l2_cmd_stream(ctxt->client,fl); | ||
184 | } | ||
185 | |||
186 | |||
187 | static int decoder_detect(struct pvr2_i2c_client *cp) | ||
188 | { | ||
189 | int ret; | ||
190 | /* Attempt to query the decoder - let's see if it will answer */ | ||
191 | struct v4l2_queryctrl qc; | ||
192 | |||
193 | memset(&qc,0,sizeof(qc)); | ||
194 | |||
195 | qc.id = V4L2_CID_BRIGHTNESS; | ||
196 | |||
197 | ret = pvr2_i2c_client_cmd(cp,VIDIOC_QUERYCTRL,&qc); | ||
198 | return ret == 0; /* Return true if it answered */ | ||
199 | } | ||
200 | |||
201 | |||
202 | static int decoder_is_tuned(struct pvr2_v4l_cx2584x *ctxt) | ||
203 | { | ||
204 | struct v4l2_tuner vt; | ||
205 | int ret; | ||
206 | |||
207 | memset(&vt,0,sizeof(vt)); | ||
208 | ret = pvr2_i2c_client_cmd(ctxt->client,VIDIOC_G_TUNER,&vt); | ||
209 | if (ret < 0) return -EINVAL; | ||
210 | return vt.signal ? 1 : 0; | ||
211 | } | ||
212 | |||
213 | |||
214 | static unsigned int decoder_describe(struct pvr2_v4l_cx2584x *ctxt, | ||
215 | char *buf,unsigned int cnt) | ||
216 | { | ||
217 | return scnprintf(buf,cnt,"handler: pvrusb2-cx2584x-v4l"); | ||
218 | } | ||
219 | |||
220 | |||
221 | static void decoder_reset(struct pvr2_v4l_cx2584x *ctxt) | ||
222 | { | ||
223 | int ret; | ||
224 | ret = pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_RESET,0); | ||
225 | pvr2_trace(PVR2_TRACE_CHIPS,"i2c cx25840 decoder_reset (ret=%d)",ret); | ||
226 | } | ||
227 | |||
228 | |||
229 | const static struct pvr2_i2c_handler_functions hfuncs = { | ||
230 | .detach = (void (*)(void *))decoder_detach, | ||
231 | .check = (int (*)(void *))decoder_check, | ||
232 | .update = (void (*)(void *))decoder_update, | ||
233 | .describe = (unsigned int (*)(void *,char *,unsigned int))decoder_describe, | ||
234 | }; | ||
235 | |||
236 | |||
237 | int pvr2_i2c_cx2584x_v4l_setup(struct pvr2_hdw *hdw, | ||
238 | struct pvr2_i2c_client *cp) | ||
239 | { | ||
240 | struct pvr2_v4l_cx2584x *ctxt; | ||
241 | |||
242 | if (hdw->decoder_ctrl) return 0; | ||
243 | if (cp->handler) return 0; | ||
244 | if (!decoder_detect(cp)) return 0; | ||
245 | |||
246 | ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL); | ||
247 | if (!ctxt) return 0; | ||
248 | memset(ctxt,0,sizeof(*ctxt)); | ||
249 | |||
250 | ctxt->handler.func_data = ctxt; | ||
251 | ctxt->handler.func_table = &hfuncs; | ||
252 | ctxt->ctrl.ctxt = ctxt; | ||
253 | ctxt->ctrl.detach = (void (*)(void *))decoder_detach; | ||
254 | ctxt->ctrl.enable = (void (*)(void *,int))decoder_enable; | ||
255 | ctxt->ctrl.tuned = (int (*)(void *))decoder_is_tuned; | ||
256 | ctxt->ctrl.force_reset = (void (*)(void*))decoder_reset; | ||
257 | ctxt->client = cp; | ||
258 | ctxt->hdw = hdw; | ||
259 | ctxt->stale_mask = (1 << (sizeof(decoder_ops)/ | ||
260 | sizeof(decoder_ops[0]))) - 1; | ||
261 | hdw->decoder_ctrl = &ctxt->ctrl; | ||
262 | cp->handler = &ctxt->handler; | ||
263 | pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x cx2584x V4L2 handler set up", | ||
264 | cp->client->addr); | ||
265 | return !0; | ||
266 | } | ||
267 | |||
268 | |||
269 | |||
270 | |||
271 | /* | ||
272 | Stuff for Emacs to see, in order to encourage consistent editing style: | ||
273 | *** Local Variables: *** | ||
274 | *** mode: c *** | ||
275 | *** fill-column: 70 *** | ||
276 | *** tab-width: 8 *** | ||
277 | *** c-basic-offset: 8 *** | ||
278 | *** End: *** | ||
279 | */ | ||
diff --git a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h new file mode 100644 index 000000000000..54b2844e7a71 --- /dev/null +++ b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h | |||
@@ -0,0 +1,53 @@ | |||
1 | /* | ||
2 | * | ||
3 | * $Id$ | ||
4 | * | ||
5 | * Copyright (C) 2005 Mike Isely <isely@pobox.com> | ||
6 | * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License | ||
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 | |||
23 | #ifndef __PVRUSB2_CX2584X_V4L_H | ||
24 | #define __PVRUSB2_CX2584X_V4L_H | ||
25 | |||
26 | /* | ||
27 | |||
28 | This module connects the pvrusb2 driver to the I2C chip level | ||
29 | driver which handles combined device audio & video processing. | ||
30 | This interface is used internally by the driver; higher level code | ||
31 | should only interact through the interface provided by | ||
32 | pvrusb2-hdw.h. | ||
33 | |||
34 | */ | ||
35 | |||
36 | |||
37 | |||
38 | #include "pvrusb2-i2c-core.h" | ||
39 | |||
40 | int pvr2_i2c_cx2584x_v4l_setup(struct pvr2_hdw *,struct pvr2_i2c_client *); | ||
41 | |||
42 | |||
43 | #endif /* __PVRUSB2_CX2584X_V4L_H */ | ||
44 | |||
45 | /* | ||
46 | Stuff for Emacs to see, in order to encourage consistent editing style: | ||
47 | *** Local Variables: *** | ||
48 | *** mode: c *** | ||
49 | *** fill-column: 70 *** | ||
50 | *** tab-width: 8 *** | ||
51 | *** c-basic-offset: 8 *** | ||
52 | *** End: *** | ||
53 | */ | ||
diff --git a/drivers/media/video/pvrusb2/pvrusb2-debug.h b/drivers/media/video/pvrusb2/pvrusb2-debug.h new file mode 100644 index 000000000000..d95a8588e4f8 --- /dev/null +++ b/drivers/media/video/pvrusb2/pvrusb2-debug.h | |||
@@ -0,0 +1,67 @@ | |||
1 | /* | ||
2 | * $Id$ | ||
3 | * | ||
4 | * Copyright (C) 2005 Mike Isely <isely@pobox.com> | ||
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 as published by | ||
8 | * the Free Software Foundation; either version 2 of the License | ||
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 | #ifndef __PVRUSB2_DEBUG_H | ||
21 | #define __PVRUSB2_DEBUG_H | ||
22 | |||
23 | extern int pvrusb2_debug; | ||
24 | |||
25 | #define pvr2_trace(msk, fmt, arg...) do {if(msk & pvrusb2_debug) printk(KERN_INFO "pvrusb2: " fmt "\n", ##arg); } while (0) | ||
26 | |||
27 | /* These are listed in *rough* order of decreasing usefulness and | ||
28 | increasing noise level. */ | ||
29 | #define PVR2_TRACE_INFO (1 << 0) // Normal messages | ||
30 | #define PVR2_TRACE_ERROR_LEGS (1 << 1) // error messages | ||
31 | #define PVR2_TRACE_TOLERANCE (1 << 2) // track tolerance-affected errors | ||
32 | #define PVR2_TRACE_TRAP (1 << 3) // Trap & report misbehavior from app | ||
33 | #define PVR2_TRACE_INIT (1 << 4) // misc initialization steps | ||
34 | #define PVR2_TRACE_START_STOP (1 << 5) // Streaming start / stop | ||
35 | #define PVR2_TRACE_CTL (1 << 6) // commit of control changes | ||
36 | #define PVR2_TRACE_DEBUG (1 << 7) // Temporary debug code | ||
37 | #define PVR2_TRACE_EEPROM (1 << 8) // eeprom parsing / report | ||
38 | #define PVR2_TRACE_STRUCT (1 << 9) // internal struct creation | ||
39 | #define PVR2_TRACE_OPEN_CLOSE (1 << 10) // application open / close | ||
40 | #define PVR2_TRACE_CREG (1 << 11) // Main critical region entry / exit | ||
41 | #define PVR2_TRACE_SYSFS (1 << 12) // Sysfs driven I/O | ||
42 | #define PVR2_TRACE_FIRMWARE (1 << 13) // firmware upload actions | ||
43 | #define PVR2_TRACE_CHIPS (1 << 14) // chip broadcast operation | ||
44 | #define PVR2_TRACE_I2C (1 << 15) // I2C related stuff | ||
45 | #define PVR2_TRACE_I2C_CMD (1 << 16) // Software commands to I2C modules | ||
46 | #define PVR2_TRACE_I2C_CORE (1 << 17) // I2C core debugging | ||
47 | #define PVR2_TRACE_I2C_TRAF (1 << 18) // I2C traffic through the adapter | ||
48 | #define PVR2_TRACE_V4LIOCTL (1 << 19) // v4l ioctl details | ||
49 | #define PVR2_TRACE_ENCODER (1 << 20) // mpeg2 encoder operation | ||
50 | #define PVR2_TRACE_BUF_POOL (1 << 21) // Track buffer pool management | ||
51 | #define PVR2_TRACE_BUF_FLOW (1 << 22) // Track buffer flow in system | ||
52 | #define PVR2_TRACE_DATA_FLOW (1 << 23) // Track data flow | ||
53 | #define PVR2_TRACE_DEBUGIFC (1 << 24) // Debug interface actions | ||
54 | #define PVR2_TRACE_GPIO (1 << 25) // GPIO state bit changes | ||
55 | |||
56 | |||
57 | #endif /* __PVRUSB2_HDW_INTERNAL_H */ | ||
58 | |||
59 | /* | ||
60 | Stuff for Emacs to see, in order to encourage consistent editing style: | ||
61 | *** Local Variables: *** | ||
62 | *** mode: c *** | ||
63 | *** fill-column: 75 *** | ||
64 | *** tab-width: 8 *** | ||
65 | *** c-basic-offset: 8 *** | ||
66 | *** End: *** | ||
67 | */ | ||
diff --git a/drivers/media/video/pvrusb2/pvrusb2-debugifc.c b/drivers/media/video/pvrusb2/pvrusb2-debugifc.c new file mode 100644 index 000000000000..586900e365ff --- /dev/null +++ b/drivers/media/video/pvrusb2/pvrusb2-debugifc.c | |||
@@ -0,0 +1,478 @@ | |||
1 | /* | ||
2 | * | ||
3 | * $Id$ | ||
4 | * | ||
5 | * Copyright (C) 2005 Mike Isely <isely@pobox.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 | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include <linux/string.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include "pvrusb2-debugifc.h" | ||
25 | #include "pvrusb2-hdw.h" | ||
26 | #include "pvrusb2-debug.h" | ||
27 | #include "pvrusb2-i2c-core.h" | ||
28 | |||
29 | struct debugifc_mask_item { | ||
30 | const char *name; | ||
31 | unsigned long msk; | ||
32 | }; | ||
33 | |||
34 | static struct debugifc_mask_item mask_items[] = { | ||
35 | {"ENC_FIRMWARE",(1<<PVR2_SUBSYS_B_ENC_FIRMWARE)}, | ||
36 | {"ENC_CFG",(1<<PVR2_SUBSYS_B_ENC_CFG)}, | ||
37 | {"DIG_RUN",(1<<PVR2_SUBSYS_B_DIGITIZER_RUN)}, | ||
38 | {"USB_RUN",(1<<PVR2_SUBSYS_B_USBSTREAM_RUN)}, | ||
39 | {"ENC_RUN",(1<<PVR2_SUBSYS_B_ENC_RUN)}, | ||
40 | }; | ||
41 | |||
42 | |||
43 | static unsigned int debugifc_count_whitespace(const char *buf, | ||
44 | unsigned int count) | ||
45 | { | ||
46 | unsigned int scnt; | ||
47 | char ch; | ||
48 | |||
49 | for (scnt = 0; scnt < count; scnt++) { | ||
50 | ch = buf[scnt]; | ||
51 | if (ch == ' ') continue; | ||
52 | if (ch == '\t') continue; | ||
53 | if (ch == '\n') continue; | ||
54 | break; | ||
55 | } | ||
56 | return scnt; | ||
57 | } | ||
58 | |||
59 | |||
60 | static unsigned int debugifc_count_nonwhitespace(const char *buf, | ||
61 | unsigned int count) | ||
62 | { | ||
63 | unsigned int scnt; | ||
64 | char ch; | ||
65 | |||
66 | for (scnt = 0; scnt < count; scnt++) { | ||
67 | ch = buf[scnt]; | ||
68 | if (ch == ' ') break; | ||
69 | if (ch == '\t') break; | ||
70 | if (ch == '\n') break; | ||
71 | } | ||
72 | return scnt; | ||
73 | } | ||
74 | |||
75 | |||
76 | static unsigned int debugifc_isolate_word(const char *buf,unsigned int count, | ||
77 | const char **wstrPtr, | ||
78 | unsigned int *wlenPtr) | ||
79 | { | ||
80 | const char *wptr; | ||
81 | unsigned int consume_cnt = 0; | ||
82 | unsigned int wlen; | ||
83 | unsigned int scnt; | ||
84 | |||
85 | wptr = 0; | ||
86 | wlen = 0; | ||
87 | scnt = debugifc_count_whitespace(buf,count); | ||
88 | consume_cnt += scnt; count -= scnt; buf += scnt; | ||
89 | if (!count) goto done; | ||
90 | |||
91 | scnt = debugifc_count_nonwhitespace(buf,count); | ||
92 | if (!scnt) goto done; | ||
93 | wptr = buf; | ||
94 | wlen = scnt; | ||
95 | consume_cnt += scnt; count -= scnt; buf += scnt; | ||
96 | |||
97 | done: | ||
98 | *wstrPtr = wptr; | ||
99 | *wlenPtr = wlen; | ||
100 | return consume_cnt; | ||
101 | } | ||
102 | |||
103 | |||
104 | static int debugifc_parse_unsigned_number(const char *buf,unsigned int count, | ||
105 | u32 *num_ptr) | ||
106 | { | ||
107 | u32 result = 0; | ||
108 | u32 val; | ||
109 | int ch; | ||
110 | int radix = 10; | ||
111 | if ((count >= 2) && (buf[0] == '0') && | ||
112 | ((buf[1] == 'x') || (buf[1] == 'X'))) { | ||
113 | radix = 16; | ||
114 | count -= 2; | ||
115 | buf += 2; | ||
116 | } else if ((count >= 1) && (buf[0] == '0')) { | ||
117 | radix = 8; | ||
118 | } | ||
119 | |||
120 | while (count--) { | ||
121 | ch = *buf++; | ||
122 | if ((ch >= '0') && (ch <= '9')) { | ||
123 | val = ch - '0'; | ||
124 | } else if ((ch >= 'a') && (ch <= 'f')) { | ||
125 | val = ch - 'a' + 10; | ||
126 | } else if ((ch >= 'A') && (ch <= 'F')) { | ||
127 | val = ch - 'A' + 10; | ||
128 | } else { | ||
129 | return -EINVAL; | ||
130 | } | ||
131 | if (val >= radix) return -EINVAL; | ||
132 | result *= radix; | ||
133 | result += val; | ||
134 | } | ||
135 | *num_ptr = result; | ||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | |||
140 | static int debugifc_match_keyword(const char *buf,unsigned int count, | ||
141 | const char *keyword) | ||
142 | { | ||
143 | unsigned int kl; | ||
144 | if (!keyword) return 0; | ||
145 | kl = strlen(keyword); | ||
146 | if (kl != count) return 0; | ||
147 | return !memcmp(buf,keyword,kl); | ||
148 | } | ||
149 | |||
150 | |||
151 | static unsigned long debugifc_find_mask(const char *buf,unsigned int count) | ||
152 | { | ||
153 | struct debugifc_mask_item *mip; | ||
154 | unsigned int idx; | ||
155 | for (idx = 0; idx < sizeof(mask_items)/sizeof(mask_items[0]); idx++) { | ||
156 | mip = mask_items + idx; | ||
157 | if (debugifc_match_keyword(buf,count,mip->name)) { | ||
158 | return mip->msk; | ||
159 | } | ||
160 | } | ||
161 | return 0; | ||
162 | } | ||
163 | |||
164 | |||
165 | static int debugifc_print_mask(char *buf,unsigned int sz, | ||
166 | unsigned long msk,unsigned long val) | ||
167 | { | ||
168 | struct debugifc_mask_item *mip; | ||
169 | unsigned int idx; | ||
170 | int bcnt = 0; | ||
171 | int ccnt; | ||
172 | for (idx = 0; idx < sizeof(mask_items)/sizeof(mask_items[0]); idx++) { | ||
173 | mip = mask_items + idx; | ||
174 | if (!(mip->msk & msk)) continue; | ||
175 | ccnt = scnprintf(buf,sz,"%s%c%s", | ||
176 | (bcnt ? " " : ""), | ||
177 | ((mip->msk & val) ? '+' : '-'), | ||
178 | mip->name); | ||
179 | sz -= ccnt; | ||
180 | buf += ccnt; | ||
181 | bcnt += ccnt; | ||
182 | } | ||
183 | return bcnt; | ||
184 | } | ||
185 | |||
186 | static unsigned int debugifc_parse_subsys_mask(const char *buf, | ||
187 | unsigned int count, | ||
188 | unsigned long *mskPtr, | ||
189 | unsigned long *valPtr) | ||
190 | { | ||
191 | const char *wptr; | ||
192 | unsigned int consume_cnt = 0; | ||
193 | unsigned int scnt; | ||
194 | unsigned int wlen; | ||
195 | int mode; | ||
196 | unsigned long m1,msk,val; | ||
197 | |||
198 | msk = 0; | ||
199 | val = 0; | ||
200 | |||
201 | while (count) { | ||
202 | scnt = debugifc_isolate_word(buf,count,&wptr,&wlen); | ||
203 | if (!scnt) break; | ||
204 | consume_cnt += scnt; count -= scnt; buf += scnt; | ||
205 | if (!wptr) break; | ||
206 | |||
207 | mode = 0; | ||
208 | if (wlen) switch (wptr[0]) { | ||
209 | case '+': | ||
210 | wptr++; | ||
211 | wlen--; | ||
212 | break; | ||
213 | case '-': | ||
214 | mode = 1; | ||
215 | wptr++; | ||
216 | wlen--; | ||
217 | break; | ||
218 | } | ||
219 | if (!wlen) continue; | ||
220 | m1 = debugifc_find_mask(wptr,wlen); | ||
221 | if (!m1) break; | ||
222 | msk |= m1; | ||
223 | if (!mode) val |= m1; | ||
224 | } | ||
225 | *mskPtr = msk; | ||
226 | *valPtr = val; | ||
227 | return consume_cnt; | ||
228 | } | ||
229 | |||
230 | |||
231 | int pvr2_debugifc_print_info(struct pvr2_hdw *hdw,char *buf,unsigned int acnt) | ||
232 | { | ||
233 | int bcnt = 0; | ||
234 | int ccnt; | ||
235 | struct pvr2_hdw_debug_info dbg; | ||
236 | |||
237 | pvr2_hdw_get_debug_info(hdw,&dbg); | ||
238 | |||
239 | ccnt = scnprintf(buf,acnt,"big lock %s; ctl lock %s", | ||
240 | (dbg.big_lock_held ? "held" : "free"), | ||
241 | (dbg.ctl_lock_held ? "held" : "free")); | ||
242 | bcnt += ccnt; acnt -= ccnt; buf += ccnt; | ||
243 | if (dbg.ctl_lock_held) { | ||
244 | ccnt = scnprintf(buf,acnt,"; cmd_state=%d cmd_code=%d" | ||
245 | " cmd_wlen=%d cmd_rlen=%d" | ||
246 | " wpend=%d rpend=%d tmout=%d rstatus=%d" | ||
247 | " wstatus=%d", | ||
248 | dbg.cmd_debug_state,dbg.cmd_code, | ||
249 | dbg.cmd_debug_write_len, | ||
250 | dbg.cmd_debug_read_len, | ||
251 | dbg.cmd_debug_write_pend, | ||
252 | dbg.cmd_debug_read_pend, | ||
253 | dbg.cmd_debug_timeout, | ||
254 | dbg.cmd_debug_rstatus, | ||
255 | dbg.cmd_debug_wstatus); | ||
256 | bcnt += ccnt; acnt -= ccnt; buf += ccnt; | ||
257 | } | ||
258 | ccnt = scnprintf(buf,acnt,"\n"); | ||
259 | bcnt += ccnt; acnt -= ccnt; buf += ccnt; | ||
260 | ccnt = scnprintf( | ||
261 | buf,acnt,"driver flags: %s %s %s\n", | ||
262 | (dbg.flag_init_ok ? "initialized" : "uninitialized"), | ||
263 | (dbg.flag_ok ? "ok" : "fail"), | ||
264 | (dbg.flag_disconnected ? "disconnected" : "connected")); | ||
265 | bcnt += ccnt; acnt -= ccnt; buf += ccnt; | ||
266 | ccnt = scnprintf(buf,acnt,"Subsystems enabled / configured: "); | ||
267 | bcnt += ccnt; acnt -= ccnt; buf += ccnt; | ||
268 | ccnt = debugifc_print_mask(buf,acnt,dbg.subsys_flags,dbg.subsys_flags); | ||
269 | bcnt += ccnt; acnt -= ccnt; buf += ccnt; | ||
270 | ccnt = scnprintf(buf,acnt,"\n"); | ||
271 | bcnt += ccnt; acnt -= ccnt; buf += ccnt; | ||
272 | ccnt = scnprintf(buf,acnt,"Subsystems disabled / unconfigured: "); | ||
273 | bcnt += ccnt; acnt -= ccnt; buf += ccnt; | ||
274 | ccnt = debugifc_print_mask(buf,acnt,~dbg.subsys_flags,dbg.subsys_flags); | ||
275 | bcnt += ccnt; acnt -= ccnt; buf += ccnt; | ||
276 | ccnt = scnprintf(buf,acnt,"\n"); | ||
277 | bcnt += ccnt; acnt -= ccnt; buf += ccnt; | ||
278 | |||
279 | ccnt = scnprintf(buf,acnt,"Attached I2C modules:\n"); | ||
280 | bcnt += ccnt; acnt -= ccnt; buf += ccnt; | ||
281 | ccnt = pvr2_i2c_report(hdw,buf,acnt); | ||
282 | bcnt += ccnt; acnt -= ccnt; buf += ccnt; | ||
283 | |||
284 | return bcnt; | ||
285 | } | ||
286 | |||
287 | |||
288 | int pvr2_debugifc_print_status(struct pvr2_hdw *hdw, | ||
289 | char *buf,unsigned int acnt) | ||
290 | { | ||
291 | int bcnt = 0; | ||
292 | int ccnt; | ||
293 | unsigned long msk; | ||
294 | int ret; | ||
295 | u32 gpio_dir,gpio_in,gpio_out; | ||
296 | |||
297 | ret = pvr2_hdw_is_hsm(hdw); | ||
298 | ccnt = scnprintf(buf,acnt,"USB link speed: %s\n", | ||
299 | (ret < 0 ? "FAIL" : (ret ? "high" : "full"))); | ||
300 | bcnt += ccnt; acnt -= ccnt; buf += ccnt; | ||
301 | |||
302 | gpio_dir = 0; gpio_in = 0; gpio_out = 0; | ||
303 | pvr2_hdw_gpio_get_dir(hdw,&gpio_dir); | ||
304 | pvr2_hdw_gpio_get_out(hdw,&gpio_out); | ||
305 | pvr2_hdw_gpio_get_in(hdw,&gpio_in); | ||
306 | ccnt = scnprintf(buf,acnt,"GPIO state: dir=0x%x in=0x%x out=0x%x\n", | ||
307 | gpio_dir,gpio_in,gpio_out); | ||
308 | bcnt += ccnt; acnt -= ccnt; buf += ccnt; | ||
309 | |||
310 | ccnt = scnprintf(buf,acnt,"Streaming is %s\n", | ||
311 | pvr2_hdw_get_streaming(hdw) ? "on" : "off"); | ||
312 | bcnt += ccnt; acnt -= ccnt; buf += ccnt; | ||
313 | |||
314 | msk = pvr2_hdw_subsys_get(hdw); | ||
315 | ccnt = scnprintf(buf,acnt,"Subsystems enabled / configured: "); | ||
316 | bcnt += ccnt; acnt -= ccnt; buf += ccnt; | ||
317 | ccnt = debugifc_print_mask(buf,acnt,msk,msk); | ||
318 | bcnt += ccnt; acnt -= ccnt; buf += ccnt; | ||
319 | ccnt = scnprintf(buf,acnt,"\n"); | ||
320 | bcnt += ccnt; acnt -= ccnt; buf += ccnt; | ||
321 | ccnt = scnprintf(buf,acnt,"Subsystems disabled / unconfigured: "); | ||
322 | bcnt += ccnt; acnt -= ccnt; buf += ccnt; | ||
323 | ccnt = debugifc_print_mask(buf,acnt,~msk,msk); | ||
324 | bcnt += ccnt; acnt -= ccnt; buf += ccnt; | ||
325 | ccnt = scnprintf(buf,acnt,"\n"); | ||
326 | bcnt += ccnt; acnt -= ccnt; buf += ccnt; | ||
327 | |||
328 | msk = pvr2_hdw_subsys_stream_get(hdw); | ||
329 | ccnt = scnprintf(buf,acnt,"Subsystems stopped on stream shutdown: "); | ||
330 | bcnt += ccnt; acnt -= ccnt; buf += ccnt; | ||
331 | ccnt = debugifc_print_mask(buf,acnt,msk,msk); | ||
332 | bcnt += ccnt; acnt -= ccnt; buf += ccnt; | ||
333 | ccnt = scnprintf(buf,acnt,"\n"); | ||
334 | bcnt += ccnt; acnt -= ccnt; buf += ccnt; | ||
335 | |||
336 | return bcnt; | ||
337 | } | ||
338 | |||
339 | |||
340 | int pvr2_debugifc_do1cmd(struct pvr2_hdw *hdw,const char *buf, | ||
341 | unsigned int count) | ||
342 | { | ||
343 | const char *wptr; | ||
344 | unsigned int wlen; | ||
345 | unsigned int scnt; | ||
346 | |||
347 | scnt = debugifc_isolate_word(buf,count,&wptr,&wlen); | ||
348 | if (!scnt) return 0; | ||
349 | count -= scnt; buf += scnt; | ||
350 | if (!wptr) return 0; | ||
351 | |||
352 | pvr2_trace(PVR2_TRACE_DEBUGIFC,"debugifc cmd: \"%.*s\"",wlen,wptr); | ||
353 | if (debugifc_match_keyword(wptr,wlen,"reset")) { | ||
354 | scnt = debugifc_isolate_word(buf,count,&wptr,&wlen); | ||
355 | if (!scnt) return -EINVAL; | ||
356 | count -= scnt; buf += scnt; | ||
357 | if (!wptr) return -EINVAL; | ||
358 | if (debugifc_match_keyword(wptr,wlen,"cpu")) { | ||
359 | pvr2_hdw_cpureset_assert(hdw,!0); | ||
360 | pvr2_hdw_cpureset_assert(hdw,0); | ||
361 | return 0; | ||
362 | } else if (debugifc_match_keyword(wptr,wlen,"bus")) { | ||
363 | pvr2_hdw_device_reset(hdw); | ||
364 | } else if (debugifc_match_keyword(wptr,wlen,"soft")) { | ||
365 | return pvr2_hdw_cmd_powerup(hdw); | ||
366 | } else if (debugifc_match_keyword(wptr,wlen,"deep")) { | ||
367 | return pvr2_hdw_cmd_deep_reset(hdw); | ||
368 | } else if (debugifc_match_keyword(wptr,wlen,"firmware")) { | ||
369 | return pvr2_upload_firmware2(hdw); | ||
370 | } else if (debugifc_match_keyword(wptr,wlen,"decoder")) { | ||
371 | return pvr2_hdw_cmd_decoder_reset(hdw); | ||
372 | } | ||
373 | return -EINVAL; | ||
374 | } else if (debugifc_match_keyword(wptr,wlen,"subsys_flags")) { | ||
375 | unsigned long msk = 0; | ||
376 | unsigned long val = 0; | ||
377 | if (debugifc_parse_subsys_mask(buf,count,&msk,&val) != count) { | ||
378 | pvr2_trace(PVR2_TRACE_DEBUGIFC, | ||
379 | "debugifc parse error on subsys mask"); | ||
380 | return -EINVAL; | ||
381 | } | ||
382 | pvr2_hdw_subsys_bit_chg(hdw,msk,val); | ||
383 | return 0; | ||
384 | } else if (debugifc_match_keyword(wptr,wlen,"stream_flags")) { | ||
385 | unsigned long msk = 0; | ||
386 | unsigned long val = 0; | ||
387 | if (debugifc_parse_subsys_mask(buf,count,&msk,&val) != count) { | ||
388 | pvr2_trace(PVR2_TRACE_DEBUGIFC, | ||
389 | "debugifc parse error on stream mask"); | ||
390 | return -EINVAL; | ||
391 | } | ||
392 | pvr2_hdw_subsys_stream_bit_chg(hdw,msk,val); | ||
393 | return 0; | ||
394 | } else if (debugifc_match_keyword(wptr,wlen,"cpufw")) { | ||
395 | scnt = debugifc_isolate_word(buf,count,&wptr,&wlen); | ||
396 | if (!scnt) return -EINVAL; | ||
397 | count -= scnt; buf += scnt; | ||
398 | if (!wptr) return -EINVAL; | ||
399 | if (debugifc_match_keyword(wptr,wlen,"fetch")) { | ||
400 | pvr2_hdw_cpufw_set_enabled(hdw,!0); | ||
401 | return 0; | ||
402 | } else if (debugifc_match_keyword(wptr,wlen,"done")) { | ||
403 | pvr2_hdw_cpufw_set_enabled(hdw,0); | ||
404 | return 0; | ||
405 | } else { | ||
406 | return -EINVAL; | ||
407 | } | ||
408 | } else if (debugifc_match_keyword(wptr,wlen,"gpio")) { | ||
409 | int dir_fl = 0; | ||
410 | int ret; | ||
411 | u32 msk,val; | ||
412 | scnt = debugifc_isolate_word(buf,count,&wptr,&wlen); | ||
413 | if (!scnt) return -EINVAL; | ||
414 | count -= scnt; buf += scnt; | ||
415 | if (!wptr) return -EINVAL; | ||
416 | if (debugifc_match_keyword(wptr,wlen,"dir")) { | ||
417 | dir_fl = !0; | ||
418 | } else if (!debugifc_match_keyword(wptr,wlen,"out")) { | ||
419 | return -EINVAL; | ||
420 | } | ||
421 | scnt = debugifc_isolate_word(buf,count,&wptr,&wlen); | ||
422 | if (!scnt) return -EINVAL; | ||
423 | count -= scnt; buf += scnt; | ||
424 | if (!wptr) return -EINVAL; | ||
425 | ret = debugifc_parse_unsigned_number(wptr,wlen,&msk); | ||
426 | if (ret) return ret; | ||
427 | scnt = debugifc_isolate_word(buf,count,&wptr,&wlen); | ||
428 | if (wptr) { | ||
429 | ret = debugifc_parse_unsigned_number(wptr,wlen,&val); | ||
430 | if (ret) return ret; | ||
431 | } else { | ||
432 | val = msk; | ||
433 | msk = 0xffffffff; | ||
434 | } | ||
435 | if (dir_fl) { | ||
436 | ret = pvr2_hdw_gpio_chg_dir(hdw,msk,val); | ||
437 | } else { | ||
438 | ret = pvr2_hdw_gpio_chg_out(hdw,msk,val); | ||
439 | } | ||
440 | return ret; | ||
441 | } | ||
442 | pvr2_trace(PVR2_TRACE_DEBUGIFC, | ||
443 | "debugifc failed to recognize cmd: \"%.*s\"",wlen,wptr); | ||
444 | return -EINVAL; | ||
445 | } | ||
446 | |||
447 | |||
448 | int pvr2_debugifc_docmd(struct pvr2_hdw *hdw,const char *buf, | ||
449 | unsigned int count) | ||
450 | { | ||
451 | unsigned int bcnt = 0; | ||
452 | int ret; | ||
453 | |||
454 | while (count) { | ||
455 | for (bcnt = 0; bcnt < count; bcnt++) { | ||
456 | if (buf[bcnt] == '\n') break; | ||
457 | } | ||
458 | |||
459 | ret = pvr2_debugifc_do1cmd(hdw,buf,bcnt); | ||
460 | if (ret < 0) return ret; | ||
461 | if (bcnt < count) bcnt++; | ||
462 | buf += bcnt; | ||
463 | count -= bcnt; | ||
464 | } | ||
465 | |||
466 | return 0; | ||
467 | } | ||
468 | |||
469 | |||
470 | /* | ||
471 | Stuff for Emacs to see, in order to encourage consistent editing style: | ||
472 | *** Local Variables: *** | ||
473 | *** mode: c *** | ||
474 | *** fill-column: 75 *** | ||
475 | *** tab-width: 8 *** | ||
476 | *** c-basic-offset: 8 *** | ||
477 | *** End: *** | ||
478 | */ | ||
diff --git a/drivers/media/video/pvrusb2/pvrusb2-debugifc.h b/drivers/media/video/pvrusb2/pvrusb2-debugifc.h new file mode 100644 index 000000000000..990b02d35d36 --- /dev/null +++ b/drivers/media/video/pvrusb2/pvrusb2-debugifc.h | |||
@@ -0,0 +1,53 @@ | |||
1 | /* | ||
2 | * | ||
3 | * $Id$ | ||
4 | * | ||
5 | * Copyright (C) 2005 Mike Isely <isely@pobox.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 | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | * | ||
20 | */ | ||
21 | #ifndef __PVRUSB2_DEBUGIFC_H | ||
22 | #define __PVRUSB2_DEBUGIFC_H | ||
23 | |||
24 | struct pvr2_hdw; | ||
25 | |||
26 | /* Non-intrusively print some useful debugging info from inside the | ||
27 | driver. This should work even if the driver appears to be | ||
28 | wedged. */ | ||
29 | int pvr2_debugifc_print_info(struct pvr2_hdw *, | ||
30 | char *buf_ptr,unsigned int buf_size); | ||
31 | |||
32 | /* Print general status of driver. This will also trigger a probe of | ||
33 | the USB link. Unlike print_info(), this one synchronizes with the | ||
34 | driver so the information should be self-consistent (but it will | ||
35 | hang if the driver is wedged). */ | ||
36 | int pvr2_debugifc_print_status(struct pvr2_hdw *, | ||
37 | char *buf_ptr,unsigned int buf_size); | ||
38 | |||
39 | /* Parse a string command into a driver action. */ | ||
40 | int pvr2_debugifc_docmd(struct pvr2_hdw *, | ||
41 | const char *buf_ptr,unsigned int buf_size); | ||
42 | |||
43 | #endif /* __PVRUSB2_DEBUGIFC_H */ | ||
44 | |||
45 | /* | ||
46 | Stuff for Emacs to see, in order to encourage consistent editing style: | ||
47 | *** Local Variables: *** | ||
48 | *** mode: c *** | ||
49 | *** fill-column: 75 *** | ||
50 | *** tab-width: 8 *** | ||
51 | *** c-basic-offset: 8 *** | ||
52 | *** End: *** | ||
53 | */ | ||
diff --git a/drivers/media/video/pvrusb2/pvrusb2-demod.c b/drivers/media/video/pvrusb2/pvrusb2-demod.c new file mode 100644 index 000000000000..9686569a11f6 --- /dev/null +++ b/drivers/media/video/pvrusb2/pvrusb2-demod.c | |||
@@ -0,0 +1,126 @@ | |||
1 | /* | ||
2 | * | ||
3 | * $Id$ | ||
4 | * | ||
5 | * Copyright (C) 2005 Mike Isely <isely@pobox.com> | ||
6 | * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License | ||
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 | |||
23 | #include "pvrusb2.h" | ||
24 | #include "pvrusb2-util.h" | ||
25 | #include "pvrusb2-demod.h" | ||
26 | #include "pvrusb2-hdw-internal.h" | ||
27 | #include "pvrusb2-debug.h" | ||
28 | #include <linux/videodev2.h> | ||
29 | #include <media/tuner.h> | ||
30 | #include <media/v4l2-common.h> | ||
31 | |||
32 | |||
33 | struct pvr2_demod_handler { | ||
34 | struct pvr2_hdw *hdw; | ||
35 | struct pvr2_i2c_client *client; | ||
36 | struct pvr2_i2c_handler i2c_handler; | ||
37 | int type_update_fl; | ||
38 | }; | ||
39 | |||
40 | |||
41 | static void set_config(struct pvr2_demod_handler *ctxt) | ||
42 | { | ||
43 | struct pvr2_hdw *hdw = ctxt->hdw; | ||
44 | int cfg = 0; | ||
45 | |||
46 | switch (hdw->tuner_type) { | ||
47 | case TUNER_PHILIPS_FM1216ME_MK3: | ||
48 | case TUNER_PHILIPS_FM1236_MK3: | ||
49 | cfg = TDA9887_PORT1_ACTIVE|TDA9887_PORT2_ACTIVE; | ||
50 | break; | ||
51 | default: | ||
52 | break; | ||
53 | } | ||
54 | pvr2_trace(PVR2_TRACE_CHIPS,"i2c demod set_config(0x%x)",cfg); | ||
55 | pvr2_i2c_client_cmd(ctxt->client,TDA9887_SET_CONFIG,&cfg); | ||
56 | ctxt->type_update_fl = 0; | ||
57 | } | ||
58 | |||
59 | |||
60 | static int demod_check(struct pvr2_demod_handler *ctxt) | ||
61 | { | ||
62 | struct pvr2_hdw *hdw = ctxt->hdw; | ||
63 | if (hdw->tuner_updated) ctxt->type_update_fl = !0; | ||
64 | return ctxt->type_update_fl != 0; | ||
65 | } | ||
66 | |||
67 | |||
68 | static void demod_update(struct pvr2_demod_handler *ctxt) | ||
69 | { | ||
70 | if (ctxt->type_update_fl) set_config(ctxt); | ||
71 | } | ||
72 | |||
73 | |||
74 | static void demod_detach(struct pvr2_demod_handler *ctxt) | ||
75 | { | ||
76 | ctxt->client->handler = 0; | ||
77 | kfree(ctxt); | ||
78 | } | ||
79 | |||
80 | |||
81 | static unsigned int demod_describe(struct pvr2_demod_handler *ctxt,char *buf,unsigned int cnt) | ||
82 | { | ||
83 | return scnprintf(buf,cnt,"handler: pvrusb2-demod"); | ||
84 | } | ||
85 | |||
86 | |||
87 | const static struct pvr2_i2c_handler_functions tuner_funcs = { | ||
88 | .detach = (void (*)(void *))demod_detach, | ||
89 | .check = (int (*)(void *))demod_check, | ||
90 | .update = (void (*)(void *))demod_update, | ||
91 | .describe = (unsigned int (*)(void *,char *,unsigned int))demod_describe, | ||
92 | }; | ||
93 | |||
94 | |||
95 | int pvr2_i2c_demod_setup(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp) | ||
96 | { | ||
97 | struct pvr2_demod_handler *ctxt; | ||
98 | if (cp->handler) return 0; | ||
99 | |||
100 | ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL); | ||
101 | if (!ctxt) return 0; | ||
102 | memset(ctxt,0,sizeof(*ctxt)); | ||
103 | |||
104 | ctxt->i2c_handler.func_data = ctxt; | ||
105 | ctxt->i2c_handler.func_table = &tuner_funcs; | ||
106 | ctxt->type_update_fl = !0; | ||
107 | ctxt->client = cp; | ||
108 | ctxt->hdw = hdw; | ||
109 | cp->handler = &ctxt->i2c_handler; | ||
110 | pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x tda9887 V4L2 handler set up", | ||
111 | cp->client->addr); | ||
112 | return !0; | ||
113 | } | ||
114 | |||
115 | |||
116 | |||
117 | |||
118 | /* | ||
119 | Stuff for Emacs to see, in order to encourage consistent editing style: | ||
120 | *** Local Variables: *** | ||
121 | *** mode: c *** | ||
122 | *** fill-column: 70 *** | ||
123 | *** tab-width: 8 *** | ||
124 | *** c-basic-offset: 8 *** | ||
125 | *** End: *** | ||
126 | */ | ||
diff --git a/drivers/media/video/pvrusb2/pvrusb2-demod.h b/drivers/media/video/pvrusb2/pvrusb2-demod.h new file mode 100644 index 000000000000..4c4e40ffbf03 --- /dev/null +++ b/drivers/media/video/pvrusb2/pvrusb2-demod.h | |||
@@ -0,0 +1,38 @@ | |||
1 | /* | ||
2 | * | ||
3 | * $Id$ | ||
4 | * | ||
5 | * Copyright (C) 2005 Mike Isely <isely@pobox.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 | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | * | ||
20 | */ | ||
21 | #ifndef __PVRUSB2_DEMOD_H | ||
22 | #define __PVRUSB2_DEMOD_H | ||
23 | |||
24 | #include "pvrusb2-i2c-core.h" | ||
25 | |||
26 | int pvr2_i2c_demod_setup(struct pvr2_hdw *,struct pvr2_i2c_client *); | ||
27 | |||
28 | #endif /* __PVRUSB2_DEMOD_H */ | ||
29 | |||
30 | /* | ||
31 | Stuff for Emacs to see, in order to encourage consistent editing style: | ||
32 | *** Local Variables: *** | ||
33 | *** mode: c *** | ||
34 | *** fill-column: 70 *** | ||
35 | *** tab-width: 8 *** | ||
36 | *** c-basic-offset: 8 *** | ||
37 | *** End: *** | ||
38 | */ | ||
diff --git a/drivers/media/video/pvrusb2/pvrusb2-eeprom.c b/drivers/media/video/pvrusb2/pvrusb2-eeprom.c new file mode 100644 index 000000000000..94d383ff9889 --- /dev/null +++ b/drivers/media/video/pvrusb2/pvrusb2-eeprom.c | |||
@@ -0,0 +1,164 @@ | |||
1 | /* | ||
2 | * | ||
3 | * $Id$ | ||
4 | * | ||
5 | * Copyright (C) 2005 Mike Isely <isely@pobox.com> | ||
6 | * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License | ||
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 | |||
23 | #include "pvrusb2-eeprom.h" | ||
24 | #include "pvrusb2-hdw-internal.h" | ||
25 | #include "pvrusb2-debug.h" | ||
26 | |||
27 | #define trace_eeprom(...) pvr2_trace(PVR2_TRACE_EEPROM,__VA_ARGS__) | ||
28 | |||
29 | |||
30 | |||
31 | /* | ||
32 | |||
33 | Read and analyze data in the eeprom. Use tveeprom to figure out | ||
34 | the packet structure, since this is another Hauppauge device and | ||
35 | internally it has a family resemblence to ivtv-type devices | ||
36 | |||
37 | */ | ||
38 | |||
39 | #include <media/tveeprom.h> | ||
40 | |||
41 | /* We seem to only be interested in the last 128 bytes of the EEPROM */ | ||
42 | #define EEPROM_SIZE 128 | ||
43 | |||
44 | /* Grab EEPROM contents, needed for direct method. */ | ||
45 | static u8 *pvr2_eeprom_fetch(struct pvr2_hdw *hdw) | ||
46 | { | ||
47 | struct i2c_msg msg[2]; | ||
48 | u8 *eeprom; | ||
49 | u8 iadd[2]; | ||
50 | u8 addr; | ||
51 | u16 eepromSize; | ||
52 | unsigned int offs; | ||
53 | int ret; | ||
54 | int mode16 = 0; | ||
55 | unsigned pcnt,tcnt; | ||
56 | eeprom = kmalloc(EEPROM_SIZE,GFP_KERNEL); | ||
57 | if (!eeprom) { | ||
58 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, | ||
59 | "Failed to allocate memory" | ||
60 | " required to read eeprom"); | ||
61 | return 0; | ||
62 | } | ||
63 | |||
64 | trace_eeprom("Value for eeprom addr from controller was 0x%x", | ||
65 | hdw->eeprom_addr); | ||
66 | addr = hdw->eeprom_addr; | ||
67 | /* Seems that if the high bit is set, then the *real* eeprom | ||
68 | address is shifted right now bit position (noticed this in | ||
69 | newer PVR USB2 hardware) */ | ||
70 | if (addr & 0x80) addr >>= 1; | ||
71 | |||
72 | /* FX2 documentation states that a 16bit-addressed eeprom is | ||
73 | expected if the I2C address is an odd number (yeah, this is | ||
74 | strange but it's what they do) */ | ||
75 | mode16 = (addr & 1); | ||
76 | eepromSize = (mode16 ? 4096 : 256); | ||
77 | trace_eeprom("Examining %d byte eeprom at location 0x%x" | ||
78 | " using %d bit addressing",eepromSize,addr, | ||
79 | mode16 ? 16 : 8); | ||
80 | |||
81 | msg[0].addr = addr; | ||
82 | msg[0].flags = 0; | ||
83 | msg[0].len = mode16 ? 2 : 1; | ||
84 | msg[0].buf = iadd; | ||
85 | msg[1].addr = addr; | ||
86 | msg[1].flags = I2C_M_RD; | ||
87 | |||
88 | /* We have to do the actual eeprom data fetch ourselves, because | ||
89 | (1) we're only fetching part of the eeprom, and (2) if we were | ||
90 | getting the whole thing our I2C driver can't grab it in one | ||
91 | pass - which is what tveeprom is otherwise going to attempt */ | ||
92 | memset(eeprom,0,EEPROM_SIZE); | ||
93 | for (tcnt = 0; tcnt < EEPROM_SIZE; tcnt += pcnt) { | ||
94 | pcnt = 16; | ||
95 | if (pcnt + tcnt > EEPROM_SIZE) pcnt = EEPROM_SIZE-tcnt; | ||
96 | offs = tcnt + (eepromSize - EEPROM_SIZE); | ||
97 | if (mode16) { | ||
98 | iadd[0] = offs >> 8; | ||
99 | iadd[1] = offs; | ||
100 | } else { | ||
101 | iadd[0] = offs; | ||
102 | } | ||
103 | msg[1].len = pcnt; | ||
104 | msg[1].buf = eeprom+tcnt; | ||
105 | if ((ret = i2c_transfer( | ||
106 | &hdw->i2c_adap, | ||
107 | msg,sizeof(msg)/sizeof(msg[0]))) != 2) { | ||
108 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, | ||
109 | "eeprom fetch set offs err=%d",ret); | ||
110 | kfree(eeprom); | ||
111 | return 0; | ||
112 | } | ||
113 | } | ||
114 | return eeprom; | ||
115 | } | ||
116 | |||
117 | |||
118 | /* Directly call eeprom analysis function within tveeprom. */ | ||
119 | int pvr2_eeprom_analyze(struct pvr2_hdw *hdw) | ||
120 | { | ||
121 | u8 *eeprom; | ||
122 | struct tveeprom tvdata; | ||
123 | |||
124 | memset(&tvdata,0,sizeof(tvdata)); | ||
125 | |||
126 | eeprom = pvr2_eeprom_fetch(hdw); | ||
127 | if (!eeprom) return -EINVAL; | ||
128 | |||
129 | { | ||
130 | struct i2c_client fake_client; | ||
131 | /* Newer version expects a useless client interface */ | ||
132 | fake_client.addr = hdw->eeprom_addr; | ||
133 | fake_client.adapter = &hdw->i2c_adap; | ||
134 | tveeprom_hauppauge_analog(&fake_client,&tvdata,eeprom); | ||
135 | } | ||
136 | |||
137 | trace_eeprom("eeprom assumed v4l tveeprom module"); | ||
138 | trace_eeprom("eeprom direct call results:"); | ||
139 | trace_eeprom("has_radio=%d",tvdata.has_radio); | ||
140 | trace_eeprom("tuner_type=%d",tvdata.tuner_type); | ||
141 | trace_eeprom("tuner_formats=0x%x",tvdata.tuner_formats); | ||
142 | trace_eeprom("audio_processor=%d",tvdata.audio_processor); | ||
143 | trace_eeprom("model=%d",tvdata.model); | ||
144 | trace_eeprom("revision=%d",tvdata.revision); | ||
145 | trace_eeprom("serial_number=%d",tvdata.serial_number); | ||
146 | trace_eeprom("rev_str=%s",tvdata.rev_str); | ||
147 | hdw->tuner_type = tvdata.tuner_type; | ||
148 | hdw->serial_number = tvdata.serial_number; | ||
149 | hdw->std_mask_eeprom = tvdata.tuner_formats; | ||
150 | |||
151 | kfree(eeprom); | ||
152 | |||
153 | return 0; | ||
154 | } | ||
155 | |||
156 | /* | ||
157 | Stuff for Emacs to see, in order to encourage consistent editing style: | ||
158 | *** Local Variables: *** | ||
159 | *** mode: c *** | ||
160 | *** fill-column: 70 *** | ||
161 | *** tab-width: 8 *** | ||
162 | *** c-basic-offset: 8 *** | ||
163 | *** End: *** | ||
164 | */ | ||
diff --git a/drivers/media/video/pvrusb2/pvrusb2-eeprom.h b/drivers/media/video/pvrusb2/pvrusb2-eeprom.h new file mode 100644 index 000000000000..84242975dea7 --- /dev/null +++ b/drivers/media/video/pvrusb2/pvrusb2-eeprom.h | |||
@@ -0,0 +1,40 @@ | |||
1 | /* | ||
2 | * | ||
3 | * $Id$ | ||
4 | * | ||
5 | * Copyright (C) 2005 Mike Isely <isely@pobox.com> | ||
6 | * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License | ||
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 | |||
23 | #ifndef __PVRUSB2_EEPROM_H | ||
24 | #define __PVRUSB2_EEPROM_H | ||
25 | |||
26 | struct pvr2_hdw; | ||
27 | |||
28 | int pvr2_eeprom_analyze(struct pvr2_hdw *); | ||
29 | |||
30 | #endif /* __PVRUSB2_EEPROM_H */ | ||
31 | |||
32 | /* | ||
33 | Stuff for Emacs to see, in order to encourage consistent editing style: | ||
34 | *** Local Variables: *** | ||
35 | *** mode: c *** | ||
36 | *** fill-column: 70 *** | ||
37 | *** tab-width: 8 *** | ||
38 | *** c-basic-offset: 8 *** | ||
39 | *** End: *** | ||
40 | */ | ||
diff --git a/drivers/media/video/pvrusb2/pvrusb2-encoder.c b/drivers/media/video/pvrusb2/pvrusb2-encoder.c new file mode 100644 index 000000000000..2cc31695b435 --- /dev/null +++ b/drivers/media/video/pvrusb2/pvrusb2-encoder.c | |||
@@ -0,0 +1,418 @@ | |||
1 | /* | ||
2 | * | ||
3 | * $Id$ | ||
4 | * | ||
5 | * Copyright (C) 2005 Mike Isely <isely@pobox.com> | ||
6 | * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License | ||
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 | |||
23 | #include <linux/device.h> // for linux/firmware.h | ||
24 | #include <linux/firmware.h> | ||
25 | #include "pvrusb2-util.h" | ||
26 | #include "pvrusb2-encoder.h" | ||
27 | #include "pvrusb2-hdw-internal.h" | ||
28 | #include "pvrusb2-debug.h" | ||
29 | |||
30 | |||
31 | |||
32 | /* Firmware mailbox flags - definitions found from ivtv */ | ||
33 | #define IVTV_MBOX_FIRMWARE_DONE 0x00000004 | ||
34 | #define IVTV_MBOX_DRIVER_DONE 0x00000002 | ||
35 | #define IVTV_MBOX_DRIVER_BUSY 0x00000001 | ||
36 | |||
37 | |||
38 | static int pvr2_encoder_write_words(struct pvr2_hdw *hdw, | ||
39 | const u32 *data, unsigned int dlen) | ||
40 | { | ||
41 | unsigned int idx; | ||
42 | int ret; | ||
43 | unsigned int offs = 0; | ||
44 | unsigned int chunkCnt; | ||
45 | |||
46 | /* | ||
47 | |||
48 | Format: First byte must be 0x01. Remaining 32 bit words are | ||
49 | spread out into chunks of 7 bytes each, little-endian ordered, | ||
50 | offset at zero within each 2 blank bytes following and a | ||
51 | single byte that is 0x44 plus the offset of the word. Repeat | ||
52 | request for additional words, with offset adjusted | ||
53 | accordingly. | ||
54 | |||
55 | */ | ||
56 | while (dlen) { | ||
57 | chunkCnt = 8; | ||
58 | if (chunkCnt > dlen) chunkCnt = dlen; | ||
59 | memset(hdw->cmd_buffer,0,sizeof(hdw->cmd_buffer)); | ||
60 | hdw->cmd_buffer[0] = 0x01; | ||
61 | for (idx = 0; idx < chunkCnt; idx++) { | ||
62 | hdw->cmd_buffer[1+(idx*7)+6] = 0x44 + idx + offs; | ||
63 | PVR2_DECOMPOSE_LE(hdw->cmd_buffer, 1+(idx*7), | ||
64 | data[idx]); | ||
65 | } | ||
66 | ret = pvr2_send_request(hdw, | ||
67 | hdw->cmd_buffer,1+(chunkCnt*7), | ||
68 | 0,0); | ||
69 | if (ret) return ret; | ||
70 | data += chunkCnt; | ||
71 | dlen -= chunkCnt; | ||
72 | offs += chunkCnt; | ||
73 | } | ||
74 | |||
75 | return 0; | ||
76 | } | ||
77 | |||
78 | |||
79 | static int pvr2_encoder_read_words(struct pvr2_hdw *hdw,int statusFl, | ||
80 | u32 *data, unsigned int dlen) | ||
81 | { | ||
82 | unsigned int idx; | ||
83 | int ret; | ||
84 | unsigned int offs = 0; | ||
85 | unsigned int chunkCnt; | ||
86 | |||
87 | /* | ||
88 | |||
89 | Format: First byte must be 0x02 (status check) or 0x28 (read | ||
90 | back block of 32 bit words). Next 6 bytes must be zero, | ||
91 | followed by a single byte of 0x44+offset for portion to be | ||
92 | read. Returned data is packed set of 32 bits words that were | ||
93 | read. | ||
94 | |||
95 | */ | ||
96 | |||
97 | while (dlen) { | ||
98 | chunkCnt = 16; | ||
99 | if (chunkCnt > dlen) chunkCnt = dlen; | ||
100 | memset(hdw->cmd_buffer,0,sizeof(hdw->cmd_buffer)); | ||
101 | hdw->cmd_buffer[0] = statusFl ? 0x02 : 0x28; | ||
102 | hdw->cmd_buffer[7] = 0x44 + offs; | ||
103 | ret = pvr2_send_request(hdw, | ||
104 | hdw->cmd_buffer,8, | ||
105 | hdw->cmd_buffer,chunkCnt * 4); | ||
106 | if (ret) return ret; | ||
107 | |||
108 | for (idx = 0; idx < chunkCnt; idx++) { | ||
109 | data[idx] = PVR2_COMPOSE_LE(hdw->cmd_buffer,idx*4); | ||
110 | } | ||
111 | data += chunkCnt; | ||
112 | dlen -= chunkCnt; | ||
113 | offs += chunkCnt; | ||
114 | } | ||
115 | |||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | |||
120 | /* This prototype is set up to be compatible with the | ||
121 | cx2341x_mbox_func prototype in cx2341x.h, which should be in | ||
122 | kernels 2.6.18 or later. We do this so that we can enable | ||
123 | cx2341x.ko to write to our encoder (by handing it a pointer to this | ||
124 | function). For earlier kernels this doesn't really matter. */ | ||
125 | static int pvr2_encoder_cmd(void *ctxt, | ||
126 | int cmd, | ||
127 | int arg_cnt_send, | ||
128 | int arg_cnt_recv, | ||
129 | u32 *argp) | ||
130 | { | ||
131 | unsigned int poll_count; | ||
132 | int ret = 0; | ||
133 | unsigned int idx; | ||
134 | /* These sizes look to be limited by the FX2 firmware implementation */ | ||
135 | u32 wrData[16]; | ||
136 | u32 rdData[16]; | ||
137 | struct pvr2_hdw *hdw = (struct pvr2_hdw *)ctxt; | ||
138 | |||
139 | |||
140 | /* | ||
141 | |||
142 | The encoder seems to speak entirely using blocks 32 bit words. | ||
143 | In ivtv driver terms, this is a mailbox which we populate with | ||
144 | data and watch what the hardware does with it. The first word | ||
145 | is a set of flags used to control the transaction, the second | ||
146 | word is the command to execute, the third byte is zero (ivtv | ||
147 | driver suggests that this is some kind of return value), and | ||
148 | the fourth byte is a specified timeout (windows driver always | ||
149 | uses 0x00060000 except for one case when it is zero). All | ||
150 | successive words are the argument words for the command. | ||
151 | |||
152 | First, write out the entire set of words, with the first word | ||
153 | being zero. | ||
154 | |||
155 | Next, write out just the first word again, but set it to | ||
156 | IVTV_MBOX_DRIVER_DONE | IVTV_DRIVER_BUSY this time (which | ||
157 | probably means "go"). | ||
158 | |||
159 | Next, read back 16 words as status. Check the first word, | ||
160 | which should have IVTV_MBOX_FIRMWARE_DONE set. If however | ||
161 | that bit is not set, then the command isn't done so repeat the | ||
162 | read. | ||
163 | |||
164 | Next, read back 32 words and compare with the original | ||
165 | arugments. Hopefully they will match. | ||
166 | |||
167 | Finally, write out just the first word again, but set it to | ||
168 | 0x0 this time (which probably means "idle"). | ||
169 | |||
170 | */ | ||
171 | |||
172 | if (arg_cnt_send > (sizeof(wrData)/sizeof(wrData[0]))-4) { | ||
173 | pvr2_trace( | ||
174 | PVR2_TRACE_ERROR_LEGS, | ||
175 | "Failed to write cx23416 command" | ||
176 | " - too many input arguments" | ||
177 | " (was given %u limit %u)", | ||
178 | arg_cnt_send, | ||
179 | (unsigned int)(sizeof(wrData)/sizeof(wrData[0])) - 4); | ||
180 | return -EINVAL; | ||
181 | } | ||
182 | |||
183 | if (arg_cnt_recv > (sizeof(rdData)/sizeof(rdData[0]))-4) { | ||
184 | pvr2_trace( | ||
185 | PVR2_TRACE_ERROR_LEGS, | ||
186 | "Failed to write cx23416 command" | ||
187 | " - too many return arguments" | ||
188 | " (was given %u limit %u)", | ||
189 | arg_cnt_recv, | ||
190 | (unsigned int)(sizeof(rdData)/sizeof(rdData[0])) - 4); | ||
191 | return -EINVAL; | ||
192 | } | ||
193 | |||
194 | |||
195 | LOCK_TAKE(hdw->ctl_lock); do { | ||
196 | |||
197 | wrData[0] = 0; | ||
198 | wrData[1] = cmd; | ||
199 | wrData[2] = 0; | ||
200 | wrData[3] = 0x00060000; | ||
201 | for (idx = 0; idx < arg_cnt_send; idx++) { | ||
202 | wrData[idx+4] = argp[idx]; | ||
203 | } | ||
204 | for (; idx < (sizeof(wrData)/sizeof(wrData[0]))-4; idx++) { | ||
205 | wrData[idx+4] = 0; | ||
206 | } | ||
207 | |||
208 | ret = pvr2_encoder_write_words(hdw,wrData,idx); | ||
209 | if (ret) break; | ||
210 | wrData[0] = IVTV_MBOX_DRIVER_DONE|IVTV_MBOX_DRIVER_BUSY; | ||
211 | ret = pvr2_encoder_write_words(hdw,wrData,1); | ||
212 | if (ret) break; | ||
213 | poll_count = 0; | ||
214 | while (1) { | ||
215 | if (poll_count < 10000000) poll_count++; | ||
216 | ret = pvr2_encoder_read_words(hdw,!0,rdData,1); | ||
217 | if (ret) break; | ||
218 | if (rdData[0] & IVTV_MBOX_FIRMWARE_DONE) { | ||
219 | break; | ||
220 | } | ||
221 | if (poll_count == 100) { | ||
222 | pvr2_trace( | ||
223 | PVR2_TRACE_ERROR_LEGS, | ||
224 | "***WARNING*** device's encoder" | ||
225 | " appears to be stuck" | ||
226 | " (status=0%08x)",rdData[0]); | ||
227 | pvr2_trace( | ||
228 | PVR2_TRACE_ERROR_LEGS, | ||
229 | "Encoder command: 0x%02x",cmd); | ||
230 | for (idx = 4; idx < arg_cnt_send; idx++) { | ||
231 | pvr2_trace( | ||
232 | PVR2_TRACE_ERROR_LEGS, | ||
233 | "Encoder arg%d: 0x%08x", | ||
234 | idx-3,wrData[idx]); | ||
235 | } | ||
236 | pvr2_trace( | ||
237 | PVR2_TRACE_ERROR_LEGS, | ||
238 | "Giving up waiting." | ||
239 | " It is likely that" | ||
240 | " this is a bad idea..."); | ||
241 | ret = -EBUSY; | ||
242 | break; | ||
243 | } | ||
244 | } | ||
245 | if (ret) break; | ||
246 | wrData[0] = 0x7; | ||
247 | ret = pvr2_encoder_read_words( | ||
248 | hdw,0,rdData, | ||
249 | sizeof(rdData)/sizeof(rdData[0])); | ||
250 | if (ret) break; | ||
251 | for (idx = 0; idx < arg_cnt_recv; idx++) { | ||
252 | argp[idx] = rdData[idx+4]; | ||
253 | } | ||
254 | |||
255 | wrData[0] = 0x0; | ||
256 | ret = pvr2_encoder_write_words(hdw,wrData,1); | ||
257 | if (ret) break; | ||
258 | |||
259 | } while(0); LOCK_GIVE(hdw->ctl_lock); | ||
260 | |||
261 | return ret; | ||
262 | } | ||
263 | |||
264 | |||
265 | static int pvr2_encoder_vcmd(struct pvr2_hdw *hdw, int cmd, | ||
266 | int args, ...) | ||
267 | { | ||
268 | va_list vl; | ||
269 | unsigned int idx; | ||
270 | u32 data[12]; | ||
271 | |||
272 | if (args > sizeof(data)/sizeof(data[0])) { | ||
273 | pvr2_trace( | ||
274 | PVR2_TRACE_ERROR_LEGS, | ||
275 | "Failed to write cx23416 command" | ||
276 | " - too many arguments" | ||
277 | " (was given %u limit %u)", | ||
278 | args,(unsigned int)(sizeof(data)/sizeof(data[0]))); | ||
279 | return -EINVAL; | ||
280 | } | ||
281 | |||
282 | va_start(vl, args); | ||
283 | for (idx = 0; idx < args; idx++) { | ||
284 | data[idx] = va_arg(vl, u32); | ||
285 | } | ||
286 | va_end(vl); | ||
287 | |||
288 | return pvr2_encoder_cmd(hdw,cmd,args,0,data); | ||
289 | } | ||
290 | |||
291 | int pvr2_encoder_configure(struct pvr2_hdw *hdw) | ||
292 | { | ||
293 | int ret; | ||
294 | pvr2_trace(PVR2_TRACE_ENCODER,"pvr2_encoder_configure" | ||
295 | " (cx2341x module)"); | ||
296 | hdw->enc_ctl_state.port = CX2341X_PORT_STREAMING; | ||
297 | hdw->enc_ctl_state.width = hdw->res_hor_val; | ||
298 | hdw->enc_ctl_state.height = hdw->res_ver_val; | ||
299 | hdw->enc_ctl_state.is_50hz = ((hdw->std_mask_cur & | ||
300 | (V4L2_STD_NTSC|V4L2_STD_PAL_M)) ? | ||
301 | 0 : 1); | ||
302 | |||
303 | ret = 0; | ||
304 | |||
305 | if (!ret) ret = pvr2_encoder_vcmd( | ||
306 | hdw,CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, | ||
307 | 0xf0, 0xf0); | ||
308 | |||
309 | /* setup firmware to notify us about some events (don't know why...) */ | ||
310 | if (!ret) ret = pvr2_encoder_vcmd( | ||
311 | hdw,CX2341X_ENC_SET_EVENT_NOTIFICATION, 4, | ||
312 | 0, 0, 0x10000000, 0xffffffff); | ||
313 | |||
314 | if (!ret) ret = pvr2_encoder_vcmd( | ||
315 | hdw,CX2341X_ENC_SET_VBI_LINE, 5, | ||
316 | 0xffffffff,0,0,0,0); | ||
317 | |||
318 | if (ret) { | ||
319 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, | ||
320 | "Failed to configure cx32416"); | ||
321 | return ret; | ||
322 | } | ||
323 | |||
324 | ret = cx2341x_update(hdw,pvr2_encoder_cmd, | ||
325 | (hdw->enc_cur_valid ? &hdw->enc_cur_state : 0), | ||
326 | &hdw->enc_ctl_state); | ||
327 | if (ret) { | ||
328 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, | ||
329 | "Error from cx2341x module code=%d",ret); | ||
330 | return ret; | ||
331 | } | ||
332 | |||
333 | ret = 0; | ||
334 | |||
335 | if (!ret) ret = pvr2_encoder_vcmd( | ||
336 | hdw, CX2341X_ENC_INITIALIZE_INPUT, 0); | ||
337 | |||
338 | if (ret) { | ||
339 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, | ||
340 | "Failed to initialize cx32416 video input"); | ||
341 | return ret; | ||
342 | } | ||
343 | |||
344 | hdw->subsys_enabled_mask |= (1<<PVR2_SUBSYS_B_ENC_CFG); | ||
345 | memcpy(&hdw->enc_cur_state,&hdw->enc_ctl_state, | ||
346 | sizeof(struct cx2341x_mpeg_params)); | ||
347 | hdw->enc_cur_valid = !0; | ||
348 | return 0; | ||
349 | } | ||
350 | |||
351 | |||
352 | int pvr2_encoder_start(struct pvr2_hdw *hdw) | ||
353 | { | ||
354 | int status; | ||
355 | |||
356 | /* unmask some interrupts */ | ||
357 | pvr2_write_register(hdw, 0x0048, 0xbfffffff); | ||
358 | |||
359 | /* change some GPIO data */ | ||
360 | pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000481); | ||
361 | pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000000); | ||
362 | |||
363 | if (hdw->config == pvr2_config_vbi) { | ||
364 | status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2, | ||
365 | 0x01,0x14); | ||
366 | } else if (hdw->config == pvr2_config_mpeg) { | ||
367 | status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2, | ||
368 | 0,0x13); | ||
369 | } else { | ||
370 | status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2, | ||
371 | 0,0x13); | ||
372 | } | ||
373 | if (!status) { | ||
374 | hdw->subsys_enabled_mask |= (1<<PVR2_SUBSYS_B_ENC_RUN); | ||
375 | } | ||
376 | return status; | ||
377 | } | ||
378 | |||
379 | int pvr2_encoder_stop(struct pvr2_hdw *hdw) | ||
380 | { | ||
381 | int status; | ||
382 | |||
383 | /* mask all interrupts */ | ||
384 | pvr2_write_register(hdw, 0x0048, 0xffffffff); | ||
385 | |||
386 | if (hdw->config == pvr2_config_vbi) { | ||
387 | status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3, | ||
388 | 0x01,0x01,0x14); | ||
389 | } else if (hdw->config == pvr2_config_mpeg) { | ||
390 | status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3, | ||
391 | 0x01,0,0x13); | ||
392 | } else { | ||
393 | status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3, | ||
394 | 0x01,0,0x13); | ||
395 | } | ||
396 | |||
397 | /* change some GPIO data */ | ||
398 | /* Note: Bit d7 of dir appears to control the LED. So we shut it | ||
399 | off here. */ | ||
400 | pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000401); | ||
401 | pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000000); | ||
402 | |||
403 | if (!status) { | ||
404 | hdw->subsys_enabled_mask &= ~(1<<PVR2_SUBSYS_B_ENC_RUN); | ||
405 | } | ||
406 | return status; | ||
407 | } | ||
408 | |||
409 | |||
410 | /* | ||
411 | Stuff for Emacs to see, in order to encourage consistent editing style: | ||
412 | *** Local Variables: *** | ||
413 | *** mode: c *** | ||
414 | *** fill-column: 70 *** | ||
415 | *** tab-width: 8 *** | ||
416 | *** c-basic-offset: 8 *** | ||
417 | *** End: *** | ||
418 | */ | ||
diff --git a/drivers/media/video/pvrusb2/pvrusb2-encoder.h b/drivers/media/video/pvrusb2/pvrusb2-encoder.h new file mode 100644 index 000000000000..01b5a0b89c03 --- /dev/null +++ b/drivers/media/video/pvrusb2/pvrusb2-encoder.h | |||
@@ -0,0 +1,42 @@ | |||
1 | /* | ||
2 | * | ||
3 | * $Id$ | ||
4 | * | ||
5 | * Copyright (C) 2005 Mike Isely <isely@pobox.com> | ||
6 | * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License | ||
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 | |||
23 | #ifndef __PVRUSB2_ENCODER_H | ||
24 | #define __PVRUSB2_ENCODER_H | ||
25 | |||
26 | struct pvr2_hdw; | ||
27 | |||
28 | int pvr2_encoder_configure(struct pvr2_hdw *); | ||
29 | int pvr2_encoder_start(struct pvr2_hdw *); | ||
30 | int pvr2_encoder_stop(struct pvr2_hdw *); | ||
31 | |||
32 | #endif /* __PVRUSB2_ENCODER_H */ | ||
33 | |||
34 | /* | ||
35 | Stuff for Emacs to see, in order to encourage consistent editing style: | ||
36 | *** Local Variables: *** | ||
37 | *** mode: c *** | ||
38 | *** fill-column: 70 *** | ||
39 | *** tab-width: 8 *** | ||
40 | *** c-basic-offset: 8 *** | ||
41 | *** End: *** | ||
42 | */ | ||
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h new file mode 100644 index 000000000000..ba2afbfe32c5 --- /dev/null +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h | |||
@@ -0,0 +1,384 @@ | |||
1 | /* | ||
2 | * | ||
3 | * $Id$ | ||
4 | * | ||
5 | * Copyright (C) 2005 Mike Isely <isely@pobox.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 | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | * | ||
20 | */ | ||
21 | #ifndef __PVRUSB2_HDW_INTERNAL_H | ||
22 | #define __PVRUSB2_HDW_INTERNAL_H | ||
23 | |||
24 | /* | ||
25 | |||
26 | This header sets up all the internal structures and definitions needed to | ||
27 | track and coordinate the driver's interaction with the hardware. ONLY | ||
28 | source files which actually implement part of that whole circus should be | ||
29 | including this header. Higher levels, like the external layers to the | ||
30 | various public APIs (V4L, sysfs, etc) should NOT ever include this | ||
31 | private, internal header. This means that pvrusb2-hdw, pvrusb2-encoder, | ||
32 | etc will include this, but pvrusb2-v4l should not. | ||
33 | |||
34 | */ | ||
35 | |||
36 | #include <linux/config.h> | ||
37 | #include <linux/videodev2.h> | ||
38 | #include <linux/i2c.h> | ||
39 | #include <linux/mutex.h> | ||
40 | #include "pvrusb2-hdw.h" | ||
41 | #include "pvrusb2-io.h" | ||
42 | #include <media/cx2341x.h> | ||
43 | |||
44 | /* Legal values for the SRATE state variable */ | ||
45 | #define PVR2_CVAL_SRATE_48 0 | ||
46 | #define PVR2_CVAL_SRATE_44_1 1 | ||
47 | |||
48 | /* Legal values for the AUDIOBITRATE state variable */ | ||
49 | #define PVR2_CVAL_AUDIOBITRATE_384 0 | ||
50 | #define PVR2_CVAL_AUDIOBITRATE_320 1 | ||
51 | #define PVR2_CVAL_AUDIOBITRATE_256 2 | ||
52 | #define PVR2_CVAL_AUDIOBITRATE_224 3 | ||
53 | #define PVR2_CVAL_AUDIOBITRATE_192 4 | ||
54 | #define PVR2_CVAL_AUDIOBITRATE_160 5 | ||
55 | #define PVR2_CVAL_AUDIOBITRATE_128 6 | ||
56 | #define PVR2_CVAL_AUDIOBITRATE_112 7 | ||
57 | #define PVR2_CVAL_AUDIOBITRATE_96 8 | ||
58 | #define PVR2_CVAL_AUDIOBITRATE_80 9 | ||
59 | #define PVR2_CVAL_AUDIOBITRATE_64 10 | ||
60 | #define PVR2_CVAL_AUDIOBITRATE_56 11 | ||
61 | #define PVR2_CVAL_AUDIOBITRATE_48 12 | ||
62 | #define PVR2_CVAL_AUDIOBITRATE_32 13 | ||
63 | #define PVR2_CVAL_AUDIOBITRATE_VBR 14 | ||
64 | |||
65 | /* Legal values for the AUDIOEMPHASIS state variable */ | ||
66 | #define PVR2_CVAL_AUDIOEMPHASIS_NONE 0 | ||
67 | #define PVR2_CVAL_AUDIOEMPHASIS_50_15 1 | ||
68 | #define PVR2_CVAL_AUDIOEMPHASIS_CCITT 2 | ||
69 | |||
70 | /* Legal values for PVR2_CID_HSM */ | ||
71 | #define PVR2_CVAL_HSM_FAIL 0 | ||
72 | #define PVR2_CVAL_HSM_FULL 1 | ||
73 | #define PVR2_CVAL_HSM_HIGH 2 | ||
74 | |||
75 | #define PVR2_VID_ENDPOINT 0x84 | ||
76 | #define PVR2_UNK_ENDPOINT 0x86 /* maybe raw yuv ? */ | ||
77 | #define PVR2_VBI_ENDPOINT 0x88 | ||
78 | |||
79 | #define PVR2_CTL_BUFFSIZE 64 | ||
80 | |||
81 | #define FREQTABLE_SIZE 500 | ||
82 | |||
83 | #define LOCK_TAKE(x) do { mutex_lock(&x##_mutex); x##_held = !0; } while (0) | ||
84 | #define LOCK_GIVE(x) do { x##_held = 0; mutex_unlock(&x##_mutex); } while (0) | ||
85 | |||
86 | struct pvr2_decoder; | ||
87 | |||
88 | typedef int (*pvr2_ctlf_is_dirty)(struct pvr2_ctrl *); | ||
89 | typedef void (*pvr2_ctlf_clear_dirty)(struct pvr2_ctrl *); | ||
90 | typedef int (*pvr2_ctlf_get_value)(struct pvr2_ctrl *,int *); | ||
91 | typedef int (*pvr2_ctlf_set_value)(struct pvr2_ctrl *,int msk,int val); | ||
92 | typedef int (*pvr2_ctlf_val_to_sym)(struct pvr2_ctrl *,int msk,int val, | ||
93 | char *,unsigned int,unsigned int *); | ||
94 | typedef int (*pvr2_ctlf_sym_to_val)(struct pvr2_ctrl *, | ||
95 | const char *,unsigned int, | ||
96 | int *mskp,int *valp); | ||
97 | typedef unsigned int (*pvr2_ctlf_get_v4lflags)(struct pvr2_ctrl *); | ||
98 | |||
99 | /* This structure describes a specific control. A table of these is set up | ||
100 | in pvrusb2-hdw.c. */ | ||
101 | struct pvr2_ctl_info { | ||
102 | /* Control's name suitable for use as an identifier */ | ||
103 | const char *name; | ||
104 | |||
105 | /* Short description of control */ | ||
106 | const char *desc; | ||
107 | |||
108 | /* Control's implementation */ | ||
109 | pvr2_ctlf_get_value get_value; /* Get its value */ | ||
110 | pvr2_ctlf_set_value set_value; /* Set its value */ | ||
111 | pvr2_ctlf_val_to_sym val_to_sym; /* Custom convert value->symbol */ | ||
112 | pvr2_ctlf_sym_to_val sym_to_val; /* Custom convert symbol->value */ | ||
113 | pvr2_ctlf_is_dirty is_dirty; /* Return true if dirty */ | ||
114 | pvr2_ctlf_clear_dirty clear_dirty; /* Clear dirty state */ | ||
115 | pvr2_ctlf_get_v4lflags get_v4lflags;/* Retrieve v4l flags */ | ||
116 | |||
117 | /* Control's type (int, enum, bitmask) */ | ||
118 | enum pvr2_ctl_type type; | ||
119 | |||
120 | /* Associated V4L control ID, if any */ | ||
121 | int v4l_id; | ||
122 | |||
123 | /* Associated driver internal ID, if any */ | ||
124 | int internal_id; | ||
125 | |||
126 | /* Don't implicitly initialize this control's value */ | ||
127 | int skip_init; | ||
128 | |||
129 | /* Starting value for this control */ | ||
130 | int default_value; | ||
131 | |||
132 | /* Type-specific control information */ | ||
133 | union { | ||
134 | struct { /* Integer control */ | ||
135 | long min_value; /* lower limit */ | ||
136 | long max_value; /* upper limit */ | ||
137 | } type_int; | ||
138 | struct { /* enumerated control */ | ||
139 | unsigned int count; /* enum value count */ | ||
140 | const char **value_names; /* symbol names */ | ||
141 | } type_enum; | ||
142 | struct { /* bitmask control */ | ||
143 | unsigned int valid_bits; /* bits in use */ | ||
144 | const char **bit_names; /* symbol name/bit */ | ||
145 | } type_bitmask; | ||
146 | } def; | ||
147 | }; | ||
148 | |||
149 | |||
150 | /* Same as pvr2_ctl_info, but includes storage for the control description */ | ||
151 | #define PVR2_CTLD_INFO_DESC_SIZE 32 | ||
152 | struct pvr2_ctld_info { | ||
153 | struct pvr2_ctl_info info; | ||
154 | char desc[PVR2_CTLD_INFO_DESC_SIZE]; | ||
155 | }; | ||
156 | |||
157 | struct pvr2_ctrl { | ||
158 | const struct pvr2_ctl_info *info; | ||
159 | struct pvr2_hdw *hdw; | ||
160 | }; | ||
161 | |||
162 | |||
163 | struct pvr2_audio_stat { | ||
164 | void *ctxt; | ||
165 | void (*detach)(void *); | ||
166 | int (*status)(void *); | ||
167 | }; | ||
168 | |||
169 | struct pvr2_decoder_ctrl { | ||
170 | void *ctxt; | ||
171 | void (*detach)(void *); | ||
172 | void (*enable)(void *,int); | ||
173 | int (*tuned)(void *); | ||
174 | void (*force_reset)(void *); | ||
175 | }; | ||
176 | |||
177 | #define PVR2_I2C_PEND_DETECT 0x01 /* Need to detect a client type */ | ||
178 | #define PVR2_I2C_PEND_CLIENT 0x02 /* Client needs a specific update */ | ||
179 | #define PVR2_I2C_PEND_REFRESH 0x04 /* Client has specific pending bits */ | ||
180 | #define PVR2_I2C_PEND_STALE 0x08 /* Broadcast pending bits */ | ||
181 | |||
182 | #define PVR2_I2C_PEND_ALL (PVR2_I2C_PEND_DETECT |\ | ||
183 | PVR2_I2C_PEND_CLIENT |\ | ||
184 | PVR2_I2C_PEND_REFRESH |\ | ||
185 | PVR2_I2C_PEND_STALE) | ||
186 | |||
187 | /* Disposition of firmware1 loading situation */ | ||
188 | #define FW1_STATE_UNKNOWN 0 | ||
189 | #define FW1_STATE_MISSING 1 | ||
190 | #define FW1_STATE_FAILED 2 | ||
191 | #define FW1_STATE_RELOAD 3 | ||
192 | #define FW1_STATE_OK 4 | ||
193 | |||
194 | /* Known major hardware variants, keyed from device ID */ | ||
195 | #define PVR2_HDW_TYPE_29XXX 0 | ||
196 | #ifdef CONFIG_VIDEO_PVRUSB2_24XXX | ||
197 | #define PVR2_HDW_TYPE_24XXX 1 | ||
198 | #endif | ||
199 | |||
200 | typedef int (*pvr2_i2c_func)(struct pvr2_hdw *,u8,u8 *,u16,u8 *, u16); | ||
201 | #define PVR2_I2C_FUNC_CNT 128 | ||
202 | |||
203 | /* This structure contains all state data directly needed to | ||
204 | manipulate the hardware (as opposed to complying with a kernel | ||
205 | interface) */ | ||
206 | struct pvr2_hdw { | ||
207 | /* Underlying USB device handle */ | ||
208 | struct usb_device *usb_dev; | ||
209 | struct usb_interface *usb_intf; | ||
210 | |||
211 | /* Device type, one of PVR2_HDW_TYPE_xxxxx */ | ||
212 | unsigned int hdw_type; | ||
213 | |||
214 | /* Video spigot */ | ||
215 | struct pvr2_stream *vid_stream; | ||
216 | |||
217 | /* Mutex for all hardware state control */ | ||
218 | struct mutex big_lock_mutex; | ||
219 | int big_lock_held; /* For debugging */ | ||
220 | |||
221 | void (*poll_trigger_func)(void *); | ||
222 | void *poll_trigger_data; | ||
223 | |||
224 | char name[32]; | ||
225 | |||
226 | /* I2C stuff */ | ||
227 | struct i2c_adapter i2c_adap; | ||
228 | struct i2c_algorithm i2c_algo; | ||
229 | pvr2_i2c_func i2c_func[PVR2_I2C_FUNC_CNT]; | ||
230 | int i2c_cx25840_hack_state; | ||
231 | int i2c_linked; | ||
232 | unsigned int i2c_pend_types; /* Which types of update are needed */ | ||
233 | unsigned long i2c_pend_mask; /* Change bits we need to scan */ | ||
234 | unsigned long i2c_stale_mask; /* Pending broadcast change bits */ | ||
235 | unsigned long i2c_active_mask; /* All change bits currently in use */ | ||
236 | struct list_head i2c_clients; | ||
237 | struct mutex i2c_list_lock; | ||
238 | |||
239 | /* Frequency table */ | ||
240 | unsigned int freqTable[FREQTABLE_SIZE]; | ||
241 | unsigned int freqProgSlot; | ||
242 | unsigned int freqSlot; | ||
243 | |||
244 | /* Stuff for handling low level control interaction with device */ | ||
245 | struct mutex ctl_lock_mutex; | ||
246 | int ctl_lock_held; /* For debugging */ | ||
247 | struct urb *ctl_write_urb; | ||
248 | struct urb *ctl_read_urb; | ||
249 | unsigned char *ctl_write_buffer; | ||
250 | unsigned char *ctl_read_buffer; | ||
251 | volatile int ctl_write_pend_flag; | ||
252 | volatile int ctl_read_pend_flag; | ||
253 | volatile int ctl_timeout_flag; | ||
254 | struct completion ctl_done; | ||
255 | unsigned char cmd_buffer[PVR2_CTL_BUFFSIZE]; | ||
256 | int cmd_debug_state; // Low level command debugging info | ||
257 | unsigned char cmd_debug_code; // | ||
258 | unsigned int cmd_debug_write_len; // | ||
259 | unsigned int cmd_debug_read_len; // | ||
260 | |||
261 | int flag_ok; // device in known good state | ||
262 | int flag_disconnected; // flag_ok == 0 due to disconnect | ||
263 | int flag_init_ok; // true if structure is fully initialized | ||
264 | int flag_streaming_enabled; // true if streaming should be on | ||
265 | int fw1_state; // current situation with fw1 | ||
266 | |||
267 | int flag_decoder_is_tuned; | ||
268 | |||
269 | struct pvr2_decoder_ctrl *decoder_ctrl; | ||
270 | |||
271 | // CPU firmware info (used to help find / save firmware data) | ||
272 | char *fw_buffer; | ||
273 | unsigned int fw_size; | ||
274 | |||
275 | // Which subsystem pieces have been enabled / configured | ||
276 | unsigned long subsys_enabled_mask; | ||
277 | |||
278 | // Which subsystems are manipulated to enable streaming | ||
279 | unsigned long subsys_stream_mask; | ||
280 | |||
281 | // True if there is a request to trigger logging of state in each | ||
282 | // module. | ||
283 | int log_requested; | ||
284 | |||
285 | /* Tuner / frequency control stuff */ | ||
286 | unsigned int tuner_type; | ||
287 | int tuner_updated; | ||
288 | unsigned int freqVal; | ||
289 | int freqDirty; | ||
290 | |||
291 | /* Video standard handling */ | ||
292 | v4l2_std_id std_mask_eeprom; // Hardware supported selections | ||
293 | v4l2_std_id std_mask_avail; // Which standards we may select from | ||
294 | v4l2_std_id std_mask_cur; // Currently selected standard(s) | ||
295 | unsigned int std_enum_cnt; // # of enumerated standards | ||
296 | int std_enum_cur; // selected standard enumeration value | ||
297 | int std_dirty; // True if std_mask_cur has changed | ||
298 | struct pvr2_ctl_info std_info_enum; | ||
299 | struct pvr2_ctl_info std_info_avail; | ||
300 | struct pvr2_ctl_info std_info_cur; | ||
301 | struct v4l2_standard *std_defs; | ||
302 | const char **std_enum_names; | ||
303 | |||
304 | // Generated string names, one per actual V4L2 standard | ||
305 | const char *std_mask_ptrs[32]; | ||
306 | char std_mask_names[32][10]; | ||
307 | |||
308 | int unit_number; /* ID for driver instance */ | ||
309 | unsigned long serial_number; /* ID for hardware itself */ | ||
310 | |||
311 | /* Minor number used by v4l logic (yes, this is a hack, as there should | ||
312 | be no v4l junk here). Probably a better way to do this. */ | ||
313 | int v4l_minor_number; | ||
314 | |||
315 | /* Location of eeprom or a negative number if none */ | ||
316 | int eeprom_addr; | ||
317 | |||
318 | enum pvr2_config config; | ||
319 | |||
320 | /* Information about what audio signal we're hearing */ | ||
321 | int flag_stereo; | ||
322 | int flag_bilingual; | ||
323 | struct pvr2_audio_stat *audio_stat; | ||
324 | |||
325 | /* Control state needed for cx2341x module */ | ||
326 | struct cx2341x_mpeg_params enc_cur_state; | ||
327 | struct cx2341x_mpeg_params enc_ctl_state; | ||
328 | /* True if an encoder attribute has changed */ | ||
329 | int enc_stale; | ||
330 | /* True if enc_cur_state is valid */ | ||
331 | int enc_cur_valid; | ||
332 | |||
333 | /* Control state */ | ||
334 | #define VCREATE_DATA(lab) int lab##_val; int lab##_dirty | ||
335 | VCREATE_DATA(brightness); | ||
336 | VCREATE_DATA(contrast); | ||
337 | VCREATE_DATA(saturation); | ||
338 | VCREATE_DATA(hue); | ||
339 | VCREATE_DATA(volume); | ||
340 | VCREATE_DATA(balance); | ||
341 | VCREATE_DATA(bass); | ||
342 | VCREATE_DATA(treble); | ||
343 | VCREATE_DATA(mute); | ||
344 | VCREATE_DATA(input); | ||
345 | VCREATE_DATA(audiomode); | ||
346 | VCREATE_DATA(res_hor); | ||
347 | VCREATE_DATA(res_ver); | ||
348 | VCREATE_DATA(srate); | ||
349 | #undef VCREATE_DATA | ||
350 | |||
351 | struct pvr2_ctld_info *mpeg_ctrl_info; | ||
352 | |||
353 | struct pvr2_ctrl *controls; | ||
354 | unsigned int control_cnt; | ||
355 | }; | ||
356 | |||
357 | int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw); | ||
358 | |||
359 | unsigned int pvr2_hdw_get_signal_status_internal(struct pvr2_hdw *); | ||
360 | |||
361 | void pvr2_hdw_subsys_bit_chg_no_lock(struct pvr2_hdw *hdw, | ||
362 | unsigned long msk,unsigned long val); | ||
363 | void pvr2_hdw_subsys_stream_bit_chg_no_lock(struct pvr2_hdw *hdw, | ||
364 | unsigned long msk, | ||
365 | unsigned long val); | ||
366 | |||
367 | void pvr2_hdw_internal_find_stdenum(struct pvr2_hdw *hdw); | ||
368 | void pvr2_hdw_internal_set_std_avail(struct pvr2_hdw *hdw); | ||
369 | |||
370 | int pvr2_i2c_basic_op(struct pvr2_hdw *,u8 i2c_addr, | ||
371 | u8 *wdata,u16 wlen, | ||
372 | u8 *rdata,u16 rlen); | ||
373 | |||
374 | #endif /* __PVRUSB2_HDW_INTERNAL_H */ | ||
375 | |||
376 | /* | ||
377 | Stuff for Emacs to see, in order to encourage consistent editing style: | ||
378 | *** Local Variables: *** | ||
379 | *** mode: c *** | ||
380 | *** fill-column: 75 *** | ||
381 | *** tab-width: 8 *** | ||
382 | *** c-basic-offset: 8 *** | ||
383 | *** End: *** | ||
384 | */ | ||
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c new file mode 100644 index 000000000000..643c471375da --- /dev/null +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c | |||
@@ -0,0 +1,3120 @@ | |||
1 | /* | ||
2 | * | ||
3 | * $Id$ | ||
4 | * | ||
5 | * Copyright (C) 2005 Mike Isely <isely@pobox.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 | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include <linux/errno.h> | ||
23 | #include <linux/string.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/firmware.h> | ||
26 | #include <linux/videodev2.h> | ||
27 | #include <asm/semaphore.h> | ||
28 | #include "pvrusb2.h" | ||
29 | #include "pvrusb2-std.h" | ||
30 | #include "pvrusb2-util.h" | ||
31 | #include "pvrusb2-hdw.h" | ||
32 | #include "pvrusb2-i2c-core.h" | ||
33 | #include "pvrusb2-tuner.h" | ||
34 | #include "pvrusb2-eeprom.h" | ||
35 | #include "pvrusb2-hdw-internal.h" | ||
36 | #include "pvrusb2-encoder.h" | ||
37 | #include "pvrusb2-debug.h" | ||
38 | |||
39 | struct usb_device_id pvr2_device_table[] = { | ||
40 | [PVR2_HDW_TYPE_29XXX] = { USB_DEVICE(0x2040, 0x2900) }, | ||
41 | #ifdef CONFIG_VIDEO_PVRUSB2_24XXX | ||
42 | [PVR2_HDW_TYPE_24XXX] = { USB_DEVICE(0x2040, 0x2400) }, | ||
43 | #endif | ||
44 | { } | ||
45 | }; | ||
46 | |||
47 | MODULE_DEVICE_TABLE(usb, pvr2_device_table); | ||
48 | |||
49 | static const char *pvr2_device_names[] = { | ||
50 | [PVR2_HDW_TYPE_29XXX] = "WinTV PVR USB2 Model Category 29xxxx", | ||
51 | #ifdef CONFIG_VIDEO_PVRUSB2_24XXX | ||
52 | [PVR2_HDW_TYPE_24XXX] = "WinTV PVR USB2 Model Category 24xxxx", | ||
53 | #endif | ||
54 | }; | ||
55 | |||
56 | struct pvr2_string_table { | ||
57 | const char **lst; | ||
58 | unsigned int cnt; | ||
59 | }; | ||
60 | |||
61 | #ifdef CONFIG_VIDEO_PVRUSB2_24XXX | ||
62 | // Names of other client modules to request for 24xxx model hardware | ||
63 | static const char *pvr2_client_24xxx[] = { | ||
64 | "cx25840", | ||
65 | "tuner", | ||
66 | "tda9887", | ||
67 | "wm8775", | ||
68 | }; | ||
69 | #endif | ||
70 | |||
71 | // Names of other client modules to request for 29xxx model hardware | ||
72 | static const char *pvr2_client_29xxx[] = { | ||
73 | "msp3400", | ||
74 | "saa7115", | ||
75 | "tuner", | ||
76 | "tda9887", | ||
77 | }; | ||
78 | |||
79 | static struct pvr2_string_table pvr2_client_lists[] = { | ||
80 | [PVR2_HDW_TYPE_29XXX] = { | ||
81 | pvr2_client_29xxx, | ||
82 | sizeof(pvr2_client_29xxx)/sizeof(pvr2_client_29xxx[0]), | ||
83 | }, | ||
84 | #ifdef CONFIG_VIDEO_PVRUSB2_24XXX | ||
85 | [PVR2_HDW_TYPE_24XXX] = { | ||
86 | pvr2_client_24xxx, | ||
87 | sizeof(pvr2_client_24xxx)/sizeof(pvr2_client_24xxx[0]), | ||
88 | }, | ||
89 | #endif | ||
90 | }; | ||
91 | |||
92 | static struct pvr2_hdw *unit_pointers[PVR_NUM] = {[ 0 ... PVR_NUM-1 ] = 0}; | ||
93 | DECLARE_MUTEX(pvr2_unit_sem); | ||
94 | |||
95 | static int ctlchg = 0; | ||
96 | static int initusbreset = 1; | ||
97 | static int procreload = 0; | ||
98 | static int tuner[PVR_NUM] = { [0 ... PVR_NUM-1] = -1 }; | ||
99 | static int tolerance[PVR_NUM] = { [0 ... PVR_NUM-1] = 0 }; | ||
100 | static int video_std[PVR_NUM] = { [0 ... PVR_NUM-1] = 0 }; | ||
101 | static int init_pause_msec = 0; | ||
102 | |||
103 | module_param(ctlchg, int, S_IRUGO|S_IWUSR); | ||
104 | MODULE_PARM_DESC(ctlchg, "0=optimize ctl change 1=always accept new ctl value"); | ||
105 | module_param(init_pause_msec, int, S_IRUGO|S_IWUSR); | ||
106 | MODULE_PARM_DESC(init_pause_msec, "hardware initialization settling delay"); | ||
107 | module_param(initusbreset, int, S_IRUGO|S_IWUSR); | ||
108 | MODULE_PARM_DESC(initusbreset, "Do USB reset device on probe"); | ||
109 | module_param(procreload, int, S_IRUGO|S_IWUSR); | ||
110 | MODULE_PARM_DESC(procreload, | ||
111 | "Attempt init failure recovery with firmware reload"); | ||
112 | module_param_array(tuner, int, NULL, 0444); | ||
113 | MODULE_PARM_DESC(tuner,"specify installed tuner type"); | ||
114 | module_param_array(video_std, int, NULL, 0444); | ||
115 | MODULE_PARM_DESC(video_std,"specify initial video standard"); | ||
116 | module_param_array(tolerance, int, NULL, 0444); | ||
117 | MODULE_PARM_DESC(tolerance,"specify stream error tolerance"); | ||
118 | |||
119 | #define PVR2_CTL_WRITE_ENDPOINT 0x01 | ||
120 | #define PVR2_CTL_READ_ENDPOINT 0x81 | ||
121 | |||
122 | #define PVR2_GPIO_IN 0x9008 | ||
123 | #define PVR2_GPIO_OUT 0x900c | ||
124 | #define PVR2_GPIO_DIR 0x9020 | ||
125 | |||
126 | #define trace_firmware(...) pvr2_trace(PVR2_TRACE_FIRMWARE,__VA_ARGS__) | ||
127 | |||
128 | #define PVR2_FIRMWARE_ENDPOINT 0x02 | ||
129 | |||
130 | /* size of a firmware chunk */ | ||
131 | #define FIRMWARE_CHUNK_SIZE 0x2000 | ||
132 | |||
133 | /* Define the list of additional controls we'll dynamically construct based | ||
134 | on query of the cx2341x module. */ | ||
135 | struct pvr2_mpeg_ids { | ||
136 | const char *strid; | ||
137 | int id; | ||
138 | }; | ||
139 | static const struct pvr2_mpeg_ids mpeg_ids[] = { | ||
140 | { | ||
141 | .strid = "audio_layer", | ||
142 | .id = V4L2_CID_MPEG_AUDIO_ENCODING, | ||
143 | },{ | ||
144 | .strid = "audio_bitrate", | ||
145 | .id = V4L2_CID_MPEG_AUDIO_L2_BITRATE, | ||
146 | },{ | ||
147 | /* Already using audio_mode elsewhere :-( */ | ||
148 | .strid = "mpeg_audio_mode", | ||
149 | .id = V4L2_CID_MPEG_AUDIO_MODE, | ||
150 | },{ | ||
151 | .strid = "mpeg_audio_mode_extension", | ||
152 | .id = V4L2_CID_MPEG_AUDIO_MODE_EXTENSION, | ||
153 | },{ | ||
154 | .strid = "audio_emphasis", | ||
155 | .id = V4L2_CID_MPEG_AUDIO_EMPHASIS, | ||
156 | },{ | ||
157 | .strid = "audio_crc", | ||
158 | .id = V4L2_CID_MPEG_AUDIO_CRC, | ||
159 | },{ | ||
160 | .strid = "video_aspect", | ||
161 | .id = V4L2_CID_MPEG_VIDEO_ASPECT, | ||
162 | },{ | ||
163 | .strid = "video_b_frames", | ||
164 | .id = V4L2_CID_MPEG_VIDEO_B_FRAMES, | ||
165 | },{ | ||
166 | .strid = "video_gop_size", | ||
167 | .id = V4L2_CID_MPEG_VIDEO_GOP_SIZE, | ||
168 | },{ | ||
169 | .strid = "video_gop_closure", | ||
170 | .id = V4L2_CID_MPEG_VIDEO_GOP_CLOSURE, | ||
171 | },{ | ||
172 | .strid = "video_pulldown", | ||
173 | .id = V4L2_CID_MPEG_VIDEO_PULLDOWN, | ||
174 | },{ | ||
175 | .strid = "video_bitrate_mode", | ||
176 | .id = V4L2_CID_MPEG_VIDEO_BITRATE_MODE, | ||
177 | },{ | ||
178 | .strid = "video_bitrate", | ||
179 | .id = V4L2_CID_MPEG_VIDEO_BITRATE, | ||
180 | },{ | ||
181 | .strid = "video_bitrate_peak", | ||
182 | .id = V4L2_CID_MPEG_VIDEO_BITRATE_PEAK, | ||
183 | },{ | ||
184 | .strid = "video_temporal_decimation", | ||
185 | .id = V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION, | ||
186 | },{ | ||
187 | .strid = "stream_type", | ||
188 | .id = V4L2_CID_MPEG_STREAM_TYPE, | ||
189 | },{ | ||
190 | .strid = "video_spatial_filter_mode", | ||
191 | .id = V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE, | ||
192 | },{ | ||
193 | .strid = "video_spatial_filter", | ||
194 | .id = V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER, | ||
195 | },{ | ||
196 | .strid = "video_luma_spatial_filter_type", | ||
197 | .id = V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE, | ||
198 | },{ | ||
199 | .strid = "video_chroma_spatial_filter_type", | ||
200 | .id = V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE, | ||
201 | },{ | ||
202 | .strid = "video_temporal_filter_mode", | ||
203 | .id = V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE, | ||
204 | },{ | ||
205 | .strid = "video_temporal_filter", | ||
206 | .id = V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER, | ||
207 | },{ | ||
208 | .strid = "video_median_filter_type", | ||
209 | .id = V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE, | ||
210 | },{ | ||
211 | .strid = "video_luma_median_filter_top", | ||
212 | .id = V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP, | ||
213 | },{ | ||
214 | .strid = "video_luma_median_filter_bottom", | ||
215 | .id = V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM, | ||
216 | },{ | ||
217 | .strid = "video_chroma_median_filter_top", | ||
218 | .id = V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP, | ||
219 | },{ | ||
220 | .strid = "video_chroma_median_filter_bottom", | ||
221 | .id = V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM, | ||
222 | } | ||
223 | }; | ||
224 | #define MPEGDEF_COUNT (sizeof(mpeg_ids)/sizeof(mpeg_ids[0])) | ||
225 | |||
226 | static const char *control_values_srate[] = { | ||
227 | [PVR2_CVAL_SRATE_48] = "48KHz", | ||
228 | [PVR2_CVAL_SRATE_44_1] = "44.1KHz", | ||
229 | }; | ||
230 | |||
231 | |||
232 | |||
233 | |||
234 | static const char *control_values_input[] = { | ||
235 | [PVR2_CVAL_INPUT_TV] = "television", /*xawtv needs this name*/ | ||
236 | [PVR2_CVAL_INPUT_RADIO] = "radio", | ||
237 | [PVR2_CVAL_INPUT_SVIDEO] = "s-video", | ||
238 | [PVR2_CVAL_INPUT_COMPOSITE] = "composite", | ||
239 | }; | ||
240 | |||
241 | |||
242 | static const char *control_values_audiomode[] = { | ||
243 | [V4L2_TUNER_MODE_MONO] = "Mono", | ||
244 | [V4L2_TUNER_MODE_STEREO] = "Stereo", | ||
245 | [V4L2_TUNER_MODE_LANG1] = "Lang1", | ||
246 | [V4L2_TUNER_MODE_LANG2] = "Lang2", | ||
247 | [V4L2_TUNER_MODE_LANG1_LANG2] = "Lang1+Lang2", | ||
248 | }; | ||
249 | |||
250 | |||
251 | static const char *control_values_hsm[] = { | ||
252 | [PVR2_CVAL_HSM_FAIL] = "Fail", | ||
253 | [PVR2_CVAL_HSM_HIGH] = "High", | ||
254 | [PVR2_CVAL_HSM_FULL] = "Full", | ||
255 | }; | ||
256 | |||
257 | |||
258 | static const char *control_values_subsystem[] = { | ||
259 | [PVR2_SUBSYS_B_ENC_FIRMWARE] = "enc_firmware", | ||
260 | [PVR2_SUBSYS_B_ENC_CFG] = "enc_config", | ||
261 | [PVR2_SUBSYS_B_DIGITIZER_RUN] = "digitizer_run", | ||
262 | [PVR2_SUBSYS_B_USBSTREAM_RUN] = "usbstream_run", | ||
263 | [PVR2_SUBSYS_B_ENC_RUN] = "enc_run", | ||
264 | }; | ||
265 | |||
266 | |||
267 | static int ctrl_channelfreq_get(struct pvr2_ctrl *cptr,int *vp) | ||
268 | { | ||
269 | struct pvr2_hdw *hdw = cptr->hdw; | ||
270 | if ((hdw->freqProgSlot > 0) && (hdw->freqProgSlot <= FREQTABLE_SIZE)) { | ||
271 | *vp = hdw->freqTable[hdw->freqProgSlot-1]; | ||
272 | } else { | ||
273 | *vp = 0; | ||
274 | } | ||
275 | return 0; | ||
276 | } | ||
277 | |||
278 | static int ctrl_channelfreq_set(struct pvr2_ctrl *cptr,int m,int v) | ||
279 | { | ||
280 | struct pvr2_hdw *hdw = cptr->hdw; | ||
281 | if ((hdw->freqProgSlot > 0) && (hdw->freqProgSlot <= FREQTABLE_SIZE)) { | ||
282 | hdw->freqTable[hdw->freqProgSlot-1] = v; | ||
283 | } | ||
284 | return 0; | ||
285 | } | ||
286 | |||
287 | static int ctrl_channelprog_get(struct pvr2_ctrl *cptr,int *vp) | ||
288 | { | ||
289 | *vp = cptr->hdw->freqProgSlot; | ||
290 | return 0; | ||
291 | } | ||
292 | |||
293 | static int ctrl_channelprog_set(struct pvr2_ctrl *cptr,int m,int v) | ||
294 | { | ||
295 | struct pvr2_hdw *hdw = cptr->hdw; | ||
296 | if ((v >= 0) && (v <= FREQTABLE_SIZE)) { | ||
297 | hdw->freqProgSlot = v; | ||
298 | } | ||
299 | return 0; | ||
300 | } | ||
301 | |||
302 | static int ctrl_channel_get(struct pvr2_ctrl *cptr,int *vp) | ||
303 | { | ||
304 | *vp = cptr->hdw->freqSlot; | ||
305 | return 0; | ||
306 | } | ||
307 | |||
308 | static int ctrl_channel_set(struct pvr2_ctrl *cptr,int m,int v) | ||
309 | { | ||
310 | unsigned freq = 0; | ||
311 | struct pvr2_hdw *hdw = cptr->hdw; | ||
312 | hdw->freqSlot = v; | ||
313 | if ((hdw->freqSlot > 0) && (hdw->freqSlot <= FREQTABLE_SIZE)) { | ||
314 | freq = hdw->freqTable[hdw->freqSlot-1]; | ||
315 | } | ||
316 | if (freq && (freq != hdw->freqVal)) { | ||
317 | hdw->freqVal = freq; | ||
318 | hdw->freqDirty = !0; | ||
319 | } | ||
320 | return 0; | ||
321 | } | ||
322 | |||
323 | static int ctrl_freq_get(struct pvr2_ctrl *cptr,int *vp) | ||
324 | { | ||
325 | *vp = cptr->hdw->freqVal; | ||
326 | return 0; | ||
327 | } | ||
328 | |||
329 | static int ctrl_freq_is_dirty(struct pvr2_ctrl *cptr) | ||
330 | { | ||
331 | return cptr->hdw->freqDirty != 0; | ||
332 | } | ||
333 | |||
334 | static void ctrl_freq_clear_dirty(struct pvr2_ctrl *cptr) | ||
335 | { | ||
336 | cptr->hdw->freqDirty = 0; | ||
337 | } | ||
338 | |||
339 | static int ctrl_freq_set(struct pvr2_ctrl *cptr,int m,int v) | ||
340 | { | ||
341 | struct pvr2_hdw *hdw = cptr->hdw; | ||
342 | hdw->freqVal = v; | ||
343 | hdw->freqDirty = !0; | ||
344 | hdw->freqSlot = 0; | ||
345 | return 0; | ||
346 | } | ||
347 | |||
348 | static int ctrl_cx2341x_is_dirty(struct pvr2_ctrl *cptr) | ||
349 | { | ||
350 | return cptr->hdw->enc_stale != 0; | ||
351 | } | ||
352 | |||
353 | static void ctrl_cx2341x_clear_dirty(struct pvr2_ctrl *cptr) | ||
354 | { | ||
355 | cptr->hdw->enc_stale = 0; | ||
356 | } | ||
357 | |||
358 | static int ctrl_cx2341x_get(struct pvr2_ctrl *cptr,int *vp) | ||
359 | { | ||
360 | int ret; | ||
361 | struct v4l2_ext_controls cs; | ||
362 | struct v4l2_ext_control c1; | ||
363 | memset(&cs,0,sizeof(cs)); | ||
364 | memset(&c1,0,sizeof(c1)); | ||
365 | cs.controls = &c1; | ||
366 | cs.count = 1; | ||
367 | c1.id = cptr->info->v4l_id; | ||
368 | ret = cx2341x_ext_ctrls(&cptr->hdw->enc_ctl_state,&cs, | ||
369 | VIDIOC_G_EXT_CTRLS); | ||
370 | if (ret) return ret; | ||
371 | *vp = c1.value; | ||
372 | return 0; | ||
373 | } | ||
374 | |||
375 | static int ctrl_cx2341x_set(struct pvr2_ctrl *cptr,int m,int v) | ||
376 | { | ||
377 | int ret; | ||
378 | struct v4l2_ext_controls cs; | ||
379 | struct v4l2_ext_control c1; | ||
380 | memset(&cs,0,sizeof(cs)); | ||
381 | memset(&c1,0,sizeof(c1)); | ||
382 | cs.controls = &c1; | ||
383 | cs.count = 1; | ||
384 | c1.id = cptr->info->v4l_id; | ||
385 | c1.value = v; | ||
386 | ret = cx2341x_ext_ctrls(&cptr->hdw->enc_ctl_state,&cs, | ||
387 | VIDIOC_S_EXT_CTRLS); | ||
388 | if (ret) return ret; | ||
389 | cptr->hdw->enc_stale = !0; | ||
390 | return 0; | ||
391 | } | ||
392 | |||
393 | static unsigned int ctrl_cx2341x_getv4lflags(struct pvr2_ctrl *cptr) | ||
394 | { | ||
395 | struct v4l2_queryctrl qctrl; | ||
396 | struct pvr2_ctl_info *info; | ||
397 | qctrl.id = cptr->info->v4l_id; | ||
398 | cx2341x_ctrl_query(&cptr->hdw->enc_ctl_state,&qctrl); | ||
399 | /* Strip out the const so we can adjust a function pointer. It's | ||
400 | OK to do this here because we know this is a dynamically created | ||
401 | control, so the underlying storage for the info pointer is (a) | ||
402 | private to us, and (b) not in read-only storage. Either we do | ||
403 | this or we significantly complicate the underlying control | ||
404 | implementation. */ | ||
405 | info = (struct pvr2_ctl_info *)(cptr->info); | ||
406 | if (qctrl.flags & V4L2_CTRL_FLAG_READ_ONLY) { | ||
407 | if (info->set_value) { | ||
408 | info->set_value = 0; | ||
409 | } | ||
410 | } else { | ||
411 | if (!(info->set_value)) { | ||
412 | info->set_value = ctrl_cx2341x_set; | ||
413 | } | ||
414 | } | ||
415 | return qctrl.flags; | ||
416 | } | ||
417 | |||
418 | static int ctrl_streamingenabled_get(struct pvr2_ctrl *cptr,int *vp) | ||
419 | { | ||
420 | *vp = cptr->hdw->flag_streaming_enabled; | ||
421 | return 0; | ||
422 | } | ||
423 | |||
424 | static int ctrl_hsm_get(struct pvr2_ctrl *cptr,int *vp) | ||
425 | { | ||
426 | int result = pvr2_hdw_is_hsm(cptr->hdw); | ||
427 | *vp = PVR2_CVAL_HSM_FULL; | ||
428 | if (result < 0) *vp = PVR2_CVAL_HSM_FAIL; | ||
429 | if (result) *vp = PVR2_CVAL_HSM_HIGH; | ||
430 | return 0; | ||
431 | } | ||
432 | |||
433 | static int ctrl_stdavail_get(struct pvr2_ctrl *cptr,int *vp) | ||
434 | { | ||
435 | *vp = cptr->hdw->std_mask_avail; | ||
436 | return 0; | ||
437 | } | ||
438 | |||
439 | static int ctrl_stdavail_set(struct pvr2_ctrl *cptr,int m,int v) | ||
440 | { | ||
441 | struct pvr2_hdw *hdw = cptr->hdw; | ||
442 | v4l2_std_id ns; | ||
443 | ns = hdw->std_mask_avail; | ||
444 | ns = (ns & ~m) | (v & m); | ||
445 | if (ns == hdw->std_mask_avail) return 0; | ||
446 | hdw->std_mask_avail = ns; | ||
447 | pvr2_hdw_internal_set_std_avail(hdw); | ||
448 | pvr2_hdw_internal_find_stdenum(hdw); | ||
449 | return 0; | ||
450 | } | ||
451 | |||
452 | static int ctrl_std_val_to_sym(struct pvr2_ctrl *cptr,int msk,int val, | ||
453 | char *bufPtr,unsigned int bufSize, | ||
454 | unsigned int *len) | ||
455 | { | ||
456 | *len = pvr2_std_id_to_str(bufPtr,bufSize,msk & val); | ||
457 | return 0; | ||
458 | } | ||
459 | |||
460 | static int ctrl_std_sym_to_val(struct pvr2_ctrl *cptr, | ||
461 | const char *bufPtr,unsigned int bufSize, | ||
462 | int *mskp,int *valp) | ||
463 | { | ||
464 | int ret; | ||
465 | v4l2_std_id id; | ||
466 | ret = pvr2_std_str_to_id(&id,bufPtr,bufSize); | ||
467 | if (ret < 0) return ret; | ||
468 | if (mskp) *mskp = id; | ||
469 | if (valp) *valp = id; | ||
470 | return 0; | ||
471 | } | ||
472 | |||
473 | static int ctrl_stdcur_get(struct pvr2_ctrl *cptr,int *vp) | ||
474 | { | ||
475 | *vp = cptr->hdw->std_mask_cur; | ||
476 | return 0; | ||
477 | } | ||
478 | |||
479 | static int ctrl_stdcur_set(struct pvr2_ctrl *cptr,int m,int v) | ||
480 | { | ||
481 | struct pvr2_hdw *hdw = cptr->hdw; | ||
482 | v4l2_std_id ns; | ||
483 | ns = hdw->std_mask_cur; | ||
484 | ns = (ns & ~m) | (v & m); | ||
485 | if (ns == hdw->std_mask_cur) return 0; | ||
486 | hdw->std_mask_cur = ns; | ||
487 | hdw->std_dirty = !0; | ||
488 | pvr2_hdw_internal_find_stdenum(hdw); | ||
489 | return 0; | ||
490 | } | ||
491 | |||
492 | static int ctrl_stdcur_is_dirty(struct pvr2_ctrl *cptr) | ||
493 | { | ||
494 | return cptr->hdw->std_dirty != 0; | ||
495 | } | ||
496 | |||
497 | static void ctrl_stdcur_clear_dirty(struct pvr2_ctrl *cptr) | ||
498 | { | ||
499 | cptr->hdw->std_dirty = 0; | ||
500 | } | ||
501 | |||
502 | static int ctrl_signal_get(struct pvr2_ctrl *cptr,int *vp) | ||
503 | { | ||
504 | *vp = ((pvr2_hdw_get_signal_status_internal(cptr->hdw) & | ||
505 | PVR2_SIGNAL_OK) ? 1 : 0); | ||
506 | return 0; | ||
507 | } | ||
508 | |||
509 | static int ctrl_subsys_get(struct pvr2_ctrl *cptr,int *vp) | ||
510 | { | ||
511 | *vp = cptr->hdw->subsys_enabled_mask; | ||
512 | return 0; | ||
513 | } | ||
514 | |||
515 | static int ctrl_subsys_set(struct pvr2_ctrl *cptr,int m,int v) | ||
516 | { | ||
517 | pvr2_hdw_subsys_bit_chg_no_lock(cptr->hdw,m,v); | ||
518 | return 0; | ||
519 | } | ||
520 | |||
521 | static int ctrl_subsys_stream_get(struct pvr2_ctrl *cptr,int *vp) | ||
522 | { | ||
523 | *vp = cptr->hdw->subsys_stream_mask; | ||
524 | return 0; | ||
525 | } | ||
526 | |||
527 | static int ctrl_subsys_stream_set(struct pvr2_ctrl *cptr,int m,int v) | ||
528 | { | ||
529 | pvr2_hdw_subsys_stream_bit_chg_no_lock(cptr->hdw,m,v); | ||
530 | return 0; | ||
531 | } | ||
532 | |||
533 | static int ctrl_stdenumcur_set(struct pvr2_ctrl *cptr,int m,int v) | ||
534 | { | ||
535 | struct pvr2_hdw *hdw = cptr->hdw; | ||
536 | if (v < 0) return -EINVAL; | ||
537 | if (v > hdw->std_enum_cnt) return -EINVAL; | ||
538 | hdw->std_enum_cur = v; | ||
539 | if (!v) return 0; | ||
540 | v--; | ||
541 | if (hdw->std_mask_cur == hdw->std_defs[v].id) return 0; | ||
542 | hdw->std_mask_cur = hdw->std_defs[v].id; | ||
543 | hdw->std_dirty = !0; | ||
544 | return 0; | ||
545 | } | ||
546 | |||
547 | |||
548 | static int ctrl_stdenumcur_get(struct pvr2_ctrl *cptr,int *vp) | ||
549 | { | ||
550 | *vp = cptr->hdw->std_enum_cur; | ||
551 | return 0; | ||
552 | } | ||
553 | |||
554 | |||
555 | static int ctrl_stdenumcur_is_dirty(struct pvr2_ctrl *cptr) | ||
556 | { | ||
557 | return cptr->hdw->std_dirty != 0; | ||
558 | } | ||
559 | |||
560 | |||
561 | static void ctrl_stdenumcur_clear_dirty(struct pvr2_ctrl *cptr) | ||
562 | { | ||
563 | cptr->hdw->std_dirty = 0; | ||
564 | } | ||
565 | |||
566 | |||
567 | #define DEFINT(vmin,vmax) \ | ||
568 | .type = pvr2_ctl_int, \ | ||
569 | .def.type_int.min_value = vmin, \ | ||
570 | .def.type_int.max_value = vmax | ||
571 | |||
572 | #define DEFENUM(tab) \ | ||
573 | .type = pvr2_ctl_enum, \ | ||
574 | .def.type_enum.count = (sizeof(tab)/sizeof((tab)[0])), \ | ||
575 | .def.type_enum.value_names = tab | ||
576 | |||
577 | #define DEFBOOL \ | ||
578 | .type = pvr2_ctl_bool | ||
579 | |||
580 | #define DEFMASK(msk,tab) \ | ||
581 | .type = pvr2_ctl_bitmask, \ | ||
582 | .def.type_bitmask.valid_bits = msk, \ | ||
583 | .def.type_bitmask.bit_names = tab | ||
584 | |||
585 | #define DEFREF(vname) \ | ||
586 | .set_value = ctrl_set_##vname, \ | ||
587 | .get_value = ctrl_get_##vname, \ | ||
588 | .is_dirty = ctrl_isdirty_##vname, \ | ||
589 | .clear_dirty = ctrl_cleardirty_##vname | ||
590 | |||
591 | |||
592 | #define VCREATE_FUNCS(vname) \ | ||
593 | static int ctrl_get_##vname(struct pvr2_ctrl *cptr,int *vp) \ | ||
594 | {*vp = cptr->hdw->vname##_val; return 0;} \ | ||
595 | static int ctrl_set_##vname(struct pvr2_ctrl *cptr,int m,int v) \ | ||
596 | {cptr->hdw->vname##_val = v; cptr->hdw->vname##_dirty = !0; return 0;} \ | ||
597 | static int ctrl_isdirty_##vname(struct pvr2_ctrl *cptr) \ | ||
598 | {return cptr->hdw->vname##_dirty != 0;} \ | ||
599 | static void ctrl_cleardirty_##vname(struct pvr2_ctrl *cptr) \ | ||
600 | {cptr->hdw->vname##_dirty = 0;} | ||
601 | |||
602 | VCREATE_FUNCS(brightness) | ||
603 | VCREATE_FUNCS(contrast) | ||
604 | VCREATE_FUNCS(saturation) | ||
605 | VCREATE_FUNCS(hue) | ||
606 | VCREATE_FUNCS(volume) | ||
607 | VCREATE_FUNCS(balance) | ||
608 | VCREATE_FUNCS(bass) | ||
609 | VCREATE_FUNCS(treble) | ||
610 | VCREATE_FUNCS(mute) | ||
611 | VCREATE_FUNCS(input) | ||
612 | VCREATE_FUNCS(audiomode) | ||
613 | VCREATE_FUNCS(res_hor) | ||
614 | VCREATE_FUNCS(res_ver) | ||
615 | VCREATE_FUNCS(srate) | ||
616 | |||
617 | #define MIN_FREQ 55250000L | ||
618 | #define MAX_FREQ 850000000L | ||
619 | |||
620 | /* Table definition of all controls which can be manipulated */ | ||
621 | static const struct pvr2_ctl_info control_defs[] = { | ||
622 | { | ||
623 | .v4l_id = V4L2_CID_BRIGHTNESS, | ||
624 | .desc = "Brightness", | ||
625 | .name = "brightness", | ||
626 | .default_value = 128, | ||
627 | DEFREF(brightness), | ||
628 | DEFINT(0,255), | ||
629 | },{ | ||
630 | .v4l_id = V4L2_CID_CONTRAST, | ||
631 | .desc = "Contrast", | ||
632 | .name = "contrast", | ||
633 | .default_value = 68, | ||
634 | DEFREF(contrast), | ||
635 | DEFINT(0,127), | ||
636 | },{ | ||
637 | .v4l_id = V4L2_CID_SATURATION, | ||
638 | .desc = "Saturation", | ||
639 | .name = "saturation", | ||
640 | .default_value = 64, | ||
641 | DEFREF(saturation), | ||
642 | DEFINT(0,127), | ||
643 | },{ | ||
644 | .v4l_id = V4L2_CID_HUE, | ||
645 | .desc = "Hue", | ||
646 | .name = "hue", | ||
647 | .default_value = 0, | ||
648 | DEFREF(hue), | ||
649 | DEFINT(-128,127), | ||
650 | },{ | ||
651 | .v4l_id = V4L2_CID_AUDIO_VOLUME, | ||
652 | .desc = "Volume", | ||
653 | .name = "volume", | ||
654 | .default_value = 65535, | ||
655 | DEFREF(volume), | ||
656 | DEFINT(0,65535), | ||
657 | },{ | ||
658 | .v4l_id = V4L2_CID_AUDIO_BALANCE, | ||
659 | .desc = "Balance", | ||
660 | .name = "balance", | ||
661 | .default_value = 0, | ||
662 | DEFREF(balance), | ||
663 | DEFINT(-32768,32767), | ||
664 | },{ | ||
665 | .v4l_id = V4L2_CID_AUDIO_BASS, | ||
666 | .desc = "Bass", | ||
667 | .name = "bass", | ||
668 | .default_value = 0, | ||
669 | DEFREF(bass), | ||
670 | DEFINT(-32768,32767), | ||
671 | },{ | ||
672 | .v4l_id = V4L2_CID_AUDIO_TREBLE, | ||
673 | .desc = "Treble", | ||
674 | .name = "treble", | ||
675 | .default_value = 0, | ||
676 | DEFREF(treble), | ||
677 | DEFINT(-32768,32767), | ||
678 | },{ | ||
679 | .v4l_id = V4L2_CID_AUDIO_MUTE, | ||
680 | .desc = "Mute", | ||
681 | .name = "mute", | ||
682 | .default_value = 0, | ||
683 | DEFREF(mute), | ||
684 | DEFBOOL, | ||
685 | },{ | ||
686 | .desc = "Video Source", | ||
687 | .name = "input", | ||
688 | .internal_id = PVR2_CID_INPUT, | ||
689 | .default_value = PVR2_CVAL_INPUT_TV, | ||
690 | DEFREF(input), | ||
691 | DEFENUM(control_values_input), | ||
692 | },{ | ||
693 | .desc = "Audio Mode", | ||
694 | .name = "audio_mode", | ||
695 | .internal_id = PVR2_CID_AUDIOMODE, | ||
696 | .default_value = V4L2_TUNER_MODE_STEREO, | ||
697 | DEFREF(audiomode), | ||
698 | DEFENUM(control_values_audiomode), | ||
699 | },{ | ||
700 | .desc = "Horizontal capture resolution", | ||
701 | .name = "resolution_hor", | ||
702 | .internal_id = PVR2_CID_HRES, | ||
703 | .default_value = 720, | ||
704 | DEFREF(res_hor), | ||
705 | DEFINT(320,720), | ||
706 | },{ | ||
707 | .desc = "Vertical capture resolution", | ||
708 | .name = "resolution_ver", | ||
709 | .internal_id = PVR2_CID_VRES, | ||
710 | .default_value = 480, | ||
711 | DEFREF(res_ver), | ||
712 | DEFINT(200,625), | ||
713 | },{ | ||
714 | .v4l_id = V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ, | ||
715 | .desc = "Sample rate", | ||
716 | .name = "srate", | ||
717 | .default_value = PVR2_CVAL_SRATE_48, | ||
718 | DEFREF(srate), | ||
719 | DEFENUM(control_values_srate), | ||
720 | },{ | ||
721 | .desc = "Tuner Frequency (Hz)", | ||
722 | .name = "frequency", | ||
723 | .internal_id = PVR2_CID_FREQUENCY, | ||
724 | .default_value = 175250000L, | ||
725 | .set_value = ctrl_freq_set, | ||
726 | .get_value = ctrl_freq_get, | ||
727 | .is_dirty = ctrl_freq_is_dirty, | ||
728 | .clear_dirty = ctrl_freq_clear_dirty, | ||
729 | DEFINT(MIN_FREQ,MAX_FREQ), | ||
730 | },{ | ||
731 | .desc = "Channel", | ||
732 | .name = "channel", | ||
733 | .set_value = ctrl_channel_set, | ||
734 | .get_value = ctrl_channel_get, | ||
735 | DEFINT(0,FREQTABLE_SIZE), | ||
736 | },{ | ||
737 | .desc = "Channel Program Frequency", | ||
738 | .name = "freq_table_value", | ||
739 | .set_value = ctrl_channelfreq_set, | ||
740 | .get_value = ctrl_channelfreq_get, | ||
741 | DEFINT(MIN_FREQ,MAX_FREQ), | ||
742 | },{ | ||
743 | .desc = "Channel Program ID", | ||
744 | .name = "freq_table_channel", | ||
745 | .set_value = ctrl_channelprog_set, | ||
746 | .get_value = ctrl_channelprog_get, | ||
747 | DEFINT(0,FREQTABLE_SIZE), | ||
748 | },{ | ||
749 | .desc = "Streaming Enabled", | ||
750 | .name = "streaming_enabled", | ||
751 | .get_value = ctrl_streamingenabled_get, | ||
752 | DEFBOOL, | ||
753 | },{ | ||
754 | .desc = "USB Speed", | ||
755 | .name = "usb_speed", | ||
756 | .get_value = ctrl_hsm_get, | ||
757 | DEFENUM(control_values_hsm), | ||
758 | },{ | ||
759 | .desc = "Signal Present", | ||
760 | .name = "signal_present", | ||
761 | .get_value = ctrl_signal_get, | ||
762 | DEFBOOL, | ||
763 | },{ | ||
764 | .desc = "Video Standards Available Mask", | ||
765 | .name = "video_standard_mask_available", | ||
766 | .internal_id = PVR2_CID_STDAVAIL, | ||
767 | .skip_init = !0, | ||
768 | .get_value = ctrl_stdavail_get, | ||
769 | .set_value = ctrl_stdavail_set, | ||
770 | .val_to_sym = ctrl_std_val_to_sym, | ||
771 | .sym_to_val = ctrl_std_sym_to_val, | ||
772 | .type = pvr2_ctl_bitmask, | ||
773 | },{ | ||
774 | .desc = "Video Standards In Use Mask", | ||
775 | .name = "video_standard_mask_active", | ||
776 | .internal_id = PVR2_CID_STDCUR, | ||
777 | .skip_init = !0, | ||
778 | .get_value = ctrl_stdcur_get, | ||
779 | .set_value = ctrl_stdcur_set, | ||
780 | .is_dirty = ctrl_stdcur_is_dirty, | ||
781 | .clear_dirty = ctrl_stdcur_clear_dirty, | ||
782 | .val_to_sym = ctrl_std_val_to_sym, | ||
783 | .sym_to_val = ctrl_std_sym_to_val, | ||
784 | .type = pvr2_ctl_bitmask, | ||
785 | },{ | ||
786 | .desc = "Subsystem enabled mask", | ||
787 | .name = "debug_subsys_mask", | ||
788 | .skip_init = !0, | ||
789 | .get_value = ctrl_subsys_get, | ||
790 | .set_value = ctrl_subsys_set, | ||
791 | DEFMASK(PVR2_SUBSYS_ALL,control_values_subsystem), | ||
792 | },{ | ||
793 | .desc = "Subsystem stream mask", | ||
794 | .name = "debug_subsys_stream_mask", | ||
795 | .skip_init = !0, | ||
796 | .get_value = ctrl_subsys_stream_get, | ||
797 | .set_value = ctrl_subsys_stream_set, | ||
798 | DEFMASK(PVR2_SUBSYS_ALL,control_values_subsystem), | ||
799 | },{ | ||
800 | .desc = "Video Standard Name", | ||
801 | .name = "video_standard", | ||
802 | .internal_id = PVR2_CID_STDENUM, | ||
803 | .skip_init = !0, | ||
804 | .get_value = ctrl_stdenumcur_get, | ||
805 | .set_value = ctrl_stdenumcur_set, | ||
806 | .is_dirty = ctrl_stdenumcur_is_dirty, | ||
807 | .clear_dirty = ctrl_stdenumcur_clear_dirty, | ||
808 | .type = pvr2_ctl_enum, | ||
809 | } | ||
810 | }; | ||
811 | |||
812 | #define CTRLDEF_COUNT (sizeof(control_defs)/sizeof(control_defs[0])) | ||
813 | |||
814 | |||
815 | const char *pvr2_config_get_name(enum pvr2_config cfg) | ||
816 | { | ||
817 | switch (cfg) { | ||
818 | case pvr2_config_empty: return "empty"; | ||
819 | case pvr2_config_mpeg: return "mpeg"; | ||
820 | case pvr2_config_vbi: return "vbi"; | ||
821 | case pvr2_config_radio: return "radio"; | ||
822 | } | ||
823 | return "<unknown>"; | ||
824 | } | ||
825 | |||
826 | |||
827 | struct usb_device *pvr2_hdw_get_dev(struct pvr2_hdw *hdw) | ||
828 | { | ||
829 | return hdw->usb_dev; | ||
830 | } | ||
831 | |||
832 | |||
833 | unsigned long pvr2_hdw_get_sn(struct pvr2_hdw *hdw) | ||
834 | { | ||
835 | return hdw->serial_number; | ||
836 | } | ||
837 | |||
838 | |||
839 | struct pvr2_hdw *pvr2_hdw_find(int unit_number) | ||
840 | { | ||
841 | if (unit_number < 0) return 0; | ||
842 | if (unit_number >= PVR_NUM) return 0; | ||
843 | return unit_pointers[unit_number]; | ||
844 | } | ||
845 | |||
846 | |||
847 | int pvr2_hdw_get_unit_number(struct pvr2_hdw *hdw) | ||
848 | { | ||
849 | return hdw->unit_number; | ||
850 | } | ||
851 | |||
852 | |||
853 | /* Attempt to locate one of the given set of files. Messages are logged | ||
854 | appropriate to what has been found. The return value will be 0 or | ||
855 | greater on success (it will be the index of the file name found) and | ||
856 | fw_entry will be filled in. Otherwise a negative error is returned on | ||
857 | failure. If the return value is -ENOENT then no viable firmware file | ||
858 | could be located. */ | ||
859 | static int pvr2_locate_firmware(struct pvr2_hdw *hdw, | ||
860 | const struct firmware **fw_entry, | ||
861 | const char *fwtypename, | ||
862 | unsigned int fwcount, | ||
863 | const char *fwnames[]) | ||
864 | { | ||
865 | unsigned int idx; | ||
866 | int ret = -EINVAL; | ||
867 | for (idx = 0; idx < fwcount; idx++) { | ||
868 | ret = request_firmware(fw_entry, | ||
869 | fwnames[idx], | ||
870 | &hdw->usb_dev->dev); | ||
871 | if (!ret) { | ||
872 | trace_firmware("Located %s firmware: %s;" | ||
873 | " uploading...", | ||
874 | fwtypename, | ||
875 | fwnames[idx]); | ||
876 | return idx; | ||
877 | } | ||
878 | if (ret == -ENOENT) continue; | ||
879 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, | ||
880 | "request_firmware fatal error with code=%d",ret); | ||
881 | return ret; | ||
882 | } | ||
883 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, | ||
884 | "***WARNING***" | ||
885 | " Device %s firmware" | ||
886 | " seems to be missing.", | ||
887 | fwtypename); | ||
888 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, | ||
889 | "Did you install the pvrusb2 firmware files" | ||
890 | " in their proper location?"); | ||
891 | if (fwcount == 1) { | ||
892 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, | ||
893 | "request_firmware unable to locate %s file %s", | ||
894 | fwtypename,fwnames[0]); | ||
895 | } else { | ||
896 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, | ||
897 | "request_firmware unable to locate" | ||
898 | " one of the following %s files:", | ||
899 | fwtypename); | ||
900 | for (idx = 0; idx < fwcount; idx++) { | ||
901 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, | ||
902 | "request_firmware: Failed to find %s", | ||
903 | fwnames[idx]); | ||
904 | } | ||
905 | } | ||
906 | return ret; | ||
907 | } | ||
908 | |||
909 | |||
910 | /* | ||
911 | * pvr2_upload_firmware1(). | ||
912 | * | ||
913 | * Send the 8051 firmware to the device. After the upload, arrange for | ||
914 | * device to re-enumerate. | ||
915 | * | ||
916 | * NOTE : the pointer to the firmware data given by request_firmware() | ||
917 | * is not suitable for an usb transaction. | ||
918 | * | ||
919 | */ | ||
920 | int pvr2_upload_firmware1(struct pvr2_hdw *hdw) | ||
921 | { | ||
922 | const struct firmware *fw_entry = 0; | ||
923 | void *fw_ptr; | ||
924 | unsigned int pipe; | ||
925 | int ret; | ||
926 | u16 address; | ||
927 | static const char *fw_files_29xxx[] = { | ||
928 | "v4l-pvrusb2-29xxx-01.fw", | ||
929 | }; | ||
930 | #ifdef CONFIG_VIDEO_PVRUSB2_24XXX | ||
931 | static const char *fw_files_24xxx[] = { | ||
932 | "v4l-pvrusb2-24xxx-01.fw", | ||
933 | }; | ||
934 | #endif | ||
935 | static const struct pvr2_string_table fw_file_defs[] = { | ||
936 | [PVR2_HDW_TYPE_29XXX] = { | ||
937 | fw_files_29xxx, | ||
938 | sizeof(fw_files_29xxx)/sizeof(fw_files_29xxx[0]), | ||
939 | }, | ||
940 | #ifdef CONFIG_VIDEO_PVRUSB2_24XXX | ||
941 | [PVR2_HDW_TYPE_24XXX] = { | ||
942 | fw_files_24xxx, | ||
943 | sizeof(fw_files_24xxx)/sizeof(fw_files_24xxx[0]), | ||
944 | }, | ||
945 | #endif | ||
946 | }; | ||
947 | hdw->fw1_state = FW1_STATE_FAILED; // default result | ||
948 | |||
949 | trace_firmware("pvr2_upload_firmware1"); | ||
950 | |||
951 | ret = pvr2_locate_firmware(hdw,&fw_entry,"fx2 controller", | ||
952 | fw_file_defs[hdw->hdw_type].cnt, | ||
953 | fw_file_defs[hdw->hdw_type].lst); | ||
954 | if (ret < 0) { | ||
955 | if (ret == -ENOENT) hdw->fw1_state = FW1_STATE_MISSING; | ||
956 | return ret; | ||
957 | } | ||
958 | |||
959 | usb_settoggle(hdw->usb_dev, 0 & 0xf, !(0 & USB_DIR_IN), 0); | ||
960 | usb_clear_halt(hdw->usb_dev, usb_sndbulkpipe(hdw->usb_dev, 0 & 0x7f)); | ||
961 | |||
962 | pipe = usb_sndctrlpipe(hdw->usb_dev, 0); | ||
963 | |||
964 | if (fw_entry->size != 0x2000){ | ||
965 | pvr2_trace(PVR2_TRACE_ERROR_LEGS,"wrong fx2 firmware size"); | ||
966 | release_firmware(fw_entry); | ||
967 | return -ENOMEM; | ||
968 | } | ||
969 | |||
970 | fw_ptr = kmalloc(0x800, GFP_KERNEL); | ||
971 | if (fw_ptr == NULL){ | ||
972 | release_firmware(fw_entry); | ||
973 | return -ENOMEM; | ||
974 | } | ||
975 | |||
976 | /* We have to hold the CPU during firmware upload. */ | ||
977 | pvr2_hdw_cpureset_assert(hdw,1); | ||
978 | |||
979 | /* upload the firmware to address 0000-1fff in 2048 (=0x800) bytes | ||
980 | chunk. */ | ||
981 | |||
982 | ret = 0; | ||
983 | for(address = 0; address < fw_entry->size; address += 0x800) { | ||
984 | memcpy(fw_ptr, fw_entry->data + address, 0x800); | ||
985 | ret += usb_control_msg(hdw->usb_dev, pipe, 0xa0, 0x40, address, | ||
986 | 0, fw_ptr, 0x800, HZ); | ||
987 | } | ||
988 | |||
989 | trace_firmware("Upload done, releasing device's CPU"); | ||
990 | |||
991 | /* Now release the CPU. It will disconnect and reconnect later. */ | ||
992 | pvr2_hdw_cpureset_assert(hdw,0); | ||
993 | |||
994 | kfree(fw_ptr); | ||
995 | release_firmware(fw_entry); | ||
996 | |||
997 | trace_firmware("Upload done (%d bytes sent)",ret); | ||
998 | |||
999 | /* We should have written 8192 bytes */ | ||
1000 | if (ret == 8192) { | ||
1001 | hdw->fw1_state = FW1_STATE_RELOAD; | ||
1002 | return 0; | ||
1003 | } | ||
1004 | |||
1005 | return -EIO; | ||
1006 | } | ||
1007 | |||
1008 | |||
1009 | /* | ||
1010 | * pvr2_upload_firmware2() | ||
1011 | * | ||
1012 | * This uploads encoder firmware on endpoint 2. | ||
1013 | * | ||
1014 | */ | ||
1015 | |||
1016 | int pvr2_upload_firmware2(struct pvr2_hdw *hdw) | ||
1017 | { | ||
1018 | const struct firmware *fw_entry = 0; | ||
1019 | void *fw_ptr; | ||
1020 | unsigned int pipe, fw_len, fw_done; | ||
1021 | int actual_length; | ||
1022 | int ret = 0; | ||
1023 | int fwidx; | ||
1024 | static const char *fw_files[] = { | ||
1025 | CX2341X_FIRM_ENC_FILENAME, | ||
1026 | }; | ||
1027 | |||
1028 | trace_firmware("pvr2_upload_firmware2"); | ||
1029 | |||
1030 | ret = pvr2_locate_firmware(hdw,&fw_entry,"encoder", | ||
1031 | sizeof(fw_files)/sizeof(fw_files[0]), | ||
1032 | fw_files); | ||
1033 | if (ret < 0) return ret; | ||
1034 | fwidx = ret; | ||
1035 | ret = 0; | ||
1036 | /* Since we're about to completely reinitialize the encoder, | ||
1037 | invalidate our cached copy of its configuration state. Next | ||
1038 | time we configure the encoder, then we'll fully configure it. */ | ||
1039 | hdw->enc_cur_valid = 0; | ||
1040 | |||
1041 | /* First prepare firmware loading */ | ||
1042 | ret |= pvr2_write_register(hdw, 0x0048, 0xffffffff); /*interrupt mask*/ | ||
1043 | ret |= pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000088); /*gpio dir*/ | ||
1044 | ret |= pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000008); /*gpio output state*/ | ||
1045 | ret |= pvr2_hdw_cmd_deep_reset(hdw); | ||
1046 | ret |= pvr2_write_register(hdw, 0xa064, 0x00000000); /*APU command*/ | ||
1047 | ret |= pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000408); /*gpio dir*/ | ||
1048 | ret |= pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000008); /*gpio output state*/ | ||
1049 | ret |= pvr2_write_register(hdw, 0x9058, 0xffffffed); /*VPU ctrl*/ | ||
1050 | ret |= pvr2_write_register(hdw, 0x9054, 0xfffffffd); /*reset hw blocks*/ | ||
1051 | ret |= pvr2_write_register(hdw, 0x07f8, 0x80000800); /*encoder SDRAM refresh*/ | ||
1052 | ret |= pvr2_write_register(hdw, 0x07fc, 0x0000001a); /*encoder SDRAM pre-charge*/ | ||
1053 | ret |= pvr2_write_register(hdw, 0x0700, 0x00000000); /*I2C clock*/ | ||
1054 | ret |= pvr2_write_register(hdw, 0xaa00, 0x00000000); /*unknown*/ | ||
1055 | ret |= pvr2_write_register(hdw, 0xaa04, 0x00057810); /*unknown*/ | ||
1056 | ret |= pvr2_write_register(hdw, 0xaa10, 0x00148500); /*unknown*/ | ||
1057 | ret |= pvr2_write_register(hdw, 0xaa18, 0x00840000); /*unknown*/ | ||
1058 | ret |= pvr2_write_u8(hdw, 0x52, 0); | ||
1059 | ret |= pvr2_write_u16(hdw, 0x0600, 0); | ||
1060 | |||
1061 | if (ret) { | ||
1062 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, | ||
1063 | "firmware2 upload prep failed, ret=%d",ret); | ||
1064 | release_firmware(fw_entry); | ||
1065 | return ret; | ||
1066 | } | ||
1067 | |||
1068 | /* Now send firmware */ | ||
1069 | |||
1070 | fw_len = fw_entry->size; | ||
1071 | |||
1072 | if (fw_len % FIRMWARE_CHUNK_SIZE) { | ||
1073 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, | ||
1074 | "size of %s firmware" | ||
1075 | " must be a multiple of 8192B", | ||
1076 | fw_files[fwidx]); | ||
1077 | release_firmware(fw_entry); | ||
1078 | return -1; | ||
1079 | } | ||
1080 | |||
1081 | fw_ptr = kmalloc(FIRMWARE_CHUNK_SIZE, GFP_KERNEL); | ||
1082 | if (fw_ptr == NULL){ | ||
1083 | release_firmware(fw_entry); | ||
1084 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, | ||
1085 | "failed to allocate memory for firmware2 upload"); | ||
1086 | return -ENOMEM; | ||
1087 | } | ||
1088 | |||
1089 | pipe = usb_sndbulkpipe(hdw->usb_dev, PVR2_FIRMWARE_ENDPOINT); | ||
1090 | |||
1091 | for (fw_done = 0 ; (fw_done < fw_len) && !ret ; | ||
1092 | fw_done += FIRMWARE_CHUNK_SIZE ) { | ||
1093 | int i; | ||
1094 | memcpy(fw_ptr, fw_entry->data + fw_done, FIRMWARE_CHUNK_SIZE); | ||
1095 | /* Usbsnoop log shows that we must swap bytes... */ | ||
1096 | for (i = 0; i < FIRMWARE_CHUNK_SIZE/4 ; i++) | ||
1097 | ((u32 *)fw_ptr)[i] = ___swab32(((u32 *)fw_ptr)[i]); | ||
1098 | |||
1099 | ret |= usb_bulk_msg(hdw->usb_dev, pipe, fw_ptr, | ||
1100 | FIRMWARE_CHUNK_SIZE, | ||
1101 | &actual_length, HZ); | ||
1102 | ret |= (actual_length != FIRMWARE_CHUNK_SIZE); | ||
1103 | } | ||
1104 | |||
1105 | trace_firmware("upload of %s : %i / %i ", | ||
1106 | fw_files[fwidx],fw_done,fw_len); | ||
1107 | |||
1108 | kfree(fw_ptr); | ||
1109 | release_firmware(fw_entry); | ||
1110 | |||
1111 | if (ret) { | ||
1112 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, | ||
1113 | "firmware2 upload transfer failure"); | ||
1114 | return ret; | ||
1115 | } | ||
1116 | |||
1117 | /* Finish upload */ | ||
1118 | |||
1119 | ret |= pvr2_write_register(hdw, 0x9054, 0xffffffff); /*reset hw blocks*/ | ||
1120 | ret |= pvr2_write_register(hdw, 0x9058, 0xffffffe8); /*VPU ctrl*/ | ||
1121 | ret |= pvr2_write_u16(hdw, 0x0600, 0); | ||
1122 | |||
1123 | if (ret) { | ||
1124 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, | ||
1125 | "firmware2 upload post-proc failure"); | ||
1126 | } else { | ||
1127 | hdw->subsys_enabled_mask |= (1<<PVR2_SUBSYS_B_ENC_FIRMWARE); | ||
1128 | } | ||
1129 | return ret; | ||
1130 | } | ||
1131 | |||
1132 | |||
1133 | #define FIRMWARE_RECOVERY_BITS \ | ||
1134 | ((1<<PVR2_SUBSYS_B_ENC_CFG) | \ | ||
1135 | (1<<PVR2_SUBSYS_B_ENC_RUN) | \ | ||
1136 | (1<<PVR2_SUBSYS_B_ENC_FIRMWARE) | \ | ||
1137 | (1<<PVR2_SUBSYS_B_USBSTREAM_RUN)) | ||
1138 | |||
1139 | /* | ||
1140 | |||
1141 | This single function is key to pretty much everything. The pvrusb2 | ||
1142 | device can logically be viewed as a series of subsystems which can be | ||
1143 | stopped / started or unconfigured / configured. To get things streaming, | ||
1144 | one must configure everything and start everything, but there may be | ||
1145 | various reasons over time to deconfigure something or stop something. | ||
1146 | This function handles all of this activity. Everything EVERYWHERE that | ||
1147 | must affect a subsystem eventually comes here to do the work. | ||
1148 | |||
1149 | The current state of all subsystems is represented by a single bit mask, | ||
1150 | known as subsys_enabled_mask. The bit positions are defined by the | ||
1151 | PVR2_SUBSYS_xxxx macros, with one subsystem per bit position. At any | ||
1152 | time the set of configured or active subsystems can be queried just by | ||
1153 | looking at that mask. To change bits in that mask, this function here | ||
1154 | must be called. The "msk" argument indicates which bit positions to | ||
1155 | change, and the "val" argument defines the new values for the positions | ||
1156 | defined by "msk". | ||
1157 | |||
1158 | There is a priority ordering of starting / stopping things, and for | ||
1159 | multiple requested changes, this function implements that ordering. | ||
1160 | (Thus we will act on a request to load encoder firmware before we | ||
1161 | configure the encoder.) In addition to priority ordering, there is a | ||
1162 | recovery strategy implemented here. If a particular step fails and we | ||
1163 | detect that failure, this function will clear the affected subsystem bits | ||
1164 | and restart. Thus we have a means for recovering from a dead encoder: | ||
1165 | Clear all bits that correspond to subsystems that we need to restart / | ||
1166 | reconfigure and start over. | ||
1167 | |||
1168 | */ | ||
1169 | void pvr2_hdw_subsys_bit_chg_no_lock(struct pvr2_hdw *hdw, | ||
1170 | unsigned long msk,unsigned long val) | ||
1171 | { | ||
1172 | unsigned long nmsk; | ||
1173 | unsigned long vmsk; | ||
1174 | int ret; | ||
1175 | unsigned int tryCount = 0; | ||
1176 | |||
1177 | if (!hdw->flag_ok) return; | ||
1178 | |||
1179 | msk &= PVR2_SUBSYS_ALL; | ||
1180 | nmsk = (hdw->subsys_enabled_mask & ~msk) | (val & msk); | ||
1181 | nmsk &= PVR2_SUBSYS_ALL; | ||
1182 | |||
1183 | for (;;) { | ||
1184 | tryCount++; | ||
1185 | if (!((nmsk ^ hdw->subsys_enabled_mask) & | ||
1186 | PVR2_SUBSYS_ALL)) break; | ||
1187 | if (tryCount > 4) { | ||
1188 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, | ||
1189 | "Too many retries when configuring device;" | ||
1190 | " giving up"); | ||
1191 | pvr2_hdw_render_useless(hdw); | ||
1192 | break; | ||
1193 | } | ||
1194 | if (tryCount > 1) { | ||
1195 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, | ||
1196 | "Retrying device reconfiguration"); | ||
1197 | } | ||
1198 | pvr2_trace(PVR2_TRACE_INIT, | ||
1199 | "subsys mask changing 0x%lx:0x%lx" | ||
1200 | " from 0x%lx to 0x%lx", | ||
1201 | msk,val,hdw->subsys_enabled_mask,nmsk); | ||
1202 | |||
1203 | vmsk = (nmsk ^ hdw->subsys_enabled_mask) & | ||
1204 | hdw->subsys_enabled_mask; | ||
1205 | if (vmsk) { | ||
1206 | if (vmsk & (1<<PVR2_SUBSYS_B_ENC_RUN)) { | ||
1207 | pvr2_trace(PVR2_TRACE_CTL, | ||
1208 | "/*---TRACE_CTL----*/" | ||
1209 | " pvr2_encoder_stop"); | ||
1210 | ret = pvr2_encoder_stop(hdw); | ||
1211 | if (ret) { | ||
1212 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, | ||
1213 | "Error recovery initiated"); | ||
1214 | hdw->subsys_enabled_mask &= | ||
1215 | ~FIRMWARE_RECOVERY_BITS; | ||
1216 | continue; | ||
1217 | } | ||
1218 | } | ||
1219 | if (vmsk & (1<<PVR2_SUBSYS_B_USBSTREAM_RUN)) { | ||
1220 | pvr2_trace(PVR2_TRACE_CTL, | ||
1221 | "/*---TRACE_CTL----*/" | ||
1222 | " pvr2_hdw_cmd_usbstream(0)"); | ||
1223 | pvr2_hdw_cmd_usbstream(hdw,0); | ||
1224 | } | ||
1225 | if (vmsk & (1<<PVR2_SUBSYS_B_DIGITIZER_RUN)) { | ||
1226 | pvr2_trace(PVR2_TRACE_CTL, | ||
1227 | "/*---TRACE_CTL----*/" | ||
1228 | " decoder disable"); | ||
1229 | if (hdw->decoder_ctrl) { | ||
1230 | hdw->decoder_ctrl->enable( | ||
1231 | hdw->decoder_ctrl->ctxt,0); | ||
1232 | } else { | ||
1233 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, | ||
1234 | "WARNING:" | ||
1235 | " No decoder present"); | ||
1236 | } | ||
1237 | hdw->subsys_enabled_mask &= | ||
1238 | ~(1<<PVR2_SUBSYS_B_DIGITIZER_RUN); | ||
1239 | } | ||
1240 | if (vmsk & PVR2_SUBSYS_CFG_ALL) { | ||
1241 | hdw->subsys_enabled_mask &= | ||
1242 | ~(vmsk & PVR2_SUBSYS_CFG_ALL); | ||
1243 | } | ||
1244 | } | ||
1245 | vmsk = (nmsk ^ hdw->subsys_enabled_mask) & nmsk; | ||
1246 | if (vmsk) { | ||
1247 | if (vmsk & (1<<PVR2_SUBSYS_B_ENC_FIRMWARE)) { | ||
1248 | pvr2_trace(PVR2_TRACE_CTL, | ||
1249 | "/*---TRACE_CTL----*/" | ||
1250 | " pvr2_upload_firmware2"); | ||
1251 | ret = pvr2_upload_firmware2(hdw); | ||
1252 | if (ret) { | ||
1253 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, | ||
1254 | "Failure uploading encoder" | ||
1255 | " firmware"); | ||
1256 | pvr2_hdw_render_useless(hdw); | ||
1257 | break; | ||
1258 | } | ||
1259 | } | ||
1260 | if (vmsk & (1<<PVR2_SUBSYS_B_ENC_CFG)) { | ||
1261 | pvr2_trace(PVR2_TRACE_CTL, | ||
1262 | "/*---TRACE_CTL----*/" | ||
1263 | " pvr2_encoder_configure"); | ||
1264 | ret = pvr2_encoder_configure(hdw); | ||
1265 | if (ret) { | ||
1266 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, | ||
1267 | "Error recovery initiated"); | ||
1268 | hdw->subsys_enabled_mask &= | ||
1269 | ~FIRMWARE_RECOVERY_BITS; | ||
1270 | continue; | ||
1271 | } | ||
1272 | } | ||
1273 | if (vmsk & (1<<PVR2_SUBSYS_B_DIGITIZER_RUN)) { | ||
1274 | pvr2_trace(PVR2_TRACE_CTL, | ||
1275 | "/*---TRACE_CTL----*/" | ||
1276 | " decoder enable"); | ||
1277 | if (hdw->decoder_ctrl) { | ||
1278 | hdw->decoder_ctrl->enable( | ||
1279 | hdw->decoder_ctrl->ctxt,!0); | ||
1280 | } else { | ||
1281 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, | ||
1282 | "WARNING:" | ||
1283 | " No decoder present"); | ||
1284 | } | ||
1285 | hdw->subsys_enabled_mask |= | ||
1286 | (1<<PVR2_SUBSYS_B_DIGITIZER_RUN); | ||
1287 | } | ||
1288 | if (vmsk & (1<<PVR2_SUBSYS_B_USBSTREAM_RUN)) { | ||
1289 | pvr2_trace(PVR2_TRACE_CTL, | ||
1290 | "/*---TRACE_CTL----*/" | ||
1291 | " pvr2_hdw_cmd_usbstream(1)"); | ||
1292 | pvr2_hdw_cmd_usbstream(hdw,!0); | ||
1293 | } | ||
1294 | if (vmsk & (1<<PVR2_SUBSYS_B_ENC_RUN)) { | ||
1295 | pvr2_trace(PVR2_TRACE_CTL, | ||
1296 | "/*---TRACE_CTL----*/" | ||
1297 | " pvr2_encoder_start"); | ||
1298 | ret = pvr2_encoder_start(hdw); | ||
1299 | if (ret) { | ||
1300 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, | ||
1301 | "Error recovery initiated"); | ||
1302 | hdw->subsys_enabled_mask &= | ||
1303 | ~FIRMWARE_RECOVERY_BITS; | ||
1304 | continue; | ||
1305 | } | ||
1306 | } | ||
1307 | } | ||
1308 | } | ||
1309 | } | ||
1310 | |||
1311 | |||
1312 | void pvr2_hdw_subsys_bit_chg(struct pvr2_hdw *hdw, | ||
1313 | unsigned long msk,unsigned long val) | ||
1314 | { | ||
1315 | LOCK_TAKE(hdw->big_lock); do { | ||
1316 | pvr2_hdw_subsys_bit_chg_no_lock(hdw,msk,val); | ||
1317 | } while (0); LOCK_GIVE(hdw->big_lock); | ||
1318 | } | ||
1319 | |||
1320 | |||
1321 | void pvr2_hdw_subsys_bit_set(struct pvr2_hdw *hdw,unsigned long msk) | ||
1322 | { | ||
1323 | pvr2_hdw_subsys_bit_chg(hdw,msk,msk); | ||
1324 | } | ||
1325 | |||
1326 | |||
1327 | void pvr2_hdw_subsys_bit_clr(struct pvr2_hdw *hdw,unsigned long msk) | ||
1328 | { | ||
1329 | pvr2_hdw_subsys_bit_chg(hdw,msk,0); | ||
1330 | } | ||
1331 | |||
1332 | |||
1333 | unsigned long pvr2_hdw_subsys_get(struct pvr2_hdw *hdw) | ||
1334 | { | ||
1335 | return hdw->subsys_enabled_mask; | ||
1336 | } | ||
1337 | |||
1338 | |||
1339 | unsigned long pvr2_hdw_subsys_stream_get(struct pvr2_hdw *hdw) | ||
1340 | { | ||
1341 | return hdw->subsys_stream_mask; | ||
1342 | } | ||
1343 | |||
1344 | |||
1345 | void pvr2_hdw_subsys_stream_bit_chg_no_lock(struct pvr2_hdw *hdw, | ||
1346 | unsigned long msk, | ||
1347 | unsigned long val) | ||
1348 | { | ||
1349 | unsigned long val2; | ||
1350 | msk &= PVR2_SUBSYS_ALL; | ||
1351 | val2 = ((hdw->subsys_stream_mask & ~msk) | (val & msk)); | ||
1352 | pvr2_trace(PVR2_TRACE_INIT, | ||
1353 | "stream mask changing 0x%lx:0x%lx from 0x%lx to 0x%lx", | ||
1354 | msk,val,hdw->subsys_stream_mask,val2); | ||
1355 | hdw->subsys_stream_mask = val2; | ||
1356 | } | ||
1357 | |||
1358 | |||
1359 | void pvr2_hdw_subsys_stream_bit_chg(struct pvr2_hdw *hdw, | ||
1360 | unsigned long msk, | ||
1361 | unsigned long val) | ||
1362 | { | ||
1363 | LOCK_TAKE(hdw->big_lock); do { | ||
1364 | pvr2_hdw_subsys_stream_bit_chg_no_lock(hdw,msk,val); | ||
1365 | } while (0); LOCK_GIVE(hdw->big_lock); | ||
1366 | } | ||
1367 | |||
1368 | |||
1369 | int pvr2_hdw_set_streaming_no_lock(struct pvr2_hdw *hdw,int enableFl) | ||
1370 | { | ||
1371 | if ((!enableFl) == !(hdw->flag_streaming_enabled)) return 0; | ||
1372 | if (enableFl) { | ||
1373 | pvr2_trace(PVR2_TRACE_START_STOP, | ||
1374 | "/*--TRACE_STREAM--*/ enable"); | ||
1375 | pvr2_hdw_subsys_bit_chg_no_lock(hdw,~0,~0); | ||
1376 | } else { | ||
1377 | pvr2_trace(PVR2_TRACE_START_STOP, | ||
1378 | "/*--TRACE_STREAM--*/ disable"); | ||
1379 | pvr2_hdw_subsys_bit_chg_no_lock(hdw,hdw->subsys_stream_mask,0); | ||
1380 | } | ||
1381 | if (!hdw->flag_ok) return -EIO; | ||
1382 | hdw->flag_streaming_enabled = enableFl != 0; | ||
1383 | return 0; | ||
1384 | } | ||
1385 | |||
1386 | |||
1387 | int pvr2_hdw_get_streaming(struct pvr2_hdw *hdw) | ||
1388 | { | ||
1389 | return hdw->flag_streaming_enabled != 0; | ||
1390 | } | ||
1391 | |||
1392 | |||
1393 | int pvr2_hdw_set_streaming(struct pvr2_hdw *hdw,int enable_flag) | ||
1394 | { | ||
1395 | int ret; | ||
1396 | LOCK_TAKE(hdw->big_lock); do { | ||
1397 | ret = pvr2_hdw_set_streaming_no_lock(hdw,enable_flag); | ||
1398 | } while (0); LOCK_GIVE(hdw->big_lock); | ||
1399 | return ret; | ||
1400 | } | ||
1401 | |||
1402 | |||
1403 | int pvr2_hdw_set_stream_type_no_lock(struct pvr2_hdw *hdw, | ||
1404 | enum pvr2_config config) | ||
1405 | { | ||
1406 | unsigned long sm = hdw->subsys_enabled_mask; | ||
1407 | if (!hdw->flag_ok) return -EIO; | ||
1408 | pvr2_hdw_subsys_bit_chg_no_lock(hdw,hdw->subsys_stream_mask,0); | ||
1409 | hdw->config = config; | ||
1410 | pvr2_hdw_subsys_bit_chg_no_lock(hdw,~0,sm); | ||
1411 | return 0; | ||
1412 | } | ||
1413 | |||
1414 | |||
1415 | int pvr2_hdw_set_stream_type(struct pvr2_hdw *hdw,enum pvr2_config config) | ||
1416 | { | ||
1417 | int ret; | ||
1418 | if (!hdw->flag_ok) return -EIO; | ||
1419 | LOCK_TAKE(hdw->big_lock); | ||
1420 | ret = pvr2_hdw_set_stream_type_no_lock(hdw,config); | ||
1421 | LOCK_GIVE(hdw->big_lock); | ||
1422 | return ret; | ||
1423 | } | ||
1424 | |||
1425 | |||
1426 | static int get_default_tuner_type(struct pvr2_hdw *hdw) | ||
1427 | { | ||
1428 | int unit_number = hdw->unit_number; | ||
1429 | int tp = -1; | ||
1430 | if ((unit_number >= 0) && (unit_number < PVR_NUM)) { | ||
1431 | tp = tuner[unit_number]; | ||
1432 | } | ||
1433 | if (tp < 0) return -EINVAL; | ||
1434 | hdw->tuner_type = tp; | ||
1435 | return 0; | ||
1436 | } | ||
1437 | |||
1438 | |||
1439 | static v4l2_std_id get_default_standard(struct pvr2_hdw *hdw) | ||
1440 | { | ||
1441 | int unit_number = hdw->unit_number; | ||
1442 | int tp = 0; | ||
1443 | if ((unit_number >= 0) && (unit_number < PVR_NUM)) { | ||
1444 | tp = video_std[unit_number]; | ||
1445 | } | ||
1446 | return tp; | ||
1447 | } | ||
1448 | |||
1449 | |||
1450 | static unsigned int get_default_error_tolerance(struct pvr2_hdw *hdw) | ||
1451 | { | ||
1452 | int unit_number = hdw->unit_number; | ||
1453 | int tp = 0; | ||
1454 | if ((unit_number >= 0) && (unit_number < PVR_NUM)) { | ||
1455 | tp = tolerance[unit_number]; | ||
1456 | } | ||
1457 | return tp; | ||
1458 | } | ||
1459 | |||
1460 | |||
1461 | static int pvr2_hdw_check_firmware(struct pvr2_hdw *hdw) | ||
1462 | { | ||
1463 | /* Try a harmless request to fetch the eeprom's address over | ||
1464 | endpoint 1. See what happens. Only the full FX2 image can | ||
1465 | respond to this. If this probe fails then likely the FX2 | ||
1466 | firmware needs be loaded. */ | ||
1467 | int result; | ||
1468 | LOCK_TAKE(hdw->ctl_lock); do { | ||
1469 | hdw->cmd_buffer[0] = 0xeb; | ||
1470 | result = pvr2_send_request_ex(hdw,HZ*1,!0, | ||
1471 | hdw->cmd_buffer,1, | ||
1472 | hdw->cmd_buffer,1); | ||
1473 | if (result < 0) break; | ||
1474 | } while(0); LOCK_GIVE(hdw->ctl_lock); | ||
1475 | if (result) { | ||
1476 | pvr2_trace(PVR2_TRACE_INIT, | ||
1477 | "Probe of device endpoint 1 result status %d", | ||
1478 | result); | ||
1479 | } else { | ||
1480 | pvr2_trace(PVR2_TRACE_INIT, | ||
1481 | "Probe of device endpoint 1 succeeded"); | ||
1482 | } | ||
1483 | return result == 0; | ||
1484 | } | ||
1485 | |||
1486 | static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw) | ||
1487 | { | ||
1488 | char buf[40]; | ||
1489 | unsigned int bcnt; | ||
1490 | v4l2_std_id std1,std2; | ||
1491 | |||
1492 | std1 = get_default_standard(hdw); | ||
1493 | |||
1494 | bcnt = pvr2_std_id_to_str(buf,sizeof(buf),hdw->std_mask_eeprom); | ||
1495 | pvr2_trace(PVR2_TRACE_INIT, | ||
1496 | "Supported video standard(s) reported by eeprom: %.*s", | ||
1497 | bcnt,buf); | ||
1498 | |||
1499 | hdw->std_mask_avail = hdw->std_mask_eeprom; | ||
1500 | |||
1501 | std2 = std1 & ~hdw->std_mask_avail; | ||
1502 | if (std2) { | ||
1503 | bcnt = pvr2_std_id_to_str(buf,sizeof(buf),std2); | ||
1504 | pvr2_trace(PVR2_TRACE_INIT, | ||
1505 | "Expanding supported video standards" | ||
1506 | " to include: %.*s", | ||
1507 | bcnt,buf); | ||
1508 | hdw->std_mask_avail |= std2; | ||
1509 | } | ||
1510 | |||
1511 | pvr2_hdw_internal_set_std_avail(hdw); | ||
1512 | |||
1513 | if (std1) { | ||
1514 | bcnt = pvr2_std_id_to_str(buf,sizeof(buf),std1); | ||
1515 | pvr2_trace(PVR2_TRACE_INIT, | ||
1516 | "Initial video standard forced to %.*s", | ||
1517 | bcnt,buf); | ||
1518 | hdw->std_mask_cur = std1; | ||
1519 | hdw->std_dirty = !0; | ||
1520 | pvr2_hdw_internal_find_stdenum(hdw); | ||
1521 | return; | ||
1522 | } | ||
1523 | |||
1524 | if (hdw->std_enum_cnt > 1) { | ||
1525 | // Autoselect the first listed standard | ||
1526 | hdw->std_enum_cur = 1; | ||
1527 | hdw->std_mask_cur = hdw->std_defs[hdw->std_enum_cur-1].id; | ||
1528 | hdw->std_dirty = !0; | ||
1529 | pvr2_trace(PVR2_TRACE_INIT, | ||
1530 | "Initial video standard auto-selected to %s", | ||
1531 | hdw->std_defs[hdw->std_enum_cur-1].name); | ||
1532 | return; | ||
1533 | } | ||
1534 | |||
1535 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, | ||
1536 | "Unable to select a viable initial video standard"); | ||
1537 | } | ||
1538 | |||
1539 | |||
1540 | static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw) | ||
1541 | { | ||
1542 | int ret; | ||
1543 | unsigned int idx; | ||
1544 | struct pvr2_ctrl *cptr; | ||
1545 | int reloadFl = 0; | ||
1546 | if (!reloadFl) { | ||
1547 | reloadFl = (hdw->usb_intf->cur_altsetting->desc.bNumEndpoints | ||
1548 | == 0); | ||
1549 | if (reloadFl) { | ||
1550 | pvr2_trace(PVR2_TRACE_INIT, | ||
1551 | "USB endpoint config looks strange" | ||
1552 | "; possibly firmware needs to be loaded"); | ||
1553 | } | ||
1554 | } | ||
1555 | if (!reloadFl) { | ||
1556 | reloadFl = !pvr2_hdw_check_firmware(hdw); | ||
1557 | if (reloadFl) { | ||
1558 | pvr2_trace(PVR2_TRACE_INIT, | ||
1559 | "Check for FX2 firmware failed" | ||
1560 | "; possibly firmware needs to be loaded"); | ||
1561 | } | ||
1562 | } | ||
1563 | if (reloadFl) { | ||
1564 | if (pvr2_upload_firmware1(hdw) != 0) { | ||
1565 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, | ||
1566 | "Failure uploading firmware1"); | ||
1567 | } | ||
1568 | return; | ||
1569 | } | ||
1570 | hdw->fw1_state = FW1_STATE_OK; | ||
1571 | |||
1572 | if (initusbreset) { | ||
1573 | pvr2_hdw_device_reset(hdw); | ||
1574 | } | ||
1575 | if (!pvr2_hdw_dev_ok(hdw)) return; | ||
1576 | |||
1577 | for (idx = 0; idx < pvr2_client_lists[hdw->hdw_type].cnt; idx++) { | ||
1578 | request_module(pvr2_client_lists[hdw->hdw_type].lst[idx]); | ||
1579 | } | ||
1580 | |||
1581 | pvr2_hdw_cmd_powerup(hdw); | ||
1582 | if (!pvr2_hdw_dev_ok(hdw)) return; | ||
1583 | |||
1584 | if (pvr2_upload_firmware2(hdw)){ | ||
1585 | pvr2_trace(PVR2_TRACE_ERROR_LEGS,"device unstable!!"); | ||
1586 | pvr2_hdw_render_useless(hdw); | ||
1587 | return; | ||
1588 | } | ||
1589 | |||
1590 | // This step MUST happen after the earlier powerup step. | ||
1591 | pvr2_i2c_core_init(hdw); | ||
1592 | if (!pvr2_hdw_dev_ok(hdw)) return; | ||
1593 | |||
1594 | for (idx = 0; idx < CTRLDEF_COUNT; idx++) { | ||
1595 | cptr = hdw->controls + idx; | ||
1596 | if (cptr->info->skip_init) continue; | ||
1597 | if (!cptr->info->set_value) continue; | ||
1598 | cptr->info->set_value(cptr,~0,cptr->info->default_value); | ||
1599 | } | ||
1600 | |||
1601 | // Do not use pvr2_reset_ctl_endpoints() here. It is not | ||
1602 | // thread-safe against the normal pvr2_send_request() mechanism. | ||
1603 | // (We should make it thread safe). | ||
1604 | |||
1605 | ret = pvr2_hdw_get_eeprom_addr(hdw); | ||
1606 | if (!pvr2_hdw_dev_ok(hdw)) return; | ||
1607 | if (ret < 0) { | ||
1608 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, | ||
1609 | "Unable to determine location of eeprom, skipping"); | ||
1610 | } else { | ||
1611 | hdw->eeprom_addr = ret; | ||
1612 | pvr2_eeprom_analyze(hdw); | ||
1613 | if (!pvr2_hdw_dev_ok(hdw)) return; | ||
1614 | } | ||
1615 | |||
1616 | pvr2_hdw_setup_std(hdw); | ||
1617 | |||
1618 | if (!get_default_tuner_type(hdw)) { | ||
1619 | pvr2_trace(PVR2_TRACE_INIT, | ||
1620 | "pvr2_hdw_setup: Tuner type overridden to %d", | ||
1621 | hdw->tuner_type); | ||
1622 | } | ||
1623 | |||
1624 | hdw->tuner_updated = !0; | ||
1625 | pvr2_i2c_core_check_stale(hdw); | ||
1626 | hdw->tuner_updated = 0; | ||
1627 | |||
1628 | if (!pvr2_hdw_dev_ok(hdw)) return; | ||
1629 | |||
1630 | pvr2_hdw_commit_ctl_internal(hdw); | ||
1631 | if (!pvr2_hdw_dev_ok(hdw)) return; | ||
1632 | |||
1633 | hdw->vid_stream = pvr2_stream_create(); | ||
1634 | if (!pvr2_hdw_dev_ok(hdw)) return; | ||
1635 | pvr2_trace(PVR2_TRACE_INIT, | ||
1636 | "pvr2_hdw_setup: video stream is %p",hdw->vid_stream); | ||
1637 | if (hdw->vid_stream) { | ||
1638 | idx = get_default_error_tolerance(hdw); | ||
1639 | if (idx) { | ||
1640 | pvr2_trace(PVR2_TRACE_INIT, | ||
1641 | "pvr2_hdw_setup: video stream %p" | ||
1642 | " setting tolerance %u", | ||
1643 | hdw->vid_stream,idx); | ||
1644 | } | ||
1645 | pvr2_stream_setup(hdw->vid_stream,hdw->usb_dev, | ||
1646 | PVR2_VID_ENDPOINT,idx); | ||
1647 | } | ||
1648 | |||
1649 | if (!pvr2_hdw_dev_ok(hdw)) return; | ||
1650 | |||
1651 | /* Make sure everything is up to date */ | ||
1652 | pvr2_i2c_core_sync(hdw); | ||
1653 | |||
1654 | if (!pvr2_hdw_dev_ok(hdw)) return; | ||
1655 | |||
1656 | hdw->flag_init_ok = !0; | ||
1657 | } | ||
1658 | |||
1659 | |||
1660 | int pvr2_hdw_setup(struct pvr2_hdw *hdw) | ||
1661 | { | ||
1662 | pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_setup(hdw=%p) begin",hdw); | ||
1663 | LOCK_TAKE(hdw->big_lock); do { | ||
1664 | pvr2_hdw_setup_low(hdw); | ||
1665 | pvr2_trace(PVR2_TRACE_INIT, | ||
1666 | "pvr2_hdw_setup(hdw=%p) done, ok=%d init_ok=%d", | ||
1667 | hdw,hdw->flag_ok,hdw->flag_init_ok); | ||
1668 | if (pvr2_hdw_dev_ok(hdw)) { | ||
1669 | if (pvr2_hdw_init_ok(hdw)) { | ||
1670 | pvr2_trace( | ||
1671 | PVR2_TRACE_INFO, | ||
1672 | "Device initialization" | ||
1673 | " completed successfully."); | ||
1674 | break; | ||
1675 | } | ||
1676 | if (hdw->fw1_state == FW1_STATE_RELOAD) { | ||
1677 | pvr2_trace( | ||
1678 | PVR2_TRACE_INFO, | ||
1679 | "Device microcontroller firmware" | ||
1680 | " (re)loaded; it should now reset" | ||
1681 | " and reconnect."); | ||
1682 | break; | ||
1683 | } | ||
1684 | pvr2_trace( | ||
1685 | PVR2_TRACE_ERROR_LEGS, | ||
1686 | "Device initialization was not successful."); | ||
1687 | if (hdw->fw1_state == FW1_STATE_MISSING) { | ||
1688 | pvr2_trace( | ||
1689 | PVR2_TRACE_ERROR_LEGS, | ||
1690 | "Giving up since device" | ||
1691 | " microcontroller firmware" | ||
1692 | " appears to be missing."); | ||
1693 | break; | ||
1694 | } | ||
1695 | } | ||
1696 | if (procreload) { | ||
1697 | pvr2_trace( | ||
1698 | PVR2_TRACE_ERROR_LEGS, | ||
1699 | "Attempting pvrusb2 recovery by reloading" | ||
1700 | " primary firmware."); | ||
1701 | pvr2_trace( | ||
1702 | PVR2_TRACE_ERROR_LEGS, | ||
1703 | "If this works, device should disconnect" | ||
1704 | " and reconnect in a sane state."); | ||
1705 | hdw->fw1_state = FW1_STATE_UNKNOWN; | ||
1706 | pvr2_upload_firmware1(hdw); | ||
1707 | } else { | ||
1708 | pvr2_trace( | ||
1709 | PVR2_TRACE_ERROR_LEGS, | ||
1710 | "***WARNING*** pvrusb2 device hardware" | ||
1711 | " appears to be jammed" | ||
1712 | " and I can't clear it."); | ||
1713 | pvr2_trace( | ||
1714 | PVR2_TRACE_ERROR_LEGS, | ||
1715 | "You might need to power cycle" | ||
1716 | " the pvrusb2 device" | ||
1717 | " in order to recover."); | ||
1718 | } | ||
1719 | } while (0); LOCK_GIVE(hdw->big_lock); | ||
1720 | pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_setup(hdw=%p) end",hdw); | ||
1721 | return hdw->flag_init_ok; | ||
1722 | } | ||
1723 | |||
1724 | |||
1725 | /* Create and return a structure for interacting with the underlying | ||
1726 | hardware */ | ||
1727 | struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, | ||
1728 | const struct usb_device_id *devid) | ||
1729 | { | ||
1730 | unsigned int idx,cnt1,cnt2; | ||
1731 | struct pvr2_hdw *hdw; | ||
1732 | unsigned int hdw_type; | ||
1733 | int valid_std_mask; | ||
1734 | struct pvr2_ctrl *cptr; | ||
1735 | __u8 ifnum; | ||
1736 | struct v4l2_queryctrl qctrl; | ||
1737 | struct pvr2_ctl_info *ciptr; | ||
1738 | |||
1739 | hdw_type = devid - pvr2_device_table; | ||
1740 | if (hdw_type >= | ||
1741 | sizeof(pvr2_device_names)/sizeof(pvr2_device_names[0])) { | ||
1742 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, | ||
1743 | "Bogus device type of %u reported",hdw_type); | ||
1744 | return 0; | ||
1745 | } | ||
1746 | |||
1747 | hdw = kmalloc(sizeof(*hdw),GFP_KERNEL); | ||
1748 | pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_create: hdw=%p, type \"%s\"", | ||
1749 | hdw,pvr2_device_names[hdw_type]); | ||
1750 | if (!hdw) goto fail; | ||
1751 | memset(hdw,0,sizeof(*hdw)); | ||
1752 | cx2341x_fill_defaults(&hdw->enc_ctl_state); | ||
1753 | |||
1754 | hdw->control_cnt = CTRLDEF_COUNT; | ||
1755 | hdw->control_cnt += MPEGDEF_COUNT; | ||
1756 | hdw->controls = kmalloc(sizeof(struct pvr2_ctrl) * hdw->control_cnt, | ||
1757 | GFP_KERNEL); | ||
1758 | if (!hdw->controls) goto fail; | ||
1759 | memset(hdw->controls,0,sizeof(struct pvr2_ctrl) * hdw->control_cnt); | ||
1760 | hdw->hdw_type = hdw_type; | ||
1761 | for (idx = 0; idx < hdw->control_cnt; idx++) { | ||
1762 | cptr = hdw->controls + idx; | ||
1763 | cptr->hdw = hdw; | ||
1764 | } | ||
1765 | for (idx = 0; idx < 32; idx++) { | ||
1766 | hdw->std_mask_ptrs[idx] = hdw->std_mask_names[idx]; | ||
1767 | } | ||
1768 | for (idx = 0; idx < CTRLDEF_COUNT; idx++) { | ||
1769 | cptr = hdw->controls + idx; | ||
1770 | cptr->info = control_defs+idx; | ||
1771 | } | ||
1772 | /* Define and configure additional controls from cx2341x module. */ | ||
1773 | hdw->mpeg_ctrl_info = kmalloc( | ||
1774 | sizeof(*(hdw->mpeg_ctrl_info)) * MPEGDEF_COUNT, GFP_KERNEL); | ||
1775 | if (!hdw->mpeg_ctrl_info) goto fail; | ||
1776 | memset(hdw->mpeg_ctrl_info,0, | ||
1777 | sizeof(*(hdw->mpeg_ctrl_info)) * MPEGDEF_COUNT); | ||
1778 | for (idx = 0; idx < MPEGDEF_COUNT; idx++) { | ||
1779 | cptr = hdw->controls + idx + CTRLDEF_COUNT; | ||
1780 | ciptr = &(hdw->mpeg_ctrl_info[idx].info); | ||
1781 | ciptr->desc = hdw->mpeg_ctrl_info[idx].desc; | ||
1782 | ciptr->name = mpeg_ids[idx].strid; | ||
1783 | ciptr->v4l_id = mpeg_ids[idx].id; | ||
1784 | ciptr->skip_init = !0; | ||
1785 | ciptr->get_value = ctrl_cx2341x_get; | ||
1786 | ciptr->get_v4lflags = ctrl_cx2341x_getv4lflags; | ||
1787 | ciptr->is_dirty = ctrl_cx2341x_is_dirty; | ||
1788 | if (!idx) ciptr->clear_dirty = ctrl_cx2341x_clear_dirty; | ||
1789 | qctrl.id = ciptr->v4l_id; | ||
1790 | cx2341x_ctrl_query(&hdw->enc_ctl_state,&qctrl); | ||
1791 | if (!(qctrl.flags & V4L2_CTRL_FLAG_READ_ONLY)) { | ||
1792 | ciptr->set_value = ctrl_cx2341x_set; | ||
1793 | } | ||
1794 | strncpy(hdw->mpeg_ctrl_info[idx].desc,qctrl.name, | ||
1795 | PVR2_CTLD_INFO_DESC_SIZE); | ||
1796 | hdw->mpeg_ctrl_info[idx].desc[PVR2_CTLD_INFO_DESC_SIZE-1] = 0; | ||
1797 | ciptr->default_value = qctrl.default_value; | ||
1798 | switch (qctrl.type) { | ||
1799 | default: | ||
1800 | case V4L2_CTRL_TYPE_INTEGER: | ||
1801 | ciptr->type = pvr2_ctl_int; | ||
1802 | ciptr->def.type_int.min_value = qctrl.minimum; | ||
1803 | ciptr->def.type_int.max_value = qctrl.maximum; | ||
1804 | break; | ||
1805 | case V4L2_CTRL_TYPE_BOOLEAN: | ||
1806 | ciptr->type = pvr2_ctl_bool; | ||
1807 | break; | ||
1808 | case V4L2_CTRL_TYPE_MENU: | ||
1809 | ciptr->type = pvr2_ctl_enum; | ||
1810 | ciptr->def.type_enum.value_names = | ||
1811 | cx2341x_ctrl_get_menu(ciptr->v4l_id); | ||
1812 | for (cnt1 = 0; | ||
1813 | ciptr->def.type_enum.value_names[cnt1] != NULL; | ||
1814 | cnt1++) { } | ||
1815 | ciptr->def.type_enum.count = cnt1; | ||
1816 | break; | ||
1817 | } | ||
1818 | cptr->info = ciptr; | ||
1819 | } | ||
1820 | |||
1821 | // Initialize video standard enum dynamic control | ||
1822 | cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDENUM); | ||
1823 | if (cptr) { | ||
1824 | memcpy(&hdw->std_info_enum,cptr->info, | ||
1825 | sizeof(hdw->std_info_enum)); | ||
1826 | cptr->info = &hdw->std_info_enum; | ||
1827 | |||
1828 | } | ||
1829 | // Initialize control data regarding video standard masks | ||
1830 | valid_std_mask = pvr2_std_get_usable(); | ||
1831 | for (idx = 0; idx < 32; idx++) { | ||
1832 | if (!(valid_std_mask & (1 << idx))) continue; | ||
1833 | cnt1 = pvr2_std_id_to_str( | ||
1834 | hdw->std_mask_names[idx], | ||
1835 | sizeof(hdw->std_mask_names[idx])-1, | ||
1836 | 1 << idx); | ||
1837 | hdw->std_mask_names[idx][cnt1] = 0; | ||
1838 | } | ||
1839 | cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDAVAIL); | ||
1840 | if (cptr) { | ||
1841 | memcpy(&hdw->std_info_avail,cptr->info, | ||
1842 | sizeof(hdw->std_info_avail)); | ||
1843 | cptr->info = &hdw->std_info_avail; | ||
1844 | hdw->std_info_avail.def.type_bitmask.bit_names = | ||
1845 | hdw->std_mask_ptrs; | ||
1846 | hdw->std_info_avail.def.type_bitmask.valid_bits = | ||
1847 | valid_std_mask; | ||
1848 | } | ||
1849 | cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDCUR); | ||
1850 | if (cptr) { | ||
1851 | memcpy(&hdw->std_info_cur,cptr->info, | ||
1852 | sizeof(hdw->std_info_cur)); | ||
1853 | cptr->info = &hdw->std_info_cur; | ||
1854 | hdw->std_info_cur.def.type_bitmask.bit_names = | ||
1855 | hdw->std_mask_ptrs; | ||
1856 | hdw->std_info_avail.def.type_bitmask.valid_bits = | ||
1857 | valid_std_mask; | ||
1858 | } | ||
1859 | |||
1860 | hdw->eeprom_addr = -1; | ||
1861 | hdw->unit_number = -1; | ||
1862 | hdw->v4l_minor_number = -1; | ||
1863 | hdw->ctl_write_buffer = kmalloc(PVR2_CTL_BUFFSIZE,GFP_KERNEL); | ||
1864 | if (!hdw->ctl_write_buffer) goto fail; | ||
1865 | hdw->ctl_read_buffer = kmalloc(PVR2_CTL_BUFFSIZE,GFP_KERNEL); | ||
1866 | if (!hdw->ctl_read_buffer) goto fail; | ||
1867 | hdw->ctl_write_urb = usb_alloc_urb(0,GFP_KERNEL); | ||
1868 | if (!hdw->ctl_write_urb) goto fail; | ||
1869 | hdw->ctl_read_urb = usb_alloc_urb(0,GFP_KERNEL); | ||
1870 | if (!hdw->ctl_read_urb) goto fail; | ||
1871 | |||
1872 | down(&pvr2_unit_sem); do { | ||
1873 | for (idx = 0; idx < PVR_NUM; idx++) { | ||
1874 | if (unit_pointers[idx]) continue; | ||
1875 | hdw->unit_number = idx; | ||
1876 | unit_pointers[idx] = hdw; | ||
1877 | break; | ||
1878 | } | ||
1879 | } while (0); up(&pvr2_unit_sem); | ||
1880 | |||
1881 | cnt1 = 0; | ||
1882 | cnt2 = scnprintf(hdw->name+cnt1,sizeof(hdw->name)-cnt1,"pvrusb2"); | ||
1883 | cnt1 += cnt2; | ||
1884 | if (hdw->unit_number >= 0) { | ||
1885 | cnt2 = scnprintf(hdw->name+cnt1,sizeof(hdw->name)-cnt1,"_%c", | ||
1886 | ('a' + hdw->unit_number)); | ||
1887 | cnt1 += cnt2; | ||
1888 | } | ||
1889 | if (cnt1 >= sizeof(hdw->name)) cnt1 = sizeof(hdw->name)-1; | ||
1890 | hdw->name[cnt1] = 0; | ||
1891 | |||
1892 | pvr2_trace(PVR2_TRACE_INIT,"Driver unit number is %d, name is %s", | ||
1893 | hdw->unit_number,hdw->name); | ||
1894 | |||
1895 | hdw->tuner_type = -1; | ||
1896 | hdw->flag_ok = !0; | ||
1897 | /* Initialize the mask of subsystems that we will shut down when we | ||
1898 | stop streaming. */ | ||
1899 | hdw->subsys_stream_mask = PVR2_SUBSYS_RUN_ALL; | ||
1900 | hdw->subsys_stream_mask |= (1<<PVR2_SUBSYS_B_ENC_CFG); | ||
1901 | |||
1902 | pvr2_trace(PVR2_TRACE_INIT,"subsys_stream_mask: 0x%lx", | ||
1903 | hdw->subsys_stream_mask); | ||
1904 | |||
1905 | hdw->usb_intf = intf; | ||
1906 | hdw->usb_dev = interface_to_usbdev(intf); | ||
1907 | |||
1908 | ifnum = hdw->usb_intf->cur_altsetting->desc.bInterfaceNumber; | ||
1909 | usb_set_interface(hdw->usb_dev,ifnum,0); | ||
1910 | |||
1911 | mutex_init(&hdw->ctl_lock_mutex); | ||
1912 | mutex_init(&hdw->big_lock_mutex); | ||
1913 | |||
1914 | return hdw; | ||
1915 | fail: | ||
1916 | if (hdw) { | ||
1917 | if (hdw->ctl_read_urb) usb_free_urb(hdw->ctl_read_urb); | ||
1918 | if (hdw->ctl_write_urb) usb_free_urb(hdw->ctl_write_urb); | ||
1919 | if (hdw->ctl_read_buffer) kfree(hdw->ctl_read_buffer); | ||
1920 | if (hdw->ctl_write_buffer) kfree(hdw->ctl_write_buffer); | ||
1921 | if (hdw->controls) kfree(hdw->controls); | ||
1922 | if (hdw->mpeg_ctrl_info) kfree(hdw->mpeg_ctrl_info); | ||
1923 | kfree(hdw); | ||
1924 | } | ||
1925 | return 0; | ||
1926 | } | ||
1927 | |||
1928 | |||
1929 | /* Remove _all_ associations between this driver and the underlying USB | ||
1930 | layer. */ | ||
1931 | void pvr2_hdw_remove_usb_stuff(struct pvr2_hdw *hdw) | ||
1932 | { | ||
1933 | if (hdw->flag_disconnected) return; | ||
1934 | pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_remove_usb_stuff: hdw=%p",hdw); | ||
1935 | if (hdw->ctl_read_urb) { | ||
1936 | usb_kill_urb(hdw->ctl_read_urb); | ||
1937 | usb_free_urb(hdw->ctl_read_urb); | ||
1938 | hdw->ctl_read_urb = 0; | ||
1939 | } | ||
1940 | if (hdw->ctl_write_urb) { | ||
1941 | usb_kill_urb(hdw->ctl_write_urb); | ||
1942 | usb_free_urb(hdw->ctl_write_urb); | ||
1943 | hdw->ctl_write_urb = 0; | ||
1944 | } | ||
1945 | if (hdw->ctl_read_buffer) { | ||
1946 | kfree(hdw->ctl_read_buffer); | ||
1947 | hdw->ctl_read_buffer = 0; | ||
1948 | } | ||
1949 | if (hdw->ctl_write_buffer) { | ||
1950 | kfree(hdw->ctl_write_buffer); | ||
1951 | hdw->ctl_write_buffer = 0; | ||
1952 | } | ||
1953 | pvr2_hdw_render_useless_unlocked(hdw); | ||
1954 | hdw->flag_disconnected = !0; | ||
1955 | hdw->usb_dev = 0; | ||
1956 | hdw->usb_intf = 0; | ||
1957 | } | ||
1958 | |||
1959 | |||
1960 | /* Destroy hardware interaction structure */ | ||
1961 | void pvr2_hdw_destroy(struct pvr2_hdw *hdw) | ||
1962 | { | ||
1963 | pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_destroy: hdw=%p",hdw); | ||
1964 | if (hdw->fw_buffer) { | ||
1965 | kfree(hdw->fw_buffer); | ||
1966 | hdw->fw_buffer = 0; | ||
1967 | } | ||
1968 | if (hdw->vid_stream) { | ||
1969 | pvr2_stream_destroy(hdw->vid_stream); | ||
1970 | hdw->vid_stream = 0; | ||
1971 | } | ||
1972 | if (hdw->audio_stat) { | ||
1973 | hdw->audio_stat->detach(hdw->audio_stat->ctxt); | ||
1974 | } | ||
1975 | if (hdw->decoder_ctrl) { | ||
1976 | hdw->decoder_ctrl->detach(hdw->decoder_ctrl->ctxt); | ||
1977 | } | ||
1978 | pvr2_i2c_core_done(hdw); | ||
1979 | pvr2_hdw_remove_usb_stuff(hdw); | ||
1980 | down(&pvr2_unit_sem); do { | ||
1981 | if ((hdw->unit_number >= 0) && | ||
1982 | (hdw->unit_number < PVR_NUM) && | ||
1983 | (unit_pointers[hdw->unit_number] == hdw)) { | ||
1984 | unit_pointers[hdw->unit_number] = 0; | ||
1985 | } | ||
1986 | } while (0); up(&pvr2_unit_sem); | ||
1987 | if (hdw->controls) kfree(hdw->controls); | ||
1988 | if (hdw->mpeg_ctrl_info) kfree(hdw->mpeg_ctrl_info); | ||
1989 | if (hdw->std_defs) kfree(hdw->std_defs); | ||
1990 | if (hdw->std_enum_names) kfree(hdw->std_enum_names); | ||
1991 | kfree(hdw); | ||
1992 | } | ||
1993 | |||
1994 | |||
1995 | int pvr2_hdw_init_ok(struct pvr2_hdw *hdw) | ||
1996 | { | ||
1997 | return hdw->flag_init_ok; | ||
1998 | } | ||
1999 | |||
2000 | |||
2001 | int pvr2_hdw_dev_ok(struct pvr2_hdw *hdw) | ||
2002 | { | ||
2003 | return (hdw && hdw->flag_ok); | ||
2004 | } | ||
2005 | |||
2006 | |||
2007 | /* Called when hardware has been unplugged */ | ||
2008 | void pvr2_hdw_disconnect(struct pvr2_hdw *hdw) | ||
2009 | { | ||
2010 | pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_disconnect(hdw=%p)",hdw); | ||
2011 | LOCK_TAKE(hdw->big_lock); | ||
2012 | LOCK_TAKE(hdw->ctl_lock); | ||
2013 | pvr2_hdw_remove_usb_stuff(hdw); | ||
2014 | LOCK_GIVE(hdw->ctl_lock); | ||
2015 | LOCK_GIVE(hdw->big_lock); | ||
2016 | } | ||
2017 | |||
2018 | |||
2019 | // Attempt to autoselect an appropriate value for std_enum_cur given | ||
2020 | // whatever is currently in std_mask_cur | ||
2021 | void pvr2_hdw_internal_find_stdenum(struct pvr2_hdw *hdw) | ||
2022 | { | ||
2023 | unsigned int idx; | ||
2024 | for (idx = 1; idx < hdw->std_enum_cnt; idx++) { | ||
2025 | if (hdw->std_defs[idx-1].id == hdw->std_mask_cur) { | ||
2026 | hdw->std_enum_cur = idx; | ||
2027 | return; | ||
2028 | } | ||
2029 | } | ||
2030 | hdw->std_enum_cur = 0; | ||
2031 | } | ||
2032 | |||
2033 | |||
2034 | // Calculate correct set of enumerated standards based on currently known | ||
2035 | // set of available standards bits. | ||
2036 | void pvr2_hdw_internal_set_std_avail(struct pvr2_hdw *hdw) | ||
2037 | { | ||
2038 | struct v4l2_standard *newstd; | ||
2039 | unsigned int std_cnt; | ||
2040 | unsigned int idx; | ||
2041 | |||
2042 | newstd = pvr2_std_create_enum(&std_cnt,hdw->std_mask_avail); | ||
2043 | |||
2044 | if (hdw->std_defs) { | ||
2045 | kfree(hdw->std_defs); | ||
2046 | hdw->std_defs = 0; | ||
2047 | } | ||
2048 | hdw->std_enum_cnt = 0; | ||
2049 | if (hdw->std_enum_names) { | ||
2050 | kfree(hdw->std_enum_names); | ||
2051 | hdw->std_enum_names = 0; | ||
2052 | } | ||
2053 | |||
2054 | if (!std_cnt) { | ||
2055 | pvr2_trace( | ||
2056 | PVR2_TRACE_ERROR_LEGS, | ||
2057 | "WARNING: Failed to identify any viable standards"); | ||
2058 | } | ||
2059 | hdw->std_enum_names = kmalloc(sizeof(char *)*(std_cnt+1),GFP_KERNEL); | ||
2060 | hdw->std_enum_names[0] = "none"; | ||
2061 | for (idx = 0; idx < std_cnt; idx++) { | ||
2062 | hdw->std_enum_names[idx+1] = | ||
2063 | newstd[idx].name; | ||
2064 | } | ||
2065 | // Set up the dynamic control for this standard | ||
2066 | hdw->std_info_enum.def.type_enum.value_names = hdw->std_enum_names; | ||
2067 | hdw->std_info_enum.def.type_enum.count = std_cnt+1; | ||
2068 | hdw->std_defs = newstd; | ||
2069 | hdw->std_enum_cnt = std_cnt+1; | ||
2070 | hdw->std_enum_cur = 0; | ||
2071 | hdw->std_info_cur.def.type_bitmask.valid_bits = hdw->std_mask_avail; | ||
2072 | } | ||
2073 | |||
2074 | |||
2075 | int pvr2_hdw_get_stdenum_value(struct pvr2_hdw *hdw, | ||
2076 | struct v4l2_standard *std, | ||
2077 | unsigned int idx) | ||
2078 | { | ||
2079 | int ret = -EINVAL; | ||
2080 | if (!idx) return ret; | ||
2081 | LOCK_TAKE(hdw->big_lock); do { | ||
2082 | if (idx >= hdw->std_enum_cnt) break; | ||
2083 | idx--; | ||
2084 | memcpy(std,hdw->std_defs+idx,sizeof(*std)); | ||
2085 | ret = 0; | ||
2086 | } while (0); LOCK_GIVE(hdw->big_lock); | ||
2087 | return ret; | ||
2088 | } | ||
2089 | |||
2090 | |||
2091 | /* Get the number of defined controls */ | ||
2092 | unsigned int pvr2_hdw_get_ctrl_count(struct pvr2_hdw *hdw) | ||
2093 | { | ||
2094 | return hdw->control_cnt; | ||
2095 | } | ||
2096 | |||
2097 | |||
2098 | /* Retrieve a control handle given its index (0..count-1) */ | ||
2099 | struct pvr2_ctrl *pvr2_hdw_get_ctrl_by_index(struct pvr2_hdw *hdw, | ||
2100 | unsigned int idx) | ||
2101 | { | ||
2102 | if (idx >= hdw->control_cnt) return 0; | ||
2103 | return hdw->controls + idx; | ||
2104 | } | ||
2105 | |||
2106 | |||
2107 | /* Retrieve a control handle given its index (0..count-1) */ | ||
2108 | struct pvr2_ctrl *pvr2_hdw_get_ctrl_by_id(struct pvr2_hdw *hdw, | ||
2109 | unsigned int ctl_id) | ||
2110 | { | ||
2111 | struct pvr2_ctrl *cptr; | ||
2112 | unsigned int idx; | ||
2113 | int i; | ||
2114 | |||
2115 | /* This could be made a lot more efficient, but for now... */ | ||
2116 | for (idx = 0; idx < hdw->control_cnt; idx++) { | ||
2117 | cptr = hdw->controls + idx; | ||
2118 | i = cptr->info->internal_id; | ||
2119 | if (i && (i == ctl_id)) return cptr; | ||
2120 | } | ||
2121 | return 0; | ||
2122 | } | ||
2123 | |||
2124 | |||
2125 | /* Given a V4L ID, retrieve the control structure associated with it. */ | ||
2126 | struct pvr2_ctrl *pvr2_hdw_get_ctrl_v4l(struct pvr2_hdw *hdw,unsigned int ctl_id) | ||
2127 | { | ||
2128 | struct pvr2_ctrl *cptr; | ||
2129 | unsigned int idx; | ||
2130 | int i; | ||
2131 | |||
2132 | /* This could be made a lot more efficient, but for now... */ | ||
2133 | for (idx = 0; idx < hdw->control_cnt; idx++) { | ||
2134 | cptr = hdw->controls + idx; | ||
2135 | i = cptr->info->v4l_id; | ||
2136 | if (i && (i == ctl_id)) return cptr; | ||
2137 | } | ||
2138 | return 0; | ||
2139 | } | ||
2140 | |||
2141 | |||
2142 | /* Given a V4L ID for its immediate predecessor, retrieve the control | ||
2143 | structure associated with it. */ | ||
2144 | struct pvr2_ctrl *pvr2_hdw_get_ctrl_nextv4l(struct pvr2_hdw *hdw, | ||
2145 | unsigned int ctl_id) | ||
2146 | { | ||
2147 | struct pvr2_ctrl *cptr,*cp2; | ||
2148 | unsigned int idx; | ||
2149 | int i; | ||
2150 | |||
2151 | /* This could be made a lot more efficient, but for now... */ | ||
2152 | cp2 = 0; | ||
2153 | for (idx = 0; idx < hdw->control_cnt; idx++) { | ||
2154 | cptr = hdw->controls + idx; | ||
2155 | i = cptr->info->v4l_id; | ||
2156 | if (!i) continue; | ||
2157 | if (i <= ctl_id) continue; | ||
2158 | if (cp2 && (cp2->info->v4l_id < i)) continue; | ||
2159 | cp2 = cptr; | ||
2160 | } | ||
2161 | return cp2; | ||
2162 | return 0; | ||
2163 | } | ||
2164 | |||
2165 | |||
2166 | static const char *get_ctrl_typename(enum pvr2_ctl_type tp) | ||
2167 | { | ||
2168 | switch (tp) { | ||
2169 | case pvr2_ctl_int: return "integer"; | ||
2170 | case pvr2_ctl_enum: return "enum"; | ||
2171 | case pvr2_ctl_bool: return "boolean"; | ||
2172 | case pvr2_ctl_bitmask: return "bitmask"; | ||
2173 | } | ||
2174 | return ""; | ||
2175 | } | ||
2176 | |||
2177 | |||
2178 | /* Commit all control changes made up to this point. Subsystems can be | ||
2179 | indirectly affected by these changes. For a given set of things being | ||
2180 | committed, we'll clear the affected subsystem bits and then once we're | ||
2181 | done committing everything we'll make a request to restore the subsystem | ||
2182 | state(s) back to their previous value before this function was called. | ||
2183 | Thus we can automatically reconfigure affected pieces of the driver as | ||
2184 | controls are changed. */ | ||
2185 | int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw) | ||
2186 | { | ||
2187 | unsigned long saved_subsys_mask = hdw->subsys_enabled_mask; | ||
2188 | unsigned long stale_subsys_mask = 0; | ||
2189 | unsigned int idx; | ||
2190 | struct pvr2_ctrl *cptr; | ||
2191 | int value; | ||
2192 | int commit_flag = 0; | ||
2193 | char buf[100]; | ||
2194 | unsigned int bcnt,ccnt; | ||
2195 | |||
2196 | for (idx = 0; idx < hdw->control_cnt; idx++) { | ||
2197 | cptr = hdw->controls + idx; | ||
2198 | if (cptr->info->is_dirty == 0) continue; | ||
2199 | if (!cptr->info->is_dirty(cptr)) continue; | ||
2200 | if (!commit_flag) { | ||
2201 | commit_flag = !0; | ||
2202 | } | ||
2203 | |||
2204 | bcnt = scnprintf(buf,sizeof(buf),"\"%s\" <-- ", | ||
2205 | cptr->info->name); | ||
2206 | value = 0; | ||
2207 | cptr->info->get_value(cptr,&value); | ||
2208 | pvr2_ctrl_value_to_sym_internal(cptr,~0,value, | ||
2209 | buf+bcnt, | ||
2210 | sizeof(buf)-bcnt,&ccnt); | ||
2211 | bcnt += ccnt; | ||
2212 | bcnt += scnprintf(buf+bcnt,sizeof(buf)-bcnt," <%s>", | ||
2213 | get_ctrl_typename(cptr->info->type)); | ||
2214 | pvr2_trace(PVR2_TRACE_CTL, | ||
2215 | "/*--TRACE_COMMIT--*/ %.*s", | ||
2216 | bcnt,buf); | ||
2217 | } | ||
2218 | |||
2219 | if (!commit_flag) { | ||
2220 | /* Nothing has changed */ | ||
2221 | return 0; | ||
2222 | } | ||
2223 | |||
2224 | /* When video standard changes, reset the hres and vres values - | ||
2225 | but if the user has pending changes there, then let the changes | ||
2226 | take priority. */ | ||
2227 | if (hdw->std_dirty) { | ||
2228 | /* Rewrite the vertical resolution to be appropriate to the | ||
2229 | video standard that has been selected. */ | ||
2230 | int nvres; | ||
2231 | if (hdw->std_mask_cur & V4L2_STD_525_60) { | ||
2232 | nvres = 480; | ||
2233 | } else { | ||
2234 | nvres = 576; | ||
2235 | } | ||
2236 | if (nvres != hdw->res_ver_val) { | ||
2237 | hdw->res_ver_val = nvres; | ||
2238 | hdw->res_ver_dirty = !0; | ||
2239 | } | ||
2240 | } | ||
2241 | |||
2242 | if (hdw->std_dirty || | ||
2243 | 0) { | ||
2244 | /* If any of this changes, then the encoder needs to be | ||
2245 | reconfigured, and we need to reset the stream. */ | ||
2246 | stale_subsys_mask |= (1<<PVR2_SUBSYS_B_ENC_CFG); | ||
2247 | stale_subsys_mask |= hdw->subsys_stream_mask; | ||
2248 | } | ||
2249 | |||
2250 | if (hdw->srate_dirty) { | ||
2251 | /* Write new sample rate into control structure since | ||
2252 | * the master copy is stale. We must track srate | ||
2253 | * separate from the mpeg control structure because | ||
2254 | * other logic also uses this value. */ | ||
2255 | struct v4l2_ext_controls cs; | ||
2256 | struct v4l2_ext_control c1; | ||
2257 | memset(&cs,0,sizeof(cs)); | ||
2258 | memset(&c1,0,sizeof(c1)); | ||
2259 | cs.controls = &c1; | ||
2260 | cs.count = 1; | ||
2261 | c1.id = V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ; | ||
2262 | c1.value = hdw->srate_val; | ||
2263 | cx2341x_ext_ctrls(&hdw->enc_ctl_state,&cs,VIDIOC_S_EXT_CTRLS); | ||
2264 | } | ||
2265 | |||
2266 | /* Scan i2c core at this point - before we clear all the dirty | ||
2267 | bits. Various parts of the i2c core will notice dirty bits as | ||
2268 | appropriate and arrange to broadcast or directly send updates to | ||
2269 | the client drivers in order to keep everything in sync */ | ||
2270 | pvr2_i2c_core_check_stale(hdw); | ||
2271 | |||
2272 | for (idx = 0; idx < hdw->control_cnt; idx++) { | ||
2273 | cptr = hdw->controls + idx; | ||
2274 | if (!cptr->info->clear_dirty) continue; | ||
2275 | cptr->info->clear_dirty(cptr); | ||
2276 | } | ||
2277 | |||
2278 | /* Now execute i2c core update */ | ||
2279 | pvr2_i2c_core_sync(hdw); | ||
2280 | |||
2281 | pvr2_hdw_subsys_bit_chg_no_lock(hdw,stale_subsys_mask,0); | ||
2282 | pvr2_hdw_subsys_bit_chg_no_lock(hdw,~0,saved_subsys_mask); | ||
2283 | |||
2284 | return 0; | ||
2285 | } | ||
2286 | |||
2287 | |||
2288 | int pvr2_hdw_commit_ctl(struct pvr2_hdw *hdw) | ||
2289 | { | ||
2290 | LOCK_TAKE(hdw->big_lock); do { | ||
2291 | pvr2_hdw_commit_ctl_internal(hdw); | ||
2292 | } while (0); LOCK_GIVE(hdw->big_lock); | ||
2293 | return 0; | ||
2294 | } | ||
2295 | |||
2296 | |||
2297 | void pvr2_hdw_poll(struct pvr2_hdw *hdw) | ||
2298 | { | ||
2299 | LOCK_TAKE(hdw->big_lock); do { | ||
2300 | pvr2_i2c_core_sync(hdw); | ||
2301 | } while (0); LOCK_GIVE(hdw->big_lock); | ||
2302 | } | ||
2303 | |||
2304 | |||
2305 | void pvr2_hdw_setup_poll_trigger(struct pvr2_hdw *hdw, | ||
2306 | void (*func)(void *), | ||
2307 | void *data) | ||
2308 | { | ||
2309 | LOCK_TAKE(hdw->big_lock); do { | ||
2310 | hdw->poll_trigger_func = func; | ||
2311 | hdw->poll_trigger_data = data; | ||
2312 | } while (0); LOCK_GIVE(hdw->big_lock); | ||
2313 | } | ||
2314 | |||
2315 | |||
2316 | void pvr2_hdw_poll_trigger_unlocked(struct pvr2_hdw *hdw) | ||
2317 | { | ||
2318 | if (hdw->poll_trigger_func) { | ||
2319 | hdw->poll_trigger_func(hdw->poll_trigger_data); | ||
2320 | } | ||
2321 | } | ||
2322 | |||
2323 | |||
2324 | void pvr2_hdw_poll_trigger(struct pvr2_hdw *hdw) | ||
2325 | { | ||
2326 | LOCK_TAKE(hdw->big_lock); do { | ||
2327 | pvr2_hdw_poll_trigger_unlocked(hdw); | ||
2328 | } while (0); LOCK_GIVE(hdw->big_lock); | ||
2329 | } | ||
2330 | |||
2331 | |||
2332 | /* Return name for this driver instance */ | ||
2333 | const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *hdw) | ||
2334 | { | ||
2335 | return hdw->name; | ||
2336 | } | ||
2337 | |||
2338 | |||
2339 | /* Return bit mask indicating signal status */ | ||
2340 | unsigned int pvr2_hdw_get_signal_status_internal(struct pvr2_hdw *hdw) | ||
2341 | { | ||
2342 | unsigned int msk = 0; | ||
2343 | switch (hdw->input_val) { | ||
2344 | case PVR2_CVAL_INPUT_TV: | ||
2345 | case PVR2_CVAL_INPUT_RADIO: | ||
2346 | if (hdw->decoder_ctrl && | ||
2347 | hdw->decoder_ctrl->tuned(hdw->decoder_ctrl->ctxt)) { | ||
2348 | msk |= PVR2_SIGNAL_OK; | ||
2349 | if (hdw->audio_stat && | ||
2350 | hdw->audio_stat->status(hdw->audio_stat->ctxt)) { | ||
2351 | if (hdw->flag_stereo) { | ||
2352 | msk |= PVR2_SIGNAL_STEREO; | ||
2353 | } | ||
2354 | if (hdw->flag_bilingual) { | ||
2355 | msk |= PVR2_SIGNAL_SAP; | ||
2356 | } | ||
2357 | } | ||
2358 | } | ||
2359 | break; | ||
2360 | default: | ||
2361 | msk |= PVR2_SIGNAL_OK | PVR2_SIGNAL_STEREO; | ||
2362 | } | ||
2363 | return msk; | ||
2364 | } | ||
2365 | |||
2366 | |||
2367 | int pvr2_hdw_is_hsm(struct pvr2_hdw *hdw) | ||
2368 | { | ||
2369 | int result; | ||
2370 | LOCK_TAKE(hdw->ctl_lock); do { | ||
2371 | hdw->cmd_buffer[0] = 0x0b; | ||
2372 | result = pvr2_send_request(hdw, | ||
2373 | hdw->cmd_buffer,1, | ||
2374 | hdw->cmd_buffer,1); | ||
2375 | if (result < 0) break; | ||
2376 | result = (hdw->cmd_buffer[0] != 0); | ||
2377 | } while(0); LOCK_GIVE(hdw->ctl_lock); | ||
2378 | return result; | ||
2379 | } | ||
2380 | |||
2381 | |||
2382 | /* Return bit mask indicating signal status */ | ||
2383 | unsigned int pvr2_hdw_get_signal_status(struct pvr2_hdw *hdw) | ||
2384 | { | ||
2385 | unsigned int msk = 0; | ||
2386 | LOCK_TAKE(hdw->big_lock); do { | ||
2387 | msk = pvr2_hdw_get_signal_status_internal(hdw); | ||
2388 | } while (0); LOCK_GIVE(hdw->big_lock); | ||
2389 | return msk; | ||
2390 | } | ||
2391 | |||
2392 | |||
2393 | /* Get handle to video output stream */ | ||
2394 | struct pvr2_stream *pvr2_hdw_get_video_stream(struct pvr2_hdw *hp) | ||
2395 | { | ||
2396 | return hp->vid_stream; | ||
2397 | } | ||
2398 | |||
2399 | |||
2400 | void pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw) | ||
2401 | { | ||
2402 | int nr = pvr2_hdw_get_unit_number(hdw); | ||
2403 | LOCK_TAKE(hdw->big_lock); do { | ||
2404 | hdw->log_requested = !0; | ||
2405 | printk(KERN_INFO "pvrusb2: ================= START STATUS CARD #%d =================\n", nr); | ||
2406 | pvr2_i2c_core_check_stale(hdw); | ||
2407 | hdw->log_requested = 0; | ||
2408 | pvr2_i2c_core_sync(hdw); | ||
2409 | pvr2_trace(PVR2_TRACE_INFO,"cx2341x config:"); | ||
2410 | cx2341x_log_status(&hdw->enc_ctl_state, "pvrusb2"); | ||
2411 | printk(KERN_INFO "pvrusb2: ================== END STATUS CARD #%d ==================\n", nr); | ||
2412 | } while (0); LOCK_GIVE(hdw->big_lock); | ||
2413 | } | ||
2414 | |||
2415 | void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw, int enable_flag) | ||
2416 | { | ||
2417 | int ret; | ||
2418 | u16 address; | ||
2419 | unsigned int pipe; | ||
2420 | LOCK_TAKE(hdw->big_lock); do { | ||
2421 | if ((hdw->fw_buffer == 0) == !enable_flag) break; | ||
2422 | |||
2423 | if (!enable_flag) { | ||
2424 | pvr2_trace(PVR2_TRACE_FIRMWARE, | ||
2425 | "Cleaning up after CPU firmware fetch"); | ||
2426 | kfree(hdw->fw_buffer); | ||
2427 | hdw->fw_buffer = 0; | ||
2428 | hdw->fw_size = 0; | ||
2429 | /* Now release the CPU. It will disconnect and | ||
2430 | reconnect later. */ | ||
2431 | pvr2_hdw_cpureset_assert(hdw,0); | ||
2432 | break; | ||
2433 | } | ||
2434 | |||
2435 | pvr2_trace(PVR2_TRACE_FIRMWARE, | ||
2436 | "Preparing to suck out CPU firmware"); | ||
2437 | hdw->fw_size = 0x2000; | ||
2438 | hdw->fw_buffer = kmalloc(hdw->fw_size,GFP_KERNEL); | ||
2439 | if (!hdw->fw_buffer) { | ||
2440 | hdw->fw_size = 0; | ||
2441 | break; | ||
2442 | } | ||
2443 | |||
2444 | memset(hdw->fw_buffer,0,hdw->fw_size); | ||
2445 | |||
2446 | /* We have to hold the CPU during firmware upload. */ | ||
2447 | pvr2_hdw_cpureset_assert(hdw,1); | ||
2448 | |||
2449 | /* download the firmware from address 0000-1fff in 2048 | ||
2450 | (=0x800) bytes chunk. */ | ||
2451 | |||
2452 | pvr2_trace(PVR2_TRACE_FIRMWARE,"Grabbing CPU firmware"); | ||
2453 | pipe = usb_rcvctrlpipe(hdw->usb_dev, 0); | ||
2454 | for(address = 0; address < hdw->fw_size; address += 0x800) { | ||
2455 | ret = usb_control_msg(hdw->usb_dev,pipe,0xa0,0xc0, | ||
2456 | address,0, | ||
2457 | hdw->fw_buffer+address,0x800,HZ); | ||
2458 | if (ret < 0) break; | ||
2459 | } | ||
2460 | |||
2461 | pvr2_trace(PVR2_TRACE_FIRMWARE,"Done grabbing CPU firmware"); | ||
2462 | |||
2463 | } while (0); LOCK_GIVE(hdw->big_lock); | ||
2464 | } | ||
2465 | |||
2466 | |||
2467 | /* Return true if we're in a mode for retrieval CPU firmware */ | ||
2468 | int pvr2_hdw_cpufw_get_enabled(struct pvr2_hdw *hdw) | ||
2469 | { | ||
2470 | return hdw->fw_buffer != 0; | ||
2471 | } | ||
2472 | |||
2473 | |||
2474 | int pvr2_hdw_cpufw_get(struct pvr2_hdw *hdw,unsigned int offs, | ||
2475 | char *buf,unsigned int cnt) | ||
2476 | { | ||
2477 | int ret = -EINVAL; | ||
2478 | LOCK_TAKE(hdw->big_lock); do { | ||
2479 | if (!buf) break; | ||
2480 | if (!cnt) break; | ||
2481 | |||
2482 | if (!hdw->fw_buffer) { | ||
2483 | ret = -EIO; | ||
2484 | break; | ||
2485 | } | ||
2486 | |||
2487 | if (offs >= hdw->fw_size) { | ||
2488 | pvr2_trace(PVR2_TRACE_FIRMWARE, | ||
2489 | "Read firmware data offs=%d EOF", | ||
2490 | offs); | ||
2491 | ret = 0; | ||
2492 | break; | ||
2493 | } | ||
2494 | |||
2495 | if (offs + cnt > hdw->fw_size) cnt = hdw->fw_size - offs; | ||
2496 | |||
2497 | memcpy(buf,hdw->fw_buffer+offs,cnt); | ||
2498 | |||
2499 | pvr2_trace(PVR2_TRACE_FIRMWARE, | ||
2500 | "Read firmware data offs=%d cnt=%d", | ||
2501 | offs,cnt); | ||
2502 | ret = cnt; | ||
2503 | } while (0); LOCK_GIVE(hdw->big_lock); | ||
2504 | |||
2505 | return ret; | ||
2506 | } | ||
2507 | |||
2508 | |||
2509 | int pvr2_hdw_v4l_get_minor_number(struct pvr2_hdw *hdw) | ||
2510 | { | ||
2511 | return hdw->v4l_minor_number; | ||
2512 | } | ||
2513 | |||
2514 | |||
2515 | /* Store the v4l minor device number */ | ||
2516 | void pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *hdw,int v) | ||
2517 | { | ||
2518 | hdw->v4l_minor_number = v; | ||
2519 | } | ||
2520 | |||
2521 | |||
2522 | void pvr2_reset_ctl_endpoints(struct pvr2_hdw *hdw) | ||
2523 | { | ||
2524 | if (!hdw->usb_dev) return; | ||
2525 | usb_settoggle(hdw->usb_dev, PVR2_CTL_WRITE_ENDPOINT & 0xf, | ||
2526 | !(PVR2_CTL_WRITE_ENDPOINT & USB_DIR_IN), 0); | ||
2527 | usb_settoggle(hdw->usb_dev, PVR2_CTL_READ_ENDPOINT & 0xf, | ||
2528 | !(PVR2_CTL_READ_ENDPOINT & USB_DIR_IN), 0); | ||
2529 | usb_clear_halt(hdw->usb_dev, | ||
2530 | usb_rcvbulkpipe(hdw->usb_dev, | ||
2531 | PVR2_CTL_READ_ENDPOINT & 0x7f)); | ||
2532 | usb_clear_halt(hdw->usb_dev, | ||
2533 | usb_sndbulkpipe(hdw->usb_dev, | ||
2534 | PVR2_CTL_WRITE_ENDPOINT & 0x7f)); | ||
2535 | } | ||
2536 | |||
2537 | |||
2538 | static void pvr2_ctl_write_complete(struct urb *urb, struct pt_regs *regs) | ||
2539 | { | ||
2540 | struct pvr2_hdw *hdw = urb->context; | ||
2541 | hdw->ctl_write_pend_flag = 0; | ||
2542 | if (hdw->ctl_read_pend_flag) return; | ||
2543 | complete(&hdw->ctl_done); | ||
2544 | } | ||
2545 | |||
2546 | |||
2547 | static void pvr2_ctl_read_complete(struct urb *urb, struct pt_regs *regs) | ||
2548 | { | ||
2549 | struct pvr2_hdw *hdw = urb->context; | ||
2550 | hdw->ctl_read_pend_flag = 0; | ||
2551 | if (hdw->ctl_write_pend_flag) return; | ||
2552 | complete(&hdw->ctl_done); | ||
2553 | } | ||
2554 | |||
2555 | |||
2556 | static void pvr2_ctl_timeout(unsigned long data) | ||
2557 | { | ||
2558 | struct pvr2_hdw *hdw = (struct pvr2_hdw *)data; | ||
2559 | if (hdw->ctl_write_pend_flag || hdw->ctl_read_pend_flag) { | ||
2560 | hdw->ctl_timeout_flag = !0; | ||
2561 | if (hdw->ctl_write_pend_flag && hdw->ctl_write_urb) { | ||
2562 | usb_unlink_urb(hdw->ctl_write_urb); | ||
2563 | } | ||
2564 | if (hdw->ctl_read_pend_flag && hdw->ctl_read_urb) { | ||
2565 | usb_unlink_urb(hdw->ctl_read_urb); | ||
2566 | } | ||
2567 | } | ||
2568 | } | ||
2569 | |||
2570 | |||
2571 | int pvr2_send_request_ex(struct pvr2_hdw *hdw, | ||
2572 | unsigned int timeout,int probe_fl, | ||
2573 | void *write_data,unsigned int write_len, | ||
2574 | void *read_data,unsigned int read_len) | ||
2575 | { | ||
2576 | unsigned int idx; | ||
2577 | int status = 0; | ||
2578 | struct timer_list timer; | ||
2579 | if (!hdw->ctl_lock_held) { | ||
2580 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, | ||
2581 | "Attempted to execute control transfer" | ||
2582 | " without lock!!"); | ||
2583 | return -EDEADLK; | ||
2584 | } | ||
2585 | if ((!hdw->flag_ok) && !probe_fl) { | ||
2586 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, | ||
2587 | "Attempted to execute control transfer" | ||
2588 | " when device not ok"); | ||
2589 | return -EIO; | ||
2590 | } | ||
2591 | if (!(hdw->ctl_read_urb && hdw->ctl_write_urb)) { | ||
2592 | if (!probe_fl) { | ||
2593 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, | ||
2594 | "Attempted to execute control transfer" | ||
2595 | " when USB is disconnected"); | ||
2596 | } | ||
2597 | return -ENOTTY; | ||
2598 | } | ||
2599 | |||
2600 | /* Ensure that we have sane parameters */ | ||
2601 | if (!write_data) write_len = 0; | ||
2602 | if (!read_data) read_len = 0; | ||
2603 | if (write_len > PVR2_CTL_BUFFSIZE) { | ||
2604 | pvr2_trace( | ||
2605 | PVR2_TRACE_ERROR_LEGS, | ||
2606 | "Attempted to execute %d byte" | ||
2607 | " control-write transfer (limit=%d)", | ||
2608 | write_len,PVR2_CTL_BUFFSIZE); | ||
2609 | return -EINVAL; | ||
2610 | } | ||
2611 | if (read_len > PVR2_CTL_BUFFSIZE) { | ||
2612 | pvr2_trace( | ||
2613 | PVR2_TRACE_ERROR_LEGS, | ||
2614 | "Attempted to execute %d byte" | ||
2615 | " control-read transfer (limit=%d)", | ||
2616 | write_len,PVR2_CTL_BUFFSIZE); | ||
2617 | return -EINVAL; | ||
2618 | } | ||
2619 | if ((!write_len) && (!read_len)) { | ||
2620 | pvr2_trace( | ||
2621 | PVR2_TRACE_ERROR_LEGS, | ||
2622 | "Attempted to execute null control transfer?"); | ||
2623 | return -EINVAL; | ||
2624 | } | ||
2625 | |||
2626 | |||
2627 | hdw->cmd_debug_state = 1; | ||
2628 | if (write_len) { | ||
2629 | hdw->cmd_debug_code = ((unsigned char *)write_data)[0]; | ||
2630 | } else { | ||
2631 | hdw->cmd_debug_code = 0; | ||
2632 | } | ||
2633 | hdw->cmd_debug_write_len = write_len; | ||
2634 | hdw->cmd_debug_read_len = read_len; | ||
2635 | |||
2636 | /* Initialize common stuff */ | ||
2637 | init_completion(&hdw->ctl_done); | ||
2638 | hdw->ctl_timeout_flag = 0; | ||
2639 | hdw->ctl_write_pend_flag = 0; | ||
2640 | hdw->ctl_read_pend_flag = 0; | ||
2641 | init_timer(&timer); | ||
2642 | timer.expires = jiffies + timeout; | ||
2643 | timer.data = (unsigned long)hdw; | ||
2644 | timer.function = pvr2_ctl_timeout; | ||
2645 | |||
2646 | if (write_len) { | ||
2647 | hdw->cmd_debug_state = 2; | ||
2648 | /* Transfer write data to internal buffer */ | ||
2649 | for (idx = 0; idx < write_len; idx++) { | ||
2650 | hdw->ctl_write_buffer[idx] = | ||
2651 | ((unsigned char *)write_data)[idx]; | ||
2652 | } | ||
2653 | /* Initiate a write request */ | ||
2654 | usb_fill_bulk_urb(hdw->ctl_write_urb, | ||
2655 | hdw->usb_dev, | ||
2656 | usb_sndbulkpipe(hdw->usb_dev, | ||
2657 | PVR2_CTL_WRITE_ENDPOINT), | ||
2658 | hdw->ctl_write_buffer, | ||
2659 | write_len, | ||
2660 | pvr2_ctl_write_complete, | ||
2661 | hdw); | ||
2662 | hdw->ctl_write_urb->actual_length = 0; | ||
2663 | hdw->ctl_write_pend_flag = !0; | ||
2664 | status = usb_submit_urb(hdw->ctl_write_urb,GFP_KERNEL); | ||
2665 | if (status < 0) { | ||
2666 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, | ||
2667 | "Failed to submit write-control" | ||
2668 | " URB status=%d",status); | ||
2669 | hdw->ctl_write_pend_flag = 0; | ||
2670 | goto done; | ||
2671 | } | ||
2672 | } | ||
2673 | |||
2674 | if (read_len) { | ||
2675 | hdw->cmd_debug_state = 3; | ||
2676 | memset(hdw->ctl_read_buffer,0x43,read_len); | ||
2677 | /* Initiate a read request */ | ||
2678 | usb_fill_bulk_urb(hdw->ctl_read_urb, | ||
2679 | hdw->usb_dev, | ||
2680 | usb_rcvbulkpipe(hdw->usb_dev, | ||
2681 | PVR2_CTL_READ_ENDPOINT), | ||
2682 | hdw->ctl_read_buffer, | ||
2683 | read_len, | ||
2684 | pvr2_ctl_read_complete, | ||
2685 | hdw); | ||
2686 | hdw->ctl_read_urb->actual_length = 0; | ||
2687 | hdw->ctl_read_pend_flag = !0; | ||
2688 | status = usb_submit_urb(hdw->ctl_read_urb,GFP_KERNEL); | ||
2689 | if (status < 0) { | ||
2690 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, | ||
2691 | "Failed to submit read-control" | ||
2692 | " URB status=%d",status); | ||
2693 | hdw->ctl_read_pend_flag = 0; | ||
2694 | goto done; | ||
2695 | } | ||
2696 | } | ||
2697 | |||
2698 | /* Start timer */ | ||
2699 | add_timer(&timer); | ||
2700 | |||
2701 | /* Now wait for all I/O to complete */ | ||
2702 | hdw->cmd_debug_state = 4; | ||
2703 | while (hdw->ctl_write_pend_flag || hdw->ctl_read_pend_flag) { | ||
2704 | wait_for_completion(&hdw->ctl_done); | ||
2705 | } | ||
2706 | hdw->cmd_debug_state = 5; | ||
2707 | |||
2708 | /* Stop timer */ | ||
2709 | del_timer_sync(&timer); | ||
2710 | |||
2711 | hdw->cmd_debug_state = 6; | ||
2712 | status = 0; | ||
2713 | |||
2714 | if (hdw->ctl_timeout_flag) { | ||
2715 | status = -ETIMEDOUT; | ||
2716 | if (!probe_fl) { | ||
2717 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, | ||
2718 | "Timed out control-write"); | ||
2719 | } | ||
2720 | goto done; | ||
2721 | } | ||
2722 | |||
2723 | if (write_len) { | ||
2724 | /* Validate results of write request */ | ||
2725 | if ((hdw->ctl_write_urb->status != 0) && | ||
2726 | (hdw->ctl_write_urb->status != -ENOENT) && | ||
2727 | (hdw->ctl_write_urb->status != -ESHUTDOWN) && | ||
2728 | (hdw->ctl_write_urb->status != -ECONNRESET)) { | ||
2729 | /* USB subsystem is reporting some kind of failure | ||
2730 | on the write */ | ||
2731 | status = hdw->ctl_write_urb->status; | ||
2732 | if (!probe_fl) { | ||
2733 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, | ||
2734 | "control-write URB failure," | ||
2735 | " status=%d", | ||
2736 | status); | ||
2737 | } | ||
2738 | goto done; | ||
2739 | } | ||
2740 | if (hdw->ctl_write_urb->actual_length < write_len) { | ||
2741 | /* Failed to write enough data */ | ||
2742 | status = -EIO; | ||
2743 | if (!probe_fl) { | ||
2744 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, | ||
2745 | "control-write URB short," | ||
2746 | " expected=%d got=%d", | ||
2747 | write_len, | ||
2748 | hdw->ctl_write_urb->actual_length); | ||
2749 | } | ||
2750 | goto done; | ||
2751 | } | ||
2752 | } | ||
2753 | if (read_len) { | ||
2754 | /* Validate results of read request */ | ||
2755 | if ((hdw->ctl_read_urb->status != 0) && | ||
2756 | (hdw->ctl_read_urb->status != -ENOENT) && | ||
2757 | (hdw->ctl_read_urb->status != -ESHUTDOWN) && | ||
2758 | (hdw->ctl_read_urb->status != -ECONNRESET)) { | ||
2759 | /* USB subsystem is reporting some kind of failure | ||
2760 | on the read */ | ||
2761 | status = hdw->ctl_read_urb->status; | ||
2762 | if (!probe_fl) { | ||
2763 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, | ||
2764 | "control-read URB failure," | ||
2765 | " status=%d", | ||
2766 | status); | ||
2767 | } | ||
2768 | goto done; | ||
2769 | } | ||
2770 | if (hdw->ctl_read_urb->actual_length < read_len) { | ||
2771 | /* Failed to read enough data */ | ||
2772 | status = -EIO; | ||
2773 | if (!probe_fl) { | ||
2774 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, | ||
2775 | "control-read URB short," | ||
2776 | " expected=%d got=%d", | ||
2777 | read_len, | ||
2778 | hdw->ctl_read_urb->actual_length); | ||
2779 | } | ||
2780 | goto done; | ||
2781 | } | ||
2782 | /* Transfer retrieved data out from internal buffer */ | ||
2783 | for (idx = 0; idx < read_len; idx++) { | ||
2784 | ((unsigned char *)read_data)[idx] = | ||
2785 | hdw->ctl_read_buffer[idx]; | ||
2786 | } | ||
2787 | } | ||
2788 | |||
2789 | done: | ||
2790 | |||
2791 | hdw->cmd_debug_state = 0; | ||
2792 | if ((status < 0) && (!probe_fl)) { | ||
2793 | pvr2_hdw_render_useless_unlocked(hdw); | ||
2794 | } | ||
2795 | return status; | ||
2796 | } | ||
2797 | |||
2798 | |||
2799 | int pvr2_send_request(struct pvr2_hdw *hdw, | ||
2800 | void *write_data,unsigned int write_len, | ||
2801 | void *read_data,unsigned int read_len) | ||
2802 | { | ||
2803 | return pvr2_send_request_ex(hdw,HZ*4,0, | ||
2804 | write_data,write_len, | ||
2805 | read_data,read_len); | ||
2806 | } | ||
2807 | |||
2808 | int pvr2_write_register(struct pvr2_hdw *hdw, u16 reg, u32 data) | ||
2809 | { | ||
2810 | int ret; | ||
2811 | |||
2812 | LOCK_TAKE(hdw->ctl_lock); | ||
2813 | |||
2814 | hdw->cmd_buffer[0] = 0x04; /* write register prefix */ | ||
2815 | PVR2_DECOMPOSE_LE(hdw->cmd_buffer,1,data); | ||
2816 | hdw->cmd_buffer[5] = 0; | ||
2817 | hdw->cmd_buffer[6] = (reg >> 8) & 0xff; | ||
2818 | hdw->cmd_buffer[7] = reg & 0xff; | ||
2819 | |||
2820 | |||
2821 | ret = pvr2_send_request(hdw, hdw->cmd_buffer, 8, hdw->cmd_buffer, 0); | ||
2822 | |||
2823 | LOCK_GIVE(hdw->ctl_lock); | ||
2824 | |||
2825 | return ret; | ||
2826 | } | ||
2827 | |||
2828 | |||
2829 | int pvr2_read_register(struct pvr2_hdw *hdw, u16 reg, u32 *data) | ||
2830 | { | ||
2831 | int ret = 0; | ||
2832 | |||
2833 | LOCK_TAKE(hdw->ctl_lock); | ||
2834 | |||
2835 | hdw->cmd_buffer[0] = 0x05; /* read register prefix */ | ||
2836 | hdw->cmd_buffer[1] = 0; | ||
2837 | hdw->cmd_buffer[2] = 0; | ||
2838 | hdw->cmd_buffer[3] = 0; | ||
2839 | hdw->cmd_buffer[4] = 0; | ||
2840 | hdw->cmd_buffer[5] = 0; | ||
2841 | hdw->cmd_buffer[6] = (reg >> 8) & 0xff; | ||
2842 | hdw->cmd_buffer[7] = reg & 0xff; | ||
2843 | |||
2844 | ret |= pvr2_send_request(hdw, hdw->cmd_buffer, 8, hdw->cmd_buffer, 4); | ||
2845 | *data = PVR2_COMPOSE_LE(hdw->cmd_buffer,0); | ||
2846 | |||
2847 | LOCK_GIVE(hdw->ctl_lock); | ||
2848 | |||
2849 | return ret; | ||
2850 | } | ||
2851 | |||
2852 | |||
2853 | int pvr2_write_u16(struct pvr2_hdw *hdw, u16 data, int res) | ||
2854 | { | ||
2855 | int ret; | ||
2856 | |||
2857 | LOCK_TAKE(hdw->ctl_lock); | ||
2858 | |||
2859 | hdw->cmd_buffer[0] = (data >> 8) & 0xff; | ||
2860 | hdw->cmd_buffer[1] = data & 0xff; | ||
2861 | |||
2862 | ret = pvr2_send_request(hdw, hdw->cmd_buffer, 2, hdw->cmd_buffer, res); | ||
2863 | |||
2864 | LOCK_GIVE(hdw->ctl_lock); | ||
2865 | |||
2866 | return ret; | ||
2867 | } | ||
2868 | |||
2869 | |||
2870 | int pvr2_write_u8(struct pvr2_hdw *hdw, u8 data, int res) | ||
2871 | { | ||
2872 | int ret; | ||
2873 | |||
2874 | LOCK_TAKE(hdw->ctl_lock); | ||
2875 | |||
2876 | hdw->cmd_buffer[0] = data; | ||
2877 | |||
2878 | ret = pvr2_send_request(hdw, hdw->cmd_buffer, 1, hdw->cmd_buffer, res); | ||
2879 | |||
2880 | LOCK_GIVE(hdw->ctl_lock); | ||
2881 | |||
2882 | return ret; | ||
2883 | } | ||
2884 | |||
2885 | |||
2886 | void pvr2_hdw_render_useless_unlocked(struct pvr2_hdw *hdw) | ||
2887 | { | ||
2888 | if (!hdw->flag_ok) return; | ||
2889 | pvr2_trace(PVR2_TRACE_INIT,"render_useless"); | ||
2890 | hdw->flag_ok = 0; | ||
2891 | if (hdw->vid_stream) { | ||
2892 | pvr2_stream_setup(hdw->vid_stream,0,0,0); | ||
2893 | } | ||
2894 | hdw->flag_streaming_enabled = 0; | ||
2895 | hdw->subsys_enabled_mask = 0; | ||
2896 | } | ||
2897 | |||
2898 | |||
2899 | void pvr2_hdw_render_useless(struct pvr2_hdw *hdw) | ||
2900 | { | ||
2901 | LOCK_TAKE(hdw->ctl_lock); | ||
2902 | pvr2_hdw_render_useless_unlocked(hdw); | ||
2903 | LOCK_GIVE(hdw->ctl_lock); | ||
2904 | } | ||
2905 | |||
2906 | |||
2907 | void pvr2_hdw_device_reset(struct pvr2_hdw *hdw) | ||
2908 | { | ||
2909 | int ret; | ||
2910 | pvr2_trace(PVR2_TRACE_INIT,"Performing a device reset..."); | ||
2911 | ret = usb_lock_device_for_reset(hdw->usb_dev,0); | ||
2912 | if (ret == 1) { | ||
2913 | ret = usb_reset_device(hdw->usb_dev); | ||
2914 | usb_unlock_device(hdw->usb_dev); | ||
2915 | } else { | ||
2916 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, | ||
2917 | "Failed to lock USB device ret=%d",ret); | ||
2918 | } | ||
2919 | if (init_pause_msec) { | ||
2920 | pvr2_trace(PVR2_TRACE_INFO, | ||
2921 | "Waiting %u msec for hardware to settle", | ||
2922 | init_pause_msec); | ||
2923 | msleep(init_pause_msec); | ||
2924 | } | ||
2925 | |||
2926 | } | ||
2927 | |||
2928 | |||
2929 | void pvr2_hdw_cpureset_assert(struct pvr2_hdw *hdw,int val) | ||
2930 | { | ||
2931 | char da[1]; | ||
2932 | unsigned int pipe; | ||
2933 | int ret; | ||
2934 | |||
2935 | if (!hdw->usb_dev) return; | ||
2936 | |||
2937 | pvr2_trace(PVR2_TRACE_INIT,"cpureset_assert(%d)",val); | ||
2938 | |||
2939 | da[0] = val ? 0x01 : 0x00; | ||
2940 | |||
2941 | /* Write the CPUCS register on the 8051. The lsb of the register | ||
2942 | is the reset bit; a 1 asserts reset while a 0 clears it. */ | ||
2943 | pipe = usb_sndctrlpipe(hdw->usb_dev, 0); | ||
2944 | ret = usb_control_msg(hdw->usb_dev,pipe,0xa0,0x40,0xe600,0,da,1,HZ); | ||
2945 | if (ret < 0) { | ||
2946 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, | ||
2947 | "cpureset_assert(%d) error=%d",val,ret); | ||
2948 | pvr2_hdw_render_useless(hdw); | ||
2949 | } | ||
2950 | } | ||
2951 | |||
2952 | |||
2953 | int pvr2_hdw_cmd_deep_reset(struct pvr2_hdw *hdw) | ||
2954 | { | ||
2955 | int status; | ||
2956 | LOCK_TAKE(hdw->ctl_lock); do { | ||
2957 | pvr2_trace(PVR2_TRACE_INIT,"Requesting uproc hard reset"); | ||
2958 | hdw->flag_ok = !0; | ||
2959 | hdw->cmd_buffer[0] = 0xdd; | ||
2960 | status = pvr2_send_request(hdw,hdw->cmd_buffer,1,0,0); | ||
2961 | } while (0); LOCK_GIVE(hdw->ctl_lock); | ||
2962 | return status; | ||
2963 | } | ||
2964 | |||
2965 | |||
2966 | int pvr2_hdw_cmd_powerup(struct pvr2_hdw *hdw) | ||
2967 | { | ||
2968 | int status; | ||
2969 | LOCK_TAKE(hdw->ctl_lock); do { | ||
2970 | pvr2_trace(PVR2_TRACE_INIT,"Requesting powerup"); | ||
2971 | hdw->cmd_buffer[0] = 0xde; | ||
2972 | status = pvr2_send_request(hdw,hdw->cmd_buffer,1,0,0); | ||
2973 | } while (0); LOCK_GIVE(hdw->ctl_lock); | ||
2974 | return status; | ||
2975 | } | ||
2976 | |||
2977 | |||
2978 | int pvr2_hdw_cmd_decoder_reset(struct pvr2_hdw *hdw) | ||
2979 | { | ||
2980 | if (!hdw->decoder_ctrl) { | ||
2981 | pvr2_trace(PVR2_TRACE_INIT, | ||
2982 | "Unable to reset decoder: nothing attached"); | ||
2983 | return -ENOTTY; | ||
2984 | } | ||
2985 | |||
2986 | if (!hdw->decoder_ctrl->force_reset) { | ||
2987 | pvr2_trace(PVR2_TRACE_INIT, | ||
2988 | "Unable to reset decoder: not implemented"); | ||
2989 | return -ENOTTY; | ||
2990 | } | ||
2991 | |||
2992 | pvr2_trace(PVR2_TRACE_INIT, | ||
2993 | "Requesting decoder reset"); | ||
2994 | hdw->decoder_ctrl->force_reset(hdw->decoder_ctrl->ctxt); | ||
2995 | return 0; | ||
2996 | } | ||
2997 | |||
2998 | |||
2999 | int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl) | ||
3000 | { | ||
3001 | int status; | ||
3002 | LOCK_TAKE(hdw->ctl_lock); do { | ||
3003 | hdw->cmd_buffer[0] = (runFl ? 0x36 : 0x37); | ||
3004 | status = pvr2_send_request(hdw,hdw->cmd_buffer,1,0,0); | ||
3005 | } while (0); LOCK_GIVE(hdw->ctl_lock); | ||
3006 | if (!status) { | ||
3007 | hdw->subsys_enabled_mask = | ||
3008 | ((hdw->subsys_enabled_mask & | ||
3009 | ~(1<<PVR2_SUBSYS_B_USBSTREAM_RUN)) | | ||
3010 | (runFl ? (1<<PVR2_SUBSYS_B_USBSTREAM_RUN) : 0)); | ||
3011 | } | ||
3012 | return status; | ||
3013 | } | ||
3014 | |||
3015 | |||
3016 | void pvr2_hdw_get_debug_info(const struct pvr2_hdw *hdw, | ||
3017 | struct pvr2_hdw_debug_info *ptr) | ||
3018 | { | ||
3019 | ptr->big_lock_held = hdw->big_lock_held; | ||
3020 | ptr->ctl_lock_held = hdw->ctl_lock_held; | ||
3021 | ptr->flag_ok = hdw->flag_ok; | ||
3022 | ptr->flag_disconnected = hdw->flag_disconnected; | ||
3023 | ptr->flag_init_ok = hdw->flag_init_ok; | ||
3024 | ptr->flag_streaming_enabled = hdw->flag_streaming_enabled; | ||
3025 | ptr->subsys_flags = hdw->subsys_enabled_mask; | ||
3026 | ptr->cmd_debug_state = hdw->cmd_debug_state; | ||
3027 | ptr->cmd_code = hdw->cmd_debug_code; | ||
3028 | ptr->cmd_debug_write_len = hdw->cmd_debug_write_len; | ||
3029 | ptr->cmd_debug_read_len = hdw->cmd_debug_read_len; | ||
3030 | ptr->cmd_debug_timeout = hdw->ctl_timeout_flag; | ||
3031 | ptr->cmd_debug_write_pend = hdw->ctl_write_pend_flag; | ||
3032 | ptr->cmd_debug_read_pend = hdw->ctl_read_pend_flag; | ||
3033 | ptr->cmd_debug_rstatus = hdw->ctl_read_urb->status; | ||
3034 | ptr->cmd_debug_wstatus = hdw->ctl_read_urb->status; | ||
3035 | } | ||
3036 | |||
3037 | |||
3038 | int pvr2_hdw_gpio_get_dir(struct pvr2_hdw *hdw,u32 *dp) | ||
3039 | { | ||
3040 | return pvr2_read_register(hdw,PVR2_GPIO_DIR,dp); | ||
3041 | } | ||
3042 | |||
3043 | |||
3044 | int pvr2_hdw_gpio_get_out(struct pvr2_hdw *hdw,u32 *dp) | ||
3045 | { | ||
3046 | return pvr2_read_register(hdw,PVR2_GPIO_OUT,dp); | ||
3047 | } | ||
3048 | |||
3049 | |||
3050 | int pvr2_hdw_gpio_get_in(struct pvr2_hdw *hdw,u32 *dp) | ||
3051 | { | ||
3052 | return pvr2_read_register(hdw,PVR2_GPIO_IN,dp); | ||
3053 | } | ||
3054 | |||
3055 | |||
3056 | int pvr2_hdw_gpio_chg_dir(struct pvr2_hdw *hdw,u32 msk,u32 val) | ||
3057 | { | ||
3058 | u32 cval,nval; | ||
3059 | int ret; | ||
3060 | if (~msk) { | ||
3061 | ret = pvr2_read_register(hdw,PVR2_GPIO_DIR,&cval); | ||
3062 | if (ret) return ret; | ||
3063 | nval = (cval & ~msk) | (val & msk); | ||
3064 | pvr2_trace(PVR2_TRACE_GPIO, | ||
3065 | "GPIO direction changing 0x%x:0x%x" | ||
3066 | " from 0x%x to 0x%x", | ||
3067 | msk,val,cval,nval); | ||
3068 | } else { | ||
3069 | nval = val; | ||
3070 | pvr2_trace(PVR2_TRACE_GPIO, | ||
3071 | "GPIO direction changing to 0x%x",nval); | ||
3072 | } | ||
3073 | return pvr2_write_register(hdw,PVR2_GPIO_DIR,nval); | ||
3074 | } | ||
3075 | |||
3076 | |||
3077 | int pvr2_hdw_gpio_chg_out(struct pvr2_hdw *hdw,u32 msk,u32 val) | ||
3078 | { | ||
3079 | u32 cval,nval; | ||
3080 | int ret; | ||
3081 | if (~msk) { | ||
3082 | ret = pvr2_read_register(hdw,PVR2_GPIO_OUT,&cval); | ||
3083 | if (ret) return ret; | ||
3084 | nval = (cval & ~msk) | (val & msk); | ||
3085 | pvr2_trace(PVR2_TRACE_GPIO, | ||
3086 | "GPIO output changing 0x%x:0x%x from 0x%x to 0x%x", | ||
3087 | msk,val,cval,nval); | ||
3088 | } else { | ||
3089 | nval = val; | ||
3090 | pvr2_trace(PVR2_TRACE_GPIO, | ||
3091 | "GPIO output changing to 0x%x",nval); | ||
3092 | } | ||
3093 | return pvr2_write_register(hdw,PVR2_GPIO_OUT,nval); | ||
3094 | } | ||
3095 | |||
3096 | |||
3097 | int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw) | ||
3098 | { | ||
3099 | int result; | ||
3100 | LOCK_TAKE(hdw->ctl_lock); do { | ||
3101 | hdw->cmd_buffer[0] = 0xeb; | ||
3102 | result = pvr2_send_request(hdw, | ||
3103 | hdw->cmd_buffer,1, | ||
3104 | hdw->cmd_buffer,1); | ||
3105 | if (result < 0) break; | ||
3106 | result = hdw->cmd_buffer[0]; | ||
3107 | } while(0); LOCK_GIVE(hdw->ctl_lock); | ||
3108 | return result; | ||
3109 | } | ||
3110 | |||
3111 | |||
3112 | /* | ||
3113 | Stuff for Emacs to see, in order to encourage consistent editing style: | ||
3114 | *** Local Variables: *** | ||
3115 | *** mode: c *** | ||
3116 | *** fill-column: 75 *** | ||
3117 | *** tab-width: 8 *** | ||
3118 | *** c-basic-offset: 8 *** | ||
3119 | *** End: *** | ||
3120 | */ | ||
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/drivers/media/video/pvrusb2/pvrusb2-hdw.h new file mode 100644 index 000000000000..63f529154431 --- /dev/null +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.h | |||
@@ -0,0 +1,335 @@ | |||
1 | /* | ||
2 | * | ||
3 | * $Id$ | ||
4 | * | ||
5 | * Copyright (C) 2005 Mike Isely <isely@pobox.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 | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | * | ||
20 | */ | ||
21 | #ifndef __PVRUSB2_HDW_H | ||
22 | #define __PVRUSB2_HDW_H | ||
23 | |||
24 | #include <linux/usb.h> | ||
25 | #include <linux/videodev2.h> | ||
26 | #include "pvrusb2-io.h" | ||
27 | #include "pvrusb2-ctrl.h" | ||
28 | |||
29 | |||
30 | /* Private internal control ids, look these up with | ||
31 | pvr2_hdw_get_ctrl_by_id() - these are NOT visible in V4L */ | ||
32 | #define PVR2_CID_STDENUM 1 | ||
33 | #define PVR2_CID_STDCUR 2 | ||
34 | #define PVR2_CID_STDAVAIL 3 | ||
35 | #define PVR2_CID_INPUT 4 | ||
36 | #define PVR2_CID_AUDIOMODE 5 | ||
37 | #define PVR2_CID_FREQUENCY 6 | ||
38 | #define PVR2_CID_HRES 7 | ||
39 | #define PVR2_CID_VRES 8 | ||
40 | |||
41 | /* Legal values for the INPUT state variable */ | ||
42 | #define PVR2_CVAL_INPUT_TV 0 | ||
43 | #define PVR2_CVAL_INPUT_SVIDEO 1 | ||
44 | #define PVR2_CVAL_INPUT_COMPOSITE 2 | ||
45 | #define PVR2_CVAL_INPUT_RADIO 3 | ||
46 | |||
47 | /* Values that pvr2_hdw_get_signal_status() returns */ | ||
48 | #define PVR2_SIGNAL_OK 0x0001 | ||
49 | #define PVR2_SIGNAL_STEREO 0x0002 | ||
50 | #define PVR2_SIGNAL_SAP 0x0004 | ||
51 | |||
52 | |||
53 | /* Subsystem definitions - these are various pieces that can be | ||
54 | independently stopped / started. Usually you don't want to mess with | ||
55 | this directly (let the driver handle things itself), but it is useful | ||
56 | for debugging. */ | ||
57 | #define PVR2_SUBSYS_B_ENC_FIRMWARE 0 | ||
58 | #define PVR2_SUBSYS_B_ENC_CFG 1 | ||
59 | #define PVR2_SUBSYS_B_DIGITIZER_RUN 2 | ||
60 | #define PVR2_SUBSYS_B_USBSTREAM_RUN 3 | ||
61 | #define PVR2_SUBSYS_B_ENC_RUN 4 | ||
62 | |||
63 | #define PVR2_SUBSYS_CFG_ALL ( \ | ||
64 | (1 << PVR2_SUBSYS_B_ENC_FIRMWARE) | \ | ||
65 | (1 << PVR2_SUBSYS_B_ENC_CFG) ) | ||
66 | #define PVR2_SUBSYS_RUN_ALL ( \ | ||
67 | (1 << PVR2_SUBSYS_B_DIGITIZER_RUN) | \ | ||
68 | (1 << PVR2_SUBSYS_B_USBSTREAM_RUN) | \ | ||
69 | (1 << PVR2_SUBSYS_B_ENC_RUN) ) | ||
70 | #define PVR2_SUBSYS_ALL ( \ | ||
71 | PVR2_SUBSYS_CFG_ALL | \ | ||
72 | PVR2_SUBSYS_RUN_ALL ) | ||
73 | |||
74 | enum pvr2_config { | ||
75 | pvr2_config_empty, | ||
76 | pvr2_config_mpeg, | ||
77 | pvr2_config_vbi, | ||
78 | pvr2_config_radio, | ||
79 | }; | ||
80 | |||
81 | const char *pvr2_config_get_name(enum pvr2_config); | ||
82 | |||
83 | struct pvr2_hdw; | ||
84 | |||
85 | /* Create and return a structure for interacting with the underlying | ||
86 | hardware */ | ||
87 | struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, | ||
88 | const struct usb_device_id *devid); | ||
89 | |||
90 | /* Poll for background activity (if any) */ | ||
91 | void pvr2_hdw_poll(struct pvr2_hdw *); | ||
92 | |||
93 | /* Trigger a poll to take place later at a convenient time */ | ||
94 | void pvr2_hdw_poll_trigger(struct pvr2_hdw *); | ||
95 | void pvr2_hdw_poll_trigger_unlocked(struct pvr2_hdw *); | ||
96 | |||
97 | /* Register a callback used to trigger a future poll */ | ||
98 | void pvr2_hdw_setup_poll_trigger(struct pvr2_hdw *, | ||
99 | void (*func)(void *), | ||
100 | void *data); | ||
101 | |||
102 | /* Get pointer to structure given unit number */ | ||
103 | struct pvr2_hdw *pvr2_hdw_find(int unit_number); | ||
104 | |||
105 | /* Destroy hardware interaction structure */ | ||
106 | void pvr2_hdw_destroy(struct pvr2_hdw *); | ||
107 | |||
108 | /* Set up the structure and attempt to put the device into a usable state. | ||
109 | This can be a time-consuming operation, which is why it is not done | ||
110 | internally as part of the create() step. Return value is exactly the | ||
111 | same as pvr2_hdw_init_ok(). */ | ||
112 | int pvr2_hdw_setup(struct pvr2_hdw *); | ||
113 | |||
114 | /* Initialization succeeded */ | ||
115 | int pvr2_hdw_init_ok(struct pvr2_hdw *); | ||
116 | |||
117 | /* Return true if in the ready (normal) state */ | ||
118 | int pvr2_hdw_dev_ok(struct pvr2_hdw *); | ||
119 | |||
120 | /* Return small integer number [1..N] for logical instance number of this | ||
121 | device. This is useful for indexing array-valued module parameters. */ | ||
122 | int pvr2_hdw_get_unit_number(struct pvr2_hdw *); | ||
123 | |||
124 | /* Get pointer to underlying USB device */ | ||
125 | struct usb_device *pvr2_hdw_get_dev(struct pvr2_hdw *); | ||
126 | |||
127 | /* Retrieve serial number of device */ | ||
128 | unsigned long pvr2_hdw_get_sn(struct pvr2_hdw *); | ||
129 | |||
130 | /* Called when hardware has been unplugged */ | ||
131 | void pvr2_hdw_disconnect(struct pvr2_hdw *); | ||
132 | |||
133 | /* Get the number of defined controls */ | ||
134 | unsigned int pvr2_hdw_get_ctrl_count(struct pvr2_hdw *); | ||
135 | |||
136 | /* Retrieve a control handle given its index (0..count-1) */ | ||
137 | struct pvr2_ctrl *pvr2_hdw_get_ctrl_by_index(struct pvr2_hdw *,unsigned int); | ||
138 | |||
139 | /* Retrieve a control handle given its internal ID (if any) */ | ||
140 | struct pvr2_ctrl *pvr2_hdw_get_ctrl_by_id(struct pvr2_hdw *,unsigned int); | ||
141 | |||
142 | /* Retrieve a control handle given its V4L ID (if any) */ | ||
143 | struct pvr2_ctrl *pvr2_hdw_get_ctrl_v4l(struct pvr2_hdw *,unsigned int ctl_id); | ||
144 | |||
145 | /* Retrieve a control handle given its immediate predecessor V4L ID (if any) */ | ||
146 | struct pvr2_ctrl *pvr2_hdw_get_ctrl_nextv4l(struct pvr2_hdw *, | ||
147 | unsigned int ctl_id); | ||
148 | |||
149 | /* Commit all control changes made up to this point */ | ||
150 | int pvr2_hdw_commit_ctl(struct pvr2_hdw *); | ||
151 | |||
152 | /* Return name for this driver instance */ | ||
153 | const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *); | ||
154 | |||
155 | /* Return PVR2_SIGNAL_XXXX bit mask indicating signal status */ | ||
156 | unsigned int pvr2_hdw_get_signal_status(struct pvr2_hdw *); | ||
157 | |||
158 | /* Query device and see if it thinks it is on a high-speed USB link */ | ||
159 | int pvr2_hdw_is_hsm(struct pvr2_hdw *); | ||
160 | |||
161 | /* Turn streaming on/off */ | ||
162 | int pvr2_hdw_set_streaming(struct pvr2_hdw *,int); | ||
163 | |||
164 | /* Find out if streaming is on */ | ||
165 | int pvr2_hdw_get_streaming(struct pvr2_hdw *); | ||
166 | |||
167 | /* Configure the type of stream to generate */ | ||
168 | int pvr2_hdw_set_stream_type(struct pvr2_hdw *, enum pvr2_config); | ||
169 | |||
170 | /* Get handle to video output stream */ | ||
171 | struct pvr2_stream *pvr2_hdw_get_video_stream(struct pvr2_hdw *); | ||
172 | |||
173 | /* Emit a video standard struct */ | ||
174 | int pvr2_hdw_get_stdenum_value(struct pvr2_hdw *hdw,struct v4l2_standard *std, | ||
175 | unsigned int idx); | ||
176 | |||
177 | /* Enable / disable various pieces of hardware. Items to change are | ||
178 | identified by bit positions within msk, and new state for each item is | ||
179 | identified by corresponding bit positions within val. */ | ||
180 | void pvr2_hdw_subsys_bit_chg(struct pvr2_hdw *hdw, | ||
181 | unsigned long msk,unsigned long val); | ||
182 | |||
183 | /* Shortcut for pvr2_hdw_subsys_bit_chg(hdw,msk,msk) */ | ||
184 | void pvr2_hdw_subsys_bit_set(struct pvr2_hdw *hdw,unsigned long msk); | ||
185 | |||
186 | /* Shortcut for pvr2_hdw_subsys_bit_chg(hdw,msk,0) */ | ||
187 | void pvr2_hdw_subsys_bit_clr(struct pvr2_hdw *hdw,unsigned long msk); | ||
188 | |||
189 | /* Retrieve mask indicating which pieces of hardware are currently enabled | ||
190 | / configured. */ | ||
191 | unsigned long pvr2_hdw_subsys_get(struct pvr2_hdw *); | ||
192 | |||
193 | /* Adjust mask of what get shut down when streaming is stopped. This is a | ||
194 | debugging aid. */ | ||
195 | void pvr2_hdw_subsys_stream_bit_chg(struct pvr2_hdw *hdw, | ||
196 | unsigned long msk,unsigned long val); | ||
197 | |||
198 | /* Retrieve mask indicating which pieces of hardware are disabled when | ||
199 | streaming is turned off. */ | ||
200 | unsigned long pvr2_hdw_subsys_stream_get(struct pvr2_hdw *); | ||
201 | |||
202 | |||
203 | /* Enable / disable retrieval of CPU firmware. This must be enabled before | ||
204 | pvr2_hdw_cpufw_get() will function. Note that doing this may prevent | ||
205 | the device from running (and leaving this mode may imply a device | ||
206 | reset). */ | ||
207 | void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *, int enable_flag); | ||
208 | |||
209 | /* Return true if we're in a mode for retrieval CPU firmware */ | ||
210 | int pvr2_hdw_cpufw_get_enabled(struct pvr2_hdw *); | ||
211 | |||
212 | /* Retrieve a piece of the CPU's firmware at the given offset. Return | ||
213 | value is the number of bytes retrieved or zero if we're past the end or | ||
214 | an error otherwise (e.g. if firmware retrieval is not enabled). */ | ||
215 | int pvr2_hdw_cpufw_get(struct pvr2_hdw *,unsigned int offs, | ||
216 | char *buf,unsigned int cnt); | ||
217 | |||
218 | /* Retrieve previously stored v4l minor device number */ | ||
219 | int pvr2_hdw_v4l_get_minor_number(struct pvr2_hdw *); | ||
220 | |||
221 | /* Store the v4l minor device number */ | ||
222 | void pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *,int); | ||
223 | |||
224 | |||
225 | /* The following entry points are all lower level things you normally don't | ||
226 | want to worry about. */ | ||
227 | |||
228 | /* Attempt to recover from a USB foul-up (in practice I find that if you | ||
229 | have to do this, then it's already too late). */ | ||
230 | void pvr2_reset_ctl_endpoints(struct pvr2_hdw *hdw); | ||
231 | |||
232 | /* Issue a command and get a response from the device. LOTS of higher | ||
233 | level stuff is built on this. */ | ||
234 | int pvr2_send_request(struct pvr2_hdw *, | ||
235 | void *write_ptr,unsigned int write_len, | ||
236 | void *read_ptr,unsigned int read_len); | ||
237 | |||
238 | /* Issue a command and get a response from the device. This extended | ||
239 | version includes a probe flag (which if set means that device errors | ||
240 | should not be logged or treated as fatal) and a timeout in jiffies. | ||
241 | This can be used to non-lethally probe the health of endpoint 1. */ | ||
242 | int pvr2_send_request_ex(struct pvr2_hdw *,unsigned int timeout,int probe_fl, | ||
243 | void *write_ptr,unsigned int write_len, | ||
244 | void *read_ptr,unsigned int read_len); | ||
245 | |||
246 | /* Slightly higher level device communication functions. */ | ||
247 | int pvr2_write_register(struct pvr2_hdw *, u16, u32); | ||
248 | int pvr2_read_register(struct pvr2_hdw *, u16, u32 *); | ||
249 | int pvr2_write_u16(struct pvr2_hdw *, u16, int); | ||
250 | int pvr2_write_u8(struct pvr2_hdw *, u8, int); | ||
251 | |||
252 | /* Call if for any reason we can't talk to the hardware anymore - this will | ||
253 | cause the driver to stop flailing on the device. */ | ||
254 | void pvr2_hdw_render_useless(struct pvr2_hdw *); | ||
255 | void pvr2_hdw_render_useless_unlocked(struct pvr2_hdw *); | ||
256 | |||
257 | /* Set / clear 8051's reset bit */ | ||
258 | void pvr2_hdw_cpureset_assert(struct pvr2_hdw *,int); | ||
259 | |||
260 | /* Execute a USB-commanded device reset */ | ||
261 | void pvr2_hdw_device_reset(struct pvr2_hdw *); | ||
262 | |||
263 | /* Execute hard reset command (after this point it's likely that the | ||
264 | encoder will have to be reconfigured). This also clears the "useless" | ||
265 | state. */ | ||
266 | int pvr2_hdw_cmd_deep_reset(struct pvr2_hdw *); | ||
267 | |||
268 | /* Execute simple reset command */ | ||
269 | int pvr2_hdw_cmd_powerup(struct pvr2_hdw *); | ||
270 | |||
271 | /* Order decoder to reset */ | ||
272 | int pvr2_hdw_cmd_decoder_reset(struct pvr2_hdw *); | ||
273 | |||
274 | /* Stop / start video stream transport */ | ||
275 | int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl); | ||
276 | |||
277 | /* Find I2C address of eeprom */ | ||
278 | int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *); | ||
279 | |||
280 | /* Direct manipulation of GPIO bits */ | ||
281 | int pvr2_hdw_gpio_get_dir(struct pvr2_hdw *hdw,u32 *); | ||
282 | int pvr2_hdw_gpio_get_out(struct pvr2_hdw *hdw,u32 *); | ||
283 | int pvr2_hdw_gpio_get_in(struct pvr2_hdw *hdw,u32 *); | ||
284 | int pvr2_hdw_gpio_chg_dir(struct pvr2_hdw *hdw,u32 msk,u32 val); | ||
285 | int pvr2_hdw_gpio_chg_out(struct pvr2_hdw *hdw,u32 msk,u32 val); | ||
286 | |||
287 | /* This data structure is specifically for the next function... */ | ||
288 | struct pvr2_hdw_debug_info { | ||
289 | int big_lock_held; | ||
290 | int ctl_lock_held; | ||
291 | int flag_ok; | ||
292 | int flag_disconnected; | ||
293 | int flag_init_ok; | ||
294 | int flag_streaming_enabled; | ||
295 | unsigned long subsys_flags; | ||
296 | int cmd_debug_state; | ||
297 | int cmd_debug_write_len; | ||
298 | int cmd_debug_read_len; | ||
299 | int cmd_debug_write_pend; | ||
300 | int cmd_debug_read_pend; | ||
301 | int cmd_debug_timeout; | ||
302 | int cmd_debug_rstatus; | ||
303 | int cmd_debug_wstatus; | ||
304 | unsigned char cmd_code; | ||
305 | }; | ||
306 | |||
307 | /* Non-intrusively retrieve internal state info - this is useful for | ||
308 | diagnosing lockups. Note that this operation is completed without any | ||
309 | kind of locking and so it is not atomic and may yield inconsistent | ||
310 | results. This is *purely* a debugging aid. */ | ||
311 | void pvr2_hdw_get_debug_info(const struct pvr2_hdw *hdw, | ||
312 | struct pvr2_hdw_debug_info *); | ||
313 | |||
314 | /* Cause modules to log their state once */ | ||
315 | void pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw); | ||
316 | |||
317 | /* Cause encoder firmware to be uploaded into the device. This is normally | ||
318 | done autonomously, but the interface is exported here because it is also | ||
319 | a debugging aid. */ | ||
320 | int pvr2_upload_firmware2(struct pvr2_hdw *hdw); | ||
321 | |||
322 | /* List of device types that we can match */ | ||
323 | extern struct usb_device_id pvr2_device_table[]; | ||
324 | |||
325 | #endif /* __PVRUSB2_HDW_H */ | ||
326 | |||
327 | /* | ||
328 | Stuff for Emacs to see, in order to encourage consistent editing style: | ||
329 | *** Local Variables: *** | ||
330 | *** mode: c *** | ||
331 | *** fill-column: 75 *** | ||
332 | *** tab-width: 8 *** | ||
333 | *** c-basic-offset: 8 *** | ||
334 | *** End: *** | ||
335 | */ | ||
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c new file mode 100644 index 000000000000..1dd4f6249b99 --- /dev/null +++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c | |||
@@ -0,0 +1,115 @@ | |||
1 | /* | ||
2 | * | ||
3 | * $Id$ | ||
4 | * | ||
5 | * Copyright (C) 2005 Mike Isely <isely@pobox.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 | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include "pvrusb2-i2c-core.h" | ||
23 | #include "pvrusb2-hdw-internal.h" | ||
24 | #include "pvrusb2-debug.h" | ||
25 | #include "pvrusb2-i2c-cmd-v4l2.h" | ||
26 | #include "pvrusb2-audio.h" | ||
27 | #include "pvrusb2-tuner.h" | ||
28 | #include "pvrusb2-demod.h" | ||
29 | #include "pvrusb2-video-v4l.h" | ||
30 | #ifdef CONFIG_VIDEO_PVRUSB2_24XXX | ||
31 | #include "pvrusb2-cx2584x-v4l.h" | ||
32 | #include "pvrusb2-wm8775.h" | ||
33 | #endif | ||
34 | |||
35 | #define trace_i2c(...) pvr2_trace(PVR2_TRACE_I2C,__VA_ARGS__) | ||
36 | |||
37 | #define OP_STANDARD 0 | ||
38 | #define OP_BCSH 1 | ||
39 | #define OP_VOLUME 2 | ||
40 | #define OP_FREQ 3 | ||
41 | #define OP_AUDIORATE 4 | ||
42 | #define OP_SIZE 5 | ||
43 | #define OP_LOG 6 | ||
44 | |||
45 | static const struct pvr2_i2c_op * const ops[] = { | ||
46 | [OP_STANDARD] = &pvr2_i2c_op_v4l2_standard, | ||
47 | [OP_BCSH] = &pvr2_i2c_op_v4l2_bcsh, | ||
48 | [OP_VOLUME] = &pvr2_i2c_op_v4l2_volume, | ||
49 | [OP_FREQ] = &pvr2_i2c_op_v4l2_frequency, | ||
50 | [OP_SIZE] = &pvr2_i2c_op_v4l2_size, | ||
51 | [OP_LOG] = &pvr2_i2c_op_v4l2_log, | ||
52 | }; | ||
53 | |||
54 | void pvr2_i2c_probe(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp) | ||
55 | { | ||
56 | int id; | ||
57 | id = cp->client->driver->id; | ||
58 | cp->ctl_mask = ((1 << OP_STANDARD) | | ||
59 | (1 << OP_BCSH) | | ||
60 | (1 << OP_VOLUME) | | ||
61 | (1 << OP_FREQ) | | ||
62 | (1 << OP_SIZE) | | ||
63 | (1 << OP_LOG)); | ||
64 | |||
65 | if (id == I2C_DRIVERID_MSP3400) { | ||
66 | if (pvr2_i2c_msp3400_setup(hdw,cp)) { | ||
67 | return; | ||
68 | } | ||
69 | } | ||
70 | if (id == I2C_DRIVERID_TUNER) { | ||
71 | if (pvr2_i2c_tuner_setup(hdw,cp)) { | ||
72 | return; | ||
73 | } | ||
74 | } | ||
75 | #ifdef CONFIG_VIDEO_PVRUSB2_24XXX | ||
76 | if (id == I2C_DRIVERID_CX25840) { | ||
77 | if (pvr2_i2c_cx2584x_v4l_setup(hdw,cp)) { | ||
78 | return; | ||
79 | } | ||
80 | } | ||
81 | if (id == I2C_DRIVERID_WM8775) { | ||
82 | if (pvr2_i2c_wm8775_setup(hdw,cp)) { | ||
83 | return; | ||
84 | } | ||
85 | } | ||
86 | #endif | ||
87 | if (id == I2C_DRIVERID_SAA711X) { | ||
88 | if (pvr2_i2c_decoder_v4l_setup(hdw,cp)) { | ||
89 | return; | ||
90 | } | ||
91 | } | ||
92 | if (id == I2C_DRIVERID_TDA9887) { | ||
93 | if (pvr2_i2c_demod_setup(hdw,cp)) { | ||
94 | return; | ||
95 | } | ||
96 | } | ||
97 | } | ||
98 | |||
99 | |||
100 | const struct pvr2_i2c_op *pvr2_i2c_get_op(unsigned int idx) | ||
101 | { | ||
102 | if (idx >= sizeof(ops)/sizeof(ops[0])) return 0; | ||
103 | return ops[idx]; | ||
104 | } | ||
105 | |||
106 | |||
107 | /* | ||
108 | Stuff for Emacs to see, in order to encourage consistent editing style: | ||
109 | *** Local Variables: *** | ||
110 | *** mode: c *** | ||
111 | *** fill-column: 75 *** | ||
112 | *** tab-width: 8 *** | ||
113 | *** c-basic-offset: 8 *** | ||
114 | *** End: *** | ||
115 | */ | ||
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c new file mode 100644 index 000000000000..9f81aff2b38a --- /dev/null +++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c | |||
@@ -0,0 +1,232 @@ | |||
1 | /* | ||
2 | * | ||
3 | * $Id$ | ||
4 | * | ||
5 | * Copyright (C) 2005 Mike Isely <isely@pobox.com> | ||
6 | * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License | ||
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 | |||
23 | #include "pvrusb2-i2c-cmd-v4l2.h" | ||
24 | #include "pvrusb2-hdw-internal.h" | ||
25 | #include "pvrusb2-debug.h" | ||
26 | #include <linux/videodev2.h> | ||
27 | |||
28 | |||
29 | static void set_standard(struct pvr2_hdw *hdw) | ||
30 | { | ||
31 | v4l2_std_id vs; | ||
32 | vs = hdw->std_mask_cur; | ||
33 | pvr2_trace(PVR2_TRACE_CHIPS, | ||
34 | "i2c v4l2 set_standard(0x%llx)",(__u64)vs); | ||
35 | |||
36 | pvr2_i2c_core_cmd(hdw,VIDIOC_S_STD,&vs); | ||
37 | } | ||
38 | |||
39 | |||
40 | static int check_standard(struct pvr2_hdw *hdw) | ||
41 | { | ||
42 | return hdw->std_dirty != 0; | ||
43 | } | ||
44 | |||
45 | |||
46 | const struct pvr2_i2c_op pvr2_i2c_op_v4l2_standard = { | ||
47 | .check = check_standard, | ||
48 | .update = set_standard, | ||
49 | .name = "v4l2_standard", | ||
50 | }; | ||
51 | |||
52 | |||
53 | static void set_bcsh(struct pvr2_hdw *hdw) | ||
54 | { | ||
55 | struct v4l2_control ctrl; | ||
56 | pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_bcsh" | ||
57 | " b=%d c=%d s=%d h=%d", | ||
58 | hdw->brightness_val,hdw->contrast_val, | ||
59 | hdw->saturation_val,hdw->hue_val); | ||
60 | memset(&ctrl,0,sizeof(ctrl)); | ||
61 | ctrl.id = V4L2_CID_BRIGHTNESS; | ||
62 | ctrl.value = hdw->brightness_val; | ||
63 | pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl); | ||
64 | ctrl.id = V4L2_CID_CONTRAST; | ||
65 | ctrl.value = hdw->contrast_val; | ||
66 | pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl); | ||
67 | ctrl.id = V4L2_CID_SATURATION; | ||
68 | ctrl.value = hdw->saturation_val; | ||
69 | pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl); | ||
70 | ctrl.id = V4L2_CID_HUE; | ||
71 | ctrl.value = hdw->hue_val; | ||
72 | pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl); | ||
73 | } | ||
74 | |||
75 | |||
76 | static int check_bcsh(struct pvr2_hdw *hdw) | ||
77 | { | ||
78 | return (hdw->brightness_dirty || | ||
79 | hdw->contrast_dirty || | ||
80 | hdw->saturation_dirty || | ||
81 | hdw->hue_dirty); | ||
82 | } | ||
83 | |||
84 | |||
85 | const struct pvr2_i2c_op pvr2_i2c_op_v4l2_bcsh = { | ||
86 | .check = check_bcsh, | ||
87 | .update = set_bcsh, | ||
88 | .name = "v4l2_bcsh", | ||
89 | }; | ||
90 | |||
91 | |||
92 | static void set_volume(struct pvr2_hdw *hdw) | ||
93 | { | ||
94 | struct v4l2_control ctrl; | ||
95 | pvr2_trace(PVR2_TRACE_CHIPS, | ||
96 | "i2c v4l2 set_volume" | ||
97 | "(vol=%d bal=%d bas=%d treb=%d mute=%d)", | ||
98 | hdw->volume_val, | ||
99 | hdw->balance_val, | ||
100 | hdw->bass_val, | ||
101 | hdw->treble_val, | ||
102 | hdw->mute_val); | ||
103 | memset(&ctrl,0,sizeof(ctrl)); | ||
104 | ctrl.id = V4L2_CID_AUDIO_MUTE; | ||
105 | ctrl.value = hdw->mute_val ? 1 : 0; | ||
106 | pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl); | ||
107 | ctrl.id = V4L2_CID_AUDIO_VOLUME; | ||
108 | ctrl.value = hdw->volume_val; | ||
109 | pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl); | ||
110 | ctrl.id = V4L2_CID_AUDIO_BALANCE; | ||
111 | ctrl.value = hdw->balance_val; | ||
112 | pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl); | ||
113 | ctrl.id = V4L2_CID_AUDIO_BASS; | ||
114 | ctrl.value = hdw->bass_val; | ||
115 | pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl); | ||
116 | ctrl.id = V4L2_CID_AUDIO_TREBLE; | ||
117 | ctrl.value = hdw->treble_val; | ||
118 | pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl); | ||
119 | } | ||
120 | |||
121 | |||
122 | static int check_volume(struct pvr2_hdw *hdw) | ||
123 | { | ||
124 | return (hdw->volume_dirty || | ||
125 | hdw->balance_dirty || | ||
126 | hdw->bass_dirty || | ||
127 | hdw->treble_dirty || | ||
128 | hdw->mute_dirty); | ||
129 | } | ||
130 | |||
131 | |||
132 | const struct pvr2_i2c_op pvr2_i2c_op_v4l2_volume = { | ||
133 | .check = check_volume, | ||
134 | .update = set_volume, | ||
135 | .name = "v4l2_volume", | ||
136 | }; | ||
137 | |||
138 | |||
139 | static void set_frequency(struct pvr2_hdw *hdw) | ||
140 | { | ||
141 | unsigned long fv; | ||
142 | struct v4l2_frequency freq; | ||
143 | fv = hdw->freqVal; | ||
144 | pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_freq(%lu)",fv); | ||
145 | memset(&freq,0,sizeof(freq)); | ||
146 | freq.frequency = fv / 62500; | ||
147 | freq.tuner = 0; | ||
148 | freq.type = V4L2_TUNER_ANALOG_TV; | ||
149 | pvr2_i2c_core_cmd(hdw,VIDIOC_S_FREQUENCY,&freq); | ||
150 | } | ||
151 | |||
152 | |||
153 | static int check_frequency(struct pvr2_hdw *hdw) | ||
154 | { | ||
155 | return hdw->freqDirty != 0; | ||
156 | } | ||
157 | |||
158 | |||
159 | const struct pvr2_i2c_op pvr2_i2c_op_v4l2_frequency = { | ||
160 | .check = check_frequency, | ||
161 | .update = set_frequency, | ||
162 | .name = "v4l2_freq", | ||
163 | }; | ||
164 | |||
165 | |||
166 | static void set_size(struct pvr2_hdw *hdw) | ||
167 | { | ||
168 | struct v4l2_format fmt; | ||
169 | |||
170 | memset(&fmt,0,sizeof(fmt)); | ||
171 | |||
172 | fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
173 | fmt.fmt.pix.width = hdw->res_hor_val; | ||
174 | fmt.fmt.pix.height = hdw->res_ver_val; | ||
175 | |||
176 | pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_size(%dx%d)", | ||
177 | fmt.fmt.pix.width,fmt.fmt.pix.height); | ||
178 | |||
179 | pvr2_i2c_core_cmd(hdw,VIDIOC_S_FMT,&fmt); | ||
180 | } | ||
181 | |||
182 | |||
183 | static int check_size(struct pvr2_hdw *hdw) | ||
184 | { | ||
185 | return (hdw->res_hor_dirty || hdw->res_ver_dirty); | ||
186 | } | ||
187 | |||
188 | |||
189 | const struct pvr2_i2c_op pvr2_i2c_op_v4l2_size = { | ||
190 | .check = check_size, | ||
191 | .update = set_size, | ||
192 | .name = "v4l2_size", | ||
193 | }; | ||
194 | |||
195 | |||
196 | static void do_log(struct pvr2_hdw *hdw) | ||
197 | { | ||
198 | pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 do_log()"); | ||
199 | pvr2_i2c_core_cmd(hdw,VIDIOC_LOG_STATUS,0); | ||
200 | |||
201 | } | ||
202 | |||
203 | |||
204 | static int check_log(struct pvr2_hdw *hdw) | ||
205 | { | ||
206 | return hdw->log_requested != 0; | ||
207 | } | ||
208 | |||
209 | |||
210 | const struct pvr2_i2c_op pvr2_i2c_op_v4l2_log = { | ||
211 | .check = check_log, | ||
212 | .update = do_log, | ||
213 | .name = "v4l2_log", | ||
214 | }; | ||
215 | |||
216 | |||
217 | void pvr2_v4l2_cmd_stream(struct pvr2_i2c_client *cp,int fl) | ||
218 | { | ||
219 | pvr2_i2c_client_cmd(cp, | ||
220 | (fl ? VIDIOC_STREAMON : VIDIOC_STREAMOFF),0); | ||
221 | } | ||
222 | |||
223 | |||
224 | /* | ||
225 | Stuff for Emacs to see, in order to encourage consistent editing style: | ||
226 | *** Local Variables: *** | ||
227 | *** mode: c *** | ||
228 | *** fill-column: 70 *** | ||
229 | *** tab-width: 8 *** | ||
230 | *** c-basic-offset: 8 *** | ||
231 | *** End: *** | ||
232 | */ | ||
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h b/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h new file mode 100644 index 000000000000..ecabddba1ec5 --- /dev/null +++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h | |||
@@ -0,0 +1,47 @@ | |||
1 | /* | ||
2 | * | ||
3 | * $Id$ | ||
4 | * | ||
5 | * Copyright (C) 2005 Mike Isely <isely@pobox.com> | ||
6 | * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License | ||
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 | |||
23 | #ifndef __PVRUSB2_CMD_V4L2_H | ||
24 | #define __PVRUSB2_CMD_V4L2_H | ||
25 | |||
26 | #include "pvrusb2-i2c-core.h" | ||
27 | |||
28 | extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_standard; | ||
29 | extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_bcsh; | ||
30 | extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_volume; | ||
31 | extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_frequency; | ||
32 | extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_size; | ||
33 | extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_log; | ||
34 | |||
35 | void pvr2_v4l2_cmd_stream(struct pvr2_i2c_client *,int); | ||
36 | |||
37 | #endif /* __PVRUSB2_CMD_V4L2_H */ | ||
38 | |||
39 | /* | ||
40 | Stuff for Emacs to see, in order to encourage consistent editing style: | ||
41 | *** Local Variables: *** | ||
42 | *** mode: c *** | ||
43 | *** fill-column: 70 *** | ||
44 | *** tab-width: 8 *** | ||
45 | *** c-basic-offset: 8 *** | ||
46 | *** End: *** | ||
47 | */ | ||
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c new file mode 100644 index 000000000000..c8d0bdee3ff1 --- /dev/null +++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c | |||
@@ -0,0 +1,937 @@ | |||
1 | /* | ||
2 | * | ||
3 | * $Id$ | ||
4 | * | ||
5 | * Copyright (C) 2005 Mike Isely <isely@pobox.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 | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include "pvrusb2-i2c-core.h" | ||
23 | #include "pvrusb2-hdw-internal.h" | ||
24 | #include "pvrusb2-debug.h" | ||
25 | |||
26 | #define trace_i2c(...) pvr2_trace(PVR2_TRACE_I2C,__VA_ARGS__) | ||
27 | |||
28 | /* | ||
29 | |||
30 | This module attempts to implement a compliant I2C adapter for the pvrusb2 | ||
31 | device. By doing this we can then make use of existing functionality in | ||
32 | V4L (e.g. tuner.c) rather than rolling our own. | ||
33 | |||
34 | */ | ||
35 | |||
36 | static unsigned int i2c_scan = 0; | ||
37 | module_param(i2c_scan, int, S_IRUGO|S_IWUSR); | ||
38 | MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time"); | ||
39 | |||
40 | static int pvr2_i2c_write(struct pvr2_hdw *hdw, /* Context */ | ||
41 | u8 i2c_addr, /* I2C address we're talking to */ | ||
42 | u8 *data, /* Data to write */ | ||
43 | u16 length) /* Size of data to write */ | ||
44 | { | ||
45 | /* Return value - default 0 means success */ | ||
46 | int ret; | ||
47 | |||
48 | |||
49 | if (!data) length = 0; | ||
50 | if (length > (sizeof(hdw->cmd_buffer) - 3)) { | ||
51 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, | ||
52 | "Killing an I2C write to %u that is too large" | ||
53 | " (desired=%u limit=%u)", | ||
54 | i2c_addr, | ||
55 | length,(unsigned int)(sizeof(hdw->cmd_buffer) - 3)); | ||
56 | return -ENOTSUPP; | ||
57 | } | ||
58 | |||
59 | LOCK_TAKE(hdw->ctl_lock); | ||
60 | |||
61 | /* Clear the command buffer (likely to be paranoia) */ | ||
62 | memset(hdw->cmd_buffer, 0, sizeof(hdw->cmd_buffer)); | ||
63 | |||
64 | /* Set up command buffer for an I2C write */ | ||
65 | hdw->cmd_buffer[0] = 0x08; /* write prefix */ | ||
66 | hdw->cmd_buffer[1] = i2c_addr; /* i2c addr of chip */ | ||
67 | hdw->cmd_buffer[2] = length; /* length of what follows */ | ||
68 | if (length) memcpy(hdw->cmd_buffer + 3, data, length); | ||
69 | |||
70 | /* Do the operation */ | ||
71 | ret = pvr2_send_request(hdw, | ||
72 | hdw->cmd_buffer, | ||
73 | length + 3, | ||
74 | hdw->cmd_buffer, | ||
75 | 1); | ||
76 | if (!ret) { | ||
77 | if (hdw->cmd_buffer[0] != 8) { | ||
78 | ret = -EIO; | ||
79 | if (hdw->cmd_buffer[0] != 7) { | ||
80 | trace_i2c("unexpected status" | ||
81 | " from i2_write[%d]: %d", | ||
82 | i2c_addr,hdw->cmd_buffer[0]); | ||
83 | } | ||
84 | } | ||
85 | } | ||
86 | |||
87 | LOCK_GIVE(hdw->ctl_lock); | ||
88 | |||
89 | return ret; | ||
90 | } | ||
91 | |||
92 | static int pvr2_i2c_read(struct pvr2_hdw *hdw, /* Context */ | ||
93 | u8 i2c_addr, /* I2C address we're talking to */ | ||
94 | u8 *data, /* Data to write */ | ||
95 | u16 dlen, /* Size of data to write */ | ||
96 | u8 *res, /* Where to put data we read */ | ||
97 | u16 rlen) /* Amount of data to read */ | ||
98 | { | ||
99 | /* Return value - default 0 means success */ | ||
100 | int ret; | ||
101 | |||
102 | |||
103 | if (!data) dlen = 0; | ||
104 | if (dlen > (sizeof(hdw->cmd_buffer) - 4)) { | ||
105 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, | ||
106 | "Killing an I2C read to %u that has wlen too large" | ||
107 | " (desired=%u limit=%u)", | ||
108 | i2c_addr, | ||
109 | dlen,(unsigned int)(sizeof(hdw->cmd_buffer) - 4)); | ||
110 | return -ENOTSUPP; | ||
111 | } | ||
112 | if (res && (rlen > (sizeof(hdw->cmd_buffer) - 1))) { | ||
113 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, | ||
114 | "Killing an I2C read to %u that has rlen too large" | ||
115 | " (desired=%u limit=%u)", | ||
116 | i2c_addr, | ||
117 | rlen,(unsigned int)(sizeof(hdw->cmd_buffer) - 1)); | ||
118 | return -ENOTSUPP; | ||
119 | } | ||
120 | |||
121 | LOCK_TAKE(hdw->ctl_lock); | ||
122 | |||
123 | /* Clear the command buffer (likely to be paranoia) */ | ||
124 | memset(hdw->cmd_buffer, 0, sizeof(hdw->cmd_buffer)); | ||
125 | |||
126 | /* Set up command buffer for an I2C write followed by a read */ | ||
127 | hdw->cmd_buffer[0] = 0x09; /* read prefix */ | ||
128 | hdw->cmd_buffer[1] = dlen; /* arg length */ | ||
129 | hdw->cmd_buffer[2] = rlen; /* answer length. Device will send one | ||
130 | more byte (status). */ | ||
131 | hdw->cmd_buffer[3] = i2c_addr; /* i2c addr of chip */ | ||
132 | if (dlen) memcpy(hdw->cmd_buffer + 4, data, dlen); | ||
133 | |||
134 | /* Do the operation */ | ||
135 | ret = pvr2_send_request(hdw, | ||
136 | hdw->cmd_buffer, | ||
137 | 4 + dlen, | ||
138 | hdw->cmd_buffer, | ||
139 | rlen + 1); | ||
140 | if (!ret) { | ||
141 | if (hdw->cmd_buffer[0] != 8) { | ||
142 | ret = -EIO; | ||
143 | if (hdw->cmd_buffer[0] != 7) { | ||
144 | trace_i2c("unexpected status" | ||
145 | " from i2_read[%d]: %d", | ||
146 | i2c_addr,hdw->cmd_buffer[0]); | ||
147 | } | ||
148 | } | ||
149 | } | ||
150 | |||
151 | /* Copy back the result */ | ||
152 | if (res && rlen) { | ||
153 | if (ret) { | ||
154 | /* Error, just blank out the return buffer */ | ||
155 | memset(res, 0, rlen); | ||
156 | } else { | ||
157 | memcpy(res, hdw->cmd_buffer + 1, rlen); | ||
158 | } | ||
159 | } | ||
160 | |||
161 | LOCK_GIVE(hdw->ctl_lock); | ||
162 | |||
163 | return ret; | ||
164 | } | ||
165 | |||
166 | /* This is the common low level entry point for doing I2C operations to the | ||
167 | hardware. */ | ||
168 | int pvr2_i2c_basic_op(struct pvr2_hdw *hdw, | ||
169 | u8 i2c_addr, | ||
170 | u8 *wdata, | ||
171 | u16 wlen, | ||
172 | u8 *rdata, | ||
173 | u16 rlen) | ||
174 | { | ||
175 | if (!rdata) rlen = 0; | ||
176 | if (!wdata) wlen = 0; | ||
177 | if (rlen || !wlen) { | ||
178 | return pvr2_i2c_read(hdw,i2c_addr,wdata,wlen,rdata,rlen); | ||
179 | } else { | ||
180 | return pvr2_i2c_write(hdw,i2c_addr,wdata,wlen); | ||
181 | } | ||
182 | } | ||
183 | |||
184 | #ifdef CONFIG_VIDEO_PVRUSB2_24XXX | ||
185 | |||
186 | /* This is a special entry point that is entered if an I2C operation is | ||
187 | attempted to a wm8775 chip on model 24xxx hardware. Autodetect of this | ||
188 | part doesn't work, but we know it is really there. So let's look for | ||
189 | the autodetect attempt and just return success if we see that. */ | ||
190 | static int i2c_hack_wm8775(struct pvr2_hdw *hdw, | ||
191 | u8 i2c_addr,u8 *wdata,u16 wlen,u8 *rdata,u16 rlen) | ||
192 | { | ||
193 | if (!(rlen || wlen)) { | ||
194 | // This is a probe attempt. Just let it succeed. | ||
195 | return 0; | ||
196 | } | ||
197 | return pvr2_i2c_basic_op(hdw,i2c_addr,wdata,wlen,rdata,rlen); | ||
198 | } | ||
199 | |||
200 | /* This is a special entry point that is entered if an I2C operation is | ||
201 | attempted to a cx25840 chip on model 24xxx hardware. This chip can | ||
202 | sometimes wedge itself. Worse still, when this happens msp3400 can | ||
203 | falsely detect this part and then the system gets hosed up after msp3400 | ||
204 | gets confused and dies. What we want to do here is try to keep msp3400 | ||
205 | away and also try to notice if the chip is wedged and send a warning to | ||
206 | the system log. */ | ||
207 | static int i2c_hack_cx25840(struct pvr2_hdw *hdw, | ||
208 | u8 i2c_addr,u8 *wdata,u16 wlen,u8 *rdata,u16 rlen) | ||
209 | { | ||
210 | int ret; | ||
211 | unsigned int subaddr; | ||
212 | u8 wbuf[2]; | ||
213 | int state = hdw->i2c_cx25840_hack_state; | ||
214 | |||
215 | if (!(rlen || wlen)) { | ||
216 | // Probe attempt - always just succeed and don't bother the | ||
217 | // hardware (this helps to make the state machine further | ||
218 | // down somewhat easier). | ||
219 | return 0; | ||
220 | } | ||
221 | |||
222 | if (state == 3) { | ||
223 | return pvr2_i2c_basic_op(hdw,i2c_addr,wdata,wlen,rdata,rlen); | ||
224 | } | ||
225 | |||
226 | /* We're looking for the exact pattern where the revision register | ||
227 | is being read. The cx25840 module will always look at the | ||
228 | revision register first. Any other pattern of access therefore | ||
229 | has to be a probe attempt from somebody else so we'll reject it. | ||
230 | Normally we could just let each client just probe the part | ||
231 | anyway, but when the cx25840 is wedged, msp3400 will get a false | ||
232 | positive and that just screws things up... */ | ||
233 | |||
234 | if (wlen == 0) { | ||
235 | switch (state) { | ||
236 | case 1: subaddr = 0x0100; break; | ||
237 | case 2: subaddr = 0x0101; break; | ||
238 | default: goto fail; | ||
239 | } | ||
240 | } else if (wlen == 2) { | ||
241 | subaddr = (wdata[0] << 8) | wdata[1]; | ||
242 | switch (subaddr) { | ||
243 | case 0x0100: state = 1; break; | ||
244 | case 0x0101: state = 2; break; | ||
245 | default: goto fail; | ||
246 | } | ||
247 | } else { | ||
248 | goto fail; | ||
249 | } | ||
250 | if (!rlen) goto success; | ||
251 | state = 0; | ||
252 | if (rlen != 1) goto fail; | ||
253 | |||
254 | /* If we get to here then we have a legitimate read for one of the | ||
255 | two revision bytes, so pass it through. */ | ||
256 | wbuf[0] = subaddr >> 8; | ||
257 | wbuf[1] = subaddr; | ||
258 | ret = pvr2_i2c_basic_op(hdw,i2c_addr,wbuf,2,rdata,rlen); | ||
259 | |||
260 | if ((ret != 0) || (*rdata == 0x04) || (*rdata == 0x0a)) { | ||
261 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, | ||
262 | "WARNING: Detected a wedged cx25840 chip;" | ||
263 | " the device will not work."); | ||
264 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, | ||
265 | "WARNING: Try power cycling the pvrusb2 device."); | ||
266 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, | ||
267 | "WARNING: Disabling further access to the device" | ||
268 | " to prevent other foul-ups."); | ||
269 | // This blocks all further communication with the part. | ||
270 | hdw->i2c_func[0x44] = 0; | ||
271 | pvr2_hdw_render_useless(hdw); | ||
272 | goto fail; | ||
273 | } | ||
274 | |||
275 | /* Success! */ | ||
276 | pvr2_trace(PVR2_TRACE_CHIPS,"cx25840 appears to be OK."); | ||
277 | state = 3; | ||
278 | |||
279 | success: | ||
280 | hdw->i2c_cx25840_hack_state = state; | ||
281 | return 0; | ||
282 | |||
283 | fail: | ||
284 | hdw->i2c_cx25840_hack_state = state; | ||
285 | return -EIO; | ||
286 | } | ||
287 | |||
288 | #endif /* CONFIG_VIDEO_PVRUSB2_24XXX */ | ||
289 | |||
290 | /* This is a very, very limited I2C adapter implementation. We can only | ||
291 | support what we actually know will work on the device... */ | ||
292 | static int pvr2_i2c_xfer(struct i2c_adapter *i2c_adap, | ||
293 | struct i2c_msg msgs[], | ||
294 | int num) | ||
295 | { | ||
296 | int ret = -ENOTSUPP; | ||
297 | pvr2_i2c_func funcp = 0; | ||
298 | struct pvr2_hdw *hdw = (struct pvr2_hdw *)(i2c_adap->algo_data); | ||
299 | |||
300 | if (!num) { | ||
301 | ret = -EINVAL; | ||
302 | goto done; | ||
303 | } | ||
304 | if ((msgs[0].flags & I2C_M_NOSTART)) { | ||
305 | trace_i2c("i2c refusing I2C_M_NOSTART"); | ||
306 | goto done; | ||
307 | } | ||
308 | if (msgs[0].addr < PVR2_I2C_FUNC_CNT) { | ||
309 | funcp = hdw->i2c_func[msgs[0].addr]; | ||
310 | } | ||
311 | if (!funcp) { | ||
312 | ret = -EIO; | ||
313 | goto done; | ||
314 | } | ||
315 | |||
316 | if (num == 1) { | ||
317 | if (msgs[0].flags & I2C_M_RD) { | ||
318 | /* Simple read */ | ||
319 | u16 tcnt,bcnt,offs; | ||
320 | if (!msgs[0].len) { | ||
321 | /* Length == 0 read. This is a probe. */ | ||
322 | if (funcp(hdw,msgs[0].addr,0,0,0,0)) { | ||
323 | ret = -EIO; | ||
324 | goto done; | ||
325 | } | ||
326 | ret = 1; | ||
327 | goto done; | ||
328 | } | ||
329 | /* If the read is short enough we'll do the whole | ||
330 | thing atomically. Otherwise we have no choice | ||
331 | but to break apart the reads. */ | ||
332 | tcnt = msgs[0].len; | ||
333 | offs = 0; | ||
334 | while (tcnt) { | ||
335 | bcnt = tcnt; | ||
336 | if (bcnt > sizeof(hdw->cmd_buffer)-1) { | ||
337 | bcnt = sizeof(hdw->cmd_buffer)-1; | ||
338 | } | ||
339 | if (funcp(hdw,msgs[0].addr,0,0, | ||
340 | msgs[0].buf+offs,bcnt)) { | ||
341 | ret = -EIO; | ||
342 | goto done; | ||
343 | } | ||
344 | offs += bcnt; | ||
345 | tcnt -= bcnt; | ||
346 | } | ||
347 | ret = 1; | ||
348 | goto done; | ||
349 | } else { | ||
350 | /* Simple write */ | ||
351 | ret = 1; | ||
352 | if (funcp(hdw,msgs[0].addr, | ||
353 | msgs[0].buf,msgs[0].len,0,0)) { | ||
354 | ret = -EIO; | ||
355 | } | ||
356 | goto done; | ||
357 | } | ||
358 | } else if (num == 2) { | ||
359 | if (msgs[0].addr != msgs[1].addr) { | ||
360 | trace_i2c("i2c refusing 2 phase transfer with" | ||
361 | " conflicting target addresses"); | ||
362 | ret = -ENOTSUPP; | ||
363 | goto done; | ||
364 | } | ||
365 | if ((!((msgs[0].flags & I2C_M_RD))) && | ||
366 | (msgs[1].flags & I2C_M_RD)) { | ||
367 | u16 tcnt,bcnt,wcnt,offs; | ||
368 | /* Write followed by atomic read. If the read | ||
369 | portion is short enough we'll do the whole thing | ||
370 | atomically. Otherwise we have no choice but to | ||
371 | break apart the reads. */ | ||
372 | tcnt = msgs[1].len; | ||
373 | wcnt = msgs[0].len; | ||
374 | offs = 0; | ||
375 | while (tcnt || wcnt) { | ||
376 | bcnt = tcnt; | ||
377 | if (bcnt > sizeof(hdw->cmd_buffer)-1) { | ||
378 | bcnt = sizeof(hdw->cmd_buffer)-1; | ||
379 | } | ||
380 | if (funcp(hdw,msgs[0].addr, | ||
381 | msgs[0].buf,wcnt, | ||
382 | msgs[1].buf+offs,bcnt)) { | ||
383 | ret = -EIO; | ||
384 | goto done; | ||
385 | } | ||
386 | offs += bcnt; | ||
387 | tcnt -= bcnt; | ||
388 | wcnt = 0; | ||
389 | } | ||
390 | ret = 2; | ||
391 | goto done; | ||
392 | } else { | ||
393 | trace_i2c("i2c refusing complex transfer" | ||
394 | " read0=%d read1=%d", | ||
395 | (msgs[0].flags & I2C_M_RD), | ||
396 | (msgs[1].flags & I2C_M_RD)); | ||
397 | } | ||
398 | } else { | ||
399 | trace_i2c("i2c refusing %d phase transfer",num); | ||
400 | } | ||
401 | |||
402 | done: | ||
403 | if (pvrusb2_debug & PVR2_TRACE_I2C_TRAF) { | ||
404 | unsigned int idx,offs,cnt; | ||
405 | for (idx = 0; idx < num; idx++) { | ||
406 | cnt = msgs[idx].len; | ||
407 | printk(KERN_INFO | ||
408 | "pvrusb2 i2c xfer %u/%u:" | ||
409 | " addr=0x%x len=%d %s%s", | ||
410 | idx+1,num, | ||
411 | msgs[idx].addr, | ||
412 | cnt, | ||
413 | (msgs[idx].flags & I2C_M_RD ? | ||
414 | "read" : "write"), | ||
415 | (msgs[idx].flags & I2C_M_NOSTART ? | ||
416 | " nostart" : "")); | ||
417 | if ((ret > 0) || !(msgs[idx].flags & I2C_M_RD)) { | ||
418 | if (cnt > 8) cnt = 8; | ||
419 | printk(" ["); | ||
420 | for (offs = 0; offs < (cnt>8?8:cnt); offs++) { | ||
421 | if (offs) printk(" "); | ||
422 | printk("%02x",msgs[idx].buf[offs]); | ||
423 | } | ||
424 | if (offs < cnt) printk(" ..."); | ||
425 | printk("]"); | ||
426 | } | ||
427 | if (idx+1 == num) { | ||
428 | printk(" result=%d",ret); | ||
429 | } | ||
430 | printk("\n"); | ||
431 | } | ||
432 | if (!num) { | ||
433 | printk(KERN_INFO | ||
434 | "pvrusb2 i2c xfer null transfer result=%d\n", | ||
435 | ret); | ||
436 | } | ||
437 | } | ||
438 | return ret; | ||
439 | } | ||
440 | |||
441 | static int pvr2_i2c_control(struct i2c_adapter *adapter, | ||
442 | unsigned int cmd, unsigned long arg) | ||
443 | { | ||
444 | return 0; | ||
445 | } | ||
446 | |||
447 | static u32 pvr2_i2c_functionality(struct i2c_adapter *adap) | ||
448 | { | ||
449 | return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C | I2C_FUNC_SMBUS_BYTE_DATA; | ||
450 | } | ||
451 | |||
452 | static int pvr2_i2c_core_singleton(struct i2c_client *cp, | ||
453 | unsigned int cmd,void *arg) | ||
454 | { | ||
455 | int stat; | ||
456 | if (!cp) return -EINVAL; | ||
457 | if (!(cp->driver)) return -EINVAL; | ||
458 | if (!(cp->driver->command)) return -EINVAL; | ||
459 | if (!try_module_get(cp->driver->driver.owner)) return -EAGAIN; | ||
460 | stat = cp->driver->command(cp,cmd,arg); | ||
461 | module_put(cp->driver->driver.owner); | ||
462 | return stat; | ||
463 | } | ||
464 | |||
465 | int pvr2_i2c_client_cmd(struct pvr2_i2c_client *cp,unsigned int cmd,void *arg) | ||
466 | { | ||
467 | int stat; | ||
468 | if (pvrusb2_debug & PVR2_TRACE_I2C_CMD) { | ||
469 | char buf[100]; | ||
470 | unsigned int cnt; | ||
471 | cnt = pvr2_i2c_client_describe(cp,PVR2_I2C_DETAIL_DEBUG, | ||
472 | buf,sizeof(buf)); | ||
473 | pvr2_trace(PVR2_TRACE_I2C_CMD, | ||
474 | "i2c COMMAND (code=%u 0x%x) to %.*s", | ||
475 | cmd,cmd,cnt,buf); | ||
476 | } | ||
477 | stat = pvr2_i2c_core_singleton(cp->client,cmd,arg); | ||
478 | if (pvrusb2_debug & PVR2_TRACE_I2C_CMD) { | ||
479 | char buf[100]; | ||
480 | unsigned int cnt; | ||
481 | cnt = pvr2_i2c_client_describe(cp,PVR2_I2C_DETAIL_DEBUG, | ||
482 | buf,sizeof(buf)); | ||
483 | pvr2_trace(PVR2_TRACE_I2C_CMD, | ||
484 | "i2c COMMAND to %.*s (ret=%d)",cnt,buf,stat); | ||
485 | } | ||
486 | return stat; | ||
487 | } | ||
488 | |||
489 | int pvr2_i2c_core_cmd(struct pvr2_hdw *hdw,unsigned int cmd,void *arg) | ||
490 | { | ||
491 | struct list_head *item,*nc; | ||
492 | struct pvr2_i2c_client *cp; | ||
493 | int stat = -EINVAL; | ||
494 | |||
495 | if (!hdw) return stat; | ||
496 | |||
497 | mutex_lock(&hdw->i2c_list_lock); | ||
498 | list_for_each_safe(item,nc,&hdw->i2c_clients) { | ||
499 | cp = list_entry(item,struct pvr2_i2c_client,list); | ||
500 | if (!cp->recv_enable) continue; | ||
501 | mutex_unlock(&hdw->i2c_list_lock); | ||
502 | stat = pvr2_i2c_client_cmd(cp,cmd,arg); | ||
503 | mutex_lock(&hdw->i2c_list_lock); | ||
504 | } | ||
505 | mutex_unlock(&hdw->i2c_list_lock); | ||
506 | return stat; | ||
507 | } | ||
508 | |||
509 | |||
510 | static int handler_check(struct pvr2_i2c_client *cp) | ||
511 | { | ||
512 | struct pvr2_i2c_handler *hp = cp->handler; | ||
513 | if (!hp) return 0; | ||
514 | if (!hp->func_table->check) return 0; | ||
515 | return hp->func_table->check(hp->func_data) != 0; | ||
516 | } | ||
517 | |||
518 | #define BUFSIZE 500 | ||
519 | |||
520 | void pvr2_i2c_core_sync(struct pvr2_hdw *hdw) | ||
521 | { | ||
522 | unsigned long msk; | ||
523 | unsigned int idx; | ||
524 | struct list_head *item,*nc; | ||
525 | struct pvr2_i2c_client *cp; | ||
526 | |||
527 | if (!hdw->i2c_linked) return; | ||
528 | if (!(hdw->i2c_pend_types & PVR2_I2C_PEND_ALL)) { | ||
529 | return; | ||
530 | } | ||
531 | mutex_lock(&hdw->i2c_list_lock); do { | ||
532 | pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: core_sync BEGIN"); | ||
533 | if (hdw->i2c_pend_types & PVR2_I2C_PEND_DETECT) { | ||
534 | /* One or more I2C clients have attached since we | ||
535 | last synced. So scan the list and identify the | ||
536 | new clients. */ | ||
537 | char *buf; | ||
538 | unsigned int cnt; | ||
539 | unsigned long amask = 0; | ||
540 | buf = kmalloc(BUFSIZE,GFP_KERNEL); | ||
541 | pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_DETECT"); | ||
542 | hdw->i2c_pend_types &= ~PVR2_I2C_PEND_DETECT; | ||
543 | list_for_each(item,&hdw->i2c_clients) { | ||
544 | cp = list_entry(item,struct pvr2_i2c_client, | ||
545 | list); | ||
546 | if (!cp->detected_flag) { | ||
547 | cp->ctl_mask = 0; | ||
548 | pvr2_i2c_probe(hdw,cp); | ||
549 | cp->detected_flag = !0; | ||
550 | msk = cp->ctl_mask; | ||
551 | cnt = 0; | ||
552 | if (buf) { | ||
553 | cnt = pvr2_i2c_client_describe( | ||
554 | cp, | ||
555 | PVR2_I2C_DETAIL_ALL, | ||
556 | buf,BUFSIZE); | ||
557 | } | ||
558 | trace_i2c("Probed: %.*s",cnt,buf); | ||
559 | if (handler_check(cp)) { | ||
560 | hdw->i2c_pend_types |= | ||
561 | PVR2_I2C_PEND_CLIENT; | ||
562 | } | ||
563 | cp->pend_mask = msk; | ||
564 | hdw->i2c_pend_mask |= msk; | ||
565 | hdw->i2c_pend_types |= | ||
566 | PVR2_I2C_PEND_REFRESH; | ||
567 | } | ||
568 | amask |= cp->ctl_mask; | ||
569 | } | ||
570 | hdw->i2c_active_mask = amask; | ||
571 | if (buf) kfree(buf); | ||
572 | } | ||
573 | if (hdw->i2c_pend_types & PVR2_I2C_PEND_STALE) { | ||
574 | /* Need to do one or more global updates. Arrange | ||
575 | for this to happen. */ | ||
576 | unsigned long m2; | ||
577 | pvr2_trace(PVR2_TRACE_I2C_CORE, | ||
578 | "i2c: PEND_STALE (0x%lx)", | ||
579 | hdw->i2c_stale_mask); | ||
580 | hdw->i2c_pend_types &= ~PVR2_I2C_PEND_STALE; | ||
581 | list_for_each(item,&hdw->i2c_clients) { | ||
582 | cp = list_entry(item,struct pvr2_i2c_client, | ||
583 | list); | ||
584 | m2 = hdw->i2c_stale_mask; | ||
585 | m2 &= cp->ctl_mask; | ||
586 | m2 &= ~cp->pend_mask; | ||
587 | if (m2) { | ||
588 | pvr2_trace(PVR2_TRACE_I2C_CORE, | ||
589 | "i2c: cp=%p setting 0x%lx", | ||
590 | cp,m2); | ||
591 | cp->pend_mask |= m2; | ||
592 | } | ||
593 | } | ||
594 | hdw->i2c_pend_mask |= hdw->i2c_stale_mask; | ||
595 | hdw->i2c_stale_mask = 0; | ||
596 | hdw->i2c_pend_types |= PVR2_I2C_PEND_REFRESH; | ||
597 | } | ||
598 | if (hdw->i2c_pend_types & PVR2_I2C_PEND_CLIENT) { | ||
599 | /* One or more client handlers are asking for an | ||
600 | update. Run through the list of known clients | ||
601 | and update each one. */ | ||
602 | pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_CLIENT"); | ||
603 | hdw->i2c_pend_types &= ~PVR2_I2C_PEND_CLIENT; | ||
604 | list_for_each_safe(item,nc,&hdw->i2c_clients) { | ||
605 | cp = list_entry(item,struct pvr2_i2c_client, | ||
606 | list); | ||
607 | if (!cp->handler) continue; | ||
608 | if (!cp->handler->func_table->update) continue; | ||
609 | pvr2_trace(PVR2_TRACE_I2C_CORE, | ||
610 | "i2c: cp=%p update",cp); | ||
611 | mutex_unlock(&hdw->i2c_list_lock); | ||
612 | cp->handler->func_table->update( | ||
613 | cp->handler->func_data); | ||
614 | mutex_lock(&hdw->i2c_list_lock); | ||
615 | /* If client's update function set some | ||
616 | additional pending bits, account for that | ||
617 | here. */ | ||
618 | if (cp->pend_mask & ~hdw->i2c_pend_mask) { | ||
619 | hdw->i2c_pend_mask |= cp->pend_mask; | ||
620 | hdw->i2c_pend_types |= | ||
621 | PVR2_I2C_PEND_REFRESH; | ||
622 | } | ||
623 | } | ||
624 | } | ||
625 | if (hdw->i2c_pend_types & PVR2_I2C_PEND_REFRESH) { | ||
626 | const struct pvr2_i2c_op *opf; | ||
627 | unsigned long pm; | ||
628 | /* Some actual updates are pending. Walk through | ||
629 | each update type and perform it. */ | ||
630 | pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_REFRESH" | ||
631 | " (0x%lx)",hdw->i2c_pend_mask); | ||
632 | hdw->i2c_pend_types &= ~PVR2_I2C_PEND_REFRESH; | ||
633 | pm = hdw->i2c_pend_mask; | ||
634 | hdw->i2c_pend_mask = 0; | ||
635 | for (idx = 0, msk = 1; pm; idx++, msk <<= 1) { | ||
636 | if (!(pm & msk)) continue; | ||
637 | pm &= ~msk; | ||
638 | list_for_each(item,&hdw->i2c_clients) { | ||
639 | cp = list_entry(item, | ||
640 | struct pvr2_i2c_client, | ||
641 | list); | ||
642 | if (cp->pend_mask & msk) { | ||
643 | cp->pend_mask &= ~msk; | ||
644 | cp->recv_enable = !0; | ||
645 | } else { | ||
646 | cp->recv_enable = 0; | ||
647 | } | ||
648 | } | ||
649 | opf = pvr2_i2c_get_op(idx); | ||
650 | if (!opf) continue; | ||
651 | mutex_unlock(&hdw->i2c_list_lock); | ||
652 | opf->update(hdw); | ||
653 | mutex_lock(&hdw->i2c_list_lock); | ||
654 | } | ||
655 | } | ||
656 | pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: core_sync END"); | ||
657 | } while (0); mutex_unlock(&hdw->i2c_list_lock); | ||
658 | } | ||
659 | |||
660 | int pvr2_i2c_core_check_stale(struct pvr2_hdw *hdw) | ||
661 | { | ||
662 | unsigned long msk,sm,pm; | ||
663 | unsigned int idx; | ||
664 | const struct pvr2_i2c_op *opf; | ||
665 | struct list_head *item; | ||
666 | struct pvr2_i2c_client *cp; | ||
667 | unsigned int pt = 0; | ||
668 | |||
669 | pvr2_trace(PVR2_TRACE_I2C_CORE,"pvr2_i2c_core_check_stale BEGIN"); | ||
670 | |||
671 | pm = hdw->i2c_active_mask; | ||
672 | sm = 0; | ||
673 | for (idx = 0, msk = 1; pm; idx++, msk <<= 1) { | ||
674 | if (!(msk & pm)) continue; | ||
675 | pm &= ~msk; | ||
676 | opf = pvr2_i2c_get_op(idx); | ||
677 | if (!opf) continue; | ||
678 | if (opf->check(hdw)) { | ||
679 | sm |= msk; | ||
680 | } | ||
681 | } | ||
682 | if (sm) pt |= PVR2_I2C_PEND_STALE; | ||
683 | |||
684 | list_for_each(item,&hdw->i2c_clients) { | ||
685 | cp = list_entry(item,struct pvr2_i2c_client,list); | ||
686 | if (!handler_check(cp)) continue; | ||
687 | pt |= PVR2_I2C_PEND_CLIENT; | ||
688 | } | ||
689 | |||
690 | if (pt) { | ||
691 | mutex_lock(&hdw->i2c_list_lock); do { | ||
692 | hdw->i2c_pend_types |= pt; | ||
693 | hdw->i2c_stale_mask |= sm; | ||
694 | hdw->i2c_pend_mask |= hdw->i2c_stale_mask; | ||
695 | } while (0); mutex_unlock(&hdw->i2c_list_lock); | ||
696 | } | ||
697 | |||
698 | pvr2_trace(PVR2_TRACE_I2C_CORE, | ||
699 | "i2c: types=0x%x stale=0x%lx pend=0x%lx", | ||
700 | hdw->i2c_pend_types, | ||
701 | hdw->i2c_stale_mask, | ||
702 | hdw->i2c_pend_mask); | ||
703 | pvr2_trace(PVR2_TRACE_I2C_CORE,"pvr2_i2c_core_check_stale END"); | ||
704 | |||
705 | return (hdw->i2c_pend_types & PVR2_I2C_PEND_ALL) != 0; | ||
706 | } | ||
707 | |||
708 | unsigned int pvr2_i2c_client_describe(struct pvr2_i2c_client *cp, | ||
709 | unsigned int detail, | ||
710 | char *buf,unsigned int maxlen) | ||
711 | { | ||
712 | unsigned int ccnt,bcnt; | ||
713 | int spcfl = 0; | ||
714 | const struct pvr2_i2c_op *opf; | ||
715 | |||
716 | ccnt = 0; | ||
717 | if (detail & PVR2_I2C_DETAIL_DEBUG) { | ||
718 | bcnt = scnprintf(buf,maxlen, | ||
719 | "ctxt=%p ctl_mask=0x%lx", | ||
720 | cp,cp->ctl_mask); | ||
721 | ccnt += bcnt; buf += bcnt; maxlen -= bcnt; | ||
722 | spcfl = !0; | ||
723 | } | ||
724 | bcnt = scnprintf(buf,maxlen, | ||
725 | "%s%s @ 0x%x", | ||
726 | (spcfl ? " " : ""), | ||
727 | cp->client->name, | ||
728 | cp->client->addr); | ||
729 | ccnt += bcnt; buf += bcnt; maxlen -= bcnt; | ||
730 | if ((detail & PVR2_I2C_DETAIL_HANDLER) && | ||
731 | cp->handler && cp->handler->func_table->describe) { | ||
732 | bcnt = scnprintf(buf,maxlen," ("); | ||
733 | ccnt += bcnt; buf += bcnt; maxlen -= bcnt; | ||
734 | bcnt = cp->handler->func_table->describe( | ||
735 | cp->handler->func_data,buf,maxlen); | ||
736 | ccnt += bcnt; buf += bcnt; maxlen -= bcnt; | ||
737 | bcnt = scnprintf(buf,maxlen,")"); | ||
738 | ccnt += bcnt; buf += bcnt; maxlen -= bcnt; | ||
739 | } | ||
740 | if ((detail & PVR2_I2C_DETAIL_CTLMASK) && cp->ctl_mask) { | ||
741 | unsigned int idx; | ||
742 | unsigned long msk,sm; | ||
743 | int spcfl; | ||
744 | bcnt = scnprintf(buf,maxlen," ["); | ||
745 | ccnt += bcnt; buf += bcnt; maxlen -= bcnt; | ||
746 | sm = 0; | ||
747 | spcfl = 0; | ||
748 | for (idx = 0, msk = 1; msk; idx++, msk <<= 1) { | ||
749 | if (!(cp->ctl_mask & msk)) continue; | ||
750 | opf = pvr2_i2c_get_op(idx); | ||
751 | if (opf) { | ||
752 | bcnt = scnprintf(buf,maxlen,"%s%s", | ||
753 | spcfl ? " " : "", | ||
754 | opf->name); | ||
755 | ccnt += bcnt; buf += bcnt; maxlen -= bcnt; | ||
756 | spcfl = !0; | ||
757 | } else { | ||
758 | sm |= msk; | ||
759 | } | ||
760 | } | ||
761 | if (sm) { | ||
762 | bcnt = scnprintf(buf,maxlen,"%s%lx", | ||
763 | idx != 0 ? " " : "",sm); | ||
764 | ccnt += bcnt; buf += bcnt; maxlen -= bcnt; | ||
765 | } | ||
766 | bcnt = scnprintf(buf,maxlen,"]"); | ||
767 | ccnt += bcnt; buf += bcnt; maxlen -= bcnt; | ||
768 | } | ||
769 | return ccnt; | ||
770 | } | ||
771 | |||
772 | unsigned int pvr2_i2c_report(struct pvr2_hdw *hdw, | ||
773 | char *buf,unsigned int maxlen) | ||
774 | { | ||
775 | unsigned int ccnt,bcnt; | ||
776 | struct list_head *item; | ||
777 | struct pvr2_i2c_client *cp; | ||
778 | ccnt = 0; | ||
779 | mutex_lock(&hdw->i2c_list_lock); do { | ||
780 | list_for_each(item,&hdw->i2c_clients) { | ||
781 | cp = list_entry(item,struct pvr2_i2c_client,list); | ||
782 | bcnt = pvr2_i2c_client_describe( | ||
783 | cp, | ||
784 | (PVR2_I2C_DETAIL_HANDLER| | ||
785 | PVR2_I2C_DETAIL_CTLMASK), | ||
786 | buf,maxlen); | ||
787 | ccnt += bcnt; buf += bcnt; maxlen -= bcnt; | ||
788 | bcnt = scnprintf(buf,maxlen,"\n"); | ||
789 | ccnt += bcnt; buf += bcnt; maxlen -= bcnt; | ||
790 | } | ||
791 | } while (0); mutex_unlock(&hdw->i2c_list_lock); | ||
792 | return ccnt; | ||
793 | } | ||
794 | |||
795 | static int pvr2_i2c_attach_inform(struct i2c_client *client) | ||
796 | { | ||
797 | struct pvr2_hdw *hdw = (struct pvr2_hdw *)(client->adapter->algo_data); | ||
798 | struct pvr2_i2c_client *cp; | ||
799 | int fl = !(hdw->i2c_pend_types & PVR2_I2C_PEND_ALL); | ||
800 | cp = kmalloc(sizeof(*cp),GFP_KERNEL); | ||
801 | trace_i2c("i2c_attach [client=%s @ 0x%x ctxt=%p]", | ||
802 | client->name, | ||
803 | client->addr,cp); | ||
804 | if (!cp) return -ENOMEM; | ||
805 | memset(cp,0,sizeof(*cp)); | ||
806 | INIT_LIST_HEAD(&cp->list); | ||
807 | cp->client = client; | ||
808 | mutex_lock(&hdw->i2c_list_lock); do { | ||
809 | list_add_tail(&cp->list,&hdw->i2c_clients); | ||
810 | hdw->i2c_pend_types |= PVR2_I2C_PEND_DETECT; | ||
811 | } while (0); mutex_unlock(&hdw->i2c_list_lock); | ||
812 | if (fl) pvr2_hdw_poll_trigger_unlocked(hdw); | ||
813 | return 0; | ||
814 | } | ||
815 | |||
816 | static int pvr2_i2c_detach_inform(struct i2c_client *client) | ||
817 | { | ||
818 | struct pvr2_hdw *hdw = (struct pvr2_hdw *)(client->adapter->algo_data); | ||
819 | struct pvr2_i2c_client *cp; | ||
820 | struct list_head *item,*nc; | ||
821 | unsigned long amask = 0; | ||
822 | int foundfl = 0; | ||
823 | mutex_lock(&hdw->i2c_list_lock); do { | ||
824 | list_for_each_safe(item,nc,&hdw->i2c_clients) { | ||
825 | cp = list_entry(item,struct pvr2_i2c_client,list); | ||
826 | if (cp->client == client) { | ||
827 | trace_i2c("pvr2_i2c_detach" | ||
828 | " [client=%s @ 0x%x ctxt=%p]", | ||
829 | client->name, | ||
830 | client->addr,cp); | ||
831 | if (cp->handler && | ||
832 | cp->handler->func_table->detach) { | ||
833 | cp->handler->func_table->detach( | ||
834 | cp->handler->func_data); | ||
835 | } | ||
836 | list_del(&cp->list); | ||
837 | kfree(cp); | ||
838 | foundfl = !0; | ||
839 | continue; | ||
840 | } | ||
841 | amask |= cp->ctl_mask; | ||
842 | } | ||
843 | hdw->i2c_active_mask = amask; | ||
844 | } while (0); mutex_unlock(&hdw->i2c_list_lock); | ||
845 | if (!foundfl) { | ||
846 | trace_i2c("pvr2_i2c_detach [client=%s @ 0x%x ctxt=<unknown>]", | ||
847 | client->name, | ||
848 | client->addr); | ||
849 | } | ||
850 | return 0; | ||
851 | } | ||
852 | |||
853 | static struct i2c_algorithm pvr2_i2c_algo_template = { | ||
854 | .master_xfer = pvr2_i2c_xfer, | ||
855 | .algo_control = pvr2_i2c_control, | ||
856 | .functionality = pvr2_i2c_functionality, | ||
857 | }; | ||
858 | |||
859 | static struct i2c_adapter pvr2_i2c_adap_template = { | ||
860 | .owner = THIS_MODULE, | ||
861 | .class = I2C_CLASS_TV_ANALOG, | ||
862 | .id = I2C_HW_B_BT848, | ||
863 | .client_register = pvr2_i2c_attach_inform, | ||
864 | .client_unregister = pvr2_i2c_detach_inform, | ||
865 | }; | ||
866 | |||
867 | static void do_i2c_scan(struct pvr2_hdw *hdw) | ||
868 | { | ||
869 | struct i2c_msg msg[1]; | ||
870 | int i,rc; | ||
871 | msg[0].addr = 0; | ||
872 | msg[0].flags = I2C_M_RD; | ||
873 | msg[0].len = 0; | ||
874 | msg[0].buf = 0; | ||
875 | printk("%s: i2c scan beginning\n",hdw->name); | ||
876 | for (i = 0; i < 128; i++) { | ||
877 | msg[0].addr = i; | ||
878 | rc = i2c_transfer(&hdw->i2c_adap,msg, | ||
879 | sizeof(msg)/sizeof(msg[0])); | ||
880 | if (rc != 1) continue; | ||
881 | printk("%s: i2c scan: found device @ 0x%x\n",hdw->name,i); | ||
882 | } | ||
883 | printk("%s: i2c scan done.\n",hdw->name); | ||
884 | } | ||
885 | |||
886 | void pvr2_i2c_core_init(struct pvr2_hdw *hdw) | ||
887 | { | ||
888 | unsigned int idx; | ||
889 | |||
890 | // The default action for all possible I2C addresses is just to do | ||
891 | // the transfer normally. | ||
892 | for (idx = 0; idx < PVR2_I2C_FUNC_CNT; idx++) { | ||
893 | hdw->i2c_func[idx] = pvr2_i2c_basic_op; | ||
894 | } | ||
895 | |||
896 | #ifdef CONFIG_VIDEO_PVRUSB2_24XXX | ||
897 | // If however we're dealing with new hardware, insert some hacks in | ||
898 | // the I2C transfer stack to let things work better. | ||
899 | if (hdw->hdw_type == PVR2_HDW_TYPE_24XXX) { | ||
900 | hdw->i2c_func[0x1b] = i2c_hack_wm8775; | ||
901 | hdw->i2c_func[0x44] = i2c_hack_cx25840; | ||
902 | } | ||
903 | #endif | ||
904 | |||
905 | // Configure the adapter and set up everything else related to it. | ||
906 | memcpy(&hdw->i2c_adap,&pvr2_i2c_adap_template,sizeof(hdw->i2c_adap)); | ||
907 | memcpy(&hdw->i2c_algo,&pvr2_i2c_algo_template,sizeof(hdw->i2c_algo)); | ||
908 | strlcpy(hdw->i2c_adap.name,hdw->name,sizeof(hdw->i2c_adap.name)); | ||
909 | hdw->i2c_adap.algo = &hdw->i2c_algo; | ||
910 | hdw->i2c_adap.algo_data = hdw; | ||
911 | hdw->i2c_pend_mask = 0; | ||
912 | hdw->i2c_stale_mask = 0; | ||
913 | hdw->i2c_active_mask = 0; | ||
914 | INIT_LIST_HEAD(&hdw->i2c_clients); | ||
915 | mutex_init(&hdw->i2c_list_lock); | ||
916 | hdw->i2c_linked = !0; | ||
917 | i2c_add_adapter(&hdw->i2c_adap); | ||
918 | if (i2c_scan) do_i2c_scan(hdw); | ||
919 | } | ||
920 | |||
921 | void pvr2_i2c_core_done(struct pvr2_hdw *hdw) | ||
922 | { | ||
923 | if (hdw->i2c_linked) { | ||
924 | i2c_del_adapter(&hdw->i2c_adap); | ||
925 | hdw->i2c_linked = 0; | ||
926 | } | ||
927 | } | ||
928 | |||
929 | /* | ||
930 | Stuff for Emacs to see, in order to encourage consistent editing style: | ||
931 | *** Local Variables: *** | ||
932 | *** mode: c *** | ||
933 | *** fill-column: 75 *** | ||
934 | *** tab-width: 8 *** | ||
935 | *** c-basic-offset: 8 *** | ||
936 | *** End: *** | ||
937 | */ | ||
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h new file mode 100644 index 000000000000..e8af5b0ed3ce --- /dev/null +++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h | |||
@@ -0,0 +1,96 @@ | |||
1 | /* | ||
2 | * | ||
3 | * $Id$ | ||
4 | * | ||
5 | * Copyright (C) 2005 Mike Isely <isely@pobox.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 | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | * | ||
20 | */ | ||
21 | #ifndef __PVRUSB2_I2C_CORE_H | ||
22 | #define __PVRUSB2_I2C_CORE_H | ||
23 | |||
24 | #include <linux/list.h> | ||
25 | #include <linux/i2c.h> | ||
26 | |||
27 | struct pvr2_hdw; | ||
28 | struct pvr2_i2c_client; | ||
29 | struct pvr2_i2c_handler; | ||
30 | struct pvr2_i2c_handler_functions; | ||
31 | struct pvr2_i2c_op; | ||
32 | struct pvr2_i2c_op_functions; | ||
33 | |||
34 | struct pvr2_i2c_client { | ||
35 | struct i2c_client *client; | ||
36 | struct pvr2_i2c_handler *handler; | ||
37 | struct list_head list; | ||
38 | int detected_flag; | ||
39 | int recv_enable; | ||
40 | unsigned long pend_mask; | ||
41 | unsigned long ctl_mask; | ||
42 | }; | ||
43 | |||
44 | struct pvr2_i2c_handler { | ||
45 | void *func_data; | ||
46 | const struct pvr2_i2c_handler_functions *func_table; | ||
47 | }; | ||
48 | |||
49 | struct pvr2_i2c_handler_functions { | ||
50 | void (*detach)(void *); | ||
51 | int (*check)(void *); | ||
52 | void (*update)(void *); | ||
53 | unsigned int (*describe)(void *,char *,unsigned int); | ||
54 | }; | ||
55 | |||
56 | struct pvr2_i2c_op { | ||
57 | int (*check)(struct pvr2_hdw *); | ||
58 | void (*update)(struct pvr2_hdw *); | ||
59 | const char *name; | ||
60 | }; | ||
61 | |||
62 | void pvr2_i2c_core_init(struct pvr2_hdw *); | ||
63 | void pvr2_i2c_core_done(struct pvr2_hdw *); | ||
64 | |||
65 | int pvr2_i2c_client_cmd(struct pvr2_i2c_client *,unsigned int cmd,void *arg); | ||
66 | int pvr2_i2c_core_cmd(struct pvr2_hdw *,unsigned int cmd,void *arg); | ||
67 | |||
68 | int pvr2_i2c_core_check_stale(struct pvr2_hdw *); | ||
69 | void pvr2_i2c_core_sync(struct pvr2_hdw *); | ||
70 | unsigned int pvr2_i2c_report(struct pvr2_hdw *,char *buf,unsigned int maxlen); | ||
71 | #define PVR2_I2C_DETAIL_DEBUG 0x0001 | ||
72 | #define PVR2_I2C_DETAIL_HANDLER 0x0002 | ||
73 | #define PVR2_I2C_DETAIL_CTLMASK 0x0004 | ||
74 | #define PVR2_I2C_DETAIL_ALL (\ | ||
75 | PVR2_I2C_DETAIL_DEBUG |\ | ||
76 | PVR2_I2C_DETAIL_HANDLER |\ | ||
77 | PVR2_I2C_DETAIL_CTLMASK) | ||
78 | unsigned int pvr2_i2c_client_describe(struct pvr2_i2c_client *, | ||
79 | unsigned int detail_mask, | ||
80 | char *buf,unsigned int maxlen); | ||
81 | |||
82 | void pvr2_i2c_probe(struct pvr2_hdw *,struct pvr2_i2c_client *); | ||
83 | const struct pvr2_i2c_op *pvr2_i2c_get_op(unsigned int idx); | ||
84 | |||
85 | #endif /* __PVRUSB2_I2C_CORE_H */ | ||
86 | |||
87 | |||
88 | /* | ||
89 | Stuff for Emacs to see, in order to encourage consistent editing style: | ||
90 | *** Local Variables: *** | ||
91 | *** mode: c *** | ||
92 | *** fill-column: 75 *** | ||
93 | *** tab-width: 8 *** | ||
94 | *** c-basic-offset: 8 *** | ||
95 | *** End: *** | ||
96 | */ | ||
diff --git a/drivers/media/video/pvrusb2/pvrusb2-io.c b/drivers/media/video/pvrusb2/pvrusb2-io.c new file mode 100644 index 000000000000..a984c91f571c --- /dev/null +++ b/drivers/media/video/pvrusb2/pvrusb2-io.c | |||
@@ -0,0 +1,695 @@ | |||
1 | /* | ||
2 | * | ||
3 | * $Id$ | ||
4 | * | ||
5 | * Copyright (C) 2005 Mike Isely <isely@pobox.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 | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include "pvrusb2-io.h" | ||
23 | #include "pvrusb2-debug.h" | ||
24 | #include <linux/errno.h> | ||
25 | #include <linux/string.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/mutex.h> | ||
28 | |||
29 | #define BUFFER_SIG 0x47653271 | ||
30 | |||
31 | // #define SANITY_CHECK_BUFFERS | ||
32 | |||
33 | |||
34 | #ifdef SANITY_CHECK_BUFFERS | ||
35 | #define BUFFER_CHECK(bp) do { \ | ||
36 | if ((bp)->signature != BUFFER_SIG) { \ | ||
37 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, \ | ||
38 | "Buffer %p is bad at %s:%d", \ | ||
39 | (bp),__FILE__,__LINE__); \ | ||
40 | pvr2_buffer_describe(bp,"BadSig"); \ | ||
41 | BUG(); \ | ||
42 | } \ | ||
43 | } while (0) | ||
44 | #else | ||
45 | #define BUFFER_CHECK(bp) do {} while(0) | ||
46 | #endif | ||
47 | |||
48 | struct pvr2_stream { | ||
49 | /* Buffers queued for reading */ | ||
50 | struct list_head queued_list; | ||
51 | unsigned int q_count; | ||
52 | unsigned int q_bcount; | ||
53 | /* Buffers with retrieved data */ | ||
54 | struct list_head ready_list; | ||
55 | unsigned int r_count; | ||
56 | unsigned int r_bcount; | ||
57 | /* Buffers available for use */ | ||
58 | struct list_head idle_list; | ||
59 | unsigned int i_count; | ||
60 | unsigned int i_bcount; | ||
61 | /* Pointers to all buffers */ | ||
62 | struct pvr2_buffer **buffers; | ||
63 | /* Array size of buffers */ | ||
64 | unsigned int buffer_slot_count; | ||
65 | /* Total buffers actually in circulation */ | ||
66 | unsigned int buffer_total_count; | ||
67 | /* Designed number of buffers to be in circulation */ | ||
68 | unsigned int buffer_target_count; | ||
69 | /* Executed when ready list become non-empty */ | ||
70 | pvr2_stream_callback callback_func; | ||
71 | void *callback_data; | ||
72 | /* Context for transfer endpoint */ | ||
73 | struct usb_device *dev; | ||
74 | int endpoint; | ||
75 | /* Overhead for mutex enforcement */ | ||
76 | spinlock_t list_lock; | ||
77 | struct mutex mutex; | ||
78 | /* Tracking state for tolerating errors */ | ||
79 | unsigned int fail_count; | ||
80 | unsigned int fail_tolerance; | ||
81 | }; | ||
82 | |||
83 | struct pvr2_buffer { | ||
84 | int id; | ||
85 | int signature; | ||
86 | enum pvr2_buffer_state state; | ||
87 | void *ptr; /* Pointer to storage area */ | ||
88 | unsigned int max_count; /* Size of storage area */ | ||
89 | unsigned int used_count; /* Amount of valid data in storage area */ | ||
90 | int status; /* Transfer result status */ | ||
91 | struct pvr2_stream *stream; | ||
92 | struct list_head list_overhead; | ||
93 | struct urb *purb; | ||
94 | }; | ||
95 | |||
96 | const char *pvr2_buffer_state_decode(enum pvr2_buffer_state st) | ||
97 | { | ||
98 | switch (st) { | ||
99 | case pvr2_buffer_state_none: return "none"; | ||
100 | case pvr2_buffer_state_idle: return "idle"; | ||
101 | case pvr2_buffer_state_queued: return "queued"; | ||
102 | case pvr2_buffer_state_ready: return "ready"; | ||
103 | } | ||
104 | return "unknown"; | ||
105 | } | ||
106 | |||
107 | void pvr2_buffer_describe(struct pvr2_buffer *bp,const char *msg) | ||
108 | { | ||
109 | pvr2_trace(PVR2_TRACE_INFO, | ||
110 | "buffer%s%s %p state=%s id=%d status=%d" | ||
111 | " stream=%p purb=%p sig=0x%x", | ||
112 | (msg ? " " : ""), | ||
113 | (msg ? msg : ""), | ||
114 | bp, | ||
115 | (bp ? pvr2_buffer_state_decode(bp->state) : "(invalid)"), | ||
116 | (bp ? bp->id : 0), | ||
117 | (bp ? bp->status : 0), | ||
118 | (bp ? bp->stream : 0), | ||
119 | (bp ? bp->purb : 0), | ||
120 | (bp ? bp->signature : 0)); | ||
121 | } | ||
122 | |||
123 | static void pvr2_buffer_remove(struct pvr2_buffer *bp) | ||
124 | { | ||
125 | unsigned int *cnt; | ||
126 | unsigned int *bcnt; | ||
127 | unsigned int ccnt; | ||
128 | struct pvr2_stream *sp = bp->stream; | ||
129 | switch (bp->state) { | ||
130 | case pvr2_buffer_state_idle: | ||
131 | cnt = &sp->i_count; | ||
132 | bcnt = &sp->i_bcount; | ||
133 | ccnt = bp->max_count; | ||
134 | break; | ||
135 | case pvr2_buffer_state_queued: | ||
136 | cnt = &sp->q_count; | ||
137 | bcnt = &sp->q_bcount; | ||
138 | ccnt = bp->max_count; | ||
139 | break; | ||
140 | case pvr2_buffer_state_ready: | ||
141 | cnt = &sp->r_count; | ||
142 | bcnt = &sp->r_bcount; | ||
143 | ccnt = bp->used_count; | ||
144 | break; | ||
145 | default: | ||
146 | return; | ||
147 | } | ||
148 | list_del_init(&bp->list_overhead); | ||
149 | (*cnt)--; | ||
150 | (*bcnt) -= ccnt; | ||
151 | pvr2_trace(PVR2_TRACE_BUF_FLOW, | ||
152 | "/*---TRACE_FLOW---*/" | ||
153 | " bufferPool %8s dec cap=%07d cnt=%02d", | ||
154 | pvr2_buffer_state_decode(bp->state),*bcnt,*cnt); | ||
155 | bp->state = pvr2_buffer_state_none; | ||
156 | } | ||
157 | |||
158 | static void pvr2_buffer_set_none(struct pvr2_buffer *bp) | ||
159 | { | ||
160 | unsigned long irq_flags; | ||
161 | struct pvr2_stream *sp; | ||
162 | BUFFER_CHECK(bp); | ||
163 | sp = bp->stream; | ||
164 | pvr2_trace(PVR2_TRACE_BUF_FLOW, | ||
165 | "/*---TRACE_FLOW---*/ bufferState %p %6s --> %6s", | ||
166 | bp, | ||
167 | pvr2_buffer_state_decode(bp->state), | ||
168 | pvr2_buffer_state_decode(pvr2_buffer_state_none)); | ||
169 | spin_lock_irqsave(&sp->list_lock,irq_flags); | ||
170 | pvr2_buffer_remove(bp); | ||
171 | spin_unlock_irqrestore(&sp->list_lock,irq_flags); | ||
172 | } | ||
173 | |||
174 | static int pvr2_buffer_set_ready(struct pvr2_buffer *bp) | ||
175 | { | ||
176 | int fl; | ||
177 | unsigned long irq_flags; | ||
178 | struct pvr2_stream *sp; | ||
179 | BUFFER_CHECK(bp); | ||
180 | sp = bp->stream; | ||
181 | pvr2_trace(PVR2_TRACE_BUF_FLOW, | ||
182 | "/*---TRACE_FLOW---*/ bufferState %p %6s --> %6s", | ||
183 | bp, | ||
184 | pvr2_buffer_state_decode(bp->state), | ||
185 | pvr2_buffer_state_decode(pvr2_buffer_state_ready)); | ||
186 | spin_lock_irqsave(&sp->list_lock,irq_flags); | ||
187 | fl = (sp->r_count == 0); | ||
188 | pvr2_buffer_remove(bp); | ||
189 | list_add_tail(&bp->list_overhead,&sp->ready_list); | ||
190 | bp->state = pvr2_buffer_state_ready; | ||
191 | (sp->r_count)++; | ||
192 | sp->r_bcount += bp->used_count; | ||
193 | pvr2_trace(PVR2_TRACE_BUF_FLOW, | ||
194 | "/*---TRACE_FLOW---*/" | ||
195 | " bufferPool %8s inc cap=%07d cnt=%02d", | ||
196 | pvr2_buffer_state_decode(bp->state), | ||
197 | sp->r_bcount,sp->r_count); | ||
198 | spin_unlock_irqrestore(&sp->list_lock,irq_flags); | ||
199 | return fl; | ||
200 | } | ||
201 | |||
202 | static void pvr2_buffer_set_idle(struct pvr2_buffer *bp) | ||
203 | { | ||
204 | unsigned long irq_flags; | ||
205 | struct pvr2_stream *sp; | ||
206 | BUFFER_CHECK(bp); | ||
207 | sp = bp->stream; | ||
208 | pvr2_trace(PVR2_TRACE_BUF_FLOW, | ||
209 | "/*---TRACE_FLOW---*/ bufferState %p %6s --> %6s", | ||
210 | bp, | ||
211 | pvr2_buffer_state_decode(bp->state), | ||
212 | pvr2_buffer_state_decode(pvr2_buffer_state_idle)); | ||
213 | spin_lock_irqsave(&sp->list_lock,irq_flags); | ||
214 | pvr2_buffer_remove(bp); | ||
215 | list_add_tail(&bp->list_overhead,&sp->idle_list); | ||
216 | bp->state = pvr2_buffer_state_idle; | ||
217 | (sp->i_count)++; | ||
218 | sp->i_bcount += bp->max_count; | ||
219 | pvr2_trace(PVR2_TRACE_BUF_FLOW, | ||
220 | "/*---TRACE_FLOW---*/" | ||
221 | " bufferPool %8s inc cap=%07d cnt=%02d", | ||
222 | pvr2_buffer_state_decode(bp->state), | ||
223 | sp->i_bcount,sp->i_count); | ||
224 | spin_unlock_irqrestore(&sp->list_lock,irq_flags); | ||
225 | } | ||
226 | |||
227 | static void pvr2_buffer_set_queued(struct pvr2_buffer *bp) | ||
228 | { | ||
229 | unsigned long irq_flags; | ||
230 | struct pvr2_stream *sp; | ||
231 | BUFFER_CHECK(bp); | ||
232 | sp = bp->stream; | ||
233 | pvr2_trace(PVR2_TRACE_BUF_FLOW, | ||
234 | "/*---TRACE_FLOW---*/ bufferState %p %6s --> %6s", | ||
235 | bp, | ||
236 | pvr2_buffer_state_decode(bp->state), | ||
237 | pvr2_buffer_state_decode(pvr2_buffer_state_queued)); | ||
238 | spin_lock_irqsave(&sp->list_lock,irq_flags); | ||
239 | pvr2_buffer_remove(bp); | ||
240 | list_add_tail(&bp->list_overhead,&sp->queued_list); | ||
241 | bp->state = pvr2_buffer_state_queued; | ||
242 | (sp->q_count)++; | ||
243 | sp->q_bcount += bp->max_count; | ||
244 | pvr2_trace(PVR2_TRACE_BUF_FLOW, | ||
245 | "/*---TRACE_FLOW---*/" | ||
246 | " bufferPool %8s inc cap=%07d cnt=%02d", | ||
247 | pvr2_buffer_state_decode(bp->state), | ||
248 | sp->q_bcount,sp->q_count); | ||
249 | spin_unlock_irqrestore(&sp->list_lock,irq_flags); | ||
250 | } | ||
251 | |||
252 | static void pvr2_buffer_wipe(struct pvr2_buffer *bp) | ||
253 | { | ||
254 | if (bp->state == pvr2_buffer_state_queued) { | ||
255 | usb_kill_urb(bp->purb); | ||
256 | } | ||
257 | } | ||
258 | |||
259 | static int pvr2_buffer_init(struct pvr2_buffer *bp, | ||
260 | struct pvr2_stream *sp, | ||
261 | unsigned int id) | ||
262 | { | ||
263 | memset(bp,0,sizeof(*bp)); | ||
264 | bp->signature = BUFFER_SIG; | ||
265 | bp->id = id; | ||
266 | pvr2_trace(PVR2_TRACE_BUF_POOL, | ||
267 | "/*---TRACE_FLOW---*/ bufferInit %p stream=%p",bp,sp); | ||
268 | bp->stream = sp; | ||
269 | bp->state = pvr2_buffer_state_none; | ||
270 | INIT_LIST_HEAD(&bp->list_overhead); | ||
271 | bp->purb = usb_alloc_urb(0,GFP_KERNEL); | ||
272 | if (! bp->purb) return -ENOMEM; | ||
273 | #ifdef SANITY_CHECK_BUFFERS | ||
274 | pvr2_buffer_describe(bp,"create"); | ||
275 | #endif | ||
276 | return 0; | ||
277 | } | ||
278 | |||
279 | static void pvr2_buffer_done(struct pvr2_buffer *bp) | ||
280 | { | ||
281 | #ifdef SANITY_CHECK_BUFFERS | ||
282 | pvr2_buffer_describe(bp,"delete"); | ||
283 | #endif | ||
284 | pvr2_buffer_wipe(bp); | ||
285 | pvr2_buffer_set_none(bp); | ||
286 | bp->signature = 0; | ||
287 | bp->stream = 0; | ||
288 | if (bp->purb) usb_free_urb(bp->purb); | ||
289 | pvr2_trace(PVR2_TRACE_BUF_POOL,"/*---TRACE_FLOW---*/" | ||
290 | " bufferDone %p",bp); | ||
291 | } | ||
292 | |||
293 | static int pvr2_stream_buffer_count(struct pvr2_stream *sp,unsigned int cnt) | ||
294 | { | ||
295 | int ret; | ||
296 | unsigned int scnt; | ||
297 | |||
298 | /* Allocate buffers pointer array in multiples of 32 entries */ | ||
299 | if (cnt == sp->buffer_total_count) return 0; | ||
300 | |||
301 | pvr2_trace(PVR2_TRACE_BUF_POOL, | ||
302 | "/*---TRACE_FLOW---*/ poolResize " | ||
303 | " stream=%p cur=%d adj=%+d", | ||
304 | sp, | ||
305 | sp->buffer_total_count, | ||
306 | cnt-sp->buffer_total_count); | ||
307 | |||
308 | scnt = cnt & ~0x1f; | ||
309 | if (cnt > scnt) scnt += 0x20; | ||
310 | |||
311 | if (cnt > sp->buffer_total_count) { | ||
312 | if (scnt > sp->buffer_slot_count) { | ||
313 | struct pvr2_buffer **nb; | ||
314 | nb = kmalloc(scnt * sizeof(*nb),GFP_KERNEL); | ||
315 | if (!nb) return -ENOMEM; | ||
316 | if (sp->buffer_slot_count) { | ||
317 | memcpy(nb,sp->buffers, | ||
318 | sp->buffer_slot_count * sizeof(*nb)); | ||
319 | kfree(sp->buffers); | ||
320 | } | ||
321 | sp->buffers = nb; | ||
322 | sp->buffer_slot_count = scnt; | ||
323 | } | ||
324 | while (sp->buffer_total_count < cnt) { | ||
325 | struct pvr2_buffer *bp; | ||
326 | bp = kmalloc(sizeof(*bp),GFP_KERNEL); | ||
327 | if (!bp) return -ENOMEM; | ||
328 | ret = pvr2_buffer_init(bp,sp,sp->buffer_total_count); | ||
329 | if (ret) { | ||
330 | kfree(bp); | ||
331 | return -ENOMEM; | ||
332 | } | ||
333 | sp->buffers[sp->buffer_total_count] = bp; | ||
334 | (sp->buffer_total_count)++; | ||
335 | pvr2_buffer_set_idle(bp); | ||
336 | } | ||
337 | } else { | ||
338 | while (sp->buffer_total_count > cnt) { | ||
339 | struct pvr2_buffer *bp; | ||
340 | bp = sp->buffers[sp->buffer_total_count - 1]; | ||
341 | /* Paranoia */ | ||
342 | sp->buffers[sp->buffer_total_count - 1] = 0; | ||
343 | (sp->buffer_total_count)--; | ||
344 | pvr2_buffer_done(bp); | ||
345 | kfree(bp); | ||
346 | } | ||
347 | if (scnt < sp->buffer_slot_count) { | ||
348 | struct pvr2_buffer **nb = 0; | ||
349 | if (scnt) { | ||
350 | nb = kmalloc(scnt * sizeof(*nb),GFP_KERNEL); | ||
351 | if (!nb) return -ENOMEM; | ||
352 | memcpy(nb,sp->buffers,scnt * sizeof(*nb)); | ||
353 | } | ||
354 | kfree(sp->buffers); | ||
355 | sp->buffers = nb; | ||
356 | sp->buffer_slot_count = scnt; | ||
357 | } | ||
358 | } | ||
359 | return 0; | ||
360 | } | ||
361 | |||
362 | static int pvr2_stream_achieve_buffer_count(struct pvr2_stream *sp) | ||
363 | { | ||
364 | struct pvr2_buffer *bp; | ||
365 | unsigned int cnt; | ||
366 | |||
367 | if (sp->buffer_total_count == sp->buffer_target_count) return 0; | ||
368 | |||
369 | pvr2_trace(PVR2_TRACE_BUF_POOL, | ||
370 | "/*---TRACE_FLOW---*/" | ||
371 | " poolCheck stream=%p cur=%d tgt=%d", | ||
372 | sp,sp->buffer_total_count,sp->buffer_target_count); | ||
373 | |||
374 | if (sp->buffer_total_count < sp->buffer_target_count) { | ||
375 | return pvr2_stream_buffer_count(sp,sp->buffer_target_count); | ||
376 | } | ||
377 | |||
378 | cnt = 0; | ||
379 | while ((sp->buffer_total_count - cnt) > sp->buffer_target_count) { | ||
380 | bp = sp->buffers[sp->buffer_total_count - (cnt + 1)]; | ||
381 | if (bp->state != pvr2_buffer_state_idle) break; | ||
382 | cnt++; | ||
383 | } | ||
384 | if (cnt) { | ||
385 | pvr2_stream_buffer_count(sp,sp->buffer_total_count - cnt); | ||
386 | } | ||
387 | |||
388 | return 0; | ||
389 | } | ||
390 | |||
391 | static void pvr2_stream_internal_flush(struct pvr2_stream *sp) | ||
392 | { | ||
393 | struct list_head *lp; | ||
394 | struct pvr2_buffer *bp1; | ||
395 | while ((lp = sp->queued_list.next) != &sp->queued_list) { | ||
396 | bp1 = list_entry(lp,struct pvr2_buffer,list_overhead); | ||
397 | pvr2_buffer_wipe(bp1); | ||
398 | /* At this point, we should be guaranteed that no | ||
399 | completion callback may happen on this buffer. But it's | ||
400 | possible that it might have completed after we noticed | ||
401 | it but before we wiped it. So double check its status | ||
402 | here first. */ | ||
403 | if (bp1->state != pvr2_buffer_state_queued) continue; | ||
404 | pvr2_buffer_set_idle(bp1); | ||
405 | } | ||
406 | if (sp->buffer_total_count != sp->buffer_target_count) { | ||
407 | pvr2_stream_achieve_buffer_count(sp); | ||
408 | } | ||
409 | } | ||
410 | |||
411 | static void pvr2_stream_init(struct pvr2_stream *sp) | ||
412 | { | ||
413 | spin_lock_init(&sp->list_lock); | ||
414 | mutex_init(&sp->mutex); | ||
415 | INIT_LIST_HEAD(&sp->queued_list); | ||
416 | INIT_LIST_HEAD(&sp->ready_list); | ||
417 | INIT_LIST_HEAD(&sp->idle_list); | ||
418 | } | ||
419 | |||
420 | static void pvr2_stream_done(struct pvr2_stream *sp) | ||
421 | { | ||
422 | mutex_lock(&sp->mutex); do { | ||
423 | pvr2_stream_internal_flush(sp); | ||
424 | pvr2_stream_buffer_count(sp,0); | ||
425 | } while (0); mutex_unlock(&sp->mutex); | ||
426 | } | ||
427 | |||
428 | static void buffer_complete(struct urb *urb, struct pt_regs *regs) | ||
429 | { | ||
430 | struct pvr2_buffer *bp = urb->context; | ||
431 | struct pvr2_stream *sp; | ||
432 | unsigned long irq_flags; | ||
433 | BUFFER_CHECK(bp); | ||
434 | sp = bp->stream; | ||
435 | bp->used_count = 0; | ||
436 | bp->status = 0; | ||
437 | pvr2_trace(PVR2_TRACE_BUF_FLOW, | ||
438 | "/*---TRACE_FLOW---*/ bufferComplete %p stat=%d cnt=%d", | ||
439 | bp,urb->status,urb->actual_length); | ||
440 | spin_lock_irqsave(&sp->list_lock,irq_flags); | ||
441 | if ((!(urb->status)) || | ||
442 | (urb->status == -ENOENT) || | ||
443 | (urb->status == -ECONNRESET) || | ||
444 | (urb->status == -ESHUTDOWN)) { | ||
445 | bp->used_count = urb->actual_length; | ||
446 | if (sp->fail_count) { | ||
447 | pvr2_trace(PVR2_TRACE_TOLERANCE, | ||
448 | "stream %p transfer ok" | ||
449 | " - fail count reset",sp); | ||
450 | sp->fail_count = 0; | ||
451 | } | ||
452 | } else if (sp->fail_count < sp->fail_tolerance) { | ||
453 | // We can tolerate this error, because we're below the | ||
454 | // threshold... | ||
455 | (sp->fail_count)++; | ||
456 | pvr2_trace(PVR2_TRACE_TOLERANCE, | ||
457 | "stream %p ignoring error %d" | ||
458 | " - fail count increased to %u", | ||
459 | sp,urb->status,sp->fail_count); | ||
460 | } else { | ||
461 | bp->status = urb->status; | ||
462 | } | ||
463 | spin_unlock_irqrestore(&sp->list_lock,irq_flags); | ||
464 | pvr2_buffer_set_ready(bp); | ||
465 | if (sp && sp->callback_func) { | ||
466 | sp->callback_func(sp->callback_data); | ||
467 | } | ||
468 | } | ||
469 | |||
470 | struct pvr2_stream *pvr2_stream_create(void) | ||
471 | { | ||
472 | struct pvr2_stream *sp; | ||
473 | sp = kmalloc(sizeof(*sp),GFP_KERNEL); | ||
474 | if (!sp) return sp; | ||
475 | memset(sp,0,sizeof(*sp)); | ||
476 | pvr2_trace(PVR2_TRACE_INIT,"pvr2_stream_create: sp=%p",sp); | ||
477 | pvr2_stream_init(sp); | ||
478 | return sp; | ||
479 | } | ||
480 | |||
481 | void pvr2_stream_destroy(struct pvr2_stream *sp) | ||
482 | { | ||
483 | if (!sp) return; | ||
484 | pvr2_trace(PVR2_TRACE_INIT,"pvr2_stream_destroy: sp=%p",sp); | ||
485 | pvr2_stream_done(sp); | ||
486 | kfree(sp); | ||
487 | } | ||
488 | |||
489 | void pvr2_stream_setup(struct pvr2_stream *sp, | ||
490 | struct usb_device *dev, | ||
491 | int endpoint, | ||
492 | unsigned int tolerance) | ||
493 | { | ||
494 | mutex_lock(&sp->mutex); do { | ||
495 | pvr2_stream_internal_flush(sp); | ||
496 | sp->dev = dev; | ||
497 | sp->endpoint = endpoint; | ||
498 | sp->fail_tolerance = tolerance; | ||
499 | } while(0); mutex_unlock(&sp->mutex); | ||
500 | } | ||
501 | |||
502 | void pvr2_stream_set_callback(struct pvr2_stream *sp, | ||
503 | pvr2_stream_callback func, | ||
504 | void *data) | ||
505 | { | ||
506 | unsigned long irq_flags; | ||
507 | mutex_lock(&sp->mutex); do { | ||
508 | spin_lock_irqsave(&sp->list_lock,irq_flags); | ||
509 | sp->callback_data = data; | ||
510 | sp->callback_func = func; | ||
511 | spin_unlock_irqrestore(&sp->list_lock,irq_flags); | ||
512 | } while(0); mutex_unlock(&sp->mutex); | ||
513 | } | ||
514 | |||
515 | /* Query / set the nominal buffer count */ | ||
516 | int pvr2_stream_get_buffer_count(struct pvr2_stream *sp) | ||
517 | { | ||
518 | return sp->buffer_target_count; | ||
519 | } | ||
520 | |||
521 | int pvr2_stream_set_buffer_count(struct pvr2_stream *sp,unsigned int cnt) | ||
522 | { | ||
523 | int ret; | ||
524 | if (sp->buffer_target_count == cnt) return 0; | ||
525 | mutex_lock(&sp->mutex); do { | ||
526 | sp->buffer_target_count = cnt; | ||
527 | ret = pvr2_stream_achieve_buffer_count(sp); | ||
528 | } while(0); mutex_unlock(&sp->mutex); | ||
529 | return ret; | ||
530 | } | ||
531 | |||
532 | struct pvr2_buffer *pvr2_stream_get_idle_buffer(struct pvr2_stream *sp) | ||
533 | { | ||
534 | struct list_head *lp = sp->idle_list.next; | ||
535 | if (lp == &sp->idle_list) return 0; | ||
536 | return list_entry(lp,struct pvr2_buffer,list_overhead); | ||
537 | } | ||
538 | |||
539 | struct pvr2_buffer *pvr2_stream_get_ready_buffer(struct pvr2_stream *sp) | ||
540 | { | ||
541 | struct list_head *lp = sp->ready_list.next; | ||
542 | if (lp == &sp->ready_list) return 0; | ||
543 | return list_entry(lp,struct pvr2_buffer,list_overhead); | ||
544 | } | ||
545 | |||
546 | struct pvr2_buffer *pvr2_stream_get_buffer(struct pvr2_stream *sp,int id) | ||
547 | { | ||
548 | if (id < 0) return 0; | ||
549 | if (id >= sp->buffer_total_count) return 0; | ||
550 | return sp->buffers[id]; | ||
551 | } | ||
552 | |||
553 | int pvr2_stream_get_ready_count(struct pvr2_stream *sp) | ||
554 | { | ||
555 | return sp->r_count; | ||
556 | } | ||
557 | |||
558 | int pvr2_stream_get_idle_count(struct pvr2_stream *sp) | ||
559 | { | ||
560 | return sp->i_count; | ||
561 | } | ||
562 | |||
563 | void pvr2_stream_flush(struct pvr2_stream *sp) | ||
564 | { | ||
565 | mutex_lock(&sp->mutex); do { | ||
566 | pvr2_stream_internal_flush(sp); | ||
567 | } while(0); mutex_unlock(&sp->mutex); | ||
568 | } | ||
569 | |||
570 | void pvr2_stream_kill(struct pvr2_stream *sp) | ||
571 | { | ||
572 | struct pvr2_buffer *bp; | ||
573 | mutex_lock(&sp->mutex); do { | ||
574 | pvr2_stream_internal_flush(sp); | ||
575 | while ((bp = pvr2_stream_get_ready_buffer(sp)) != 0) { | ||
576 | pvr2_buffer_set_idle(bp); | ||
577 | } | ||
578 | if (sp->buffer_total_count != sp->buffer_target_count) { | ||
579 | pvr2_stream_achieve_buffer_count(sp); | ||
580 | } | ||
581 | } while(0); mutex_unlock(&sp->mutex); | ||
582 | } | ||
583 | |||
584 | int pvr2_buffer_queue(struct pvr2_buffer *bp) | ||
585 | { | ||
586 | #undef SEED_BUFFER | ||
587 | #ifdef SEED_BUFFER | ||
588 | unsigned int idx; | ||
589 | unsigned int val; | ||
590 | #endif | ||
591 | int ret = 0; | ||
592 | struct pvr2_stream *sp; | ||
593 | if (!bp) return -EINVAL; | ||
594 | sp = bp->stream; | ||
595 | mutex_lock(&sp->mutex); do { | ||
596 | pvr2_buffer_wipe(bp); | ||
597 | if (!sp->dev) { | ||
598 | ret = -EIO; | ||
599 | break; | ||
600 | } | ||
601 | pvr2_buffer_set_queued(bp); | ||
602 | #ifdef SEED_BUFFER | ||
603 | for (idx = 0; idx < (bp->max_count) / 4; idx++) { | ||
604 | val = bp->id << 24; | ||
605 | val |= idx; | ||
606 | ((unsigned int *)(bp->ptr))[idx] = val; | ||
607 | } | ||
608 | #endif | ||
609 | bp->status = -EINPROGRESS; | ||
610 | usb_fill_bulk_urb(bp->purb, // struct urb *urb | ||
611 | sp->dev, // struct usb_device *dev | ||
612 | // endpoint (below) | ||
613 | usb_rcvbulkpipe(sp->dev,sp->endpoint), | ||
614 | bp->ptr, // void *transfer_buffer | ||
615 | bp->max_count, // int buffer_length | ||
616 | buffer_complete, | ||
617 | bp); | ||
618 | usb_submit_urb(bp->purb,GFP_KERNEL); | ||
619 | } while(0); mutex_unlock(&sp->mutex); | ||
620 | return ret; | ||
621 | } | ||
622 | |||
623 | int pvr2_buffer_idle(struct pvr2_buffer *bp) | ||
624 | { | ||
625 | struct pvr2_stream *sp; | ||
626 | if (!bp) return -EINVAL; | ||
627 | sp = bp->stream; | ||
628 | mutex_lock(&sp->mutex); do { | ||
629 | pvr2_buffer_wipe(bp); | ||
630 | pvr2_buffer_set_idle(bp); | ||
631 | if (sp->buffer_total_count != sp->buffer_target_count) { | ||
632 | pvr2_stream_achieve_buffer_count(sp); | ||
633 | } | ||
634 | } while(0); mutex_unlock(&sp->mutex); | ||
635 | return 0; | ||
636 | } | ||
637 | |||
638 | int pvr2_buffer_set_buffer(struct pvr2_buffer *bp,void *ptr,unsigned int cnt) | ||
639 | { | ||
640 | int ret = 0; | ||
641 | unsigned long irq_flags; | ||
642 | struct pvr2_stream *sp; | ||
643 | if (!bp) return -EINVAL; | ||
644 | sp = bp->stream; | ||
645 | mutex_lock(&sp->mutex); do { | ||
646 | spin_lock_irqsave(&sp->list_lock,irq_flags); | ||
647 | if (bp->state != pvr2_buffer_state_idle) { | ||
648 | ret = -EPERM; | ||
649 | } else { | ||
650 | bp->ptr = ptr; | ||
651 | bp->stream->i_bcount -= bp->max_count; | ||
652 | bp->max_count = cnt; | ||
653 | bp->stream->i_bcount += bp->max_count; | ||
654 | pvr2_trace(PVR2_TRACE_BUF_FLOW, | ||
655 | "/*---TRACE_FLOW---*/ bufferPool " | ||
656 | " %8s cap cap=%07d cnt=%02d", | ||
657 | pvr2_buffer_state_decode( | ||
658 | pvr2_buffer_state_idle), | ||
659 | bp->stream->i_bcount,bp->stream->i_count); | ||
660 | } | ||
661 | spin_unlock_irqrestore(&sp->list_lock,irq_flags); | ||
662 | } while(0); mutex_unlock(&sp->mutex); | ||
663 | return ret; | ||
664 | } | ||
665 | |||
666 | unsigned int pvr2_buffer_get_count(struct pvr2_buffer *bp) | ||
667 | { | ||
668 | return bp->used_count; | ||
669 | } | ||
670 | |||
671 | int pvr2_buffer_get_status(struct pvr2_buffer *bp) | ||
672 | { | ||
673 | return bp->status; | ||
674 | } | ||
675 | |||
676 | enum pvr2_buffer_state pvr2_buffer_get_state(struct pvr2_buffer *bp) | ||
677 | { | ||
678 | return bp->state; | ||
679 | } | ||
680 | |||
681 | int pvr2_buffer_get_id(struct pvr2_buffer *bp) | ||
682 | { | ||
683 | return bp->id; | ||
684 | } | ||
685 | |||
686 | |||
687 | /* | ||
688 | Stuff for Emacs to see, in order to encourage consistent editing style: | ||
689 | *** Local Variables: *** | ||
690 | *** mode: c *** | ||
691 | *** fill-column: 75 *** | ||
692 | *** tab-width: 8 *** | ||
693 | *** c-basic-offset: 8 *** | ||
694 | *** End: *** | ||
695 | */ | ||
diff --git a/drivers/media/video/pvrusb2/pvrusb2-io.h b/drivers/media/video/pvrusb2/pvrusb2-io.h new file mode 100644 index 000000000000..65e11385b2b3 --- /dev/null +++ b/drivers/media/video/pvrusb2/pvrusb2-io.h | |||
@@ -0,0 +1,102 @@ | |||
1 | /* | ||
2 | * | ||
3 | * $Id$ | ||
4 | * | ||
5 | * Copyright (C) 2005 Mike Isely <isely@pobox.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 | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | * | ||
20 | */ | ||
21 | #ifndef __PVRUSB2_IO_H | ||
22 | #define __PVRUSB2_IO_H | ||
23 | |||
24 | #include <linux/usb.h> | ||
25 | #include <linux/list.h> | ||
26 | |||
27 | typedef void (*pvr2_stream_callback)(void *); | ||
28 | |||
29 | enum pvr2_buffer_state { | ||
30 | pvr2_buffer_state_none = 0, // Not on any list | ||
31 | pvr2_buffer_state_idle = 1, // Buffer is ready to be used again | ||
32 | pvr2_buffer_state_queued = 2, // Buffer has been queued for filling | ||
33 | pvr2_buffer_state_ready = 3, // Buffer has data available | ||
34 | }; | ||
35 | |||
36 | struct pvr2_stream; | ||
37 | struct pvr2_buffer; | ||
38 | |||
39 | const char *pvr2_buffer_state_decode(enum pvr2_buffer_state); | ||
40 | |||
41 | /* Initialize / tear down stream structure */ | ||
42 | struct pvr2_stream *pvr2_stream_create(void); | ||
43 | void pvr2_stream_destroy(struct pvr2_stream *); | ||
44 | void pvr2_stream_setup(struct pvr2_stream *, | ||
45 | struct usb_device *dev,int endpoint, | ||
46 | unsigned int tolerance); | ||
47 | void pvr2_stream_set_callback(struct pvr2_stream *, | ||
48 | pvr2_stream_callback func, | ||
49 | void *data); | ||
50 | |||
51 | /* Query / set the nominal buffer count */ | ||
52 | int pvr2_stream_get_buffer_count(struct pvr2_stream *); | ||
53 | int pvr2_stream_set_buffer_count(struct pvr2_stream *,unsigned int); | ||
54 | |||
55 | /* Get a pointer to a buffer that is either idle, ready, or is specified | ||
56 | named. */ | ||
57 | struct pvr2_buffer *pvr2_stream_get_idle_buffer(struct pvr2_stream *); | ||
58 | struct pvr2_buffer *pvr2_stream_get_ready_buffer(struct pvr2_stream *); | ||
59 | struct pvr2_buffer *pvr2_stream_get_buffer(struct pvr2_stream *sp,int id); | ||
60 | |||
61 | /* Find out how many buffers are idle or ready */ | ||
62 | int pvr2_stream_get_idle_count(struct pvr2_stream *); | ||
63 | int pvr2_stream_get_ready_count(struct pvr2_stream *); | ||
64 | |||
65 | /* Kill all pending operations */ | ||
66 | void pvr2_stream_flush(struct pvr2_stream *); | ||
67 | |||
68 | /* Kill all pending buffers and throw away any ready buffers as well */ | ||
69 | void pvr2_stream_kill(struct pvr2_stream *); | ||
70 | |||
71 | /* Set up the actual storage for a buffer */ | ||
72 | int pvr2_buffer_set_buffer(struct pvr2_buffer *,void *ptr,unsigned int cnt); | ||
73 | |||
74 | /* Find out size of data in the given ready buffer */ | ||
75 | unsigned int pvr2_buffer_get_count(struct pvr2_buffer *); | ||
76 | |||
77 | /* Retrieve completion code for given ready buffer */ | ||
78 | int pvr2_buffer_get_status(struct pvr2_buffer *); | ||
79 | |||
80 | /* Retrieve state of given buffer */ | ||
81 | enum pvr2_buffer_state pvr2_buffer_get_state(struct pvr2_buffer *); | ||
82 | |||
83 | /* Retrieve ID of given buffer */ | ||
84 | int pvr2_buffer_get_id(struct pvr2_buffer *); | ||
85 | |||
86 | /* Start reading into given buffer (kill it if needed) */ | ||
87 | int pvr2_buffer_queue(struct pvr2_buffer *); | ||
88 | |||
89 | /* Move buffer back to idle pool (kill it if needed) */ | ||
90 | int pvr2_buffer_idle(struct pvr2_buffer *); | ||
91 | |||
92 | #endif /* __PVRUSB2_IO_H */ | ||
93 | |||
94 | /* | ||
95 | Stuff for Emacs to see, in order to encourage consistent editing style: | ||
96 | *** Local Variables: *** | ||
97 | *** mode: c *** | ||
98 | *** fill-column: 75 *** | ||
99 | *** tab-width: 8 *** | ||
100 | *** c-basic-offset: 8 *** | ||
101 | *** End: *** | ||
102 | */ | ||
diff --git a/drivers/media/video/pvrusb2/pvrusb2-ioread.c b/drivers/media/video/pvrusb2/pvrusb2-ioread.c new file mode 100644 index 000000000000..49da062e3271 --- /dev/null +++ b/drivers/media/video/pvrusb2/pvrusb2-ioread.c | |||
@@ -0,0 +1,513 @@ | |||
1 | /* | ||
2 | * | ||
3 | * $Id$ | ||
4 | * | ||
5 | * Copyright (C) 2005 Mike Isely <isely@pobox.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 | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include "pvrusb2-ioread.h" | ||
23 | #include "pvrusb2-debug.h" | ||
24 | #include <linux/errno.h> | ||
25 | #include <linux/string.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/mutex.h> | ||
28 | #include <asm/uaccess.h> | ||
29 | |||
30 | #define BUFFER_COUNT 32 | ||
31 | #define BUFFER_SIZE PAGE_ALIGN(0x4000) | ||
32 | |||
33 | struct pvr2_ioread { | ||
34 | struct pvr2_stream *stream; | ||
35 | char *buffer_storage[BUFFER_COUNT]; | ||
36 | char *sync_key_ptr; | ||
37 | unsigned int sync_key_len; | ||
38 | unsigned int sync_buf_offs; | ||
39 | unsigned int sync_state; | ||
40 | unsigned int sync_trashed_count; | ||
41 | int enabled; // Streaming is on | ||
42 | int spigot_open; // OK to pass data to client | ||
43 | int stream_running; // Passing data to client now | ||
44 | |||
45 | /* State relevant to current buffer being read */ | ||
46 | struct pvr2_buffer *c_buf; | ||
47 | char *c_data_ptr; | ||
48 | unsigned int c_data_len; | ||
49 | unsigned int c_data_offs; | ||
50 | struct mutex mutex; | ||
51 | }; | ||
52 | |||
53 | static int pvr2_ioread_init(struct pvr2_ioread *cp) | ||
54 | { | ||
55 | unsigned int idx; | ||
56 | |||
57 | cp->stream = 0; | ||
58 | mutex_init(&cp->mutex); | ||
59 | |||
60 | for (idx = 0; idx < BUFFER_COUNT; idx++) { | ||
61 | cp->buffer_storage[idx] = kmalloc(BUFFER_SIZE,GFP_KERNEL); | ||
62 | if (!(cp->buffer_storage[idx])) break; | ||
63 | } | ||
64 | |||
65 | if (idx < BUFFER_COUNT) { | ||
66 | // An allocation appears to have failed | ||
67 | for (idx = 0; idx < BUFFER_COUNT; idx++) { | ||
68 | if (!(cp->buffer_storage[idx])) continue; | ||
69 | kfree(cp->buffer_storage[idx]); | ||
70 | } | ||
71 | return -ENOMEM; | ||
72 | } | ||
73 | return 0; | ||
74 | } | ||
75 | |||
76 | static void pvr2_ioread_done(struct pvr2_ioread *cp) | ||
77 | { | ||
78 | unsigned int idx; | ||
79 | |||
80 | pvr2_ioread_setup(cp,0); | ||
81 | for (idx = 0; idx < BUFFER_COUNT; idx++) { | ||
82 | if (!(cp->buffer_storage[idx])) continue; | ||
83 | kfree(cp->buffer_storage[idx]); | ||
84 | } | ||
85 | } | ||
86 | |||
87 | struct pvr2_ioread *pvr2_ioread_create(void) | ||
88 | { | ||
89 | struct pvr2_ioread *cp; | ||
90 | cp = kmalloc(sizeof(*cp),GFP_KERNEL); | ||
91 | if (!cp) return 0; | ||
92 | pvr2_trace(PVR2_TRACE_STRUCT,"pvr2_ioread_create id=%p",cp); | ||
93 | memset(cp,0,sizeof(*cp)); | ||
94 | if (pvr2_ioread_init(cp) < 0) { | ||
95 | kfree(cp); | ||
96 | return 0; | ||
97 | } | ||
98 | return cp; | ||
99 | } | ||
100 | |||
101 | void pvr2_ioread_destroy(struct pvr2_ioread *cp) | ||
102 | { | ||
103 | if (!cp) return; | ||
104 | pvr2_ioread_done(cp); | ||
105 | pvr2_trace(PVR2_TRACE_STRUCT,"pvr2_ioread_destroy id=%p",cp); | ||
106 | if (cp->sync_key_ptr) { | ||
107 | kfree(cp->sync_key_ptr); | ||
108 | cp->sync_key_ptr = 0; | ||
109 | } | ||
110 | kfree(cp); | ||
111 | } | ||
112 | |||
113 | void pvr2_ioread_set_sync_key(struct pvr2_ioread *cp, | ||
114 | const char *sync_key_ptr, | ||
115 | unsigned int sync_key_len) | ||
116 | { | ||
117 | if (!cp) return; | ||
118 | |||
119 | if (!sync_key_ptr) sync_key_len = 0; | ||
120 | if ((sync_key_len == cp->sync_key_len) && | ||
121 | ((!sync_key_len) || | ||
122 | (!memcmp(sync_key_ptr,cp->sync_key_ptr,sync_key_len)))) return; | ||
123 | |||
124 | if (sync_key_len != cp->sync_key_len) { | ||
125 | if (cp->sync_key_ptr) { | ||
126 | kfree(cp->sync_key_ptr); | ||
127 | cp->sync_key_ptr = 0; | ||
128 | } | ||
129 | cp->sync_key_len = 0; | ||
130 | if (sync_key_len) { | ||
131 | cp->sync_key_ptr = kmalloc(sync_key_len,GFP_KERNEL); | ||
132 | if (cp->sync_key_ptr) { | ||
133 | cp->sync_key_len = sync_key_len; | ||
134 | } | ||
135 | } | ||
136 | } | ||
137 | if (!cp->sync_key_len) return; | ||
138 | memcpy(cp->sync_key_ptr,sync_key_ptr,cp->sync_key_len); | ||
139 | } | ||
140 | |||
141 | static void pvr2_ioread_stop(struct pvr2_ioread *cp) | ||
142 | { | ||
143 | if (!(cp->enabled)) return; | ||
144 | pvr2_trace(PVR2_TRACE_START_STOP, | ||
145 | "/*---TRACE_READ---*/ pvr2_ioread_stop id=%p",cp); | ||
146 | pvr2_stream_kill(cp->stream); | ||
147 | cp->c_buf = 0; | ||
148 | cp->c_data_ptr = 0; | ||
149 | cp->c_data_len = 0; | ||
150 | cp->c_data_offs = 0; | ||
151 | cp->enabled = 0; | ||
152 | cp->stream_running = 0; | ||
153 | cp->spigot_open = 0; | ||
154 | if (cp->sync_state) { | ||
155 | pvr2_trace(PVR2_TRACE_DATA_FLOW, | ||
156 | "/*---TRACE_READ---*/ sync_state <== 0"); | ||
157 | cp->sync_state = 0; | ||
158 | } | ||
159 | } | ||
160 | |||
161 | static int pvr2_ioread_start(struct pvr2_ioread *cp) | ||
162 | { | ||
163 | int stat; | ||
164 | struct pvr2_buffer *bp; | ||
165 | if (cp->enabled) return 0; | ||
166 | if (!(cp->stream)) return 0; | ||
167 | pvr2_trace(PVR2_TRACE_START_STOP, | ||
168 | "/*---TRACE_READ---*/ pvr2_ioread_start id=%p",cp); | ||
169 | while ((bp = pvr2_stream_get_idle_buffer(cp->stream)) != 0) { | ||
170 | stat = pvr2_buffer_queue(bp); | ||
171 | if (stat < 0) { | ||
172 | pvr2_trace(PVR2_TRACE_DATA_FLOW, | ||
173 | "/*---TRACE_READ---*/" | ||
174 | " pvr2_ioread_start id=%p" | ||
175 | " error=%d", | ||
176 | cp,stat); | ||
177 | pvr2_ioread_stop(cp); | ||
178 | return stat; | ||
179 | } | ||
180 | } | ||
181 | cp->enabled = !0; | ||
182 | cp->c_buf = 0; | ||
183 | cp->c_data_ptr = 0; | ||
184 | cp->c_data_len = 0; | ||
185 | cp->c_data_offs = 0; | ||
186 | cp->stream_running = 0; | ||
187 | if (cp->sync_key_len) { | ||
188 | pvr2_trace(PVR2_TRACE_DATA_FLOW, | ||
189 | "/*---TRACE_READ---*/ sync_state <== 1"); | ||
190 | cp->sync_state = 1; | ||
191 | cp->sync_trashed_count = 0; | ||
192 | cp->sync_buf_offs = 0; | ||
193 | } | ||
194 | cp->spigot_open = 0; | ||
195 | return 0; | ||
196 | } | ||
197 | |||
198 | struct pvr2_stream *pvr2_ioread_get_stream(struct pvr2_ioread *cp) | ||
199 | { | ||
200 | return cp->stream; | ||
201 | } | ||
202 | |||
203 | int pvr2_ioread_setup(struct pvr2_ioread *cp,struct pvr2_stream *sp) | ||
204 | { | ||
205 | int ret; | ||
206 | unsigned int idx; | ||
207 | struct pvr2_buffer *bp; | ||
208 | |||
209 | mutex_lock(&cp->mutex); do { | ||
210 | if (cp->stream) { | ||
211 | pvr2_trace(PVR2_TRACE_START_STOP, | ||
212 | "/*---TRACE_READ---*/" | ||
213 | " pvr2_ioread_setup (tear-down) id=%p",cp); | ||
214 | pvr2_ioread_stop(cp); | ||
215 | pvr2_stream_kill(cp->stream); | ||
216 | pvr2_stream_set_buffer_count(cp->stream,0); | ||
217 | cp->stream = 0; | ||
218 | } | ||
219 | if (sp) { | ||
220 | pvr2_trace(PVR2_TRACE_START_STOP, | ||
221 | "/*---TRACE_READ---*/" | ||
222 | " pvr2_ioread_setup (setup) id=%p",cp); | ||
223 | pvr2_stream_kill(sp); | ||
224 | ret = pvr2_stream_set_buffer_count(sp,BUFFER_COUNT); | ||
225 | if (ret < 0) return ret; | ||
226 | for (idx = 0; idx < BUFFER_COUNT; idx++) { | ||
227 | bp = pvr2_stream_get_buffer(sp,idx); | ||
228 | pvr2_buffer_set_buffer(bp, | ||
229 | cp->buffer_storage[idx], | ||
230 | BUFFER_SIZE); | ||
231 | } | ||
232 | cp->stream = sp; | ||
233 | } | ||
234 | } while (0); mutex_unlock(&cp->mutex); | ||
235 | |||
236 | return 0; | ||
237 | } | ||
238 | |||
239 | int pvr2_ioread_set_enabled(struct pvr2_ioread *cp,int fl) | ||
240 | { | ||
241 | int ret = 0; | ||
242 | if ((!fl) == (!(cp->enabled))) return ret; | ||
243 | |||
244 | mutex_lock(&cp->mutex); do { | ||
245 | if (fl) { | ||
246 | ret = pvr2_ioread_start(cp); | ||
247 | } else { | ||
248 | pvr2_ioread_stop(cp); | ||
249 | } | ||
250 | } while (0); mutex_unlock(&cp->mutex); | ||
251 | return ret; | ||
252 | } | ||
253 | |||
254 | int pvr2_ioread_get_enabled(struct pvr2_ioread *cp) | ||
255 | { | ||
256 | return cp->enabled != 0; | ||
257 | } | ||
258 | |||
259 | int pvr2_ioread_get_buffer(struct pvr2_ioread *cp) | ||
260 | { | ||
261 | int stat; | ||
262 | |||
263 | while (cp->c_data_len <= cp->c_data_offs) { | ||
264 | if (cp->c_buf) { | ||
265 | // Flush out current buffer first. | ||
266 | stat = pvr2_buffer_queue(cp->c_buf); | ||
267 | if (stat < 0) { | ||
268 | // Streaming error... | ||
269 | pvr2_trace(PVR2_TRACE_DATA_FLOW, | ||
270 | "/*---TRACE_READ---*/" | ||
271 | " pvr2_ioread_read id=%p" | ||
272 | " queue_error=%d", | ||
273 | cp,stat); | ||
274 | pvr2_ioread_stop(cp); | ||
275 | return 0; | ||
276 | } | ||
277 | cp->c_buf = 0; | ||
278 | cp->c_data_ptr = 0; | ||
279 | cp->c_data_len = 0; | ||
280 | cp->c_data_offs = 0; | ||
281 | } | ||
282 | // Now get a freshly filled buffer. | ||
283 | cp->c_buf = pvr2_stream_get_ready_buffer(cp->stream); | ||
284 | if (!cp->c_buf) break; // Nothing ready; done. | ||
285 | cp->c_data_len = pvr2_buffer_get_count(cp->c_buf); | ||
286 | if (!cp->c_data_len) { | ||
287 | // Nothing transferred. Was there an error? | ||
288 | stat = pvr2_buffer_get_status(cp->c_buf); | ||
289 | if (stat < 0) { | ||
290 | // Streaming error... | ||
291 | pvr2_trace(PVR2_TRACE_DATA_FLOW, | ||
292 | "/*---TRACE_READ---*/" | ||
293 | " pvr2_ioread_read id=%p" | ||
294 | " buffer_error=%d", | ||
295 | cp,stat); | ||
296 | pvr2_ioread_stop(cp); | ||
297 | // Give up. | ||
298 | return 0; | ||
299 | } | ||
300 | // Start over... | ||
301 | continue; | ||
302 | } | ||
303 | cp->c_data_offs = 0; | ||
304 | cp->c_data_ptr = cp->buffer_storage[ | ||
305 | pvr2_buffer_get_id(cp->c_buf)]; | ||
306 | } | ||
307 | return !0; | ||
308 | } | ||
309 | |||
310 | void pvr2_ioread_filter(struct pvr2_ioread *cp) | ||
311 | { | ||
312 | unsigned int idx; | ||
313 | if (!cp->enabled) return; | ||
314 | if (cp->sync_state != 1) return; | ||
315 | |||
316 | // Search the stream for our synchronization key. This is made | ||
317 | // complicated by the fact that in order to be honest with | ||
318 | // ourselves here we must search across buffer boundaries... | ||
319 | mutex_lock(&cp->mutex); while (1) { | ||
320 | // Ensure we have a buffer | ||
321 | if (!pvr2_ioread_get_buffer(cp)) break; | ||
322 | if (!cp->c_data_len) break; | ||
323 | |||
324 | // Now walk the buffer contents until we match the key or | ||
325 | // run out of buffer data. | ||
326 | for (idx = cp->c_data_offs; idx < cp->c_data_len; idx++) { | ||
327 | if (cp->sync_buf_offs >= cp->sync_key_len) break; | ||
328 | if (cp->c_data_ptr[idx] == | ||
329 | cp->sync_key_ptr[cp->sync_buf_offs]) { | ||
330 | // Found the next key byte | ||
331 | (cp->sync_buf_offs)++; | ||
332 | } else { | ||
333 | // Whoops, mismatched. Start key over... | ||
334 | cp->sync_buf_offs = 0; | ||
335 | } | ||
336 | } | ||
337 | |||
338 | // Consume what we've walked through | ||
339 | cp->c_data_offs += idx; | ||
340 | cp->sync_trashed_count += idx; | ||
341 | |||
342 | // If we've found the key, then update state and get out. | ||
343 | if (cp->sync_buf_offs >= cp->sync_key_len) { | ||
344 | cp->sync_trashed_count -= cp->sync_key_len; | ||
345 | pvr2_trace(PVR2_TRACE_DATA_FLOW, | ||
346 | "/*---TRACE_READ---*/" | ||
347 | " sync_state <== 2 (skipped %u bytes)", | ||
348 | cp->sync_trashed_count); | ||
349 | cp->sync_state = 2; | ||
350 | cp->sync_buf_offs = 0; | ||
351 | break; | ||
352 | } | ||
353 | |||
354 | if (cp->c_data_offs < cp->c_data_len) { | ||
355 | // Sanity check - should NEVER get here | ||
356 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, | ||
357 | "ERROR: pvr2_ioread filter sync problem" | ||
358 | " len=%u offs=%u", | ||
359 | cp->c_data_len,cp->c_data_offs); | ||
360 | // Get out so we don't get stuck in an infinite | ||
361 | // loop. | ||
362 | break; | ||
363 | } | ||
364 | |||
365 | continue; // (for clarity) | ||
366 | } mutex_unlock(&cp->mutex); | ||
367 | } | ||
368 | |||
369 | int pvr2_ioread_avail(struct pvr2_ioread *cp) | ||
370 | { | ||
371 | int ret; | ||
372 | if (!(cp->enabled)) { | ||
373 | // Stream is not enabled; so this is an I/O error | ||
374 | return -EIO; | ||
375 | } | ||
376 | |||
377 | if (cp->sync_state == 1) { | ||
378 | pvr2_ioread_filter(cp); | ||
379 | if (cp->sync_state == 1) return -EAGAIN; | ||
380 | } | ||
381 | |||
382 | ret = 0; | ||
383 | if (cp->stream_running) { | ||
384 | if (!pvr2_stream_get_ready_count(cp->stream)) { | ||
385 | // No data available at all right now. | ||
386 | ret = -EAGAIN; | ||
387 | } | ||
388 | } else { | ||
389 | if (pvr2_stream_get_ready_count(cp->stream) < BUFFER_COUNT/2) { | ||
390 | // Haven't buffered up enough yet; try again later | ||
391 | ret = -EAGAIN; | ||
392 | } | ||
393 | } | ||
394 | |||
395 | if ((!(cp->spigot_open)) != (!(ret == 0))) { | ||
396 | cp->spigot_open = (ret == 0); | ||
397 | pvr2_trace(PVR2_TRACE_DATA_FLOW, | ||
398 | "/*---TRACE_READ---*/ data is %s", | ||
399 | cp->spigot_open ? "available" : "pending"); | ||
400 | } | ||
401 | |||
402 | return ret; | ||
403 | } | ||
404 | |||
405 | int pvr2_ioread_read(struct pvr2_ioread *cp,void __user *buf,unsigned int cnt) | ||
406 | { | ||
407 | unsigned int copied_cnt; | ||
408 | unsigned int bcnt; | ||
409 | const char *src; | ||
410 | int stat; | ||
411 | int ret = 0; | ||
412 | unsigned int req_cnt = cnt; | ||
413 | |||
414 | if (!cnt) { | ||
415 | pvr2_trace(PVR2_TRACE_TRAP, | ||
416 | "/*---TRACE_READ---*/ pvr2_ioread_read id=%p" | ||
417 | " ZERO Request? Returning zero.",cp); | ||
418 | return 0; | ||
419 | } | ||
420 | |||
421 | stat = pvr2_ioread_avail(cp); | ||
422 | if (stat < 0) return stat; | ||
423 | |||
424 | cp->stream_running = !0; | ||
425 | |||
426 | mutex_lock(&cp->mutex); do { | ||
427 | |||
428 | // Suck data out of the buffers and copy to the user | ||
429 | copied_cnt = 0; | ||
430 | if (!buf) cnt = 0; | ||
431 | while (1) { | ||
432 | if (!pvr2_ioread_get_buffer(cp)) { | ||
433 | ret = -EIO; | ||
434 | break; | ||
435 | } | ||
436 | |||
437 | if (!cnt) break; | ||
438 | |||
439 | if (cp->sync_state == 2) { | ||
440 | // We're repeating the sync key data into | ||
441 | // the stream. | ||
442 | src = cp->sync_key_ptr + cp->sync_buf_offs; | ||
443 | bcnt = cp->sync_key_len - cp->sync_buf_offs; | ||
444 | } else { | ||
445 | // Normal buffer copy | ||
446 | src = cp->c_data_ptr + cp->c_data_offs; | ||
447 | bcnt = cp->c_data_len - cp->c_data_offs; | ||
448 | } | ||
449 | |||
450 | if (!bcnt) break; | ||
451 | |||
452 | // Don't run past user's buffer | ||
453 | if (bcnt > cnt) bcnt = cnt; | ||
454 | |||
455 | if (copy_to_user(buf,src,bcnt)) { | ||
456 | // User supplied a bad pointer? | ||
457 | // Give up - this *will* cause data | ||
458 | // to be lost. | ||
459 | ret = -EFAULT; | ||
460 | break; | ||
461 | } | ||
462 | cnt -= bcnt; | ||
463 | buf += bcnt; | ||
464 | copied_cnt += bcnt; | ||
465 | |||
466 | if (cp->sync_state == 2) { | ||
467 | // Update offset inside sync key that we're | ||
468 | // repeating back out. | ||
469 | cp->sync_buf_offs += bcnt; | ||
470 | if (cp->sync_buf_offs >= cp->sync_key_len) { | ||
471 | // Consumed entire key; switch mode | ||
472 | // to normal. | ||
473 | pvr2_trace(PVR2_TRACE_DATA_FLOW, | ||
474 | "/*---TRACE_READ---*/" | ||
475 | " sync_state <== 0"); | ||
476 | cp->sync_state = 0; | ||
477 | } | ||
478 | } else { | ||
479 | // Update buffer offset. | ||
480 | cp->c_data_offs += bcnt; | ||
481 | } | ||
482 | } | ||
483 | |||
484 | } while (0); mutex_unlock(&cp->mutex); | ||
485 | |||
486 | if (!ret) { | ||
487 | if (copied_cnt) { | ||
488 | // If anything was copied, return that count | ||
489 | ret = copied_cnt; | ||
490 | } else { | ||
491 | // Nothing copied; suggest to caller that another | ||
492 | // attempt should be tried again later | ||
493 | ret = -EAGAIN; | ||
494 | } | ||
495 | } | ||
496 | |||
497 | pvr2_trace(PVR2_TRACE_DATA_FLOW, | ||
498 | "/*---TRACE_READ---*/ pvr2_ioread_read" | ||
499 | " id=%p request=%d result=%d", | ||
500 | cp,req_cnt,ret); | ||
501 | return ret; | ||
502 | } | ||
503 | |||
504 | |||
505 | /* | ||
506 | Stuff for Emacs to see, in order to encourage consistent editing style: | ||
507 | *** Local Variables: *** | ||
508 | *** mode: c *** | ||
509 | *** fill-column: 75 *** | ||
510 | *** tab-width: 8 *** | ||
511 | *** c-basic-offset: 8 *** | ||
512 | *** End: *** | ||
513 | */ | ||
diff --git a/drivers/media/video/pvrusb2/pvrusb2-ioread.h b/drivers/media/video/pvrusb2/pvrusb2-ioread.h new file mode 100644 index 000000000000..6b002597f5de --- /dev/null +++ b/drivers/media/video/pvrusb2/pvrusb2-ioread.h | |||
@@ -0,0 +1,50 @@ | |||
1 | /* | ||
2 | * | ||
3 | * $Id$ | ||
4 | * | ||
5 | * Copyright (C) 2005 Mike Isely <isely@pobox.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 | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | * | ||
20 | */ | ||
21 | #ifndef __PVRUSB2_IOREAD_H | ||
22 | #define __PVRUSB2_IOREAD_H | ||
23 | |||
24 | #include "pvrusb2-io.h" | ||
25 | |||
26 | struct pvr2_ioread; | ||
27 | |||
28 | struct pvr2_ioread *pvr2_ioread_create(void); | ||
29 | void pvr2_ioread_destroy(struct pvr2_ioread *); | ||
30 | int pvr2_ioread_setup(struct pvr2_ioread *,struct pvr2_stream *); | ||
31 | struct pvr2_stream *pvr2_ioread_get_stream(struct pvr2_ioread *); | ||
32 | void pvr2_ioread_set_sync_key(struct pvr2_ioread *, | ||
33 | const char *sync_key_ptr, | ||
34 | unsigned int sync_key_len); | ||
35 | int pvr2_ioread_set_enabled(struct pvr2_ioread *,int fl); | ||
36 | int pvr2_ioread_get_enabled(struct pvr2_ioread *); | ||
37 | int pvr2_ioread_read(struct pvr2_ioread *,void __user *buf,unsigned int cnt); | ||
38 | int pvr2_ioread_avail(struct pvr2_ioread *); | ||
39 | |||
40 | #endif /* __PVRUSB2_IOREAD_H */ | ||
41 | |||
42 | /* | ||
43 | Stuff for Emacs to see, in order to encourage consistent editing style: | ||
44 | *** Local Variables: *** | ||
45 | *** mode: c *** | ||
46 | *** fill-column: 75 *** | ||
47 | *** tab-width: 8 *** | ||
48 | *** c-basic-offset: 8 *** | ||
49 | *** End: *** | ||
50 | */ | ||
diff --git a/drivers/media/video/pvrusb2/pvrusb2-main.c b/drivers/media/video/pvrusb2/pvrusb2-main.c new file mode 100644 index 000000000000..b95248274ed0 --- /dev/null +++ b/drivers/media/video/pvrusb2/pvrusb2-main.c | |||
@@ -0,0 +1,172 @@ | |||
1 | /* | ||
2 | * | ||
3 | * $Id$ | ||
4 | * | ||
5 | * Copyright (C) 2005 Mike Isely <isely@pobox.com> | ||
6 | * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License | ||
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 | |||
23 | #include <linux/config.h> | ||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/errno.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/module.h> | ||
28 | #include <linux/moduleparam.h> | ||
29 | #include <linux/smp_lock.h> | ||
30 | #include <linux/usb.h> | ||
31 | #include <linux/videodev2.h> | ||
32 | |||
33 | #include "pvrusb2-hdw.h" | ||
34 | #include "pvrusb2-context.h" | ||
35 | #include "pvrusb2-debug.h" | ||
36 | #include "pvrusb2-v4l2.h" | ||
37 | #ifdef CONFIG_VIDEO_PVRUSB2_SYSFS | ||
38 | #include "pvrusb2-sysfs.h" | ||
39 | #endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */ | ||
40 | |||
41 | #define DRIVER_AUTHOR "Mike Isely <isely@pobox.com>" | ||
42 | #define DRIVER_DESC "Hauppauge WinTV-PVR-USB2 MPEG2 Encoder/Tuner" | ||
43 | #define DRIVER_VERSION "V4L in-tree version" | ||
44 | |||
45 | #define DEFAULT_DEBUG_MASK (PVR2_TRACE_ERROR_LEGS| \ | ||
46 | PVR2_TRACE_INFO| \ | ||
47 | PVR2_TRACE_TOLERANCE| \ | ||
48 | PVR2_TRACE_TRAP| \ | ||
49 | 0) | ||
50 | |||
51 | int pvrusb2_debug = DEFAULT_DEBUG_MASK; | ||
52 | |||
53 | module_param_named(debug,pvrusb2_debug,int,S_IRUGO|S_IWUSR); | ||
54 | MODULE_PARM_DESC(debug, "Debug trace mask"); | ||
55 | |||
56 | #ifdef CONFIG_VIDEO_PVRUSB2_SYSFS | ||
57 | static struct pvr2_sysfs_class *class_ptr = 0; | ||
58 | #endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */ | ||
59 | |||
60 | static void pvr_setup_attach(struct pvr2_context *pvr) | ||
61 | { | ||
62 | /* Create association with v4l layer */ | ||
63 | pvr2_v4l2_create(pvr); | ||
64 | #ifdef CONFIG_VIDEO_PVRUSB2_SYSFS | ||
65 | pvr2_sysfs_create(pvr,class_ptr); | ||
66 | #endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */ | ||
67 | } | ||
68 | |||
69 | static int pvr_probe(struct usb_interface *intf, | ||
70 | const struct usb_device_id *devid) | ||
71 | { | ||
72 | struct pvr2_context *pvr; | ||
73 | |||
74 | /* Create underlying hardware interface */ | ||
75 | pvr = pvr2_context_create(intf,devid,pvr_setup_attach); | ||
76 | if (!pvr) { | ||
77 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, | ||
78 | "Failed to create hdw handler"); | ||
79 | return -ENOMEM; | ||
80 | } | ||
81 | |||
82 | pvr2_trace(PVR2_TRACE_INIT,"pvr_probe(pvr=%p)",pvr); | ||
83 | |||
84 | usb_set_intfdata(intf, pvr); | ||
85 | |||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | /* | ||
90 | * pvr_disconnect() | ||
91 | * | ||
92 | */ | ||
93 | static void pvr_disconnect(struct usb_interface *intf) | ||
94 | { | ||
95 | struct pvr2_context *pvr = usb_get_intfdata(intf); | ||
96 | |||
97 | pvr2_trace(PVR2_TRACE_INIT,"pvr_disconnect(pvr=%p) BEGIN",pvr); | ||
98 | |||
99 | usb_set_intfdata (intf, NULL); | ||
100 | pvr2_context_disconnect(pvr); | ||
101 | |||
102 | pvr2_trace(PVR2_TRACE_INIT,"pvr_disconnect(pvr=%p) DONE",pvr); | ||
103 | |||
104 | } | ||
105 | |||
106 | static struct usb_driver pvr_driver = { | ||
107 | name: "pvrusb2", | ||
108 | id_table: pvr2_device_table, | ||
109 | probe: pvr_probe, | ||
110 | disconnect: pvr_disconnect | ||
111 | }; | ||
112 | |||
113 | /* | ||
114 | * pvr_init() / pvr_exit() | ||
115 | * | ||
116 | * This code is run to initialize/exit the driver. | ||
117 | * | ||
118 | */ | ||
119 | static int __init pvr_init(void) | ||
120 | { | ||
121 | int ret; | ||
122 | |||
123 | pvr2_trace(PVR2_TRACE_INIT,"pvr_init"); | ||
124 | |||
125 | #ifdef CONFIG_VIDEO_PVRUSB2_SYSFS | ||
126 | class_ptr = pvr2_sysfs_class_create(); | ||
127 | #endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */ | ||
128 | |||
129 | ret = usb_register(&pvr_driver); | ||
130 | |||
131 | if (ret == 0) | ||
132 | info(DRIVER_DESC " : " DRIVER_VERSION); | ||
133 | if (pvrusb2_debug) info("Debug mask is %d (0x%x)", | ||
134 | pvrusb2_debug,pvrusb2_debug); | ||
135 | |||
136 | return ret; | ||
137 | } | ||
138 | |||
139 | static void __exit pvr_exit(void) | ||
140 | { | ||
141 | |||
142 | pvr2_trace(PVR2_TRACE_INIT,"pvr_exit"); | ||
143 | |||
144 | #ifdef CONFIG_VIDEO_PVRUSB2_SYSFS | ||
145 | pvr2_sysfs_class_destroy(class_ptr); | ||
146 | #endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */ | ||
147 | |||
148 | usb_deregister(&pvr_driver); | ||
149 | } | ||
150 | |||
151 | module_init(pvr_init); | ||
152 | module_exit(pvr_exit); | ||
153 | |||
154 | /* Mike Isely <mcisely@pobox.com> 11-Mar-2006: See pvrusb2-hdw.c for | ||
155 | MODULE_DEVICE_TABLE(). We have to declare that attribute there | ||
156 | because that's where the device table actually is now and it seems | ||
157 | that certain gcc configurations get angry if MODULE_DEVICE_TABLE() | ||
158 | is used on what ends up being an external symbol. */ | ||
159 | MODULE_AUTHOR(DRIVER_AUTHOR); | ||
160 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
161 | MODULE_LICENSE("GPL"); | ||
162 | |||
163 | |||
164 | /* | ||
165 | Stuff for Emacs to see, in order to encourage consistent editing style: | ||
166 | *** Local Variables: *** | ||
167 | *** mode: c *** | ||
168 | *** fill-column: 70 *** | ||
169 | *** tab-width: 8 *** | ||
170 | *** c-basic-offset: 8 *** | ||
171 | *** End: *** | ||
172 | */ | ||
diff --git a/drivers/media/video/pvrusb2/pvrusb2-std.c b/drivers/media/video/pvrusb2/pvrusb2-std.c new file mode 100644 index 000000000000..134063693643 --- /dev/null +++ b/drivers/media/video/pvrusb2/pvrusb2-std.c | |||
@@ -0,0 +1,408 @@ | |||
1 | /* | ||
2 | * | ||
3 | * $Id$ | ||
4 | * | ||
5 | * Copyright (C) 2005 Mike Isely <isely@pobox.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 | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include "pvrusb2-std.h" | ||
23 | #include "pvrusb2-debug.h" | ||
24 | #include <asm/string.h> | ||
25 | #include <linux/slab.h> | ||
26 | |||
27 | struct std_name { | ||
28 | const char *name; | ||
29 | v4l2_std_id id; | ||
30 | }; | ||
31 | |||
32 | |||
33 | #define CSTD_PAL \ | ||
34 | (V4L2_STD_PAL_B| \ | ||
35 | V4L2_STD_PAL_B1| \ | ||
36 | V4L2_STD_PAL_G| \ | ||
37 | V4L2_STD_PAL_H| \ | ||
38 | V4L2_STD_PAL_I| \ | ||
39 | V4L2_STD_PAL_D| \ | ||
40 | V4L2_STD_PAL_D1| \ | ||
41 | V4L2_STD_PAL_K| \ | ||
42 | V4L2_STD_PAL_M| \ | ||
43 | V4L2_STD_PAL_N| \ | ||
44 | V4L2_STD_PAL_Nc| \ | ||
45 | V4L2_STD_PAL_60) | ||
46 | |||
47 | #define CSTD_NTSC \ | ||
48 | (V4L2_STD_NTSC_M| \ | ||
49 | V4L2_STD_NTSC_M_JP| \ | ||
50 | V4L2_STD_NTSC_M_KR| \ | ||
51 | V4L2_STD_NTSC_443) | ||
52 | |||
53 | #define CSTD_SECAM \ | ||
54 | (V4L2_STD_SECAM_B| \ | ||
55 | V4L2_STD_SECAM_D| \ | ||
56 | V4L2_STD_SECAM_G| \ | ||
57 | V4L2_STD_SECAM_H| \ | ||
58 | V4L2_STD_SECAM_K| \ | ||
59 | V4L2_STD_SECAM_K1| \ | ||
60 | V4L2_STD_SECAM_L| \ | ||
61 | V4L2_STD_SECAM_LC) | ||
62 | |||
63 | #define TSTD_B (V4L2_STD_PAL_B|V4L2_STD_SECAM_B) | ||
64 | #define TSTD_B1 (V4L2_STD_PAL_B1) | ||
65 | #define TSTD_D (V4L2_STD_PAL_D|V4L2_STD_SECAM_D) | ||
66 | #define TSTD_D1 (V4L2_STD_PAL_D1) | ||
67 | #define TSTD_G (V4L2_STD_PAL_G|V4L2_STD_SECAM_G) | ||
68 | #define TSTD_H (V4L2_STD_PAL_H|V4L2_STD_SECAM_H) | ||
69 | #define TSTD_I (V4L2_STD_PAL_I) | ||
70 | #define TSTD_K (V4L2_STD_PAL_K|V4L2_STD_SECAM_K) | ||
71 | #define TSTD_K1 (V4L2_STD_SECAM_K1) | ||
72 | #define TSTD_L (V4L2_STD_SECAM_L) | ||
73 | #define TSTD_M (V4L2_STD_PAL_M|V4L2_STD_NTSC_M) | ||
74 | #define TSTD_N (V4L2_STD_PAL_N) | ||
75 | #define TSTD_Nc (V4L2_STD_PAL_Nc) | ||
76 | #define TSTD_60 (V4L2_STD_PAL_60) | ||
77 | |||
78 | #define CSTD_ALL (CSTD_PAL|CSTD_NTSC|CSTD_SECAM) | ||
79 | |||
80 | /* Mapping of standard bits to color system */ | ||
81 | const static struct std_name std_groups[] = { | ||
82 | {"PAL",CSTD_PAL}, | ||
83 | {"NTSC",CSTD_NTSC}, | ||
84 | {"SECAM",CSTD_SECAM}, | ||
85 | }; | ||
86 | |||
87 | /* Mapping of standard bits to modulation system */ | ||
88 | const static struct std_name std_items[] = { | ||
89 | {"B",TSTD_B}, | ||
90 | {"B1",TSTD_B1}, | ||
91 | {"D",TSTD_D}, | ||
92 | {"D1",TSTD_D1}, | ||
93 | {"G",TSTD_G}, | ||
94 | {"H",TSTD_H}, | ||
95 | {"I",TSTD_I}, | ||
96 | {"K",TSTD_K}, | ||
97 | {"K1",TSTD_K1}, | ||
98 | {"L",TSTD_L}, | ||
99 | {"LC",V4L2_STD_SECAM_LC}, | ||
100 | {"M",TSTD_M}, | ||
101 | {"Mj",V4L2_STD_NTSC_M_JP}, | ||
102 | {"443",V4L2_STD_NTSC_443}, | ||
103 | {"Mk",V4L2_STD_NTSC_M_KR}, | ||
104 | {"N",TSTD_N}, | ||
105 | {"Nc",TSTD_Nc}, | ||
106 | {"60",TSTD_60}, | ||
107 | }; | ||
108 | |||
109 | |||
110 | // Search an array of std_name structures and return a pointer to the | ||
111 | // element with the matching name. | ||
112 | static const struct std_name *find_std_name(const struct std_name *arrPtr, | ||
113 | unsigned int arrSize, | ||
114 | const char *bufPtr, | ||
115 | unsigned int bufSize) | ||
116 | { | ||
117 | unsigned int idx; | ||
118 | const struct std_name *p; | ||
119 | for (idx = 0; idx < arrSize; idx++) { | ||
120 | p = arrPtr + idx; | ||
121 | if (strlen(p->name) != bufSize) continue; | ||
122 | if (!memcmp(bufPtr,p->name,bufSize)) return p; | ||
123 | } | ||
124 | return 0; | ||
125 | } | ||
126 | |||
127 | |||
128 | int pvr2_std_str_to_id(v4l2_std_id *idPtr,const char *bufPtr, | ||
129 | unsigned int bufSize) | ||
130 | { | ||
131 | v4l2_std_id id = 0; | ||
132 | v4l2_std_id cmsk = 0; | ||
133 | v4l2_std_id t; | ||
134 | int mMode = 0; | ||
135 | unsigned int cnt; | ||
136 | char ch; | ||
137 | const struct std_name *sp; | ||
138 | |||
139 | while (bufSize) { | ||
140 | if (!mMode) { | ||
141 | cnt = 0; | ||
142 | while ((cnt < bufSize) && (bufPtr[cnt] != '-')) cnt++; | ||
143 | if (cnt >= bufSize) return 0; // No more characters | ||
144 | sp = find_std_name( | ||
145 | std_groups, | ||
146 | sizeof(std_groups)/sizeof(std_groups[0]), | ||
147 | bufPtr,cnt); | ||
148 | if (!sp) return 0; // Illegal color system name | ||
149 | cnt++; | ||
150 | bufPtr += cnt; | ||
151 | bufSize -= cnt; | ||
152 | mMode = !0; | ||
153 | cmsk = sp->id; | ||
154 | continue; | ||
155 | } | ||
156 | cnt = 0; | ||
157 | while (cnt < bufSize) { | ||
158 | ch = bufPtr[cnt]; | ||
159 | if (ch == ';') { | ||
160 | mMode = 0; | ||
161 | break; | ||
162 | } | ||
163 | if (ch == '/') break; | ||
164 | cnt++; | ||
165 | } | ||
166 | sp = find_std_name(std_items, | ||
167 | sizeof(std_items)/sizeof(std_items[0]), | ||
168 | bufPtr,cnt); | ||
169 | if (!sp) return 0; // Illegal modulation system ID | ||
170 | t = sp->id & cmsk; | ||
171 | if (!t) return 0; // Specific color + modulation system illegal | ||
172 | id |= t; | ||
173 | if (cnt < bufSize) cnt++; | ||
174 | bufPtr += cnt; | ||
175 | bufSize -= cnt; | ||
176 | } | ||
177 | |||
178 | if (idPtr) *idPtr = id; | ||
179 | return !0; | ||
180 | } | ||
181 | |||
182 | |||
183 | unsigned int pvr2_std_id_to_str(char *bufPtr, unsigned int bufSize, | ||
184 | v4l2_std_id id) | ||
185 | { | ||
186 | unsigned int idx1,idx2; | ||
187 | const struct std_name *ip,*gp; | ||
188 | int gfl,cfl; | ||
189 | unsigned int c1,c2; | ||
190 | cfl = 0; | ||
191 | c1 = 0; | ||
192 | for (idx1 = 0; | ||
193 | idx1 < sizeof(std_groups)/sizeof(std_groups[0]); | ||
194 | idx1++) { | ||
195 | gp = std_groups + idx1; | ||
196 | gfl = 0; | ||
197 | for (idx2 = 0; | ||
198 | idx2 < sizeof(std_items)/sizeof(std_items[0]); | ||
199 | idx2++) { | ||
200 | ip = std_items + idx2; | ||
201 | if (!(gp->id & ip->id & id)) continue; | ||
202 | if (!gfl) { | ||
203 | if (cfl) { | ||
204 | c2 = scnprintf(bufPtr,bufSize,";"); | ||
205 | c1 += c2; | ||
206 | bufSize -= c2; | ||
207 | bufPtr += c2; | ||
208 | } | ||
209 | cfl = !0; | ||
210 | c2 = scnprintf(bufPtr,bufSize, | ||
211 | "%s-",gp->name); | ||
212 | gfl = !0; | ||
213 | } else { | ||
214 | c2 = scnprintf(bufPtr,bufSize,"/"); | ||
215 | } | ||
216 | c1 += c2; | ||
217 | bufSize -= c2; | ||
218 | bufPtr += c2; | ||
219 | c2 = scnprintf(bufPtr,bufSize, | ||
220 | ip->name); | ||
221 | c1 += c2; | ||
222 | bufSize -= c2; | ||
223 | bufPtr += c2; | ||
224 | } | ||
225 | } | ||
226 | return c1; | ||
227 | } | ||
228 | |||
229 | |||
230 | // Template data for possible enumerated video standards. Here we group | ||
231 | // standards which share common frame rates and resolution. | ||
232 | static struct v4l2_standard generic_standards[] = { | ||
233 | { | ||
234 | .id = (TSTD_B|TSTD_B1| | ||
235 | TSTD_D|TSTD_D1| | ||
236 | TSTD_G| | ||
237 | TSTD_H| | ||
238 | TSTD_I| | ||
239 | TSTD_K|TSTD_K1| | ||
240 | TSTD_L| | ||
241 | V4L2_STD_SECAM_LC | | ||
242 | TSTD_N|TSTD_Nc), | ||
243 | .frameperiod = | ||
244 | { | ||
245 | .numerator = 1, | ||
246 | .denominator= 25 | ||
247 | }, | ||
248 | .framelines = 625, | ||
249 | .reserved = {0,0,0,0} | ||
250 | }, { | ||
251 | .id = (TSTD_M| | ||
252 | V4L2_STD_NTSC_M_JP| | ||
253 | V4L2_STD_NTSC_M_KR), | ||
254 | .frameperiod = | ||
255 | { | ||
256 | .numerator = 1001, | ||
257 | .denominator= 30000 | ||
258 | }, | ||
259 | .framelines = 525, | ||
260 | .reserved = {0,0,0,0} | ||
261 | }, { // This is a total wild guess | ||
262 | .id = (TSTD_60), | ||
263 | .frameperiod = | ||
264 | { | ||
265 | .numerator = 1001, | ||
266 | .denominator= 30000 | ||
267 | }, | ||
268 | .framelines = 525, | ||
269 | .reserved = {0,0,0,0} | ||
270 | }, { // This is total wild guess | ||
271 | .id = V4L2_STD_NTSC_443, | ||
272 | .frameperiod = | ||
273 | { | ||
274 | .numerator = 1001, | ||
275 | .denominator= 30000 | ||
276 | }, | ||
277 | .framelines = 525, | ||
278 | .reserved = {0,0,0,0} | ||
279 | } | ||
280 | }; | ||
281 | |||
282 | #define generic_standards_cnt (sizeof(generic_standards)/sizeof(generic_standards[0])) | ||
283 | |||
284 | static struct v4l2_standard *match_std(v4l2_std_id id) | ||
285 | { | ||
286 | unsigned int idx; | ||
287 | for (idx = 0; idx < generic_standards_cnt; idx++) { | ||
288 | if (generic_standards[idx].id & id) { | ||
289 | return generic_standards + idx; | ||
290 | } | ||
291 | } | ||
292 | return 0; | ||
293 | } | ||
294 | |||
295 | static int pvr2_std_fill(struct v4l2_standard *std,v4l2_std_id id) | ||
296 | { | ||
297 | struct v4l2_standard *template; | ||
298 | int idx; | ||
299 | unsigned int bcnt; | ||
300 | template = match_std(id); | ||
301 | if (!template) return 0; | ||
302 | idx = std->index; | ||
303 | memcpy(std,template,sizeof(*template)); | ||
304 | std->index = idx; | ||
305 | std->id = id; | ||
306 | bcnt = pvr2_std_id_to_str(std->name,sizeof(std->name)-1,id); | ||
307 | std->name[bcnt] = 0; | ||
308 | pvr2_trace(PVR2_TRACE_INIT,"Set up standard idx=%u name=%s", | ||
309 | std->index,std->name); | ||
310 | return !0; | ||
311 | } | ||
312 | |||
313 | /* These are special cases of combined standards that we should enumerate | ||
314 | separately if the component pieces are present. */ | ||
315 | static v4l2_std_id std_mixes[] = { | ||
316 | V4L2_STD_PAL_B | V4L2_STD_PAL_G, | ||
317 | V4L2_STD_PAL_D | V4L2_STD_PAL_K, | ||
318 | V4L2_STD_SECAM_B | V4L2_STD_SECAM_G, | ||
319 | V4L2_STD_SECAM_D | V4L2_STD_SECAM_K, | ||
320 | }; | ||
321 | |||
322 | struct v4l2_standard *pvr2_std_create_enum(unsigned int *countptr, | ||
323 | v4l2_std_id id) | ||
324 | { | ||
325 | unsigned int std_cnt = 0; | ||
326 | unsigned int idx,bcnt,idx2; | ||
327 | v4l2_std_id idmsk,cmsk,fmsk; | ||
328 | struct v4l2_standard *stddefs; | ||
329 | |||
330 | if (pvrusb2_debug & PVR2_TRACE_INIT) { | ||
331 | char buf[50]; | ||
332 | bcnt = pvr2_std_id_to_str(buf,sizeof(buf),id); | ||
333 | pvr2_trace( | ||
334 | PVR2_TRACE_INIT,"Mapping standards mask=0x%x (%.*s)", | ||
335 | (int)id,bcnt,buf); | ||
336 | } | ||
337 | |||
338 | *countptr = 0; | ||
339 | std_cnt = 0; | ||
340 | fmsk = 0; | ||
341 | for (idmsk = 1, cmsk = id; cmsk; idmsk <<= 1) { | ||
342 | if (!(idmsk & cmsk)) continue; | ||
343 | cmsk &= ~idmsk; | ||
344 | if (match_std(idmsk)) { | ||
345 | std_cnt++; | ||
346 | continue; | ||
347 | } | ||
348 | fmsk |= idmsk; | ||
349 | } | ||
350 | |||
351 | for (idx2 = 0; idx2 < sizeof(std_mixes)/sizeof(std_mixes[0]); idx2++) { | ||
352 | if ((id & std_mixes[idx2]) == std_mixes[idx2]) std_cnt++; | ||
353 | } | ||
354 | |||
355 | if (fmsk) { | ||
356 | char buf[50]; | ||
357 | bcnt = pvr2_std_id_to_str(buf,sizeof(buf),fmsk); | ||
358 | pvr2_trace( | ||
359 | PVR2_TRACE_ERROR_LEGS, | ||
360 | "WARNING:" | ||
361 | " Failed to classify the following standard(s): %.*s", | ||
362 | bcnt,buf); | ||
363 | } | ||
364 | |||
365 | pvr2_trace(PVR2_TRACE_INIT,"Setting up %u unique standard(s)", | ||
366 | std_cnt); | ||
367 | if (!std_cnt) return 0; // paranoia | ||
368 | |||
369 | stddefs = kmalloc(sizeof(struct v4l2_standard) * std_cnt, | ||
370 | GFP_KERNEL); | ||
371 | memset(stddefs,0,sizeof(struct v4l2_standard) * std_cnt); | ||
372 | for (idx = 0; idx < std_cnt; idx++) stddefs[idx].index = idx; | ||
373 | |||
374 | idx = 0; | ||
375 | |||
376 | /* Enumerate potential special cases */ | ||
377 | for (idx2 = 0; ((idx2 < sizeof(std_mixes)/sizeof(std_mixes[0])) && | ||
378 | (idx < std_cnt)); idx2++) { | ||
379 | if (!(id & std_mixes[idx2])) continue; | ||
380 | if (pvr2_std_fill(stddefs+idx,std_mixes[idx2])) idx++; | ||
381 | } | ||
382 | /* Now enumerate individual pieces */ | ||
383 | for (idmsk = 1, cmsk = id; cmsk && (idx < std_cnt); idmsk <<= 1) { | ||
384 | if (!(idmsk & cmsk)) continue; | ||
385 | cmsk &= ~idmsk; | ||
386 | if (!pvr2_std_fill(stddefs+idx,idmsk)) continue; | ||
387 | idx++; | ||
388 | } | ||
389 | |||
390 | *countptr = std_cnt; | ||
391 | return stddefs; | ||
392 | } | ||
393 | |||
394 | v4l2_std_id pvr2_std_get_usable(void) | ||
395 | { | ||
396 | return CSTD_ALL; | ||
397 | } | ||
398 | |||
399 | |||
400 | /* | ||
401 | Stuff for Emacs to see, in order to encourage consistent editing style: | ||
402 | *** Local Variables: *** | ||
403 | *** mode: c *** | ||
404 | *** fill-column: 75 *** | ||
405 | *** tab-width: 8 *** | ||
406 | *** c-basic-offset: 8 *** | ||
407 | *** End: *** | ||
408 | */ | ||
diff --git a/drivers/media/video/pvrusb2/pvrusb2-std.h b/drivers/media/video/pvrusb2/pvrusb2-std.h new file mode 100644 index 000000000000..07c399375341 --- /dev/null +++ b/drivers/media/video/pvrusb2/pvrusb2-std.h | |||
@@ -0,0 +1,60 @@ | |||
1 | /* | ||
2 | * | ||
3 | * $Id$ | ||
4 | * | ||
5 | * Copyright (C) 2005 Mike Isely <isely@pobox.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 | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | * | ||
20 | */ | ||
21 | #ifndef __PVRUSB2_STD_H | ||
22 | #define __PVRUSB2_STD_H | ||
23 | |||
24 | #include <linux/videodev2.h> | ||
25 | |||
26 | // Convert string describing one or more video standards into a mask of V4L | ||
27 | // standard bits. Return true if conversion succeeds otherwise return | ||
28 | // false. String is expected to be of the form: C1-x/y;C2-a/b where C1 and | ||
29 | // C2 are color system names (e.g. "PAL", "NTSC") and x, y, a, and b are | ||
30 | // modulation schemes (e.g. "M", "B", "G", etc). | ||
31 | int pvr2_std_str_to_id(v4l2_std_id *idPtr,const char *bufPtr, | ||
32 | unsigned int bufSize); | ||
33 | |||
34 | // Convert any arbitrary set of video standard bits into an unambiguous | ||
35 | // readable string. Return value is the number of bytes consumed in the | ||
36 | // buffer. The formatted string is of a form that can be parsed by our | ||
37 | // sibling std_std_to_id() function. | ||
38 | unsigned int pvr2_std_id_to_str(char *bufPtr, unsigned int bufSize, | ||
39 | v4l2_std_id id); | ||
40 | |||
41 | // Create an array of suitable v4l2_standard structures given a bit mask of | ||
42 | // video standards to support. The array is allocated from the heap, and | ||
43 | // the number of elements is returned in the first argument. | ||
44 | struct v4l2_standard *pvr2_std_create_enum(unsigned int *countptr, | ||
45 | v4l2_std_id id); | ||
46 | |||
47 | // Return mask of which video standard bits are valid | ||
48 | v4l2_std_id pvr2_std_get_usable(void); | ||
49 | |||
50 | #endif /* __PVRUSB2_STD_H */ | ||
51 | |||
52 | /* | ||
53 | Stuff for Emacs to see, in order to encourage consistent editing style: | ||
54 | *** Local Variables: *** | ||
55 | *** mode: c *** | ||
56 | *** fill-column: 75 *** | ||
57 | *** tab-width: 8 *** | ||
58 | *** c-basic-offset: 8 *** | ||
59 | *** End: *** | ||
60 | */ | ||
diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c new file mode 100644 index 000000000000..c6e6523d74b4 --- /dev/null +++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c | |||
@@ -0,0 +1,865 @@ | |||
1 | /* | ||
2 | * | ||
3 | * $Id$ | ||
4 | * | ||
5 | * Copyright (C) 2005 Mike Isely <isely@pobox.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 | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include <linux/config.h> | ||
23 | #include <linux/string.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <asm/semaphore.h> | ||
26 | #include "pvrusb2-sysfs.h" | ||
27 | #include "pvrusb2-hdw.h" | ||
28 | #include "pvrusb2-debug.h" | ||
29 | #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC | ||
30 | #include "pvrusb2-debugifc.h" | ||
31 | #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ | ||
32 | |||
33 | #define pvr2_sysfs_trace(...) pvr2_trace(PVR2_TRACE_SYSFS,__VA_ARGS__) | ||
34 | |||
35 | struct pvr2_sysfs { | ||
36 | struct pvr2_channel channel; | ||
37 | struct class_device *class_dev; | ||
38 | #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC | ||
39 | struct pvr2_sysfs_debugifc *debugifc; | ||
40 | #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ | ||
41 | struct pvr2_sysfs_ctl_item *item_first; | ||
42 | struct pvr2_sysfs_ctl_item *item_last; | ||
43 | struct sysfs_ops kops; | ||
44 | struct kobj_type ktype; | ||
45 | struct class_device_attribute attr_v4l_minor_number; | ||
46 | struct class_device_attribute attr_unit_number; | ||
47 | }; | ||
48 | |||
49 | #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC | ||
50 | struct pvr2_sysfs_debugifc { | ||
51 | struct class_device_attribute attr_debugcmd; | ||
52 | struct class_device_attribute attr_debuginfo; | ||
53 | }; | ||
54 | #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ | ||
55 | |||
56 | struct pvr2_sysfs_ctl_item { | ||
57 | struct class_device_attribute attr_name; | ||
58 | struct class_device_attribute attr_type; | ||
59 | struct class_device_attribute attr_min; | ||
60 | struct class_device_attribute attr_max; | ||
61 | struct class_device_attribute attr_enum; | ||
62 | struct class_device_attribute attr_bits; | ||
63 | struct class_device_attribute attr_val; | ||
64 | struct class_device_attribute attr_custom; | ||
65 | struct pvr2_ctrl *cptr; | ||
66 | struct pvr2_sysfs *chptr; | ||
67 | struct pvr2_sysfs_ctl_item *item_next; | ||
68 | struct attribute *attr_gen[7]; | ||
69 | struct attribute_group grp; | ||
70 | char name[80]; | ||
71 | }; | ||
72 | |||
73 | struct pvr2_sysfs_class { | ||
74 | struct class class; | ||
75 | }; | ||
76 | |||
77 | static ssize_t show_name(int id,struct class_device *class_dev,char *buf) | ||
78 | { | ||
79 | struct pvr2_ctrl *cptr; | ||
80 | struct pvr2_sysfs *sfp; | ||
81 | const char *name; | ||
82 | |||
83 | sfp = (struct pvr2_sysfs *)class_dev->class_data; | ||
84 | if (!sfp) return -EINVAL; | ||
85 | cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); | ||
86 | if (!cptr) return -EINVAL; | ||
87 | |||
88 | name = pvr2_ctrl_get_desc(cptr); | ||
89 | pvr2_sysfs_trace("pvr2_sysfs(%p) show_name(cid=%d) is %s",sfp,id,name); | ||
90 | |||
91 | if (!name) return -EINVAL; | ||
92 | |||
93 | return scnprintf(buf,PAGE_SIZE,"%s\n",name); | ||
94 | } | ||
95 | |||
96 | static ssize_t show_type(int id,struct class_device *class_dev,char *buf) | ||
97 | { | ||
98 | struct pvr2_ctrl *cptr; | ||
99 | struct pvr2_sysfs *sfp; | ||
100 | const char *name; | ||
101 | enum pvr2_ctl_type tp; | ||
102 | |||
103 | sfp = (struct pvr2_sysfs *)class_dev->class_data; | ||
104 | if (!sfp) return -EINVAL; | ||
105 | cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); | ||
106 | if (!cptr) return -EINVAL; | ||
107 | |||
108 | tp = pvr2_ctrl_get_type(cptr); | ||
109 | switch (tp) { | ||
110 | case pvr2_ctl_int: name = "integer"; break; | ||
111 | case pvr2_ctl_enum: name = "enum"; break; | ||
112 | case pvr2_ctl_bitmask: name = "bitmask"; break; | ||
113 | case pvr2_ctl_bool: name = "boolean"; break; | ||
114 | default: name = "?"; break; | ||
115 | } | ||
116 | pvr2_sysfs_trace("pvr2_sysfs(%p) show_type(cid=%d) is %s",sfp,id,name); | ||
117 | |||
118 | if (!name) return -EINVAL; | ||
119 | |||
120 | return scnprintf(buf,PAGE_SIZE,"%s\n",name); | ||
121 | } | ||
122 | |||
123 | static ssize_t show_min(int id,struct class_device *class_dev,char *buf) | ||
124 | { | ||
125 | struct pvr2_ctrl *cptr; | ||
126 | struct pvr2_sysfs *sfp; | ||
127 | long val; | ||
128 | |||
129 | sfp = (struct pvr2_sysfs *)class_dev->class_data; | ||
130 | if (!sfp) return -EINVAL; | ||
131 | cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); | ||
132 | if (!cptr) return -EINVAL; | ||
133 | val = pvr2_ctrl_get_min(cptr); | ||
134 | |||
135 | pvr2_sysfs_trace("pvr2_sysfs(%p) show_min(cid=%d) is %ld",sfp,id,val); | ||
136 | |||
137 | return scnprintf(buf,PAGE_SIZE,"%ld\n",val); | ||
138 | } | ||
139 | |||
140 | static ssize_t show_max(int id,struct class_device *class_dev,char *buf) | ||
141 | { | ||
142 | struct pvr2_ctrl *cptr; | ||
143 | struct pvr2_sysfs *sfp; | ||
144 | long val; | ||
145 | |||
146 | sfp = (struct pvr2_sysfs *)class_dev->class_data; | ||
147 | if (!sfp) return -EINVAL; | ||
148 | cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); | ||
149 | if (!cptr) return -EINVAL; | ||
150 | val = pvr2_ctrl_get_max(cptr); | ||
151 | |||
152 | pvr2_sysfs_trace("pvr2_sysfs(%p) show_max(cid=%d) is %ld",sfp,id,val); | ||
153 | |||
154 | return scnprintf(buf,PAGE_SIZE,"%ld\n",val); | ||
155 | } | ||
156 | |||
157 | static ssize_t show_val_norm(int id,struct class_device *class_dev,char *buf) | ||
158 | { | ||
159 | struct pvr2_ctrl *cptr; | ||
160 | struct pvr2_sysfs *sfp; | ||
161 | int val,ret; | ||
162 | unsigned int cnt = 0; | ||
163 | |||
164 | sfp = (struct pvr2_sysfs *)class_dev->class_data; | ||
165 | if (!sfp) return -EINVAL; | ||
166 | cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); | ||
167 | if (!cptr) return -EINVAL; | ||
168 | |||
169 | ret = pvr2_ctrl_get_value(cptr,&val); | ||
170 | if (ret < 0) return ret; | ||
171 | |||
172 | ret = pvr2_ctrl_value_to_sym(cptr,~0,val, | ||
173 | buf,PAGE_SIZE-1,&cnt); | ||
174 | |||
175 | pvr2_sysfs_trace("pvr2_sysfs(%p) show_val_norm(cid=%d) is %.*s (%d)", | ||
176 | sfp,id,cnt,buf,val); | ||
177 | buf[cnt] = '\n'; | ||
178 | return cnt+1; | ||
179 | } | ||
180 | |||
181 | static ssize_t show_val_custom(int id,struct class_device *class_dev,char *buf) | ||
182 | { | ||
183 | struct pvr2_ctrl *cptr; | ||
184 | struct pvr2_sysfs *sfp; | ||
185 | int val,ret; | ||
186 | unsigned int cnt = 0; | ||
187 | |||
188 | sfp = (struct pvr2_sysfs *)class_dev->class_data; | ||
189 | if (!sfp) return -EINVAL; | ||
190 | cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); | ||
191 | if (!cptr) return -EINVAL; | ||
192 | |||
193 | ret = pvr2_ctrl_get_value(cptr,&val); | ||
194 | if (ret < 0) return ret; | ||
195 | |||
196 | ret = pvr2_ctrl_custom_value_to_sym(cptr,~0,val, | ||
197 | buf,PAGE_SIZE-1,&cnt); | ||
198 | |||
199 | pvr2_sysfs_trace("pvr2_sysfs(%p) show_val_custom(cid=%d) is %.*s (%d)", | ||
200 | sfp,id,cnt,buf,val); | ||
201 | buf[cnt] = '\n'; | ||
202 | return cnt+1; | ||
203 | } | ||
204 | |||
205 | static ssize_t show_enum(int id,struct class_device *class_dev,char *buf) | ||
206 | { | ||
207 | struct pvr2_ctrl *cptr; | ||
208 | struct pvr2_sysfs *sfp; | ||
209 | long val; | ||
210 | unsigned int bcnt,ccnt,ecnt; | ||
211 | |||
212 | sfp = (struct pvr2_sysfs *)class_dev->class_data; | ||
213 | if (!sfp) return -EINVAL; | ||
214 | cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); | ||
215 | if (!cptr) return -EINVAL; | ||
216 | ecnt = pvr2_ctrl_get_cnt(cptr); | ||
217 | bcnt = 0; | ||
218 | for (val = 0; val < ecnt; val++) { | ||
219 | pvr2_ctrl_get_valname(cptr,val,buf+bcnt,PAGE_SIZE-bcnt,&ccnt); | ||
220 | if (!ccnt) continue; | ||
221 | bcnt += ccnt; | ||
222 | if (bcnt >= PAGE_SIZE) break; | ||
223 | buf[bcnt] = '\n'; | ||
224 | bcnt++; | ||
225 | } | ||
226 | pvr2_sysfs_trace("pvr2_sysfs(%p) show_enum(cid=%d)",sfp,id); | ||
227 | return bcnt; | ||
228 | } | ||
229 | |||
230 | static ssize_t show_bits(int id,struct class_device *class_dev,char *buf) | ||
231 | { | ||
232 | struct pvr2_ctrl *cptr; | ||
233 | struct pvr2_sysfs *sfp; | ||
234 | int valid_bits,msk; | ||
235 | unsigned int bcnt,ccnt; | ||
236 | |||
237 | sfp = (struct pvr2_sysfs *)class_dev->class_data; | ||
238 | if (!sfp) return -EINVAL; | ||
239 | cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); | ||
240 | if (!cptr) return -EINVAL; | ||
241 | valid_bits = pvr2_ctrl_get_mask(cptr); | ||
242 | bcnt = 0; | ||
243 | for (msk = 1; valid_bits; msk <<= 1) { | ||
244 | if (!(msk & valid_bits)) continue; | ||
245 | valid_bits &= ~msk; | ||
246 | pvr2_ctrl_get_valname(cptr,msk,buf+bcnt,PAGE_SIZE-bcnt,&ccnt); | ||
247 | bcnt += ccnt; | ||
248 | if (bcnt >= PAGE_SIZE) break; | ||
249 | buf[bcnt] = '\n'; | ||
250 | bcnt++; | ||
251 | } | ||
252 | pvr2_sysfs_trace("pvr2_sysfs(%p) show_bits(cid=%d)",sfp,id); | ||
253 | return bcnt; | ||
254 | } | ||
255 | |||
256 | static int store_val_any(int id,int customfl,struct pvr2_sysfs *sfp, | ||
257 | const char *buf,unsigned int count) | ||
258 | { | ||
259 | struct pvr2_ctrl *cptr; | ||
260 | int ret; | ||
261 | int mask,val; | ||
262 | |||
263 | cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); | ||
264 | if (customfl) { | ||
265 | ret = pvr2_ctrl_custom_sym_to_value(cptr,buf,count,&mask,&val); | ||
266 | } else { | ||
267 | ret = pvr2_ctrl_sym_to_value(cptr,buf,count,&mask,&val); | ||
268 | } | ||
269 | if (ret < 0) return ret; | ||
270 | ret = pvr2_ctrl_set_mask_value(cptr,mask,val); | ||
271 | pvr2_hdw_commit_ctl(sfp->channel.hdw); | ||
272 | return ret; | ||
273 | } | ||
274 | |||
275 | static ssize_t store_val_norm(int id,struct class_device *class_dev, | ||
276 | const char *buf,size_t count) | ||
277 | { | ||
278 | struct pvr2_sysfs *sfp; | ||
279 | int ret; | ||
280 | sfp = (struct pvr2_sysfs *)class_dev->class_data; | ||
281 | ret = store_val_any(id,0,sfp,buf,count); | ||
282 | if (!ret) ret = count; | ||
283 | return ret; | ||
284 | } | ||
285 | |||
286 | static ssize_t store_val_custom(int id,struct class_device *class_dev, | ||
287 | const char *buf,size_t count) | ||
288 | { | ||
289 | struct pvr2_sysfs *sfp; | ||
290 | int ret; | ||
291 | sfp = (struct pvr2_sysfs *)class_dev->class_data; | ||
292 | ret = store_val_any(id,1,sfp,buf,count); | ||
293 | if (!ret) ret = count; | ||
294 | return ret; | ||
295 | } | ||
296 | |||
297 | /* | ||
298 | Mike Isely <isely@pobox.com> 30-April-2005 | ||
299 | |||
300 | This next batch of horrible preprocessor hackery is needed because the | ||
301 | kernel's class_device_attribute mechanism fails to pass the actual | ||
302 | attribute through to the show / store functions, which means we have no | ||
303 | way to package up any attribute-specific parameters, like for example the | ||
304 | control id. So we work around this brain-damage by encoding the control | ||
305 | id into the show / store functions themselves and pick the function based | ||
306 | on the control id we're setting up. These macros try to ease the pain. | ||
307 | Yuck. | ||
308 | */ | ||
309 | |||
310 | #define CREATE_SHOW_INSTANCE(sf_name,ctl_id) \ | ||
311 | static ssize_t sf_name##_##ctl_id(struct class_device *class_dev,char *buf) \ | ||
312 | { return sf_name(ctl_id,class_dev,buf); } | ||
313 | |||
314 | #define CREATE_STORE_INSTANCE(sf_name,ctl_id) \ | ||
315 | static ssize_t sf_name##_##ctl_id(struct class_device *class_dev,const char *buf,size_t count) \ | ||
316 | { return sf_name(ctl_id,class_dev,buf,count); } | ||
317 | |||
318 | #define CREATE_BATCH(ctl_id) \ | ||
319 | CREATE_SHOW_INSTANCE(show_name,ctl_id) \ | ||
320 | CREATE_SHOW_INSTANCE(show_type,ctl_id) \ | ||
321 | CREATE_SHOW_INSTANCE(show_min,ctl_id) \ | ||
322 | CREATE_SHOW_INSTANCE(show_max,ctl_id) \ | ||
323 | CREATE_SHOW_INSTANCE(show_val_norm,ctl_id) \ | ||
324 | CREATE_SHOW_INSTANCE(show_val_custom,ctl_id) \ | ||
325 | CREATE_SHOW_INSTANCE(show_enum,ctl_id) \ | ||
326 | CREATE_SHOW_INSTANCE(show_bits,ctl_id) \ | ||
327 | CREATE_STORE_INSTANCE(store_val_norm,ctl_id) \ | ||
328 | CREATE_STORE_INSTANCE(store_val_custom,ctl_id) \ | ||
329 | |||
330 | CREATE_BATCH(0) | ||
331 | CREATE_BATCH(1) | ||
332 | CREATE_BATCH(2) | ||
333 | CREATE_BATCH(3) | ||
334 | CREATE_BATCH(4) | ||
335 | CREATE_BATCH(5) | ||
336 | CREATE_BATCH(6) | ||
337 | CREATE_BATCH(7) | ||
338 | CREATE_BATCH(8) | ||
339 | CREATE_BATCH(9) | ||
340 | CREATE_BATCH(10) | ||
341 | CREATE_BATCH(11) | ||
342 | CREATE_BATCH(12) | ||
343 | CREATE_BATCH(13) | ||
344 | CREATE_BATCH(14) | ||
345 | CREATE_BATCH(15) | ||
346 | CREATE_BATCH(16) | ||
347 | CREATE_BATCH(17) | ||
348 | CREATE_BATCH(18) | ||
349 | CREATE_BATCH(19) | ||
350 | CREATE_BATCH(20) | ||
351 | CREATE_BATCH(21) | ||
352 | CREATE_BATCH(22) | ||
353 | CREATE_BATCH(23) | ||
354 | CREATE_BATCH(24) | ||
355 | CREATE_BATCH(25) | ||
356 | CREATE_BATCH(26) | ||
357 | CREATE_BATCH(27) | ||
358 | CREATE_BATCH(28) | ||
359 | CREATE_BATCH(29) | ||
360 | CREATE_BATCH(30) | ||
361 | CREATE_BATCH(31) | ||
362 | CREATE_BATCH(32) | ||
363 | CREATE_BATCH(33) | ||
364 | CREATE_BATCH(34) | ||
365 | CREATE_BATCH(35) | ||
366 | CREATE_BATCH(36) | ||
367 | CREATE_BATCH(37) | ||
368 | CREATE_BATCH(38) | ||
369 | CREATE_BATCH(39) | ||
370 | CREATE_BATCH(40) | ||
371 | CREATE_BATCH(41) | ||
372 | CREATE_BATCH(42) | ||
373 | CREATE_BATCH(43) | ||
374 | CREATE_BATCH(44) | ||
375 | CREATE_BATCH(45) | ||
376 | CREATE_BATCH(46) | ||
377 | CREATE_BATCH(47) | ||
378 | CREATE_BATCH(48) | ||
379 | CREATE_BATCH(49) | ||
380 | CREATE_BATCH(50) | ||
381 | CREATE_BATCH(51) | ||
382 | CREATE_BATCH(52) | ||
383 | CREATE_BATCH(53) | ||
384 | CREATE_BATCH(54) | ||
385 | CREATE_BATCH(55) | ||
386 | CREATE_BATCH(56) | ||
387 | CREATE_BATCH(57) | ||
388 | CREATE_BATCH(58) | ||
389 | CREATE_BATCH(59) | ||
390 | |||
391 | struct pvr2_sysfs_func_set { | ||
392 | ssize_t (*show_name)(struct class_device *,char *); | ||
393 | ssize_t (*show_type)(struct class_device *,char *); | ||
394 | ssize_t (*show_min)(struct class_device *,char *); | ||
395 | ssize_t (*show_max)(struct class_device *,char *); | ||
396 | ssize_t (*show_enum)(struct class_device *,char *); | ||
397 | ssize_t (*show_bits)(struct class_device *,char *); | ||
398 | ssize_t (*show_val_norm)(struct class_device *,char *); | ||
399 | ssize_t (*store_val_norm)(struct class_device *, | ||
400 | const char *,size_t); | ||
401 | ssize_t (*show_val_custom)(struct class_device *,char *); | ||
402 | ssize_t (*store_val_custom)(struct class_device *, | ||
403 | const char *,size_t); | ||
404 | }; | ||
405 | |||
406 | #define INIT_BATCH(ctl_id) \ | ||
407 | [ctl_id] = { \ | ||
408 | .show_name = show_name_##ctl_id, \ | ||
409 | .show_type = show_type_##ctl_id, \ | ||
410 | .show_min = show_min_##ctl_id, \ | ||
411 | .show_max = show_max_##ctl_id, \ | ||
412 | .show_enum = show_enum_##ctl_id, \ | ||
413 | .show_bits = show_bits_##ctl_id, \ | ||
414 | .show_val_norm = show_val_norm_##ctl_id, \ | ||
415 | .store_val_norm = store_val_norm_##ctl_id, \ | ||
416 | .show_val_custom = show_val_custom_##ctl_id, \ | ||
417 | .store_val_custom = store_val_custom_##ctl_id, \ | ||
418 | } \ | ||
419 | |||
420 | static struct pvr2_sysfs_func_set funcs[] = { | ||
421 | INIT_BATCH(0), | ||
422 | INIT_BATCH(1), | ||
423 | INIT_BATCH(2), | ||
424 | INIT_BATCH(3), | ||
425 | INIT_BATCH(4), | ||
426 | INIT_BATCH(5), | ||
427 | INIT_BATCH(6), | ||
428 | INIT_BATCH(7), | ||
429 | INIT_BATCH(8), | ||
430 | INIT_BATCH(9), | ||
431 | INIT_BATCH(10), | ||
432 | INIT_BATCH(11), | ||
433 | INIT_BATCH(12), | ||
434 | INIT_BATCH(13), | ||
435 | INIT_BATCH(14), | ||
436 | INIT_BATCH(15), | ||
437 | INIT_BATCH(16), | ||
438 | INIT_BATCH(17), | ||
439 | INIT_BATCH(18), | ||
440 | INIT_BATCH(19), | ||
441 | INIT_BATCH(20), | ||
442 | INIT_BATCH(21), | ||
443 | INIT_BATCH(22), | ||
444 | INIT_BATCH(23), | ||
445 | INIT_BATCH(24), | ||
446 | INIT_BATCH(25), | ||
447 | INIT_BATCH(26), | ||
448 | INIT_BATCH(27), | ||
449 | INIT_BATCH(28), | ||
450 | INIT_BATCH(29), | ||
451 | INIT_BATCH(30), | ||
452 | INIT_BATCH(31), | ||
453 | INIT_BATCH(32), | ||
454 | INIT_BATCH(33), | ||
455 | INIT_BATCH(34), | ||
456 | INIT_BATCH(35), | ||
457 | INIT_BATCH(36), | ||
458 | INIT_BATCH(37), | ||
459 | INIT_BATCH(38), | ||
460 | INIT_BATCH(39), | ||
461 | INIT_BATCH(40), | ||
462 | INIT_BATCH(41), | ||
463 | INIT_BATCH(42), | ||
464 | INIT_BATCH(43), | ||
465 | INIT_BATCH(44), | ||
466 | INIT_BATCH(45), | ||
467 | INIT_BATCH(46), | ||
468 | INIT_BATCH(47), | ||
469 | INIT_BATCH(48), | ||
470 | INIT_BATCH(49), | ||
471 | INIT_BATCH(50), | ||
472 | INIT_BATCH(51), | ||
473 | INIT_BATCH(52), | ||
474 | INIT_BATCH(53), | ||
475 | INIT_BATCH(54), | ||
476 | INIT_BATCH(55), | ||
477 | INIT_BATCH(56), | ||
478 | INIT_BATCH(57), | ||
479 | INIT_BATCH(58), | ||
480 | INIT_BATCH(59), | ||
481 | }; | ||
482 | |||
483 | |||
484 | static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id) | ||
485 | { | ||
486 | struct pvr2_sysfs_ctl_item *cip; | ||
487 | struct pvr2_sysfs_func_set *fp; | ||
488 | struct pvr2_ctrl *cptr; | ||
489 | unsigned int cnt,acnt; | ||
490 | |||
491 | if ((ctl_id < 0) || (ctl_id >= (sizeof(funcs)/sizeof(funcs[0])))) { | ||
492 | return; | ||
493 | } | ||
494 | |||
495 | fp = funcs + ctl_id; | ||
496 | cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,ctl_id); | ||
497 | if (!cptr) return; | ||
498 | |||
499 | cip = kmalloc(sizeof(*cip),GFP_KERNEL); | ||
500 | if (!cip) return; | ||
501 | memset(cip,0,sizeof(*cip)); | ||
502 | pvr2_sysfs_trace("Creating pvr2_sysfs_ctl_item id=%p",cip); | ||
503 | |||
504 | cip->cptr = cptr; | ||
505 | |||
506 | cip->chptr = sfp; | ||
507 | cip->item_next = 0; | ||
508 | if (sfp->item_last) { | ||
509 | sfp->item_last->item_next = cip; | ||
510 | } else { | ||
511 | sfp->item_first = cip; | ||
512 | } | ||
513 | sfp->item_last = cip; | ||
514 | |||
515 | cip->attr_name.attr.owner = THIS_MODULE; | ||
516 | cip->attr_name.attr.name = "name"; | ||
517 | cip->attr_name.attr.mode = S_IRUGO; | ||
518 | cip->attr_name.show = fp->show_name; | ||
519 | |||
520 | cip->attr_type.attr.owner = THIS_MODULE; | ||
521 | cip->attr_type.attr.name = "type"; | ||
522 | cip->attr_type.attr.mode = S_IRUGO; | ||
523 | cip->attr_type.show = fp->show_type; | ||
524 | |||
525 | cip->attr_min.attr.owner = THIS_MODULE; | ||
526 | cip->attr_min.attr.name = "min_val"; | ||
527 | cip->attr_min.attr.mode = S_IRUGO; | ||
528 | cip->attr_min.show = fp->show_min; | ||
529 | |||
530 | cip->attr_max.attr.owner = THIS_MODULE; | ||
531 | cip->attr_max.attr.name = "max_val"; | ||
532 | cip->attr_max.attr.mode = S_IRUGO; | ||
533 | cip->attr_max.show = fp->show_max; | ||
534 | |||
535 | cip->attr_val.attr.owner = THIS_MODULE; | ||
536 | cip->attr_val.attr.name = "cur_val"; | ||
537 | cip->attr_val.attr.mode = S_IRUGO; | ||
538 | |||
539 | cip->attr_custom.attr.owner = THIS_MODULE; | ||
540 | cip->attr_custom.attr.name = "custom_val"; | ||
541 | cip->attr_custom.attr.mode = S_IRUGO; | ||
542 | |||
543 | cip->attr_enum.attr.owner = THIS_MODULE; | ||
544 | cip->attr_enum.attr.name = "enum_val"; | ||
545 | cip->attr_enum.attr.mode = S_IRUGO; | ||
546 | cip->attr_enum.show = fp->show_enum; | ||
547 | |||
548 | cip->attr_bits.attr.owner = THIS_MODULE; | ||
549 | cip->attr_bits.attr.name = "bit_val"; | ||
550 | cip->attr_bits.attr.mode = S_IRUGO; | ||
551 | cip->attr_bits.show = fp->show_bits; | ||
552 | |||
553 | if (pvr2_ctrl_is_writable(cptr)) { | ||
554 | cip->attr_val.attr.mode |= S_IWUSR|S_IWGRP; | ||
555 | cip->attr_custom.attr.mode |= S_IWUSR|S_IWGRP; | ||
556 | } | ||
557 | |||
558 | acnt = 0; | ||
559 | cip->attr_gen[acnt++] = &cip->attr_name.attr; | ||
560 | cip->attr_gen[acnt++] = &cip->attr_type.attr; | ||
561 | cip->attr_gen[acnt++] = &cip->attr_val.attr; | ||
562 | cip->attr_val.show = fp->show_val_norm; | ||
563 | cip->attr_val.store = fp->store_val_norm; | ||
564 | if (pvr2_ctrl_has_custom_symbols(cptr)) { | ||
565 | cip->attr_gen[acnt++] = &cip->attr_custom.attr; | ||
566 | cip->attr_custom.show = fp->show_val_custom; | ||
567 | cip->attr_custom.store = fp->store_val_custom; | ||
568 | } | ||
569 | switch (pvr2_ctrl_get_type(cptr)) { | ||
570 | case pvr2_ctl_enum: | ||
571 | // Control is an enumeration | ||
572 | cip->attr_gen[acnt++] = &cip->attr_enum.attr; | ||
573 | break; | ||
574 | case pvr2_ctl_int: | ||
575 | // Control is an integer | ||
576 | cip->attr_gen[acnt++] = &cip->attr_min.attr; | ||
577 | cip->attr_gen[acnt++] = &cip->attr_max.attr; | ||
578 | break; | ||
579 | case pvr2_ctl_bitmask: | ||
580 | // Control is an bitmask | ||
581 | cip->attr_gen[acnt++] = &cip->attr_bits.attr; | ||
582 | break; | ||
583 | default: break; | ||
584 | } | ||
585 | |||
586 | cnt = scnprintf(cip->name,sizeof(cip->name)-1,"ctl_%s", | ||
587 | pvr2_ctrl_get_name(cptr)); | ||
588 | cip->name[cnt] = 0; | ||
589 | cip->grp.name = cip->name; | ||
590 | cip->grp.attrs = cip->attr_gen; | ||
591 | |||
592 | sysfs_create_group(&sfp->class_dev->kobj,&cip->grp); | ||
593 | } | ||
594 | |||
595 | #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC | ||
596 | static ssize_t debuginfo_show(struct class_device *,char *); | ||
597 | static ssize_t debugcmd_show(struct class_device *,char *); | ||
598 | static ssize_t debugcmd_store(struct class_device *,const char *,size_t count); | ||
599 | |||
600 | static void pvr2_sysfs_add_debugifc(struct pvr2_sysfs *sfp) | ||
601 | { | ||
602 | struct pvr2_sysfs_debugifc *dip; | ||
603 | dip = kmalloc(sizeof(*dip),GFP_KERNEL); | ||
604 | if (!dip) return; | ||
605 | memset(dip,0,sizeof(*dip)); | ||
606 | dip->attr_debugcmd.attr.owner = THIS_MODULE; | ||
607 | dip->attr_debugcmd.attr.name = "debugcmd"; | ||
608 | dip->attr_debugcmd.attr.mode = S_IRUGO|S_IWUSR|S_IWGRP; | ||
609 | dip->attr_debugcmd.show = debugcmd_show; | ||
610 | dip->attr_debugcmd.store = debugcmd_store; | ||
611 | dip->attr_debuginfo.attr.owner = THIS_MODULE; | ||
612 | dip->attr_debuginfo.attr.name = "debuginfo"; | ||
613 | dip->attr_debuginfo.attr.mode = S_IRUGO; | ||
614 | dip->attr_debuginfo.show = debuginfo_show; | ||
615 | sfp->debugifc = dip; | ||
616 | class_device_create_file(sfp->class_dev,&dip->attr_debugcmd); | ||
617 | class_device_create_file(sfp->class_dev,&dip->attr_debuginfo); | ||
618 | } | ||
619 | |||
620 | |||
621 | static void pvr2_sysfs_tear_down_debugifc(struct pvr2_sysfs *sfp) | ||
622 | { | ||
623 | if (!sfp->debugifc) return; | ||
624 | class_device_remove_file(sfp->class_dev, | ||
625 | &sfp->debugifc->attr_debuginfo); | ||
626 | class_device_remove_file(sfp->class_dev,&sfp->debugifc->attr_debugcmd); | ||
627 | kfree(sfp->debugifc); | ||
628 | sfp->debugifc = 0; | ||
629 | } | ||
630 | #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ | ||
631 | |||
632 | |||
633 | static void pvr2_sysfs_add_controls(struct pvr2_sysfs *sfp) | ||
634 | { | ||
635 | unsigned int idx,cnt; | ||
636 | cnt = pvr2_hdw_get_ctrl_count(sfp->channel.hdw); | ||
637 | for (idx = 0; idx < cnt; idx++) { | ||
638 | pvr2_sysfs_add_control(sfp,idx); | ||
639 | } | ||
640 | } | ||
641 | |||
642 | |||
643 | static void pvr2_sysfs_tear_down_controls(struct pvr2_sysfs *sfp) | ||
644 | { | ||
645 | struct pvr2_sysfs_ctl_item *cip1,*cip2; | ||
646 | for (cip1 = sfp->item_first; cip1; cip1 = cip2) { | ||
647 | cip2 = cip1->item_next; | ||
648 | sysfs_remove_group(&sfp->class_dev->kobj,&cip1->grp); | ||
649 | pvr2_sysfs_trace("Destroying pvr2_sysfs_ctl_item id=%p",cip1); | ||
650 | kfree(cip1); | ||
651 | } | ||
652 | } | ||
653 | |||
654 | |||
655 | static void pvr2_sysfs_class_release(struct class *class) | ||
656 | { | ||
657 | struct pvr2_sysfs_class *clp; | ||
658 | clp = container_of(class,struct pvr2_sysfs_class,class); | ||
659 | pvr2_sysfs_trace("Destroying pvr2_sysfs_class id=%p",clp); | ||
660 | kfree(clp); | ||
661 | } | ||
662 | |||
663 | |||
664 | static void pvr2_sysfs_release(struct class_device *class_dev) | ||
665 | { | ||
666 | pvr2_sysfs_trace("Releasing class_dev id=%p",class_dev); | ||
667 | kfree(class_dev); | ||
668 | } | ||
669 | |||
670 | |||
671 | static void class_dev_destroy(struct pvr2_sysfs *sfp) | ||
672 | { | ||
673 | if (!sfp->class_dev) return; | ||
674 | #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC | ||
675 | pvr2_sysfs_tear_down_debugifc(sfp); | ||
676 | #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ | ||
677 | pvr2_sysfs_tear_down_controls(sfp); | ||
678 | class_device_remove_file(sfp->class_dev,&sfp->attr_v4l_minor_number); | ||
679 | class_device_remove_file(sfp->class_dev,&sfp->attr_unit_number); | ||
680 | pvr2_sysfs_trace("Destroying class_dev id=%p",sfp->class_dev); | ||
681 | sfp->class_dev->class_data = 0; | ||
682 | class_device_unregister(sfp->class_dev); | ||
683 | sfp->class_dev = 0; | ||
684 | } | ||
685 | |||
686 | |||
687 | static ssize_t v4l_minor_number_show(struct class_device *class_dev,char *buf) | ||
688 | { | ||
689 | struct pvr2_sysfs *sfp; | ||
690 | sfp = (struct pvr2_sysfs *)class_dev->class_data; | ||
691 | if (!sfp) return -EINVAL; | ||
692 | return scnprintf(buf,PAGE_SIZE,"%d\n", | ||
693 | pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw)); | ||
694 | } | ||
695 | |||
696 | |||
697 | static ssize_t unit_number_show(struct class_device *class_dev,char *buf) | ||
698 | { | ||
699 | struct pvr2_sysfs *sfp; | ||
700 | sfp = (struct pvr2_sysfs *)class_dev->class_data; | ||
701 | if (!sfp) return -EINVAL; | ||
702 | return scnprintf(buf,PAGE_SIZE,"%d\n", | ||
703 | pvr2_hdw_get_unit_number(sfp->channel.hdw)); | ||
704 | } | ||
705 | |||
706 | |||
707 | static void class_dev_create(struct pvr2_sysfs *sfp, | ||
708 | struct pvr2_sysfs_class *class_ptr) | ||
709 | { | ||
710 | struct usb_device *usb_dev; | ||
711 | struct class_device *class_dev; | ||
712 | usb_dev = pvr2_hdw_get_dev(sfp->channel.hdw); | ||
713 | if (!usb_dev) return; | ||
714 | class_dev = kmalloc(sizeof(*class_dev),GFP_KERNEL); | ||
715 | if (!class_dev) return; | ||
716 | memset(class_dev,0,sizeof(*class_dev)); | ||
717 | |||
718 | pvr2_sysfs_trace("Creating class_dev id=%p",class_dev); | ||
719 | |||
720 | class_dev->class = &class_ptr->class; | ||
721 | if (pvr2_hdw_get_sn(sfp->channel.hdw)) { | ||
722 | snprintf(class_dev->class_id,BUS_ID_SIZE,"sn-%lu", | ||
723 | pvr2_hdw_get_sn(sfp->channel.hdw)); | ||
724 | } else if (pvr2_hdw_get_unit_number(sfp->channel.hdw) >= 0) { | ||
725 | snprintf(class_dev->class_id,BUS_ID_SIZE,"unit-%c", | ||
726 | pvr2_hdw_get_unit_number(sfp->channel.hdw) + 'a'); | ||
727 | } else { | ||
728 | kfree(class_dev); | ||
729 | return; | ||
730 | } | ||
731 | |||
732 | class_dev->dev = &usb_dev->dev; | ||
733 | |||
734 | sfp->class_dev = class_dev; | ||
735 | class_dev->class_data = sfp; | ||
736 | class_device_register(class_dev); | ||
737 | |||
738 | sfp->attr_v4l_minor_number.attr.owner = THIS_MODULE; | ||
739 | sfp->attr_v4l_minor_number.attr.name = "v4l_minor_number"; | ||
740 | sfp->attr_v4l_minor_number.attr.mode = S_IRUGO; | ||
741 | sfp->attr_v4l_minor_number.show = v4l_minor_number_show; | ||
742 | sfp->attr_v4l_minor_number.store = 0; | ||
743 | class_device_create_file(sfp->class_dev,&sfp->attr_v4l_minor_number); | ||
744 | sfp->attr_unit_number.attr.owner = THIS_MODULE; | ||
745 | sfp->attr_unit_number.attr.name = "unit_number"; | ||
746 | sfp->attr_unit_number.attr.mode = S_IRUGO; | ||
747 | sfp->attr_unit_number.show = unit_number_show; | ||
748 | sfp->attr_unit_number.store = 0; | ||
749 | class_device_create_file(sfp->class_dev,&sfp->attr_unit_number); | ||
750 | |||
751 | pvr2_sysfs_add_controls(sfp); | ||
752 | #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC | ||
753 | pvr2_sysfs_add_debugifc(sfp); | ||
754 | #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ | ||
755 | } | ||
756 | |||
757 | |||
758 | static void pvr2_sysfs_internal_check(struct pvr2_channel *chp) | ||
759 | { | ||
760 | struct pvr2_sysfs *sfp; | ||
761 | sfp = container_of(chp,struct pvr2_sysfs,channel); | ||
762 | if (!sfp->channel.mc_head->disconnect_flag) return; | ||
763 | pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr2_sysfs id=%p",sfp); | ||
764 | class_dev_destroy(sfp); | ||
765 | pvr2_channel_done(&sfp->channel); | ||
766 | kfree(sfp); | ||
767 | } | ||
768 | |||
769 | |||
770 | struct pvr2_sysfs *pvr2_sysfs_create(struct pvr2_context *mp, | ||
771 | struct pvr2_sysfs_class *class_ptr) | ||
772 | { | ||
773 | struct pvr2_sysfs *sfp; | ||
774 | sfp = kmalloc(sizeof(*sfp),GFP_KERNEL); | ||
775 | if (!sfp) return sfp; | ||
776 | memset(sfp,0,sizeof(*sfp)); | ||
777 | pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr2_sysfs id=%p",sfp); | ||
778 | pvr2_channel_init(&sfp->channel,mp); | ||
779 | sfp->channel.check_func = pvr2_sysfs_internal_check; | ||
780 | |||
781 | class_dev_create(sfp,class_ptr); | ||
782 | return sfp; | ||
783 | } | ||
784 | |||
785 | |||
786 | static int pvr2_sysfs_hotplug(struct class_device *cd,char **envp, | ||
787 | int numenvp,char *buf,int size) | ||
788 | { | ||
789 | /* Even though we don't do anything here, we still need this function | ||
790 | because sysfs will still try to call it. */ | ||
791 | return 0; | ||
792 | } | ||
793 | |||
794 | struct pvr2_sysfs_class *pvr2_sysfs_class_create(void) | ||
795 | { | ||
796 | struct pvr2_sysfs_class *clp; | ||
797 | clp = kmalloc(sizeof(*clp),GFP_KERNEL); | ||
798 | if (!clp) return clp; | ||
799 | memset(clp,0,sizeof(*clp)); | ||
800 | pvr2_sysfs_trace("Creating pvr2_sysfs_class id=%p",clp); | ||
801 | clp->class.name = "pvrusb2"; | ||
802 | clp->class.class_release = pvr2_sysfs_class_release; | ||
803 | clp->class.release = pvr2_sysfs_release; | ||
804 | clp->class.uevent = pvr2_sysfs_hotplug; | ||
805 | if (class_register(&clp->class)) { | ||
806 | pvr2_sysfs_trace( | ||
807 | "Registration failed for pvr2_sysfs_class id=%p",clp); | ||
808 | kfree(clp); | ||
809 | clp = 0; | ||
810 | } | ||
811 | return clp; | ||
812 | } | ||
813 | |||
814 | |||
815 | void pvr2_sysfs_class_destroy(struct pvr2_sysfs_class *clp) | ||
816 | { | ||
817 | class_unregister(&clp->class); | ||
818 | } | ||
819 | |||
820 | |||
821 | #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC | ||
822 | static ssize_t debuginfo_show(struct class_device *class_dev,char *buf) | ||
823 | { | ||
824 | struct pvr2_sysfs *sfp; | ||
825 | sfp = (struct pvr2_sysfs *)class_dev->class_data; | ||
826 | if (!sfp) return -EINVAL; | ||
827 | pvr2_hdw_trigger_module_log(sfp->channel.hdw); | ||
828 | return pvr2_debugifc_print_info(sfp->channel.hdw,buf,PAGE_SIZE); | ||
829 | } | ||
830 | |||
831 | |||
832 | static ssize_t debugcmd_show(struct class_device *class_dev,char *buf) | ||
833 | { | ||
834 | struct pvr2_sysfs *sfp; | ||
835 | sfp = (struct pvr2_sysfs *)class_dev->class_data; | ||
836 | if (!sfp) return -EINVAL; | ||
837 | return pvr2_debugifc_print_status(sfp->channel.hdw,buf,PAGE_SIZE); | ||
838 | } | ||
839 | |||
840 | |||
841 | static ssize_t debugcmd_store(struct class_device *class_dev, | ||
842 | const char *buf,size_t count) | ||
843 | { | ||
844 | struct pvr2_sysfs *sfp; | ||
845 | int ret; | ||
846 | |||
847 | sfp = (struct pvr2_sysfs *)class_dev->class_data; | ||
848 | if (!sfp) return -EINVAL; | ||
849 | |||
850 | ret = pvr2_debugifc_docmd(sfp->channel.hdw,buf,count); | ||
851 | if (ret < 0) return ret; | ||
852 | return count; | ||
853 | } | ||
854 | #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ | ||
855 | |||
856 | |||
857 | /* | ||
858 | Stuff for Emacs to see, in order to encourage consistent editing style: | ||
859 | *** Local Variables: *** | ||
860 | *** mode: c *** | ||
861 | *** fill-column: 75 *** | ||
862 | *** tab-width: 8 *** | ||
863 | *** c-basic-offset: 8 *** | ||
864 | *** End: *** | ||
865 | */ | ||
diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.h b/drivers/media/video/pvrusb2/pvrusb2-sysfs.h new file mode 100644 index 000000000000..ff9373b47f8f --- /dev/null +++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.h | |||
@@ -0,0 +1,47 @@ | |||
1 | /* | ||
2 | * | ||
3 | * $Id$ | ||
4 | * | ||
5 | * Copyright (C) 2005 Mike Isely <isely@pobox.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 | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | * | ||
20 | */ | ||
21 | #ifndef __PVRUSB2_SYSFS_H | ||
22 | #define __PVRUSB2_SYSFS_H | ||
23 | |||
24 | #include <linux/list.h> | ||
25 | #include <linux/sysfs.h> | ||
26 | #include "pvrusb2-context.h" | ||
27 | |||
28 | struct pvr2_sysfs; | ||
29 | struct pvr2_sysfs_class; | ||
30 | |||
31 | struct pvr2_sysfs_class *pvr2_sysfs_class_create(void); | ||
32 | void pvr2_sysfs_class_destroy(struct pvr2_sysfs_class *); | ||
33 | |||
34 | struct pvr2_sysfs *pvr2_sysfs_create(struct pvr2_context *, | ||
35 | struct pvr2_sysfs_class *); | ||
36 | |||
37 | #endif /* __PVRUSB2_SYSFS_H */ | ||
38 | |||
39 | /* | ||
40 | Stuff for Emacs to see, in order to encourage consistent editing style: | ||
41 | *** Local Variables: *** | ||
42 | *** mode: c *** | ||
43 | *** fill-column: 75 *** | ||
44 | *** tab-width: 8 *** | ||
45 | *** c-basic-offset: 8 *** | ||
46 | *** End: *** | ||
47 | */ | ||
diff --git a/drivers/media/video/pvrusb2/pvrusb2-tuner.c b/drivers/media/video/pvrusb2/pvrusb2-tuner.c new file mode 100644 index 000000000000..f4aba8144ce0 --- /dev/null +++ b/drivers/media/video/pvrusb2/pvrusb2-tuner.c | |||
@@ -0,0 +1,122 @@ | |||
1 | /* | ||
2 | * | ||
3 | * $Id$ | ||
4 | * | ||
5 | * Copyright (C) 2005 Mike Isely <isely@pobox.com> | ||
6 | * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License | ||
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 | |||
23 | #include "pvrusb2.h" | ||
24 | #include "pvrusb2-util.h" | ||
25 | #include "pvrusb2-tuner.h" | ||
26 | #include "pvrusb2-hdw-internal.h" | ||
27 | #include "pvrusb2-debug.h" | ||
28 | #include <linux/videodev2.h> | ||
29 | #include <media/tuner.h> | ||
30 | #include <media/v4l2-common.h> | ||
31 | |||
32 | struct pvr2_tuner_handler { | ||
33 | struct pvr2_hdw *hdw; | ||
34 | struct pvr2_i2c_client *client; | ||
35 | struct pvr2_i2c_handler i2c_handler; | ||
36 | int type_update_fl; | ||
37 | }; | ||
38 | |||
39 | |||
40 | static void set_type(struct pvr2_tuner_handler *ctxt) | ||
41 | { | ||
42 | struct pvr2_hdw *hdw = ctxt->hdw; | ||
43 | struct tuner_setup setup; | ||
44 | pvr2_trace(PVR2_TRACE_CHIPS,"i2c tuner set_type(%d)",hdw->tuner_type); | ||
45 | if (((int)(hdw->tuner_type)) < 0) return; | ||
46 | |||
47 | setup.addr = ADDR_UNSET; | ||
48 | setup.type = hdw->tuner_type; | ||
49 | setup.mode_mask = T_RADIO | T_ANALOG_TV; | ||
50 | /* We may really want mode_mask to be T_ANALOG_TV for now */ | ||
51 | pvr2_i2c_client_cmd(ctxt->client,TUNER_SET_TYPE_ADDR,&setup); | ||
52 | ctxt->type_update_fl = 0; | ||
53 | } | ||
54 | |||
55 | |||
56 | static int tuner_check(struct pvr2_tuner_handler *ctxt) | ||
57 | { | ||
58 | struct pvr2_hdw *hdw = ctxt->hdw; | ||
59 | if (hdw->tuner_updated) ctxt->type_update_fl = !0; | ||
60 | return ctxt->type_update_fl != 0; | ||
61 | } | ||
62 | |||
63 | |||
64 | static void tuner_update(struct pvr2_tuner_handler *ctxt) | ||
65 | { | ||
66 | if (ctxt->type_update_fl) set_type(ctxt); | ||
67 | } | ||
68 | |||
69 | |||
70 | static void pvr2_tuner_detach(struct pvr2_tuner_handler *ctxt) | ||
71 | { | ||
72 | ctxt->client->handler = 0; | ||
73 | kfree(ctxt); | ||
74 | } | ||
75 | |||
76 | |||
77 | static unsigned int pvr2_tuner_describe(struct pvr2_tuner_handler *ctxt,char *buf,unsigned int cnt) | ||
78 | { | ||
79 | return scnprintf(buf,cnt,"handler: pvrusb2-tuner"); | ||
80 | } | ||
81 | |||
82 | |||
83 | const static struct pvr2_i2c_handler_functions tuner_funcs = { | ||
84 | .detach = (void (*)(void *))pvr2_tuner_detach, | ||
85 | .check = (int (*)(void *))tuner_check, | ||
86 | .update = (void (*)(void *))tuner_update, | ||
87 | .describe = (unsigned int (*)(void *,char *,unsigned int))pvr2_tuner_describe, | ||
88 | }; | ||
89 | |||
90 | |||
91 | int pvr2_i2c_tuner_setup(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp) | ||
92 | { | ||
93 | struct pvr2_tuner_handler *ctxt; | ||
94 | if (cp->handler) return 0; | ||
95 | |||
96 | ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL); | ||
97 | if (!ctxt) return 0; | ||
98 | memset(ctxt,0,sizeof(*ctxt)); | ||
99 | |||
100 | ctxt->i2c_handler.func_data = ctxt; | ||
101 | ctxt->i2c_handler.func_table = &tuner_funcs; | ||
102 | ctxt->type_update_fl = !0; | ||
103 | ctxt->client = cp; | ||
104 | ctxt->hdw = hdw; | ||
105 | cp->handler = &ctxt->i2c_handler; | ||
106 | pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x tuner handler set up", | ||
107 | cp->client->addr); | ||
108 | return !0; | ||
109 | } | ||
110 | |||
111 | |||
112 | |||
113 | |||
114 | /* | ||
115 | Stuff for Emacs to see, in order to encourage consistent editing style: | ||
116 | *** Local Variables: *** | ||
117 | *** mode: c *** | ||
118 | *** fill-column: 70 *** | ||
119 | *** tab-width: 8 *** | ||
120 | *** c-basic-offset: 8 *** | ||
121 | *** End: *** | ||
122 | */ | ||
diff --git a/drivers/media/video/pvrusb2/pvrusb2-tuner.h b/drivers/media/video/pvrusb2/pvrusb2-tuner.h new file mode 100644 index 000000000000..556f12aa9160 --- /dev/null +++ b/drivers/media/video/pvrusb2/pvrusb2-tuner.h | |||
@@ -0,0 +1,38 @@ | |||
1 | /* | ||
2 | * | ||
3 | * $Id$ | ||
4 | * | ||
5 | * Copyright (C) 2005 Mike Isely <isely@pobox.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 | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | * | ||
20 | */ | ||
21 | #ifndef __PVRUSB2_TUNER_H | ||
22 | #define __PVRUSB2_TUNER_H | ||
23 | |||
24 | #include "pvrusb2-i2c-core.h" | ||
25 | |||
26 | int pvr2_i2c_tuner_setup(struct pvr2_hdw *,struct pvr2_i2c_client *); | ||
27 | |||
28 | #endif /* __PVRUSB2_TUNER_H */ | ||
29 | |||
30 | /* | ||
31 | Stuff for Emacs to see, in order to encourage consistent editing style: | ||
32 | *** Local Variables: *** | ||
33 | *** mode: c *** | ||
34 | *** fill-column: 70 *** | ||
35 | *** tab-width: 8 *** | ||
36 | *** c-basic-offset: 8 *** | ||
37 | *** End: *** | ||
38 | */ | ||
diff --git a/drivers/media/video/pvrusb2/pvrusb2-util.h b/drivers/media/video/pvrusb2/pvrusb2-util.h new file mode 100644 index 000000000000..e53aee416f56 --- /dev/null +++ b/drivers/media/video/pvrusb2/pvrusb2-util.h | |||
@@ -0,0 +1,63 @@ | |||
1 | /* | ||
2 | * | ||
3 | * $Id$ | ||
4 | * | ||
5 | * Copyright (C) 2005 Mike Isely <isely@pobox.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 | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | * | ||
20 | */ | ||
21 | #ifndef __PVRUSB2_UTIL_H | ||
22 | #define __PVRUSB2_UTIL_H | ||
23 | |||
24 | #define PVR2_DECOMPOSE_LE(t,i,d) \ | ||
25 | do { \ | ||
26 | (t)[i] = (d) & 0xff;\ | ||
27 | (t)[i+1] = ((d) >> 8) & 0xff;\ | ||
28 | (t)[i+2] = ((d) >> 16) & 0xff;\ | ||
29 | (t)[i+3] = ((d) >> 24) & 0xff;\ | ||
30 | } while(0) | ||
31 | |||
32 | #define PVR2_DECOMPOSE_BE(t,i,d) \ | ||
33 | do { \ | ||
34 | (t)[i+3] = (d) & 0xff;\ | ||
35 | (t)[i+2] = ((d) >> 8) & 0xff;\ | ||
36 | (t)[i+1] = ((d) >> 16) & 0xff;\ | ||
37 | (t)[i] = ((d) >> 24) & 0xff;\ | ||
38 | } while(0) | ||
39 | |||
40 | #define PVR2_COMPOSE_LE(t,i) \ | ||
41 | ((((u32)((t)[i+3])) << 24) | \ | ||
42 | (((u32)((t)[i+2])) << 16) | \ | ||
43 | (((u32)((t)[i+1])) << 8) | \ | ||
44 | ((u32)((t)[i]))) | ||
45 | |||
46 | #define PVR2_COMPOSE_BE(t,i) \ | ||
47 | ((((u32)((t)[i])) << 24) | \ | ||
48 | (((u32)((t)[i+1])) << 16) | \ | ||
49 | (((u32)((t)[i+2])) << 8) | \ | ||
50 | ((u32)((t)[i+3]))) | ||
51 | |||
52 | |||
53 | #endif /* __PVRUSB2_UTIL_H */ | ||
54 | |||
55 | /* | ||
56 | Stuff for Emacs to see, in order to encourage consistent editing style: | ||
57 | *** Local Variables: *** | ||
58 | *** mode: c *** | ||
59 | *** fill-column: 75 *** | ||
60 | *** tab-width: 8 *** | ||
61 | *** c-basic-offset: 8 *** | ||
62 | *** End: *** | ||
63 | */ | ||
diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c new file mode 100644 index 000000000000..961951010c27 --- /dev/null +++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c | |||
@@ -0,0 +1,1126 @@ | |||
1 | /* | ||
2 | * | ||
3 | * $Id$ | ||
4 | * | ||
5 | * Copyright (C) 2005 Mike Isely <isely@pobox.com> | ||
6 | * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License | ||
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 | |||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/version.h> | ||
25 | #include "pvrusb2-context.h" | ||
26 | #include "pvrusb2-hdw.h" | ||
27 | #include "pvrusb2.h" | ||
28 | #include "pvrusb2-debug.h" | ||
29 | #include "pvrusb2-v4l2.h" | ||
30 | #include "pvrusb2-ioread.h" | ||
31 | #include <linux/videodev2.h> | ||
32 | #include <media/v4l2-common.h> | ||
33 | |||
34 | struct pvr2_v4l2_dev; | ||
35 | struct pvr2_v4l2_fh; | ||
36 | struct pvr2_v4l2; | ||
37 | |||
38 | /* V4L no longer provide the ability to set / get a private context pointer | ||
39 | (i.e. video_get_drvdata / video_set_drvdata), which means we have to | ||
40 | concoct our own context locating mechanism. Supposedly this is intended | ||
41 | to simplify driver implementation. It's not clear to me how that can | ||
42 | possibly be true. Our solution here is to maintain a lookup table of | ||
43 | our context instances, indexed by the minor device number of the V4L | ||
44 | device. See pvr2_v4l2_open() for some implications of this approach. */ | ||
45 | static struct pvr2_v4l2_dev *devices[256]; | ||
46 | static DEFINE_MUTEX(device_lock); | ||
47 | |||
48 | struct pvr2_v4l2_dev { | ||
49 | struct pvr2_v4l2 *v4lp; | ||
50 | struct video_device *vdev; | ||
51 | struct pvr2_context_stream *stream; | ||
52 | int ctxt_idx; | ||
53 | enum pvr2_config config; | ||
54 | }; | ||
55 | |||
56 | struct pvr2_v4l2_fh { | ||
57 | struct pvr2_channel channel; | ||
58 | struct pvr2_v4l2_dev *dev_info; | ||
59 | enum v4l2_priority prio; | ||
60 | struct pvr2_ioread *rhp; | ||
61 | struct file *file; | ||
62 | struct pvr2_v4l2 *vhead; | ||
63 | struct pvr2_v4l2_fh *vnext; | ||
64 | struct pvr2_v4l2_fh *vprev; | ||
65 | wait_queue_head_t wait_data; | ||
66 | int fw_mode_flag; | ||
67 | }; | ||
68 | |||
69 | struct pvr2_v4l2 { | ||
70 | struct pvr2_channel channel; | ||
71 | struct pvr2_v4l2_fh *vfirst; | ||
72 | struct pvr2_v4l2_fh *vlast; | ||
73 | |||
74 | struct v4l2_prio_state prio; | ||
75 | |||
76 | /* streams */ | ||
77 | struct pvr2_v4l2_dev video_dev; | ||
78 | }; | ||
79 | |||
80 | static int video_nr[PVR_NUM] = {[0 ... PVR_NUM-1] = -1}; | ||
81 | module_param_array(video_nr, int, NULL, 0444); | ||
82 | MODULE_PARM_DESC(video_nr, "Offset for device's minor"); | ||
83 | |||
84 | struct v4l2_capability pvr_capability ={ | ||
85 | .driver = "pvrusb2", | ||
86 | .card = "Hauppauge WinTV pvr-usb2", | ||
87 | .bus_info = "usb", | ||
88 | .version = KERNEL_VERSION(0,8,0), | ||
89 | .capabilities = (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VBI_CAPTURE | | ||
90 | V4L2_CAP_TUNER | V4L2_CAP_AUDIO | | ||
91 | V4L2_CAP_READWRITE), | ||
92 | .reserved = {0,0,0,0} | ||
93 | }; | ||
94 | |||
95 | static struct v4l2_tuner pvr_v4l2_tuners[]= { | ||
96 | { | ||
97 | .index = 0, | ||
98 | .name = "TV Tuner", | ||
99 | .type = V4L2_TUNER_ANALOG_TV, | ||
100 | .capability = (V4L2_TUNER_CAP_NORM | | ||
101 | V4L2_TUNER_CAP_STEREO | | ||
102 | V4L2_TUNER_CAP_LANG1 | | ||
103 | V4L2_TUNER_CAP_LANG2), | ||
104 | .rangelow = 0, | ||
105 | .rangehigh = 0, | ||
106 | .rxsubchans = V4L2_TUNER_SUB_STEREO, | ||
107 | .audmode = V4L2_TUNER_MODE_STEREO, | ||
108 | .signal = 0, | ||
109 | .afc = 0, | ||
110 | .reserved = {0,0,0,0} | ||
111 | } | ||
112 | }; | ||
113 | |||
114 | struct v4l2_fmtdesc pvr_fmtdesc [] = { | ||
115 | { | ||
116 | .index = 0, | ||
117 | .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
118 | .flags = V4L2_FMT_FLAG_COMPRESSED, | ||
119 | .description = "MPEG1/2", | ||
120 | // This should really be V4L2_PIX_FMT_MPEG, but xawtv | ||
121 | // breaks when I do that. | ||
122 | .pixelformat = 0, // V4L2_PIX_FMT_MPEG, | ||
123 | .reserved = { 0, 0, 0, 0 } | ||
124 | } | ||
125 | }; | ||
126 | |||
127 | #define PVR_FORMAT_PIX 0 | ||
128 | #define PVR_FORMAT_VBI 1 | ||
129 | |||
130 | struct v4l2_format pvr_format [] = { | ||
131 | [PVR_FORMAT_PIX] = { | ||
132 | .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
133 | .fmt = { | ||
134 | .pix = { | ||
135 | .width = 720, | ||
136 | .height = 576, | ||
137 | // This should really be V4L2_PIX_FMT_MPEG, | ||
138 | // but xawtv breaks when I do that. | ||
139 | .pixelformat = 0, // V4L2_PIX_FMT_MPEG, | ||
140 | .field = V4L2_FIELD_INTERLACED, | ||
141 | .bytesperline = 0, // doesn't make sense | ||
142 | // here | ||
143 | //FIXME : Don't know what to put here... | ||
144 | .sizeimage = (32*1024), | ||
145 | .colorspace = 0, // doesn't make sense here | ||
146 | .priv = 0 | ||
147 | } | ||
148 | } | ||
149 | }, | ||
150 | [PVR_FORMAT_VBI] = { | ||
151 | .type = V4L2_BUF_TYPE_VBI_CAPTURE, | ||
152 | .fmt = { | ||
153 | .vbi = { | ||
154 | .sampling_rate = 27000000, | ||
155 | .offset = 248, | ||
156 | .samples_per_line = 1443, | ||
157 | .sample_format = V4L2_PIX_FMT_GREY, | ||
158 | .start = { 0, 0 }, | ||
159 | .count = { 0, 0 }, | ||
160 | .flags = 0, | ||
161 | .reserved = { 0, 0 } | ||
162 | } | ||
163 | } | ||
164 | } | ||
165 | }; | ||
166 | |||
167 | /* | ||
168 | * pvr_ioctl() | ||
169 | * | ||
170 | * This is part of Video 4 Linux API. The procedure handles ioctl() calls. | ||
171 | * | ||
172 | */ | ||
173 | static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file, | ||
174 | unsigned int cmd, void *arg) | ||
175 | { | ||
176 | struct pvr2_v4l2_fh *fh = file->private_data; | ||
177 | struct pvr2_v4l2 *vp = fh->vhead; | ||
178 | struct pvr2_v4l2_dev *dev_info = fh->dev_info; | ||
179 | struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; | ||
180 | int ret = -EINVAL; | ||
181 | |||
182 | if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) { | ||
183 | v4l_print_ioctl(pvr2_hdw_get_driver_name(hdw),cmd); | ||
184 | } | ||
185 | |||
186 | if (!pvr2_hdw_dev_ok(hdw)) { | ||
187 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, | ||
188 | "ioctl failed - bad or no context"); | ||
189 | return -EFAULT; | ||
190 | } | ||
191 | |||
192 | /* check priority */ | ||
193 | switch (cmd) { | ||
194 | case VIDIOC_S_CTRL: | ||
195 | case VIDIOC_S_STD: | ||
196 | case VIDIOC_S_INPUT: | ||
197 | case VIDIOC_S_TUNER: | ||
198 | case VIDIOC_S_FREQUENCY: | ||
199 | ret = v4l2_prio_check(&vp->prio, &fh->prio); | ||
200 | if (ret) | ||
201 | return ret; | ||
202 | } | ||
203 | |||
204 | switch (cmd) { | ||
205 | case VIDIOC_QUERYCAP: | ||
206 | { | ||
207 | struct v4l2_capability *cap = arg; | ||
208 | |||
209 | memcpy(cap, &pvr_capability, sizeof(struct v4l2_capability)); | ||
210 | |||
211 | ret = 0; | ||
212 | break; | ||
213 | } | ||
214 | |||
215 | case VIDIOC_G_PRIORITY: | ||
216 | { | ||
217 | enum v4l2_priority *p = arg; | ||
218 | |||
219 | *p = v4l2_prio_max(&vp->prio); | ||
220 | ret = 0; | ||
221 | break; | ||
222 | } | ||
223 | |||
224 | case VIDIOC_S_PRIORITY: | ||
225 | { | ||
226 | enum v4l2_priority *prio = arg; | ||
227 | |||
228 | ret = v4l2_prio_change(&vp->prio, &fh->prio, *prio); | ||
229 | break; | ||
230 | } | ||
231 | |||
232 | case VIDIOC_ENUMSTD: | ||
233 | { | ||
234 | struct v4l2_standard *vs = (struct v4l2_standard *)arg; | ||
235 | int idx = vs->index; | ||
236 | ret = pvr2_hdw_get_stdenum_value(hdw,vs,idx+1); | ||
237 | break; | ||
238 | } | ||
239 | |||
240 | case VIDIOC_G_STD: | ||
241 | { | ||
242 | int val = 0; | ||
243 | ret = pvr2_ctrl_get_value( | ||
244 | pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDCUR),&val); | ||
245 | *(v4l2_std_id *)arg = val; | ||
246 | break; | ||
247 | } | ||
248 | |||
249 | case VIDIOC_S_STD: | ||
250 | { | ||
251 | ret = pvr2_ctrl_set_value( | ||
252 | pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDCUR), | ||
253 | *(v4l2_std_id *)arg); | ||
254 | break; | ||
255 | } | ||
256 | |||
257 | case VIDIOC_ENUMINPUT: | ||
258 | { | ||
259 | struct pvr2_ctrl *cptr; | ||
260 | struct v4l2_input *vi = (struct v4l2_input *)arg; | ||
261 | struct v4l2_input tmp; | ||
262 | unsigned int cnt; | ||
263 | |||
264 | cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT); | ||
265 | |||
266 | memset(&tmp,0,sizeof(tmp)); | ||
267 | tmp.index = vi->index; | ||
268 | ret = 0; | ||
269 | switch (vi->index) { | ||
270 | case PVR2_CVAL_INPUT_TV: | ||
271 | case PVR2_CVAL_INPUT_RADIO: | ||
272 | tmp.type = V4L2_INPUT_TYPE_TUNER; | ||
273 | break; | ||
274 | case PVR2_CVAL_INPUT_SVIDEO: | ||
275 | case PVR2_CVAL_INPUT_COMPOSITE: | ||
276 | tmp.type = V4L2_INPUT_TYPE_CAMERA; | ||
277 | break; | ||
278 | default: | ||
279 | ret = -EINVAL; | ||
280 | break; | ||
281 | } | ||
282 | if (ret < 0) break; | ||
283 | |||
284 | cnt = 0; | ||
285 | pvr2_ctrl_get_valname(cptr,vi->index, | ||
286 | tmp.name,sizeof(tmp.name)-1,&cnt); | ||
287 | tmp.name[cnt] = 0; | ||
288 | |||
289 | /* Don't bother with audioset, since this driver currently | ||
290 | always switches the audio whenever the video is | ||
291 | switched. */ | ||
292 | |||
293 | /* Handling std is a tougher problem. It doesn't make | ||
294 | sense in cases where a device might be multi-standard. | ||
295 | We could just copy out the current value for the | ||
296 | standard, but it can change over time. For now just | ||
297 | leave it zero. */ | ||
298 | |||
299 | memcpy(vi, &tmp, sizeof(tmp)); | ||
300 | |||
301 | ret = 0; | ||
302 | break; | ||
303 | } | ||
304 | |||
305 | case VIDIOC_G_INPUT: | ||
306 | { | ||
307 | struct pvr2_ctrl *cptr; | ||
308 | struct v4l2_input *vi = (struct v4l2_input *)arg; | ||
309 | int val; | ||
310 | cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT); | ||
311 | val = 0; | ||
312 | ret = pvr2_ctrl_get_value(cptr,&val); | ||
313 | vi->index = val; | ||
314 | break; | ||
315 | } | ||
316 | |||
317 | case VIDIOC_S_INPUT: | ||
318 | { | ||
319 | struct v4l2_input *vi = (struct v4l2_input *)arg; | ||
320 | ret = pvr2_ctrl_set_value( | ||
321 | pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT), | ||
322 | vi->index); | ||
323 | break; | ||
324 | } | ||
325 | |||
326 | case VIDIOC_ENUMAUDIO: | ||
327 | { | ||
328 | ret = -EINVAL; | ||
329 | break; | ||
330 | } | ||
331 | |||
332 | case VIDIOC_G_AUDIO: | ||
333 | { | ||
334 | ret = -EINVAL; | ||
335 | break; | ||
336 | } | ||
337 | |||
338 | case VIDIOC_S_AUDIO: | ||
339 | { | ||
340 | ret = -EINVAL; | ||
341 | break; | ||
342 | } | ||
343 | case VIDIOC_G_TUNER: | ||
344 | { | ||
345 | struct v4l2_tuner *vt = (struct v4l2_tuner *)arg; | ||
346 | unsigned int status_mask; | ||
347 | int val; | ||
348 | if (vt->index !=0) break; | ||
349 | |||
350 | status_mask = pvr2_hdw_get_signal_status(hdw); | ||
351 | |||
352 | memcpy(vt, &pvr_v4l2_tuners[vt->index], | ||
353 | sizeof(struct v4l2_tuner)); | ||
354 | |||
355 | vt->signal = 0; | ||
356 | if (status_mask & PVR2_SIGNAL_OK) { | ||
357 | if (status_mask & PVR2_SIGNAL_STEREO) { | ||
358 | vt->rxsubchans = V4L2_TUNER_SUB_STEREO; | ||
359 | } else { | ||
360 | vt->rxsubchans = V4L2_TUNER_SUB_MONO; | ||
361 | } | ||
362 | if (status_mask & PVR2_SIGNAL_SAP) { | ||
363 | vt->rxsubchans |= (V4L2_TUNER_SUB_LANG1 | | ||
364 | V4L2_TUNER_SUB_LANG2); | ||
365 | } | ||
366 | vt->signal = 65535; | ||
367 | } | ||
368 | |||
369 | val = 0; | ||
370 | ret = pvr2_ctrl_get_value( | ||
371 | pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_AUDIOMODE), | ||
372 | &val); | ||
373 | vt->audmode = val; | ||
374 | break; | ||
375 | } | ||
376 | |||
377 | case VIDIOC_S_TUNER: | ||
378 | { | ||
379 | struct v4l2_tuner *vt=(struct v4l2_tuner *)arg; | ||
380 | |||
381 | if (vt->index != 0) | ||
382 | break; | ||
383 | |||
384 | ret = pvr2_ctrl_set_value( | ||
385 | pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_AUDIOMODE), | ||
386 | vt->audmode); | ||
387 | } | ||
388 | |||
389 | case VIDIOC_S_FREQUENCY: | ||
390 | { | ||
391 | const struct v4l2_frequency *vf = (struct v4l2_frequency *)arg; | ||
392 | ret = pvr2_ctrl_set_value( | ||
393 | pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_FREQUENCY), | ||
394 | vf->frequency * 62500); | ||
395 | break; | ||
396 | } | ||
397 | |||
398 | case VIDIOC_G_FREQUENCY: | ||
399 | { | ||
400 | struct v4l2_frequency *vf = (struct v4l2_frequency *)arg; | ||
401 | int val = 0; | ||
402 | ret = pvr2_ctrl_get_value( | ||
403 | pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_FREQUENCY), | ||
404 | &val); | ||
405 | val /= 62500; | ||
406 | vf->frequency = val; | ||
407 | break; | ||
408 | } | ||
409 | |||
410 | case VIDIOC_ENUM_FMT: | ||
411 | { | ||
412 | struct v4l2_fmtdesc *fd = (struct v4l2_fmtdesc *)arg; | ||
413 | |||
414 | /* Only one format is supported : mpeg.*/ | ||
415 | if (fd->index != 0) | ||
416 | break; | ||
417 | |||
418 | memcpy(fd, pvr_fmtdesc, sizeof(struct v4l2_fmtdesc)); | ||
419 | ret = 0; | ||
420 | break; | ||
421 | } | ||
422 | |||
423 | case VIDIOC_G_FMT: | ||
424 | { | ||
425 | struct v4l2_format *vf = (struct v4l2_format *)arg; | ||
426 | int val; | ||
427 | switch(vf->type) { | ||
428 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | ||
429 | memcpy(vf, &pvr_format[PVR_FORMAT_PIX], | ||
430 | sizeof(struct v4l2_format)); | ||
431 | val = 0; | ||
432 | pvr2_ctrl_get_value( | ||
433 | pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_HRES), | ||
434 | &val); | ||
435 | vf->fmt.pix.width = val; | ||
436 | val = 0; | ||
437 | pvr2_ctrl_get_value( | ||
438 | pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_VRES), | ||
439 | &val); | ||
440 | vf->fmt.pix.height = val; | ||
441 | ret = 0; | ||
442 | break; | ||
443 | case V4L2_BUF_TYPE_VBI_CAPTURE: | ||
444 | // ????? Still need to figure out to do VBI correctly | ||
445 | ret = -EINVAL; | ||
446 | break; | ||
447 | default: | ||
448 | ret = -EINVAL; | ||
449 | break; | ||
450 | } | ||
451 | break; | ||
452 | } | ||
453 | |||
454 | case VIDIOC_TRY_FMT: | ||
455 | case VIDIOC_S_FMT: | ||
456 | { | ||
457 | struct v4l2_format *vf = (struct v4l2_format *)arg; | ||
458 | |||
459 | ret = 0; | ||
460 | switch(vf->type) { | ||
461 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: { | ||
462 | int h = vf->fmt.pix.height; | ||
463 | int w = vf->fmt.pix.width; | ||
464 | |||
465 | if (h < 200) { | ||
466 | h = 200; | ||
467 | } else if (h > 625) { | ||
468 | h = 625; | ||
469 | } | ||
470 | if (w < 320) { | ||
471 | w = 320; | ||
472 | } else if (w > 720) { | ||
473 | w = 720; | ||
474 | } | ||
475 | |||
476 | memcpy(vf, &pvr_format[PVR_FORMAT_PIX], | ||
477 | sizeof(struct v4l2_format)); | ||
478 | vf->fmt.pix.width = w; | ||
479 | vf->fmt.pix.height = h; | ||
480 | |||
481 | if (cmd == VIDIOC_S_FMT) { | ||
482 | pvr2_ctrl_set_value( | ||
483 | pvr2_hdw_get_ctrl_by_id(hdw, | ||
484 | PVR2_CID_HRES), | ||
485 | vf->fmt.pix.width); | ||
486 | pvr2_ctrl_set_value( | ||
487 | pvr2_hdw_get_ctrl_by_id(hdw, | ||
488 | PVR2_CID_VRES), | ||
489 | vf->fmt.pix.height); | ||
490 | } | ||
491 | } break; | ||
492 | case V4L2_BUF_TYPE_VBI_CAPTURE: | ||
493 | // ????? Still need to figure out to do VBI correctly | ||
494 | ret = -EINVAL; | ||
495 | break; | ||
496 | default: | ||
497 | ret = -EINVAL; | ||
498 | break; | ||
499 | } | ||
500 | break; | ||
501 | } | ||
502 | |||
503 | case VIDIOC_STREAMON: | ||
504 | { | ||
505 | ret = pvr2_hdw_set_stream_type(hdw,dev_info->config); | ||
506 | if (ret < 0) return ret; | ||
507 | ret = pvr2_hdw_set_streaming(hdw,!0); | ||
508 | break; | ||
509 | } | ||
510 | |||
511 | case VIDIOC_STREAMOFF: | ||
512 | { | ||
513 | ret = pvr2_hdw_set_streaming(hdw,0); | ||
514 | break; | ||
515 | } | ||
516 | |||
517 | case VIDIOC_QUERYCTRL: | ||
518 | { | ||
519 | struct pvr2_ctrl *cptr; | ||
520 | struct v4l2_queryctrl *vc = (struct v4l2_queryctrl *)arg; | ||
521 | ret = 0; | ||
522 | if (vc->id & V4L2_CTRL_FLAG_NEXT_CTRL) { | ||
523 | cptr = pvr2_hdw_get_ctrl_nextv4l( | ||
524 | hdw,(vc->id & ~V4L2_CTRL_FLAG_NEXT_CTRL)); | ||
525 | if (cptr) vc->id = pvr2_ctrl_get_v4lid(cptr); | ||
526 | } else { | ||
527 | cptr = pvr2_hdw_get_ctrl_v4l(hdw,vc->id); | ||
528 | } | ||
529 | if (!cptr) { | ||
530 | pvr2_trace(PVR2_TRACE_V4LIOCTL, | ||
531 | "QUERYCTRL id=0x%x not implemented here", | ||
532 | vc->id); | ||
533 | ret = -EINVAL; | ||
534 | break; | ||
535 | } | ||
536 | |||
537 | pvr2_trace(PVR2_TRACE_V4LIOCTL, | ||
538 | "QUERYCTRL id=0x%x mapping name=%s (%s)", | ||
539 | vc->id,pvr2_ctrl_get_name(cptr), | ||
540 | pvr2_ctrl_get_desc(cptr)); | ||
541 | strlcpy(vc->name,pvr2_ctrl_get_desc(cptr),sizeof(vc->name)); | ||
542 | vc->flags = pvr2_ctrl_get_v4lflags(cptr); | ||
543 | vc->default_value = pvr2_ctrl_get_def(cptr); | ||
544 | switch (pvr2_ctrl_get_type(cptr)) { | ||
545 | case pvr2_ctl_enum: | ||
546 | vc->type = V4L2_CTRL_TYPE_MENU; | ||
547 | vc->minimum = 0; | ||
548 | vc->maximum = pvr2_ctrl_get_cnt(cptr) - 1; | ||
549 | vc->step = 1; | ||
550 | break; | ||
551 | case pvr2_ctl_bool: | ||
552 | vc->type = V4L2_CTRL_TYPE_BOOLEAN; | ||
553 | vc->minimum = 0; | ||
554 | vc->maximum = 1; | ||
555 | vc->step = 1; | ||
556 | break; | ||
557 | case pvr2_ctl_int: | ||
558 | vc->type = V4L2_CTRL_TYPE_INTEGER; | ||
559 | vc->minimum = pvr2_ctrl_get_min(cptr); | ||
560 | vc->maximum = pvr2_ctrl_get_max(cptr); | ||
561 | vc->step = 1; | ||
562 | break; | ||
563 | default: | ||
564 | pvr2_trace(PVR2_TRACE_V4LIOCTL, | ||
565 | "QUERYCTRL id=0x%x name=%s not mappable", | ||
566 | vc->id,pvr2_ctrl_get_name(cptr)); | ||
567 | ret = -EINVAL; | ||
568 | break; | ||
569 | } | ||
570 | break; | ||
571 | } | ||
572 | |||
573 | case VIDIOC_QUERYMENU: | ||
574 | { | ||
575 | struct v4l2_querymenu *vm = (struct v4l2_querymenu *)arg; | ||
576 | unsigned int cnt = 0; | ||
577 | ret = pvr2_ctrl_get_valname(pvr2_hdw_get_ctrl_v4l(hdw,vm->id), | ||
578 | vm->index, | ||
579 | vm->name,sizeof(vm->name)-1, | ||
580 | &cnt); | ||
581 | vm->name[cnt] = 0; | ||
582 | break; | ||
583 | } | ||
584 | |||
585 | case VIDIOC_G_CTRL: | ||
586 | { | ||
587 | struct v4l2_control *vc = (struct v4l2_control *)arg; | ||
588 | int val = 0; | ||
589 | ret = pvr2_ctrl_get_value(pvr2_hdw_get_ctrl_v4l(hdw,vc->id), | ||
590 | &val); | ||
591 | vc->value = val; | ||
592 | break; | ||
593 | } | ||
594 | |||
595 | case VIDIOC_S_CTRL: | ||
596 | { | ||
597 | struct v4l2_control *vc = (struct v4l2_control *)arg; | ||
598 | ret = pvr2_ctrl_set_value(pvr2_hdw_get_ctrl_v4l(hdw,vc->id), | ||
599 | vc->value); | ||
600 | break; | ||
601 | } | ||
602 | |||
603 | case VIDIOC_G_EXT_CTRLS: | ||
604 | { | ||
605 | struct v4l2_ext_controls *ctls = | ||
606 | (struct v4l2_ext_controls *)arg; | ||
607 | struct v4l2_ext_control *ctrl; | ||
608 | unsigned int idx; | ||
609 | int val; | ||
610 | for (idx = 0; idx < ctls->count; idx++) { | ||
611 | ctrl = ctls->controls + idx; | ||
612 | ret = pvr2_ctrl_get_value( | ||
613 | pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id),&val); | ||
614 | if (ret) { | ||
615 | ctls->error_idx = idx; | ||
616 | break; | ||
617 | } | ||
618 | /* Ensure that if read as a 64 bit value, the user | ||
619 | will still get a hopefully sane value */ | ||
620 | ctrl->value64 = 0; | ||
621 | ctrl->value = val; | ||
622 | } | ||
623 | break; | ||
624 | } | ||
625 | |||
626 | case VIDIOC_S_EXT_CTRLS: | ||
627 | { | ||
628 | struct v4l2_ext_controls *ctls = | ||
629 | (struct v4l2_ext_controls *)arg; | ||
630 | struct v4l2_ext_control *ctrl; | ||
631 | unsigned int idx; | ||
632 | for (idx = 0; idx < ctls->count; idx++) { | ||
633 | ctrl = ctls->controls + idx; | ||
634 | ret = pvr2_ctrl_set_value( | ||
635 | pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id), | ||
636 | ctrl->value); | ||
637 | if (ret) { | ||
638 | ctls->error_idx = idx; | ||
639 | break; | ||
640 | } | ||
641 | } | ||
642 | break; | ||
643 | } | ||
644 | |||
645 | case VIDIOC_TRY_EXT_CTRLS: | ||
646 | { | ||
647 | struct v4l2_ext_controls *ctls = | ||
648 | (struct v4l2_ext_controls *)arg; | ||
649 | struct v4l2_ext_control *ctrl; | ||
650 | struct pvr2_ctrl *pctl; | ||
651 | unsigned int idx; | ||
652 | /* For the moment just validate that the requested control | ||
653 | actually exists. */ | ||
654 | for (idx = 0; idx < ctls->count; idx++) { | ||
655 | ctrl = ctls->controls + idx; | ||
656 | pctl = pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id); | ||
657 | if (!pctl) { | ||
658 | ret = -EINVAL; | ||
659 | ctls->error_idx = idx; | ||
660 | break; | ||
661 | } | ||
662 | } | ||
663 | break; | ||
664 | } | ||
665 | |||
666 | case VIDIOC_LOG_STATUS: | ||
667 | { | ||
668 | pvr2_hdw_trigger_module_log(hdw); | ||
669 | ret = 0; | ||
670 | break; | ||
671 | } | ||
672 | |||
673 | default : | ||
674 | ret = v4l_compat_translate_ioctl(inode,file,cmd, | ||
675 | arg,pvr2_v4l2_do_ioctl); | ||
676 | } | ||
677 | |||
678 | pvr2_hdw_commit_ctl(hdw); | ||
679 | |||
680 | if (ret < 0) { | ||
681 | if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) { | ||
682 | pvr2_trace(PVR2_TRACE_V4LIOCTL, | ||
683 | "pvr2_v4l2_do_ioctl failure, ret=%d",ret); | ||
684 | } else { | ||
685 | if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) { | ||
686 | pvr2_trace(PVR2_TRACE_V4LIOCTL, | ||
687 | "pvr2_v4l2_do_ioctl failure, ret=%d" | ||
688 | " command was:",ret); | ||
689 | v4l_print_ioctl(pvr2_hdw_get_driver_name(hdw), | ||
690 | cmd); | ||
691 | } | ||
692 | } | ||
693 | } else { | ||
694 | pvr2_trace(PVR2_TRACE_V4LIOCTL, | ||
695 | "pvr2_v4l2_do_ioctl complete, ret=%d (0x%x)", | ||
696 | ret,ret); | ||
697 | } | ||
698 | return ret; | ||
699 | } | ||
700 | |||
701 | |||
702 | static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip) | ||
703 | { | ||
704 | pvr2_trace(PVR2_TRACE_INIT, | ||
705 | "unregistering device video%d [%s]", | ||
706 | dip->vdev->minor,pvr2_config_get_name(dip->config)); | ||
707 | if (dip->ctxt_idx >= 0) { | ||
708 | mutex_lock(&device_lock); | ||
709 | devices[dip->ctxt_idx] = NULL; | ||
710 | dip->ctxt_idx = -1; | ||
711 | mutex_unlock(&device_lock); | ||
712 | } | ||
713 | video_unregister_device(dip->vdev); | ||
714 | } | ||
715 | |||
716 | |||
717 | static void pvr2_v4l2_destroy_no_lock(struct pvr2_v4l2 *vp) | ||
718 | { | ||
719 | pvr2_hdw_v4l_store_minor_number(vp->channel.mc_head->hdw,-1); | ||
720 | pvr2_v4l2_dev_destroy(&vp->video_dev); | ||
721 | |||
722 | pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr2_v4l2 id=%p",vp); | ||
723 | pvr2_channel_done(&vp->channel); | ||
724 | kfree(vp); | ||
725 | } | ||
726 | |||
727 | |||
728 | void pvr2_v4l2_internal_check(struct pvr2_channel *chp) | ||
729 | { | ||
730 | struct pvr2_v4l2 *vp; | ||
731 | vp = container_of(chp,struct pvr2_v4l2,channel); | ||
732 | if (!vp->channel.mc_head->disconnect_flag) return; | ||
733 | if (vp->vfirst) return; | ||
734 | pvr2_v4l2_destroy_no_lock(vp); | ||
735 | } | ||
736 | |||
737 | |||
738 | int pvr2_v4l2_ioctl(struct inode *inode, struct file *file, | ||
739 | unsigned int cmd, unsigned long arg) | ||
740 | { | ||
741 | |||
742 | /* Temporary hack : use ivtv api until a v4l2 one is available. */ | ||
743 | #define IVTV_IOC_G_CODEC 0xFFEE7703 | ||
744 | #define IVTV_IOC_S_CODEC 0xFFEE7704 | ||
745 | if (cmd == IVTV_IOC_G_CODEC || cmd == IVTV_IOC_S_CODEC) return 0; | ||
746 | return video_usercopy(inode, file, cmd, arg, pvr2_v4l2_do_ioctl); | ||
747 | } | ||
748 | |||
749 | |||
750 | int pvr2_v4l2_release(struct inode *inode, struct file *file) | ||
751 | { | ||
752 | struct pvr2_v4l2_fh *fhp = file->private_data; | ||
753 | struct pvr2_v4l2 *vp = fhp->vhead; | ||
754 | struct pvr2_context *mp = fhp->vhead->channel.mc_head; | ||
755 | |||
756 | pvr2_trace(PVR2_TRACE_OPEN_CLOSE,"pvr2_v4l2_release"); | ||
757 | |||
758 | if (fhp->rhp) { | ||
759 | struct pvr2_stream *sp; | ||
760 | struct pvr2_hdw *hdw; | ||
761 | hdw = fhp->channel.mc_head->hdw; | ||
762 | pvr2_hdw_set_streaming(hdw,0); | ||
763 | sp = pvr2_ioread_get_stream(fhp->rhp); | ||
764 | if (sp) pvr2_stream_set_callback(sp,0,0); | ||
765 | pvr2_ioread_destroy(fhp->rhp); | ||
766 | fhp->rhp = 0; | ||
767 | } | ||
768 | v4l2_prio_close(&vp->prio, &fhp->prio); | ||
769 | file->private_data = NULL; | ||
770 | |||
771 | pvr2_context_enter(mp); do { | ||
772 | if (fhp->vnext) { | ||
773 | fhp->vnext->vprev = fhp->vprev; | ||
774 | } else { | ||
775 | vp->vlast = fhp->vprev; | ||
776 | } | ||
777 | if (fhp->vprev) { | ||
778 | fhp->vprev->vnext = fhp->vnext; | ||
779 | } else { | ||
780 | vp->vfirst = fhp->vnext; | ||
781 | } | ||
782 | fhp->vnext = 0; | ||
783 | fhp->vprev = 0; | ||
784 | fhp->vhead = 0; | ||
785 | pvr2_channel_done(&fhp->channel); | ||
786 | pvr2_trace(PVR2_TRACE_STRUCT, | ||
787 | "Destroying pvr_v4l2_fh id=%p",fhp); | ||
788 | kfree(fhp); | ||
789 | if (vp->channel.mc_head->disconnect_flag && !vp->vfirst) { | ||
790 | pvr2_v4l2_destroy_no_lock(vp); | ||
791 | } | ||
792 | } while (0); pvr2_context_exit(mp); | ||
793 | return 0; | ||
794 | } | ||
795 | |||
796 | |||
797 | int pvr2_v4l2_open(struct inode *inode, struct file *file) | ||
798 | { | ||
799 | struct pvr2_v4l2_dev *dip = 0; /* Our own context pointer */ | ||
800 | struct pvr2_v4l2_fh *fhp; | ||
801 | struct pvr2_v4l2 *vp; | ||
802 | struct pvr2_hdw *hdw; | ||
803 | |||
804 | mutex_lock(&device_lock); | ||
805 | /* MCI 7-Jun-2006 Even though we're just doing what amounts to an | ||
806 | atomic read of the device mapping array here, we still need the | ||
807 | mutex. The problem is that there is a tiny race possible when | ||
808 | we register the device. We can't update the device mapping | ||
809 | array until after the device has been registered, owing to the | ||
810 | fact that we can't know the minor device number until after the | ||
811 | registration succeeds. And if another thread tries to open the | ||
812 | device in the window of time after registration but before the | ||
813 | map is updated, then it will get back an erroneous null pointer | ||
814 | and the open will result in a spurious failure. The only way to | ||
815 | prevent that is to (a) be inside the mutex here before we access | ||
816 | the array, and (b) cover the entire registration process later | ||
817 | on with this same mutex. Thus if we get inside the mutex here, | ||
818 | then we can be assured that the registration process actually | ||
819 | completed correctly. This is an unhappy complication from the | ||
820 | use of global data in a driver that lives in a preemptible | ||
821 | environment. It sure would be nice if the video device itself | ||
822 | had a means for storing and retrieving a local context pointer. | ||
823 | Oh wait. It did. But now it's gone. Silly me. */ | ||
824 | { | ||
825 | unsigned int midx = iminor(file->f_dentry->d_inode); | ||
826 | if (midx < sizeof(devices)/sizeof(devices[0])) { | ||
827 | dip = devices[midx]; | ||
828 | } | ||
829 | } | ||
830 | mutex_unlock(&device_lock); | ||
831 | |||
832 | if (!dip) return -ENODEV; /* Should be impossible but I'm paranoid */ | ||
833 | |||
834 | vp = dip->v4lp; | ||
835 | hdw = vp->channel.hdw; | ||
836 | |||
837 | pvr2_trace(PVR2_TRACE_OPEN_CLOSE,"pvr2_v4l2_open"); | ||
838 | |||
839 | if (!pvr2_hdw_dev_ok(hdw)) { | ||
840 | pvr2_trace(PVR2_TRACE_OPEN_CLOSE, | ||
841 | "pvr2_v4l2_open: hardware not ready"); | ||
842 | return -EIO; | ||
843 | } | ||
844 | |||
845 | fhp = kmalloc(sizeof(*fhp),GFP_KERNEL); | ||
846 | if (!fhp) { | ||
847 | return -ENOMEM; | ||
848 | } | ||
849 | memset(fhp,0,sizeof(*fhp)); | ||
850 | |||
851 | init_waitqueue_head(&fhp->wait_data); | ||
852 | fhp->dev_info = dip; | ||
853 | |||
854 | pvr2_context_enter(vp->channel.mc_head); do { | ||
855 | pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr_v4l2_fh id=%p",fhp); | ||
856 | pvr2_channel_init(&fhp->channel,vp->channel.mc_head); | ||
857 | fhp->vnext = 0; | ||
858 | fhp->vprev = vp->vlast; | ||
859 | if (vp->vlast) { | ||
860 | vp->vlast->vnext = fhp; | ||
861 | } else { | ||
862 | vp->vfirst = fhp; | ||
863 | } | ||
864 | vp->vlast = fhp; | ||
865 | fhp->vhead = vp; | ||
866 | } while (0); pvr2_context_exit(vp->channel.mc_head); | ||
867 | |||
868 | fhp->file = file; | ||
869 | file->private_data = fhp; | ||
870 | v4l2_prio_open(&vp->prio,&fhp->prio); | ||
871 | |||
872 | fhp->fw_mode_flag = pvr2_hdw_cpufw_get_enabled(hdw); | ||
873 | |||
874 | return 0; | ||
875 | } | ||
876 | |||
877 | |||
878 | static void pvr2_v4l2_notify(struct pvr2_v4l2_fh *fhp) | ||
879 | { | ||
880 | wake_up(&fhp->wait_data); | ||
881 | } | ||
882 | |||
883 | static int pvr2_v4l2_iosetup(struct pvr2_v4l2_fh *fh) | ||
884 | { | ||
885 | int ret; | ||
886 | struct pvr2_stream *sp; | ||
887 | struct pvr2_hdw *hdw; | ||
888 | if (fh->rhp) return 0; | ||
889 | |||
890 | /* First read() attempt. Try to claim the stream and start | ||
891 | it... */ | ||
892 | if ((ret = pvr2_channel_claim_stream(&fh->channel, | ||
893 | fh->dev_info->stream)) != 0) { | ||
894 | /* Someone else must already have it */ | ||
895 | return ret; | ||
896 | } | ||
897 | |||
898 | fh->rhp = pvr2_channel_create_mpeg_stream(fh->dev_info->stream); | ||
899 | if (!fh->rhp) { | ||
900 | pvr2_channel_claim_stream(&fh->channel,0); | ||
901 | return -ENOMEM; | ||
902 | } | ||
903 | |||
904 | hdw = fh->channel.mc_head->hdw; | ||
905 | sp = fh->dev_info->stream->stream; | ||
906 | pvr2_stream_set_callback(sp,(pvr2_stream_callback)pvr2_v4l2_notify,fh); | ||
907 | pvr2_hdw_set_stream_type(hdw,fh->dev_info->config); | ||
908 | pvr2_hdw_set_streaming(hdw,!0); | ||
909 | ret = pvr2_ioread_set_enabled(fh->rhp,!0); | ||
910 | |||
911 | return ret; | ||
912 | } | ||
913 | |||
914 | |||
915 | static ssize_t pvr2_v4l2_read(struct file *file, | ||
916 | char __user *buff, size_t count, loff_t *ppos) | ||
917 | { | ||
918 | struct pvr2_v4l2_fh *fh = file->private_data; | ||
919 | int ret; | ||
920 | |||
921 | if (fh->fw_mode_flag) { | ||
922 | struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; | ||
923 | char *tbuf; | ||
924 | int c1,c2; | ||
925 | int tcnt = 0; | ||
926 | unsigned int offs = *ppos; | ||
927 | |||
928 | tbuf = kmalloc(PAGE_SIZE,GFP_KERNEL); | ||
929 | if (!tbuf) return -ENOMEM; | ||
930 | |||
931 | while (count) { | ||
932 | c1 = count; | ||
933 | if (c1 > PAGE_SIZE) c1 = PAGE_SIZE; | ||
934 | c2 = pvr2_hdw_cpufw_get(hdw,offs,tbuf,c1); | ||
935 | if (c2 < 0) { | ||
936 | tcnt = c2; | ||
937 | break; | ||
938 | } | ||
939 | if (!c2) break; | ||
940 | if (copy_to_user(buff,tbuf,c2)) { | ||
941 | tcnt = -EFAULT; | ||
942 | break; | ||
943 | } | ||
944 | offs += c2; | ||
945 | tcnt += c2; | ||
946 | buff += c2; | ||
947 | count -= c2; | ||
948 | *ppos += c2; | ||
949 | } | ||
950 | kfree(tbuf); | ||
951 | return tcnt; | ||
952 | } | ||
953 | |||
954 | if (!fh->rhp) { | ||
955 | ret = pvr2_v4l2_iosetup(fh); | ||
956 | if (ret) { | ||
957 | return ret; | ||
958 | } | ||
959 | } | ||
960 | |||
961 | for (;;) { | ||
962 | ret = pvr2_ioread_read(fh->rhp,buff,count); | ||
963 | if (ret >= 0) break; | ||
964 | if (ret != -EAGAIN) break; | ||
965 | if (file->f_flags & O_NONBLOCK) break; | ||
966 | /* Doing blocking I/O. Wait here. */ | ||
967 | ret = wait_event_interruptible( | ||
968 | fh->wait_data, | ||
969 | pvr2_ioread_avail(fh->rhp) >= 0); | ||
970 | if (ret < 0) break; | ||
971 | } | ||
972 | |||
973 | return ret; | ||
974 | } | ||
975 | |||
976 | |||
977 | static unsigned int pvr2_v4l2_poll(struct file *file, poll_table *wait) | ||
978 | { | ||
979 | unsigned int mask = 0; | ||
980 | struct pvr2_v4l2_fh *fh = file->private_data; | ||
981 | int ret; | ||
982 | |||
983 | if (fh->fw_mode_flag) { | ||
984 | mask |= POLLIN | POLLRDNORM; | ||
985 | return mask; | ||
986 | } | ||
987 | |||
988 | if (!fh->rhp) { | ||
989 | ret = pvr2_v4l2_iosetup(fh); | ||
990 | if (ret) return POLLERR; | ||
991 | } | ||
992 | |||
993 | poll_wait(file,&fh->wait_data,wait); | ||
994 | |||
995 | if (pvr2_ioread_avail(fh->rhp) >= 0) { | ||
996 | mask |= POLLIN | POLLRDNORM; | ||
997 | } | ||
998 | |||
999 | return mask; | ||
1000 | } | ||
1001 | |||
1002 | |||
1003 | static struct file_operations vdev_fops = { | ||
1004 | .owner = THIS_MODULE, | ||
1005 | .open = pvr2_v4l2_open, | ||
1006 | .release = pvr2_v4l2_release, | ||
1007 | .read = pvr2_v4l2_read, | ||
1008 | .ioctl = pvr2_v4l2_ioctl, | ||
1009 | .llseek = no_llseek, | ||
1010 | .poll = pvr2_v4l2_poll, | ||
1011 | }; | ||
1012 | |||
1013 | |||
1014 | #define VID_HARDWARE_PVRUSB2 38 /* FIXME : need a good value */ | ||
1015 | |||
1016 | static struct video_device vdev_template = { | ||
1017 | .owner = THIS_MODULE, | ||
1018 | .type = VID_TYPE_CAPTURE | VID_TYPE_TUNER, | ||
1019 | .type2 = (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VBI_CAPTURE | ||
1020 | | V4L2_CAP_TUNER | V4L2_CAP_AUDIO | ||
1021 | | V4L2_CAP_READWRITE), | ||
1022 | .hardware = VID_HARDWARE_PVRUSB2, | ||
1023 | .fops = &vdev_fops, | ||
1024 | }; | ||
1025 | |||
1026 | |||
1027 | static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip, | ||
1028 | struct pvr2_v4l2 *vp, | ||
1029 | enum pvr2_config cfg) | ||
1030 | { | ||
1031 | int mindevnum; | ||
1032 | int unit_number; | ||
1033 | int v4l_type; | ||
1034 | dip->v4lp = vp; | ||
1035 | dip->config = cfg; | ||
1036 | |||
1037 | |||
1038 | switch (cfg) { | ||
1039 | case pvr2_config_mpeg: | ||
1040 | v4l_type = VFL_TYPE_GRABBER; | ||
1041 | dip->stream = &vp->channel.mc_head->video_stream; | ||
1042 | break; | ||
1043 | case pvr2_config_vbi: | ||
1044 | v4l_type = VFL_TYPE_VBI; | ||
1045 | break; | ||
1046 | case pvr2_config_radio: | ||
1047 | v4l_type = VFL_TYPE_RADIO; | ||
1048 | break; | ||
1049 | default: | ||
1050 | /* Bail out (this should be impossible) */ | ||
1051 | err("Failed to set up pvrusb2 v4l dev" | ||
1052 | " due to unrecognized config"); | ||
1053 | return; | ||
1054 | } | ||
1055 | |||
1056 | if (!dip->stream) { | ||
1057 | err("Failed to set up pvrusb2 v4l dev" | ||
1058 | " due to missing stream instance"); | ||
1059 | return; | ||
1060 | } | ||
1061 | |||
1062 | dip->vdev = video_device_alloc(); | ||
1063 | if (!dip->vdev) { | ||
1064 | err("Alloc of pvrusb2 v4l video device failed"); | ||
1065 | return; | ||
1066 | } | ||
1067 | |||
1068 | memcpy(dip->vdev,&vdev_template,sizeof(vdev_template)); | ||
1069 | dip->vdev->release = video_device_release; | ||
1070 | mutex_lock(&device_lock); | ||
1071 | |||
1072 | mindevnum = -1; | ||
1073 | unit_number = pvr2_hdw_get_unit_number(vp->channel.mc_head->hdw); | ||
1074 | if ((unit_number >= 0) && (unit_number < PVR_NUM)) { | ||
1075 | mindevnum = video_nr[unit_number]; | ||
1076 | } | ||
1077 | if ((video_register_device(dip->vdev, v4l_type, mindevnum) < 0) && | ||
1078 | (video_register_device(dip->vdev, v4l_type, -1) < 0)) { | ||
1079 | err("Failed to register pvrusb2 v4l video device"); | ||
1080 | } else { | ||
1081 | pvr2_trace(PVR2_TRACE_INIT, | ||
1082 | "registered device video%d [%s]", | ||
1083 | dip->vdev->minor,pvr2_config_get_name(dip->config)); | ||
1084 | } | ||
1085 | |||
1086 | if ((dip->vdev->minor < sizeof(devices)/sizeof(devices[0])) && | ||
1087 | (devices[dip->vdev->minor] == NULL)) { | ||
1088 | dip->ctxt_idx = dip->vdev->minor; | ||
1089 | devices[dip->ctxt_idx] = dip; | ||
1090 | } | ||
1091 | mutex_unlock(&device_lock); | ||
1092 | |||
1093 | pvr2_hdw_v4l_store_minor_number(vp->channel.mc_head->hdw, | ||
1094 | dip->vdev->minor); | ||
1095 | } | ||
1096 | |||
1097 | |||
1098 | struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *mnp) | ||
1099 | { | ||
1100 | struct pvr2_v4l2 *vp; | ||
1101 | |||
1102 | vp = kmalloc(sizeof(*vp),GFP_KERNEL); | ||
1103 | if (!vp) return vp; | ||
1104 | memset(vp,0,sizeof(*vp)); | ||
1105 | vp->video_dev.ctxt_idx = -1; | ||
1106 | pvr2_channel_init(&vp->channel,mnp); | ||
1107 | pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr2_v4l2 id=%p",vp); | ||
1108 | |||
1109 | vp->channel.check_func = pvr2_v4l2_internal_check; | ||
1110 | |||
1111 | /* register streams */ | ||
1112 | pvr2_v4l2_dev_init(&vp->video_dev,vp,pvr2_config_mpeg); | ||
1113 | |||
1114 | |||
1115 | return vp; | ||
1116 | } | ||
1117 | |||
1118 | /* | ||
1119 | Stuff for Emacs to see, in order to encourage consistent editing style: | ||
1120 | *** Local Variables: *** | ||
1121 | *** mode: c *** | ||
1122 | *** fill-column: 75 *** | ||
1123 | *** tab-width: 8 *** | ||
1124 | *** c-basic-offset: 8 *** | ||
1125 | *** End: *** | ||
1126 | */ | ||
diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.h b/drivers/media/video/pvrusb2/pvrusb2-v4l2.h new file mode 100644 index 000000000000..9a995e2d2256 --- /dev/null +++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.h | |||
@@ -0,0 +1,40 @@ | |||
1 | /* | ||
2 | * | ||
3 | * $Id$ | ||
4 | * | ||
5 | * Copyright (C) 2005 Mike Isely <isely@pobox.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 | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | * | ||
20 | */ | ||
21 | #ifndef __PVRUSB2_V4L2_H | ||
22 | #define __PVRUSB2_V4L2_H | ||
23 | |||
24 | #include "pvrusb2-context.h" | ||
25 | |||
26 | struct pvr2_v4l2; | ||
27 | |||
28 | struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *); | ||
29 | |||
30 | #endif /* __PVRUSB2_V4L2_H */ | ||
31 | |||
32 | /* | ||
33 | Stuff for Emacs to see, in order to encourage consistent editing style: | ||
34 | *** Local Variables: *** | ||
35 | *** mode: c *** | ||
36 | *** fill-column: 75 *** | ||
37 | *** tab-width: 8 *** | ||
38 | *** c-basic-offset: 8 *** | ||
39 | *** End: *** | ||
40 | */ | ||
diff --git a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c new file mode 100644 index 000000000000..e4ec7f25194c --- /dev/null +++ b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c | |||
@@ -0,0 +1,253 @@ | |||
1 | /* | ||
2 | * | ||
3 | * $Id$ | ||
4 | * | ||
5 | * Copyright (C) 2005 Mike Isely <isely@pobox.com> | ||
6 | * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License | ||
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 | |||
23 | /* | ||
24 | |||
25 | This source file is specifically designed to interface with the | ||
26 | saa711x support that is available in the v4l available starting | ||
27 | with linux 2.6.15. | ||
28 | |||
29 | */ | ||
30 | |||
31 | #include "pvrusb2-video-v4l.h" | ||
32 | #include "pvrusb2-i2c-cmd-v4l2.h" | ||
33 | |||
34 | |||
35 | #include "pvrusb2-hdw-internal.h" | ||
36 | #include "pvrusb2-debug.h" | ||
37 | #include <linux/videodev2.h> | ||
38 | #include <media/v4l2-common.h> | ||
39 | #include <media/saa7115.h> | ||
40 | #include <linux/errno.h> | ||
41 | #include <linux/slab.h> | ||
42 | |||
43 | struct pvr2_v4l_decoder { | ||
44 | struct pvr2_i2c_handler handler; | ||
45 | struct pvr2_decoder_ctrl ctrl; | ||
46 | struct pvr2_i2c_client *client; | ||
47 | struct pvr2_hdw *hdw; | ||
48 | unsigned long stale_mask; | ||
49 | }; | ||
50 | |||
51 | |||
52 | static void set_input(struct pvr2_v4l_decoder *ctxt) | ||
53 | { | ||
54 | struct pvr2_hdw *hdw = ctxt->hdw; | ||
55 | struct v4l2_routing route; | ||
56 | |||
57 | pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_input(%d)",hdw->input_val); | ||
58 | switch(hdw->input_val) { | ||
59 | case PVR2_CVAL_INPUT_TV: | ||
60 | route.input = SAA7115_COMPOSITE4; | ||
61 | break; | ||
62 | case PVR2_CVAL_INPUT_COMPOSITE: | ||
63 | route.input = SAA7115_COMPOSITE5; | ||
64 | break; | ||
65 | case PVR2_CVAL_INPUT_SVIDEO: | ||
66 | route.input = SAA7115_SVIDEO2; | ||
67 | break; | ||
68 | case PVR2_CVAL_INPUT_RADIO: | ||
69 | // ????? No idea yet what to do here | ||
70 | default: | ||
71 | return; | ||
72 | } | ||
73 | route.output = 0; | ||
74 | pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_VIDEO_ROUTING,&route); | ||
75 | } | ||
76 | |||
77 | |||
78 | static int check_input(struct pvr2_v4l_decoder *ctxt) | ||
79 | { | ||
80 | struct pvr2_hdw *hdw = ctxt->hdw; | ||
81 | return hdw->input_dirty != 0; | ||
82 | } | ||
83 | |||
84 | |||
85 | static void set_audio(struct pvr2_v4l_decoder *ctxt) | ||
86 | { | ||
87 | u32 val; | ||
88 | struct pvr2_hdw *hdw = ctxt->hdw; | ||
89 | |||
90 | pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_audio %d", | ||
91 | hdw->srate_val); | ||
92 | switch (hdw->srate_val) { | ||
93 | default: | ||
94 | case V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000: | ||
95 | val = 48000; | ||
96 | break; | ||
97 | case V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100: | ||
98 | val = 44100; | ||
99 | break; | ||
100 | case V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000: | ||
101 | val = 32000; | ||
102 | break; | ||
103 | } | ||
104 | pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_AUDIO_CLOCK_FREQ,&val); | ||
105 | } | ||
106 | |||
107 | |||
108 | static int check_audio(struct pvr2_v4l_decoder *ctxt) | ||
109 | { | ||
110 | struct pvr2_hdw *hdw = ctxt->hdw; | ||
111 | return hdw->srate_dirty != 0; | ||
112 | } | ||
113 | |||
114 | |||
115 | struct pvr2_v4l_decoder_ops { | ||
116 | void (*update)(struct pvr2_v4l_decoder *); | ||
117 | int (*check)(struct pvr2_v4l_decoder *); | ||
118 | }; | ||
119 | |||
120 | |||
121 | static const struct pvr2_v4l_decoder_ops decoder_ops[] = { | ||
122 | { .update = set_input, .check = check_input}, | ||
123 | { .update = set_audio, .check = check_audio}, | ||
124 | }; | ||
125 | |||
126 | |||
127 | static void decoder_detach(struct pvr2_v4l_decoder *ctxt) | ||
128 | { | ||
129 | ctxt->client->handler = 0; | ||
130 | ctxt->hdw->decoder_ctrl = 0; | ||
131 | kfree(ctxt); | ||
132 | } | ||
133 | |||
134 | |||
135 | static int decoder_check(struct pvr2_v4l_decoder *ctxt) | ||
136 | { | ||
137 | unsigned long msk; | ||
138 | unsigned int idx; | ||
139 | |||
140 | for (idx = 0; idx < sizeof(decoder_ops)/sizeof(decoder_ops[0]); | ||
141 | idx++) { | ||
142 | msk = 1 << idx; | ||
143 | if (ctxt->stale_mask & msk) continue; | ||
144 | if (decoder_ops[idx].check(ctxt)) { | ||
145 | ctxt->stale_mask |= msk; | ||
146 | } | ||
147 | } | ||
148 | return ctxt->stale_mask != 0; | ||
149 | } | ||
150 | |||
151 | |||
152 | static void decoder_update(struct pvr2_v4l_decoder *ctxt) | ||
153 | { | ||
154 | unsigned long msk; | ||
155 | unsigned int idx; | ||
156 | |||
157 | for (idx = 0; idx < sizeof(decoder_ops)/sizeof(decoder_ops[0]); | ||
158 | idx++) { | ||
159 | msk = 1 << idx; | ||
160 | if (!(ctxt->stale_mask & msk)) continue; | ||
161 | ctxt->stale_mask &= ~msk; | ||
162 | decoder_ops[idx].update(ctxt); | ||
163 | } | ||
164 | } | ||
165 | |||
166 | |||
167 | static int decoder_detect(struct pvr2_i2c_client *cp) | ||
168 | { | ||
169 | /* Attempt to query the decoder - let's see if it will answer */ | ||
170 | struct v4l2_tuner vt; | ||
171 | int ret; | ||
172 | |||
173 | memset(&vt,0,sizeof(vt)); | ||
174 | ret = pvr2_i2c_client_cmd(cp,VIDIOC_G_TUNER,&vt); | ||
175 | return ret == 0; /* Return true if it answered */ | ||
176 | } | ||
177 | |||
178 | |||
179 | static void decoder_enable(struct pvr2_v4l_decoder *ctxt,int fl) | ||
180 | { | ||
181 | pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 decoder_enable(%d)",fl); | ||
182 | pvr2_v4l2_cmd_stream(ctxt->client,fl); | ||
183 | } | ||
184 | |||
185 | |||
186 | static int decoder_is_tuned(struct pvr2_v4l_decoder *ctxt) | ||
187 | { | ||
188 | struct v4l2_tuner vt; | ||
189 | int ret; | ||
190 | |||
191 | memset(&vt,0,sizeof(vt)); | ||
192 | ret = pvr2_i2c_client_cmd(ctxt->client,VIDIOC_G_TUNER,&vt); | ||
193 | if (ret < 0) return -EINVAL; | ||
194 | return vt.signal ? 1 : 0; | ||
195 | } | ||
196 | |||
197 | |||
198 | static unsigned int decoder_describe(struct pvr2_v4l_decoder *ctxt,char *buf,unsigned int cnt) | ||
199 | { | ||
200 | return scnprintf(buf,cnt,"handler: pvrusb2-video-v4l"); | ||
201 | } | ||
202 | |||
203 | |||
204 | const static struct pvr2_i2c_handler_functions hfuncs = { | ||
205 | .detach = (void (*)(void *))decoder_detach, | ||
206 | .check = (int (*)(void *))decoder_check, | ||
207 | .update = (void (*)(void *))decoder_update, | ||
208 | .describe = (unsigned int (*)(void *,char *,unsigned int))decoder_describe, | ||
209 | }; | ||
210 | |||
211 | |||
212 | int pvr2_i2c_decoder_v4l_setup(struct pvr2_hdw *hdw, | ||
213 | struct pvr2_i2c_client *cp) | ||
214 | { | ||
215 | struct pvr2_v4l_decoder *ctxt; | ||
216 | |||
217 | if (hdw->decoder_ctrl) return 0; | ||
218 | if (cp->handler) return 0; | ||
219 | if (!decoder_detect(cp)) return 0; | ||
220 | |||
221 | ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL); | ||
222 | if (!ctxt) return 0; | ||
223 | memset(ctxt,0,sizeof(*ctxt)); | ||
224 | |||
225 | ctxt->handler.func_data = ctxt; | ||
226 | ctxt->handler.func_table = &hfuncs; | ||
227 | ctxt->ctrl.ctxt = ctxt; | ||
228 | ctxt->ctrl.detach = (void (*)(void *))decoder_detach; | ||
229 | ctxt->ctrl.enable = (void (*)(void *,int))decoder_enable; | ||
230 | ctxt->ctrl.tuned = (int (*)(void *))decoder_is_tuned; | ||
231 | ctxt->client = cp; | ||
232 | ctxt->hdw = hdw; | ||
233 | ctxt->stale_mask = (1 << (sizeof(decoder_ops)/ | ||
234 | sizeof(decoder_ops[0]))) - 1; | ||
235 | hdw->decoder_ctrl = &ctxt->ctrl; | ||
236 | cp->handler = &ctxt->handler; | ||
237 | pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x saa711x V4L2 handler set up", | ||
238 | cp->client->addr); | ||
239 | return !0; | ||
240 | } | ||
241 | |||
242 | |||
243 | |||
244 | |||
245 | /* | ||
246 | Stuff for Emacs to see, in order to encourage consistent editing style: | ||
247 | *** Local Variables: *** | ||
248 | *** mode: c *** | ||
249 | *** fill-column: 70 *** | ||
250 | *** tab-width: 8 *** | ||
251 | *** c-basic-offset: 8 *** | ||
252 | *** End: *** | ||
253 | */ | ||
diff --git a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.h b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.h new file mode 100644 index 000000000000..2b917fda02e4 --- /dev/null +++ b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.h | |||
@@ -0,0 +1,52 @@ | |||
1 | /* | ||
2 | * | ||
3 | * $Id$ | ||
4 | * | ||
5 | * Copyright (C) 2005 Mike Isely <isely@pobox.com> | ||
6 | * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License | ||
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 | |||
23 | #ifndef __PVRUSB2_VIDEO_V4L_H | ||
24 | #define __PVRUSB2_VIDEO_V4L_H | ||
25 | |||
26 | /* | ||
27 | |||
28 | This module connects the pvrusb2 driver to the I2C chip level | ||
29 | driver which handles device video processing. This interface is | ||
30 | used internally by the driver; higher level code should only | ||
31 | interact through the interface provided by pvrusb2-hdw.h. | ||
32 | |||
33 | */ | ||
34 | |||
35 | |||
36 | |||
37 | #include "pvrusb2-i2c-core.h" | ||
38 | |||
39 | int pvr2_i2c_decoder_v4l_setup(struct pvr2_hdw *,struct pvr2_i2c_client *); | ||
40 | |||
41 | |||
42 | #endif /* __PVRUSB2_VIDEO_V4L_H */ | ||
43 | |||
44 | /* | ||
45 | Stuff for Emacs to see, in order to encourage consistent editing style: | ||
46 | *** Local Variables: *** | ||
47 | *** mode: c *** | ||
48 | *** fill-column: 70 *** | ||
49 | *** tab-width: 8 *** | ||
50 | *** c-basic-offset: 8 *** | ||
51 | *** End: *** | ||
52 | */ | ||
diff --git a/drivers/media/video/pvrusb2/pvrusb2-wm8775.c b/drivers/media/video/pvrusb2/pvrusb2-wm8775.c new file mode 100644 index 000000000000..fcad346e3955 --- /dev/null +++ b/drivers/media/video/pvrusb2/pvrusb2-wm8775.c | |||
@@ -0,0 +1,170 @@ | |||
1 | /* | ||
2 | * | ||
3 | * $Id$ | ||
4 | * | ||
5 | * Copyright (C) 2005 Mike Isely <isely@pobox.com> | ||
6 | * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License | ||
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 | |||
23 | /* | ||
24 | |||
25 | This source file is specifically designed to interface with the | ||
26 | wm8775. | ||
27 | |||
28 | */ | ||
29 | |||
30 | #include "pvrusb2-wm8775.h" | ||
31 | #include "pvrusb2-i2c-cmd-v4l2.h" | ||
32 | |||
33 | |||
34 | #include "pvrusb2-hdw-internal.h" | ||
35 | #include "pvrusb2-debug.h" | ||
36 | #include <linux/videodev2.h> | ||
37 | #include <media/v4l2-common.h> | ||
38 | #include <linux/errno.h> | ||
39 | #include <linux/slab.h> | ||
40 | |||
41 | struct pvr2_v4l_wm8775 { | ||
42 | struct pvr2_i2c_handler handler; | ||
43 | struct pvr2_i2c_client *client; | ||
44 | struct pvr2_hdw *hdw; | ||
45 | unsigned long stale_mask; | ||
46 | }; | ||
47 | |||
48 | |||
49 | static void set_input(struct pvr2_v4l_wm8775 *ctxt) | ||
50 | { | ||
51 | struct v4l2_routing route; | ||
52 | struct pvr2_hdw *hdw = ctxt->hdw; | ||
53 | int msk = 0; | ||
54 | |||
55 | memset(&route,0,sizeof(route)); | ||
56 | |||
57 | pvr2_trace(PVR2_TRACE_CHIPS,"i2c wm8775 set_input(val=%d msk=0x%x)", | ||
58 | hdw->input_val,msk); | ||
59 | |||
60 | // Always point to input #1 no matter what | ||
61 | route.input = 2; | ||
62 | pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_AUDIO_ROUTING,&route); | ||
63 | } | ||
64 | |||
65 | static int check_input(struct pvr2_v4l_wm8775 *ctxt) | ||
66 | { | ||
67 | struct pvr2_hdw *hdw = ctxt->hdw; | ||
68 | return hdw->input_dirty != 0; | ||
69 | } | ||
70 | |||
71 | |||
72 | struct pvr2_v4l_wm8775_ops { | ||
73 | void (*update)(struct pvr2_v4l_wm8775 *); | ||
74 | int (*check)(struct pvr2_v4l_wm8775 *); | ||
75 | }; | ||
76 | |||
77 | |||
78 | static const struct pvr2_v4l_wm8775_ops wm8775_ops[] = { | ||
79 | { .update = set_input, .check = check_input}, | ||
80 | }; | ||
81 | |||
82 | |||
83 | static unsigned int wm8775_describe(struct pvr2_v4l_wm8775 *ctxt, | ||
84 | char *buf,unsigned int cnt) | ||
85 | { | ||
86 | return scnprintf(buf,cnt,"handler: pvrusb2-wm8775"); | ||
87 | } | ||
88 | |||
89 | |||
90 | static void wm8775_detach(struct pvr2_v4l_wm8775 *ctxt) | ||
91 | { | ||
92 | ctxt->client->handler = 0; | ||
93 | kfree(ctxt); | ||
94 | } | ||
95 | |||
96 | |||
97 | static int wm8775_check(struct pvr2_v4l_wm8775 *ctxt) | ||
98 | { | ||
99 | unsigned long msk; | ||
100 | unsigned int idx; | ||
101 | |||
102 | for (idx = 0; idx < sizeof(wm8775_ops)/sizeof(wm8775_ops[0]); | ||
103 | idx++) { | ||
104 | msk = 1 << idx; | ||
105 | if (ctxt->stale_mask & msk) continue; | ||
106 | if (wm8775_ops[idx].check(ctxt)) { | ||
107 | ctxt->stale_mask |= msk; | ||
108 | } | ||
109 | } | ||
110 | return ctxt->stale_mask != 0; | ||
111 | } | ||
112 | |||
113 | |||
114 | static void wm8775_update(struct pvr2_v4l_wm8775 *ctxt) | ||
115 | { | ||
116 | unsigned long msk; | ||
117 | unsigned int idx; | ||
118 | |||
119 | for (idx = 0; idx < sizeof(wm8775_ops)/sizeof(wm8775_ops[0]); | ||
120 | idx++) { | ||
121 | msk = 1 << idx; | ||
122 | if (!(ctxt->stale_mask & msk)) continue; | ||
123 | ctxt->stale_mask &= ~msk; | ||
124 | wm8775_ops[idx].update(ctxt); | ||
125 | } | ||
126 | } | ||
127 | |||
128 | |||
129 | const static struct pvr2_i2c_handler_functions hfuncs = { | ||
130 | .detach = (void (*)(void *))wm8775_detach, | ||
131 | .check = (int (*)(void *))wm8775_check, | ||
132 | .update = (void (*)(void *))wm8775_update, | ||
133 | .describe = (unsigned int (*)(void *,char *,unsigned int))wm8775_describe, | ||
134 | }; | ||
135 | |||
136 | |||
137 | int pvr2_i2c_wm8775_setup(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp) | ||
138 | { | ||
139 | struct pvr2_v4l_wm8775 *ctxt; | ||
140 | |||
141 | if (cp->handler) return 0; | ||
142 | |||
143 | ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL); | ||
144 | if (!ctxt) return 0; | ||
145 | memset(ctxt,0,sizeof(*ctxt)); | ||
146 | |||
147 | ctxt->handler.func_data = ctxt; | ||
148 | ctxt->handler.func_table = &hfuncs; | ||
149 | ctxt->client = cp; | ||
150 | ctxt->hdw = hdw; | ||
151 | ctxt->stale_mask = (1 << (sizeof(wm8775_ops)/ | ||
152 | sizeof(wm8775_ops[0]))) - 1; | ||
153 | cp->handler = &ctxt->handler; | ||
154 | pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x wm8775 V4L2 handler set up", | ||
155 | cp->client->addr); | ||
156 | return !0; | ||
157 | } | ||
158 | |||
159 | |||
160 | |||
161 | |||
162 | /* | ||
163 | Stuff for Emacs to see, in order to encourage consistent editing style: | ||
164 | *** Local Variables: *** | ||
165 | *** mode: c *** | ||
166 | *** fill-column: 70 *** | ||
167 | *** tab-width: 8 *** | ||
168 | *** c-basic-offset: 8 *** | ||
169 | *** End: *** | ||
170 | */ | ||
diff --git a/drivers/media/video/pvrusb2/pvrusb2-wm8775.h b/drivers/media/video/pvrusb2/pvrusb2-wm8775.h new file mode 100644 index 000000000000..8aaeff4e1e20 --- /dev/null +++ b/drivers/media/video/pvrusb2/pvrusb2-wm8775.h | |||
@@ -0,0 +1,53 @@ | |||
1 | /* | ||
2 | * | ||
3 | * $Id$ | ||
4 | * | ||
5 | * Copyright (C) 2005 Mike Isely <isely@pobox.com> | ||
6 | * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License | ||
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 | |||
23 | #ifndef __PVRUSB2_WM8775_H | ||
24 | #define __PVRUSB2_WM8775_H | ||
25 | |||
26 | /* | ||
27 | |||
28 | This module connects the pvrusb2 driver to the I2C chip level | ||
29 | driver which performs analog -> digital audio conversion for | ||
30 | external audio inputs. This interface is used internally by the | ||
31 | driver; higher level code should only interact through the | ||
32 | interface provided by pvrusb2-hdw.h. | ||
33 | |||
34 | */ | ||
35 | |||
36 | |||
37 | |||
38 | #include "pvrusb2-i2c-core.h" | ||
39 | |||
40 | int pvr2_i2c_wm8775_setup(struct pvr2_hdw *,struct pvr2_i2c_client *); | ||
41 | |||
42 | |||
43 | #endif /* __PVRUSB2_WM8775_H */ | ||
44 | |||
45 | /* | ||
46 | Stuff for Emacs to see, in order to encourage consistent editing style: | ||
47 | *** Local Variables: *** | ||
48 | *** mode: c *** | ||
49 | *** fill-column: 70 *** | ||
50 | *** tab-width: 8 *** | ||
51 | *** c-basic-offset: 8 *** | ||
52 | *** End: *** | ||
53 | */ | ||
diff --git a/drivers/media/video/pvrusb2/pvrusb2.h b/drivers/media/video/pvrusb2/pvrusb2.h new file mode 100644 index 000000000000..074533e9c21e --- /dev/null +++ b/drivers/media/video/pvrusb2/pvrusb2.h | |||
@@ -0,0 +1,43 @@ | |||
1 | /* | ||
2 | * | ||
3 | * $Id$ | ||
4 | * | ||
5 | * Copyright (C) 2005 Mike Isely <isely@pobox.com> | ||
6 | * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License | ||
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 | |||
23 | #ifndef __PVRUSB2_H | ||
24 | #define __PVRUSB2_H | ||
25 | |||
26 | /* Maximum number of pvrusb2 instances we can track at once. You | ||
27 | might want to increase this - however the driver operation will not | ||
28 | be impaired if it is too small. Instead additional units just | ||
29 | won't have an ID assigned and it might not be possible to specify | ||
30 | module paramters for those extra units. */ | ||
31 | #define PVR_NUM 20 | ||
32 | |||
33 | #endif /* __PVRUSB2_H */ | ||
34 | |||
35 | /* | ||
36 | Stuff for Emacs to see, in order to encourage consistent editing style: | ||
37 | *** Local Variables: *** | ||
38 | *** mode: c *** | ||
39 | *** fill-column: 70 *** | ||
40 | *** tab-width: 8 *** | ||
41 | *** c-basic-offset: 8 *** | ||
42 | *** End: *** | ||
43 | */ | ||
diff --git a/drivers/media/video/saa7134/saa6752hs.c b/drivers/media/video/saa7134/saa6752hs.c index de7b9e6e932a..afc8f352b8e7 100644 --- a/drivers/media/video/saa7134/saa6752hs.c +++ b/drivers/media/video/saa7134/saa6752hs.c | |||
@@ -432,10 +432,10 @@ static void saa6752hs_old_set_params(struct i2c_client* client, | |||
432 | } | 432 | } |
433 | 433 | ||
434 | static int handle_ctrl(struct saa6752hs_mpeg_params *params, | 434 | static int handle_ctrl(struct saa6752hs_mpeg_params *params, |
435 | struct v4l2_ext_control *ctrl, int cmd) | 435 | struct v4l2_ext_control *ctrl, unsigned int cmd) |
436 | { | 436 | { |
437 | int old = 0, new; | 437 | int old = 0, new; |
438 | int set = cmd == VIDIOC_S_EXT_CTRLS; | 438 | int set = (cmd == VIDIOC_S_EXT_CTRLS); |
439 | 439 | ||
440 | new = ctrl->value; | 440 | new = ctrl->value; |
441 | switch (ctrl->id) { | 441 | switch (ctrl->id) { |
diff --git a/drivers/media/video/stradis.c b/drivers/media/video/stradis.c index 6be9c1131e1f..c18b31d9928c 100644 --- a/drivers/media/video/stradis.c +++ b/drivers/media/video/stradis.c | |||
@@ -2190,7 +2190,7 @@ static struct pci_driver stradis_driver = { | |||
2190 | .remove = __devexit_p(stradis_remove) | 2190 | .remove = __devexit_p(stradis_remove) |
2191 | }; | 2191 | }; |
2192 | 2192 | ||
2193 | int __init stradis_init(void) | 2193 | static int __init stradis_init(void) |
2194 | { | 2194 | { |
2195 | int retval; | 2195 | int retval; |
2196 | 2196 | ||
@@ -2203,7 +2203,7 @@ int __init stradis_init(void) | |||
2203 | return retval; | 2203 | return retval; |
2204 | } | 2204 | } |
2205 | 2205 | ||
2206 | void __exit stradis_exit(void) | 2206 | static void __exit stradis_exit(void) |
2207 | { | 2207 | { |
2208 | pci_unregister_driver(&stradis_driver); | 2208 | pci_unregister_driver(&stradis_driver); |
2209 | printk(KERN_INFO "stradis: module cleanup complete\n"); | 2209 | printk(KERN_INFO "stradis: module cleanup complete\n"); |
diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index b6ae969563b2..2fadabf99688 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c | |||
@@ -22,11 +22,11 @@ | |||
22 | */ | 22 | */ |
23 | 23 | ||
24 | #define tda9887_info(fmt, arg...) do {\ | 24 | #define tda9887_info(fmt, arg...) do {\ |
25 | printk(KERN_INFO "%s %d-%04x (tda9887): " fmt, t->i2c.name, \ | 25 | printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.name, \ |
26 | i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0) | 26 | i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0) |
27 | #define tda9887_dbg(fmt, arg...) do {\ | 27 | #define tda9887_dbg(fmt, arg...) do {\ |
28 | if (tuner_debug) \ | 28 | if (tuner_debug) \ |
29 | printk(KERN_INFO "%s %d-%04x (tda9887): " fmt, t->i2c.name, \ | 29 | printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.name, \ |
30 | i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0) | 30 | i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0) |
31 | 31 | ||
32 | 32 | ||
@@ -84,8 +84,7 @@ struct tvnorm { | |||
84 | #define cAudioGain6 0x80 // bit c7 | 84 | #define cAudioGain6 0x80 // bit c7 |
85 | 85 | ||
86 | #define cTopMask 0x1f // bit c0:4 | 86 | #define cTopMask 0x1f // bit c0:4 |
87 | #define cTopPalSecamDefault 0x14 // bit c0:4 | 87 | #define cTopDefault 0x10 // bit c0:4 |
88 | #define cTopNtscRadioDefault 0x10 // bit c0:4 | ||
89 | 88 | ||
90 | //// third reg (e) | 89 | //// third reg (e) |
91 | #define cAudioIF_4_5 0x00 // bit e0:1 | 90 | #define cAudioIF_4_5 0x00 // bit e0:1 |
@@ -123,7 +122,7 @@ static struct tvnorm tvnorms[] = { | |||
123 | cQSS ), | 122 | cQSS ), |
124 | .c = ( cDeemphasisON | | 123 | .c = ( cDeemphasisON | |
125 | cDeemphasis50 | | 124 | cDeemphasis50 | |
126 | cTopPalSecamDefault), | 125 | cTopDefault), |
127 | .e = ( cGating_36 | | 126 | .e = ( cGating_36 | |
128 | cAudioIF_5_5 | | 127 | cAudioIF_5_5 | |
129 | cVideoIF_38_90 ), | 128 | cVideoIF_38_90 ), |
@@ -134,7 +133,7 @@ static struct tvnorm tvnorms[] = { | |||
134 | cQSS ), | 133 | cQSS ), |
135 | .c = ( cDeemphasisON | | 134 | .c = ( cDeemphasisON | |
136 | cDeemphasis50 | | 135 | cDeemphasis50 | |
137 | cTopPalSecamDefault), | 136 | cTopDefault), |
138 | .e = ( cGating_36 | | 137 | .e = ( cGating_36 | |
139 | cAudioIF_6_0 | | 138 | cAudioIF_6_0 | |
140 | cVideoIF_38_90 ), | 139 | cVideoIF_38_90 ), |
@@ -145,7 +144,7 @@ static struct tvnorm tvnorms[] = { | |||
145 | cQSS ), | 144 | cQSS ), |
146 | .c = ( cDeemphasisON | | 145 | .c = ( cDeemphasisON | |
147 | cDeemphasis50 | | 146 | cDeemphasis50 | |
148 | cTopPalSecamDefault), | 147 | cTopDefault), |
149 | .e = ( cGating_36 | | 148 | .e = ( cGating_36 | |
150 | cAudioIF_6_5 | | 149 | cAudioIF_6_5 | |
151 | cVideoIF_38_90 ), | 150 | cVideoIF_38_90 ), |
@@ -156,7 +155,7 @@ static struct tvnorm tvnorms[] = { | |||
156 | cQSS ), | 155 | cQSS ), |
157 | .c = ( cDeemphasisON | | 156 | .c = ( cDeemphasisON | |
158 | cDeemphasis75 | | 157 | cDeemphasis75 | |
159 | cTopNtscRadioDefault), | 158 | cTopDefault), |
160 | .e = ( cGating_36 | | 159 | .e = ( cGating_36 | |
161 | cAudioIF_4_5 | | 160 | cAudioIF_4_5 | |
162 | cVideoIF_45_75 ), | 161 | cVideoIF_45_75 ), |
@@ -165,7 +164,7 @@ static struct tvnorm tvnorms[] = { | |||
165 | .name = "SECAM-BGH", | 164 | .name = "SECAM-BGH", |
166 | .b = ( cPositiveAmTV | | 165 | .b = ( cPositiveAmTV | |
167 | cQSS ), | 166 | cQSS ), |
168 | .c = ( cTopPalSecamDefault), | 167 | .c = ( cTopDefault), |
169 | .e = ( cGating_36 | | 168 | .e = ( cGating_36 | |
170 | cAudioIF_5_5 | | 169 | cAudioIF_5_5 | |
171 | cVideoIF_38_90 ), | 170 | cVideoIF_38_90 ), |
@@ -174,7 +173,7 @@ static struct tvnorm tvnorms[] = { | |||
174 | .name = "SECAM-L", | 173 | .name = "SECAM-L", |
175 | .b = ( cPositiveAmTV | | 174 | .b = ( cPositiveAmTV | |
176 | cQSS ), | 175 | cQSS ), |
177 | .c = ( cTopPalSecamDefault), | 176 | .c = ( cTopDefault), |
178 | .e = ( cGating_36 | | 177 | .e = ( cGating_36 | |
179 | cAudioIF_6_5 | | 178 | cAudioIF_6_5 | |
180 | cVideoIF_38_90 ), | 179 | cVideoIF_38_90 ), |
@@ -184,7 +183,7 @@ static struct tvnorm tvnorms[] = { | |||
184 | .b = ( cOutputPort2Inactive | | 183 | .b = ( cOutputPort2Inactive | |
185 | cPositiveAmTV | | 184 | cPositiveAmTV | |
186 | cQSS ), | 185 | cQSS ), |
187 | .c = ( cTopPalSecamDefault), | 186 | .c = ( cTopDefault), |
188 | .e = ( cGating_36 | | 187 | .e = ( cGating_36 | |
189 | cAudioIF_6_5 | | 188 | cAudioIF_6_5 | |
190 | cVideoIF_33_90 ), | 189 | cVideoIF_33_90 ), |
@@ -195,7 +194,7 @@ static struct tvnorm tvnorms[] = { | |||
195 | cQSS ), | 194 | cQSS ), |
196 | .c = ( cDeemphasisON | | 195 | .c = ( cDeemphasisON | |
197 | cDeemphasis50 | | 196 | cDeemphasis50 | |
198 | cTopPalSecamDefault), | 197 | cTopDefault), |
199 | .e = ( cGating_36 | | 198 | .e = ( cGating_36 | |
200 | cAudioIF_6_5 | | 199 | cAudioIF_6_5 | |
201 | cVideoIF_38_90 ), | 200 | cVideoIF_38_90 ), |
@@ -206,7 +205,7 @@ static struct tvnorm tvnorms[] = { | |||
206 | cQSS ), | 205 | cQSS ), |
207 | .c = ( cDeemphasisON | | 206 | .c = ( cDeemphasisON | |
208 | cDeemphasis75 | | 207 | cDeemphasis75 | |
209 | cTopNtscRadioDefault), | 208 | cTopDefault), |
210 | .e = ( cGating_36 | | 209 | .e = ( cGating_36 | |
211 | cAudioIF_4_5 | | 210 | cAudioIF_4_5 | |
212 | cVideoIF_45_75 ), | 211 | cVideoIF_45_75 ), |
@@ -217,7 +216,7 @@ static struct tvnorm tvnorms[] = { | |||
217 | cQSS ), | 216 | cQSS ), |
218 | .c = ( cDeemphasisON | | 217 | .c = ( cDeemphasisON | |
219 | cDeemphasis50 | | 218 | cDeemphasis50 | |
220 | cTopNtscRadioDefault), | 219 | cTopDefault), |
221 | .e = ( cGating_36 | | 220 | .e = ( cGating_36 | |
222 | cAudioIF_4_5 | | 221 | cAudioIF_4_5 | |
223 | cVideoIF_58_75 ), | 222 | cVideoIF_58_75 ), |
@@ -230,7 +229,7 @@ static struct tvnorm radio_stereo = { | |||
230 | cQSS ), | 229 | cQSS ), |
231 | .c = ( cDeemphasisOFF | | 230 | .c = ( cDeemphasisOFF | |
232 | cAudioGain6 | | 231 | cAudioGain6 | |
233 | cTopNtscRadioDefault), | 232 | cTopDefault), |
234 | .e = ( cTunerGainLow | | 233 | .e = ( cTunerGainLow | |
235 | cAudioIF_5_5 | | 234 | cAudioIF_5_5 | |
236 | cRadioIF_38_90 ), | 235 | cRadioIF_38_90 ), |
@@ -242,7 +241,7 @@ static struct tvnorm radio_mono = { | |||
242 | cQSS ), | 241 | cQSS ), |
243 | .c = ( cDeemphasisON | | 242 | .c = ( cDeemphasisON | |
244 | cDeemphasis75 | | 243 | cDeemphasis75 | |
245 | cTopNtscRadioDefault), | 244 | cTopDefault), |
246 | .e = ( cTunerGainLow | | 245 | .e = ( cTunerGainLow | |
247 | cAudioIF_5_5 | | 246 | cAudioIF_5_5 | |
248 | cRadioIF_38_90 ), | 247 | cRadioIF_38_90 ), |
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index e95792fd70f8..011413cf34a8 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c | |||
@@ -40,7 +40,6 @@ static unsigned int no_autodetect = 0; | |||
40 | static unsigned int show_i2c = 0; | 40 | static unsigned int show_i2c = 0; |
41 | 41 | ||
42 | /* insmod options used at runtime => read/write */ | 42 | /* insmod options used at runtime => read/write */ |
43 | static unsigned int tuner_debug_old = 0; | ||
44 | int tuner_debug = 0; | 43 | int tuner_debug = 0; |
45 | 44 | ||
46 | static unsigned int tv_range[2] = { 44, 958 }; | 45 | static unsigned int tv_range[2] = { 44, 958 }; |
@@ -54,8 +53,6 @@ static char ntsc[] = "-"; | |||
54 | module_param(addr, int, 0444); | 53 | module_param(addr, int, 0444); |
55 | module_param(no_autodetect, int, 0444); | 54 | module_param(no_autodetect, int, 0444); |
56 | module_param(show_i2c, int, 0444); | 55 | module_param(show_i2c, int, 0444); |
57 | /* Note: tuner_debug is deprecated and will be removed in 2.6.17 */ | ||
58 | module_param_named(tuner_debug,tuner_debug_old, int, 0444); | ||
59 | module_param_named(debug,tuner_debug, int, 0644); | 56 | module_param_named(debug,tuner_debug, int, 0644); |
60 | module_param_string(pal, pal, sizeof(pal), 0644); | 57 | module_param_string(pal, pal, sizeof(pal), 0644); |
61 | module_param_string(secam, secam, sizeof(secam), 0644); | 58 | module_param_string(secam, secam, sizeof(secam), 0644); |
@@ -442,11 +439,6 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) | |||
442 | t->audmode = V4L2_TUNER_MODE_STEREO; | 439 | t->audmode = V4L2_TUNER_MODE_STEREO; |
443 | t->mode_mask = T_UNINITIALIZED; | 440 | t->mode_mask = T_UNINITIALIZED; |
444 | t->tuner_status = tuner_status; | 441 | t->tuner_status = tuner_status; |
445 | if (tuner_debug_old) { | ||
446 | tuner_debug = tuner_debug_old; | ||
447 | printk(KERN_ERR "tuner: tuner_debug is deprecated and will be removed in 2.6.17.\n"); | ||
448 | printk(KERN_ERR "tuner: use the debug option instead.\n"); | ||
449 | } | ||
450 | 442 | ||
451 | if (show_i2c) { | 443 | if (show_i2c) { |
452 | unsigned char buffer[16]; | 444 | unsigned char buffer[16]; |
@@ -730,14 +722,10 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) | |||
730 | { | 722 | { |
731 | struct v4l2_frequency *f = arg; | 723 | struct v4l2_frequency *f = arg; |
732 | 724 | ||
725 | if (set_mode (client, t, f->type, "VIDIOC_S_FREQUENCY") | ||
726 | == EINVAL) | ||
727 | return 0; | ||
733 | switch_v4l2(); | 728 | switch_v4l2(); |
734 | if ((V4L2_TUNER_RADIO == f->type && V4L2_TUNER_RADIO != t->mode) | ||
735 | || (V4L2_TUNER_DIGITAL_TV == f->type | ||
736 | && V4L2_TUNER_DIGITAL_TV != t->mode)) { | ||
737 | if (set_mode (client, t, f->type, "VIDIOC_S_FREQUENCY") | ||
738 | == EINVAL) | ||
739 | return 0; | ||
740 | } | ||
741 | set_freq(client,f->frequency); | 729 | set_freq(client,f->frequency); |
742 | 730 | ||
743 | break; | 731 | break; |
diff --git a/drivers/media/video/usbvideo/quickcam_messenger.c b/drivers/media/video/usbvideo/quickcam_messenger.c index 3f3182a24da1..56e01b622417 100644 --- a/drivers/media/video/usbvideo/quickcam_messenger.c +++ b/drivers/media/video/usbvideo/quickcam_messenger.c | |||
@@ -33,7 +33,7 @@ | |||
33 | #include <linux/module.h> | 33 | #include <linux/module.h> |
34 | #include <linux/init.h> | 34 | #include <linux/init.h> |
35 | #include <linux/input.h> | 35 | #include <linux/input.h> |
36 | #include <linux/usb_input.h> | 36 | #include <linux/usb/input.h> |
37 | 37 | ||
38 | #include "usbvideo.h" | 38 | #include "usbvideo.h" |
39 | #include "quickcam_messenger.h" | 39 | #include "quickcam_messenger.h" |
diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c index 14e523471354..97f946db8597 100644 --- a/drivers/media/video/v4l2-common.c +++ b/drivers/media/video/v4l2-common.c | |||
@@ -1101,6 +1101,11 @@ const char **v4l2_ctrl_get_menu(u32 id) | |||
1101 | "MPEG-2 SVCD-compatible Stream", | 1101 | "MPEG-2 SVCD-compatible Stream", |
1102 | NULL | 1102 | NULL |
1103 | }; | 1103 | }; |
1104 | static const char *mpeg_stream_vbi_fmt[] = { | ||
1105 | "No VBI", | ||
1106 | "Private packet, IVTV format", | ||
1107 | NULL | ||
1108 | }; | ||
1104 | 1109 | ||
1105 | switch (id) { | 1110 | switch (id) { |
1106 | case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: | 1111 | case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: |
@@ -1129,6 +1134,8 @@ const char **v4l2_ctrl_get_menu(u32 id) | |||
1129 | return mpeg_video_bitrate_mode; | 1134 | return mpeg_video_bitrate_mode; |
1130 | case V4L2_CID_MPEG_STREAM_TYPE: | 1135 | case V4L2_CID_MPEG_STREAM_TYPE: |
1131 | return mpeg_stream_type; | 1136 | return mpeg_stream_type; |
1137 | case V4L2_CID_MPEG_STREAM_VBI_FMT: | ||
1138 | return mpeg_stream_vbi_fmt; | ||
1132 | default: | 1139 | default: |
1133 | return NULL; | 1140 | return NULL; |
1134 | } | 1141 | } |
@@ -1182,6 +1189,7 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste | |||
1182 | case V4L2_CID_MPEG_STREAM_PID_PCR: name = "Stream PCR Program ID"; break; | 1189 | case V4L2_CID_MPEG_STREAM_PID_PCR: name = "Stream PCR Program ID"; break; |
1183 | case V4L2_CID_MPEG_STREAM_PES_ID_AUDIO: name = "Stream PES Audio ID"; break; | 1190 | case V4L2_CID_MPEG_STREAM_PES_ID_AUDIO: name = "Stream PES Audio ID"; break; |
1184 | case V4L2_CID_MPEG_STREAM_PES_ID_VIDEO: name = "Stream PES Video ID"; break; | 1191 | case V4L2_CID_MPEG_STREAM_PES_ID_VIDEO: name = "Stream PES Video ID"; break; |
1192 | case V4L2_CID_MPEG_STREAM_VBI_FMT: name = "Stream VBI Format"; break; | ||
1185 | 1193 | ||
1186 | default: | 1194 | default: |
1187 | return -EINVAL; | 1195 | return -EINVAL; |
@@ -1208,6 +1216,7 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste | |||
1208 | case V4L2_CID_MPEG_VIDEO_ASPECT: | 1216 | case V4L2_CID_MPEG_VIDEO_ASPECT: |
1209 | case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: | 1217 | case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: |
1210 | case V4L2_CID_MPEG_STREAM_TYPE: | 1218 | case V4L2_CID_MPEG_STREAM_TYPE: |
1219 | case V4L2_CID_MPEG_STREAM_VBI_FMT: | ||
1211 | qctrl->type = V4L2_CTRL_TYPE_MENU; | 1220 | qctrl->type = V4L2_CTRL_TYPE_MENU; |
1212 | step = 1; | 1221 | step = 1; |
1213 | break; | 1222 | break; |
@@ -1367,6 +1376,11 @@ int v4l2_ctrl_query_fill_std(struct v4l2_queryctrl *qctrl) | |||
1367 | return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 0); | 1376 | return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 0); |
1368 | case V4L2_CID_MPEG_STREAM_PES_ID_VIDEO: | 1377 | case V4L2_CID_MPEG_STREAM_PES_ID_VIDEO: |
1369 | return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 0); | 1378 | return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 0); |
1379 | case V4L2_CID_MPEG_STREAM_VBI_FMT: | ||
1380 | return v4l2_ctrl_query_fill(qctrl, | ||
1381 | V4L2_MPEG_STREAM_VBI_FMT_NONE, | ||
1382 | V4L2_MPEG_STREAM_VBI_FMT_IVTV, 1, | ||
1383 | V4L2_MPEG_STREAM_VBI_FMT_NONE); | ||
1370 | default: | 1384 | default: |
1371 | return -EINVAL; | 1385 | return -EINVAL; |
1372 | } | 1386 | } |
diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c index d0141ccbb7af..a8f2fa985455 100644 --- a/drivers/message/fusion/mptfc.c +++ b/drivers/message/fusion/mptfc.c | |||
@@ -305,10 +305,8 @@ mptfc_GetFcDevPage0(MPT_ADAPTER *ioc, int ioc_port, | |||
305 | } | 305 | } |
306 | 306 | ||
307 | out: | 307 | out: |
308 | if (pp0_array) | 308 | kfree(pp0_array); |
309 | kfree(pp0_array); | 309 | kfree(p0_array); |
310 | if (p0_array) | ||
311 | kfree(p0_array); | ||
312 | return rc; | 310 | return rc; |
313 | } | 311 | } |
314 | 312 | ||
diff --git a/drivers/message/i2o/iop.c b/drivers/message/i2o/iop.c index febbdd4e0605..c74e5460f834 100644 --- a/drivers/message/i2o/iop.c +++ b/drivers/message/i2o/iop.c | |||
@@ -1239,7 +1239,6 @@ EXPORT_SYMBOL(i2o_cntxt_list_remove); | |||
1239 | EXPORT_SYMBOL(i2o_cntxt_list_get_ptr); | 1239 | EXPORT_SYMBOL(i2o_cntxt_list_get_ptr); |
1240 | #endif | 1240 | #endif |
1241 | EXPORT_SYMBOL(i2o_msg_get_wait); | 1241 | EXPORT_SYMBOL(i2o_msg_get_wait); |
1242 | EXPORT_SYMBOL(i2o_msg_nop); | ||
1243 | EXPORT_SYMBOL(i2o_find_iop); | 1242 | EXPORT_SYMBOL(i2o_find_iop); |
1244 | EXPORT_SYMBOL(i2o_iop_find_device); | 1243 | EXPORT_SYMBOL(i2o_iop_find_device); |
1245 | EXPORT_SYMBOL(i2o_event_register); | 1244 | EXPORT_SYMBOL(i2o_event_register); |
diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c index aff83f966803..c8426a9bf273 100644 --- a/drivers/mfd/ucb1x00-core.c +++ b/drivers/mfd/ucb1x00-core.c | |||
@@ -420,8 +420,10 @@ static int ucb1x00_detect_irq(struct ucb1x00 *ucb) | |||
420 | unsigned long mask; | 420 | unsigned long mask; |
421 | 421 | ||
422 | mask = probe_irq_on(); | 422 | mask = probe_irq_on(); |
423 | if (!mask) | 423 | if (!mask) { |
424 | probe_irq_off(mask); | ||
424 | return NO_IRQ; | 425 | return NO_IRQ; |
426 | } | ||
425 | 427 | ||
426 | /* | 428 | /* |
427 | * Enable the ADC interrupt. | 429 | * Enable the ADC interrupt. |
diff --git a/drivers/misc/ibmasm/module.c b/drivers/misc/ibmasm/module.c index 1fdf03fd2da7..9706cc19134a 100644 --- a/drivers/misc/ibmasm/module.c +++ b/drivers/misc/ibmasm/module.c | |||
@@ -85,7 +85,7 @@ static int __devinit ibmasm_init_one(struct pci_dev *pdev, const struct pci_devi | |||
85 | } | 85 | } |
86 | memset(sp, 0, sizeof(struct service_processor)); | 86 | memset(sp, 0, sizeof(struct service_processor)); |
87 | 87 | ||
88 | sp->lock = SPIN_LOCK_UNLOCKED; | 88 | spin_lock_init(&sp->lock); |
89 | INIT_LIST_HEAD(&sp->command_queue); | 89 | INIT_LIST_HEAD(&sp->command_queue); |
90 | 90 | ||
91 | pci_set_drvdata(pdev, (void *)sp); | 91 | pci_set_drvdata(pdev, (void *)sp); |
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index 5ac265dde423..1344ad7a4b14 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig | |||
@@ -86,14 +86,14 @@ config MTD_REDBOOT_DIRECTORY_BLOCK | |||
86 | block and "-2" means the penultimate block. | 86 | block and "-2" means the penultimate block. |
87 | 87 | ||
88 | config MTD_REDBOOT_PARTS_UNALLOCATED | 88 | config MTD_REDBOOT_PARTS_UNALLOCATED |
89 | bool " Include unallocated flash regions" | 89 | bool "Include unallocated flash regions" |
90 | depends on MTD_REDBOOT_PARTS | 90 | depends on MTD_REDBOOT_PARTS |
91 | help | 91 | help |
92 | If you need to register each unallocated flash region as a MTD | 92 | If you need to register each unallocated flash region as a MTD |
93 | 'partition', enable this option. | 93 | 'partition', enable this option. |
94 | 94 | ||
95 | config MTD_REDBOOT_PARTS_READONLY | 95 | config MTD_REDBOOT_PARTS_READONLY |
96 | bool " Force read-only for RedBoot system images" | 96 | bool "Force read-only for RedBoot system images" |
97 | depends on MTD_REDBOOT_PARTS | 97 | depends on MTD_REDBOOT_PARTS |
98 | help | 98 | help |
99 | If you need to force read-only for 'RedBoot', 'RedBoot Config' and | 99 | If you need to force read-only for 'RedBoot', 'RedBoot Config' and |
diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index 0d435814aaa1..39edb8250fbc 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c | |||
@@ -357,6 +357,7 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary) | |||
357 | mtd->resume = cfi_intelext_resume; | 357 | mtd->resume = cfi_intelext_resume; |
358 | mtd->flags = MTD_CAP_NORFLASH; | 358 | mtd->flags = MTD_CAP_NORFLASH; |
359 | mtd->name = map->name; | 359 | mtd->name = map->name; |
360 | mtd->writesize = 1; | ||
360 | 361 | ||
361 | mtd->reboot_notifier.notifier_call = cfi_intelext_reboot; | 362 | mtd->reboot_notifier.notifier_call = cfi_intelext_reboot; |
362 | 363 | ||
diff --git a/drivers/mtd/chips/jedec.c b/drivers/mtd/chips/jedec.c index c40b48dabed3..2c3f019197c1 100644 --- a/drivers/mtd/chips/jedec.c +++ b/drivers/mtd/chips/jedec.c | |||
@@ -256,6 +256,7 @@ static struct mtd_info *jedec_probe(struct map_info *map) | |||
256 | MTD->name = map->name; | 256 | MTD->name = map->name; |
257 | MTD->type = MTD_NORFLASH; | 257 | MTD->type = MTD_NORFLASH; |
258 | MTD->flags = MTD_CAP_NORFLASH; | 258 | MTD->flags = MTD_CAP_NORFLASH; |
259 | MTD->writesize = 1; | ||
259 | MTD->erasesize = SectorSize*(map->buswidth); | 260 | MTD->erasesize = SectorSize*(map->buswidth); |
260 | // printk("MTD->erasesize is %x\n",(unsigned int)MTD->erasesize); | 261 | // printk("MTD->erasesize is %x\n",(unsigned int)MTD->erasesize); |
261 | MTD->size = priv->size; | 262 | MTD->size = priv->size; |
diff --git a/drivers/mtd/chips/map_absent.c b/drivers/mtd/chips/map_absent.c index a611de9b1515..ac01a949b687 100644 --- a/drivers/mtd/chips/map_absent.c +++ b/drivers/mtd/chips/map_absent.c | |||
@@ -64,7 +64,8 @@ static struct mtd_info *map_absent_probe(struct map_info *map) | |||
64 | mtd->write = map_absent_write; | 64 | mtd->write = map_absent_write; |
65 | mtd->sync = map_absent_sync; | 65 | mtd->sync = map_absent_sync; |
66 | mtd->flags = 0; | 66 | mtd->flags = 0; |
67 | mtd->erasesize = PAGE_SIZE; | 67 | mtd->erasesize = PAGE_SIZE; |
68 | mtd->writesize = 1; | ||
68 | 69 | ||
69 | __module_get(THIS_MODULE); | 70 | __module_get(THIS_MODULE); |
70 | return mtd; | 71 | return mtd; |
diff --git a/drivers/mtd/chips/map_ram.c b/drivers/mtd/chips/map_ram.c index 763925747db6..3a66680abfd0 100644 --- a/drivers/mtd/chips/map_ram.c +++ b/drivers/mtd/chips/map_ram.c | |||
@@ -71,6 +71,7 @@ static struct mtd_info *map_ram_probe(struct map_info *map) | |||
71 | mtd->write = mapram_write; | 71 | mtd->write = mapram_write; |
72 | mtd->sync = mapram_nop; | 72 | mtd->sync = mapram_nop; |
73 | mtd->flags = MTD_CAP_RAM; | 73 | mtd->flags = MTD_CAP_RAM; |
74 | mtd->writesize = 1; | ||
74 | 75 | ||
75 | mtd->erasesize = PAGE_SIZE; | 76 | mtd->erasesize = PAGE_SIZE; |
76 | while(mtd->size & (mtd->erasesize - 1)) | 77 | while(mtd->size & (mtd->erasesize - 1)) |
diff --git a/drivers/mtd/chips/map_rom.c b/drivers/mtd/chips/map_rom.c index bc6ee9ef8a31..1b328b1378fd 100644 --- a/drivers/mtd/chips/map_rom.c +++ b/drivers/mtd/chips/map_rom.c | |||
@@ -47,6 +47,7 @@ static struct mtd_info *map_rom_probe(struct map_info *map) | |||
47 | mtd->sync = maprom_nop; | 47 | mtd->sync = maprom_nop; |
48 | mtd->flags = MTD_CAP_ROM; | 48 | mtd->flags = MTD_CAP_ROM; |
49 | mtd->erasesize = map->size; | 49 | mtd->erasesize = map->size; |
50 | mtd->writesize = 1; | ||
50 | 51 | ||
51 | __module_get(THIS_MODULE); | 52 | __module_get(THIS_MODULE); |
52 | return mtd; | 53 | return mtd; |
diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c index 0d98c223c5fc..be3f1c136d02 100644 --- a/drivers/mtd/devices/block2mtd.c +++ b/drivers/mtd/devices/block2mtd.c | |||
@@ -324,6 +324,7 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size) | |||
324 | 324 | ||
325 | dev->mtd.size = dev->blkdev->bd_inode->i_size & PAGE_MASK; | 325 | dev->mtd.size = dev->blkdev->bd_inode->i_size & PAGE_MASK; |
326 | dev->mtd.erasesize = erase_size; | 326 | dev->mtd.erasesize = erase_size; |
327 | dev->mtd.writesize = 1; | ||
327 | dev->mtd.type = MTD_RAM; | 328 | dev->mtd.type = MTD_RAM; |
328 | dev->mtd.flags = MTD_CAP_RAM; | 329 | dev->mtd.flags = MTD_CAP_RAM; |
329 | dev->mtd.erase = block2mtd_erase; | 330 | dev->mtd.erase = block2mtd_erase; |
diff --git a/drivers/mtd/devices/ms02-nv.c b/drivers/mtd/devices/ms02-nv.c index 4ab7670770e4..08dfb899b272 100644 --- a/drivers/mtd/devices/ms02-nv.c +++ b/drivers/mtd/devices/ms02-nv.c | |||
@@ -225,6 +225,7 @@ static int __init ms02nv_init_one(ulong addr) | |||
225 | mtd->owner = THIS_MODULE; | 225 | mtd->owner = THIS_MODULE; |
226 | mtd->read = ms02nv_read; | 226 | mtd->read = ms02nv_read; |
227 | mtd->write = ms02nv_write; | 227 | mtd->write = ms02nv_write; |
228 | mtd->writesize = 1; | ||
228 | 229 | ||
229 | ret = -EIO; | 230 | ret = -EIO; |
230 | if (add_mtd_device(mtd)) { | 231 | if (add_mtd_device(mtd)) { |
diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c index a19480d07888..04271d02b6b6 100644 --- a/drivers/mtd/devices/mtd_dataflash.c +++ b/drivers/mtd/devices/mtd_dataflash.c | |||
@@ -478,6 +478,7 @@ add_dataflash(struct spi_device *spi, char *name, | |||
478 | device->name = (pdata && pdata->name) ? pdata->name : priv->name; | 478 | device->name = (pdata && pdata->name) ? pdata->name : priv->name; |
479 | device->size = nr_pages * pagesize; | 479 | device->size = nr_pages * pagesize; |
480 | device->erasesize = pagesize; | 480 | device->erasesize = pagesize; |
481 | device->writesize = pagesize; | ||
481 | device->owner = THIS_MODULE; | 482 | device->owner = THIS_MODULE; |
482 | device->type = MTD_DATAFLASH; | 483 | device->type = MTD_DATAFLASH; |
483 | device->flags = MTD_CAP_NORFLASH; | 484 | device->flags = MTD_CAP_NORFLASH; |
diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c index e09e416667d3..6c7337f9ebbb 100644 --- a/drivers/mtd/devices/phram.c +++ b/drivers/mtd/devices/phram.c | |||
@@ -151,6 +151,7 @@ static int register_device(char *name, unsigned long start, unsigned long len) | |||
151 | new->mtd.owner = THIS_MODULE; | 151 | new->mtd.owner = THIS_MODULE; |
152 | new->mtd.type = MTD_RAM; | 152 | new->mtd.type = MTD_RAM; |
153 | new->mtd.erasesize = PAGE_SIZE; | 153 | new->mtd.erasesize = PAGE_SIZE; |
154 | new->mtd.writesize = 1; | ||
154 | 155 | ||
155 | ret = -EAGAIN; | 156 | ret = -EAGAIN; |
156 | if (add_mtd_device(&new->mtd)) { | 157 | if (add_mtd_device(&new->mtd)) { |
diff --git a/drivers/mtd/devices/pmc551.c b/drivers/mtd/devices/pmc551.c index 666cce1bf60c..f620d74f1004 100644 --- a/drivers/mtd/devices/pmc551.c +++ b/drivers/mtd/devices/pmc551.c | |||
@@ -778,7 +778,8 @@ static int __init init_pmc551(void) | |||
778 | mtd->type = MTD_RAM; | 778 | mtd->type = MTD_RAM; |
779 | mtd->name = "PMC551 RAM board"; | 779 | mtd->name = "PMC551 RAM board"; |
780 | mtd->erasesize = 0x10000; | 780 | mtd->erasesize = 0x10000; |
781 | mtd->owner = THIS_MODULE; | 781 | mtd->writesize = 1; |
782 | mtd->owner = THIS_MODULE; | ||
782 | 783 | ||
783 | if (add_mtd_device(mtd)) { | 784 | if (add_mtd_device(mtd)) { |
784 | printk(KERN_NOTICE "pmc551: Failed to register new device\n"); | 785 | printk(KERN_NOTICE "pmc551: Failed to register new device\n"); |
diff --git a/drivers/mtd/devices/slram.c b/drivers/mtd/devices/slram.c index b3f665e3c38b..542a0c009006 100644 --- a/drivers/mtd/devices/slram.c +++ b/drivers/mtd/devices/slram.c | |||
@@ -209,6 +209,7 @@ static int register_device(char *name, unsigned long start, unsigned long length | |||
209 | (*curmtd)->mtdinfo->owner = THIS_MODULE; | 209 | (*curmtd)->mtdinfo->owner = THIS_MODULE; |
210 | (*curmtd)->mtdinfo->type = MTD_RAM; | 210 | (*curmtd)->mtdinfo->type = MTD_RAM; |
211 | (*curmtd)->mtdinfo->erasesize = SLRAM_BLK_SZ; | 211 | (*curmtd)->mtdinfo->erasesize = SLRAM_BLK_SZ; |
212 | (*curmtd)->mtdinfo->writesize = 1; | ||
212 | 213 | ||
213 | if (add_mtd_device((*curmtd)->mtdinfo)) { | 214 | if (add_mtd_device((*curmtd)->mtdinfo)) { |
214 | E("slram: Failed to register new device\n"); | 215 | E("slram: Failed to register new device\n"); |
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index 6bdaacc6d6f9..83d0b2a52527 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig | |||
@@ -212,7 +212,7 @@ config MTD_NETtel | |||
212 | Support for flash chips on NETtel/SecureEdge/SnapGear boards. | 212 | Support for flash chips on NETtel/SecureEdge/SnapGear boards. |
213 | 213 | ||
214 | config MTD_ALCHEMY | 214 | config MTD_ALCHEMY |
215 | tristate ' AMD Alchemy Pb1xxx/Db1xxx/RDK MTD support' | 215 | tristate "AMD Alchemy Pb1xxx/Db1xxx/RDK MTD support" |
216 | depends on SOC_AU1X00 | 216 | depends on SOC_AU1X00 |
217 | help | 217 | help |
218 | Flash memory access on AMD Alchemy Pb/Db/RDK Reference Boards | 218 | Flash memory access on AMD Alchemy Pb/Db/RDK Reference Boards |
diff --git a/drivers/mtd/maps/ixp2000.c b/drivers/mtd/maps/ixp2000.c index 2c9cc7f37e92..c26488a1793a 100644 --- a/drivers/mtd/maps/ixp2000.c +++ b/drivers/mtd/maps/ixp2000.c | |||
@@ -42,7 +42,6 @@ struct ixp2000_flash_info { | |||
42 | struct map_info map; | 42 | struct map_info map; |
43 | struct mtd_partition *partitions; | 43 | struct mtd_partition *partitions; |
44 | struct resource *res; | 44 | struct resource *res; |
45 | int nr_banks; | ||
46 | }; | 45 | }; |
47 | 46 | ||
48 | static inline unsigned long flash_bank_setup(struct map_info *map, unsigned long ofs) | 47 | static inline unsigned long flash_bank_setup(struct map_info *map, unsigned long ofs) |
@@ -183,7 +182,6 @@ static int ixp2000_flash_probe(struct platform_device *dev) | |||
183 | */ | 182 | */ |
184 | info->map.phys = NO_XIP; | 183 | info->map.phys = NO_XIP; |
185 | 184 | ||
186 | info->nr_banks = ixp_data->nr_banks; | ||
187 | info->map.size = ixp_data->nr_banks * window_size; | 185 | info->map.size = ixp_data->nr_banks * window_size; |
188 | info->map.bankwidth = 1; | 186 | info->map.bankwidth = 1; |
189 | 187 | ||
diff --git a/drivers/mtd/maps/physmap.c b/drivers/mtd/maps/physmap.c index 433c3cac3ca9..d6301f08906d 100644 --- a/drivers/mtd/maps/physmap.c +++ b/drivers/mtd/maps/physmap.c | |||
@@ -182,7 +182,7 @@ static struct physmap_flash_data physmap_flash_data = { | |||
182 | 182 | ||
183 | static struct resource physmap_flash_resource = { | 183 | static struct resource physmap_flash_resource = { |
184 | .start = CONFIG_MTD_PHYSMAP_START, | 184 | .start = CONFIG_MTD_PHYSMAP_START, |
185 | .end = CONFIG_MTD_PHYSMAP_START + CONFIG_MTD_PHYSMAP_LEN, | 185 | .end = CONFIG_MTD_PHYSMAP_START + CONFIG_MTD_PHYSMAP_LEN - 1, |
186 | .flags = IORESOURCE_MEM, | 186 | .flags = IORESOURCE_MEM, |
187 | }; | 187 | }; |
188 | 188 | ||
diff --git a/drivers/mtd/maps/sun_uflash.c b/drivers/mtd/maps/sun_uflash.c index 0758cb1d0105..24a03152d196 100644 --- a/drivers/mtd/maps/sun_uflash.c +++ b/drivers/mtd/maps/sun_uflash.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/ioport.h> | 18 | #include <linux/ioport.h> |
19 | #include <asm/ebus.h> | 19 | #include <asm/ebus.h> |
20 | #include <asm/oplib.h> | 20 | #include <asm/oplib.h> |
21 | #include <asm/prom.h> | ||
21 | #include <asm/uaccess.h> | 22 | #include <asm/uaccess.h> |
22 | #include <asm/io.h> | 23 | #include <asm/io.h> |
23 | 24 | ||
@@ -30,146 +31,140 @@ | |||
30 | #define UFLASH_WINDOW_SIZE 0x200000 | 31 | #define UFLASH_WINDOW_SIZE 0x200000 |
31 | #define UFLASH_BUSWIDTH 1 /* EBus is 8-bit */ | 32 | #define UFLASH_BUSWIDTH 1 /* EBus is 8-bit */ |
32 | 33 | ||
33 | MODULE_AUTHOR | 34 | MODULE_AUTHOR("Eric Brower <ebrower@usa.net>"); |
34 | ("Eric Brower <ebrower@usa.net>"); | 35 | MODULE_DESCRIPTION("User-programmable flash device on Sun Microsystems boardsets"); |
35 | MODULE_DESCRIPTION | 36 | MODULE_SUPPORTED_DEVICE("userflash"); |
36 | ("User-programmable flash device on Sun Microsystems boardsets"); | 37 | MODULE_LICENSE("GPL"); |
37 | MODULE_SUPPORTED_DEVICE | 38 | MODULE_VERSION("2.0"); |
38 | ("userflash"); | ||
39 | MODULE_LICENSE | ||
40 | ("GPL"); | ||
41 | 39 | ||
42 | static LIST_HEAD(device_list); | 40 | static LIST_HEAD(device_list); |
43 | struct uflash_dev { | 41 | struct uflash_dev { |
44 | char * name; /* device name */ | 42 | char *name; /* device name */ |
45 | struct map_info map; /* mtd map info */ | 43 | struct map_info map; /* mtd map info */ |
46 | struct mtd_info * mtd; /* mtd info */ | 44 | struct mtd_info *mtd; /* mtd info */ |
47 | struct list_head list; | ||
48 | }; | 45 | }; |
49 | 46 | ||
50 | 47 | ||
51 | struct map_info uflash_map_templ = { | 48 | struct map_info uflash_map_templ = { |
52 | .name = "SUNW,???-????", | 49 | .name = "SUNW,???-????", |
53 | .size = UFLASH_WINDOW_SIZE, | 50 | .size = UFLASH_WINDOW_SIZE, |
54 | .bankwidth = UFLASH_BUSWIDTH, | 51 | .bankwidth = UFLASH_BUSWIDTH, |
55 | }; | 52 | }; |
56 | 53 | ||
57 | int uflash_devinit(struct linux_ebus_device* edev) | 54 | int uflash_devinit(struct linux_ebus_device *edev, struct device_node *dp) |
58 | { | 55 | { |
59 | int iTmp, nregs; | 56 | struct uflash_dev *up; |
60 | struct linux_prom_registers regs[2]; | 57 | struct resource *res; |
61 | struct uflash_dev *pdev; | ||
62 | |||
63 | iTmp = prom_getproperty( | ||
64 | edev->prom_node, "reg", (void *)regs, sizeof(regs)); | ||
65 | if ((iTmp % sizeof(regs[0])) != 0) { | ||
66 | printk("%s: Strange reg property size %d\n", | ||
67 | UFLASH_DEVNAME, iTmp); | ||
68 | return -ENODEV; | ||
69 | } | ||
70 | 58 | ||
71 | nregs = iTmp / sizeof(regs[0]); | 59 | res = &edev->resource[0]; |
72 | 60 | ||
73 | if (nregs != 1) { | 61 | if (edev->num_addrs != 1) { |
74 | /* Non-CFI userflash device-- once I find one we | 62 | /* Non-CFI userflash device-- once I find one we |
75 | * can work on supporting it. | 63 | * can work on supporting it. |
76 | */ | 64 | */ |
77 | printk("%s: unsupported device at 0x%lx (%d regs): " \ | 65 | printk("%s: unsupported device at 0x%lx (%d regs): " \ |
78 | "email ebrower@usa.net\n", | 66 | "email ebrower@usa.net\n", |
79 | UFLASH_DEVNAME, edev->resource[0].start, nregs); | 67 | dp->full_name, res->start, edev->num_addrs); |
68 | |||
80 | return -ENODEV; | 69 | return -ENODEV; |
81 | } | 70 | } |
82 | 71 | ||
83 | if(0 == (pdev = kmalloc(sizeof(struct uflash_dev), GFP_KERNEL))) { | 72 | up = kzalloc(sizeof(struct uflash_dev), GFP_KERNEL); |
84 | printk("%s: unable to kmalloc new device\n", UFLASH_DEVNAME); | 73 | if (!up) |
85 | return(-ENOMEM); | 74 | return -ENOMEM; |
86 | } | ||
87 | 75 | ||
88 | /* copy defaults and tweak parameters */ | 76 | /* copy defaults and tweak parameters */ |
89 | memcpy(&pdev->map, &uflash_map_templ, sizeof(uflash_map_templ)); | 77 | memcpy(&up->map, &uflash_map_templ, sizeof(uflash_map_templ)); |
90 | pdev->map.size = regs[0].reg_size; | 78 | up->map.size = (res->end - res->start) + 1UL; |
91 | 79 | ||
92 | iTmp = prom_getproplen(edev->prom_node, "model"); | 80 | up->name = of_get_property(dp, "model", NULL); |
93 | pdev->name = kmalloc(iTmp, GFP_KERNEL); | 81 | if (up->name && 0 < strlen(up->name)) |
94 | prom_getstring(edev->prom_node, "model", pdev->name, iTmp); | 82 | up->map.name = up->name; |
95 | if(0 != pdev->name && 0 < strlen(pdev->name)) { | 83 | |
96 | pdev->map.name = pdev->name; | 84 | up->map.phys = res->start; |
97 | } | 85 | |
98 | pdev->map.phys = edev->resource[0].start; | 86 | up->map.virt = ioremap_nocache(res->start, up->map.size); |
99 | pdev->map.virt = ioremap_nocache(edev->resource[0].start, pdev->map.size); | 87 | if (!up->map.virt) { |
100 | if(0 == pdev->map.virt) { | 88 | printk("%s: Failed to map device.\n", dp->full_name); |
101 | printk("%s: failed to map device\n", __FUNCTION__); | 89 | kfree(up); |
102 | kfree(pdev->name); | 90 | |
103 | kfree(pdev); | 91 | return -EINVAL; |
104 | return(-1); | ||
105 | } | 92 | } |
106 | 93 | ||
107 | simple_map_init(&pdev->map); | 94 | simple_map_init(&up->map); |
108 | 95 | ||
109 | /* MTD registration */ | 96 | /* MTD registration */ |
110 | pdev->mtd = do_map_probe("cfi_probe", &pdev->map); | 97 | up->mtd = do_map_probe("cfi_probe", &up->map); |
111 | if(0 == pdev->mtd) { | 98 | if (!up->mtd) { |
112 | iounmap(pdev->map.virt); | 99 | iounmap(up->map.virt); |
113 | kfree(pdev->name); | 100 | kfree(up); |
114 | kfree(pdev); | 101 | |
115 | return(-ENXIO); | 102 | return -ENXIO; |
116 | } | 103 | } |
117 | 104 | ||
118 | list_add(&pdev->list, &device_list); | 105 | up->mtd->owner = THIS_MODULE; |
119 | 106 | ||
120 | pdev->mtd->owner = THIS_MODULE; | 107 | add_mtd_device(up->mtd); |
121 | 108 | ||
122 | add_mtd_device(pdev->mtd); | 109 | dev_set_drvdata(&edev->ofdev.dev, up); |
123 | return(0); | 110 | |
111 | return 0; | ||
124 | } | 112 | } |
125 | 113 | ||
126 | static int __init uflash_init(void) | 114 | static int __devinit uflash_probe(struct of_device *dev, const struct of_device_id *match) |
127 | { | 115 | { |
128 | struct linux_ebus *ebus = NULL; | 116 | struct linux_ebus_device *edev = to_ebus_device(&dev->dev); |
129 | struct linux_ebus_device *edev = NULL; | 117 | struct device_node *dp = dev->node; |
130 | |||
131 | for_each_ebus(ebus) { | ||
132 | for_each_ebusdev(edev, ebus) { | ||
133 | if (!strcmp(edev->prom_name, UFLASH_OBPNAME)) { | ||
134 | if(0 > prom_getproplen(edev->prom_node, "user")) { | ||
135 | DEBUG(2, "%s: ignoring device at 0x%lx\n", | ||
136 | UFLASH_DEVNAME, edev->resource[0].start); | ||
137 | } else { | ||
138 | uflash_devinit(edev); | ||
139 | } | ||
140 | } | ||
141 | } | ||
142 | } | ||
143 | 118 | ||
144 | if(list_empty(&device_list)) { | 119 | if (of_find_property(dp, "user", NULL)) |
145 | printk("%s: unable to locate device\n", UFLASH_DEVNAME); | ||
146 | return -ENODEV; | 120 | return -ENODEV; |
147 | } | 121 | |
148 | return(0); | 122 | return uflash_devinit(edev, dp); |
149 | } | 123 | } |
150 | 124 | ||
151 | static void __exit uflash_cleanup(void) | 125 | static int __devexit uflash_remove(struct of_device *dev) |
152 | { | 126 | { |
153 | struct list_head *udevlist; | 127 | struct uflash_dev *up = dev_get_drvdata(&dev->dev); |
154 | struct uflash_dev *udev; | 128 | |
155 | 129 | if (up->mtd) { | |
156 | list_for_each(udevlist, &device_list) { | 130 | del_mtd_device(up->mtd); |
157 | udev = list_entry(udevlist, struct uflash_dev, list); | 131 | map_destroy(up->mtd); |
158 | DEBUG(2, "%s: removing device %s\n", | ||
159 | UFLASH_DEVNAME, udev->name); | ||
160 | |||
161 | if(0 != udev->mtd) { | ||
162 | del_mtd_device(udev->mtd); | ||
163 | map_destroy(udev->mtd); | ||
164 | } | ||
165 | if(0 != udev->map.virt) { | ||
166 | iounmap(udev->map.virt); | ||
167 | udev->map.virt = NULL; | ||
168 | } | ||
169 | kfree(udev->name); | ||
170 | kfree(udev); | ||
171 | } | 132 | } |
133 | if (up->map.virt) { | ||
134 | iounmap(up->map.virt); | ||
135 | up->map.virt = NULL; | ||
136 | } | ||
137 | |||
138 | kfree(up); | ||
139 | |||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | static struct of_device_id uflash_match[] = { | ||
144 | { | ||
145 | .name = UFLASH_OBPNAME, | ||
146 | }, | ||
147 | {}, | ||
148 | }; | ||
149 | |||
150 | MODULE_DEVICE_TABLE(of, uflash_match); | ||
151 | |||
152 | static struct of_platform_driver uflash_driver = { | ||
153 | .name = UFLASH_DEVNAME, | ||
154 | .match_table = uflash_match, | ||
155 | .probe = uflash_probe, | ||
156 | .remove = __devexit_p(uflash_remove), | ||
157 | }; | ||
158 | |||
159 | static int __init uflash_init(void) | ||
160 | { | ||
161 | return of_register_driver(&uflash_driver, &ebus_bus_type); | ||
162 | } | ||
163 | |||
164 | static void __exit uflash_exit(void) | ||
165 | { | ||
166 | of_unregister_driver(&uflash_driver); | ||
172 | } | 167 | } |
173 | 168 | ||
174 | module_init(uflash_init); | 169 | module_init(uflash_init); |
175 | module_exit(uflash_cleanup); | 170 | module_exit(uflash_exit); |
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index aa18d45b264b..9a4b59d92525 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c | |||
@@ -78,7 +78,7 @@ static loff_t mtd_lseek (struct file *file, loff_t offset, int orig) | |||
78 | return -EINVAL; | 78 | return -EINVAL; |
79 | } | 79 | } |
80 | 80 | ||
81 | if (offset >= 0 && offset < mtd->size) | 81 | if (offset >= 0 && offset <= mtd->size) |
82 | return file->f_pos = offset; | 82 | return file->f_pos = offset; |
83 | 83 | ||
84 | return -EINVAL; | 84 | return -EINVAL; |
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 27083ed0a017..80a76654d963 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c | |||
@@ -1176,7 +1176,7 @@ static int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip, | |||
1176 | 1176 | ||
1177 | status = chip->waitfunc(mtd, chip); | 1177 | status = chip->waitfunc(mtd, chip); |
1178 | 1178 | ||
1179 | return status; | 1179 | return status & NAND_STATUS_FAIL ? -EIO : 0; |
1180 | } | 1180 | } |
1181 | 1181 | ||
1182 | /** | 1182 | /** |
@@ -1271,10 +1271,6 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, | |||
1271 | sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd); | 1271 | sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd); |
1272 | buf = nand_transfer_oob(chip, buf, ops); | 1272 | buf = nand_transfer_oob(chip, buf, ops); |
1273 | 1273 | ||
1274 | readlen -= ops->ooblen; | ||
1275 | if (!readlen) | ||
1276 | break; | ||
1277 | |||
1278 | if (!(chip->options & NAND_NO_READRDY)) { | 1274 | if (!(chip->options & NAND_NO_READRDY)) { |
1279 | /* | 1275 | /* |
1280 | * Apply delay or wait for ready/busy pin. Do this | 1276 | * Apply delay or wait for ready/busy pin. Do this |
@@ -1288,6 +1284,10 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, | |||
1288 | nand_wait_ready(mtd); | 1284 | nand_wait_ready(mtd); |
1289 | } | 1285 | } |
1290 | 1286 | ||
1287 | readlen -= ops->ooblen; | ||
1288 | if (!readlen) | ||
1289 | break; | ||
1290 | |||
1291 | /* Increment page address */ | 1291 | /* Increment page address */ |
1292 | realpage++; | 1292 | realpage++; |
1293 | 1293 | ||
@@ -1610,13 +1610,13 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, | |||
1610 | if (!writelen) | 1610 | if (!writelen) |
1611 | return 0; | 1611 | return 0; |
1612 | 1612 | ||
1613 | chipnr = (int)(to >> chip->chip_shift); | ||
1614 | chip->select_chip(mtd, chipnr); | ||
1615 | |||
1613 | /* Check, if it is write protected */ | 1616 | /* Check, if it is write protected */ |
1614 | if (nand_check_wp(mtd)) | 1617 | if (nand_check_wp(mtd)) |
1615 | return -EIO; | 1618 | return -EIO; |
1616 | 1619 | ||
1617 | chipnr = (int)(to >> chip->chip_shift); | ||
1618 | chip->select_chip(mtd, chipnr); | ||
1619 | |||
1620 | realpage = (int)(to >> chip->page_shift); | 1620 | realpage = (int)(to >> chip->page_shift); |
1621 | page = realpage & chip->pagemask; | 1621 | page = realpage & chip->pagemask; |
1622 | blockmask = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; | 1622 | blockmask = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; |
diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c index fe8d38514ba6..e5bd88f2d560 100644 --- a/drivers/mtd/nand/ndfc.c +++ b/drivers/mtd/nand/ndfc.c | |||
@@ -61,15 +61,15 @@ static void ndfc_select_chip(struct mtd_info *mtd, int chip) | |||
61 | 61 | ||
62 | static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) | 62 | static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) |
63 | { | 63 | { |
64 | struct nand_chip *chip = mtd->priv; | 64 | struct ndfc_controller *ndfc = &ndfc_ctrl; |
65 | 65 | ||
66 | if (cmd == NAND_CMD_NONE) | 66 | if (cmd == NAND_CMD_NONE) |
67 | return; | 67 | return; |
68 | 68 | ||
69 | if (ctrl & NAND_CLE) | 69 | if (ctrl & NAND_CLE) |
70 | writel(cmd & 0xFF, chip->IO_ADDR_W + NDFC_CMD); | 70 | writel(cmd & 0xFF, ndfc->ndfcbase + NDFC_CMD); |
71 | else | 71 | else |
72 | writel(cmd & 0xFF, chip->IO_ADDR_W + NDFC_ALE); | 72 | writel(cmd & 0xFF, ndfc->ndfcbase + NDFC_ALE); |
73 | } | 73 | } |
74 | 74 | ||
75 | static int ndfc_ready(struct mtd_info *mtd) | 75 | static int ndfc_ready(struct mtd_info *mtd) |
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index 2c262fe03d8a..ff5cef24d5bb 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c | |||
@@ -63,8 +63,6 @@ | |||
63 | #include <asm/arch/regs-nand.h> | 63 | #include <asm/arch/regs-nand.h> |
64 | #include <asm/arch/nand.h> | 64 | #include <asm/arch/nand.h> |
65 | 65 | ||
66 | #define PFX "s3c2410-nand: " | ||
67 | |||
68 | #ifdef CONFIG_MTD_NAND_S3C2410_HWECC | 66 | #ifdef CONFIG_MTD_NAND_S3C2410_HWECC |
69 | static int hardware_ecc = 1; | 67 | static int hardware_ecc = 1; |
70 | #else | 68 | #else |
@@ -99,6 +97,12 @@ struct s3c2410_nand_mtd { | |||
99 | int scan_res; | 97 | int scan_res; |
100 | }; | 98 | }; |
101 | 99 | ||
100 | enum s3c_cpu_type { | ||
101 | TYPE_S3C2410, | ||
102 | TYPE_S3C2412, | ||
103 | TYPE_S3C2440, | ||
104 | }; | ||
105 | |||
102 | /* overview of the s3c2410 nand state */ | 106 | /* overview of the s3c2410 nand state */ |
103 | 107 | ||
104 | struct s3c2410_nand_info { | 108 | struct s3c2410_nand_info { |
@@ -112,9 +116,11 @@ struct s3c2410_nand_info { | |||
112 | struct resource *area; | 116 | struct resource *area; |
113 | struct clk *clk; | 117 | struct clk *clk; |
114 | void __iomem *regs; | 118 | void __iomem *regs; |
119 | void __iomem *sel_reg; | ||
120 | int sel_bit; | ||
115 | int mtd_count; | 121 | int mtd_count; |
116 | 122 | ||
117 | unsigned char is_s3c2440; | 123 | enum s3c_cpu_type cpu_type; |
118 | }; | 124 | }; |
119 | 125 | ||
120 | /* conversion functions */ | 126 | /* conversion functions */ |
@@ -148,7 +154,7 @@ static inline int allow_clk_stop(struct s3c2410_nand_info *info) | |||
148 | 154 | ||
149 | #define NS_IN_KHZ 1000000 | 155 | #define NS_IN_KHZ 1000000 |
150 | 156 | ||
151 | static int s3c2410_nand_calc_rate(int wanted, unsigned long clk, int max) | 157 | static int s3c_nand_calc_rate(int wanted, unsigned long clk, int max) |
152 | { | 158 | { |
153 | int result; | 159 | int result; |
154 | 160 | ||
@@ -172,53 +178,58 @@ static int s3c2410_nand_calc_rate(int wanted, unsigned long clk, int max) | |||
172 | 178 | ||
173 | /* controller setup */ | 179 | /* controller setup */ |
174 | 180 | ||
175 | static int s3c2410_nand_inithw(struct s3c2410_nand_info *info, struct platform_device *pdev) | 181 | static int s3c2410_nand_inithw(struct s3c2410_nand_info *info, |
182 | struct platform_device *pdev) | ||
176 | { | 183 | { |
177 | struct s3c2410_platform_nand *plat = to_nand_plat(pdev); | 184 | struct s3c2410_platform_nand *plat = to_nand_plat(pdev); |
178 | unsigned long clkrate = clk_get_rate(info->clk); | 185 | unsigned long clkrate = clk_get_rate(info->clk); |
186 | int tacls_max = (info->cpu_type == TYPE_S3C2412) ? 8 : 4; | ||
179 | int tacls, twrph0, twrph1; | 187 | int tacls, twrph0, twrph1; |
180 | unsigned long cfg; | 188 | unsigned long cfg = 0; |
181 | 189 | ||
182 | /* calculate the timing information for the controller */ | 190 | /* calculate the timing information for the controller */ |
183 | 191 | ||
184 | clkrate /= 1000; /* turn clock into kHz for ease of use */ | 192 | clkrate /= 1000; /* turn clock into kHz for ease of use */ |
185 | 193 | ||
186 | if (plat != NULL) { | 194 | if (plat != NULL) { |
187 | tacls = s3c2410_nand_calc_rate(plat->tacls, clkrate, 4); | 195 | tacls = s3c_nand_calc_rate(plat->tacls, clkrate, tacls_max); |
188 | twrph0 = s3c2410_nand_calc_rate(plat->twrph0, clkrate, 8); | 196 | twrph0 = s3c_nand_calc_rate(plat->twrph0, clkrate, 8); |
189 | twrph1 = s3c2410_nand_calc_rate(plat->twrph1, clkrate, 8); | 197 | twrph1 = s3c_nand_calc_rate(plat->twrph1, clkrate, 8); |
190 | } else { | 198 | } else { |
191 | /* default timings */ | 199 | /* default timings */ |
192 | tacls = 4; | 200 | tacls = tacls_max; |
193 | twrph0 = 8; | 201 | twrph0 = 8; |
194 | twrph1 = 8; | 202 | twrph1 = 8; |
195 | } | 203 | } |
196 | 204 | ||
197 | if (tacls < 0 || twrph0 < 0 || twrph1 < 0) { | 205 | if (tacls < 0 || twrph0 < 0 || twrph1 < 0) { |
198 | printk(KERN_ERR PFX "cannot get timings suitable for board\n"); | 206 | dev_err(info->device, "cannot get suitable timings\n"); |
199 | return -EINVAL; | 207 | return -EINVAL; |
200 | } | 208 | } |
201 | 209 | ||
202 | printk(KERN_INFO PFX "Tacls=%d, %dns Twrph0=%d %dns, Twrph1=%d %dns\n", | 210 | dev_info(info->device, "Tacls=%d, %dns Twrph0=%d %dns, Twrph1=%d %dns\n", |
203 | tacls, to_ns(tacls, clkrate), twrph0, to_ns(twrph0, clkrate), twrph1, to_ns(twrph1, clkrate)); | 211 | tacls, to_ns(tacls, clkrate), twrph0, to_ns(twrph0, clkrate), twrph1, to_ns(twrph1, clkrate)); |
204 | 212 | ||
205 | if (!info->is_s3c2440) { | 213 | switch (info->cpu_type) { |
214 | case TYPE_S3C2410: | ||
206 | cfg = S3C2410_NFCONF_EN; | 215 | cfg = S3C2410_NFCONF_EN; |
207 | cfg |= S3C2410_NFCONF_TACLS(tacls - 1); | 216 | cfg |= S3C2410_NFCONF_TACLS(tacls - 1); |
208 | cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1); | 217 | cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1); |
209 | cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1); | 218 | cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1); |
210 | } else { | 219 | break; |
220 | |||
221 | case TYPE_S3C2440: | ||
222 | case TYPE_S3C2412: | ||
211 | cfg = S3C2440_NFCONF_TACLS(tacls - 1); | 223 | cfg = S3C2440_NFCONF_TACLS(tacls - 1); |
212 | cfg |= S3C2440_NFCONF_TWRPH0(twrph0 - 1); | 224 | cfg |= S3C2440_NFCONF_TWRPH0(twrph0 - 1); |
213 | cfg |= S3C2440_NFCONF_TWRPH1(twrph1 - 1); | 225 | cfg |= S3C2440_NFCONF_TWRPH1(twrph1 - 1); |
214 | 226 | ||
215 | /* enable the controller and de-assert nFCE */ | 227 | /* enable the controller and de-assert nFCE */ |
216 | 228 | ||
217 | writel(S3C2440_NFCONT_ENABLE | S3C2440_NFCONT_ENABLE, | 229 | writel(S3C2440_NFCONT_ENABLE, info->regs + S3C2440_NFCONT); |
218 | info->regs + S3C2440_NFCONT); | ||
219 | } | 230 | } |
220 | 231 | ||
221 | pr_debug(PFX "NF_CONF is 0x%lx\n", cfg); | 232 | dev_dbg(info->device, "NF_CONF is 0x%lx\n", cfg); |
222 | 233 | ||
223 | writel(cfg, info->regs + S3C2410_NFCONF); | 234 | writel(cfg, info->regs + S3C2410_NFCONF); |
224 | return 0; | 235 | return 0; |
@@ -231,26 +242,21 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip) | |||
231 | struct s3c2410_nand_info *info; | 242 | struct s3c2410_nand_info *info; |
232 | struct s3c2410_nand_mtd *nmtd; | 243 | struct s3c2410_nand_mtd *nmtd; |
233 | struct nand_chip *this = mtd->priv; | 244 | struct nand_chip *this = mtd->priv; |
234 | void __iomem *reg; | ||
235 | unsigned long cur; | 245 | unsigned long cur; |
236 | unsigned long bit; | ||
237 | 246 | ||
238 | nmtd = this->priv; | 247 | nmtd = this->priv; |
239 | info = nmtd->info; | 248 | info = nmtd->info; |
240 | 249 | ||
241 | bit = (info->is_s3c2440) ? S3C2440_NFCONT_nFCE : S3C2410_NFCONF_nFCE; | ||
242 | reg = info->regs + ((info->is_s3c2440) ? S3C2440_NFCONT : S3C2410_NFCONF); | ||
243 | |||
244 | if (chip != -1 && allow_clk_stop(info)) | 250 | if (chip != -1 && allow_clk_stop(info)) |
245 | clk_enable(info->clk); | 251 | clk_enable(info->clk); |
246 | 252 | ||
247 | cur = readl(reg); | 253 | cur = readl(info->sel_reg); |
248 | 254 | ||
249 | if (chip == -1) { | 255 | if (chip == -1) { |
250 | cur |= bit; | 256 | cur |= info->sel_bit; |
251 | } else { | 257 | } else { |
252 | if (nmtd->set != NULL && chip > nmtd->set->nr_chips) { | 258 | if (nmtd->set != NULL && chip > nmtd->set->nr_chips) { |
253 | printk(KERN_ERR PFX "chip %d out of range\n", chip); | 259 | dev_err(info->device, "invalid chip %d\n", chip); |
254 | return; | 260 | return; |
255 | } | 261 | } |
256 | 262 | ||
@@ -259,10 +265,10 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip) | |||
259 | (info->platform->select_chip) (nmtd->set, chip); | 265 | (info->platform->select_chip) (nmtd->set, chip); |
260 | } | 266 | } |
261 | 267 | ||
262 | cur &= ~bit; | 268 | cur &= ~info->sel_bit; |
263 | } | 269 | } |
264 | 270 | ||
265 | writel(cur, reg); | 271 | writel(cur, info->sel_reg); |
266 | 272 | ||
267 | if (chip == -1 && allow_clk_stop(info)) | 273 | if (chip == -1 && allow_clk_stop(info)) |
268 | clk_disable(info->clk); | 274 | clk_disable(info->clk); |
@@ -311,15 +317,25 @@ static void s3c2440_nand_hwcontrol(struct mtd_info *mtd, int cmd, | |||
311 | static int s3c2410_nand_devready(struct mtd_info *mtd) | 317 | static int s3c2410_nand_devready(struct mtd_info *mtd) |
312 | { | 318 | { |
313 | struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); | 319 | struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); |
314 | |||
315 | if (info->is_s3c2440) | ||
316 | return readb(info->regs + S3C2440_NFSTAT) & S3C2440_NFSTAT_READY; | ||
317 | return readb(info->regs + S3C2410_NFSTAT) & S3C2410_NFSTAT_BUSY; | 320 | return readb(info->regs + S3C2410_NFSTAT) & S3C2410_NFSTAT_BUSY; |
318 | } | 321 | } |
319 | 322 | ||
323 | static int s3c2440_nand_devready(struct mtd_info *mtd) | ||
324 | { | ||
325 | struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); | ||
326 | return readb(info->regs + S3C2440_NFSTAT) & S3C2440_NFSTAT_READY; | ||
327 | } | ||
328 | |||
329 | static int s3c2412_nand_devready(struct mtd_info *mtd) | ||
330 | { | ||
331 | struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); | ||
332 | return readb(info->regs + S3C2412_NFSTAT) & S3C2412_NFSTAT_READY; | ||
333 | } | ||
334 | |||
320 | /* ECC handling functions */ | 335 | /* ECC handling functions */ |
321 | 336 | ||
322 | static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc) | 337 | static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat, |
338 | u_char *read_ecc, u_char *calc_ecc) | ||
323 | { | 339 | { |
324 | pr_debug("s3c2410_nand_correct_data(%p,%p,%p,%p)\n", mtd, dat, read_ecc, calc_ecc); | 340 | pr_debug("s3c2410_nand_correct_data(%p,%p,%p,%p)\n", mtd, dat, read_ecc, calc_ecc); |
325 | 341 | ||
@@ -487,11 +503,8 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, | |||
487 | struct s3c2410_nand_set *set) | 503 | struct s3c2410_nand_set *set) |
488 | { | 504 | { |
489 | struct nand_chip *chip = &nmtd->chip; | 505 | struct nand_chip *chip = &nmtd->chip; |
506 | void __iomem *regs = info->regs; | ||
490 | 507 | ||
491 | chip->IO_ADDR_R = info->regs + S3C2410_NFDATA; | ||
492 | chip->IO_ADDR_W = info->regs + S3C2410_NFDATA; | ||
493 | chip->cmd_ctrl = s3c2410_nand_hwcontrol; | ||
494 | chip->dev_ready = s3c2410_nand_devready; | ||
495 | chip->write_buf = s3c2410_nand_write_buf; | 508 | chip->write_buf = s3c2410_nand_write_buf; |
496 | chip->read_buf = s3c2410_nand_read_buf; | 509 | chip->read_buf = s3c2410_nand_read_buf; |
497 | chip->select_chip = s3c2410_nand_select_chip; | 510 | chip->select_chip = s3c2410_nand_select_chip; |
@@ -500,11 +513,37 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, | |||
500 | chip->options = 0; | 513 | chip->options = 0; |
501 | chip->controller = &info->controller; | 514 | chip->controller = &info->controller; |
502 | 515 | ||
503 | if (info->is_s3c2440) { | 516 | switch (info->cpu_type) { |
504 | chip->IO_ADDR_R = info->regs + S3C2440_NFDATA; | 517 | case TYPE_S3C2410: |
505 | chip->IO_ADDR_W = info->regs + S3C2440_NFDATA; | 518 | chip->IO_ADDR_W = regs + S3C2410_NFDATA; |
506 | chip->cmd_ctrl = s3c2440_nand_hwcontrol; | 519 | info->sel_reg = regs + S3C2410_NFCONF; |
507 | } | 520 | info->sel_bit = S3C2410_NFCONF_nFCE; |
521 | chip->cmd_ctrl = s3c2410_nand_hwcontrol; | ||
522 | chip->dev_ready = s3c2410_nand_devready; | ||
523 | break; | ||
524 | |||
525 | case TYPE_S3C2440: | ||
526 | chip->IO_ADDR_W = regs + S3C2440_NFDATA; | ||
527 | info->sel_reg = regs + S3C2440_NFCONT; | ||
528 | info->sel_bit = S3C2440_NFCONT_nFCE; | ||
529 | chip->cmd_ctrl = s3c2440_nand_hwcontrol; | ||
530 | chip->dev_ready = s3c2440_nand_devready; | ||
531 | break; | ||
532 | |||
533 | case TYPE_S3C2412: | ||
534 | chip->IO_ADDR_W = regs + S3C2440_NFDATA; | ||
535 | info->sel_reg = regs + S3C2440_NFCONT; | ||
536 | info->sel_bit = S3C2412_NFCONT_nFCE0; | ||
537 | chip->cmd_ctrl = s3c2440_nand_hwcontrol; | ||
538 | chip->dev_ready = s3c2412_nand_devready; | ||
539 | |||
540 | if (readl(regs + S3C2410_NFCONF) & S3C2412_NFCONF_NANDBOOT) | ||
541 | dev_info(info->device, "System booted from NAND\n"); | ||
542 | |||
543 | break; | ||
544 | } | ||
545 | |||
546 | chip->IO_ADDR_R = chip->IO_ADDR_W; | ||
508 | 547 | ||
509 | nmtd->info = info; | 548 | nmtd->info = info; |
510 | nmtd->mtd.priv = chip; | 549 | nmtd->mtd.priv = chip; |
@@ -512,17 +551,25 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, | |||
512 | nmtd->set = set; | 551 | nmtd->set = set; |
513 | 552 | ||
514 | if (hardware_ecc) { | 553 | if (hardware_ecc) { |
515 | chip->ecc.correct = s3c2410_nand_correct_data; | ||
516 | chip->ecc.hwctl = s3c2410_nand_enable_hwecc; | ||
517 | chip->ecc.calculate = s3c2410_nand_calculate_ecc; | 554 | chip->ecc.calculate = s3c2410_nand_calculate_ecc; |
555 | chip->ecc.correct = s3c2410_nand_correct_data; | ||
518 | chip->ecc.mode = NAND_ECC_HW; | 556 | chip->ecc.mode = NAND_ECC_HW; |
519 | chip->ecc.size = 512; | 557 | chip->ecc.size = 512; |
520 | chip->ecc.bytes = 3; | 558 | chip->ecc.bytes = 3; |
521 | chip->ecc.layout = &nand_hw_eccoob; | 559 | chip->ecc.layout = &nand_hw_eccoob; |
522 | 560 | ||
523 | if (info->is_s3c2440) { | 561 | switch (info->cpu_type) { |
524 | chip->ecc.hwctl = s3c2440_nand_enable_hwecc; | 562 | case TYPE_S3C2410: |
525 | chip->ecc.calculate = s3c2440_nand_calculate_ecc; | 563 | chip->ecc.hwctl = s3c2410_nand_enable_hwecc; |
564 | chip->ecc.calculate = s3c2410_nand_calculate_ecc; | ||
565 | break; | ||
566 | |||
567 | case TYPE_S3C2412: | ||
568 | case TYPE_S3C2440: | ||
569 | chip->ecc.hwctl = s3c2440_nand_enable_hwecc; | ||
570 | chip->ecc.calculate = s3c2440_nand_calculate_ecc; | ||
571 | break; | ||
572 | |||
526 | } | 573 | } |
527 | } else { | 574 | } else { |
528 | chip->ecc.mode = NAND_ECC_SOFT; | 575 | chip->ecc.mode = NAND_ECC_SOFT; |
@@ -537,7 +584,8 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, | |||
537 | * nand layer to look for devices | 584 | * nand layer to look for devices |
538 | */ | 585 | */ |
539 | 586 | ||
540 | static int s3c24xx_nand_probe(struct platform_device *pdev, int is_s3c2440) | 587 | static int s3c24xx_nand_probe(struct platform_device *pdev, |
588 | enum s3c_cpu_type cpu_type) | ||
541 | { | 589 | { |
542 | struct s3c2410_platform_nand *plat = to_nand_plat(pdev); | 590 | struct s3c2410_platform_nand *plat = to_nand_plat(pdev); |
543 | struct s3c2410_nand_info *info; | 591 | struct s3c2410_nand_info *info; |
@@ -592,7 +640,7 @@ static int s3c24xx_nand_probe(struct platform_device *pdev, int is_s3c2440) | |||
592 | info->device = &pdev->dev; | 640 | info->device = &pdev->dev; |
593 | info->platform = plat; | 641 | info->platform = plat; |
594 | info->regs = ioremap(res->start, size); | 642 | info->regs = ioremap(res->start, size); |
595 | info->is_s3c2440 = is_s3c2440; | 643 | info->cpu_type = cpu_type; |
596 | 644 | ||
597 | if (info->regs == NULL) { | 645 | if (info->regs == NULL) { |
598 | dev_err(&pdev->dev, "cannot reserve register region\n"); | 646 | dev_err(&pdev->dev, "cannot reserve register region\n"); |
@@ -699,12 +747,17 @@ static int s3c24xx_nand_resume(struct platform_device *dev) | |||
699 | 747 | ||
700 | static int s3c2410_nand_probe(struct platform_device *dev) | 748 | static int s3c2410_nand_probe(struct platform_device *dev) |
701 | { | 749 | { |
702 | return s3c24xx_nand_probe(dev, 0); | 750 | return s3c24xx_nand_probe(dev, TYPE_S3C2410); |
703 | } | 751 | } |
704 | 752 | ||
705 | static int s3c2440_nand_probe(struct platform_device *dev) | 753 | static int s3c2440_nand_probe(struct platform_device *dev) |
706 | { | 754 | { |
707 | return s3c24xx_nand_probe(dev, 1); | 755 | return s3c24xx_nand_probe(dev, TYPE_S3C2440); |
756 | } | ||
757 | |||
758 | static int s3c2412_nand_probe(struct platform_device *dev) | ||
759 | { | ||
760 | return s3c24xx_nand_probe(dev, TYPE_S3C2412); | ||
708 | } | 761 | } |
709 | 762 | ||
710 | static struct platform_driver s3c2410_nand_driver = { | 763 | static struct platform_driver s3c2410_nand_driver = { |
@@ -729,16 +782,29 @@ static struct platform_driver s3c2440_nand_driver = { | |||
729 | }, | 782 | }, |
730 | }; | 783 | }; |
731 | 784 | ||
785 | static struct platform_driver s3c2412_nand_driver = { | ||
786 | .probe = s3c2412_nand_probe, | ||
787 | .remove = s3c2410_nand_remove, | ||
788 | .suspend = s3c24xx_nand_suspend, | ||
789 | .resume = s3c24xx_nand_resume, | ||
790 | .driver = { | ||
791 | .name = "s3c2412-nand", | ||
792 | .owner = THIS_MODULE, | ||
793 | }, | ||
794 | }; | ||
795 | |||
732 | static int __init s3c2410_nand_init(void) | 796 | static int __init s3c2410_nand_init(void) |
733 | { | 797 | { |
734 | printk("S3C24XX NAND Driver, (c) 2004 Simtec Electronics\n"); | 798 | printk("S3C24XX NAND Driver, (c) 2004 Simtec Electronics\n"); |
735 | 799 | ||
800 | platform_driver_register(&s3c2412_nand_driver); | ||
736 | platform_driver_register(&s3c2440_nand_driver); | 801 | platform_driver_register(&s3c2440_nand_driver); |
737 | return platform_driver_register(&s3c2410_nand_driver); | 802 | return platform_driver_register(&s3c2410_nand_driver); |
738 | } | 803 | } |
739 | 804 | ||
740 | static void __exit s3c2410_nand_exit(void) | 805 | static void __exit s3c2410_nand_exit(void) |
741 | { | 806 | { |
807 | platform_driver_unregister(&s3c2412_nand_driver); | ||
742 | platform_driver_unregister(&s3c2440_nand_driver); | 808 | platform_driver_unregister(&s3c2440_nand_driver); |
743 | platform_driver_unregister(&s3c2410_nand_driver); | 809 | platform_driver_unregister(&s3c2410_nand_driver); |
744 | } | 810 | } |
diff --git a/drivers/mtd/nand/ts7250.c b/drivers/mtd/nand/ts7250.c index a0b4b1edcb0d..f40081069ab2 100644 --- a/drivers/mtd/nand/ts7250.c +++ b/drivers/mtd/nand/ts7250.c | |||
@@ -97,7 +97,7 @@ static void ts7250_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) | |||
97 | unsigned long addr = TS72XX_NAND_CONTROL_VIRT_BASE; | 97 | unsigned long addr = TS72XX_NAND_CONTROL_VIRT_BASE; |
98 | unsigned char bits; | 98 | unsigned char bits; |
99 | 99 | ||
100 | bits = (ctrl & NAND_CNE) << 2; | 100 | bits = (ctrl & NAND_NCE) << 2; |
101 | bits |= ctrl & NAND_CLE; | 101 | bits |= ctrl & NAND_CLE; |
102 | bits |= (ctrl & NAND_ALE) >> 2; | 102 | bits |= (ctrl & NAND_ALE) >> 2; |
103 | 103 | ||
diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c index bb44509fd404..07136ec423bd 100644 --- a/drivers/net/3c501.c +++ b/drivers/net/3c501.c | |||
@@ -508,11 +508,11 @@ static int el_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
508 | * speak of. We simply pull the packet out of its PIO buffer (which is slow) | 508 | * speak of. We simply pull the packet out of its PIO buffer (which is slow) |
509 | * and queue it for the kernel. Then we reset the card for the next packet. | 509 | * and queue it for the kernel. Then we reset the card for the next packet. |
510 | * | 510 | * |
511 | * We sometimes get suprise interrupts late both because the SMP IRQ delivery | 511 | * We sometimes get surprise interrupts late both because the SMP IRQ delivery |
512 | * is message passing and because the card sometimes seems to deliver late. I | 512 | * is message passing and because the card sometimes seems to deliver late. I |
513 | * think if it is part way through a receive and the mode is changed it carries | 513 | * think if it is part way through a receive and the mode is changed it carries |
514 | * on receiving and sends us an interrupt. We have to band aid all these cases | 514 | * on receiving and sends us an interrupt. We have to band aid all these cases |
515 | * to get a sensible 150kbytes/second performance. Even then you want a small | 515 | * to get a sensible 150kBytes/second performance. Even then you want a small |
516 | * TCP window. | 516 | * TCP window. |
517 | */ | 517 | */ |
518 | 518 | ||
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index e27778926eba..b467c383ae60 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c | |||
@@ -375,8 +375,7 @@ limit of 4K. | |||
375 | of the drivers, and will likely be provided by some future kernel. | 375 | of the drivers, and will likely be provided by some future kernel. |
376 | */ | 376 | */ |
377 | enum pci_flags_bit { | 377 | enum pci_flags_bit { |
378 | PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4, | 378 | PCI_USES_MASTER=4, |
379 | PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3, | ||
380 | }; | 379 | }; |
381 | 380 | ||
382 | enum { IS_VORTEX=1, IS_BOOMERANG=2, IS_CYCLONE=4, IS_TORNADO=8, | 381 | enum { IS_VORTEX=1, IS_BOOMERANG=2, IS_CYCLONE=4, IS_TORNADO=8, |
@@ -446,95 +445,95 @@ static struct vortex_chip_info { | |||
446 | int io_size; | 445 | int io_size; |
447 | } vortex_info_tbl[] __devinitdata = { | 446 | } vortex_info_tbl[] __devinitdata = { |
448 | {"3c590 Vortex 10Mbps", | 447 | {"3c590 Vortex 10Mbps", |
449 | PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, }, | 448 | PCI_USES_MASTER, IS_VORTEX, 32, }, |
450 | {"3c592 EISA 10Mbps Demon/Vortex", /* AKPM: from Don's 3c59x_cb.c 0.49H */ | 449 | {"3c592 EISA 10Mbps Demon/Vortex", /* AKPM: from Don's 3c59x_cb.c 0.49H */ |
451 | PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, }, | 450 | PCI_USES_MASTER, IS_VORTEX, 32, }, |
452 | {"3c597 EISA Fast Demon/Vortex", /* AKPM: from Don's 3c59x_cb.c 0.49H */ | 451 | {"3c597 EISA Fast Demon/Vortex", /* AKPM: from Don's 3c59x_cb.c 0.49H */ |
453 | PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, }, | 452 | PCI_USES_MASTER, IS_VORTEX, 32, }, |
454 | {"3c595 Vortex 100baseTx", | 453 | {"3c595 Vortex 100baseTx", |
455 | PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, }, | 454 | PCI_USES_MASTER, IS_VORTEX, 32, }, |
456 | {"3c595 Vortex 100baseT4", | 455 | {"3c595 Vortex 100baseT4", |
457 | PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, }, | 456 | PCI_USES_MASTER, IS_VORTEX, 32, }, |
458 | 457 | ||
459 | {"3c595 Vortex 100base-MII", | 458 | {"3c595 Vortex 100base-MII", |
460 | PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, }, | 459 | PCI_USES_MASTER, IS_VORTEX, 32, }, |
461 | {"3c900 Boomerang 10baseT", | 460 | {"3c900 Boomerang 10baseT", |
462 | PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|EEPROM_RESET, 64, }, | 461 | PCI_USES_MASTER, IS_BOOMERANG|EEPROM_RESET, 64, }, |
463 | {"3c900 Boomerang 10Mbps Combo", | 462 | {"3c900 Boomerang 10Mbps Combo", |
464 | PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|EEPROM_RESET, 64, }, | 463 | PCI_USES_MASTER, IS_BOOMERANG|EEPROM_RESET, 64, }, |
465 | {"3c900 Cyclone 10Mbps TPO", /* AKPM: from Don's 0.99M */ | 464 | {"3c900 Cyclone 10Mbps TPO", /* AKPM: from Don's 0.99M */ |
466 | PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, }, | 465 | PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, }, |
467 | {"3c900 Cyclone 10Mbps Combo", | 466 | {"3c900 Cyclone 10Mbps Combo", |
468 | PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, }, | 467 | PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, }, |
469 | 468 | ||
470 | {"3c900 Cyclone 10Mbps TPC", /* AKPM: from Don's 0.99M */ | 469 | {"3c900 Cyclone 10Mbps TPC", /* AKPM: from Don's 0.99M */ |
471 | PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, }, | 470 | PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, }, |
472 | {"3c900B-FL Cyclone 10base-FL", | 471 | {"3c900B-FL Cyclone 10base-FL", |
473 | PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, }, | 472 | PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, }, |
474 | {"3c905 Boomerang 100baseTx", | 473 | {"3c905 Boomerang 100baseTx", |
475 | PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_RESET, 64, }, | 474 | PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_RESET, 64, }, |
476 | {"3c905 Boomerang 100baseT4", | 475 | {"3c905 Boomerang 100baseT4", |
477 | PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_RESET, 64, }, | 476 | PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_RESET, 64, }, |
478 | {"3c905B Cyclone 100baseTx", | 477 | {"3c905B Cyclone 100baseTx", |
479 | PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM|EXTRA_PREAMBLE, 128, }, | 478 | PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM|EXTRA_PREAMBLE, 128, }, |
480 | 479 | ||
481 | {"3c905B Cyclone 10/100/BNC", | 480 | {"3c905B Cyclone 10/100/BNC", |
482 | PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, }, | 481 | PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, }, |
483 | {"3c905B-FX Cyclone 100baseFx", | 482 | {"3c905B-FX Cyclone 100baseFx", |
484 | PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, }, | 483 | PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, }, |
485 | {"3c905C Tornado", | 484 | {"3c905C Tornado", |
486 | PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM|EXTRA_PREAMBLE, 128, }, | 485 | PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM|EXTRA_PREAMBLE, 128, }, |
487 | {"3c920B-EMB-WNM (ATI Radeon 9100 IGP)", | 486 | {"3c920B-EMB-WNM (ATI Radeon 9100 IGP)", |
488 | PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_MII|HAS_HWCKSM, 128, }, | 487 | PCI_USES_MASTER, IS_TORNADO|HAS_MII|HAS_HWCKSM, 128, }, |
489 | {"3c980 Cyclone", | 488 | {"3c980 Cyclone", |
490 | PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, }, | 489 | PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, }, |
491 | 490 | ||
492 | {"3c980C Python-T", | 491 | {"3c980C Python-T", |
493 | PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, }, | 492 | PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, }, |
494 | {"3cSOHO100-TX Hurricane", | 493 | {"3cSOHO100-TX Hurricane", |
495 | PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, }, | 494 | PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, }, |
496 | {"3c555 Laptop Hurricane", | 495 | {"3c555 Laptop Hurricane", |
497 | PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|EEPROM_8BIT|HAS_HWCKSM, 128, }, | 496 | PCI_USES_MASTER, IS_CYCLONE|EEPROM_8BIT|HAS_HWCKSM, 128, }, |
498 | {"3c556 Laptop Tornado", | 497 | {"3c556 Laptop Tornado", |
499 | PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|EEPROM_8BIT|HAS_CB_FNS|INVERT_MII_PWR| | 498 | PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|EEPROM_8BIT|HAS_CB_FNS|INVERT_MII_PWR| |
500 | HAS_HWCKSM, 128, }, | 499 | HAS_HWCKSM, 128, }, |
501 | {"3c556B Laptop Hurricane", | 500 | {"3c556B Laptop Hurricane", |
502 | PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|EEPROM_OFFSET|HAS_CB_FNS|INVERT_MII_PWR| | 501 | PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|EEPROM_OFFSET|HAS_CB_FNS|INVERT_MII_PWR| |
503 | WNO_XCVR_PWR|HAS_HWCKSM, 128, }, | 502 | WNO_XCVR_PWR|HAS_HWCKSM, 128, }, |
504 | 503 | ||
505 | {"3c575 [Megahertz] 10/100 LAN CardBus", | 504 | {"3c575 [Megahertz] 10/100 LAN CardBus", |
506 | PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_8BIT, 128, }, | 505 | PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_8BIT, 128, }, |
507 | {"3c575 Boomerang CardBus", | 506 | {"3c575 Boomerang CardBus", |
508 | PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_8BIT, 128, }, | 507 | PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_8BIT, 128, }, |
509 | {"3CCFE575BT Cyclone CardBus", | 508 | {"3CCFE575BT Cyclone CardBus", |
510 | PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT| | 509 | PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT| |
511 | INVERT_LED_PWR|HAS_HWCKSM, 128, }, | 510 | INVERT_LED_PWR|HAS_HWCKSM, 128, }, |
512 | {"3CCFE575CT Tornado CardBus", | 511 | {"3CCFE575CT Tornado CardBus", |
513 | PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR| | 512 | PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR| |
514 | MAX_COLLISION_RESET|HAS_HWCKSM, 128, }, | 513 | MAX_COLLISION_RESET|HAS_HWCKSM, 128, }, |
515 | {"3CCFE656 Cyclone CardBus", | 514 | {"3CCFE656 Cyclone CardBus", |
516 | PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR| | 515 | PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR| |
517 | INVERT_LED_PWR|HAS_HWCKSM, 128, }, | 516 | INVERT_LED_PWR|HAS_HWCKSM, 128, }, |
518 | 517 | ||
519 | {"3CCFEM656B Cyclone+Winmodem CardBus", | 518 | {"3CCFEM656B Cyclone+Winmodem CardBus", |
520 | PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR| | 519 | PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR| |
521 | INVERT_LED_PWR|HAS_HWCKSM, 128, }, | 520 | INVERT_LED_PWR|HAS_HWCKSM, 128, }, |
522 | {"3CXFEM656C Tornado+Winmodem CardBus", /* From pcmcia-cs-3.1.5 */ | 521 | {"3CXFEM656C Tornado+Winmodem CardBus", /* From pcmcia-cs-3.1.5 */ |
523 | PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR| | 522 | PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR| |
524 | MAX_COLLISION_RESET|HAS_HWCKSM, 128, }, | 523 | MAX_COLLISION_RESET|HAS_HWCKSM, 128, }, |
525 | {"3c450 HomePNA Tornado", /* AKPM: from Don's 0.99Q */ | 524 | {"3c450 HomePNA Tornado", /* AKPM: from Don's 0.99Q */ |
526 | PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, }, | 525 | PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, }, |
527 | {"3c920 Tornado", | 526 | {"3c920 Tornado", |
528 | PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, }, | 527 | PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, }, |
529 | {"3c982 Hydra Dual Port A", | 528 | {"3c982 Hydra Dual Port A", |
530 | PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_HWCKSM|HAS_NWAY, 128, }, | 529 | PCI_USES_MASTER, IS_TORNADO|HAS_HWCKSM|HAS_NWAY, 128, }, |
531 | 530 | ||
532 | {"3c982 Hydra Dual Port B", | 531 | {"3c982 Hydra Dual Port B", |
533 | PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_HWCKSM|HAS_NWAY, 128, }, | 532 | PCI_USES_MASTER, IS_TORNADO|HAS_HWCKSM|HAS_NWAY, 128, }, |
534 | {"3c905B-T4", | 533 | {"3c905B-T4", |
535 | PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM|EXTRA_PREAMBLE, 128, }, | 534 | PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM|EXTRA_PREAMBLE, 128, }, |
536 | {"3c920B-EMB-WNM Tornado", | 535 | {"3c920B-EMB-WNM Tornado", |
537 | PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, }, | 536 | PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, }, |
538 | 537 | ||
539 | {NULL,}, /* NULL terminated list. */ | 538 | {NULL,}, /* NULL terminated list. */ |
540 | }; | 539 | }; |
diff --git a/drivers/net/dl2k.h b/drivers/net/dl2k.h index 6e75482d75f2..53449207e53b 100644 --- a/drivers/net/dl2k.h +++ b/drivers/net/dl2k.h | |||
@@ -683,11 +683,6 @@ struct netdev_private { | |||
683 | }; | 683 | }; |
684 | 684 | ||
685 | /* The station address location in the EEPROM. */ | 685 | /* The station address location in the EEPROM. */ |
686 | #ifdef MEM_MAPPING | ||
687 | #define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR1) | ||
688 | #else | ||
689 | #define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_IO | PCI_ADDR0) | ||
690 | #endif | ||
691 | /* The struct pci_device_id consist of: | 686 | /* The struct pci_device_id consist of: |
692 | vendor, device Vendor and device ID to match (or PCI_ANY_ID) | 687 | vendor, device Vendor and device ID to match (or PCI_ANY_ID) |
693 | subvendor, subdevice Subsystem vendor and device ID to match (or PCI_ANY_ID) | 688 | subvendor, subdevice Subsystem vendor and device ID to match (or PCI_ANY_ID) |
@@ -695,9 +690,10 @@ struct netdev_private { | |||
695 | class_mask of the class are honored during the comparison. | 690 | class_mask of the class are honored during the comparison. |
696 | driver_data Data private to the driver. | 691 | driver_data Data private to the driver. |
697 | */ | 692 | */ |
698 | static struct pci_device_id rio_pci_tbl[] = { | 693 | |
699 | {0x1186, 0x4000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | 694 | static const struct pci_device_id rio_pci_tbl[] = { |
700 | {0,} | 695 | {0x1186, 0x4000, PCI_ANY_ID, PCI_ANY_ID, }, |
696 | { } | ||
701 | }; | 697 | }; |
702 | MODULE_DEVICE_TABLE (pci, rio_pci_tbl); | 698 | MODULE_DEVICE_TABLE (pci, rio_pci_tbl); |
703 | #define TX_TIMEOUT (4*HZ) | 699 | #define TX_TIMEOUT (4*HZ) |
diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index 24996da4c1c4..7965a9b08e79 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c | |||
@@ -410,10 +410,7 @@ dm9000_probe(struct platform_device *pdev) | |||
410 | if (pdev->num_resources < 2) { | 410 | if (pdev->num_resources < 2) { |
411 | ret = -ENODEV; | 411 | ret = -ENODEV; |
412 | goto out; | 412 | goto out; |
413 | } | 413 | } else if (pdev->num_resources == 2) { |
414 | |||
415 | switch (pdev->num_resources) { | ||
416 | case 2: | ||
417 | base = pdev->resource[0].start; | 414 | base = pdev->resource[0].start; |
418 | 415 | ||
419 | if (!request_mem_region(base, 4, ndev->name)) { | 416 | if (!request_mem_region(base, 4, ndev->name)) { |
@@ -423,17 +420,16 @@ dm9000_probe(struct platform_device *pdev) | |||
423 | 420 | ||
424 | ndev->base_addr = base; | 421 | ndev->base_addr = base; |
425 | ndev->irq = pdev->resource[1].start; | 422 | ndev->irq = pdev->resource[1].start; |
426 | db->io_addr = (void *)base; | 423 | db->io_addr = (void __iomem *)base; |
427 | db->io_data = (void *)(base + 4); | 424 | db->io_data = (void __iomem *)(base + 4); |
428 | |||
429 | break; | ||
430 | 425 | ||
431 | case 3: | 426 | } else { |
432 | db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 427 | db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
433 | db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); | 428 | db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); |
434 | db->irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | 429 | db->irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); |
435 | 430 | ||
436 | if (db->addr_res == NULL || db->data_res == NULL) { | 431 | if (db->addr_res == NULL || db->data_res == NULL || |
432 | db->irq_res == NULL) { | ||
437 | printk(KERN_ERR PFX "insufficient resources\n"); | 433 | printk(KERN_ERR PFX "insufficient resources\n"); |
438 | ret = -ENOENT; | 434 | ret = -ENOENT; |
439 | goto out; | 435 | goto out; |
@@ -482,7 +478,6 @@ dm9000_probe(struct platform_device *pdev) | |||
482 | 478 | ||
483 | /* ensure at least we have a default set of IO routines */ | 479 | /* ensure at least we have a default set of IO routines */ |
484 | dm9000_set_io(db, iosize); | 480 | dm9000_set_io(db, iosize); |
485 | |||
486 | } | 481 | } |
487 | 482 | ||
488 | /* check to see if anything is being over-ridden */ | 483 | /* check to see if anything is being over-ridden */ |
@@ -564,6 +559,13 @@ dm9000_probe(struct platform_device *pdev) | |||
564 | for (i = 0; i < 6; i++) | 559 | for (i = 0; i < 6; i++) |
565 | ndev->dev_addr[i] = db->srom[i]; | 560 | ndev->dev_addr[i] = db->srom[i]; |
566 | 561 | ||
562 | if (!is_valid_ether_addr(ndev->dev_addr)) { | ||
563 | /* try reading from mac */ | ||
564 | |||
565 | for (i = 0; i < 6; i++) | ||
566 | ndev->dev_addr[i] = ior(db, i+DM9000_PAR); | ||
567 | } | ||
568 | |||
567 | if (!is_valid_ether_addr(ndev->dev_addr)) | 569 | if (!is_valid_ether_addr(ndev->dev_addr)) |
568 | printk("%s: Invalid ethernet MAC address. Please " | 570 | printk("%s: Invalid ethernet MAC address. Please " |
569 | "set using ifconfig\n", ndev->name); | 571 | "set using ifconfig\n", ndev->name); |
@@ -663,7 +665,6 @@ dm9000_init_dm9000(struct net_device *dev) | |||
663 | db->tx_pkt_cnt = 0; | 665 | db->tx_pkt_cnt = 0; |
664 | db->queue_pkt_len = 0; | 666 | db->queue_pkt_len = 0; |
665 | dev->trans_start = 0; | 667 | dev->trans_start = 0; |
666 | spin_lock_init(&db->lock); | ||
667 | } | 668 | } |
668 | 669 | ||
669 | /* | 670 | /* |
@@ -767,7 +768,7 @@ dm9000_stop(struct net_device *ndev) | |||
767 | * receive the packet to upper layer, free the transmitted packet | 768 | * receive the packet to upper layer, free the transmitted packet |
768 | */ | 769 | */ |
769 | 770 | ||
770 | void | 771 | static void |
771 | dm9000_tx_done(struct net_device *dev, board_info_t * db) | 772 | dm9000_tx_done(struct net_device *dev, board_info_t * db) |
772 | { | 773 | { |
773 | int tx_status = ior(db, DM9000_NSR); /* Got TX status */ | 774 | int tx_status = ior(db, DM9000_NSR); /* Got TX status */ |
@@ -1187,13 +1188,14 @@ dm9000_drv_remove(struct platform_device *pdev) | |||
1187 | } | 1188 | } |
1188 | 1189 | ||
1189 | static struct platform_driver dm9000_driver = { | 1190 | static struct platform_driver dm9000_driver = { |
1191 | .driver = { | ||
1192 | .name = "dm9000", | ||
1193 | .owner = THIS_MODULE, | ||
1194 | }, | ||
1190 | .probe = dm9000_probe, | 1195 | .probe = dm9000_probe, |
1191 | .remove = dm9000_drv_remove, | 1196 | .remove = dm9000_drv_remove, |
1192 | .suspend = dm9000_drv_suspend, | 1197 | .suspend = dm9000_drv_suspend, |
1193 | .resume = dm9000_drv_resume, | 1198 | .resume = dm9000_drv_resume, |
1194 | .driver = { | ||
1195 | .name = "dm9000", | ||
1196 | }, | ||
1197 | }; | 1199 | }; |
1198 | 1200 | ||
1199 | static int __init | 1201 | static int __init |
diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c index 467fc861360d..ecf5ad85a684 100644 --- a/drivers/net/eepro100.c +++ b/drivers/net/eepro100.c | |||
@@ -278,11 +278,6 @@ having to sign an Intel NDA when I'm helping Intel sell their own product! | |||
278 | 278 | ||
279 | static int speedo_found1(struct pci_dev *pdev, void __iomem *ioaddr, int fnd_cnt, int acpi_idle_state); | 279 | static int speedo_found1(struct pci_dev *pdev, void __iomem *ioaddr, int fnd_cnt, int acpi_idle_state); |
280 | 280 | ||
281 | enum pci_flags_bit { | ||
282 | PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4, | ||
283 | PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3, | ||
284 | }; | ||
285 | |||
286 | /* Offsets to the various registers. | 281 | /* Offsets to the various registers. |
287 | All accesses need not be longword aligned. */ | 282 | All accesses need not be longword aligned. */ |
288 | enum speedo_offsets { | 283 | enum speedo_offsets { |
diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c index 724d7dc35fa3..ee34a16eb4e2 100644 --- a/drivers/net/epic100.c +++ b/drivers/net/epic100.c | |||
@@ -191,23 +191,10 @@ IVc. Errata | |||
191 | */ | 191 | */ |
192 | 192 | ||
193 | 193 | ||
194 | enum pci_id_flags_bits { | ||
195 | /* Set PCI command register bits before calling probe1(). */ | ||
196 | PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4, | ||
197 | /* Read and map the single following PCI BAR. */ | ||
198 | PCI_ADDR0=0<<4, PCI_ADDR1=1<<4, PCI_ADDR2=2<<4, PCI_ADDR3=3<<4, | ||
199 | PCI_ADDR_64BITS=0x100, PCI_NO_ACPI_WAKE=0x200, PCI_NO_MIN_LATENCY=0x400, | ||
200 | }; | ||
201 | |||
202 | enum chip_capability_flags { MII_PWRDWN=1, TYPE2_INTR=2, NO_MII=4 }; | 194 | enum chip_capability_flags { MII_PWRDWN=1, TYPE2_INTR=2, NO_MII=4 }; |
203 | 195 | ||
204 | #define EPIC_TOTAL_SIZE 0x100 | 196 | #define EPIC_TOTAL_SIZE 0x100 |
205 | #define USE_IO_OPS 1 | 197 | #define USE_IO_OPS 1 |
206 | #ifdef USE_IO_OPS | ||
207 | #define EPIC_IOTYPE PCI_USES_MASTER|PCI_USES_IO|PCI_ADDR0 | ||
208 | #else | ||
209 | #define EPIC_IOTYPE PCI_USES_MASTER|PCI_USES_MEM|PCI_ADDR1 | ||
210 | #endif | ||
211 | 198 | ||
212 | typedef enum { | 199 | typedef enum { |
213 | SMSC_83C170_0, | 200 | SMSC_83C170_0, |
@@ -218,7 +205,6 @@ typedef enum { | |||
218 | 205 | ||
219 | struct epic_chip_info { | 206 | struct epic_chip_info { |
220 | const char *name; | 207 | const char *name; |
221 | enum pci_id_flags_bits pci_flags; | ||
222 | int io_size; /* Needed for I/O region check or ioremap(). */ | 208 | int io_size; /* Needed for I/O region check or ioremap(). */ |
223 | int drv_flags; /* Driver use, intended as capability flags. */ | 209 | int drv_flags; /* Driver use, intended as capability flags. */ |
224 | }; | 210 | }; |
@@ -227,11 +213,11 @@ struct epic_chip_info { | |||
227 | /* indexed by chip_t */ | 213 | /* indexed by chip_t */ |
228 | static const struct epic_chip_info pci_id_tbl[] = { | 214 | static const struct epic_chip_info pci_id_tbl[] = { |
229 | { "SMSC EPIC/100 83c170", | 215 | { "SMSC EPIC/100 83c170", |
230 | EPIC_IOTYPE, EPIC_TOTAL_SIZE, TYPE2_INTR | NO_MII | MII_PWRDWN }, | 216 | EPIC_TOTAL_SIZE, TYPE2_INTR | NO_MII | MII_PWRDWN }, |
231 | { "SMSC EPIC/100 83c170", | 217 | { "SMSC EPIC/100 83c170", |
232 | EPIC_IOTYPE, EPIC_TOTAL_SIZE, TYPE2_INTR }, | 218 | EPIC_TOTAL_SIZE, TYPE2_INTR }, |
233 | { "SMSC EPIC/C 83c175", | 219 | { "SMSC EPIC/C 83c175", |
234 | EPIC_IOTYPE, EPIC_TOTAL_SIZE, TYPE2_INTR | MII_PWRDWN }, | 220 | EPIC_TOTAL_SIZE, TYPE2_INTR | MII_PWRDWN }, |
235 | }; | 221 | }; |
236 | 222 | ||
237 | 223 | ||
diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c index a8449265e5fd..13eca7ede2af 100644 --- a/drivers/net/fealnx.c +++ b/drivers/net/fealnx.c | |||
@@ -126,16 +126,6 @@ MODULE_PARM_DESC(full_duplex, "fealnx full duplex setting(s) (1)"); | |||
126 | 126 | ||
127 | #define MIN_REGION_SIZE 136 | 127 | #define MIN_REGION_SIZE 136 |
128 | 128 | ||
129 | enum pci_flags_bit { | ||
130 | PCI_USES_IO = 1, | ||
131 | PCI_USES_MEM = 2, | ||
132 | PCI_USES_MASTER = 4, | ||
133 | PCI_ADDR0 = 0x10 << 0, | ||
134 | PCI_ADDR1 = 0x10 << 1, | ||
135 | PCI_ADDR2 = 0x10 << 2, | ||
136 | PCI_ADDR3 = 0x10 << 3, | ||
137 | }; | ||
138 | |||
139 | /* A chip capabilities table, matching the entries in pci_tbl[] above. */ | 129 | /* A chip capabilities table, matching the entries in pci_tbl[] above. */ |
140 | enum chip_capability_flags { | 130 | enum chip_capability_flags { |
141 | HAS_MII_XCVR, | 131 | HAS_MII_XCVR, |
diff --git a/drivers/net/fec.c b/drivers/net/fec.c index bd6983d1afba..db694c832989 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c | |||
@@ -22,7 +22,7 @@ | |||
22 | * Copyright (c) 2001-2005 Greg Ungerer (gerg@snapgear.com) | 22 | * Copyright (c) 2001-2005 Greg Ungerer (gerg@snapgear.com) |
23 | * | 23 | * |
24 | * Bug fixes and cleanup by Philippe De Muyter (phdm@macqel.be) | 24 | * Bug fixes and cleanup by Philippe De Muyter (phdm@macqel.be) |
25 | * Copyright (c) 2004-2005 Macq Electronique SA. | 25 | * Copyright (c) 2004-2006 Macq Electronique SA. |
26 | */ | 26 | */ |
27 | 27 | ||
28 | #include <linux/config.h> | 28 | #include <linux/config.h> |
@@ -51,7 +51,7 @@ | |||
51 | 51 | ||
52 | #if defined(CONFIG_M523x) || defined(CONFIG_M527x) || \ | 52 | #if defined(CONFIG_M523x) || defined(CONFIG_M527x) || \ |
53 | defined(CONFIG_M5272) || defined(CONFIG_M528x) || \ | 53 | defined(CONFIG_M5272) || defined(CONFIG_M528x) || \ |
54 | defined(CONFIG_M520x) | 54 | defined(CONFIG_M520x) || defined(CONFIG_M532x) |
55 | #include <asm/coldfire.h> | 55 | #include <asm/coldfire.h> |
56 | #include <asm/mcfsim.h> | 56 | #include <asm/mcfsim.h> |
57 | #include "fec.h" | 57 | #include "fec.h" |
@@ -80,6 +80,8 @@ static unsigned int fec_hw[] = { | |||
80 | (MCF_MBAR + 0x1000), | 80 | (MCF_MBAR + 0x1000), |
81 | #elif defined(CONFIG_M520x) | 81 | #elif defined(CONFIG_M520x) |
82 | (MCF_MBAR+0x30000), | 82 | (MCF_MBAR+0x30000), |
83 | #elif defined(CONFIG_M532x) | ||
84 | (MCF_MBAR+0xfc030000), | ||
83 | #else | 85 | #else |
84 | &(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec), | 86 | &(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec), |
85 | #endif | 87 | #endif |
@@ -143,7 +145,7 @@ typedef struct { | |||
143 | #define TX_RING_MOD_MASK 15 /* for this to work */ | 145 | #define TX_RING_MOD_MASK 15 /* for this to work */ |
144 | 146 | ||
145 | #if (((RX_RING_SIZE + TX_RING_SIZE) * 8) > PAGE_SIZE) | 147 | #if (((RX_RING_SIZE + TX_RING_SIZE) * 8) > PAGE_SIZE) |
146 | #error "FEC: descriptor ring size contants too large" | 148 | #error "FEC: descriptor ring size constants too large" |
147 | #endif | 149 | #endif |
148 | 150 | ||
149 | /* Interrupt events/masks. | 151 | /* Interrupt events/masks. |
@@ -167,12 +169,12 @@ typedef struct { | |||
167 | 169 | ||
168 | 170 | ||
169 | /* | 171 | /* |
170 | * The 5270/5271/5280/5282 RX control register also contains maximum frame | 172 | * The 5270/5271/5280/5282/532x RX control register also contains maximum frame |
171 | * size bits. Other FEC hardware does not, so we need to take that into | 173 | * size bits. Other FEC hardware does not, so we need to take that into |
172 | * account when setting it. | 174 | * account when setting it. |
173 | */ | 175 | */ |
174 | #if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \ | 176 | #if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \ |
175 | defined(CONFIG_M520x) | 177 | defined(CONFIG_M520x) || defined(CONFIG_M532x) |
176 | #define OPT_FRAME_SIZE (PKT_MAXBUF_SIZE << 16) | 178 | #define OPT_FRAME_SIZE (PKT_MAXBUF_SIZE << 16) |
177 | #else | 179 | #else |
178 | #define OPT_FRAME_SIZE 0 | 180 | #define OPT_FRAME_SIZE 0 |
@@ -308,6 +310,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
308 | struct fec_enet_private *fep; | 310 | struct fec_enet_private *fep; |
309 | volatile fec_t *fecp; | 311 | volatile fec_t *fecp; |
310 | volatile cbd_t *bdp; | 312 | volatile cbd_t *bdp; |
313 | unsigned short status; | ||
311 | 314 | ||
312 | fep = netdev_priv(dev); | 315 | fep = netdev_priv(dev); |
313 | fecp = (volatile fec_t*)dev->base_addr; | 316 | fecp = (volatile fec_t*)dev->base_addr; |
@@ -320,8 +323,9 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
320 | /* Fill in a Tx ring entry */ | 323 | /* Fill in a Tx ring entry */ |
321 | bdp = fep->cur_tx; | 324 | bdp = fep->cur_tx; |
322 | 325 | ||
326 | status = bdp->cbd_sc; | ||
323 | #ifndef final_version | 327 | #ifndef final_version |
324 | if (bdp->cbd_sc & BD_ENET_TX_READY) { | 328 | if (status & BD_ENET_TX_READY) { |
325 | /* Ooops. All transmit buffers are full. Bail out. | 329 | /* Ooops. All transmit buffers are full. Bail out. |
326 | * This should not happen, since dev->tbusy should be set. | 330 | * This should not happen, since dev->tbusy should be set. |
327 | */ | 331 | */ |
@@ -332,7 +336,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
332 | 336 | ||
333 | /* Clear all of the status flags. | 337 | /* Clear all of the status flags. |
334 | */ | 338 | */ |
335 | bdp->cbd_sc &= ~BD_ENET_TX_STATS; | 339 | status &= ~BD_ENET_TX_STATS; |
336 | 340 | ||
337 | /* Set buffer length and buffer pointer. | 341 | /* Set buffer length and buffer pointer. |
338 | */ | 342 | */ |
@@ -366,21 +370,22 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
366 | 370 | ||
367 | spin_lock_irq(&fep->lock); | 371 | spin_lock_irq(&fep->lock); |
368 | 372 | ||
369 | /* Send it on its way. Tell FEC its ready, interrupt when done, | 373 | /* Send it on its way. Tell FEC it's ready, interrupt when done, |
370 | * its the last BD of the frame, and to put the CRC on the end. | 374 | * it's the last BD of the frame, and to put the CRC on the end. |
371 | */ | 375 | */ |
372 | 376 | ||
373 | bdp->cbd_sc |= (BD_ENET_TX_READY | BD_ENET_TX_INTR | 377 | status |= (BD_ENET_TX_READY | BD_ENET_TX_INTR |
374 | | BD_ENET_TX_LAST | BD_ENET_TX_TC); | 378 | | BD_ENET_TX_LAST | BD_ENET_TX_TC); |
379 | bdp->cbd_sc = status; | ||
375 | 380 | ||
376 | dev->trans_start = jiffies; | 381 | dev->trans_start = jiffies; |
377 | 382 | ||
378 | /* Trigger transmission start */ | 383 | /* Trigger transmission start */ |
379 | fecp->fec_x_des_active = 0x01000000; | 384 | fecp->fec_x_des_active = 0; |
380 | 385 | ||
381 | /* If this was the last BD in the ring, start at the beginning again. | 386 | /* If this was the last BD in the ring, start at the beginning again. |
382 | */ | 387 | */ |
383 | if (bdp->cbd_sc & BD_ENET_TX_WRAP) { | 388 | if (status & BD_ENET_TX_WRAP) { |
384 | bdp = fep->tx_bd_base; | 389 | bdp = fep->tx_bd_base; |
385 | } else { | 390 | } else { |
386 | bdp++; | 391 | bdp++; |
@@ -491,43 +496,44 @@ fec_enet_tx(struct net_device *dev) | |||
491 | { | 496 | { |
492 | struct fec_enet_private *fep; | 497 | struct fec_enet_private *fep; |
493 | volatile cbd_t *bdp; | 498 | volatile cbd_t *bdp; |
499 | unsigned short status; | ||
494 | struct sk_buff *skb; | 500 | struct sk_buff *skb; |
495 | 501 | ||
496 | fep = netdev_priv(dev); | 502 | fep = netdev_priv(dev); |
497 | spin_lock(&fep->lock); | 503 | spin_lock(&fep->lock); |
498 | bdp = fep->dirty_tx; | 504 | bdp = fep->dirty_tx; |
499 | 505 | ||
500 | while ((bdp->cbd_sc&BD_ENET_TX_READY) == 0) { | 506 | while (((status = bdp->cbd_sc) & BD_ENET_TX_READY) == 0) { |
501 | if (bdp == fep->cur_tx && fep->tx_full == 0) break; | 507 | if (bdp == fep->cur_tx && fep->tx_full == 0) break; |
502 | 508 | ||
503 | skb = fep->tx_skbuff[fep->skb_dirty]; | 509 | skb = fep->tx_skbuff[fep->skb_dirty]; |
504 | /* Check for errors. */ | 510 | /* Check for errors. */ |
505 | if (bdp->cbd_sc & (BD_ENET_TX_HB | BD_ENET_TX_LC | | 511 | if (status & (BD_ENET_TX_HB | BD_ENET_TX_LC | |
506 | BD_ENET_TX_RL | BD_ENET_TX_UN | | 512 | BD_ENET_TX_RL | BD_ENET_TX_UN | |
507 | BD_ENET_TX_CSL)) { | 513 | BD_ENET_TX_CSL)) { |
508 | fep->stats.tx_errors++; | 514 | fep->stats.tx_errors++; |
509 | if (bdp->cbd_sc & BD_ENET_TX_HB) /* No heartbeat */ | 515 | if (status & BD_ENET_TX_HB) /* No heartbeat */ |
510 | fep->stats.tx_heartbeat_errors++; | 516 | fep->stats.tx_heartbeat_errors++; |
511 | if (bdp->cbd_sc & BD_ENET_TX_LC) /* Late collision */ | 517 | if (status & BD_ENET_TX_LC) /* Late collision */ |
512 | fep->stats.tx_window_errors++; | 518 | fep->stats.tx_window_errors++; |
513 | if (bdp->cbd_sc & BD_ENET_TX_RL) /* Retrans limit */ | 519 | if (status & BD_ENET_TX_RL) /* Retrans limit */ |
514 | fep->stats.tx_aborted_errors++; | 520 | fep->stats.tx_aborted_errors++; |
515 | if (bdp->cbd_sc & BD_ENET_TX_UN) /* Underrun */ | 521 | if (status & BD_ENET_TX_UN) /* Underrun */ |
516 | fep->stats.tx_fifo_errors++; | 522 | fep->stats.tx_fifo_errors++; |
517 | if (bdp->cbd_sc & BD_ENET_TX_CSL) /* Carrier lost */ | 523 | if (status & BD_ENET_TX_CSL) /* Carrier lost */ |
518 | fep->stats.tx_carrier_errors++; | 524 | fep->stats.tx_carrier_errors++; |
519 | } else { | 525 | } else { |
520 | fep->stats.tx_packets++; | 526 | fep->stats.tx_packets++; |
521 | } | 527 | } |
522 | 528 | ||
523 | #ifndef final_version | 529 | #ifndef final_version |
524 | if (bdp->cbd_sc & BD_ENET_TX_READY) | 530 | if (status & BD_ENET_TX_READY) |
525 | printk("HEY! Enet xmit interrupt and TX_READY.\n"); | 531 | printk("HEY! Enet xmit interrupt and TX_READY.\n"); |
526 | #endif | 532 | #endif |
527 | /* Deferred means some collisions occurred during transmit, | 533 | /* Deferred means some collisions occurred during transmit, |
528 | * but we eventually sent the packet OK. | 534 | * but we eventually sent the packet OK. |
529 | */ | 535 | */ |
530 | if (bdp->cbd_sc & BD_ENET_TX_DEF) | 536 | if (status & BD_ENET_TX_DEF) |
531 | fep->stats.collisions++; | 537 | fep->stats.collisions++; |
532 | 538 | ||
533 | /* Free the sk buffer associated with this last transmit. | 539 | /* Free the sk buffer associated with this last transmit. |
@@ -538,7 +544,7 @@ fec_enet_tx(struct net_device *dev) | |||
538 | 544 | ||
539 | /* Update pointer to next buffer descriptor to be transmitted. | 545 | /* Update pointer to next buffer descriptor to be transmitted. |
540 | */ | 546 | */ |
541 | if (bdp->cbd_sc & BD_ENET_TX_WRAP) | 547 | if (status & BD_ENET_TX_WRAP) |
542 | bdp = fep->tx_bd_base; | 548 | bdp = fep->tx_bd_base; |
543 | else | 549 | else |
544 | bdp++; | 550 | bdp++; |
@@ -568,9 +574,14 @@ fec_enet_rx(struct net_device *dev) | |||
568 | struct fec_enet_private *fep; | 574 | struct fec_enet_private *fep; |
569 | volatile fec_t *fecp; | 575 | volatile fec_t *fecp; |
570 | volatile cbd_t *bdp; | 576 | volatile cbd_t *bdp; |
577 | unsigned short status; | ||
571 | struct sk_buff *skb; | 578 | struct sk_buff *skb; |
572 | ushort pkt_len; | 579 | ushort pkt_len; |
573 | __u8 *data; | 580 | __u8 *data; |
581 | |||
582 | #ifdef CONFIG_M532x | ||
583 | flush_cache_all(); | ||
584 | #endif | ||
574 | 585 | ||
575 | fep = netdev_priv(dev); | 586 | fep = netdev_priv(dev); |
576 | fecp = (volatile fec_t*)dev->base_addr; | 587 | fecp = (volatile fec_t*)dev->base_addr; |
@@ -580,13 +591,13 @@ fec_enet_rx(struct net_device *dev) | |||
580 | */ | 591 | */ |
581 | bdp = fep->cur_rx; | 592 | bdp = fep->cur_rx; |
582 | 593 | ||
583 | while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) { | 594 | while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) { |
584 | 595 | ||
585 | #ifndef final_version | 596 | #ifndef final_version |
586 | /* Since we have allocated space to hold a complete frame, | 597 | /* Since we have allocated space to hold a complete frame, |
587 | * the last indicator should be set. | 598 | * the last indicator should be set. |
588 | */ | 599 | */ |
589 | if ((bdp->cbd_sc & BD_ENET_RX_LAST) == 0) | 600 | if ((status & BD_ENET_RX_LAST) == 0) |
590 | printk("FEC ENET: rcv is not +last\n"); | 601 | printk("FEC ENET: rcv is not +last\n"); |
591 | #endif | 602 | #endif |
592 | 603 | ||
@@ -594,26 +605,26 @@ while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) { | |||
594 | goto rx_processing_done; | 605 | goto rx_processing_done; |
595 | 606 | ||
596 | /* Check for errors. */ | 607 | /* Check for errors. */ |
597 | if (bdp->cbd_sc & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO | | 608 | if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO | |
598 | BD_ENET_RX_CR | BD_ENET_RX_OV)) { | 609 | BD_ENET_RX_CR | BD_ENET_RX_OV)) { |
599 | fep->stats.rx_errors++; | 610 | fep->stats.rx_errors++; |
600 | if (bdp->cbd_sc & (BD_ENET_RX_LG | BD_ENET_RX_SH)) { | 611 | if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH)) { |
601 | /* Frame too long or too short. */ | 612 | /* Frame too long or too short. */ |
602 | fep->stats.rx_length_errors++; | 613 | fep->stats.rx_length_errors++; |
603 | } | 614 | } |
604 | if (bdp->cbd_sc & BD_ENET_RX_NO) /* Frame alignment */ | 615 | if (status & BD_ENET_RX_NO) /* Frame alignment */ |
605 | fep->stats.rx_frame_errors++; | 616 | fep->stats.rx_frame_errors++; |
606 | if (bdp->cbd_sc & BD_ENET_RX_CR) /* CRC Error */ | 617 | if (status & BD_ENET_RX_CR) /* CRC Error */ |
607 | fep->stats.rx_crc_errors++; | ||
608 | if (bdp->cbd_sc & BD_ENET_RX_OV) /* FIFO overrun */ | ||
609 | fep->stats.rx_crc_errors++; | 618 | fep->stats.rx_crc_errors++; |
619 | if (status & BD_ENET_RX_OV) /* FIFO overrun */ | ||
620 | fep->stats.rx_fifo_errors++; | ||
610 | } | 621 | } |
611 | 622 | ||
612 | /* Report late collisions as a frame error. | 623 | /* Report late collisions as a frame error. |
613 | * On this error, the BD is closed, but we don't know what we | 624 | * On this error, the BD is closed, but we don't know what we |
614 | * have in the buffer. So, just drop this frame on the floor. | 625 | * have in the buffer. So, just drop this frame on the floor. |
615 | */ | 626 | */ |
616 | if (bdp->cbd_sc & BD_ENET_RX_CL) { | 627 | if (status & BD_ENET_RX_CL) { |
617 | fep->stats.rx_errors++; | 628 | fep->stats.rx_errors++; |
618 | fep->stats.rx_frame_errors++; | 629 | fep->stats.rx_frame_errors++; |
619 | goto rx_processing_done; | 630 | goto rx_processing_done; |
@@ -639,9 +650,7 @@ while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) { | |||
639 | } else { | 650 | } else { |
640 | skb->dev = dev; | 651 | skb->dev = dev; |
641 | skb_put(skb,pkt_len-4); /* Make room */ | 652 | skb_put(skb,pkt_len-4); /* Make room */ |
642 | eth_copy_and_sum(skb, | 653 | eth_copy_and_sum(skb, data, pkt_len-4, 0); |
643 | (unsigned char *)__va(bdp->cbd_bufaddr), | ||
644 | pkt_len-4, 0); | ||
645 | skb->protocol=eth_type_trans(skb,dev); | 654 | skb->protocol=eth_type_trans(skb,dev); |
646 | netif_rx(skb); | 655 | netif_rx(skb); |
647 | } | 656 | } |
@@ -649,15 +658,16 @@ while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) { | |||
649 | 658 | ||
650 | /* Clear the status flags for this buffer. | 659 | /* Clear the status flags for this buffer. |
651 | */ | 660 | */ |
652 | bdp->cbd_sc &= ~BD_ENET_RX_STATS; | 661 | status &= ~BD_ENET_RX_STATS; |
653 | 662 | ||
654 | /* Mark the buffer empty. | 663 | /* Mark the buffer empty. |
655 | */ | 664 | */ |
656 | bdp->cbd_sc |= BD_ENET_RX_EMPTY; | 665 | status |= BD_ENET_RX_EMPTY; |
666 | bdp->cbd_sc = status; | ||
657 | 667 | ||
658 | /* Update BD pointer to next entry. | 668 | /* Update BD pointer to next entry. |
659 | */ | 669 | */ |
660 | if (bdp->cbd_sc & BD_ENET_RX_WRAP) | 670 | if (status & BD_ENET_RX_WRAP) |
661 | bdp = fep->rx_bd_base; | 671 | bdp = fep->rx_bd_base; |
662 | else | 672 | else |
663 | bdp++; | 673 | bdp++; |
@@ -667,9 +677,9 @@ while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) { | |||
667 | * incoming frames. On a heavily loaded network, we should be | 677 | * incoming frames. On a heavily loaded network, we should be |
668 | * able to keep up at the expense of system resources. | 678 | * able to keep up at the expense of system resources. |
669 | */ | 679 | */ |
670 | fecp->fec_r_des_active = 0x01000000; | 680 | fecp->fec_r_des_active = 0; |
671 | #endif | 681 | #endif |
672 | } /* while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) */ | 682 | } /* while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) */ |
673 | fep->cur_rx = (cbd_t *)bdp; | 683 | fep->cur_rx = (cbd_t *)bdp; |
674 | 684 | ||
675 | #if 0 | 685 | #if 0 |
@@ -680,11 +690,12 @@ while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) { | |||
680 | * our way back to the interrupt return only to come right back | 690 | * our way back to the interrupt return only to come right back |
681 | * here. | 691 | * here. |
682 | */ | 692 | */ |
683 | fecp->fec_r_des_active = 0x01000000; | 693 | fecp->fec_r_des_active = 0; |
684 | #endif | 694 | #endif |
685 | } | 695 | } |
686 | 696 | ||
687 | 697 | ||
698 | /* called from interrupt context */ | ||
688 | static void | 699 | static void |
689 | fec_enet_mii(struct net_device *dev) | 700 | fec_enet_mii(struct net_device *dev) |
690 | { | 701 | { |
@@ -696,10 +707,12 @@ fec_enet_mii(struct net_device *dev) | |||
696 | fep = netdev_priv(dev); | 707 | fep = netdev_priv(dev); |
697 | ep = fep->hwp; | 708 | ep = fep->hwp; |
698 | mii_reg = ep->fec_mii_data; | 709 | mii_reg = ep->fec_mii_data; |
710 | |||
711 | spin_lock(&fep->lock); | ||
699 | 712 | ||
700 | if ((mip = mii_head) == NULL) { | 713 | if ((mip = mii_head) == NULL) { |
701 | printk("MII and no head!\n"); | 714 | printk("MII and no head!\n"); |
702 | return; | 715 | goto unlock; |
703 | } | 716 | } |
704 | 717 | ||
705 | if (mip->mii_func != NULL) | 718 | if (mip->mii_func != NULL) |
@@ -711,6 +724,9 @@ fec_enet_mii(struct net_device *dev) | |||
711 | 724 | ||
712 | if ((mip = mii_head) != NULL) | 725 | if ((mip = mii_head) != NULL) |
713 | ep->fec_mii_data = mip->mii_regval; | 726 | ep->fec_mii_data = mip->mii_regval; |
727 | |||
728 | unlock: | ||
729 | spin_unlock(&fep->lock); | ||
714 | } | 730 | } |
715 | 731 | ||
716 | static int | 732 | static int |
@@ -728,8 +744,7 @@ mii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_devi | |||
728 | 744 | ||
729 | retval = 0; | 745 | retval = 0; |
730 | 746 | ||
731 | save_flags(flags); | 747 | spin_lock_irqsave(&fep->lock,flags); |
732 | cli(); | ||
733 | 748 | ||
734 | if ((mip = mii_free) != NULL) { | 749 | if ((mip = mii_free) != NULL) { |
735 | mii_free = mip->mii_next; | 750 | mii_free = mip->mii_next; |
@@ -749,7 +764,7 @@ mii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_devi | |||
749 | retval = 1; | 764 | retval = 1; |
750 | } | 765 | } |
751 | 766 | ||
752 | restore_flags(flags); | 767 | spin_unlock_irqrestore(&fep->lock,flags); |
753 | 768 | ||
754 | return(retval); | 769 | return(retval); |
755 | } | 770 | } |
@@ -1216,7 +1231,7 @@ static phy_info_t const * const phy_info[] = { | |||
1216 | }; | 1231 | }; |
1217 | 1232 | ||
1218 | /* ------------------------------------------------------------------------- */ | 1233 | /* ------------------------------------------------------------------------- */ |
1219 | 1234 | #if !defined(CONFIG_M532x) | |
1220 | #ifdef CONFIG_RPXCLASSIC | 1235 | #ifdef CONFIG_RPXCLASSIC |
1221 | static void | 1236 | static void |
1222 | mii_link_interrupt(void *dev_id); | 1237 | mii_link_interrupt(void *dev_id); |
@@ -1224,6 +1239,7 @@ mii_link_interrupt(void *dev_id); | |||
1224 | static irqreturn_t | 1239 | static irqreturn_t |
1225 | mii_link_interrupt(int irq, void * dev_id, struct pt_regs * regs); | 1240 | mii_link_interrupt(int irq, void * dev_id, struct pt_regs * regs); |
1226 | #endif | 1241 | #endif |
1242 | #endif | ||
1227 | 1243 | ||
1228 | #if defined(CONFIG_M5272) | 1244 | #if defined(CONFIG_M5272) |
1229 | 1245 | ||
@@ -1384,13 +1400,13 @@ static void __inline__ fec_request_intrs(struct net_device *dev) | |||
1384 | { | 1400 | { |
1385 | volatile unsigned char *icrp; | 1401 | volatile unsigned char *icrp; |
1386 | volatile unsigned long *imrp; | 1402 | volatile unsigned long *imrp; |
1387 | int i; | 1403 | int i, ilip; |
1388 | 1404 | ||
1389 | b = (fep->index) ? MCFICM_INTC1 : MCFICM_INTC0; | 1405 | b = (fep->index) ? MCFICM_INTC1 : MCFICM_INTC0; |
1390 | icrp = (volatile unsigned char *) (MCF_IPSBAR + b + | 1406 | icrp = (volatile unsigned char *) (MCF_IPSBAR + b + |
1391 | MCFINTC_ICR0); | 1407 | MCFINTC_ICR0); |
1392 | for (i = 23; (i < 36); i++) | 1408 | for (i = 23, ilip = 0x28; (i < 36); i++) |
1393 | icrp[i] = 0x23; | 1409 | icrp[i] = ilip--; |
1394 | 1410 | ||
1395 | imrp = (volatile unsigned long *) (MCF_IPSBAR + b + | 1411 | imrp = (volatile unsigned long *) (MCF_IPSBAR + b + |
1396 | MCFINTC_IMRH); | 1412 | MCFINTC_IMRH); |
@@ -1618,6 +1634,159 @@ static void __inline__ fec_uncache(unsigned long addr) | |||
1618 | 1634 | ||
1619 | /* ------------------------------------------------------------------------- */ | 1635 | /* ------------------------------------------------------------------------- */ |
1620 | 1636 | ||
1637 | #elif defined(CONFIG_M532x) | ||
1638 | /* | ||
1639 | * Code specific for M532x | ||
1640 | */ | ||
1641 | static void __inline__ fec_request_intrs(struct net_device *dev) | ||
1642 | { | ||
1643 | struct fec_enet_private *fep; | ||
1644 | int b; | ||
1645 | static const struct idesc { | ||
1646 | char *name; | ||
1647 | unsigned short irq; | ||
1648 | } *idp, id[] = { | ||
1649 | { "fec(TXF)", 36 }, | ||
1650 | { "fec(TXB)", 37 }, | ||
1651 | { "fec(TXFIFO)", 38 }, | ||
1652 | { "fec(TXCR)", 39 }, | ||
1653 | { "fec(RXF)", 40 }, | ||
1654 | { "fec(RXB)", 41 }, | ||
1655 | { "fec(MII)", 42 }, | ||
1656 | { "fec(LC)", 43 }, | ||
1657 | { "fec(HBERR)", 44 }, | ||
1658 | { "fec(GRA)", 45 }, | ||
1659 | { "fec(EBERR)", 46 }, | ||
1660 | { "fec(BABT)", 47 }, | ||
1661 | { "fec(BABR)", 48 }, | ||
1662 | { NULL }, | ||
1663 | }; | ||
1664 | |||
1665 | fep = netdev_priv(dev); | ||
1666 | b = (fep->index) ? 128 : 64; | ||
1667 | |||
1668 | /* Setup interrupt handlers. */ | ||
1669 | for (idp = id; idp->name; idp++) { | ||
1670 | if (request_irq(b+idp->irq,fec_enet_interrupt,0,idp->name,dev)!=0) | ||
1671 | printk("FEC: Could not allocate %s IRQ(%d)!\n", | ||
1672 | idp->name, b+idp->irq); | ||
1673 | } | ||
1674 | |||
1675 | /* Unmask interrupts */ | ||
1676 | MCF_INTC0_ICR36 = 0x2; | ||
1677 | MCF_INTC0_ICR37 = 0x2; | ||
1678 | MCF_INTC0_ICR38 = 0x2; | ||
1679 | MCF_INTC0_ICR39 = 0x2; | ||
1680 | MCF_INTC0_ICR40 = 0x2; | ||
1681 | MCF_INTC0_ICR41 = 0x2; | ||
1682 | MCF_INTC0_ICR42 = 0x2; | ||
1683 | MCF_INTC0_ICR43 = 0x2; | ||
1684 | MCF_INTC0_ICR44 = 0x2; | ||
1685 | MCF_INTC0_ICR45 = 0x2; | ||
1686 | MCF_INTC0_ICR46 = 0x2; | ||
1687 | MCF_INTC0_ICR47 = 0x2; | ||
1688 | MCF_INTC0_ICR48 = 0x2; | ||
1689 | |||
1690 | MCF_INTC0_IMRH &= ~( | ||
1691 | MCF_INTC_IMRH_INT_MASK36 | | ||
1692 | MCF_INTC_IMRH_INT_MASK37 | | ||
1693 | MCF_INTC_IMRH_INT_MASK38 | | ||
1694 | MCF_INTC_IMRH_INT_MASK39 | | ||
1695 | MCF_INTC_IMRH_INT_MASK40 | | ||
1696 | MCF_INTC_IMRH_INT_MASK41 | | ||
1697 | MCF_INTC_IMRH_INT_MASK42 | | ||
1698 | MCF_INTC_IMRH_INT_MASK43 | | ||
1699 | MCF_INTC_IMRH_INT_MASK44 | | ||
1700 | MCF_INTC_IMRH_INT_MASK45 | | ||
1701 | MCF_INTC_IMRH_INT_MASK46 | | ||
1702 | MCF_INTC_IMRH_INT_MASK47 | | ||
1703 | MCF_INTC_IMRH_INT_MASK48 ); | ||
1704 | |||
1705 | /* Set up gpio outputs for MII lines */ | ||
1706 | MCF_GPIO_PAR_FECI2C |= (0 | | ||
1707 | MCF_GPIO_PAR_FECI2C_PAR_MDC_EMDC | | ||
1708 | MCF_GPIO_PAR_FECI2C_PAR_MDIO_EMDIO); | ||
1709 | MCF_GPIO_PAR_FEC = (0 | | ||
1710 | MCF_GPIO_PAR_FEC_PAR_FEC_7W_FEC | | ||
1711 | MCF_GPIO_PAR_FEC_PAR_FEC_MII_FEC); | ||
1712 | } | ||
1713 | |||
1714 | static void __inline__ fec_set_mii(struct net_device *dev, struct fec_enet_private *fep) | ||
1715 | { | ||
1716 | volatile fec_t *fecp; | ||
1717 | |||
1718 | fecp = fep->hwp; | ||
1719 | fecp->fec_r_cntrl = OPT_FRAME_SIZE | 0x04; | ||
1720 | fecp->fec_x_cntrl = 0x00; | ||
1721 | |||
1722 | /* | ||
1723 | * Set MII speed to 2.5 MHz | ||
1724 | */ | ||
1725 | fep->phy_speed = ((((MCF_CLK / 2) / (2500000 / 10)) + 5) / 10) * 2; | ||
1726 | fecp->fec_mii_speed = fep->phy_speed; | ||
1727 | |||
1728 | fec_restart(dev, 0); | ||
1729 | } | ||
1730 | |||
1731 | static void __inline__ fec_get_mac(struct net_device *dev) | ||
1732 | { | ||
1733 | struct fec_enet_private *fep = netdev_priv(dev); | ||
1734 | volatile fec_t *fecp; | ||
1735 | unsigned char *iap, tmpaddr[ETH_ALEN]; | ||
1736 | |||
1737 | fecp = fep->hwp; | ||
1738 | |||
1739 | if (FEC_FLASHMAC) { | ||
1740 | /* | ||
1741 | * Get MAC address from FLASH. | ||
1742 | * If it is all 1's or 0's, use the default. | ||
1743 | */ | ||
1744 | iap = FEC_FLASHMAC; | ||
1745 | if ((iap[0] == 0) && (iap[1] == 0) && (iap[2] == 0) && | ||
1746 | (iap[3] == 0) && (iap[4] == 0) && (iap[5] == 0)) | ||
1747 | iap = fec_mac_default; | ||
1748 | if ((iap[0] == 0xff) && (iap[1] == 0xff) && (iap[2] == 0xff) && | ||
1749 | (iap[3] == 0xff) && (iap[4] == 0xff) && (iap[5] == 0xff)) | ||
1750 | iap = fec_mac_default; | ||
1751 | } else { | ||
1752 | *((unsigned long *) &tmpaddr[0]) = fecp->fec_addr_low; | ||
1753 | *((unsigned short *) &tmpaddr[4]) = (fecp->fec_addr_high >> 16); | ||
1754 | iap = &tmpaddr[0]; | ||
1755 | } | ||
1756 | |||
1757 | memcpy(dev->dev_addr, iap, ETH_ALEN); | ||
1758 | |||
1759 | /* Adjust MAC if using default MAC address */ | ||
1760 | if (iap == fec_mac_default) | ||
1761 | dev->dev_addr[ETH_ALEN-1] = fec_mac_default[ETH_ALEN-1] + fep->index; | ||
1762 | } | ||
1763 | |||
1764 | static void __inline__ fec_enable_phy_intr(void) | ||
1765 | { | ||
1766 | } | ||
1767 | |||
1768 | static void __inline__ fec_disable_phy_intr(void) | ||
1769 | { | ||
1770 | } | ||
1771 | |||
1772 | static void __inline__ fec_phy_ack_intr(void) | ||
1773 | { | ||
1774 | } | ||
1775 | |||
1776 | static void __inline__ fec_localhw_setup(void) | ||
1777 | { | ||
1778 | } | ||
1779 | |||
1780 | /* | ||
1781 | * Do not need to make region uncached on 532x. | ||
1782 | */ | ||
1783 | static void __inline__ fec_uncache(unsigned long addr) | ||
1784 | { | ||
1785 | } | ||
1786 | |||
1787 | /* ------------------------------------------------------------------------- */ | ||
1788 | |||
1789 | |||
1621 | #else | 1790 | #else |
1622 | 1791 | ||
1623 | /* | 1792 | /* |
@@ -1985,9 +2154,12 @@ fec_enet_open(struct net_device *dev) | |||
1985 | mii_do_cmd(dev, fep->phy->config); | 2154 | mii_do_cmd(dev, fep->phy->config); |
1986 | mii_do_cmd(dev, phy_cmd_config); /* display configuration */ | 2155 | mii_do_cmd(dev, phy_cmd_config); /* display configuration */ |
1987 | 2156 | ||
1988 | /* FIXME: use netif_carrier_{on,off} ; this polls | 2157 | /* Poll until the PHY tells us its configuration |
1989 | * until link is up which is wrong... could be | 2158 | * (not link state). |
1990 | * 30 seconds or more we are trapped in here. -jgarzik | 2159 | * Request is initiated by mii_do_cmd above, but answer |
2160 | * comes by interrupt. | ||
2161 | * This should take about 25 usec per register at 2.5 MHz, | ||
2162 | * and we read approximately 5 registers. | ||
1991 | */ | 2163 | */ |
1992 | while(!fep->sequence_done) | 2164 | while(!fep->sequence_done) |
1993 | schedule(); | 2165 | schedule(); |
@@ -2253,15 +2425,11 @@ int __init fec_enet_init(struct net_device *dev) | |||
2253 | */ | 2425 | */ |
2254 | fec_request_intrs(dev); | 2426 | fec_request_intrs(dev); |
2255 | 2427 | ||
2256 | /* Clear and enable interrupts */ | ||
2257 | fecp->fec_ievent = 0xffc00000; | ||
2258 | fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_TXB | | ||
2259 | FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII); | ||
2260 | fecp->fec_hash_table_high = 0; | 2428 | fecp->fec_hash_table_high = 0; |
2261 | fecp->fec_hash_table_low = 0; | 2429 | fecp->fec_hash_table_low = 0; |
2262 | fecp->fec_r_buff_size = PKT_MAXBLR_SIZE; | 2430 | fecp->fec_r_buff_size = PKT_MAXBLR_SIZE; |
2263 | fecp->fec_ecntrl = 2; | 2431 | fecp->fec_ecntrl = 2; |
2264 | fecp->fec_r_des_active = 0x01000000; | 2432 | fecp->fec_r_des_active = 0; |
2265 | 2433 | ||
2266 | dev->base_addr = (unsigned long)fecp; | 2434 | dev->base_addr = (unsigned long)fecp; |
2267 | 2435 | ||
@@ -2281,6 +2449,11 @@ int __init fec_enet_init(struct net_device *dev) | |||
2281 | /* setup MII interface */ | 2449 | /* setup MII interface */ |
2282 | fec_set_mii(dev, fep); | 2450 | fec_set_mii(dev, fep); |
2283 | 2451 | ||
2452 | /* Clear and enable interrupts */ | ||
2453 | fecp->fec_ievent = 0xffc00000; | ||
2454 | fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_TXB | | ||
2455 | FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII); | ||
2456 | |||
2284 | /* Queue up command to detect the PHY and initialize the | 2457 | /* Queue up command to detect the PHY and initialize the |
2285 | * remainder of the interface. | 2458 | * remainder of the interface. |
2286 | */ | 2459 | */ |
@@ -2312,11 +2485,6 @@ fec_restart(struct net_device *dev, int duplex) | |||
2312 | fecp->fec_ecntrl = 1; | 2485 | fecp->fec_ecntrl = 1; |
2313 | udelay(10); | 2486 | udelay(10); |
2314 | 2487 | ||
2315 | /* Enable interrupts we wish to service. | ||
2316 | */ | ||
2317 | fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_TXB | | ||
2318 | FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII); | ||
2319 | |||
2320 | /* Clear any outstanding interrupt. | 2488 | /* Clear any outstanding interrupt. |
2321 | */ | 2489 | */ |
2322 | fecp->fec_ievent = 0xffc00000; | 2490 | fecp->fec_ievent = 0xffc00000; |
@@ -2408,7 +2576,12 @@ fec_restart(struct net_device *dev, int duplex) | |||
2408 | /* And last, enable the transmit and receive processing. | 2576 | /* And last, enable the transmit and receive processing. |
2409 | */ | 2577 | */ |
2410 | fecp->fec_ecntrl = 2; | 2578 | fecp->fec_ecntrl = 2; |
2411 | fecp->fec_r_des_active = 0x01000000; | 2579 | fecp->fec_r_des_active = 0; |
2580 | |||
2581 | /* Enable interrupts we wish to service. | ||
2582 | */ | ||
2583 | fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_TXB | | ||
2584 | FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII); | ||
2412 | } | 2585 | } |
2413 | 2586 | ||
2414 | static void | 2587 | static void |
@@ -2420,9 +2593,16 @@ fec_stop(struct net_device *dev) | |||
2420 | fep = netdev_priv(dev); | 2593 | fep = netdev_priv(dev); |
2421 | fecp = fep->hwp; | 2594 | fecp = fep->hwp; |
2422 | 2595 | ||
2423 | fecp->fec_x_cntrl = 0x01; /* Graceful transmit stop */ | 2596 | /* |
2424 | 2597 | ** We cannot expect a graceful transmit stop without link !!! | |
2425 | while(!(fecp->fec_ievent & FEC_ENET_GRA)); | 2598 | */ |
2599 | if (fep->link) | ||
2600 | { | ||
2601 | fecp->fec_x_cntrl = 0x01; /* Graceful transmit stop */ | ||
2602 | udelay(10); | ||
2603 | if (!(fecp->fec_ievent & FEC_ENET_GRA)) | ||
2604 | printk("fec_stop : Graceful transmit stop did not complete !\n"); | ||
2605 | } | ||
2426 | 2606 | ||
2427 | /* Whack a reset. We should wait for this. | 2607 | /* Whack a reset. We should wait for this. |
2428 | */ | 2608 | */ |
diff --git a/drivers/net/fs_enet/fs_enet-mii.c b/drivers/net/fs_enet/fs_enet-mii.c index c6770377ef87..0cd07150bf4a 100644 --- a/drivers/net/fs_enet/fs_enet-mii.c +++ b/drivers/net/fs_enet/fs_enet-mii.c | |||
@@ -431,8 +431,7 @@ static struct fs_enet_mii_bus *create_bus(const struct fs_mii_bus_info *bi) | |||
431 | return bus; | 431 | return bus; |
432 | 432 | ||
433 | err: | 433 | err: |
434 | if (bus) | 434 | kfree(bus); |
435 | kfree(bus); | ||
436 | return ERR_PTR(ret); | 435 | return ERR_PTR(ret); |
437 | } | 436 | } |
438 | 437 | ||
diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c index 0d5fccc984bb..c9a46b89942a 100644 --- a/drivers/net/hamradio/dmascc.c +++ b/drivers/net/hamradio/dmascc.c | |||
@@ -436,7 +436,7 @@ static int __init dmascc_init(void) | |||
436 | module_init(dmascc_init); | 436 | module_init(dmascc_init); |
437 | module_exit(dmascc_exit); | 437 | module_exit(dmascc_exit); |
438 | 438 | ||
439 | static void dev_setup(struct net_device *dev) | 439 | static void __init dev_setup(struct net_device *dev) |
440 | { | 440 | { |
441 | dev->type = ARPHRD_AX25; | 441 | dev->type = ARPHRD_AX25; |
442 | dev->hard_header_len = AX25_MAX_HEADER_LEN; | 442 | dev->hard_header_len = AX25_MAX_HEADER_LEN; |
diff --git a/drivers/net/irda/irport.c b/drivers/net/irda/irport.c index 98fa5319e5cc..44efd49bf4a9 100644 --- a/drivers/net/irda/irport.c +++ b/drivers/net/irda/irport.c | |||
@@ -386,7 +386,7 @@ static int __irport_change_speed(struct irda_task *task) | |||
386 | /* Locking notes : this function may be called from irq context with | 386 | /* Locking notes : this function may be called from irq context with |
387 | * spinlock, via irport_write_wakeup(), or from non-interrupt without | 387 | * spinlock, via irport_write_wakeup(), or from non-interrupt without |
388 | * spinlock (from the task timer). Yuck ! | 388 | * spinlock (from the task timer). Yuck ! |
389 | * This is ugly, and unsafe is the spinlock is not already aquired. | 389 | * This is ugly, and unsafe is the spinlock is not already acquired. |
390 | * This will be fixed when irda-task get rewritten. | 390 | * This will be fixed when irda-task get rewritten. |
391 | * Jean II */ | 391 | * Jean II */ |
392 | if (!spin_is_locked(&self->lock)) { | 392 | if (!spin_is_locked(&self->lock)) { |
diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c index cc7ff8f00e42..cb62f2a9676a 100644 --- a/drivers/net/irda/nsc-ircc.c +++ b/drivers/net/irda/nsc-ircc.c | |||
@@ -115,8 +115,12 @@ static nsc_chip_t chips[] = { | |||
115 | /* Contributed by Jan Frey - IBM A30/A31 */ | 115 | /* Contributed by Jan Frey - IBM A30/A31 */ |
116 | { "PC8739x", { 0x2e, 0x4e, 0x0 }, 0x20, 0xea, 0xff, | 116 | { "PC8739x", { 0x2e, 0x4e, 0x0 }, 0x20, 0xea, 0xff, |
117 | nsc_ircc_probe_39x, nsc_ircc_init_39x }, | 117 | nsc_ircc_probe_39x, nsc_ircc_init_39x }, |
118 | { "IBM", { 0x2e, 0x4e, 0x0 }, 0x20, 0xf4, 0xff, | 118 | /* IBM ThinkPads using PC8738x (T60/X60/Z60) */ |
119 | nsc_ircc_probe_39x, nsc_ircc_init_39x }, | 119 | { "IBM-PC8738x", { 0x2e, 0x4e, 0x0 }, 0x20, 0xf4, 0xff, |
120 | nsc_ircc_probe_39x, nsc_ircc_init_39x }, | ||
121 | /* IBM ThinkPads using PC8394T (T43/R52/?) */ | ||
122 | { "IBM-PC8394T", { 0x2e, 0x4e, 0x0 }, 0x20, 0xf9, 0xff, | ||
123 | nsc_ircc_probe_39x, nsc_ircc_init_39x }, | ||
120 | { NULL } | 124 | { NULL } |
121 | }; | 125 | }; |
122 | 126 | ||
diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index 2e4ecedba057..5657049c2160 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c | |||
@@ -226,7 +226,6 @@ static int full_duplex[MAX_UNITS]; | |||
226 | NATSEMI_PG1_NREGS) | 226 | NATSEMI_PG1_NREGS) |
227 | #define NATSEMI_REGS_VER 1 /* v1 added RFDR registers */ | 227 | #define NATSEMI_REGS_VER 1 /* v1 added RFDR registers */ |
228 | #define NATSEMI_REGS_SIZE (NATSEMI_NREGS * sizeof(u32)) | 228 | #define NATSEMI_REGS_SIZE (NATSEMI_NREGS * sizeof(u32)) |
229 | #define NATSEMI_DEF_EEPROM_SIZE 24 /* 12 16-bit values */ | ||
230 | 229 | ||
231 | /* Buffer sizes: | 230 | /* Buffer sizes: |
232 | * The nic writes 32-bit values, even if the upper bytes of | 231 | * The nic writes 32-bit values, even if the upper bytes of |
@@ -344,18 +343,6 @@ None characterised. | |||
344 | 343 | ||
345 | 344 | ||
346 | 345 | ||
347 | enum pcistuff { | ||
348 | PCI_USES_IO = 0x01, | ||
349 | PCI_USES_MEM = 0x02, | ||
350 | PCI_USES_MASTER = 0x04, | ||
351 | PCI_ADDR0 = 0x08, | ||
352 | PCI_ADDR1 = 0x10, | ||
353 | }; | ||
354 | |||
355 | /* MMIO operations required */ | ||
356 | #define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR1) | ||
357 | |||
358 | |||
359 | /* | 346 | /* |
360 | * Support for fibre connections on Am79C874: | 347 | * Support for fibre connections on Am79C874: |
361 | * This phy needs a special setup when connected to a fibre cable. | 348 | * This phy needs a special setup when connected to a fibre cable. |
@@ -363,22 +350,25 @@ enum pcistuff { | |||
363 | */ | 350 | */ |
364 | #define PHYID_AM79C874 0x0022561b | 351 | #define PHYID_AM79C874 0x0022561b |
365 | 352 | ||
366 | #define MII_MCTRL 0x15 /* mode control register */ | 353 | enum { |
367 | #define MII_FX_SEL 0x0001 /* 100BASE-FX (fiber) */ | 354 | MII_MCTRL = 0x15, /* mode control register */ |
368 | #define MII_EN_SCRM 0x0004 /* enable scrambler (tp) */ | 355 | MII_FX_SEL = 0x0001, /* 100BASE-FX (fiber) */ |
356 | MII_EN_SCRM = 0x0004, /* enable scrambler (tp) */ | ||
357 | }; | ||
369 | 358 | ||
370 | 359 | ||
371 | /* array of board data directly indexed by pci_tbl[x].driver_data */ | 360 | /* array of board data directly indexed by pci_tbl[x].driver_data */ |
372 | static const struct { | 361 | static const struct { |
373 | const char *name; | 362 | const char *name; |
374 | unsigned long flags; | 363 | unsigned long flags; |
364 | unsigned int eeprom_size; | ||
375 | } natsemi_pci_info[] __devinitdata = { | 365 | } natsemi_pci_info[] __devinitdata = { |
376 | { "NatSemi DP8381[56]", PCI_IOTYPE }, | 366 | { "NatSemi DP8381[56]", 0, 24 }, |
377 | }; | 367 | }; |
378 | 368 | ||
379 | static struct pci_device_id natsemi_pci_tbl[] = { | 369 | static const struct pci_device_id natsemi_pci_tbl[] __devinitdata = { |
380 | { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_83815, PCI_ANY_ID, PCI_ANY_ID, }, | 370 | { PCI_VENDOR_ID_NS, 0x0020, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, |
381 | { 0, }, | 371 | { } /* terminate list */ |
382 | }; | 372 | }; |
383 | MODULE_DEVICE_TABLE(pci, natsemi_pci_tbl); | 373 | MODULE_DEVICE_TABLE(pci, natsemi_pci_tbl); |
384 | 374 | ||
@@ -813,6 +803,42 @@ static void move_int_phy(struct net_device *dev, int addr) | |||
813 | udelay(1); | 803 | udelay(1); |
814 | } | 804 | } |
815 | 805 | ||
806 | static void __devinit natsemi_init_media (struct net_device *dev) | ||
807 | { | ||
808 | struct netdev_private *np = netdev_priv(dev); | ||
809 | u32 tmp; | ||
810 | |||
811 | netif_carrier_off(dev); | ||
812 | |||
813 | /* get the initial settings from hardware */ | ||
814 | tmp = mdio_read(dev, MII_BMCR); | ||
815 | np->speed = (tmp & BMCR_SPEED100)? SPEED_100 : SPEED_10; | ||
816 | np->duplex = (tmp & BMCR_FULLDPLX)? DUPLEX_FULL : DUPLEX_HALF; | ||
817 | np->autoneg = (tmp & BMCR_ANENABLE)? AUTONEG_ENABLE: AUTONEG_DISABLE; | ||
818 | np->advertising= mdio_read(dev, MII_ADVERTISE); | ||
819 | |||
820 | if ((np->advertising & ADVERTISE_ALL) != ADVERTISE_ALL | ||
821 | && netif_msg_probe(np)) { | ||
822 | printk(KERN_INFO "natsemi %s: Transceiver default autonegotiation %s " | ||
823 | "10%s %s duplex.\n", | ||
824 | pci_name(np->pci_dev), | ||
825 | (mdio_read(dev, MII_BMCR) & BMCR_ANENABLE)? | ||
826 | "enabled, advertise" : "disabled, force", | ||
827 | (np->advertising & | ||
828 | (ADVERTISE_100FULL|ADVERTISE_100HALF))? | ||
829 | "0" : "", | ||
830 | (np->advertising & | ||
831 | (ADVERTISE_100FULL|ADVERTISE_10FULL))? | ||
832 | "full" : "half"); | ||
833 | } | ||
834 | if (netif_msg_probe(np)) | ||
835 | printk(KERN_INFO | ||
836 | "natsemi %s: Transceiver status %#04x advertising %#04x.\n", | ||
837 | pci_name(np->pci_dev), mdio_read(dev, MII_BMSR), | ||
838 | np->advertising); | ||
839 | |||
840 | } | ||
841 | |||
816 | static int __devinit natsemi_probe1 (struct pci_dev *pdev, | 842 | static int __devinit natsemi_probe1 (struct pci_dev *pdev, |
817 | const struct pci_device_id *ent) | 843 | const struct pci_device_id *ent) |
818 | { | 844 | { |
@@ -852,8 +878,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, | |||
852 | iosize = pci_resource_len(pdev, pcibar); | 878 | iosize = pci_resource_len(pdev, pcibar); |
853 | irq = pdev->irq; | 879 | irq = pdev->irq; |
854 | 880 | ||
855 | if (natsemi_pci_info[chip_idx].flags & PCI_USES_MASTER) | 881 | pci_set_master(pdev); |
856 | pci_set_master(pdev); | ||
857 | 882 | ||
858 | dev = alloc_etherdev(sizeof (struct netdev_private)); | 883 | dev = alloc_etherdev(sizeof (struct netdev_private)); |
859 | if (!dev) | 884 | if (!dev) |
@@ -892,7 +917,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, | |||
892 | np->msg_enable = (debug >= 0) ? (1<<debug)-1 : NATSEMI_DEF_MSG; | 917 | np->msg_enable = (debug >= 0) ? (1<<debug)-1 : NATSEMI_DEF_MSG; |
893 | np->hands_off = 0; | 918 | np->hands_off = 0; |
894 | np->intr_status = 0; | 919 | np->intr_status = 0; |
895 | np->eeprom_size = NATSEMI_DEF_EEPROM_SIZE; | 920 | np->eeprom_size = natsemi_pci_info[chip_idx].eeprom_size; |
896 | 921 | ||
897 | /* Initial port: | 922 | /* Initial port: |
898 | * - If the nic was configured to use an external phy and if find_mii | 923 | * - If the nic was configured to use an external phy and if find_mii |
@@ -957,34 +982,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, | |||
957 | if (mtu) | 982 | if (mtu) |
958 | dev->mtu = mtu; | 983 | dev->mtu = mtu; |
959 | 984 | ||
960 | netif_carrier_off(dev); | 985 | natsemi_init_media(dev); |
961 | |||
962 | /* get the initial settings from hardware */ | ||
963 | tmp = mdio_read(dev, MII_BMCR); | ||
964 | np->speed = (tmp & BMCR_SPEED100)? SPEED_100 : SPEED_10; | ||
965 | np->duplex = (tmp & BMCR_FULLDPLX)? DUPLEX_FULL : DUPLEX_HALF; | ||
966 | np->autoneg = (tmp & BMCR_ANENABLE)? AUTONEG_ENABLE: AUTONEG_DISABLE; | ||
967 | np->advertising= mdio_read(dev, MII_ADVERTISE); | ||
968 | |||
969 | if ((np->advertising & ADVERTISE_ALL) != ADVERTISE_ALL | ||
970 | && netif_msg_probe(np)) { | ||
971 | printk(KERN_INFO "natsemi %s: Transceiver default autonegotiation %s " | ||
972 | "10%s %s duplex.\n", | ||
973 | pci_name(np->pci_dev), | ||
974 | (mdio_read(dev, MII_BMCR) & BMCR_ANENABLE)? | ||
975 | "enabled, advertise" : "disabled, force", | ||
976 | (np->advertising & | ||
977 | (ADVERTISE_100FULL|ADVERTISE_100HALF))? | ||
978 | "0" : "", | ||
979 | (np->advertising & | ||
980 | (ADVERTISE_100FULL|ADVERTISE_10FULL))? | ||
981 | "full" : "half"); | ||
982 | } | ||
983 | if (netif_msg_probe(np)) | ||
984 | printk(KERN_INFO | ||
985 | "natsemi %s: Transceiver status %#04x advertising %#04x.\n", | ||
986 | pci_name(np->pci_dev), mdio_read(dev, MII_BMSR), | ||
987 | np->advertising); | ||
988 | 986 | ||
989 | /* save the silicon revision for later querying */ | 987 | /* save the silicon revision for later querying */ |
990 | np->srr = readl(ioaddr + SiliconRev); | 988 | np->srr = readl(ioaddr + SiliconRev); |
diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index e74bf5014ef6..a73d54553030 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c | |||
@@ -1883,7 +1883,7 @@ static void smc_reset(struct net_device *dev) | |||
1883 | /* Set the Window 1 control, configuration and station addr registers. | 1883 | /* Set the Window 1 control, configuration and station addr registers. |
1884 | No point in writing the I/O base register ;-> */ | 1884 | No point in writing the I/O base register ;-> */ |
1885 | SMC_SELECT_BANK(1); | 1885 | SMC_SELECT_BANK(1); |
1886 | /* Automatically release succesfully transmitted packets, | 1886 | /* Automatically release successfully transmitted packets, |
1887 | Accept link errors, counter and Tx error interrupts. */ | 1887 | Accept link errors, counter and Tx error interrupts. */ |
1888 | outw(CTL_AUTO_RELEASE | CTL_TE_ENABLE | CTL_CR_ENABLE, | 1888 | outw(CTL_AUTO_RELEASE | CTL_TE_ENABLE | CTL_CR_ENABLE, |
1889 | ioaddr + CONTROL); | 1889 | ioaddr + CONTROL); |
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index fc08c4af506c..0e01c75da429 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c | |||
@@ -309,12 +309,6 @@ static int pcnet32_alloc_ring(struct net_device *dev, char *name); | |||
309 | static void pcnet32_free_ring(struct net_device *dev); | 309 | static void pcnet32_free_ring(struct net_device *dev); |
310 | static void pcnet32_check_media(struct net_device *dev, int verbose); | 310 | static void pcnet32_check_media(struct net_device *dev, int verbose); |
311 | 311 | ||
312 | enum pci_flags_bit { | ||
313 | PCI_USES_IO = 1, PCI_USES_MEM = 2, PCI_USES_MASTER = 4, | ||
314 | PCI_ADDR0 = 0x10 << 0, PCI_ADDR1 = 0x10 << 1, PCI_ADDR2 = | ||
315 | 0x10 << 2, PCI_ADDR3 = 0x10 << 3, | ||
316 | }; | ||
317 | |||
318 | static u16 pcnet32_wio_read_csr(unsigned long addr, int index) | 312 | static u16 pcnet32_wio_read_csr(unsigned long addr, int index) |
319 | { | 313 | { |
320 | outw(index, addr + PCNET32_WIO_RAP); | 314 | outw(index, addr + PCNET32_WIO_RAP); |
diff --git a/drivers/net/phy/lxt.c b/drivers/net/phy/lxt.c index bef79e454c33..3f702c503afe 100644 --- a/drivers/net/phy/lxt.c +++ b/drivers/net/phy/lxt.c | |||
@@ -123,9 +123,9 @@ static int lxt971_config_intr(struct phy_device *phydev) | |||
123 | } | 123 | } |
124 | 124 | ||
125 | static struct phy_driver lxt970_driver = { | 125 | static struct phy_driver lxt970_driver = { |
126 | .phy_id = 0x07810000, | 126 | .phy_id = 0x78100000, |
127 | .name = "LXT970", | 127 | .name = "LXT970", |
128 | .phy_id_mask = 0x0fffffff, | 128 | .phy_id_mask = 0xfffffff0, |
129 | .features = PHY_BASIC_FEATURES, | 129 | .features = PHY_BASIC_FEATURES, |
130 | .flags = PHY_HAS_INTERRUPT, | 130 | .flags = PHY_HAS_INTERRUPT, |
131 | .config_init = lxt970_config_init, | 131 | .config_init = lxt970_config_init, |
@@ -137,9 +137,9 @@ static struct phy_driver lxt970_driver = { | |||
137 | }; | 137 | }; |
138 | 138 | ||
139 | static struct phy_driver lxt971_driver = { | 139 | static struct phy_driver lxt971_driver = { |
140 | .phy_id = 0x0001378e, | 140 | .phy_id = 0x001378e0, |
141 | .name = "LXT971", | 141 | .name = "LXT971", |
142 | .phy_id_mask = 0x0fffffff, | 142 | .phy_id_mask = 0xfffffff0, |
143 | .features = PHY_BASIC_FEATURES, | 143 | .features = PHY_BASIC_FEATURES, |
144 | .flags = PHY_HAS_INTERRUPT, | 144 | .flags = PHY_HAS_INTERRUPT, |
145 | .config_aneg = genphy_config_aneg, | 145 | .config_aneg = genphy_config_aneg, |
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index 01cd8ec751ea..d643a097faa5 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c | |||
@@ -2578,8 +2578,7 @@ ppp_find_channel(int unit) | |||
2578 | 2578 | ||
2579 | list_for_each_entry(pch, &new_channels, list) { | 2579 | list_for_each_entry(pch, &new_channels, list) { |
2580 | if (pch->file.index == unit) { | 2580 | if (pch->file.index == unit) { |
2581 | list_del(&pch->list); | 2581 | list_move(&pch->list, &all_channels); |
2582 | list_add(&pch->list, &all_channels); | ||
2583 | return pch; | 2582 | return pch; |
2584 | } | 2583 | } |
2585 | } | 2584 | } |
diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c index 8fea2aa455d4..602a6e5002a0 100644 --- a/drivers/net/tulip/winbond-840.c +++ b/drivers/net/tulip/winbond-840.c | |||
@@ -212,26 +212,15 @@ Test with 'ping -s 10000' on a fast computer. | |||
212 | /* | 212 | /* |
213 | PCI probe table. | 213 | PCI probe table. |
214 | */ | 214 | */ |
215 | enum pci_id_flags_bits { | ||
216 | /* Set PCI command register bits before calling probe1(). */ | ||
217 | PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4, | ||
218 | /* Read and map the single following PCI BAR. */ | ||
219 | PCI_ADDR0=0<<4, PCI_ADDR1=1<<4, PCI_ADDR2=2<<4, PCI_ADDR3=3<<4, | ||
220 | PCI_ADDR_64BITS=0x100, PCI_NO_ACPI_WAKE=0x200, PCI_NO_MIN_LATENCY=0x400, | ||
221 | }; | ||
222 | enum chip_capability_flags { | 215 | enum chip_capability_flags { |
223 | CanHaveMII=1, HasBrokenTx=2, AlwaysFDX=4, FDXOnNoMII=8,}; | 216 | CanHaveMII=1, HasBrokenTx=2, AlwaysFDX=4, FDXOnNoMII=8, |
224 | #ifdef USE_IO_OPS | 217 | }; |
225 | #define W840_FLAGS (PCI_USES_IO | PCI_ADDR0 | PCI_USES_MASTER) | ||
226 | #else | ||
227 | #define W840_FLAGS (PCI_USES_MEM | PCI_ADDR1 | PCI_USES_MASTER) | ||
228 | #endif | ||
229 | 218 | ||
230 | static struct pci_device_id w840_pci_tbl[] = { | 219 | static const struct pci_device_id w840_pci_tbl[] = { |
231 | { 0x1050, 0x0840, PCI_ANY_ID, 0x8153, 0, 0, 0 }, | 220 | { 0x1050, 0x0840, PCI_ANY_ID, 0x8153, 0, 0, 0 }, |
232 | { 0x1050, 0x0840, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 }, | 221 | { 0x1050, 0x0840, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 }, |
233 | { 0x11f6, 0x2011, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 }, | 222 | { 0x11f6, 0x2011, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 }, |
234 | { 0, } | 223 | { } |
235 | }; | 224 | }; |
236 | MODULE_DEVICE_TABLE(pci, w840_pci_tbl); | 225 | MODULE_DEVICE_TABLE(pci, w840_pci_tbl); |
237 | 226 | ||
@@ -241,18 +230,17 @@ struct pci_id_info { | |||
241 | int pci, pci_mask, subsystem, subsystem_mask; | 230 | int pci, pci_mask, subsystem, subsystem_mask; |
242 | int revision, revision_mask; /* Only 8 bits. */ | 231 | int revision, revision_mask; /* Only 8 bits. */ |
243 | } id; | 232 | } id; |
244 | enum pci_id_flags_bits pci_flags; | ||
245 | int io_size; /* Needed for I/O region check or ioremap(). */ | 233 | int io_size; /* Needed for I/O region check or ioremap(). */ |
246 | int drv_flags; /* Driver use, intended as capability flags. */ | 234 | int drv_flags; /* Driver use, intended as capability flags. */ |
247 | }; | 235 | }; |
248 | static struct pci_id_info pci_id_tbl[] = { | 236 | static struct pci_id_info pci_id_tbl[] = { |
249 | {"Winbond W89c840", /* Sometime a Level-One switch card. */ | 237 | {"Winbond W89c840", /* Sometime a Level-One switch card. */ |
250 | { 0x08401050, 0xffffffff, 0x81530000, 0xffff0000 }, | 238 | { 0x08401050, 0xffffffff, 0x81530000, 0xffff0000 }, |
251 | W840_FLAGS, 128, CanHaveMII | HasBrokenTx | FDXOnNoMII}, | 239 | 128, CanHaveMII | HasBrokenTx | FDXOnNoMII}, |
252 | {"Winbond W89c840", { 0x08401050, 0xffffffff, }, | 240 | {"Winbond W89c840", { 0x08401050, 0xffffffff, }, |
253 | W840_FLAGS, 128, CanHaveMII | HasBrokenTx}, | 241 | 128, CanHaveMII | HasBrokenTx}, |
254 | {"Compex RL100-ATX", { 0x201111F6, 0xffffffff,}, | 242 | {"Compex RL100-ATX", { 0x201111F6, 0xffffffff,}, |
255 | W840_FLAGS, 128, CanHaveMII | HasBrokenTx}, | 243 | 128, CanHaveMII | HasBrokenTx}, |
256 | {NULL,}, /* 0 terminated list. */ | 244 | {NULL,}, /* 0 terminated list. */ |
257 | }; | 245 | }; |
258 | 246 | ||
diff --git a/drivers/net/wan/c101.c b/drivers/net/wan/c101.c index b60ef02db7b0..c92ac9fde083 100644 --- a/drivers/net/wan/c101.c +++ b/drivers/net/wan/c101.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * under the terms of version 2 of the GNU General Public License | 7 | * under the terms of version 2 of the GNU General Public License |
8 | * as published by the Free Software Foundation. | 8 | * as published by the Free Software Foundation. |
9 | * | 9 | * |
10 | * For information see http://hq.pm.waw.pl/hdlc/ | 10 | * For information see <http://www.kernel.org/pub/linux/utils/net/hdlc/> |
11 | * | 11 | * |
12 | * Sources of information: | 12 | * Sources of information: |
13 | * Hitachi HD64570 SCA User's Manual | 13 | * Hitachi HD64570 SCA User's Manual |
diff --git a/drivers/net/wan/n2.c b/drivers/net/wan/n2.c index b7d88db89a5c..e013b817cab8 100644 --- a/drivers/net/wan/n2.c +++ b/drivers/net/wan/n2.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * under the terms of version 2 of the GNU General Public License | 7 | * under the terms of version 2 of the GNU General Public License |
8 | * as published by the Free Software Foundation. | 8 | * as published by the Free Software Foundation. |
9 | * | 9 | * |
10 | * For information see http://hq.pm.waw.pl/hdlc/ | 10 | * For information see <http://www.kernel.org/pub/linux/utils/net/hdlc/> |
11 | * | 11 | * |
12 | * Note: integrated CSU/DSU/DDS are not supported by this driver | 12 | * Note: integrated CSU/DSU/DDS are not supported by this driver |
13 | * | 13 | * |
diff --git a/drivers/net/wan/pci200syn.c b/drivers/net/wan/pci200syn.c index 670e8bd2245c..24c3c57c13c9 100644 --- a/drivers/net/wan/pci200syn.c +++ b/drivers/net/wan/pci200syn.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * under the terms of version 2 of the GNU General Public License | 7 | * under the terms of version 2 of the GNU General Public License |
8 | * as published by the Free Software Foundation. | 8 | * as published by the Free Software Foundation. |
9 | * | 9 | * |
10 | * For information see http://hq.pm.waw.pl/hdlc/ | 10 | * For information see <http://www.kernel.org/pub/linux/utils/net/hdlc/> |
11 | * | 11 | * |
12 | * Sources of information: | 12 | * Sources of information: |
13 | * Hitachi HD64572 SCA-II User's Manual | 13 | * Hitachi HD64572 SCA-II User's Manual |
diff --git a/drivers/net/wireless/bcm43xx/Kconfig b/drivers/net/wireless/bcm43xx/Kconfig index 25ea4748f0b9..533993f538fc 100644 --- a/drivers/net/wireless/bcm43xx/Kconfig +++ b/drivers/net/wireless/bcm43xx/Kconfig | |||
@@ -2,6 +2,7 @@ config BCM43XX | |||
2 | tristate "Broadcom BCM43xx wireless support" | 2 | tristate "Broadcom BCM43xx wireless support" |
3 | depends on PCI && IEEE80211 && IEEE80211_SOFTMAC && NET_RADIO && EXPERIMENTAL | 3 | depends on PCI && IEEE80211 && IEEE80211_SOFTMAC && NET_RADIO && EXPERIMENTAL |
4 | select FW_LOADER | 4 | select FW_LOADER |
5 | select HW_RANDOM | ||
5 | ---help--- | 6 | ---help--- |
6 | This is an experimental driver for the Broadcom 43xx wireless chip, | 7 | This is an experimental driver for the Broadcom 43xx wireless chip, |
7 | found in the Apple Airport Extreme and various other devices. | 8 | found in the Apple Airport Extreme and various other devices. |
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index d8f917c21ea4..17a56828e232 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h | |||
@@ -1,6 +1,7 @@ | |||
1 | #ifndef BCM43xx_H_ | 1 | #ifndef BCM43xx_H_ |
2 | #define BCM43xx_H_ | 2 | #define BCM43xx_H_ |
3 | 3 | ||
4 | #include <linux/hw_random.h> | ||
4 | #include <linux/version.h> | 5 | #include <linux/version.h> |
5 | #include <linux/kernel.h> | 6 | #include <linux/kernel.h> |
6 | #include <linux/spinlock.h> | 7 | #include <linux/spinlock.h> |
@@ -82,6 +83,7 @@ | |||
82 | #define BCM43xx_MMIO_TSF_1 0x634 /* core rev < 3 only */ | 83 | #define BCM43xx_MMIO_TSF_1 0x634 /* core rev < 3 only */ |
83 | #define BCM43xx_MMIO_TSF_2 0x636 /* core rev < 3 only */ | 84 | #define BCM43xx_MMIO_TSF_2 0x636 /* core rev < 3 only */ |
84 | #define BCM43xx_MMIO_TSF_3 0x638 /* core rev < 3 only */ | 85 | #define BCM43xx_MMIO_TSF_3 0x638 /* core rev < 3 only */ |
86 | #define BCM43xx_MMIO_RNG 0x65A | ||
85 | #define BCM43xx_MMIO_POWERUP_DELAY 0x6A8 | 87 | #define BCM43xx_MMIO_POWERUP_DELAY 0x6A8 |
86 | 88 | ||
87 | /* SPROM offsets. */ | 89 | /* SPROM offsets. */ |
@@ -750,6 +752,10 @@ struct bcm43xx_private { | |||
750 | const struct firmware *initvals0; | 752 | const struct firmware *initvals0; |
751 | const struct firmware *initvals1; | 753 | const struct firmware *initvals1; |
752 | 754 | ||
755 | /* Random Number Generator. */ | ||
756 | struct hwrng rng; | ||
757 | char rng_name[20 + 1]; | ||
758 | |||
753 | /* Debugging stuff follows. */ | 759 | /* Debugging stuff follows. */ |
754 | #ifdef CONFIG_BCM43XX_DEBUG | 760 | #ifdef CONFIG_BCM43XX_DEBUG |
755 | struct bcm43xx_dfsentry *dfsentry; | 761 | struct bcm43xx_dfsentry *dfsentry; |
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 085d7857fe31..27bcf47228e2 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c | |||
@@ -3237,6 +3237,39 @@ static void bcm43xx_security_init(struct bcm43xx_private *bcm) | |||
3237 | bcm43xx_clear_keys(bcm); | 3237 | bcm43xx_clear_keys(bcm); |
3238 | } | 3238 | } |
3239 | 3239 | ||
3240 | static int bcm43xx_rng_read(struct hwrng *rng, u32 *data) | ||
3241 | { | ||
3242 | struct bcm43xx_private *bcm = (struct bcm43xx_private *)rng->priv; | ||
3243 | unsigned long flags; | ||
3244 | |||
3245 | bcm43xx_lock_irqonly(bcm, flags); | ||
3246 | *data = bcm43xx_read16(bcm, BCM43xx_MMIO_RNG); | ||
3247 | bcm43xx_unlock_irqonly(bcm, flags); | ||
3248 | |||
3249 | return (sizeof(u16)); | ||
3250 | } | ||
3251 | |||
3252 | static void bcm43xx_rng_exit(struct bcm43xx_private *bcm) | ||
3253 | { | ||
3254 | hwrng_unregister(&bcm->rng); | ||
3255 | } | ||
3256 | |||
3257 | static int bcm43xx_rng_init(struct bcm43xx_private *bcm) | ||
3258 | { | ||
3259 | int err; | ||
3260 | |||
3261 | snprintf(bcm->rng_name, ARRAY_SIZE(bcm->rng_name), | ||
3262 | "%s_%s", KBUILD_MODNAME, bcm->net_dev->name); | ||
3263 | bcm->rng.name = bcm->rng_name; | ||
3264 | bcm->rng.data_read = bcm43xx_rng_read; | ||
3265 | bcm->rng.priv = (unsigned long)bcm; | ||
3266 | err = hwrng_register(&bcm->rng); | ||
3267 | if (err) | ||
3268 | printk(KERN_ERR PFX "RNG init failed (%d)\n", err); | ||
3269 | |||
3270 | return err; | ||
3271 | } | ||
3272 | |||
3240 | /* This is the opposite of bcm43xx_init_board() */ | 3273 | /* This is the opposite of bcm43xx_init_board() */ |
3241 | static void bcm43xx_free_board(struct bcm43xx_private *bcm) | 3274 | static void bcm43xx_free_board(struct bcm43xx_private *bcm) |
3242 | { | 3275 | { |
@@ -3248,6 +3281,7 @@ static void bcm43xx_free_board(struct bcm43xx_private *bcm) | |||
3248 | 3281 | ||
3249 | bcm43xx_set_status(bcm, BCM43xx_STAT_SHUTTINGDOWN); | 3282 | bcm43xx_set_status(bcm, BCM43xx_STAT_SHUTTINGDOWN); |
3250 | 3283 | ||
3284 | bcm43xx_rng_exit(bcm); | ||
3251 | for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { | 3285 | for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { |
3252 | if (!bcm->core_80211[i].available) | 3286 | if (!bcm->core_80211[i].available) |
3253 | continue; | 3287 | continue; |
@@ -3325,6 +3359,9 @@ static int bcm43xx_init_board(struct bcm43xx_private *bcm) | |||
3325 | bcm43xx_switch_core(bcm, &bcm->core_80211[0]); | 3359 | bcm43xx_switch_core(bcm, &bcm->core_80211[0]); |
3326 | bcm43xx_mac_enable(bcm); | 3360 | bcm43xx_mac_enable(bcm); |
3327 | } | 3361 | } |
3362 | err = bcm43xx_rng_init(bcm); | ||
3363 | if (err) | ||
3364 | goto err_80211_unwind; | ||
3328 | bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC); | 3365 | bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC); |
3329 | bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_SELF, (u8 *)(bcm->net_dev->dev_addr)); | 3366 | bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_SELF, (u8 *)(bcm->net_dev->dev_addr)); |
3330 | dprintk(KERN_INFO PFX "80211 cores initialized\n"); | 3367 | dprintk(KERN_INFO PFX "80211 cores initialized\n"); |
diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index 72335c8eb97f..94aeb23a7729 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c | |||
@@ -1485,7 +1485,7 @@ static int ipw2100_hw_stop_adapter(struct ipw2100_priv *priv) | |||
1485 | * | 1485 | * |
1486 | * Sending the PREPARE_FOR_POWER_DOWN will restrict the | 1486 | * Sending the PREPARE_FOR_POWER_DOWN will restrict the |
1487 | * hardware from going into standby mode and will transition | 1487 | * hardware from going into standby mode and will transition |
1488 | * out of D0-standy if it is already in that state. | 1488 | * out of D0-standby if it is already in that state. |
1489 | * | 1489 | * |
1490 | * STATUS_PREPARE_POWER_DOWN_COMPLETE will be sent by the | 1490 | * STATUS_PREPARE_POWER_DOWN_COMPLETE will be sent by the |
1491 | * driver upon completion. Once received, the driver can | 1491 | * driver upon completion. Once received, the driver can |
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 081a8999666e..a8a8f975432f 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c | |||
@@ -1229,12 +1229,6 @@ static struct ipw_fw_error *ipw_alloc_error_log(struct ipw_priv *priv) | |||
1229 | return error; | 1229 | return error; |
1230 | } | 1230 | } |
1231 | 1231 | ||
1232 | static void ipw_free_error_log(struct ipw_fw_error *error) | ||
1233 | { | ||
1234 | if (error) | ||
1235 | kfree(error); | ||
1236 | } | ||
1237 | |||
1238 | static ssize_t show_event_log(struct device *d, | 1232 | static ssize_t show_event_log(struct device *d, |
1239 | struct device_attribute *attr, char *buf) | 1233 | struct device_attribute *attr, char *buf) |
1240 | { | 1234 | { |
@@ -1296,10 +1290,9 @@ static ssize_t clear_error(struct device *d, | |||
1296 | const char *buf, size_t count) | 1290 | const char *buf, size_t count) |
1297 | { | 1291 | { |
1298 | struct ipw_priv *priv = dev_get_drvdata(d); | 1292 | struct ipw_priv *priv = dev_get_drvdata(d); |
1299 | if (priv->error) { | 1293 | |
1300 | ipw_free_error_log(priv->error); | 1294 | kfree(priv->error); |
1301 | priv->error = NULL; | 1295 | priv->error = NULL; |
1302 | } | ||
1303 | return count; | 1296 | return count; |
1304 | } | 1297 | } |
1305 | 1298 | ||
@@ -1970,8 +1963,7 @@ static void ipw_irq_tasklet(struct ipw_priv *priv) | |||
1970 | struct ipw_fw_error *error = | 1963 | struct ipw_fw_error *error = |
1971 | ipw_alloc_error_log(priv); | 1964 | ipw_alloc_error_log(priv); |
1972 | ipw_dump_error_log(priv, error); | 1965 | ipw_dump_error_log(priv, error); |
1973 | if (error) | 1966 | kfree(error); |
1974 | ipw_free_error_log(error); | ||
1975 | } | 1967 | } |
1976 | #endif | 1968 | #endif |
1977 | } else { | 1969 | } else { |
@@ -11693,10 +11685,8 @@ static void ipw_pci_remove(struct pci_dev *pdev) | |||
11693 | } | 11685 | } |
11694 | } | 11686 | } |
11695 | 11687 | ||
11696 | if (priv->error) { | 11688 | kfree(priv->error); |
11697 | ipw_free_error_log(priv->error); | 11689 | priv->error = NULL; |
11698 | priv->error = NULL; | ||
11699 | } | ||
11700 | 11690 | ||
11701 | #ifdef CONFIG_IPW2200_PROMISCUOUS | 11691 | #ifdef CONFIG_IPW2200_PROMISCUOUS |
11702 | ipw_prom_free(priv); | 11692 | ipw_prom_free(priv); |
diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c index ecec8e5db786..569305f57561 100644 --- a/drivers/net/yellowfin.c +++ b/drivers/net/yellowfin.c | |||
@@ -234,14 +234,6 @@ See Packet Engines confidential appendix (prototype chips only). | |||
234 | 234 | ||
235 | 235 | ||
236 | 236 | ||
237 | enum pci_id_flags_bits { | ||
238 | /* Set PCI command register bits before calling probe1(). */ | ||
239 | PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4, | ||
240 | /* Read and map the single following PCI BAR. */ | ||
241 | PCI_ADDR0=0<<4, PCI_ADDR1=1<<4, PCI_ADDR2=2<<4, PCI_ADDR3=3<<4, | ||
242 | PCI_ADDR_64BITS=0x100, PCI_NO_ACPI_WAKE=0x200, PCI_NO_MIN_LATENCY=0x400, | ||
243 | PCI_UNUSED_IRQ=0x800, | ||
244 | }; | ||
245 | enum capability_flags { | 237 | enum capability_flags { |
246 | HasMII=1, FullTxStatus=2, IsGigabit=4, HasMulticastBug=8, FullRxStatus=16, | 238 | HasMII=1, FullTxStatus=2, IsGigabit=4, HasMulticastBug=8, FullRxStatus=16, |
247 | HasMACAddrBug=32, /* Only on early revs. */ | 239 | HasMACAddrBug=32, /* Only on early revs. */ |
@@ -249,11 +241,6 @@ enum capability_flags { | |||
249 | }; | 241 | }; |
250 | /* The PCI I/O space extent. */ | 242 | /* The PCI I/O space extent. */ |
251 | #define YELLOWFIN_SIZE 0x100 | 243 | #define YELLOWFIN_SIZE 0x100 |
252 | #ifdef USE_IO_OPS | ||
253 | #define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_IO | PCI_ADDR0) | ||
254 | #else | ||
255 | #define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR1) | ||
256 | #endif | ||
257 | 244 | ||
258 | struct pci_id_info { | 245 | struct pci_id_info { |
259 | const char *name; | 246 | const char *name; |
@@ -261,24 +248,23 @@ struct pci_id_info { | |||
261 | int pci, pci_mask, subsystem, subsystem_mask; | 248 | int pci, pci_mask, subsystem, subsystem_mask; |
262 | int revision, revision_mask; /* Only 8 bits. */ | 249 | int revision, revision_mask; /* Only 8 bits. */ |
263 | } id; | 250 | } id; |
264 | enum pci_id_flags_bits pci_flags; | ||
265 | int io_size; /* Needed for I/O region check or ioremap(). */ | 251 | int io_size; /* Needed for I/O region check or ioremap(). */ |
266 | int drv_flags; /* Driver use, intended as capability flags. */ | 252 | int drv_flags; /* Driver use, intended as capability flags. */ |
267 | }; | 253 | }; |
268 | 254 | ||
269 | static const struct pci_id_info pci_id_tbl[] = { | 255 | static const struct pci_id_info pci_id_tbl[] = { |
270 | {"Yellowfin G-NIC Gigabit Ethernet", { 0x07021000, 0xffffffff}, | 256 | {"Yellowfin G-NIC Gigabit Ethernet", { 0x07021000, 0xffffffff}, |
271 | PCI_IOTYPE, YELLOWFIN_SIZE, | 257 | YELLOWFIN_SIZE, |
272 | FullTxStatus | IsGigabit | HasMulticastBug | HasMACAddrBug | DontUseEeprom}, | 258 | FullTxStatus | IsGigabit | HasMulticastBug | HasMACAddrBug | DontUseEeprom}, |
273 | {"Symbios SYM83C885", { 0x07011000, 0xffffffff}, | 259 | {"Symbios SYM83C885", { 0x07011000, 0xffffffff}, |
274 | PCI_IOTYPE, YELLOWFIN_SIZE, HasMII | DontUseEeprom }, | 260 | YELLOWFIN_SIZE, HasMII | DontUseEeprom }, |
275 | {NULL,}, | 261 | { } |
276 | }; | 262 | }; |
277 | 263 | ||
278 | static struct pci_device_id yellowfin_pci_tbl[] = { | 264 | static const struct pci_device_id yellowfin_pci_tbl[] = { |
279 | { 0x1000, 0x0702, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, | 265 | { 0x1000, 0x0702, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, |
280 | { 0x1000, 0x0701, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 }, | 266 | { 0x1000, 0x0701, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 }, |
281 | { 0, } | 267 | { } |
282 | }; | 268 | }; |
283 | MODULE_DEVICE_TABLE (pci, yellowfin_pci_tbl); | 269 | MODULE_DEVICE_TABLE (pci, yellowfin_pci_tbl); |
284 | 270 | ||
diff --git a/drivers/parport/parport_gsc.c b/drivers/parport/parport_gsc.c index 1de52d9febf9..7352104f7b30 100644 --- a/drivers/parport/parport_gsc.c +++ b/drivers/parport/parport_gsc.c | |||
@@ -15,7 +15,7 @@ | |||
15 | * Phil Blundell <philb@gnu.org> | 15 | * Phil Blundell <philb@gnu.org> |
16 | * Tim Waugh <tim@cyberelk.demon.co.uk> | 16 | * Tim Waugh <tim@cyberelk.demon.co.uk> |
17 | * Jose Renau <renau@acm.org> | 17 | * Jose Renau <renau@acm.org> |
18 | * David Campbell <campbell@torque.net> | 18 | * David Campbell |
19 | * Andrea Arcangeli | 19 | * Andrea Arcangeli |
20 | */ | 20 | */ |
21 | 21 | ||
diff --git a/drivers/parport/parport_gsc.h b/drivers/parport/parport_gsc.h index 662f6c1fee5d..fc9c37c54022 100644 --- a/drivers/parport/parport_gsc.h +++ b/drivers/parport/parport_gsc.h | |||
@@ -24,7 +24,7 @@ | |||
24 | * Phil Blundell <Philip.Blundell@pobox.com> | 24 | * Phil Blundell <Philip.Blundell@pobox.com> |
25 | * Tim Waugh <tim@cyberelk.demon.co.uk> | 25 | * Tim Waugh <tim@cyberelk.demon.co.uk> |
26 | * Jose Renau <renau@acm.org> | 26 | * Jose Renau <renau@acm.org> |
27 | * David Campbell <campbell@torque.net> | 27 | * David Campbell |
28 | * Andrea Arcangeli | 28 | * Andrea Arcangeli |
29 | */ | 29 | */ |
30 | 30 | ||
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c index 48bbf32fd980..7318e4a9e436 100644 --- a/drivers/parport/parport_pc.c +++ b/drivers/parport/parport_pc.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * Authors: Phil Blundell <philb@gnu.org> | 3 | * Authors: Phil Blundell <philb@gnu.org> |
4 | * Tim Waugh <tim@cyberelk.demon.co.uk> | 4 | * Tim Waugh <tim@cyberelk.demon.co.uk> |
5 | * Jose Renau <renau@acm.org> | 5 | * Jose Renau <renau@acm.org> |
6 | * David Campbell <campbell@torque.net> | 6 | * David Campbell |
7 | * Andrea Arcangeli | 7 | * Andrea Arcangeli |
8 | * | 8 | * |
9 | * based on work by Grant Guenther <grant@torque.net> and Phil Blundell. | 9 | * based on work by Grant Guenther <grant@torque.net> and Phil Blundell. |
diff --git a/drivers/parport/parport_sunbpp.c b/drivers/parport/parport_sunbpp.c index 69a4bbd4cbee..7c43c5392bed 100644 --- a/drivers/parport/parport_sunbpp.c +++ b/drivers/parport/parport_sunbpp.c | |||
@@ -389,7 +389,7 @@ static struct of_device_id bpp_match[] = { | |||
389 | {}, | 389 | {}, |
390 | }; | 390 | }; |
391 | 391 | ||
392 | MODULE_DEVICE_TABLE(of, qec_sbus_match); | 392 | MODULE_DEVICE_TABLE(of, bpp_match); |
393 | 393 | ||
394 | static struct of_platform_driver bpp_sbus_driver = { | 394 | static struct of_platform_driver bpp_sbus_driver = { |
395 | .name = "bpp", | 395 | .name = "bpp", |
diff --git a/drivers/parport/procfs.c b/drivers/parport/procfs.c index cbe17184b9c7..8610ae88b92d 100644 --- a/drivers/parport/procfs.c +++ b/drivers/parport/procfs.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* Sysctl interface for parport devices. | 1 | /* Sysctl interface for parport devices. |
2 | * | 2 | * |
3 | * Authors: David Campbell <campbell@torque.net> | 3 | * Authors: David Campbell |
4 | * Tim Waugh <tim@cyberelk.demon.co.uk> | 4 | * Tim Waugh <tim@cyberelk.demon.co.uk> |
5 | * Philip Blundell <philb@gnu.org> | 5 | * Philip Blundell <philb@gnu.org> |
6 | * Andrea Arcangeli | 6 | * Andrea Arcangeli |
diff --git a/drivers/pci/msi-apic.c b/drivers/pci/msi-apic.c index 0eb5fe9003a2..5ed798b319c7 100644 --- a/drivers/pci/msi-apic.c +++ b/drivers/pci/msi-apic.c | |||
@@ -4,6 +4,7 @@ | |||
4 | 4 | ||
5 | #include <linux/pci.h> | 5 | #include <linux/pci.h> |
6 | #include <linux/irq.h> | 6 | #include <linux/irq.h> |
7 | #include <asm/smp.h> | ||
7 | 8 | ||
8 | #include "msi.h" | 9 | #include "msi.h" |
9 | 10 | ||
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index d408a3c30426..23d3b17c8cad 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c | |||
@@ -369,7 +369,7 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state) | |||
369 | 369 | ||
370 | /* | 370 | /* |
371 | * Give firmware a chance to be called, such as ACPI _PRx, _PSx | 371 | * Give firmware a chance to be called, such as ACPI _PRx, _PSx |
372 | * Firmware method after natice method ? | 372 | * Firmware method after native method ? |
373 | */ | 373 | */ |
374 | if (platform_pci_set_power_state) | 374 | if (platform_pci_set_power_state) |
375 | platform_pci_set_power_state(dev, state); | 375 | platform_pci_set_power_state(dev, state); |
diff --git a/drivers/pcmcia/m8xx_pcmcia.c b/drivers/pcmcia/m8xx_pcmcia.c index 0e07d9535116..d0f68ab8f041 100644 --- a/drivers/pcmcia/m8xx_pcmcia.c +++ b/drivers/pcmcia/m8xx_pcmcia.c | |||
@@ -157,7 +157,7 @@ MODULE_LICENSE("Dual MPL/GPL"); | |||
157 | 157 | ||
158 | static int pcmcia_schlvl = PCMCIA_SCHLVL; | 158 | static int pcmcia_schlvl = PCMCIA_SCHLVL; |
159 | 159 | ||
160 | static spinlock_t events_lock = SPIN_LOCK_UNLOCKED; | 160 | static DEFINE_SPINLOCK(events_lock); |
161 | 161 | ||
162 | 162 | ||
163 | #define PCMCIA_SOCKET_KEY_5V 1 | 163 | #define PCMCIA_SOCKET_KEY_5V 1 |
@@ -644,7 +644,7 @@ static struct platform_device m8xx_device = { | |||
644 | }; | 644 | }; |
645 | 645 | ||
646 | static u32 pending_events[PCMCIA_SOCKETS_NO]; | 646 | static u32 pending_events[PCMCIA_SOCKETS_NO]; |
647 | static spinlock_t pending_event_lock = SPIN_LOCK_UNLOCKED; | 647 | static DEFINE_SPINLOCK(pending_event_lock); |
648 | 648 | ||
649 | static irqreturn_t m8xx_interrupt(int irq, void *dev, struct pt_regs *regs) | 649 | static irqreturn_t m8xx_interrupt(int irq, void *dev, struct pt_regs *regs) |
650 | { | 650 | { |
diff --git a/drivers/rapidio/rio-access.c b/drivers/rapidio/rio-access.c index b9fab2ae3a36..8b56bbdd011e 100644 --- a/drivers/rapidio/rio-access.c +++ b/drivers/rapidio/rio-access.c | |||
@@ -17,8 +17,8 @@ | |||
17 | * These interrupt-safe spinlocks protect all accesses to RIO | 17 | * These interrupt-safe spinlocks protect all accesses to RIO |
18 | * configuration space and doorbell access. | 18 | * configuration space and doorbell access. |
19 | */ | 19 | */ |
20 | static spinlock_t rio_config_lock = SPIN_LOCK_UNLOCKED; | 20 | static DEFINE_SPINLOCK(rio_config_lock); |
21 | static spinlock_t rio_doorbell_lock = SPIN_LOCK_UNLOCKED; | 21 | static DEFINE_SPINLOCK(rio_doorbell_lock); |
22 | 22 | ||
23 | /* | 23 | /* |
24 | * Wrappers for all RIO configuration access functions. They just check | 24 | * Wrappers for all RIO configuration access functions. They just check |
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index 5396beec30d0..1cb61a761cb2 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c | |||
@@ -94,7 +94,9 @@ exit_kfree: | |||
94 | kfree(rtc); | 94 | kfree(rtc); |
95 | 95 | ||
96 | exit_idr: | 96 | exit_idr: |
97 | mutex_lock(&idr_lock); | ||
97 | idr_remove(&rtc_idr, id); | 98 | idr_remove(&rtc_idr, id); |
99 | mutex_unlock(&idr_lock); | ||
98 | 100 | ||
99 | exit: | 101 | exit: |
100 | dev_err(dev, "rtc core: unable to register %s, err = %d\n", | 102 | dev_err(dev, "rtc core: unable to register %s, err = %d\n", |
diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c index ecafbad41a24..762521a1419c 100644 --- a/drivers/rtc/rtc-ds1553.c +++ b/drivers/rtc/rtc-ds1553.c | |||
@@ -226,7 +226,7 @@ static int ds1553_rtc_ioctl(struct device *dev, unsigned int cmd, | |||
226 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | 226 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); |
227 | 227 | ||
228 | if (pdata->irq < 0) | 228 | if (pdata->irq < 0) |
229 | return -ENOIOCTLCMD; | 229 | return -ENOIOCTLCMD; /* fall back into rtc-dev's emulation */ |
230 | switch (cmd) { | 230 | switch (cmd) { |
231 | case RTC_AIE_OFF: | 231 | case RTC_AIE_OFF: |
232 | pdata->irqen &= ~RTC_AF; | 232 | pdata->irqen &= ~RTC_AF; |
diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index ab486fbc828d..9cd1cb304bb2 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c | |||
@@ -45,7 +45,7 @@ | |||
45 | 45 | ||
46 | static unsigned long rtc_freq = 1024; | 46 | static unsigned long rtc_freq = 1024; |
47 | static struct rtc_time rtc_alarm; | 47 | static struct rtc_time rtc_alarm; |
48 | static spinlock_t sa1100_rtc_lock = SPIN_LOCK_UNLOCKED; | 48 | static DEFINE_SPINLOCK(sa1100_rtc_lock); |
49 | 49 | ||
50 | static int rtc_update_alarm(struct rtc_time *alrm) | 50 | static int rtc_update_alarm(struct rtc_time *alrm) |
51 | { | 51 | { |
diff --git a/drivers/rtc/rtc-vr41xx.c b/drivers/rtc/rtc-vr41xx.c index 33e029207e26..4b9291dd4443 100644 --- a/drivers/rtc/rtc-vr41xx.c +++ b/drivers/rtc/rtc-vr41xx.c | |||
@@ -93,7 +93,7 @@ static void __iomem *rtc2_base; | |||
93 | 93 | ||
94 | static unsigned long epoch = 1970; /* Jan 1 1970 00:00:00 */ | 94 | static unsigned long epoch = 1970; /* Jan 1 1970 00:00:00 */ |
95 | 95 | ||
96 | static spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED; | 96 | static DEFINE_SPINLOCK(rtc_lock); |
97 | static char rtc_name[] = "RTC"; | 97 | static char rtc_name[] = "RTC"; |
98 | static unsigned long periodic_frequency; | 98 | static unsigned long periodic_frequency; |
99 | static unsigned long periodic_count; | 99 | static unsigned long periodic_count; |
diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c index 2d946b6ca074..2d8af709947f 100644 --- a/drivers/s390/block/dasd_eer.c +++ b/drivers/s390/block/dasd_eer.c | |||
@@ -89,7 +89,7 @@ struct eerbuffer { | |||
89 | }; | 89 | }; |
90 | 90 | ||
91 | static LIST_HEAD(bufferlist); | 91 | static LIST_HEAD(bufferlist); |
92 | static spinlock_t bufferlock = SPIN_LOCK_UNLOCKED; | 92 | static DEFINE_SPINLOCK(bufferlock); |
93 | static DECLARE_WAIT_QUEUE_HEAD(dasd_eer_read_wait_queue); | 93 | static DECLARE_WAIT_QUEUE_HEAD(dasd_eer_read_wait_queue); |
94 | 94 | ||
95 | /* | 95 | /* |
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index f94419b334f7..2eded55ae88d 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c | |||
@@ -1140,10 +1140,9 @@ list_modified: | |||
1140 | } | 1140 | } |
1141 | } | 1141 | } |
1142 | /* re-insert all entries from the failed_list into ipm_list */ | 1142 | /* re-insert all entries from the failed_list into ipm_list */ |
1143 | list_for_each_entry_safe(ipm, tmp, &failed_list, list) { | 1143 | list_for_each_entry_safe(ipm, tmp, &failed_list, list) |
1144 | list_del_init(&ipm->list); | 1144 | list_move_tail(&ipm->list, &card->ipm_list); |
1145 | list_add_tail(&ipm->list, &card->ipm_list); | 1145 | |
1146 | } | ||
1147 | spin_unlock_irqrestore(&card->ipm_lock, flags); | 1146 | spin_unlock_irqrestore(&card->ipm_lock, flags); |
1148 | } | 1147 | } |
1149 | 1148 | ||
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 4682c8b8bd24..909731b99d26 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c | |||
@@ -167,7 +167,7 @@ zfcp_fsf_scsi_er_timeout_handler(unsigned long data) | |||
167 | * initiates adapter recovery which is done | 167 | * initiates adapter recovery which is done |
168 | * asynchronously | 168 | * asynchronously |
169 | * | 169 | * |
170 | * returns: 0 - initiated action succesfully | 170 | * returns: 0 - initiated action successfully |
171 | * <0 - failed to initiate action | 171 | * <0 - failed to initiate action |
172 | */ | 172 | */ |
173 | int | 173 | int |
@@ -203,7 +203,7 @@ zfcp_erp_adapter_reopen_internal(struct zfcp_adapter *adapter, int clear_mask) | |||
203 | * purpose: Wrappper for zfcp_erp_adapter_reopen_internal | 203 | * purpose: Wrappper for zfcp_erp_adapter_reopen_internal |
204 | * used to ensure the correct locking | 204 | * used to ensure the correct locking |
205 | * | 205 | * |
206 | * returns: 0 - initiated action succesfully | 206 | * returns: 0 - initiated action successfully |
207 | * <0 - failed to initiate action | 207 | * <0 - failed to initiate action |
208 | */ | 208 | */ |
209 | int | 209 | int |
@@ -469,7 +469,7 @@ zfcp_test_link(struct zfcp_port *port) | |||
469 | * initiates Forced Reopen recovery which is done | 469 | * initiates Forced Reopen recovery which is done |
470 | * asynchronously | 470 | * asynchronously |
471 | * | 471 | * |
472 | * returns: 0 - initiated action succesfully | 472 | * returns: 0 - initiated action successfully |
473 | * <0 - failed to initiate action | 473 | * <0 - failed to initiate action |
474 | */ | 474 | */ |
475 | static int | 475 | static int |
@@ -509,7 +509,7 @@ zfcp_erp_port_forced_reopen_internal(struct zfcp_port *port, int clear_mask) | |||
509 | * purpose: Wrappper for zfcp_erp_port_forced_reopen_internal | 509 | * purpose: Wrappper for zfcp_erp_port_forced_reopen_internal |
510 | * used to ensure the correct locking | 510 | * used to ensure the correct locking |
511 | * | 511 | * |
512 | * returns: 0 - initiated action succesfully | 512 | * returns: 0 - initiated action successfully |
513 | * <0 - failed to initiate action | 513 | * <0 - failed to initiate action |
514 | */ | 514 | */ |
515 | int | 515 | int |
@@ -536,7 +536,7 @@ zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear_mask) | |||
536 | * initiates Reopen recovery which is done | 536 | * initiates Reopen recovery which is done |
537 | * asynchronously | 537 | * asynchronously |
538 | * | 538 | * |
539 | * returns: 0 - initiated action succesfully | 539 | * returns: 0 - initiated action successfully |
540 | * <0 - failed to initiate action | 540 | * <0 - failed to initiate action |
541 | */ | 541 | */ |
542 | static int | 542 | static int |
@@ -605,7 +605,7 @@ zfcp_erp_port_reopen(struct zfcp_port *port, int clear_mask) | |||
605 | * initiates Reopen recovery which is done | 605 | * initiates Reopen recovery which is done |
606 | * asynchronously | 606 | * asynchronously |
607 | * | 607 | * |
608 | * returns: 0 - initiated action succesfully | 608 | * returns: 0 - initiated action successfully |
609 | * <0 - failed to initiate action | 609 | * <0 - failed to initiate action |
610 | */ | 610 | */ |
611 | static int | 611 | static int |
@@ -1805,7 +1805,7 @@ zfcp_erp_modify_unit_status(struct zfcp_unit *unit, u32 mask, int set_or_clear) | |||
1805 | * purpose: Wrappper for zfcp_erp_port_reopen_all_internal | 1805 | * purpose: Wrappper for zfcp_erp_port_reopen_all_internal |
1806 | * used to ensure the correct locking | 1806 | * used to ensure the correct locking |
1807 | * | 1807 | * |
1808 | * returns: 0 - initiated action succesfully | 1808 | * returns: 0 - initiated action successfully |
1809 | * <0 - failed to initiate action | 1809 | * <0 - failed to initiate action |
1810 | */ | 1810 | */ |
1811 | int | 1811 | int |
diff --git a/drivers/sbus/char/cpwatchdog.c b/drivers/sbus/char/cpwatchdog.c index 5bf3dd901b65..21737b7e86a1 100644 --- a/drivers/sbus/char/cpwatchdog.c +++ b/drivers/sbus/char/cpwatchdog.c | |||
@@ -755,7 +755,7 @@ static int __init wd_init(void) | |||
755 | 755 | ||
756 | for_each_ebus(ebus) { | 756 | for_each_ebus(ebus) { |
757 | for_each_ebusdev(edev, ebus) { | 757 | for_each_ebusdev(edev, ebus) { |
758 | if (!strcmp(edev->prom_name, WD_OBPNAME)) | 758 | if (!strcmp(edev->ofdev.node->name, WD_OBPNAME)) |
759 | goto ebus_done; | 759 | goto ebus_done; |
760 | } | 760 | } |
761 | } | 761 | } |
diff --git a/drivers/sbus/char/openprom.c b/drivers/sbus/char/openprom.c index cf5b476b5496..d7e4bb41bd79 100644 --- a/drivers/sbus/char/openprom.c +++ b/drivers/sbus/char/openprom.c | |||
@@ -29,8 +29,6 @@ | |||
29 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 29 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
30 | */ | 30 | */ |
31 | 31 | ||
32 | #define PROMLIB_INTERNAL | ||
33 | |||
34 | #include <linux/config.h> | 32 | #include <linux/config.h> |
35 | #include <linux/module.h> | 33 | #include <linux/module.h> |
36 | #include <linux/kernel.h> | 34 | #include <linux/kernel.h> |
@@ -39,10 +37,10 @@ | |||
39 | #include <linux/slab.h> | 37 | #include <linux/slab.h> |
40 | #include <linux/string.h> | 38 | #include <linux/string.h> |
41 | #include <linux/miscdevice.h> | 39 | #include <linux/miscdevice.h> |
42 | #include <linux/smp_lock.h> | ||
43 | #include <linux/init.h> | 40 | #include <linux/init.h> |
44 | #include <linux/fs.h> | 41 | #include <linux/fs.h> |
45 | #include <asm/oplib.h> | 42 | #include <asm/oplib.h> |
43 | #include <asm/prom.h> | ||
46 | #include <asm/system.h> | 44 | #include <asm/system.h> |
47 | #include <asm/uaccess.h> | 45 | #include <asm/uaccess.h> |
48 | #include <asm/openpromio.h> | 46 | #include <asm/openpromio.h> |
@@ -51,15 +49,20 @@ | |||
51 | #include <asm/pbm.h> | 49 | #include <asm/pbm.h> |
52 | #endif | 50 | #endif |
53 | 51 | ||
52 | MODULE_AUTHOR("Thomas K. Dyas (tdyas@noc.rutgers.edu) and Eddie C. Dost (ecd@skynet.be)"); | ||
53 | MODULE_DESCRIPTION("OPENPROM Configuration Driver"); | ||
54 | MODULE_LICENSE("GPL"); | ||
55 | MODULE_VERSION("1.0"); | ||
56 | |||
54 | /* Private data kept by the driver for each descriptor. */ | 57 | /* Private data kept by the driver for each descriptor. */ |
55 | typedef struct openprom_private_data | 58 | typedef struct openprom_private_data |
56 | { | 59 | { |
57 | int current_node; /* Current node for SunOS ioctls. */ | 60 | struct device_node *current_node; /* Current node for SunOS ioctls. */ |
58 | int lastnode; /* Last valid node used by BSD ioctls. */ | 61 | struct device_node *lastnode; /* Last valid node used by BSD ioctls. */ |
59 | } DATA; | 62 | } DATA; |
60 | 63 | ||
61 | /* ID of the PROM node containing all of the EEPROM options. */ | 64 | /* ID of the PROM node containing all of the EEPROM options. */ |
62 | static int options_node = 0; | 65 | static struct device_node *options_node; |
63 | 66 | ||
64 | /* | 67 | /* |
65 | * Copy an openpromio structure into kernel space from user space. | 68 | * Copy an openpromio structure into kernel space from user space. |
@@ -87,9 +90,8 @@ static int copyin(struct openpromio __user *info, struct openpromio **opp_p) | |||
87 | if (bufsize > OPROMMAXPARAM) | 90 | if (bufsize > OPROMMAXPARAM) |
88 | bufsize = OPROMMAXPARAM; | 91 | bufsize = OPROMMAXPARAM; |
89 | 92 | ||
90 | if (!(*opp_p = kmalloc(sizeof(int) + bufsize + 1, GFP_KERNEL))) | 93 | if (!(*opp_p = kzalloc(sizeof(int) + bufsize + 1, GFP_KERNEL))) |
91 | return -ENOMEM; | 94 | return -ENOMEM; |
92 | memset(*opp_p, 0, sizeof(int) + bufsize + 1); | ||
93 | 95 | ||
94 | if (copy_from_user(&(*opp_p)->oprom_array, | 96 | if (copy_from_user(&(*opp_p)->oprom_array, |
95 | &info->oprom_array, bufsize)) { | 97 | &info->oprom_array, bufsize)) { |
@@ -107,10 +109,9 @@ static int getstrings(struct openpromio __user *info, struct openpromio **opp_p) | |||
107 | if (!info || !opp_p) | 109 | if (!info || !opp_p) |
108 | return -EFAULT; | 110 | return -EFAULT; |
109 | 111 | ||
110 | if (!(*opp_p = kmalloc(sizeof(int) + OPROMMAXPARAM + 1, GFP_KERNEL))) | 112 | if (!(*opp_p = kzalloc(sizeof(int) + OPROMMAXPARAM + 1, GFP_KERNEL))) |
111 | return -ENOMEM; | 113 | return -ENOMEM; |
112 | 114 | ||
113 | memset(*opp_p, 0, sizeof(int) + OPROMMAXPARAM + 1); | ||
114 | (*opp_p)->oprom_size = 0; | 115 | (*opp_p)->oprom_size = 0; |
115 | 116 | ||
116 | n = bufsize = 0; | 117 | n = bufsize = 0; |
@@ -140,16 +141,164 @@ static int copyout(void __user *info, struct openpromio *opp, int len) | |||
140 | return 0; | 141 | return 0; |
141 | } | 142 | } |
142 | 143 | ||
144 | static int opromgetprop(void __user *argp, struct device_node *dp, struct openpromio *op, int bufsize) | ||
145 | { | ||
146 | void *pval; | ||
147 | int len; | ||
148 | |||
149 | pval = of_get_property(dp, op->oprom_array, &len); | ||
150 | if (!pval || len <= 0 || len > bufsize) | ||
151 | return copyout(argp, op, sizeof(int)); | ||
152 | |||
153 | memcpy(op->oprom_array, pval, len); | ||
154 | op->oprom_array[len] = '\0'; | ||
155 | op->oprom_size = len; | ||
156 | |||
157 | return copyout(argp, op, sizeof(int) + bufsize); | ||
158 | } | ||
159 | |||
160 | static int opromnxtprop(void __user *argp, struct device_node *dp, struct openpromio *op, int bufsize) | ||
161 | { | ||
162 | struct property *prop; | ||
163 | int len; | ||
164 | |||
165 | if (op->oprom_array[0] == '\0') { | ||
166 | prop = dp->properties; | ||
167 | if (!prop) | ||
168 | return copyout(argp, op, sizeof(int)); | ||
169 | len = strlen(prop->name); | ||
170 | } else { | ||
171 | prop = of_find_property(dp, op->oprom_array, NULL); | ||
172 | |||
173 | if (!prop || | ||
174 | !prop->next || | ||
175 | (len = strlen(prop->next->name)) + 1 > bufsize) | ||
176 | return copyout(argp, op, sizeof(int)); | ||
177 | |||
178 | prop = prop->next; | ||
179 | } | ||
180 | |||
181 | memcpy(op->oprom_array, prop->name, len); | ||
182 | op->oprom_array[len] = '\0'; | ||
183 | op->oprom_size = ++len; | ||
184 | |||
185 | return copyout(argp, op, sizeof(int) + bufsize); | ||
186 | } | ||
187 | |||
188 | static int opromsetopt(struct device_node *dp, struct openpromio *op, int bufsize) | ||
189 | { | ||
190 | char *buf = op->oprom_array + strlen(op->oprom_array) + 1; | ||
191 | int len = op->oprom_array + bufsize - buf; | ||
192 | |||
193 | return of_set_property(options_node, op->oprom_array, buf, len); | ||
194 | } | ||
195 | |||
196 | static int opromnext(void __user *argp, unsigned int cmd, struct device_node *dp, struct openpromio *op, int bufsize, DATA *data) | ||
197 | { | ||
198 | phandle ph; | ||
199 | |||
200 | BUILD_BUG_ON(sizeof(phandle) != sizeof(int)); | ||
201 | |||
202 | if (bufsize < sizeof(phandle)) | ||
203 | return -EINVAL; | ||
204 | |||
205 | ph = *((int *) op->oprom_array); | ||
206 | if (ph) { | ||
207 | dp = of_find_node_by_phandle(ph); | ||
208 | if (!dp) | ||
209 | return -EINVAL; | ||
210 | |||
211 | switch (cmd) { | ||
212 | case OPROMNEXT: | ||
213 | dp = dp->sibling; | ||
214 | break; | ||
215 | |||
216 | case OPROMCHILD: | ||
217 | dp = dp->child; | ||
218 | break; | ||
219 | |||
220 | case OPROMSETCUR: | ||
221 | default: | ||
222 | break; | ||
223 | }; | ||
224 | } else { | ||
225 | /* Sibling of node zero is the root node. */ | ||
226 | if (cmd != OPROMNEXT) | ||
227 | return -EINVAL; | ||
228 | |||
229 | dp = of_find_node_by_path("/"); | ||
230 | } | ||
231 | |||
232 | ph = 0; | ||
233 | if (dp) | ||
234 | ph = dp->node; | ||
235 | |||
236 | data->current_node = dp; | ||
237 | *((int *) op->oprom_array) = ph; | ||
238 | op->oprom_size = sizeof(phandle); | ||
239 | |||
240 | return copyout(argp, op, bufsize + sizeof(int)); | ||
241 | } | ||
242 | |||
243 | static int oprompci2node(void __user *argp, struct device_node *dp, struct openpromio *op, int bufsize, DATA *data) | ||
244 | { | ||
245 | int err = -EINVAL; | ||
246 | |||
247 | if (bufsize >= 2*sizeof(int)) { | ||
248 | #ifdef CONFIG_PCI | ||
249 | struct pci_dev *pdev; | ||
250 | struct pcidev_cookie *pcp; | ||
251 | pdev = pci_find_slot (((int *) op->oprom_array)[0], | ||
252 | ((int *) op->oprom_array)[1]); | ||
253 | |||
254 | pcp = pdev->sysdata; | ||
255 | if (pcp != NULL) { | ||
256 | dp = pcp->prom_node; | ||
257 | data->current_node = dp; | ||
258 | *((int *)op->oprom_array) = dp->node; | ||
259 | op->oprom_size = sizeof(int); | ||
260 | err = copyout(argp, op, bufsize + sizeof(int)); | ||
261 | } | ||
262 | #endif | ||
263 | } | ||
264 | |||
265 | return err; | ||
266 | } | ||
267 | |||
268 | static int oprompath2node(void __user *argp, struct device_node *dp, struct openpromio *op, int bufsize, DATA *data) | ||
269 | { | ||
270 | dp = of_find_node_by_path(op->oprom_array); | ||
271 | data->current_node = dp; | ||
272 | *((int *)op->oprom_array) = dp->node; | ||
273 | op->oprom_size = sizeof(int); | ||
274 | |||
275 | return copyout(argp, op, bufsize + sizeof(int)); | ||
276 | } | ||
277 | |||
278 | static int opromgetbootargs(void __user *argp, struct openpromio *op, int bufsize) | ||
279 | { | ||
280 | char *buf = saved_command_line; | ||
281 | int len = strlen(buf); | ||
282 | |||
283 | if (len > bufsize) | ||
284 | return -EINVAL; | ||
285 | |||
286 | strcpy(op->oprom_array, buf); | ||
287 | op->oprom_size = len; | ||
288 | |||
289 | return copyout(argp, op, bufsize + sizeof(int)); | ||
290 | } | ||
291 | |||
143 | /* | 292 | /* |
144 | * SunOS and Solaris /dev/openprom ioctl calls. | 293 | * SunOS and Solaris /dev/openprom ioctl calls. |
145 | */ | 294 | */ |
146 | static int openprom_sunos_ioctl(struct inode * inode, struct file * file, | 295 | static int openprom_sunos_ioctl(struct inode * inode, struct file * file, |
147 | unsigned int cmd, unsigned long arg, int node) | 296 | unsigned int cmd, unsigned long arg, |
297 | struct device_node *dp) | ||
148 | { | 298 | { |
149 | DATA *data = (DATA *) file->private_data; | 299 | DATA *data = file->private_data; |
150 | char buffer[OPROMMAXPARAM+1], *buf; | ||
151 | struct openpromio *opp; | 300 | struct openpromio *opp; |
152 | int bufsize, len, error = 0; | 301 | int bufsize, error = 0; |
153 | static int cnt; | 302 | static int cnt; |
154 | void __user *argp = (void __user *)arg; | 303 | void __user *argp = (void __user *)arg; |
155 | 304 | ||
@@ -164,119 +313,35 @@ static int openprom_sunos_ioctl(struct inode * inode, struct file * file, | |||
164 | switch (cmd) { | 313 | switch (cmd) { |
165 | case OPROMGETOPT: | 314 | case OPROMGETOPT: |
166 | case OPROMGETPROP: | 315 | case OPROMGETPROP: |
167 | len = prom_getproplen(node, opp->oprom_array); | 316 | error = opromgetprop(argp, dp, opp, bufsize); |
168 | |||
169 | if (len <= 0 || len > bufsize) { | ||
170 | error = copyout(argp, opp, sizeof(int)); | ||
171 | break; | ||
172 | } | ||
173 | |||
174 | len = prom_getproperty(node, opp->oprom_array, buffer, bufsize); | ||
175 | |||
176 | memcpy(opp->oprom_array, buffer, len); | ||
177 | opp->oprom_array[len] = '\0'; | ||
178 | opp->oprom_size = len; | ||
179 | |||
180 | error = copyout(argp, opp, sizeof(int) + bufsize); | ||
181 | break; | 317 | break; |
182 | 318 | ||
183 | case OPROMNXTOPT: | 319 | case OPROMNXTOPT: |
184 | case OPROMNXTPROP: | 320 | case OPROMNXTPROP: |
185 | buf = prom_nextprop(node, opp->oprom_array, buffer); | 321 | error = opromnxtprop(argp, dp, opp, bufsize); |
186 | |||
187 | len = strlen(buf); | ||
188 | if (len == 0 || len + 1 > bufsize) { | ||
189 | error = copyout(argp, opp, sizeof(int)); | ||
190 | break; | ||
191 | } | ||
192 | |||
193 | memcpy(opp->oprom_array, buf, len); | ||
194 | opp->oprom_array[len] = '\0'; | ||
195 | opp->oprom_size = ++len; | ||
196 | |||
197 | error = copyout(argp, opp, sizeof(int) + bufsize); | ||
198 | break; | 322 | break; |
199 | 323 | ||
200 | case OPROMSETOPT: | 324 | case OPROMSETOPT: |
201 | case OPROMSETOPT2: | 325 | case OPROMSETOPT2: |
202 | buf = opp->oprom_array + strlen(opp->oprom_array) + 1; | 326 | error = opromsetopt(dp, opp, bufsize); |
203 | len = opp->oprom_array + bufsize - buf; | ||
204 | |||
205 | error = prom_setprop(options_node, opp->oprom_array, | ||
206 | buf, len); | ||
207 | |||
208 | if (error < 0) | ||
209 | error = -EINVAL; | ||
210 | break; | 327 | break; |
211 | 328 | ||
212 | case OPROMNEXT: | 329 | case OPROMNEXT: |
213 | case OPROMCHILD: | 330 | case OPROMCHILD: |
214 | case OPROMSETCUR: | 331 | case OPROMSETCUR: |
215 | if (bufsize < sizeof(int)) { | 332 | error = opromnext(argp, cmd, dp, opp, bufsize, data); |
216 | error = -EINVAL; | ||
217 | break; | ||
218 | } | ||
219 | |||
220 | node = *((int *) opp->oprom_array); | ||
221 | |||
222 | switch (cmd) { | ||
223 | case OPROMNEXT: node = __prom_getsibling(node); break; | ||
224 | case OPROMCHILD: node = __prom_getchild(node); break; | ||
225 | case OPROMSETCUR: break; | ||
226 | } | ||
227 | |||
228 | data->current_node = node; | ||
229 | *((int *)opp->oprom_array) = node; | ||
230 | opp->oprom_size = sizeof(int); | ||
231 | |||
232 | error = copyout(argp, opp, bufsize + sizeof(int)); | ||
233 | break; | 333 | break; |
234 | 334 | ||
235 | case OPROMPCI2NODE: | 335 | case OPROMPCI2NODE: |
236 | error = -EINVAL; | 336 | error = oprompci2node(argp, dp, opp, bufsize, data); |
237 | |||
238 | if (bufsize >= 2*sizeof(int)) { | ||
239 | #ifdef CONFIG_PCI | ||
240 | struct pci_dev *pdev; | ||
241 | struct pcidev_cookie *pcp; | ||
242 | pdev = pci_find_slot (((int *) opp->oprom_array)[0], | ||
243 | ((int *) opp->oprom_array)[1]); | ||
244 | |||
245 | pcp = pdev->sysdata; | ||
246 | if (pcp != NULL) { | ||
247 | node = pcp->prom_node->node; | ||
248 | data->current_node = node; | ||
249 | *((int *)opp->oprom_array) = node; | ||
250 | opp->oprom_size = sizeof(int); | ||
251 | error = copyout(argp, opp, bufsize + sizeof(int)); | ||
252 | } | ||
253 | #endif | ||
254 | } | ||
255 | break; | 337 | break; |
256 | 338 | ||
257 | case OPROMPATH2NODE: | 339 | case OPROMPATH2NODE: |
258 | node = prom_finddevice(opp->oprom_array); | 340 | error = oprompath2node(argp, dp, opp, bufsize, data); |
259 | data->current_node = node; | ||
260 | *((int *)opp->oprom_array) = node; | ||
261 | opp->oprom_size = sizeof(int); | ||
262 | |||
263 | error = copyout(argp, opp, bufsize + sizeof(int)); | ||
264 | break; | 341 | break; |
265 | 342 | ||
266 | case OPROMGETBOOTARGS: | 343 | case OPROMGETBOOTARGS: |
267 | buf = saved_command_line; | 344 | error = opromgetbootargs(argp, opp, bufsize); |
268 | |||
269 | len = strlen(buf); | ||
270 | |||
271 | if (len > bufsize) { | ||
272 | error = -EINVAL; | ||
273 | break; | ||
274 | } | ||
275 | |||
276 | strcpy(opp->oprom_array, buf); | ||
277 | opp->oprom_size = len; | ||
278 | |||
279 | error = copyout(argp, opp, bufsize + sizeof(int)); | ||
280 | break; | 345 | break; |
281 | 346 | ||
282 | case OPROMU2P: | 347 | case OPROMU2P: |
@@ -297,25 +362,14 @@ static int openprom_sunos_ioctl(struct inode * inode, struct file * file, | |||
297 | return error; | 362 | return error; |
298 | } | 363 | } |
299 | 364 | ||
300 | 365 | static struct device_node *get_node(phandle n, DATA *data) | |
301 | /* Return nonzero if a specific node is in the PROM device tree. */ | ||
302 | static int intree(int root, int node) | ||
303 | { | 366 | { |
304 | for (; root != 0; root = prom_getsibling(root)) | 367 | struct device_node *dp = of_find_node_by_phandle(n); |
305 | if (root == node || intree(prom_getchild(root),node)) | ||
306 | return 1; | ||
307 | return 0; | ||
308 | } | ||
309 | 368 | ||
310 | /* Return nonzero if a specific node is "valid". */ | 369 | if (dp) |
311 | static int goodnode(int n, DATA *data) | 370 | data->lastnode = dp; |
312 | { | 371 | |
313 | if (n == data->lastnode || n == prom_root_node || n == options_node) | 372 | return dp; |
314 | return 1; | ||
315 | if (n == 0 || n == -1 || !intree(prom_root_node,n)) | ||
316 | return 0; | ||
317 | data->lastnode = n; | ||
318 | return 1; | ||
319 | } | 373 | } |
320 | 374 | ||
321 | /* Copy in a whole string from userspace into kernelspace. */ | 375 | /* Copy in a whole string from userspace into kernelspace. */ |
@@ -330,7 +384,7 @@ static int copyin_string(char __user *user, size_t len, char **ptr) | |||
330 | if (!tmp) | 384 | if (!tmp) |
331 | return -ENOMEM; | 385 | return -ENOMEM; |
332 | 386 | ||
333 | if(copy_from_user(tmp, user, len)) { | 387 | if (copy_from_user(tmp, user, len)) { |
334 | kfree(tmp); | 388 | kfree(tmp); |
335 | return -EFAULT; | 389 | return -EFAULT; |
336 | } | 390 | } |
@@ -345,162 +399,187 @@ static int copyin_string(char __user *user, size_t len, char **ptr) | |||
345 | /* | 399 | /* |
346 | * NetBSD /dev/openprom ioctl calls. | 400 | * NetBSD /dev/openprom ioctl calls. |
347 | */ | 401 | */ |
348 | static int openprom_bsd_ioctl(struct inode * inode, struct file * file, | 402 | static int opiocget(void __user *argp, DATA *data) |
349 | unsigned int cmd, unsigned long arg) | ||
350 | { | 403 | { |
351 | DATA *data = (DATA *) file->private_data; | ||
352 | void __user *argp = (void __user *)arg; | ||
353 | struct opiocdesc op; | 404 | struct opiocdesc op; |
354 | int error, node, len; | 405 | struct device_node *dp; |
355 | char *str, *tmp; | 406 | char *str; |
356 | char buffer[64]; | 407 | void *pval; |
357 | static int cnt; | 408 | int err, len; |
358 | |||
359 | switch (cmd) { | ||
360 | case OPIOCGET: | ||
361 | if (copy_from_user(&op, argp, sizeof(op))) | ||
362 | return -EFAULT; | ||
363 | |||
364 | if (!goodnode(op.op_nodeid,data)) | ||
365 | return -EINVAL; | ||
366 | 409 | ||
367 | error = copyin_string(op.op_name, op.op_namelen, &str); | 410 | if (copy_from_user(&op, argp, sizeof(op))) |
368 | if (error) | 411 | return -EFAULT; |
369 | return error; | ||
370 | 412 | ||
371 | len = prom_getproplen(op.op_nodeid,str); | 413 | dp = get_node(op.op_nodeid, data); |
372 | 414 | ||
373 | if (len > op.op_buflen) { | 415 | err = copyin_string(op.op_name, op.op_namelen, &str); |
374 | kfree(str); | 416 | if (err) |
375 | return -ENOMEM; | 417 | return err; |
376 | } | ||
377 | 418 | ||
419 | pval = of_get_property(dp, str, &len); | ||
420 | err = 0; | ||
421 | if (!pval || len > op.op_buflen) { | ||
422 | err = -EINVAL; | ||
423 | } else { | ||
378 | op.op_buflen = len; | 424 | op.op_buflen = len; |
425 | if (copy_to_user(argp, &op, sizeof(op)) || | ||
426 | copy_to_user(op.op_buf, pval, len)) | ||
427 | err = -EFAULT; | ||
428 | } | ||
429 | kfree(str); | ||
379 | 430 | ||
380 | if (len <= 0) { | 431 | return err; |
381 | kfree(str); | 432 | } |
382 | /* Verified by the above copy_from_user */ | ||
383 | if (__copy_to_user(argp, &op, | ||
384 | sizeof(op))) | ||
385 | return -EFAULT; | ||
386 | return 0; | ||
387 | } | ||
388 | 433 | ||
389 | tmp = kmalloc(len + 1, GFP_KERNEL); | 434 | static int opiocnextprop(void __user *argp, DATA *data) |
390 | if (!tmp) { | 435 | { |
391 | kfree(str); | 436 | struct opiocdesc op; |
392 | return -ENOMEM; | 437 | struct device_node *dp; |
393 | } | 438 | struct property *prop; |
439 | char *str; | ||
440 | int err, len; | ||
394 | 441 | ||
395 | cnt = prom_getproperty(op.op_nodeid, str, tmp, len); | 442 | if (copy_from_user(&op, argp, sizeof(op))) |
396 | if (cnt <= 0) { | 443 | return -EFAULT; |
397 | error = -EINVAL; | ||
398 | } else { | ||
399 | tmp[len] = '\0'; | ||
400 | 444 | ||
401 | if (__copy_to_user(argp, &op, sizeof(op)) != 0 || | 445 | dp = get_node(op.op_nodeid, data); |
402 | copy_to_user(op.op_buf, tmp, len) != 0) | 446 | if (!dp) |
403 | error = -EFAULT; | 447 | return -EINVAL; |
404 | } | ||
405 | 448 | ||
406 | kfree(tmp); | 449 | err = copyin_string(op.op_name, op.op_namelen, &str); |
407 | kfree(str); | 450 | if (err) |
451 | return err; | ||
408 | 452 | ||
409 | return error; | 453 | if (str[0] == '\0') { |
454 | prop = dp->properties; | ||
455 | } else { | ||
456 | prop = of_find_property(dp, str, NULL); | ||
457 | if (prop) | ||
458 | prop = prop->next; | ||
459 | } | ||
460 | kfree(str); | ||
410 | 461 | ||
411 | case OPIOCNEXTPROP: | 462 | if (!prop) |
412 | if (copy_from_user(&op, argp, sizeof(op))) | 463 | len = 0; |
413 | return -EFAULT; | 464 | else |
465 | len = prop->length; | ||
414 | 466 | ||
415 | if (!goodnode(op.op_nodeid,data)) | 467 | if (len > op.op_buflen) |
416 | return -EINVAL; | 468 | len = op.op_buflen; |
417 | 469 | ||
418 | error = copyin_string(op.op_name, op.op_namelen, &str); | 470 | if (copy_to_user(argp, &op, sizeof(op))) |
419 | if (error) | 471 | return -EFAULT; |
420 | return error; | ||
421 | 472 | ||
422 | tmp = prom_nextprop(op.op_nodeid,str,buffer); | 473 | if (len && |
474 | copy_to_user(op.op_buf, prop->value, len)) | ||
475 | return -EFAULT; | ||
423 | 476 | ||
424 | if (tmp) { | 477 | return 0; |
425 | len = strlen(tmp); | 478 | } |
426 | if (len > op.op_buflen) | ||
427 | len = op.op_buflen; | ||
428 | else | ||
429 | op.op_buflen = len; | ||
430 | } else { | ||
431 | len = op.op_buflen = 0; | ||
432 | } | ||
433 | 479 | ||
434 | if (!access_ok(VERIFY_WRITE, argp, sizeof(op))) { | 480 | static int opiocset(void __user *argp, DATA *data) |
435 | kfree(str); | 481 | { |
436 | return -EFAULT; | 482 | struct opiocdesc op; |
437 | } | 483 | struct device_node *dp; |
484 | char *str, *tmp; | ||
485 | int err; | ||
438 | 486 | ||
439 | if (!access_ok(VERIFY_WRITE, op.op_buf, len)) { | 487 | if (copy_from_user(&op, argp, sizeof(op))) |
440 | kfree(str); | 488 | return -EFAULT; |
441 | return -EFAULT; | 489 | |
442 | } | 490 | dp = get_node(op.op_nodeid, data); |
491 | if (!dp) | ||
492 | return -EINVAL; | ||
443 | 493 | ||
444 | error = __copy_to_user(argp, &op, sizeof(op)); | 494 | err = copyin_string(op.op_name, op.op_namelen, &str); |
445 | if (!error) error = __copy_to_user(op.op_buf, tmp, len); | 495 | if (err) |
496 | return err; | ||
446 | 497 | ||
498 | err = copyin_string(op.op_buf, op.op_buflen, &tmp); | ||
499 | if (err) { | ||
447 | kfree(str); | 500 | kfree(str); |
501 | return err; | ||
502 | } | ||
448 | 503 | ||
449 | return error; | 504 | err = of_set_property(dp, str, tmp, op.op_buflen); |
450 | 505 | ||
451 | case OPIOCSET: | 506 | kfree(str); |
452 | if (copy_from_user(&op, argp, sizeof(op))) | 507 | kfree(tmp); |
453 | return -EFAULT; | ||
454 | 508 | ||
455 | if (!goodnode(op.op_nodeid,data)) | 509 | return err; |
456 | return -EINVAL; | 510 | } |
457 | 511 | ||
458 | error = copyin_string(op.op_name, op.op_namelen, &str); | 512 | static int opiocgetnext(unsigned int cmd, void __user *argp) |
459 | if (error) | 513 | { |
460 | return error; | 514 | struct device_node *dp; |
515 | phandle nd; | ||
461 | 516 | ||
462 | error = copyin_string(op.op_buf, op.op_buflen, &tmp); | 517 | BUILD_BUG_ON(sizeof(phandle) != sizeof(int)); |
463 | if (error) { | ||
464 | kfree(str); | ||
465 | return error; | ||
466 | } | ||
467 | 518 | ||
468 | len = prom_setprop(op.op_nodeid,str,tmp,op.op_buflen+1); | 519 | if (copy_from_user(&nd, argp, sizeof(phandle))) |
520 | return -EFAULT; | ||
469 | 521 | ||
470 | if (len != op.op_buflen) | 522 | if (nd == 0) { |
523 | if (cmd != OPIOCGETNEXT) | ||
471 | return -EINVAL; | 524 | return -EINVAL; |
525 | dp = of_find_node_by_path("/"); | ||
526 | } else { | ||
527 | dp = of_find_node_by_phandle(nd); | ||
528 | nd = 0; | ||
529 | if (dp) { | ||
530 | if (cmd == OPIOCGETNEXT) | ||
531 | dp = dp->sibling; | ||
532 | else | ||
533 | dp = dp->child; | ||
534 | } | ||
535 | } | ||
536 | if (dp) | ||
537 | nd = dp->node; | ||
538 | if (copy_to_user(argp, &nd, sizeof(phandle))) | ||
539 | return -EFAULT; | ||
472 | 540 | ||
473 | kfree(str); | 541 | return 0; |
474 | kfree(tmp); | 542 | } |
475 | 543 | ||
476 | return 0; | 544 | static int openprom_bsd_ioctl(struct inode * inode, struct file * file, |
545 | unsigned int cmd, unsigned long arg) | ||
546 | { | ||
547 | DATA *data = (DATA *) file->private_data; | ||
548 | void __user *argp = (void __user *)arg; | ||
549 | int err; | ||
477 | 550 | ||
478 | case OPIOCGETOPTNODE: | 551 | switch (cmd) { |
479 | if (copy_to_user(argp, &options_node, sizeof(int))) | 552 | case OPIOCGET: |
480 | return -EFAULT; | 553 | err = opiocget(argp, data); |
481 | return 0; | 554 | break; |
482 | 555 | ||
483 | case OPIOCGETNEXT: | 556 | case OPIOCNEXTPROP: |
484 | case OPIOCGETCHILD: | 557 | err = opiocnextprop(argp, data); |
485 | if (copy_from_user(&node, argp, sizeof(int))) | 558 | break; |
486 | return -EFAULT; | ||
487 | 559 | ||
488 | if (cmd == OPIOCGETNEXT) | 560 | case OPIOCSET: |
489 | node = __prom_getsibling(node); | 561 | err = opiocset(argp, data); |
490 | else | 562 | break; |
491 | node = __prom_getchild(node); | 563 | |
564 | case OPIOCGETOPTNODE: | ||
565 | BUILD_BUG_ON(sizeof(phandle) != sizeof(int)); | ||
492 | 566 | ||
493 | if (__copy_to_user(argp, &node, sizeof(int))) | 567 | if (copy_to_user(argp, &options_node->node, sizeof(phandle))) |
494 | return -EFAULT; | 568 | return -EFAULT; |
495 | 569 | ||
496 | return 0; | 570 | return 0; |
497 | 571 | ||
572 | case OPIOCGETNEXT: | ||
573 | case OPIOCGETCHILD: | ||
574 | err = opiocgetnext(cmd, argp); | ||
575 | break; | ||
576 | |||
498 | default: | 577 | default: |
499 | if (cnt++ < 10) | ||
500 | printk(KERN_INFO "openprom_bsd_ioctl: cmd 0x%X\n", cmd); | ||
501 | return -EINVAL; | 578 | return -EINVAL; |
502 | 579 | ||
503 | } | 580 | }; |
581 | |||
582 | return err; | ||
504 | } | 583 | } |
505 | 584 | ||
506 | 585 | ||
@@ -511,7 +590,6 @@ static int openprom_ioctl(struct inode * inode, struct file * file, | |||
511 | unsigned int cmd, unsigned long arg) | 590 | unsigned int cmd, unsigned long arg) |
512 | { | 591 | { |
513 | DATA *data = (DATA *) file->private_data; | 592 | DATA *data = (DATA *) file->private_data; |
514 | static int cnt; | ||
515 | 593 | ||
516 | switch (cmd) { | 594 | switch (cmd) { |
517 | case OPROMGETOPT: | 595 | case OPROMGETOPT: |
@@ -563,10 +641,8 @@ static int openprom_ioctl(struct inode * inode, struct file * file, | |||
563 | return openprom_bsd_ioctl(inode,file,cmd,arg); | 641 | return openprom_bsd_ioctl(inode,file,cmd,arg); |
564 | 642 | ||
565 | default: | 643 | default: |
566 | if (cnt++ < 10) | ||
567 | printk("openprom_ioctl: cmd 0x%X, arg 0x%lX\n", cmd, arg); | ||
568 | return -EINVAL; | 644 | return -EINVAL; |
569 | } | 645 | }; |
570 | } | 646 | } |
571 | 647 | ||
572 | static long openprom_compat_ioctl(struct file *file, unsigned int cmd, | 648 | static long openprom_compat_ioctl(struct file *file, unsigned int cmd, |
@@ -594,9 +670,7 @@ static long openprom_compat_ioctl(struct file *file, unsigned int cmd, | |||
594 | case OPROMSETCUR: | 670 | case OPROMSETCUR: |
595 | case OPROMPCI2NODE: | 671 | case OPROMPCI2NODE: |
596 | case OPROMPATH2NODE: | 672 | case OPROMPATH2NODE: |
597 | lock_kernel(); | ||
598 | rval = openprom_ioctl(file->f_dentry->d_inode, file, cmd, arg); | 673 | rval = openprom_ioctl(file->f_dentry->d_inode, file, cmd, arg); |
599 | lock_kernel(); | ||
600 | break; | 674 | break; |
601 | } | 675 | } |
602 | 676 | ||
@@ -607,13 +681,13 @@ static int openprom_open(struct inode * inode, struct file * file) | |||
607 | { | 681 | { |
608 | DATA *data; | 682 | DATA *data; |
609 | 683 | ||
610 | data = (DATA *) kmalloc(sizeof(DATA), GFP_KERNEL); | 684 | data = kmalloc(sizeof(DATA), GFP_KERNEL); |
611 | if (!data) | 685 | if (!data) |
612 | return -ENOMEM; | 686 | return -ENOMEM; |
613 | 687 | ||
614 | data->current_node = prom_root_node; | 688 | data->current_node = of_find_node_by_path("/"); |
615 | data->lastnode = prom_root_node; | 689 | data->lastnode = data->current_node; |
616 | file->private_data = (void *)data; | 690 | file->private_data = (void *) data; |
617 | 691 | ||
618 | return 0; | 692 | return 0; |
619 | } | 693 | } |
@@ -634,24 +708,30 @@ static struct file_operations openprom_fops = { | |||
634 | }; | 708 | }; |
635 | 709 | ||
636 | static struct miscdevice openprom_dev = { | 710 | static struct miscdevice openprom_dev = { |
637 | SUN_OPENPROM_MINOR, "openprom", &openprom_fops | 711 | .minor = SUN_OPENPROM_MINOR, |
712 | .name = "openprom", | ||
713 | .fops = &openprom_fops, | ||
638 | }; | 714 | }; |
639 | 715 | ||
640 | static int __init openprom_init(void) | 716 | static int __init openprom_init(void) |
641 | { | 717 | { |
642 | int error; | 718 | struct device_node *dp; |
719 | int err; | ||
643 | 720 | ||
644 | error = misc_register(&openprom_dev); | 721 | err = misc_register(&openprom_dev); |
645 | if (error) { | 722 | if (err) |
646 | printk(KERN_ERR "openprom: unable to get misc minor\n"); | 723 | return err; |
647 | return error; | ||
648 | } | ||
649 | 724 | ||
650 | options_node = prom_getchild(prom_root_node); | 725 | dp = of_find_node_by_path("/"); |
651 | options_node = prom_searchsiblings(options_node,"options"); | 726 | dp = dp->child; |
727 | while (dp) { | ||
728 | if (!strcmp(dp->name, "options")) | ||
729 | break; | ||
730 | dp = dp->sibling; | ||
731 | } | ||
732 | options_node = dp; | ||
652 | 733 | ||
653 | if (options_node == 0 || options_node == -1) { | 734 | if (!options_node) { |
654 | printk(KERN_ERR "openprom: unable to find options node\n"); | ||
655 | misc_deregister(&openprom_dev); | 735 | misc_deregister(&openprom_dev); |
656 | return -EIO; | 736 | return -EIO; |
657 | } | 737 | } |
@@ -666,4 +746,3 @@ static void __exit openprom_cleanup(void) | |||
666 | 746 | ||
667 | module_init(openprom_init); | 747 | module_init(openprom_init); |
668 | module_exit(openprom_cleanup); | 748 | module_exit(openprom_cleanup); |
669 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/sbus/char/riowatchdog.c b/drivers/sbus/char/riowatchdog.c index d1babff6a535..2a9cc8204429 100644 --- a/drivers/sbus/char/riowatchdog.c +++ b/drivers/sbus/char/riowatchdog.c | |||
@@ -211,7 +211,7 @@ static int __init riowd_bbc_init(void) | |||
211 | 211 | ||
212 | for_each_ebus(ebus) { | 212 | for_each_ebus(ebus) { |
213 | for_each_ebusdev(edev, ebus) { | 213 | for_each_ebusdev(edev, ebus) { |
214 | if (!strcmp(edev->prom_name, "bbc")) | 214 | if (!strcmp(edev->ofdev.node->name, "bbc")) |
215 | goto found_bbc; | 215 | goto found_bbc; |
216 | } | 216 | } |
217 | } | 217 | } |
@@ -238,7 +238,7 @@ static int __init riowd_init(void) | |||
238 | 238 | ||
239 | for_each_ebus(ebus) { | 239 | for_each_ebus(ebus) { |
240 | for_each_ebusdev(edev, ebus) { | 240 | for_each_ebusdev(edev, ebus) { |
241 | if (!strcmp(edev->prom_name, RIOWD_NAME)) | 241 | if (!strcmp(edev->ofdev.node->name, RIOWD_NAME)) |
242 | goto ebus_done; | 242 | goto ebus_done; |
243 | } | 243 | } |
244 | } | 244 | } |
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 44728ae3fe77..96a81cd17617 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig | |||
@@ -501,7 +501,7 @@ config SCSI_ATA_PIIX | |||
501 | tristate "Intel PIIX/ICH SATA support" | 501 | tristate "Intel PIIX/ICH SATA support" |
502 | depends on SCSI_SATA && PCI | 502 | depends on SCSI_SATA && PCI |
503 | help | 503 | help |
504 | This option enables support for ICH5 Serial ATA. | 504 | This option enables support for ICH5/6/7/8 Serial ATA. |
505 | If PATA support was enabled previously, this enables | 505 | If PATA support was enabled previously, this enables |
506 | support for select Intel PIIX/ICH PATA host controllers. | 506 | support for select Intel PIIX/ICH PATA host controllers. |
507 | 507 | ||
@@ -1169,7 +1169,7 @@ config SCSI_NCR_Q720 | |||
1169 | you do not have this SCSI card, so say N. | 1169 | you do not have this SCSI card, so say N. |
1170 | 1170 | ||
1171 | config SCSI_NCR53C8XX_DEFAULT_TAGS | 1171 | config SCSI_NCR53C8XX_DEFAULT_TAGS |
1172 | int " default tagged command queue depth" | 1172 | int "default tagged command queue depth" |
1173 | depends on SCSI_ZALON || SCSI_NCR_Q720 | 1173 | depends on SCSI_ZALON || SCSI_NCR_Q720 |
1174 | default "8" | 1174 | default "8" |
1175 | ---help--- | 1175 | ---help--- |
@@ -1195,7 +1195,7 @@ config SCSI_NCR53C8XX_DEFAULT_TAGS | |||
1195 | There is no safe option other than using good SCSI devices. | 1195 | There is no safe option other than using good SCSI devices. |
1196 | 1196 | ||
1197 | config SCSI_NCR53C8XX_MAX_TAGS | 1197 | config SCSI_NCR53C8XX_MAX_TAGS |
1198 | int " maximum number of queued commands" | 1198 | int "maximum number of queued commands" |
1199 | depends on SCSI_ZALON || SCSI_NCR_Q720 | 1199 | depends on SCSI_ZALON || SCSI_NCR_Q720 |
1200 | default "32" | 1200 | default "32" |
1201 | ---help--- | 1201 | ---help--- |
@@ -1212,7 +1212,7 @@ config SCSI_NCR53C8XX_MAX_TAGS | |||
1212 | There is no safe option and the default answer is recommended. | 1212 | There is no safe option and the default answer is recommended. |
1213 | 1213 | ||
1214 | config SCSI_NCR53C8XX_SYNC | 1214 | config SCSI_NCR53C8XX_SYNC |
1215 | int " synchronous transfers frequency in MHz" | 1215 | int "synchronous transfers frequency in MHz" |
1216 | depends on SCSI_ZALON || SCSI_NCR_Q720 | 1216 | depends on SCSI_ZALON || SCSI_NCR_Q720 |
1217 | default "20" | 1217 | default "20" |
1218 | ---help--- | 1218 | ---help--- |
@@ -1246,7 +1246,7 @@ config SCSI_NCR53C8XX_SYNC | |||
1246 | terminations and SCSI conformant devices. | 1246 | terminations and SCSI conformant devices. |
1247 | 1247 | ||
1248 | config SCSI_NCR53C8XX_PROFILE | 1248 | config SCSI_NCR53C8XX_PROFILE |
1249 | bool " enable profiling" | 1249 | bool "enable profiling" |
1250 | depends on SCSI_ZALON || SCSI_NCR_Q720 | 1250 | depends on SCSI_ZALON || SCSI_NCR_Q720 |
1251 | help | 1251 | help |
1252 | This option allows you to enable profiling information gathering. | 1252 | This option allows you to enable profiling information gathering. |
@@ -1257,7 +1257,7 @@ config SCSI_NCR53C8XX_PROFILE | |||
1257 | The normal answer therefore is N. | 1257 | The normal answer therefore is N. |
1258 | 1258 | ||
1259 | config SCSI_NCR53C8XX_NO_DISCONNECT | 1259 | config SCSI_NCR53C8XX_NO_DISCONNECT |
1260 | bool " not allow targets to disconnect" | 1260 | bool "not allow targets to disconnect" |
1261 | depends on (SCSI_ZALON || SCSI_NCR_Q720) && SCSI_NCR53C8XX_DEFAULT_TAGS=0 | 1261 | depends on (SCSI_ZALON || SCSI_NCR_Q720) && SCSI_NCR53C8XX_DEFAULT_TAGS=0 |
1262 | help | 1262 | help |
1263 | This option is only provided for safety if you suspect some SCSI | 1263 | This option is only provided for safety if you suspect some SCSI |
diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c index fa57e0b4a5fd..75f2f7ae2a8e 100644 --- a/drivers/scsi/NCR5380.c +++ b/drivers/scsi/NCR5380.c | |||
@@ -500,7 +500,7 @@ static void NCR5380_print_phase(struct Scsi_Host *instance) | |||
500 | /* | 500 | /* |
501 | * Function : int should_disconnect (unsigned char cmd) | 501 | * Function : int should_disconnect (unsigned char cmd) |
502 | * | 502 | * |
503 | * Purpose : decide weather a command would normally disconnect or | 503 | * Purpose : decide whether a command would normally disconnect or |
504 | * not, since if it won't disconnect we should go to sleep. | 504 | * not, since if it won't disconnect we should go to sleep. |
505 | * | 505 | * |
506 | * Input : cmd - opcode of SCSI command | 506 | * Input : cmd - opcode of SCSI command |
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index 5ee47555a8af..dd9fb3d91000 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c | |||
@@ -12374,7 +12374,7 @@ AscInitFromEEP(ASC_DVC_VAR *asc_dvc) | |||
12374 | ASC_PRINT1( | 12374 | ASC_PRINT1( |
12375 | "AscInitFromEEP: Failed to re-write EEPROM with %d errors.\n", i); | 12375 | "AscInitFromEEP: Failed to re-write EEPROM with %d errors.\n", i); |
12376 | } else { | 12376 | } else { |
12377 | ASC_PRINT("AscInitFromEEP: Succesfully re-wrote EEPROM."); | 12377 | ASC_PRINT("AscInitFromEEP: Successfully re-wrote EEPROM.\n"); |
12378 | } | 12378 | } |
12379 | } | 12379 | } |
12380 | return (warn_code); | 12380 | return (warn_code); |
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c index 4bb77f62b3b9..f05946777718 100644 --- a/drivers/scsi/ahci.c +++ b/drivers/scsi/ahci.c | |||
@@ -48,7 +48,7 @@ | |||
48 | #include <asm/io.h> | 48 | #include <asm/io.h> |
49 | 49 | ||
50 | #define DRV_NAME "ahci" | 50 | #define DRV_NAME "ahci" |
51 | #define DRV_VERSION "1.3" | 51 | #define DRV_VERSION "2.0" |
52 | 52 | ||
53 | 53 | ||
54 | enum { | 54 | enum { |
diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c index 521b718763f6..94b1261a259d 100644 --- a/drivers/scsi/ata_piix.c +++ b/drivers/scsi/ata_piix.c | |||
@@ -93,7 +93,7 @@ | |||
93 | #include <linux/libata.h> | 93 | #include <linux/libata.h> |
94 | 94 | ||
95 | #define DRV_NAME "ata_piix" | 95 | #define DRV_NAME "ata_piix" |
96 | #define DRV_VERSION "1.10" | 96 | #define DRV_VERSION "2.00" |
97 | 97 | ||
98 | enum { | 98 | enum { |
99 | PIIX_IOCFG = 0x54, /* IDE I/O configuration register */ | 99 | PIIX_IOCFG = 0x54, /* IDE I/O configuration register */ |
diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c index 183245254931..58b0748045ee 100644 --- a/drivers/scsi/dc395x.c +++ b/drivers/scsi/dc395x.c | |||
@@ -3771,7 +3771,7 @@ static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, | |||
3771 | * @target: The target for the new device. | 3771 | * @target: The target for the new device. |
3772 | * @lun: The lun for the new device. | 3772 | * @lun: The lun for the new device. |
3773 | * | 3773 | * |
3774 | * Return the new device if succesfull or NULL on failure. | 3774 | * Return the new device if successful or NULL on failure. |
3775 | **/ | 3775 | **/ |
3776 | static struct DeviceCtlBlk *device_alloc(struct AdapterCtlBlk *acb, | 3776 | static struct DeviceCtlBlk *device_alloc(struct AdapterCtlBlk *acb, |
3777 | u8 target, u8 lun) | 3777 | u8 target, u8 lun) |
diff --git a/drivers/scsi/ibmmca.c b/drivers/scsi/ibmmca.c index 115f55471ed3..497f6642b2dc 100644 --- a/drivers/scsi/ibmmca.c +++ b/drivers/scsi/ibmmca.c | |||
@@ -760,7 +760,7 @@ static int device_inquiry(int host_index, int ldn) | |||
760 | while (!got_interrupt(host_index)) | 760 | while (!got_interrupt(host_index)) |
761 | barrier(); | 761 | barrier(); |
762 | 762 | ||
763 | /*if command succesful, break */ | 763 | /*if command successful, break */ |
764 | if ((stat_result(host_index) == IM_SCB_CMD_COMPLETED) || (stat_result(host_index) == IM_SCB_CMD_COMPLETED_WITH_RETRIES)) | 764 | if ((stat_result(host_index) == IM_SCB_CMD_COMPLETED) || (stat_result(host_index) == IM_SCB_CMD_COMPLETED_WITH_RETRIES)) |
765 | return 1; | 765 | return 1; |
766 | } | 766 | } |
@@ -885,7 +885,7 @@ static int immediate_assign(int host_index, unsigned int pun, unsigned int lun, | |||
885 | while (!got_interrupt(host_index)) | 885 | while (!got_interrupt(host_index)) |
886 | barrier(); | 886 | barrier(); |
887 | 887 | ||
888 | /*if command succesful, break */ | 888 | /*if command successful, break */ |
889 | if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED) | 889 | if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED) |
890 | return 1; | 890 | return 1; |
891 | } | 891 | } |
@@ -921,7 +921,7 @@ static int immediate_feature(int host_index, unsigned int speed, unsigned int ti | |||
921 | return 2; | 921 | return 2; |
922 | } else | 922 | } else |
923 | global_command_error_excuse = 0; | 923 | global_command_error_excuse = 0; |
924 | /*if command succesful, break */ | 924 | /*if command successful, break */ |
925 | if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED) | 925 | if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED) |
926 | return 1; | 926 | return 1; |
927 | } | 927 | } |
@@ -959,7 +959,7 @@ static int immediate_reset(int host_index, unsigned int ldn) | |||
959 | /* did not work, finish */ | 959 | /* did not work, finish */ |
960 | return 1; | 960 | return 1; |
961 | } | 961 | } |
962 | /*if command succesful, break */ | 962 | /*if command successful, break */ |
963 | if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED) | 963 | if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED) |
964 | return 1; | 964 | return 1; |
965 | } | 965 | } |
diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c index cd2dffdab77a..681bd18493f3 100644 --- a/drivers/scsi/imm.c +++ b/drivers/scsi/imm.c | |||
@@ -3,9 +3,6 @@ | |||
3 | * | 3 | * |
4 | * (The IMM is the embedded controller in the ZIP Plus drive.) | 4 | * (The IMM is the embedded controller in the ZIP Plus drive.) |
5 | * | 5 | * |
6 | * Current Maintainer: David Campbell (Perth, Western Australia) | ||
7 | * campbell@torque.net | ||
8 | * | ||
9 | * My unoffical company acronym list is 21 pages long: | 6 | * My unoffical company acronym list is 21 pages long: |
10 | * FLA: Four letter acronym with built in facility for | 7 | * FLA: Four letter acronym with built in facility for |
11 | * future expansion to five letters. | 8 | * future expansion to five letters. |
diff --git a/drivers/scsi/imm.h b/drivers/scsi/imm.h index dc3aebf0e365..ece936ac29c7 100644 --- a/drivers/scsi/imm.h +++ b/drivers/scsi/imm.h | |||
@@ -2,7 +2,7 @@ | |||
2 | /* Driver for the Iomega MatchMaker parallel port SCSI HBA embedded in | 2 | /* Driver for the Iomega MatchMaker parallel port SCSI HBA embedded in |
3 | * the Iomega ZIP Plus drive | 3 | * the Iomega ZIP Plus drive |
4 | * | 4 | * |
5 | * (c) 1998 David Campbell campbell@torque.net | 5 | * (c) 1998 David Campbell |
6 | * | 6 | * |
7 | * Please note that I live in Perth, Western Australia. GMT+0800 | 7 | * Please note that I live in Perth, Western Australia. GMT+0800 |
8 | */ | 8 | */ |
diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c index 5353b28b2939..78f2ff736c3e 100644 --- a/drivers/scsi/ips.c +++ b/drivers/scsi/ips.c | |||
@@ -6438,7 +6438,7 @@ ips_erase_bios(ips_ha_t * ha) | |||
6438 | /* VPP failure */ | 6438 | /* VPP failure */ |
6439 | return (1); | 6439 | return (1); |
6440 | 6440 | ||
6441 | /* check for succesful flash */ | 6441 | /* check for successful flash */ |
6442 | if (status & 0x30) | 6442 | if (status & 0x30) |
6443 | /* sequence error */ | 6443 | /* sequence error */ |
6444 | return (1); | 6444 | return (1); |
@@ -6550,7 +6550,7 @@ ips_erase_bios_memio(ips_ha_t * ha) | |||
6550 | /* VPP failure */ | 6550 | /* VPP failure */ |
6551 | return (1); | 6551 | return (1); |
6552 | 6552 | ||
6553 | /* check for succesful flash */ | 6553 | /* check for successful flash */ |
6554 | if (status & 0x30) | 6554 | if (status & 0x30) |
6555 | /* sequence error */ | 6555 | /* sequence error */ |
6556 | return (1); | 6556 | return (1); |
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 6c66877be2bf..d1c1c30d123f 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c | |||
@@ -88,6 +88,10 @@ int libata_fua = 0; | |||
88 | module_param_named(fua, libata_fua, int, 0444); | 88 | module_param_named(fua, libata_fua, int, 0444); |
89 | MODULE_PARM_DESC(fua, "FUA support (0=off, 1=on)"); | 89 | MODULE_PARM_DESC(fua, "FUA support (0=off, 1=on)"); |
90 | 90 | ||
91 | static int ata_probe_timeout = ATA_TMOUT_INTERNAL / HZ; | ||
92 | module_param(ata_probe_timeout, int, 0444); | ||
93 | MODULE_PARM_DESC(ata_probe_timeout, "Set ATA probing timeout (seconds)"); | ||
94 | |||
91 | MODULE_AUTHOR("Jeff Garzik"); | 95 | MODULE_AUTHOR("Jeff Garzik"); |
92 | MODULE_DESCRIPTION("Library module for ATA devices"); | 96 | MODULE_DESCRIPTION("Library module for ATA devices"); |
93 | MODULE_LICENSE("GPL"); | 97 | MODULE_LICENSE("GPL"); |
@@ -777,11 +781,9 @@ void ata_std_dev_select (struct ata_port *ap, unsigned int device) | |||
777 | void ata_dev_select(struct ata_port *ap, unsigned int device, | 781 | void ata_dev_select(struct ata_port *ap, unsigned int device, |
778 | unsigned int wait, unsigned int can_sleep) | 782 | unsigned int wait, unsigned int can_sleep) |
779 | { | 783 | { |
780 | if (ata_msg_probe(ap)) { | 784 | if (ata_msg_probe(ap)) |
781 | ata_port_printk(ap, KERN_INFO, "ata_dev_select: ENTER, ata%u: " | 785 | ata_port_printk(ap, KERN_INFO, "ata_dev_select: ENTER, ata%u: " |
782 | "device %u, wait %u\n", | 786 | "device %u, wait %u\n", ap->id, device, wait); |
783 | ap->id, device, wait); | ||
784 | } | ||
785 | 787 | ||
786 | if (wait) | 788 | if (wait) |
787 | ata_wait_idle(ap); | 789 | ata_wait_idle(ap); |
@@ -950,7 +952,8 @@ void ata_port_flush_task(struct ata_port *ap) | |||
950 | */ | 952 | */ |
951 | if (!cancel_delayed_work(&ap->port_task)) { | 953 | if (!cancel_delayed_work(&ap->port_task)) { |
952 | if (ata_msg_ctl(ap)) | 954 | if (ata_msg_ctl(ap)) |
953 | ata_port_printk(ap, KERN_DEBUG, "%s: flush #2\n", __FUNCTION__); | 955 | ata_port_printk(ap, KERN_DEBUG, "%s: flush #2\n", |
956 | __FUNCTION__); | ||
954 | flush_workqueue(ata_wq); | 957 | flush_workqueue(ata_wq); |
955 | } | 958 | } |
956 | 959 | ||
@@ -1059,7 +1062,7 @@ unsigned ata_exec_internal(struct ata_device *dev, | |||
1059 | 1062 | ||
1060 | spin_unlock_irqrestore(ap->lock, flags); | 1063 | spin_unlock_irqrestore(ap->lock, flags); |
1061 | 1064 | ||
1062 | rc = wait_for_completion_timeout(&wait, ATA_TMOUT_INTERNAL); | 1065 | rc = wait_for_completion_timeout(&wait, ata_probe_timeout); |
1063 | 1066 | ||
1064 | ata_port_flush_task(ap); | 1067 | ata_port_flush_task(ap); |
1065 | 1068 | ||
@@ -1081,7 +1084,7 @@ unsigned ata_exec_internal(struct ata_device *dev, | |||
1081 | 1084 | ||
1082 | if (ata_msg_warn(ap)) | 1085 | if (ata_msg_warn(ap)) |
1083 | ata_dev_printk(dev, KERN_WARNING, | 1086 | ata_dev_printk(dev, KERN_WARNING, |
1084 | "qc timeout (cmd 0x%x)\n", command); | 1087 | "qc timeout (cmd 0x%x)\n", command); |
1085 | } | 1088 | } |
1086 | 1089 | ||
1087 | spin_unlock_irqrestore(ap->lock, flags); | 1090 | spin_unlock_irqrestore(ap->lock, flags); |
@@ -1093,9 +1096,9 @@ unsigned ata_exec_internal(struct ata_device *dev, | |||
1093 | 1096 | ||
1094 | if (qc->flags & ATA_QCFLAG_FAILED && !qc->err_mask) { | 1097 | if (qc->flags & ATA_QCFLAG_FAILED && !qc->err_mask) { |
1095 | if (ata_msg_warn(ap)) | 1098 | if (ata_msg_warn(ap)) |
1096 | ata_dev_printk(dev, KERN_WARNING, | 1099 | ata_dev_printk(dev, KERN_WARNING, |
1097 | "zero err_mask for failed " | 1100 | "zero err_mask for failed " |
1098 | "internal command, assuming AC_ERR_OTHER\n"); | 1101 | "internal command, assuming AC_ERR_OTHER\n"); |
1099 | qc->err_mask |= AC_ERR_OTHER; | 1102 | qc->err_mask |= AC_ERR_OTHER; |
1100 | } | 1103 | } |
1101 | 1104 | ||
@@ -1132,6 +1135,33 @@ unsigned ata_exec_internal(struct ata_device *dev, | |||
1132 | } | 1135 | } |
1133 | 1136 | ||
1134 | /** | 1137 | /** |
1138 | * ata_do_simple_cmd - execute simple internal command | ||
1139 | * @dev: Device to which the command is sent | ||
1140 | * @cmd: Opcode to execute | ||
1141 | * | ||
1142 | * Execute a 'simple' command, that only consists of the opcode | ||
1143 | * 'cmd' itself, without filling any other registers | ||
1144 | * | ||
1145 | * LOCKING: | ||
1146 | * Kernel thread context (may sleep). | ||
1147 | * | ||
1148 | * RETURNS: | ||
1149 | * Zero on success, AC_ERR_* mask on failure | ||
1150 | */ | ||
1151 | unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd) | ||
1152 | { | ||
1153 | struct ata_taskfile tf; | ||
1154 | |||
1155 | ata_tf_init(dev, &tf); | ||
1156 | |||
1157 | tf.command = cmd; | ||
1158 | tf.flags |= ATA_TFLAG_DEVICE; | ||
1159 | tf.protocol = ATA_PROT_NODATA; | ||
1160 | |||
1161 | return ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); | ||
1162 | } | ||
1163 | |||
1164 | /** | ||
1135 | * ata_pio_need_iordy - check if iordy needed | 1165 | * ata_pio_need_iordy - check if iordy needed |
1136 | * @adev: ATA device | 1166 | * @adev: ATA device |
1137 | * | 1167 | * |
@@ -1193,8 +1223,8 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, | |||
1193 | int rc; | 1223 | int rc; |
1194 | 1224 | ||
1195 | if (ata_msg_ctl(ap)) | 1225 | if (ata_msg_ctl(ap)) |
1196 | ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER, host %u, dev %u\n", | 1226 | ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER, host %u, dev %u\n", |
1197 | __FUNCTION__, ap->id, dev->devno); | 1227 | __FUNCTION__, ap->id, dev->devno); |
1198 | 1228 | ||
1199 | ata_dev_select(ap, dev->devno, 1, 1); /* select device 0/1 */ | 1229 | ata_dev_select(ap, dev->devno, 1, 1); /* select device 0/1 */ |
1200 | 1230 | ||
@@ -1263,9 +1293,9 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, | |||
1263 | return 0; | 1293 | return 0; |
1264 | 1294 | ||
1265 | err_out: | 1295 | err_out: |
1266 | if (ata_msg_warn(ap)) | 1296 | if (ata_msg_warn(ap)) |
1267 | ata_dev_printk(dev, KERN_WARNING, "failed to IDENTIFY " | 1297 | ata_dev_printk(dev, KERN_WARNING, "failed to IDENTIFY " |
1268 | "(%s, err_mask=0x%x)\n", reason, err_mask); | 1298 | "(%s, err_mask=0x%x)\n", reason, err_mask); |
1269 | return rc; | 1299 | return rc; |
1270 | } | 1300 | } |
1271 | 1301 | ||
@@ -1318,19 +1348,21 @@ int ata_dev_configure(struct ata_device *dev, int print_info) | |||
1318 | int i, rc; | 1348 | int i, rc; |
1319 | 1349 | ||
1320 | if (!ata_dev_enabled(dev) && ata_msg_info(ap)) { | 1350 | if (!ata_dev_enabled(dev) && ata_msg_info(ap)) { |
1321 | ata_dev_printk(dev, KERN_INFO, "%s: ENTER/EXIT (host %u, dev %u) -- nodev\n", | 1351 | ata_dev_printk(dev, KERN_INFO, |
1322 | __FUNCTION__, ap->id, dev->devno); | 1352 | "%s: ENTER/EXIT (host %u, dev %u) -- nodev\n", |
1353 | __FUNCTION__, ap->id, dev->devno); | ||
1323 | return 0; | 1354 | return 0; |
1324 | } | 1355 | } |
1325 | 1356 | ||
1326 | if (ata_msg_probe(ap)) | 1357 | if (ata_msg_probe(ap)) |
1327 | ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER, host %u, dev %u\n", | 1358 | ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER, host %u, dev %u\n", |
1328 | __FUNCTION__, ap->id, dev->devno); | 1359 | __FUNCTION__, ap->id, dev->devno); |
1329 | 1360 | ||
1330 | /* print device capabilities */ | 1361 | /* print device capabilities */ |
1331 | if (ata_msg_probe(ap)) | 1362 | if (ata_msg_probe(ap)) |
1332 | ata_dev_printk(dev, KERN_DEBUG, "%s: cfg 49:%04x 82:%04x 83:%04x " | 1363 | ata_dev_printk(dev, KERN_DEBUG, |
1333 | "84:%04x 85:%04x 86:%04x 87:%04x 88:%04x\n", | 1364 | "%s: cfg 49:%04x 82:%04x 83:%04x 84:%04x " |
1365 | "85:%04x 86:%04x 87:%04x 88:%04x\n", | ||
1334 | __FUNCTION__, | 1366 | __FUNCTION__, |
1335 | id[49], id[82], id[83], id[84], | 1367 | id[49], id[82], id[83], id[84], |
1336 | id[85], id[86], id[87], id[88]); | 1368 | id[85], id[86], id[87], id[88]); |
@@ -1402,14 +1434,16 @@ int ata_dev_configure(struct ata_device *dev, int print_info) | |||
1402 | ata_id_major_version(id), | 1434 | ata_id_major_version(id), |
1403 | ata_mode_string(xfer_mask), | 1435 | ata_mode_string(xfer_mask), |
1404 | (unsigned long long)dev->n_sectors, | 1436 | (unsigned long long)dev->n_sectors, |
1405 | dev->cylinders, dev->heads, dev->sectors); | 1437 | dev->cylinders, dev->heads, |
1438 | dev->sectors); | ||
1406 | } | 1439 | } |
1407 | 1440 | ||
1408 | if (dev->id[59] & 0x100) { | 1441 | if (dev->id[59] & 0x100) { |
1409 | dev->multi_count = dev->id[59] & 0xff; | 1442 | dev->multi_count = dev->id[59] & 0xff; |
1410 | if (ata_msg_info(ap)) | 1443 | if (ata_msg_info(ap)) |
1411 | ata_dev_printk(dev, KERN_INFO, "ata%u: dev %u multi count %u\n", | 1444 | ata_dev_printk(dev, KERN_INFO, |
1412 | ap->id, dev->devno, dev->multi_count); | 1445 | "ata%u: dev %u multi count %u\n", |
1446 | ap->id, dev->devno, dev->multi_count); | ||
1413 | } | 1447 | } |
1414 | 1448 | ||
1415 | dev->cdb_len = 16; | 1449 | dev->cdb_len = 16; |
@@ -1422,8 +1456,8 @@ int ata_dev_configure(struct ata_device *dev, int print_info) | |||
1422 | rc = atapi_cdb_len(id); | 1456 | rc = atapi_cdb_len(id); |
1423 | if ((rc < 12) || (rc > ATAPI_CDB_LEN)) { | 1457 | if ((rc < 12) || (rc > ATAPI_CDB_LEN)) { |
1424 | if (ata_msg_warn(ap)) | 1458 | if (ata_msg_warn(ap)) |
1425 | ata_dev_printk(dev, KERN_WARNING, | 1459 | ata_dev_printk(dev, KERN_WARNING, |
1426 | "unsupported CDB len\n"); | 1460 | "unsupported CDB len\n"); |
1427 | rc = -EINVAL; | 1461 | rc = -EINVAL; |
1428 | goto err_out_nosup; | 1462 | goto err_out_nosup; |
1429 | } | 1463 | } |
@@ -1466,8 +1500,8 @@ int ata_dev_configure(struct ata_device *dev, int print_info) | |||
1466 | 1500 | ||
1467 | err_out_nosup: | 1501 | err_out_nosup: |
1468 | if (ata_msg_probe(ap)) | 1502 | if (ata_msg_probe(ap)) |
1469 | ata_dev_printk(dev, KERN_DEBUG, | 1503 | ata_dev_printk(dev, KERN_DEBUG, |
1470 | "%s: EXIT, err\n", __FUNCTION__); | 1504 | "%s: EXIT, err\n", __FUNCTION__); |
1471 | return rc; | 1505 | return rc; |
1472 | } | 1506 | } |
1473 | 1507 | ||
@@ -3527,7 +3561,7 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words) | |||
3527 | * Inherited from caller. | 3561 | * Inherited from caller. |
3528 | */ | 3562 | */ |
3529 | 3563 | ||
3530 | void ata_mmio_data_xfer(struct ata_device *adev, unsigned char *buf, | 3564 | void ata_mmio_data_xfer(struct ata_device *adev, unsigned char *buf, |
3531 | unsigned int buflen, int write_data) | 3565 | unsigned int buflen, int write_data) |
3532 | { | 3566 | { |
3533 | struct ata_port *ap = adev->ap; | 3567 | struct ata_port *ap = adev->ap; |
@@ -3573,7 +3607,7 @@ void ata_mmio_data_xfer(struct ata_device *adev, unsigned char *buf, | |||
3573 | * Inherited from caller. | 3607 | * Inherited from caller. |
3574 | */ | 3608 | */ |
3575 | 3609 | ||
3576 | void ata_pio_data_xfer(struct ata_device *adev, unsigned char *buf, | 3610 | void ata_pio_data_xfer(struct ata_device *adev, unsigned char *buf, |
3577 | unsigned int buflen, int write_data) | 3611 | unsigned int buflen, int write_data) |
3578 | { | 3612 | { |
3579 | struct ata_port *ap = adev->ap; | 3613 | struct ata_port *ap = adev->ap; |
@@ -3607,7 +3641,7 @@ void ata_pio_data_xfer(struct ata_device *adev, unsigned char *buf, | |||
3607 | * @buflen: buffer length | 3641 | * @buflen: buffer length |
3608 | * @write_data: read/write | 3642 | * @write_data: read/write |
3609 | * | 3643 | * |
3610 | * Transfer data from/to the device data register by PIO. Do the | 3644 | * Transfer data from/to the device data register by PIO. Do the |
3611 | * transfer with interrupts disabled. | 3645 | * transfer with interrupts disabled. |
3612 | * | 3646 | * |
3613 | * LOCKING: | 3647 | * LOCKING: |
@@ -4946,31 +4980,9 @@ int ata_port_offline(struct ata_port *ap) | |||
4946 | return 0; | 4980 | return 0; |
4947 | } | 4981 | } |
4948 | 4982 | ||
4949 | /* | 4983 | int ata_flush_cache(struct ata_device *dev) |
4950 | * Execute a 'simple' command, that only consists of the opcode 'cmd' itself, | ||
4951 | * without filling any other registers | ||
4952 | */ | ||
4953 | static int ata_do_simple_cmd(struct ata_device *dev, u8 cmd) | ||
4954 | { | ||
4955 | struct ata_taskfile tf; | ||
4956 | int err; | ||
4957 | |||
4958 | ata_tf_init(dev, &tf); | ||
4959 | |||
4960 | tf.command = cmd; | ||
4961 | tf.flags |= ATA_TFLAG_DEVICE; | ||
4962 | tf.protocol = ATA_PROT_NODATA; | ||
4963 | |||
4964 | err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); | ||
4965 | if (err) | ||
4966 | ata_dev_printk(dev, KERN_ERR, "%s: ata command failed: %d\n", | ||
4967 | __FUNCTION__, err); | ||
4968 | |||
4969 | return err; | ||
4970 | } | ||
4971 | |||
4972 | static int ata_flush_cache(struct ata_device *dev) | ||
4973 | { | 4984 | { |
4985 | unsigned int err_mask; | ||
4974 | u8 cmd; | 4986 | u8 cmd; |
4975 | 4987 | ||
4976 | if (!ata_try_flush_cache(dev)) | 4988 | if (!ata_try_flush_cache(dev)) |
@@ -4981,17 +4993,41 @@ static int ata_flush_cache(struct ata_device *dev) | |||
4981 | else | 4993 | else |
4982 | cmd = ATA_CMD_FLUSH; | 4994 | cmd = ATA_CMD_FLUSH; |
4983 | 4995 | ||
4984 | return ata_do_simple_cmd(dev, cmd); | 4996 | err_mask = ata_do_simple_cmd(dev, cmd); |
4997 | if (err_mask) { | ||
4998 | ata_dev_printk(dev, KERN_ERR, "failed to flush cache\n"); | ||
4999 | return -EIO; | ||
5000 | } | ||
5001 | |||
5002 | return 0; | ||
4985 | } | 5003 | } |
4986 | 5004 | ||
4987 | static int ata_standby_drive(struct ata_device *dev) | 5005 | static int ata_standby_drive(struct ata_device *dev) |
4988 | { | 5006 | { |
4989 | return ata_do_simple_cmd(dev, ATA_CMD_STANDBYNOW1); | 5007 | unsigned int err_mask; |
5008 | |||
5009 | err_mask = ata_do_simple_cmd(dev, ATA_CMD_STANDBYNOW1); | ||
5010 | if (err_mask) { | ||
5011 | ata_dev_printk(dev, KERN_ERR, "failed to standby drive " | ||
5012 | "(err_mask=0x%x)\n", err_mask); | ||
5013 | return -EIO; | ||
5014 | } | ||
5015 | |||
5016 | return 0; | ||
4990 | } | 5017 | } |
4991 | 5018 | ||
4992 | static int ata_start_drive(struct ata_device *dev) | 5019 | static int ata_start_drive(struct ata_device *dev) |
4993 | { | 5020 | { |
4994 | return ata_do_simple_cmd(dev, ATA_CMD_IDLEIMMEDIATE); | 5021 | unsigned int err_mask; |
5022 | |||
5023 | err_mask = ata_do_simple_cmd(dev, ATA_CMD_IDLEIMMEDIATE); | ||
5024 | if (err_mask) { | ||
5025 | ata_dev_printk(dev, KERN_ERR, "failed to start drive " | ||
5026 | "(err_mask=0x%x)\n", err_mask); | ||
5027 | return -EIO; | ||
5028 | } | ||
5029 | |||
5030 | return 0; | ||
4995 | } | 5031 | } |
4996 | 5032 | ||
4997 | /** | 5033 | /** |
@@ -5212,7 +5248,7 @@ static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host, | |||
5212 | ap->msg_enable = 0x00FF; | 5248 | ap->msg_enable = 0x00FF; |
5213 | #elif defined(ATA_DEBUG) | 5249 | #elif defined(ATA_DEBUG) |
5214 | ap->msg_enable = ATA_MSG_DRV | ATA_MSG_INFO | ATA_MSG_CTL | ATA_MSG_WARN | ATA_MSG_ERR; | 5250 | ap->msg_enable = ATA_MSG_DRV | ATA_MSG_INFO | ATA_MSG_CTL | ATA_MSG_WARN | ATA_MSG_ERR; |
5215 | #else | 5251 | #else |
5216 | ap->msg_enable = ATA_MSG_DRV | ATA_MSG_ERR | ATA_MSG_WARN; | 5252 | ap->msg_enable = ATA_MSG_DRV | ATA_MSG_ERR | ATA_MSG_WARN; |
5217 | #endif | 5253 | #endif |
5218 | 5254 | ||
@@ -5709,6 +5745,7 @@ int ata_pci_device_resume(struct pci_dev *pdev) | |||
5709 | 5745 | ||
5710 | static int __init ata_init(void) | 5746 | static int __init ata_init(void) |
5711 | { | 5747 | { |
5748 | ata_probe_timeout *= HZ; | ||
5712 | ata_wq = create_workqueue("ata"); | 5749 | ata_wq = create_workqueue("ata"); |
5713 | if (!ata_wq) | 5750 | if (!ata_wq) |
5714 | return -ENOMEM; | 5751 | return -ENOMEM; |
@@ -5733,7 +5770,7 @@ module_init(ata_init); | |||
5733 | module_exit(ata_exit); | 5770 | module_exit(ata_exit); |
5734 | 5771 | ||
5735 | static unsigned long ratelimit_time; | 5772 | static unsigned long ratelimit_time; |
5736 | static spinlock_t ata_ratelimit_lock = SPIN_LOCK_UNLOCKED; | 5773 | static DEFINE_SPINLOCK(ata_ratelimit_lock); |
5737 | 5774 | ||
5738 | int ata_ratelimit(void) | 5775 | int ata_ratelimit(void) |
5739 | { | 5776 | { |
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c index 823385981a7a..bf5a72aca8a4 100644 --- a/drivers/scsi/libata-eh.c +++ b/drivers/scsi/libata-eh.c | |||
@@ -93,6 +93,38 @@ static int ata_ering_map(struct ata_ering *ering, | |||
93 | return rc; | 93 | return rc; |
94 | } | 94 | } |
95 | 95 | ||
96 | static unsigned int ata_eh_dev_action(struct ata_device *dev) | ||
97 | { | ||
98 | struct ata_eh_context *ehc = &dev->ap->eh_context; | ||
99 | |||
100 | return ehc->i.action | ehc->i.dev_action[dev->devno]; | ||
101 | } | ||
102 | |||
103 | static void ata_eh_clear_action(struct ata_device *dev, | ||
104 | struct ata_eh_info *ehi, unsigned int action) | ||
105 | { | ||
106 | int i; | ||
107 | |||
108 | if (!dev) { | ||
109 | ehi->action &= ~action; | ||
110 | for (i = 0; i < ATA_MAX_DEVICES; i++) | ||
111 | ehi->dev_action[i] &= ~action; | ||
112 | } else { | ||
113 | /* doesn't make sense for port-wide EH actions */ | ||
114 | WARN_ON(!(action & ATA_EH_PERDEV_MASK)); | ||
115 | |||
116 | /* break ehi->action into ehi->dev_action */ | ||
117 | if (ehi->action & action) { | ||
118 | for (i = 0; i < ATA_MAX_DEVICES; i++) | ||
119 | ehi->dev_action[i] |= ehi->action & action; | ||
120 | ehi->action &= ~action; | ||
121 | } | ||
122 | |||
123 | /* turn off the specified per-dev action */ | ||
124 | ehi->dev_action[dev->devno] &= ~action; | ||
125 | } | ||
126 | } | ||
127 | |||
96 | /** | 128 | /** |
97 | * ata_scsi_timed_out - SCSI layer time out callback | 129 | * ata_scsi_timed_out - SCSI layer time out callback |
98 | * @cmd: timed out SCSI command | 130 | * @cmd: timed out SCSI command |
@@ -702,32 +734,11 @@ static void ata_eh_detach_dev(struct ata_device *dev) | |||
702 | ap->flags |= ATA_FLAG_SCSI_HOTPLUG; | 734 | ap->flags |= ATA_FLAG_SCSI_HOTPLUG; |
703 | } | 735 | } |
704 | 736 | ||
705 | spin_unlock_irqrestore(ap->lock, flags); | 737 | /* clear per-dev EH actions */ |
706 | } | 738 | ata_eh_clear_action(dev, &ap->eh_info, ATA_EH_PERDEV_MASK); |
707 | 739 | ata_eh_clear_action(dev, &ap->eh_context.i, ATA_EH_PERDEV_MASK); | |
708 | static void ata_eh_clear_action(struct ata_device *dev, | ||
709 | struct ata_eh_info *ehi, unsigned int action) | ||
710 | { | ||
711 | int i; | ||
712 | 740 | ||
713 | if (!dev) { | 741 | spin_unlock_irqrestore(ap->lock, flags); |
714 | ehi->action &= ~action; | ||
715 | for (i = 0; i < ATA_MAX_DEVICES; i++) | ||
716 | ehi->dev_action[i] &= ~action; | ||
717 | } else { | ||
718 | /* doesn't make sense for port-wide EH actions */ | ||
719 | WARN_ON(!(action & ATA_EH_PERDEV_MASK)); | ||
720 | |||
721 | /* break ehi->action into ehi->dev_action */ | ||
722 | if (ehi->action & action) { | ||
723 | for (i = 0; i < ATA_MAX_DEVICES; i++) | ||
724 | ehi->dev_action[i] |= ehi->action & action; | ||
725 | ehi->action &= ~action; | ||
726 | } | ||
727 | |||
728 | /* turn off the specified per-dev action */ | ||
729 | ehi->dev_action[dev->devno] &= ~action; | ||
730 | } | ||
731 | } | 742 | } |
732 | 743 | ||
733 | /** | 744 | /** |
@@ -1592,7 +1603,7 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, | |||
1592 | unsigned int action; | 1603 | unsigned int action; |
1593 | 1604 | ||
1594 | dev = &ap->device[i]; | 1605 | dev = &ap->device[i]; |
1595 | action = ehc->i.action | ehc->i.dev_action[dev->devno]; | 1606 | action = ata_eh_dev_action(dev); |
1596 | 1607 | ||
1597 | if (action & ATA_EH_REVALIDATE && ata_dev_enabled(dev)) { | 1608 | if (action & ATA_EH_REVALIDATE && ata_dev_enabled(dev)) { |
1598 | if (ata_port_offline(ap)) { | 1609 | if (ata_port_offline(ap)) { |
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index 93d18a74c401..2915bca691e8 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c | |||
@@ -222,9 +222,7 @@ int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg) | |||
222 | && copy_to_user(arg + sizeof(args), argbuf, argsize)) | 222 | && copy_to_user(arg + sizeof(args), argbuf, argsize)) |
223 | rc = -EFAULT; | 223 | rc = -EFAULT; |
224 | error: | 224 | error: |
225 | if (argbuf) | 225 | kfree(argbuf); |
226 | kfree(argbuf); | ||
227 | |||
228 | return rc; | 226 | return rc; |
229 | } | 227 | } |
230 | 228 | ||
diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h index bdd488897096..c325679d9b54 100644 --- a/drivers/scsi/libata.h +++ b/drivers/scsi/libata.h | |||
@@ -29,7 +29,7 @@ | |||
29 | #define __LIBATA_H__ | 29 | #define __LIBATA_H__ |
30 | 30 | ||
31 | #define DRV_NAME "libata" | 31 | #define DRV_NAME "libata" |
32 | #define DRV_VERSION "1.30" /* must be exactly four chars */ | 32 | #define DRV_VERSION "2.00" /* must be exactly four chars */ |
33 | 33 | ||
34 | struct ata_scsi_args { | 34 | struct ata_scsi_args { |
35 | struct ata_device *dev; | 35 | struct ata_device *dev; |
@@ -50,6 +50,7 @@ extern void ata_port_flush_task(struct ata_port *ap); | |||
50 | extern unsigned ata_exec_internal(struct ata_device *dev, | 50 | extern unsigned ata_exec_internal(struct ata_device *dev, |
51 | struct ata_taskfile *tf, const u8 *cdb, | 51 | struct ata_taskfile *tf, const u8 *cdb, |
52 | int dma_dir, void *buf, unsigned int buflen); | 52 | int dma_dir, void *buf, unsigned int buflen); |
53 | extern unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd); | ||
53 | extern int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, | 54 | extern int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, |
54 | int post_reset, u16 *id); | 55 | int post_reset, u16 *id); |
55 | extern int ata_dev_configure(struct ata_device *dev, int print_info); | 56 | extern int ata_dev_configure(struct ata_device *dev, int print_info); |
@@ -64,6 +65,7 @@ extern int ata_check_atapi_dma(struct ata_queued_cmd *qc); | |||
64 | extern void ata_dev_select(struct ata_port *ap, unsigned int device, | 65 | extern void ata_dev_select(struct ata_port *ap, unsigned int device, |
65 | unsigned int wait, unsigned int can_sleep); | 66 | unsigned int wait, unsigned int can_sleep); |
66 | extern void swap_buf_le16(u16 *buf, unsigned int buf_words); | 67 | extern void swap_buf_le16(u16 *buf, unsigned int buf_words); |
68 | extern int ata_flush_cache(struct ata_device *dev); | ||
67 | extern void ata_dev_init(struct ata_device *dev); | 69 | extern void ata_dev_init(struct ata_device *dev); |
68 | extern int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg); | 70 | extern int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg); |
69 | extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg); | 71 | extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg); |
diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c index 6ab035590ee6..b28712df0b77 100644 --- a/drivers/scsi/ncr53c8xx.c +++ b/drivers/scsi/ncr53c8xx.c | |||
@@ -5118,8 +5118,7 @@ static void ncr_ccb_skipped(struct ncb *np, struct ccb *cp) | |||
5118 | cp->host_status &= ~HS_SKIPMASK; | 5118 | cp->host_status &= ~HS_SKIPMASK; |
5119 | cp->start.schedule.l_paddr = | 5119 | cp->start.schedule.l_paddr = |
5120 | cpu_to_scr(NCB_SCRIPT_PHYS (np, select)); | 5120 | cpu_to_scr(NCB_SCRIPT_PHYS (np, select)); |
5121 | list_del(&cp->link_ccbq); | 5121 | list_move_tail(&cp->link_ccbq, &lp->skip_ccbq); |
5122 | list_add_tail(&cp->link_ccbq, &lp->skip_ccbq); | ||
5123 | if (cp->queued) { | 5122 | if (cp->queued) { |
5124 | --lp->queuedccbs; | 5123 | --lp->queuedccbs; |
5125 | } | 5124 | } |
diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c index 108910f512e4..d58ac5ad509d 100644 --- a/drivers/scsi/ppa.c +++ b/drivers/scsi/ppa.c | |||
@@ -6,8 +6,6 @@ | |||
6 | * (c) 1995,1996 Grant R. Guenther, grant@torque.net, | 6 | * (c) 1995,1996 Grant R. Guenther, grant@torque.net, |
7 | * under the terms of the GNU General Public License. | 7 | * under the terms of the GNU General Public License. |
8 | * | 8 | * |
9 | * Current Maintainer: David Campbell (Perth, Western Australia, GMT+0800) | ||
10 | * campbell@torque.net | ||
11 | */ | 9 | */ |
12 | 10 | ||
13 | #include <linux/config.h> | 11 | #include <linux/config.h> |
diff --git a/drivers/scsi/ppa.h b/drivers/scsi/ppa.h index f6e1a1574bb8..7511df3588e4 100644 --- a/drivers/scsi/ppa.h +++ b/drivers/scsi/ppa.h | |||
@@ -2,7 +2,7 @@ | |||
2 | * the Iomega ZIP drive | 2 | * the Iomega ZIP drive |
3 | * | 3 | * |
4 | * (c) 1996 Grant R. Guenther grant@torque.net | 4 | * (c) 1996 Grant R. Guenther grant@torque.net |
5 | * David Campbell campbell@torque.net | 5 | * David Campbell |
6 | * | 6 | * |
7 | * All comments to David. | 7 | * All comments to David. |
8 | */ | 8 | */ |
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index ce32322f1e19..ce74a6025a07 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c | |||
@@ -2347,8 +2347,7 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha) | |||
2347 | } | 2347 | } |
2348 | 2348 | ||
2349 | /* Remove device from the new list and add it to DB */ | 2349 | /* Remove device from the new list and add it to DB */ |
2350 | list_del(&fcport->list); | 2350 | list_move_tail(&fcport->list, &ha->fcports); |
2351 | list_add_tail(&fcport->list, &ha->fcports); | ||
2352 | 2351 | ||
2353 | /* Login and update database */ | 2352 | /* Login and update database */ |
2354 | qla2x00_fabric_dev_login(ha, fcport, &next_loopid); | 2353 | qla2x00_fabric_dev_login(ha, fcport, &next_loopid); |
diff --git a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c index d18e7e0932ef..5cc42c6054eb 100644 --- a/drivers/scsi/sata_nv.c +++ b/drivers/scsi/sata_nv.c | |||
@@ -44,7 +44,7 @@ | |||
44 | #include <linux/libata.h> | 44 | #include <linux/libata.h> |
45 | 45 | ||
46 | #define DRV_NAME "sata_nv" | 46 | #define DRV_NAME "sata_nv" |
47 | #define DRV_VERSION "0.9" | 47 | #define DRV_VERSION "2.0" |
48 | 48 | ||
49 | enum { | 49 | enum { |
50 | NV_PORTS = 2, | 50 | NV_PORTS = 2, |
diff --git a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c index bc9f918a7f28..51d86d750e84 100644 --- a/drivers/scsi/sata_sil.c +++ b/drivers/scsi/sata_sil.c | |||
@@ -46,12 +46,13 @@ | |||
46 | #include <linux/libata.h> | 46 | #include <linux/libata.h> |
47 | 47 | ||
48 | #define DRV_NAME "sata_sil" | 48 | #define DRV_NAME "sata_sil" |
49 | #define DRV_VERSION "1.0" | 49 | #define DRV_VERSION "2.0" |
50 | 50 | ||
51 | enum { | 51 | enum { |
52 | /* | 52 | /* |
53 | * host flags | 53 | * host flags |
54 | */ | 54 | */ |
55 | SIL_FLAG_NO_SATA_IRQ = (1 << 28), | ||
55 | SIL_FLAG_RERR_ON_DMA_ACT = (1 << 29), | 56 | SIL_FLAG_RERR_ON_DMA_ACT = (1 << 29), |
56 | SIL_FLAG_MOD15WRITE = (1 << 30), | 57 | SIL_FLAG_MOD15WRITE = (1 << 30), |
57 | 58 | ||
@@ -62,8 +63,9 @@ enum { | |||
62 | * Controller IDs | 63 | * Controller IDs |
63 | */ | 64 | */ |
64 | sil_3112 = 0, | 65 | sil_3112 = 0, |
65 | sil_3512 = 1, | 66 | sil_3112_no_sata_irq = 1, |
66 | sil_3114 = 2, | 67 | sil_3512 = 2, |
68 | sil_3114 = 3, | ||
67 | 69 | ||
68 | /* | 70 | /* |
69 | * Register offsets | 71 | * Register offsets |
@@ -123,8 +125,8 @@ static const struct pci_device_id sil_pci_tbl[] = { | |||
123 | { 0x1095, 0x3512, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3512 }, | 125 | { 0x1095, 0x3512, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3512 }, |
124 | { 0x1095, 0x3114, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3114 }, | 126 | { 0x1095, 0x3114, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3114 }, |
125 | { 0x1002, 0x436e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 }, | 127 | { 0x1002, 0x436e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 }, |
126 | { 0x1002, 0x4379, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 }, | 128 | { 0x1002, 0x4379, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_no_sata_irq }, |
127 | { 0x1002, 0x437a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 }, | 129 | { 0x1002, 0x437a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_no_sata_irq }, |
128 | { } /* terminate list */ | 130 | { } /* terminate list */ |
129 | }; | 131 | }; |
130 | 132 | ||
@@ -217,6 +219,16 @@ static const struct ata_port_info sil_port_info[] = { | |||
217 | .udma_mask = 0x3f, /* udma0-5 */ | 219 | .udma_mask = 0x3f, /* udma0-5 */ |
218 | .port_ops = &sil_ops, | 220 | .port_ops = &sil_ops, |
219 | }, | 221 | }, |
222 | /* sil_3112_no_sata_irq */ | ||
223 | { | ||
224 | .sht = &sil_sht, | ||
225 | .host_flags = SIL_DFL_HOST_FLAGS | SIL_FLAG_MOD15WRITE | | ||
226 | SIL_FLAG_NO_SATA_IRQ, | ||
227 | .pio_mask = 0x1f, /* pio0-4 */ | ||
228 | .mwdma_mask = 0x07, /* mwdma0-2 */ | ||
229 | .udma_mask = 0x3f, /* udma0-5 */ | ||
230 | .port_ops = &sil_ops, | ||
231 | }, | ||
220 | /* sil_3512 */ | 232 | /* sil_3512 */ |
221 | { | 233 | { |
222 | .sht = &sil_sht, | 234 | .sht = &sil_sht, |
@@ -437,6 +449,10 @@ static irqreturn_t sil_interrupt(int irq, void *dev_instance, | |||
437 | if (unlikely(!ap || ap->flags & ATA_FLAG_DISABLED)) | 449 | if (unlikely(!ap || ap->flags & ATA_FLAG_DISABLED)) |
438 | continue; | 450 | continue; |
439 | 451 | ||
452 | /* turn off SATA_IRQ if not supported */ | ||
453 | if (ap->flags & SIL_FLAG_NO_SATA_IRQ) | ||
454 | bmdma2 &= ~SIL_DMA_SATA_IRQ; | ||
455 | |||
440 | if (bmdma2 == 0xffffffff || | 456 | if (bmdma2 == 0xffffffff || |
441 | !(bmdma2 & (SIL_DMA_COMPLETE | SIL_DMA_SATA_IRQ))) | 457 | !(bmdma2 & (SIL_DMA_COMPLETE | SIL_DMA_SATA_IRQ))) |
442 | continue; | 458 | continue; |
@@ -474,8 +490,9 @@ static void sil_thaw(struct ata_port *ap) | |||
474 | ata_chk_status(ap); | 490 | ata_chk_status(ap); |
475 | ata_bmdma_irq_clear(ap); | 491 | ata_bmdma_irq_clear(ap); |
476 | 492 | ||
477 | /* turn on SATA IRQ */ | 493 | /* turn on SATA IRQ if supported */ |
478 | writel(SIL_SIEN_N, mmio_base + sil_port[ap->port_no].sien); | 494 | if (!(ap->flags & SIL_FLAG_NO_SATA_IRQ)) |
495 | writel(SIL_SIEN_N, mmio_base + sil_port[ap->port_no].sien); | ||
479 | 496 | ||
480 | /* turn on IRQ */ | 497 | /* turn on IRQ */ |
481 | tmp = readl(mmio_base + SIL_SYSCFG); | 498 | tmp = readl(mmio_base + SIL_SYSCFG); |
diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c index c8b477c67247..b5f8fa955679 100644 --- a/drivers/scsi/sata_sil24.c +++ b/drivers/scsi/sata_sil24.c | |||
@@ -31,7 +31,7 @@ | |||
31 | #include <asm/io.h> | 31 | #include <asm/io.h> |
32 | 32 | ||
33 | #define DRV_NAME "sata_sil24" | 33 | #define DRV_NAME "sata_sil24" |
34 | #define DRV_VERSION "0.24" | 34 | #define DRV_VERSION "0.3" |
35 | 35 | ||
36 | /* | 36 | /* |
37 | * Port request block (PRB) 32 bytes | 37 | * Port request block (PRB) 32 bytes |
diff --git a/drivers/scsi/sata_svw.c b/drivers/scsi/sata_svw.c index c94b870cf378..7566c2cabaf7 100644 --- a/drivers/scsi/sata_svw.c +++ b/drivers/scsi/sata_svw.c | |||
@@ -54,7 +54,7 @@ | |||
54 | #endif /* CONFIG_PPC_OF */ | 54 | #endif /* CONFIG_PPC_OF */ |
55 | 55 | ||
56 | #define DRV_NAME "sata_svw" | 56 | #define DRV_NAME "sata_svw" |
57 | #define DRV_VERSION "1.8" | 57 | #define DRV_VERSION "2.0" |
58 | 58 | ||
59 | enum { | 59 | enum { |
60 | /* Taskfile registers offsets */ | 60 | /* Taskfile registers offsets */ |
diff --git a/drivers/scsi/sata_uli.c b/drivers/scsi/sata_uli.c index f668c997e9af..64f3c1aeed21 100644 --- a/drivers/scsi/sata_uli.c +++ b/drivers/scsi/sata_uli.c | |||
@@ -37,7 +37,7 @@ | |||
37 | #include <linux/libata.h> | 37 | #include <linux/libata.h> |
38 | 38 | ||
39 | #define DRV_NAME "sata_uli" | 39 | #define DRV_NAME "sata_uli" |
40 | #define DRV_VERSION "0.6" | 40 | #define DRV_VERSION "1.0" |
41 | 41 | ||
42 | enum { | 42 | enum { |
43 | uli_5289 = 0, | 43 | uli_5289 = 0, |
diff --git a/drivers/scsi/sata_via.c b/drivers/scsi/sata_via.c index 322890b400a6..67c3d2999775 100644 --- a/drivers/scsi/sata_via.c +++ b/drivers/scsi/sata_via.c | |||
@@ -47,7 +47,7 @@ | |||
47 | #include <asm/io.h> | 47 | #include <asm/io.h> |
48 | 48 | ||
49 | #define DRV_NAME "sata_via" | 49 | #define DRV_NAME "sata_via" |
50 | #define DRV_VERSION "1.2" | 50 | #define DRV_VERSION "2.0" |
51 | 51 | ||
52 | enum board_ids_enum { | 52 | enum board_ids_enum { |
53 | vt6420, | 53 | vt6420, |
diff --git a/drivers/scsi/sata_vsc.c b/drivers/scsi/sata_vsc.c index 6d0c4f18e652..616fd9634b4b 100644 --- a/drivers/scsi/sata_vsc.c +++ b/drivers/scsi/sata_vsc.c | |||
@@ -47,7 +47,7 @@ | |||
47 | #include <linux/libata.h> | 47 | #include <linux/libata.h> |
48 | 48 | ||
49 | #define DRV_NAME "sata_vsc" | 49 | #define DRV_NAME "sata_vsc" |
50 | #define DRV_VERSION "1.2" | 50 | #define DRV_VERSION "2.0" |
51 | 51 | ||
52 | enum { | 52 | enum { |
53 | /* Interrupt register offsets (from chip base address) */ | 53 | /* Interrupt register offsets (from chip base address) */ |
@@ -443,16 +443,12 @@ err_out: | |||
443 | } | 443 | } |
444 | 444 | ||
445 | 445 | ||
446 | /* | ||
447 | * Intel 31244 is supposed to be identical. | ||
448 | * Compatibility is untested as of yet. | ||
449 | */ | ||
450 | static const struct pci_device_id vsc_sata_pci_tbl[] = { | 446 | static const struct pci_device_id vsc_sata_pci_tbl[] = { |
451 | { PCI_VENDOR_ID_VITESSE, PCI_DEVICE_ID_VITESSE_VSC7174, | 447 | { PCI_VENDOR_ID_VITESSE, 0x7174, |
452 | PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 }, | 448 | PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 }, |
453 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_GD31244, | 449 | { PCI_VENDOR_ID_INTEL, 0x3200, |
454 | PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 }, | 450 | PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 }, |
455 | { } | 451 | { } /* terminate list */ |
456 | }; | 452 | }; |
457 | 453 | ||
458 | 454 | ||
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 1272dd249af3..b5218fc0ac86 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c | |||
@@ -2818,7 +2818,7 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon | |||
2818 | (cmdstatp->sense_hdr.sense_key == NO_SENSE || | 2818 | (cmdstatp->sense_hdr.sense_key == NO_SENSE || |
2819 | cmdstatp->sense_hdr.sense_key == RECOVERED_ERROR) && | 2819 | cmdstatp->sense_hdr.sense_key == RECOVERED_ERROR) && |
2820 | undone == 0) { | 2820 | undone == 0) { |
2821 | ioctl_result = 0; /* EOF written succesfully at EOM */ | 2821 | ioctl_result = 0; /* EOF written successfully at EOM */ |
2822 | if (fileno >= 0) | 2822 | if (fileno >= 0) |
2823 | fileno++; | 2823 | fileno++; |
2824 | STps->drv_file = fileno; | 2824 | STps->drv_file = fileno; |
diff --git a/drivers/serial/8250_pnp.c b/drivers/serial/8250_pnp.c index b79ed0665d51..739bc84f91e9 100644 --- a/drivers/serial/8250_pnp.c +++ b/drivers/serial/8250_pnp.c | |||
@@ -323,8 +323,10 @@ static const struct pnp_device_id pnp_dev_table[] = { | |||
323 | { "USR9180", 0 }, | 323 | { "USR9180", 0 }, |
324 | /* U.S. Robotics 56K Voice INT PnP*/ | 324 | /* U.S. Robotics 56K Voice INT PnP*/ |
325 | { "USR9190", 0 }, | 325 | { "USR9190", 0 }, |
326 | /* HP Compaq Tablet PC tc1100 Wacom tablet */ | 326 | /* Wacom tablets */ |
327 | { "WACF004", 0 }, | ||
327 | { "WACF005", 0 }, | 328 | { "WACF005", 0 }, |
329 | { "WACF006", 0 }, | ||
328 | /* Rockwell's (PORALiNK) 33600 INT PNP */ | 330 | /* Rockwell's (PORALiNK) 33600 INT PNP */ |
329 | { "WCI0003", 0 }, | 331 | { "WCI0003", 0 }, |
330 | /* Unkown PnP modems */ | 332 | /* Unkown PnP modems */ |
diff --git a/drivers/sn/ioc3.c b/drivers/sn/ioc3.c index 501316b198e5..ed946311d3a4 100644 --- a/drivers/sn/ioc3.c +++ b/drivers/sn/ioc3.c | |||
@@ -26,7 +26,7 @@ static DECLARE_RWSEM(ioc3_devices_rwsem); | |||
26 | 26 | ||
27 | static struct ioc3_submodule *ioc3_submodules[IOC3_MAX_SUBMODULES]; | 27 | static struct ioc3_submodule *ioc3_submodules[IOC3_MAX_SUBMODULES]; |
28 | static struct ioc3_submodule *ioc3_ethernet; | 28 | static struct ioc3_submodule *ioc3_ethernet; |
29 | static rwlock_t ioc3_submodules_lock = RW_LOCK_UNLOCKED; | 29 | static DEFINE_RWLOCK(ioc3_submodules_lock); |
30 | 30 | ||
31 | /* NIC probing code */ | 31 | /* NIC probing code */ |
32 | 32 | ||
diff --git a/drivers/telephony/ixj.c b/drivers/telephony/ixj.c index 5578a9dd04e8..f6b2948ab288 100644 --- a/drivers/telephony/ixj.c +++ b/drivers/telephony/ixj.c | |||
@@ -5712,7 +5712,7 @@ static int ixj_daa_write(IXJ *j) | |||
5712 | return 1; | 5712 | return 1; |
5713 | } | 5713 | } |
5714 | 5714 | ||
5715 | int ixj_set_tone_off(unsigned short arg, IXJ *j) | 5715 | static int ixj_set_tone_off(unsigned short arg, IXJ *j) |
5716 | { | 5716 | { |
5717 | j->tone_off_time = arg; | 5717 | j->tone_off_time = arg; |
5718 | if (ixj_WriteDSPCommand(0x6E05, j)) /* Set Tone Off Period */ | 5718 | if (ixj_WriteDSPCommand(0x6E05, j)) /* Set Tone Off Period */ |
diff --git a/drivers/usb/host/hc_crisv10.c b/drivers/usb/host/hc_crisv10.c index 2fe7fd19437b..4a22909518f5 100644 --- a/drivers/usb/host/hc_crisv10.c +++ b/drivers/usb/host/hc_crisv10.c | |||
@@ -411,8 +411,7 @@ static inline void urb_list_move_last(struct urb *urb, int epid) | |||
411 | urb_entry_t *urb_entry = __urb_list_entry(urb, epid); | 411 | urb_entry_t *urb_entry = __urb_list_entry(urb, epid); |
412 | assert(urb_entry); | 412 | assert(urb_entry); |
413 | 413 | ||
414 | list_del(&urb_entry->list); | 414 | list_move_tail(&urb_entry->list, &urb_list[epid]); |
415 | list_add_tail(&urb_entry->list, &urb_list[epid]); | ||
416 | } | 415 | } |
417 | 416 | ||
418 | /* Get the next urb in the list. */ | 417 | /* Get the next urb in the list. */ |
diff --git a/drivers/usb/input/fixp-arith.h b/drivers/usb/input/fixp-arith.h index b44d398de071..ed3d2da0c485 100644 --- a/drivers/usb/input/fixp-arith.h +++ b/drivers/usb/input/fixp-arith.h | |||
@@ -2,8 +2,6 @@ | |||
2 | #define _FIXP_ARITH_H | 2 | #define _FIXP_ARITH_H |
3 | 3 | ||
4 | /* | 4 | /* |
5 | * $$ | ||
6 | * | ||
7 | * Simplistic fixed-point arithmetics. | 5 | * Simplistic fixed-point arithmetics. |
8 | * Hmm, I'm probably duplicating some code :( | 6 | * Hmm, I'm probably duplicating some code :( |
9 | * | 7 | * |
@@ -31,20 +29,20 @@ | |||
31 | 29 | ||
32 | #include <linux/types.h> | 30 | #include <linux/types.h> |
33 | 31 | ||
34 | // The type representing fixed-point values | 32 | /* The type representing fixed-point values */ |
35 | typedef s16 fixp_t; | 33 | typedef s16 fixp_t; |
36 | 34 | ||
37 | #define FRAC_N 8 | 35 | #define FRAC_N 8 |
38 | #define FRAC_MASK ((1<<FRAC_N)-1) | 36 | #define FRAC_MASK ((1<<FRAC_N)-1) |
39 | 37 | ||
40 | // Not to be used directly. Use fixp_{cos,sin} | 38 | /* Not to be used directly. Use fixp_{cos,sin} */ |
41 | static const fixp_t cos_table[45] = { | 39 | static const fixp_t cos_table[46] = { |
42 | 0x0100, 0x00FF, 0x00FF, 0x00FE, 0x00FD, 0x00FC, 0x00FA, 0x00F8, | 40 | 0x0100, 0x00FF, 0x00FF, 0x00FE, 0x00FD, 0x00FC, 0x00FA, 0x00F8, |
43 | 0x00F6, 0x00F3, 0x00F0, 0x00ED, 0x00E9, 0x00E6, 0x00E2, 0x00DD, | 41 | 0x00F6, 0x00F3, 0x00F0, 0x00ED, 0x00E9, 0x00E6, 0x00E2, 0x00DD, |
44 | 0x00D9, 0x00D4, 0x00CF, 0x00C9, 0x00C4, 0x00BE, 0x00B8, 0x00B1, | 42 | 0x00D9, 0x00D4, 0x00CF, 0x00C9, 0x00C4, 0x00BE, 0x00B8, 0x00B1, |
45 | 0x00AB, 0x00A4, 0x009D, 0x0096, 0x008F, 0x0087, 0x0080, 0x0078, | 43 | 0x00AB, 0x00A4, 0x009D, 0x0096, 0x008F, 0x0087, 0x0080, 0x0078, |
46 | 0x0070, 0x0068, 0x005F, 0x0057, 0x004F, 0x0046, 0x003D, 0x0035, | 44 | 0x0070, 0x0068, 0x005F, 0x0057, 0x004F, 0x0046, 0x003D, 0x0035, |
47 | 0x002C, 0x0023, 0x001A, 0x0011, 0x0008 | 45 | 0x002C, 0x0023, 0x001A, 0x0011, 0x0008, 0x0000 |
48 | }; | 46 | }; |
49 | 47 | ||
50 | 48 | ||
@@ -68,9 +66,8 @@ static inline fixp_t fixp_cos(unsigned int degrees) | |||
68 | int quadrant = (degrees / 90) & 3; | 66 | int quadrant = (degrees / 90) & 3; |
69 | unsigned int i = degrees % 90; | 67 | unsigned int i = degrees % 90; |
70 | 68 | ||
71 | if (quadrant == 1 || quadrant == 3) { | 69 | if (quadrant == 1 || quadrant == 3) |
72 | i = 89 - i; | 70 | i = 90 - i; |
73 | } | ||
74 | 71 | ||
75 | i >>= 1; | 72 | i >>= 1; |
76 | 73 | ||
diff --git a/drivers/usb/input/hid-debug.h b/drivers/usb/input/hid-debug.h index 702c48c2f81b..f04d6d75c098 100644 --- a/drivers/usb/input/hid-debug.h +++ b/drivers/usb/input/hid-debug.h | |||
@@ -563,7 +563,7 @@ static char *keys[KEY_MAX + 1] = { | |||
563 | [KEY_VOLUMEUP] = "VolumeUp", [KEY_POWER] = "Power", | 563 | [KEY_VOLUMEUP] = "VolumeUp", [KEY_POWER] = "Power", |
564 | [KEY_KPEQUAL] = "KPEqual", [KEY_KPPLUSMINUS] = "KPPlusMinus", | 564 | [KEY_KPEQUAL] = "KPEqual", [KEY_KPPLUSMINUS] = "KPPlusMinus", |
565 | [KEY_PAUSE] = "Pause", [KEY_KPCOMMA] = "KPComma", | 565 | [KEY_PAUSE] = "Pause", [KEY_KPCOMMA] = "KPComma", |
566 | [KEY_HANGUEL] = "Hanguel", [KEY_HANJA] = "Hanja", | 566 | [KEY_HANGUEL] = "Hangeul", [KEY_HANJA] = "Hanja", |
567 | [KEY_YEN] = "Yen", [KEY_LEFTMETA] = "LeftMeta", | 567 | [KEY_YEN] = "Yen", [KEY_LEFTMETA] = "LeftMeta", |
568 | [KEY_RIGHTMETA] = "RightMeta", [KEY_COMPOSE] = "Compose", | 568 | [KEY_RIGHTMETA] = "RightMeta", [KEY_COMPOSE] = "Compose", |
569 | [KEY_STOP] = "Stop", [KEY_AGAIN] = "Again", | 569 | [KEY_STOP] = "Stop", [KEY_AGAIN] = "Again", |
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index 5b06fa366098..56ffc81302fc 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c | |||
@@ -686,19 +686,16 @@ static void whiteheat_close(struct usb_serial_port *port, struct file * filp) | |||
686 | wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); | 686 | wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); |
687 | urb = wrap->urb; | 687 | urb = wrap->urb; |
688 | usb_kill_urb(urb); | 688 | usb_kill_urb(urb); |
689 | list_del(tmp); | 689 | list_move(tmp, &info->rx_urbs_free); |
690 | list_add(tmp, &info->rx_urbs_free); | ||
691 | } | ||
692 | list_for_each_safe(tmp, tmp2, &info->rx_urb_q) { | ||
693 | list_del(tmp); | ||
694 | list_add(tmp, &info->rx_urbs_free); | ||
695 | } | 690 | } |
691 | list_for_each_safe(tmp, tmp2, &info->rx_urb_q) | ||
692 | list_move(tmp, &info->rx_urbs_free); | ||
693 | |||
696 | list_for_each_safe(tmp, tmp2, &info->tx_urbs_submitted) { | 694 | list_for_each_safe(tmp, tmp2, &info->tx_urbs_submitted) { |
697 | wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); | 695 | wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); |
698 | urb = wrap->urb; | 696 | urb = wrap->urb; |
699 | usb_kill_urb(urb); | 697 | usb_kill_urb(urb); |
700 | list_del(tmp); | 698 | list_move(tmp, &info->tx_urbs_free); |
701 | list_add(tmp, &info->tx_urbs_free); | ||
702 | } | 699 | } |
703 | spin_unlock_irqrestore(&info->lock, flags); | 700 | spin_unlock_irqrestore(&info->lock, flags); |
704 | 701 | ||
@@ -1080,8 +1077,7 @@ static void whiteheat_write_callback(struct urb *urb, struct pt_regs *regs) | |||
1080 | err("%s - Not my urb!", __FUNCTION__); | 1077 | err("%s - Not my urb!", __FUNCTION__); |
1081 | return; | 1078 | return; |
1082 | } | 1079 | } |
1083 | list_del(&wrap->list); | 1080 | list_move(&wrap->list, &info->tx_urbs_free); |
1084 | list_add(&wrap->list, &info->tx_urbs_free); | ||
1085 | spin_unlock(&info->lock); | 1081 | spin_unlock(&info->lock); |
1086 | 1082 | ||
1087 | if (urb->status) { | 1083 | if (urb->status) { |
@@ -1371,8 +1367,7 @@ static int start_port_read(struct usb_serial_port *port) | |||
1371 | wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); | 1367 | wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); |
1372 | urb = wrap->urb; | 1368 | urb = wrap->urb; |
1373 | usb_kill_urb(urb); | 1369 | usb_kill_urb(urb); |
1374 | list_del(tmp); | 1370 | list_move(tmp, &info->rx_urbs_free); |
1375 | list_add(tmp, &info->rx_urbs_free); | ||
1376 | } | 1371 | } |
1377 | break; | 1372 | break; |
1378 | } | 1373 | } |
diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h index 009fb0953a56..5284abe1b5eb 100644 --- a/drivers/usb/storage/usb.h +++ b/drivers/usb/storage/usb.h | |||
@@ -160,10 +160,10 @@ struct us_data { | |||
160 | }; | 160 | }; |
161 | 161 | ||
162 | /* Convert between us_data and the corresponding Scsi_Host */ | 162 | /* Convert between us_data and the corresponding Scsi_Host */ |
163 | static struct Scsi_Host inline *us_to_host(struct us_data *us) { | 163 | static inline struct Scsi_Host *us_to_host(struct us_data *us) { |
164 | return container_of((void *) us, struct Scsi_Host, hostdata); | 164 | return container_of((void *) us, struct Scsi_Host, hostdata); |
165 | } | 165 | } |
166 | static struct us_data inline *host_to_us(struct Scsi_Host *host) { | 166 | static inline struct us_data *host_to_us(struct Scsi_Host *host) { |
167 | return (struct us_data *) host->hostdata; | 167 | return (struct us_data *) host->hostdata; |
168 | } | 168 | } |
169 | 169 | ||
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 168ede7902bd..17de4c84db69 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig | |||
@@ -4,6 +4,21 @@ | |||
4 | 4 | ||
5 | menu "Graphics support" | 5 | menu "Graphics support" |
6 | 6 | ||
7 | config FIRMWARE_EDID | ||
8 | bool "Enable firmware EDID" | ||
9 | default y | ||
10 | ---help--- | ||
11 | This enables access to the EDID transferred from the firmware. | ||
12 | On the i386, this is from the Video BIOS. Enable this if DDC/I2C | ||
13 | transfers do not work for your driver and if you are using | ||
14 | nvidiafb, i810fb or savagefb. | ||
15 | |||
16 | In general, choosing Y for this option is safe. If you | ||
17 | experience extremely long delays while booting before you get | ||
18 | something on your display, try setting this to N. Matrox cards in | ||
19 | combination with certain motherboards and monitors are known to | ||
20 | suffer from this problem. | ||
21 | |||
7 | config FB | 22 | config FB |
8 | tristate "Support for frame buffer devices" | 23 | tristate "Support for frame buffer devices" |
9 | ---help--- | 24 | ---help--- |
@@ -70,22 +85,6 @@ config FB_MACMODES | |||
70 | depends on FB | 85 | depends on FB |
71 | default n | 86 | default n |
72 | 87 | ||
73 | config FB_FIRMWARE_EDID | ||
74 | bool "Enable firmware EDID" | ||
75 | depends on FB | ||
76 | default y | ||
77 | ---help--- | ||
78 | This enables access to the EDID transferred from the firmware. | ||
79 | On the i386, this is from the Video BIOS. Enable this if DDC/I2C | ||
80 | transfers do not work for your driver and if you are using | ||
81 | nvidiafb, i810fb or savagefb. | ||
82 | |||
83 | In general, choosing Y for this option is safe. If you | ||
84 | experience extremely long delays while booting before you get | ||
85 | something on your display, try setting this to N. Matrox cards in | ||
86 | combination with certain motherboards and monitors are known to | ||
87 | suffer from this problem. | ||
88 | |||
89 | config FB_BACKLIGHT | 88 | config FB_BACKLIGHT |
90 | bool | 89 | bool |
91 | depends on FB | 90 | depends on FB |
@@ -551,10 +550,14 @@ config FB_VESA | |||
551 | You will get a boot time penguin logo at no additional cost. Please | 550 | You will get a boot time penguin logo at no additional cost. Please |
552 | read <file:Documentation/fb/vesafb.txt>. If unsure, say Y. | 551 | read <file:Documentation/fb/vesafb.txt>. If unsure, say Y. |
553 | 552 | ||
554 | config VIDEO_SELECT | 553 | config FB_IMAC |
555 | bool | 554 | bool "Intel-based Macintosh Framebuffer Support" |
556 | depends on FB_VESA | 555 | depends on (FB = y) && X86 |
557 | default y | 556 | select FB_CFB_FILLRECT |
557 | select FB_CFB_COPYAREA | ||
558 | select FB_CFB_IMAGEBLIT | ||
559 | help | ||
560 | This is the frame buffer device driver for the Intel-based Macintosh | ||
558 | 561 | ||
559 | config FB_HGA | 562 | config FB_HGA |
560 | tristate "Hercules mono graphics support" | 563 | tristate "Hercules mono graphics support" |
@@ -578,12 +581,6 @@ config FB_HGA_ACCEL | |||
578 | This will compile the Hercules mono graphics with | 581 | This will compile the Hercules mono graphics with |
579 | acceleration functions. | 582 | acceleration functions. |
580 | 583 | ||
581 | |||
582 | config VIDEO_SELECT | ||
583 | bool | ||
584 | depends on (FB = y) && X86 | ||
585 | default y | ||
586 | |||
587 | config FB_SGIVW | 584 | config FB_SGIVW |
588 | tristate "SGI Visual Workstation framebuffer support" | 585 | tristate "SGI Visual Workstation framebuffer support" |
589 | depends on FB && X86_VISWS | 586 | depends on FB && X86_VISWS |
diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 23de3b2c7856..c335e9bc3b20 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile | |||
@@ -4,15 +4,15 @@ | |||
4 | 4 | ||
5 | # Each configuration option enables a list of files. | 5 | # Each configuration option enables a list of files. |
6 | 6 | ||
7 | obj-$(CONFIG_VT) += console/ | ||
8 | obj-$(CONFIG_LOGO) += logo/ | ||
9 | obj-$(CONFIG_SYSFS) += backlight/ | ||
10 | |||
11 | obj-$(CONFIG_FB) += fb.o | 7 | obj-$(CONFIG_FB) += fb.o |
12 | fb-y := fbmem.o fbmon.o fbcmap.o fbsysfs.o \ | 8 | fb-y := fbmem.o fbmon.o fbcmap.o fbsysfs.o \ |
13 | modedb.o fbcvt.o | 9 | modedb.o fbcvt.o |
14 | fb-objs := $(fb-y) | 10 | fb-objs := $(fb-y) |
15 | 11 | ||
12 | obj-$(CONFIG_VT) += console/ | ||
13 | obj-$(CONFIG_LOGO) += logo/ | ||
14 | obj-$(CONFIG_SYSFS) += backlight/ | ||
15 | |||
16 | obj-$(CONFIG_FB_CFB_FILLRECT) += cfbfillrect.o | 16 | obj-$(CONFIG_FB_CFB_FILLRECT) += cfbfillrect.o |
17 | obj-$(CONFIG_FB_CFB_COPYAREA) += cfbcopyarea.o | 17 | obj-$(CONFIG_FB_CFB_COPYAREA) += cfbcopyarea.o |
18 | obj-$(CONFIG_FB_CFB_IMAGEBLIT) += cfbimgblt.o | 18 | obj-$(CONFIG_FB_CFB_IMAGEBLIT) += cfbimgblt.o |
@@ -97,6 +97,7 @@ obj-$(CONFIG_FB_S3C2410) += s3c2410fb.o | |||
97 | 97 | ||
98 | # Platform or fallback drivers go here | 98 | # Platform or fallback drivers go here |
99 | obj-$(CONFIG_FB_VESA) += vesafb.o | 99 | obj-$(CONFIG_FB_VESA) += vesafb.o |
100 | obj-$(CONFIG_FB_IMAC) += imacfb.o | ||
100 | obj-$(CONFIG_FB_VGA16) += vga16fb.o vgastate.o | 101 | obj-$(CONFIG_FB_VGA16) += vga16fb.o vgastate.o |
101 | obj-$(CONFIG_FB_OF) += offb.o | 102 | obj-$(CONFIG_FB_OF) += offb.o |
102 | 103 | ||
diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c index db878fd55fb2..11cf7fcb1d55 100644 --- a/drivers/video/aty/aty128fb.c +++ b/drivers/video/aty/aty128fb.c | |||
@@ -100,7 +100,7 @@ | |||
100 | 100 | ||
101 | #ifndef CONFIG_PPC_PMAC | 101 | #ifndef CONFIG_PPC_PMAC |
102 | /* default mode */ | 102 | /* default mode */ |
103 | static struct fb_var_screeninfo default_var __initdata = { | 103 | static struct fb_var_screeninfo default_var __devinitdata = { |
104 | /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */ | 104 | /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */ |
105 | 640, 480, 640, 480, 0, 0, 8, 0, | 105 | 640, 480, 640, 480, 0, 0, 8, 0, |
106 | {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, | 106 | {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, |
@@ -123,7 +123,7 @@ static struct fb_var_screeninfo default_var = { | |||
123 | 123 | ||
124 | /* default modedb mode */ | 124 | /* default modedb mode */ |
125 | /* 640x480, 60 Hz, Non-Interlaced (25.172 MHz dotclock) */ | 125 | /* 640x480, 60 Hz, Non-Interlaced (25.172 MHz dotclock) */ |
126 | static struct fb_videomode defaultmode __initdata = { | 126 | static struct fb_videomode defaultmode __devinitdata = { |
127 | .refresh = 60, | 127 | .refresh = 60, |
128 | .xres = 640, | 128 | .xres = 640, |
129 | .yres = 480, | 129 | .yres = 480, |
@@ -335,7 +335,7 @@ static const struct aty128_meminfo sdr_sgram = | |||
335 | static const struct aty128_meminfo ddr_sgram = | 335 | static const struct aty128_meminfo ddr_sgram = |
336 | { 4, 4, 3, 3, 2, 3, 1, 16, 31, 16, "64-bit DDR SGRAM" }; | 336 | { 4, 4, 3, 3, 2, 3, 1, 16, 31, 16, "64-bit DDR SGRAM" }; |
337 | 337 | ||
338 | static struct fb_fix_screeninfo aty128fb_fix __initdata = { | 338 | static struct fb_fix_screeninfo aty128fb_fix __devinitdata = { |
339 | .id = "ATY Rage128", | 339 | .id = "ATY Rage128", |
340 | .type = FB_TYPE_PACKED_PIXELS, | 340 | .type = FB_TYPE_PACKED_PIXELS, |
341 | .visual = FB_VISUAL_PSEUDOCOLOR, | 341 | .visual = FB_VISUAL_PSEUDOCOLOR, |
@@ -345,15 +345,15 @@ static struct fb_fix_screeninfo aty128fb_fix __initdata = { | |||
345 | .accel = FB_ACCEL_ATI_RAGE128, | 345 | .accel = FB_ACCEL_ATI_RAGE128, |
346 | }; | 346 | }; |
347 | 347 | ||
348 | static char *mode_option __initdata = NULL; | 348 | static char *mode_option __devinitdata = NULL; |
349 | 349 | ||
350 | #ifdef CONFIG_PPC_PMAC | 350 | #ifdef CONFIG_PPC_PMAC |
351 | static int default_vmode __initdata = VMODE_1024_768_60; | 351 | static int default_vmode __devinitdata = VMODE_1024_768_60; |
352 | static int default_cmode __initdata = CMODE_8; | 352 | static int default_cmode __devinitdata = CMODE_8; |
353 | #endif | 353 | #endif |
354 | 354 | ||
355 | static int default_crt_on __initdata = 0; | 355 | static int default_crt_on __devinitdata = 0; |
356 | static int default_lcd_on __initdata = 1; | 356 | static int default_lcd_on __devinitdata = 1; |
357 | 357 | ||
358 | #ifdef CONFIG_MTRR | 358 | #ifdef CONFIG_MTRR |
359 | static int mtrr = 1; | 359 | static int mtrr = 1; |
@@ -445,9 +445,9 @@ static int aty128_encode_var(struct fb_var_screeninfo *var, | |||
445 | static int aty128_decode_var(struct fb_var_screeninfo *var, | 445 | static int aty128_decode_var(struct fb_var_screeninfo *var, |
446 | struct aty128fb_par *par); | 446 | struct aty128fb_par *par); |
447 | #if 0 | 447 | #if 0 |
448 | static void __init aty128_get_pllinfo(struct aty128fb_par *par, | 448 | static void __devinit aty128_get_pllinfo(struct aty128fb_par *par, |
449 | void __iomem *bios); | 449 | void __iomem *bios); |
450 | static void __init __iomem *aty128_map_ROM(struct pci_dev *pdev, const struct aty128fb_par *par); | 450 | static void __devinit __iomem *aty128_map_ROM(struct pci_dev *pdev, const struct aty128fb_par *par); |
451 | #endif | 451 | #endif |
452 | static void aty128_timings(struct aty128fb_par *par); | 452 | static void aty128_timings(struct aty128fb_par *par); |
453 | static void aty128_init_engine(struct aty128fb_par *par); | 453 | static void aty128_init_engine(struct aty128fb_par *par); |
@@ -573,7 +573,7 @@ static void aty_pll_writeupdate(const struct aty128fb_par *par) | |||
573 | 573 | ||
574 | 574 | ||
575 | /* write to the scratch register to test r/w functionality */ | 575 | /* write to the scratch register to test r/w functionality */ |
576 | static int __init register_test(const struct aty128fb_par *par) | 576 | static int __devinit register_test(const struct aty128fb_par *par) |
577 | { | 577 | { |
578 | u32 val; | 578 | u32 val; |
579 | int flag = 0; | 579 | int flag = 0; |
@@ -772,7 +772,7 @@ static u32 depth_to_dst(u32 depth) | |||
772 | 772 | ||
773 | 773 | ||
774 | #ifndef __sparc__ | 774 | #ifndef __sparc__ |
775 | static void __iomem * __init aty128_map_ROM(const struct aty128fb_par *par, struct pci_dev *dev) | 775 | static void __iomem * __devinit aty128_map_ROM(const struct aty128fb_par *par, struct pci_dev *dev) |
776 | { | 776 | { |
777 | u16 dptr; | 777 | u16 dptr; |
778 | u8 rom_type; | 778 | u8 rom_type; |
@@ -856,7 +856,7 @@ static void __iomem * __init aty128_map_ROM(const struct aty128fb_par *par, stru | |||
856 | return NULL; | 856 | return NULL; |
857 | } | 857 | } |
858 | 858 | ||
859 | static void __init aty128_get_pllinfo(struct aty128fb_par *par, unsigned char __iomem *bios) | 859 | static void __devinit aty128_get_pllinfo(struct aty128fb_par *par, unsigned char __iomem *bios) |
860 | { | 860 | { |
861 | unsigned int bios_hdr; | 861 | unsigned int bios_hdr; |
862 | unsigned int bios_pll; | 862 | unsigned int bios_pll; |
@@ -903,7 +903,7 @@ static void __iomem * __devinit aty128_find_mem_vbios(struct aty128fb_par *par) | |||
903 | #endif /* ndef(__sparc__) */ | 903 | #endif /* ndef(__sparc__) */ |
904 | 904 | ||
905 | /* fill in known card constants if pll_block is not available */ | 905 | /* fill in known card constants if pll_block is not available */ |
906 | static void __init aty128_timings(struct aty128fb_par *par) | 906 | static void __devinit aty128_timings(struct aty128fb_par *par) |
907 | { | 907 | { |
908 | #ifdef CONFIG_PPC_OF | 908 | #ifdef CONFIG_PPC_OF |
909 | /* instead of a table lookup, assume OF has properly | 909 | /* instead of a table lookup, assume OF has properly |
@@ -1645,7 +1645,7 @@ static int aty128fb_sync(struct fb_info *info) | |||
1645 | } | 1645 | } |
1646 | 1646 | ||
1647 | #ifndef MODULE | 1647 | #ifndef MODULE |
1648 | static int __init aty128fb_setup(char *options) | 1648 | static int __devinit aty128fb_setup(char *options) |
1649 | { | 1649 | { |
1650 | char *this_opt; | 1650 | char *this_opt; |
1651 | 1651 | ||
@@ -1893,7 +1893,7 @@ static void aty128_early_resume(void *data) | |||
1893 | } | 1893 | } |
1894 | #endif /* CONFIG_PPC_PMAC */ | 1894 | #endif /* CONFIG_PPC_PMAC */ |
1895 | 1895 | ||
1896 | static int __init aty128_init(struct pci_dev *pdev, const struct pci_device_id *ent) | 1896 | static int __devinit aty128_init(struct pci_dev *pdev, const struct pci_device_id *ent) |
1897 | { | 1897 | { |
1898 | struct fb_info *info = pci_get_drvdata(pdev); | 1898 | struct fb_info *info = pci_get_drvdata(pdev); |
1899 | struct aty128fb_par *par = info->par; | 1899 | struct aty128fb_par *par = info->par; |
@@ -2037,7 +2037,7 @@ static int __init aty128_init(struct pci_dev *pdev, const struct pci_device_id * | |||
2037 | 2037 | ||
2038 | #ifdef CONFIG_PCI | 2038 | #ifdef CONFIG_PCI |
2039 | /* register a card ++ajoshi */ | 2039 | /* register a card ++ajoshi */ |
2040 | static int __init aty128_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | 2040 | static int __devinit aty128_probe(struct pci_dev *pdev, const struct pci_device_id *ent) |
2041 | { | 2041 | { |
2042 | unsigned long fb_addr, reg_addr; | 2042 | unsigned long fb_addr, reg_addr; |
2043 | struct aty128fb_par *par; | 2043 | struct aty128fb_par *par; |
@@ -2556,7 +2556,7 @@ static int aty128_pci_resume(struct pci_dev *pdev) | |||
2556 | } | 2556 | } |
2557 | 2557 | ||
2558 | 2558 | ||
2559 | static int __init aty128fb_init(void) | 2559 | static int __devinit aty128fb_init(void) |
2560 | { | 2560 | { |
2561 | #ifndef MODULE | 2561 | #ifndef MODULE |
2562 | char *option = NULL; | 2562 | char *option = NULL; |
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index c5185f7cf4ba..22e720611bf6 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c | |||
@@ -316,12 +316,12 @@ static int vram; | |||
316 | static int pll; | 316 | static int pll; |
317 | static int mclk; | 317 | static int mclk; |
318 | static int xclk; | 318 | static int xclk; |
319 | static int comp_sync __initdata = -1; | 319 | static int comp_sync __devinitdata = -1; |
320 | static char *mode; | 320 | static char *mode; |
321 | 321 | ||
322 | #ifdef CONFIG_PPC | 322 | #ifdef CONFIG_PPC |
323 | static int default_vmode __initdata = VMODE_CHOOSE; | 323 | static int default_vmode __devinitdata = VMODE_CHOOSE; |
324 | static int default_cmode __initdata = CMODE_CHOOSE; | 324 | static int default_cmode __devinitdata = CMODE_CHOOSE; |
325 | 325 | ||
326 | module_param_named(vmode, default_vmode, int, 0); | 326 | module_param_named(vmode, default_vmode, int, 0); |
327 | MODULE_PARM_DESC(vmode, "int: video mode for mac"); | 327 | MODULE_PARM_DESC(vmode, "int: video mode for mac"); |
@@ -330,10 +330,10 @@ MODULE_PARM_DESC(cmode, "int: color mode for mac"); | |||
330 | #endif | 330 | #endif |
331 | 331 | ||
332 | #ifdef CONFIG_ATARI | 332 | #ifdef CONFIG_ATARI |
333 | static unsigned int mach64_count __initdata = 0; | 333 | static unsigned int mach64_count __devinitdata = 0; |
334 | static unsigned long phys_vmembase[FB_MAX] __initdata = { 0, }; | 334 | static unsigned long phys_vmembase[FB_MAX] __devinitdata = { 0, }; |
335 | static unsigned long phys_size[FB_MAX] __initdata = { 0, }; | 335 | static unsigned long phys_size[FB_MAX] __devinitdata = { 0, }; |
336 | static unsigned long phys_guiregbase[FB_MAX] __initdata = { 0, }; | 336 | static unsigned long phys_guiregbase[FB_MAX] __devinitdata = { 0, }; |
337 | #endif | 337 | #endif |
338 | 338 | ||
339 | /* top -> down is an evolution of mach64 chipset, any corrections? */ | 339 | /* top -> down is an evolution of mach64 chipset, any corrections? */ |
@@ -583,7 +583,7 @@ static u32 atyfb_get_pixclock(struct fb_var_screeninfo *var, struct atyfb_par *p | |||
583 | * Apple monitor sense | 583 | * Apple monitor sense |
584 | */ | 584 | */ |
585 | 585 | ||
586 | static int __init read_aty_sense(const struct atyfb_par *par) | 586 | static int __devinit read_aty_sense(const struct atyfb_par *par) |
587 | { | 587 | { |
588 | int sense, i; | 588 | int sense, i; |
589 | 589 | ||
@@ -1281,6 +1281,14 @@ static int atyfb_set_par(struct fb_info *info) | |||
1281 | 1281 | ||
1282 | par->accel_flags = var->accel_flags; /* hack */ | 1282 | par->accel_flags = var->accel_flags; /* hack */ |
1283 | 1283 | ||
1284 | if (var->accel_flags) { | ||
1285 | info->fbops->fb_sync = atyfb_sync; | ||
1286 | info->flags &= ~FBINFO_HWACCEL_DISABLED; | ||
1287 | } else { | ||
1288 | info->fbops->fb_sync = NULL; | ||
1289 | info->flags |= FBINFO_HWACCEL_DISABLED; | ||
1290 | } | ||
1291 | |||
1284 | if (par->blitter_may_be_busy) | 1292 | if (par->blitter_may_be_busy) |
1285 | wait_for_idle(par); | 1293 | wait_for_idle(par); |
1286 | 1294 | ||
@@ -2253,7 +2261,7 @@ static void aty_bl_exit(struct atyfb_par *par) | |||
2253 | 2261 | ||
2254 | #endif /* CONFIG_FB_ATY_BACKLIGHT */ | 2262 | #endif /* CONFIG_FB_ATY_BACKLIGHT */ |
2255 | 2263 | ||
2256 | static void __init aty_calc_mem_refresh(struct atyfb_par *par, int xclk) | 2264 | static void __devinit aty_calc_mem_refresh(struct atyfb_par *par, int xclk) |
2257 | { | 2265 | { |
2258 | const int ragepro_tbl[] = { | 2266 | const int ragepro_tbl[] = { |
2259 | 44, 50, 55, 66, 75, 80, 100 | 2267 | 44, 50, 55, 66, 75, 80, 100 |
@@ -2313,7 +2321,7 @@ static int __devinit atyfb_get_timings_from_lcd(struct atyfb_par *par, | |||
2313 | } | 2321 | } |
2314 | #endif /* defined(__i386__) && defined(CONFIG_FB_ATY_GENERIC_LCD) */ | 2322 | #endif /* defined(__i386__) && defined(CONFIG_FB_ATY_GENERIC_LCD) */ |
2315 | 2323 | ||
2316 | static int __init aty_init(struct fb_info *info, const char *name) | 2324 | static int __devinit aty_init(struct fb_info *info, const char *name) |
2317 | { | 2325 | { |
2318 | struct atyfb_par *par = (struct atyfb_par *) info->par; | 2326 | struct atyfb_par *par = (struct atyfb_par *) info->par; |
2319 | const char *ramname = NULL, *xtal; | 2327 | const char *ramname = NULL, *xtal; |
@@ -2394,12 +2402,15 @@ static int __init aty_init(struct fb_info *info, const char *name) | |||
2394 | break; | 2402 | break; |
2395 | } | 2403 | } |
2396 | switch (clk_type) { | 2404 | switch (clk_type) { |
2405 | #ifdef CONFIG_ATARI | ||
2397 | case CLK_ATI18818_1: | 2406 | case CLK_ATI18818_1: |
2398 | par->pll_ops = &aty_pll_ati18818_1; | 2407 | par->pll_ops = &aty_pll_ati18818_1; |
2399 | break; | 2408 | break; |
2409 | #else | ||
2400 | case CLK_IBMRGB514: | 2410 | case CLK_IBMRGB514: |
2401 | par->pll_ops = &aty_pll_ibm514; | 2411 | par->pll_ops = &aty_pll_ibm514; |
2402 | break; | 2412 | break; |
2413 | #endif | ||
2403 | #if 0 /* dead code */ | 2414 | #if 0 /* dead code */ |
2404 | case CLK_STG1703: | 2415 | case CLK_STG1703: |
2405 | par->pll_ops = &aty_pll_stg1703; | 2416 | par->pll_ops = &aty_pll_stg1703; |
@@ -2604,7 +2615,11 @@ static int __init aty_init(struct fb_info *info, const char *name) | |||
2604 | 2615 | ||
2605 | info->fbops = &atyfb_ops; | 2616 | info->fbops = &atyfb_ops; |
2606 | info->pseudo_palette = pseudo_palette; | 2617 | info->pseudo_palette = pseudo_palette; |
2607 | info->flags = FBINFO_FLAG_DEFAULT; | 2618 | info->flags = FBINFO_DEFAULT | |
2619 | FBINFO_HWACCEL_IMAGEBLIT | | ||
2620 | FBINFO_HWACCEL_FILLRECT | | ||
2621 | FBINFO_HWACCEL_COPYAREA | | ||
2622 | FBINFO_HWACCEL_YPAN; | ||
2608 | 2623 | ||
2609 | #ifdef CONFIG_PMAC_BACKLIGHT | 2624 | #ifdef CONFIG_PMAC_BACKLIGHT |
2610 | if (M64_HAS(G3_PB_1_1) && machine_is_compatible("PowerBook1,1")) { | 2625 | if (M64_HAS(G3_PB_1_1) && machine_is_compatible("PowerBook1,1")) { |
@@ -2733,7 +2748,7 @@ aty_init_exit: | |||
2733 | } | 2748 | } |
2734 | 2749 | ||
2735 | #ifdef CONFIG_ATARI | 2750 | #ifdef CONFIG_ATARI |
2736 | static int __init store_video_par(char *video_str, unsigned char m64_num) | 2751 | static int __devinit store_video_par(char *video_str, unsigned char m64_num) |
2737 | { | 2752 | { |
2738 | char *p; | 2753 | char *p; |
2739 | unsigned long vmembase, size, guiregbase; | 2754 | unsigned long vmembase, size, guiregbase; |
@@ -3764,7 +3779,7 @@ static struct pci_driver atyfb_driver = { | |||
3764 | #endif /* CONFIG_PCI */ | 3779 | #endif /* CONFIG_PCI */ |
3765 | 3780 | ||
3766 | #ifndef MODULE | 3781 | #ifndef MODULE |
3767 | static int __init atyfb_setup(char *options) | 3782 | static int __devinit atyfb_setup(char *options) |
3768 | { | 3783 | { |
3769 | char *this_opt; | 3784 | char *this_opt; |
3770 | 3785 | ||
@@ -3836,7 +3851,7 @@ static int __init atyfb_setup(char *options) | |||
3836 | } | 3851 | } |
3837 | #endif /* MODULE */ | 3852 | #endif /* MODULE */ |
3838 | 3853 | ||
3839 | static int __init atyfb_init(void) | 3854 | static int __devinit atyfb_init(void) |
3840 | { | 3855 | { |
3841 | #ifndef MODULE | 3856 | #ifndef MODULE |
3842 | char *option = NULL; | 3857 | char *option = NULL; |
diff --git a/drivers/video/aty/mach64_accel.c b/drivers/video/aty/mach64_accel.c index c98f4a442134..1490e5e1c232 100644 --- a/drivers/video/aty/mach64_accel.c +++ b/drivers/video/aty/mach64_accel.c | |||
@@ -200,8 +200,6 @@ void atyfb_copyarea(struct fb_info *info, const struct fb_copyarea *area) | |||
200 | if (!area->width || !area->height) | 200 | if (!area->width || !area->height) |
201 | return; | 201 | return; |
202 | if (!par->accel_flags) { | 202 | if (!par->accel_flags) { |
203 | if (par->blitter_may_be_busy) | ||
204 | wait_for_idle(par); | ||
205 | cfb_copyarea(info, area); | 203 | cfb_copyarea(info, area); |
206 | return; | 204 | return; |
207 | } | 205 | } |
@@ -248,8 +246,6 @@ void atyfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) | |||
248 | if (!rect->width || !rect->height) | 246 | if (!rect->width || !rect->height) |
249 | return; | 247 | return; |
250 | if (!par->accel_flags) { | 248 | if (!par->accel_flags) { |
251 | if (par->blitter_may_be_busy) | ||
252 | wait_for_idle(par); | ||
253 | cfb_fillrect(info, rect); | 249 | cfb_fillrect(info, rect); |
254 | return; | 250 | return; |
255 | } | 251 | } |
@@ -288,14 +284,10 @@ void atyfb_imageblit(struct fb_info *info, const struct fb_image *image) | |||
288 | return; | 284 | return; |
289 | if (!par->accel_flags || | 285 | if (!par->accel_flags || |
290 | (image->depth != 1 && info->var.bits_per_pixel != image->depth)) { | 286 | (image->depth != 1 && info->var.bits_per_pixel != image->depth)) { |
291 | if (par->blitter_may_be_busy) | ||
292 | wait_for_idle(par); | ||
293 | |||
294 | cfb_imageblit(info, image); | 287 | cfb_imageblit(info, image); |
295 | return; | 288 | return; |
296 | } | 289 | } |
297 | 290 | ||
298 | wait_for_idle(par); | ||
299 | pix_width = pix_width_save = aty_ld_le32(DP_PIX_WIDTH, par); | 291 | pix_width = pix_width_save = aty_ld_le32(DP_PIX_WIDTH, par); |
300 | host_cntl = aty_ld_le32(HOST_CNTL, par) | HOST_BYTE_ALIGN; | 292 | host_cntl = aty_ld_le32(HOST_CNTL, par) | HOST_BYTE_ALIGN; |
301 | 293 | ||
@@ -425,8 +417,6 @@ void atyfb_imageblit(struct fb_info *info, const struct fb_image *image) | |||
425 | } | 417 | } |
426 | } | 418 | } |
427 | 419 | ||
428 | wait_for_idle(par); | ||
429 | |||
430 | /* restore pix_width */ | 420 | /* restore pix_width */ |
431 | wait_for_fifo(1, par); | 421 | wait_for_fifo(1, par); |
432 | aty_st_le32(DP_PIX_WIDTH, pix_width_save, par); | 422 | aty_st_le32(DP_PIX_WIDTH, pix_width_save, par); |
diff --git a/drivers/video/aty/mach64_cursor.c b/drivers/video/aty/mach64_cursor.c index ad8b7496f853..2a7f381c330f 100644 --- a/drivers/video/aty/mach64_cursor.c +++ b/drivers/video/aty/mach64_cursor.c | |||
@@ -66,11 +66,6 @@ static const u8 cursor_bits_lookup[16] = { | |||
66 | 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55 | 66 | 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55 |
67 | }; | 67 | }; |
68 | 68 | ||
69 | static const u8 cursor_mask_lookup[16] = { | ||
70 | 0xaa, 0x2a, 0x8a, 0x0a, 0xa2, 0x22, 0x82, 0x02, | ||
71 | 0xa8, 0x28, 0x88, 0x08, 0xa0, 0x20, 0x80, 0x00 | ||
72 | }; | ||
73 | |||
74 | static int atyfb_cursor(struct fb_info *info, struct fb_cursor *cursor) | 69 | static int atyfb_cursor(struct fb_info *info, struct fb_cursor *cursor) |
75 | { | 70 | { |
76 | struct atyfb_par *par = (struct atyfb_par *) info->par; | 71 | struct atyfb_par *par = (struct atyfb_par *) info->par; |
@@ -130,13 +125,13 @@ static int atyfb_cursor(struct fb_info *info, struct fb_cursor *cursor) | |||
130 | fg_idx = cursor->image.fg_color; | 125 | fg_idx = cursor->image.fg_color; |
131 | bg_idx = cursor->image.bg_color; | 126 | bg_idx = cursor->image.bg_color; |
132 | 127 | ||
133 | fg = (info->cmap.red[fg_idx] << 24) | | 128 | fg = ((info->cmap.red[fg_idx] & 0xff) << 24) | |
134 | (info->cmap.green[fg_idx] << 16) | | 129 | ((info->cmap.green[fg_idx] & 0xff) << 16) | |
135 | (info->cmap.blue[fg_idx] << 8) | 15; | 130 | ((info->cmap.blue[fg_idx] & 0xff) << 8) | 0xff; |
136 | 131 | ||
137 | bg = (info->cmap.red[bg_idx] << 24) | | 132 | bg = ((info->cmap.red[bg_idx] & 0xff) << 24) | |
138 | (info->cmap.green[bg_idx] << 16) | | 133 | ((info->cmap.green[bg_idx] & 0xff) << 16) | |
139 | (info->cmap.blue[bg_idx] << 8); | 134 | ((info->cmap.blue[bg_idx] & 0xff) << 8); |
140 | 135 | ||
141 | wait_for_fifo(2, par); | 136 | wait_for_fifo(2, par); |
142 | aty_st_le32(CUR_CLR0, bg, par); | 137 | aty_st_le32(CUR_CLR0, bg, par); |
@@ -166,19 +161,17 @@ static int atyfb_cursor(struct fb_info *info, struct fb_cursor *cursor) | |||
166 | switch (cursor->rop) { | 161 | switch (cursor->rop) { |
167 | case ROP_XOR: | 162 | case ROP_XOR: |
168 | // Upper 4 bits of mask data | 163 | // Upper 4 bits of mask data |
169 | fb_writeb(cursor_mask_lookup[m >> 4 ] | | 164 | fb_writeb(cursor_bits_lookup[(b ^ m) >> 4], dst++); |
170 | cursor_bits_lookup[(b ^ m) >> 4], dst++); | ||
171 | // Lower 4 bits of mask | 165 | // Lower 4 bits of mask |
172 | fb_writeb(cursor_mask_lookup[m & 0x0f ] | | 166 | fb_writeb(cursor_bits_lookup[(b ^ m) & 0x0f], |
173 | cursor_bits_lookup[(b ^ m) & 0x0f], dst++); | 167 | dst++); |
174 | break; | 168 | break; |
175 | case ROP_COPY: | 169 | case ROP_COPY: |
176 | // Upper 4 bits of mask data | 170 | // Upper 4 bits of mask data |
177 | fb_writeb(cursor_mask_lookup[m >> 4 ] | | 171 | fb_writeb(cursor_bits_lookup[(b & m) >> 4], dst++); |
178 | cursor_bits_lookup[(b & m) >> 4], dst++); | ||
179 | // Lower 4 bits of mask | 172 | // Lower 4 bits of mask |
180 | fb_writeb(cursor_mask_lookup[m & 0x0f ] | | 173 | fb_writeb(cursor_bits_lookup[(b & m) & 0x0f], |
181 | cursor_bits_lookup[(b & m) & 0x0f], dst++); | 174 | dst++); |
182 | break; | 175 | break; |
183 | } | 176 | } |
184 | } | 177 | } |
@@ -194,7 +187,7 @@ static int atyfb_cursor(struct fb_info *info, struct fb_cursor *cursor) | |||
194 | return 0; | 187 | return 0; |
195 | } | 188 | } |
196 | 189 | ||
197 | int __init aty_init_cursor(struct fb_info *info) | 190 | int __devinit aty_init_cursor(struct fb_info *info) |
198 | { | 191 | { |
199 | unsigned long addr; | 192 | unsigned long addr; |
200 | 193 | ||
diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c index c5ecbb02e01d..68b15645b893 100644 --- a/drivers/video/aty/radeon_base.c +++ b/drivers/video/aty/radeon_base.c | |||
@@ -2379,7 +2379,6 @@ err_release_pci0: | |||
2379 | err_release_fb: | 2379 | err_release_fb: |
2380 | framebuffer_release(info); | 2380 | framebuffer_release(info); |
2381 | err_disable: | 2381 | err_disable: |
2382 | pci_disable_device(pdev); | ||
2383 | err_out: | 2382 | err_out: |
2384 | return ret; | 2383 | return ret; |
2385 | } | 2384 | } |
@@ -2436,7 +2435,6 @@ static void __devexit radeonfb_pci_unregister (struct pci_dev *pdev) | |||
2436 | #endif | 2435 | #endif |
2437 | fb_dealloc_cmap(&info->cmap); | 2436 | fb_dealloc_cmap(&info->cmap); |
2438 | framebuffer_release(info); | 2437 | framebuffer_release(info); |
2439 | pci_disable_device(pdev); | ||
2440 | } | 2438 | } |
2441 | 2439 | ||
2442 | 2440 | ||
diff --git a/drivers/video/au1100fb.c b/drivers/video/au1100fb.c index 789450bb0bc9..9ef68cd83bb4 100644 --- a/drivers/video/au1100fb.c +++ b/drivers/video/au1100fb.c | |||
@@ -7,6 +7,8 @@ | |||
7 | * Karl Lessard <klessard@sunrisetelecom.com> | 7 | * Karl Lessard <klessard@sunrisetelecom.com> |
8 | * <c.pellegrin@exadron.com> | 8 | * <c.pellegrin@exadron.com> |
9 | * | 9 | * |
10 | * PM support added by Rodolfo Giometti <giometti@linux.it> | ||
11 | * | ||
10 | * Copyright 2002 MontaVista Software | 12 | * Copyright 2002 MontaVista Software |
11 | * Author: MontaVista Software, Inc. | 13 | * Author: MontaVista Software, Inc. |
12 | * ppopov@mvista.com or source@mvista.com | 14 | * ppopov@mvista.com or source@mvista.com |
@@ -602,17 +604,52 @@ int au1100fb_drv_remove(struct device *dev) | |||
602 | return 0; | 604 | return 0; |
603 | } | 605 | } |
604 | 606 | ||
607 | #ifdef CONFIG_PM | ||
608 | static u32 sys_clksrc; | ||
609 | static struct au1100fb_regs fbregs; | ||
610 | |||
605 | int au1100fb_drv_suspend(struct device *dev, pm_message_t state) | 611 | int au1100fb_drv_suspend(struct device *dev, pm_message_t state) |
606 | { | 612 | { |
607 | /* TODO */ | 613 | struct au1100fb_device *fbdev = dev_get_drvdata(dev); |
614 | |||
615 | if (!fbdev) | ||
616 | return 0; | ||
617 | |||
618 | /* Save the clock source state */ | ||
619 | sys_clksrc = au_readl(SYS_CLKSRC); | ||
620 | |||
621 | /* Blank the LCD */ | ||
622 | au1100fb_fb_blank(VESA_POWERDOWN, &fbdev->info); | ||
623 | |||
624 | /* Stop LCD clocking */ | ||
625 | au_writel(sys_clksrc & ~SYS_CS_ML_MASK, SYS_CLKSRC); | ||
626 | |||
627 | memcpy(&fbregs, fbdev->regs, sizeof(struct au1100fb_regs)); | ||
628 | |||
608 | return 0; | 629 | return 0; |
609 | } | 630 | } |
610 | 631 | ||
611 | int au1100fb_drv_resume(struct device *dev) | 632 | int au1100fb_drv_resume(struct device *dev) |
612 | { | 633 | { |
613 | /* TODO */ | 634 | struct au1100fb_device *fbdev = dev_get_drvdata(dev); |
635 | |||
636 | if (!fbdev) | ||
637 | return 0; | ||
638 | |||
639 | memcpy(fbdev->regs, &fbregs, sizeof(struct au1100fb_regs)); | ||
640 | |||
641 | /* Restart LCD clocking */ | ||
642 | au_writel(sys_clksrc, SYS_CLKSRC); | ||
643 | |||
644 | /* Unblank the LCD */ | ||
645 | au1100fb_fb_blank(VESA_NO_BLANKING, &fbdev->info); | ||
646 | |||
614 | return 0; | 647 | return 0; |
615 | } | 648 | } |
649 | #else | ||
650 | #define au1100fb_drv_suspend NULL | ||
651 | #define au1100fb_drv_resume NULL | ||
652 | #endif | ||
616 | 653 | ||
617 | static struct device_driver au1100fb_driver = { | 654 | static struct device_driver au1100fb_driver = { |
618 | .name = "au1100-lcd", | 655 | .name = "au1100-lcd", |
@@ -706,8 +743,7 @@ void __exit au1100fb_cleanup(void) | |||
706 | { | 743 | { |
707 | driver_unregister(&au1100fb_driver); | 744 | driver_unregister(&au1100fb_driver); |
708 | 745 | ||
709 | if (drv_info.opt_mode) | 746 | kfree(drv_info.opt_mode); |
710 | kfree(drv_info.opt_mode); | ||
711 | } | 747 | } |
712 | 748 | ||
713 | module_init(au1100fb_init); | 749 | module_init(au1100fb_init); |
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index b895eaaa73fd..022f9d3473f5 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig | |||
@@ -10,7 +10,7 @@ menuconfig BACKLIGHT_LCD_SUPPORT | |||
10 | 10 | ||
11 | config BACKLIGHT_CLASS_DEVICE | 11 | config BACKLIGHT_CLASS_DEVICE |
12 | tristate "Lowlevel Backlight controls" | 12 | tristate "Lowlevel Backlight controls" |
13 | depends on BACKLIGHT_LCD_SUPPORT | 13 | depends on BACKLIGHT_LCD_SUPPORT && FB |
14 | default m | 14 | default m |
15 | help | 15 | help |
16 | This framework adds support for low-level control of the LCD | 16 | This framework adds support for low-level control of the LCD |
@@ -26,7 +26,7 @@ config BACKLIGHT_DEVICE | |||
26 | 26 | ||
27 | config LCD_CLASS_DEVICE | 27 | config LCD_CLASS_DEVICE |
28 | tristate "Lowlevel LCD controls" | 28 | tristate "Lowlevel LCD controls" |
29 | depends on BACKLIGHT_LCD_SUPPORT | 29 | depends on BACKLIGHT_LCD_SUPPORT && FB |
30 | default m | 30 | default m |
31 | help | 31 | help |
32 | This framework adds support for low-level control of LCD. | 32 | This framework adds support for low-level control of LCD. |
@@ -50,6 +50,14 @@ config BACKLIGHT_CORGI | |||
50 | If you have a Sharp Zaurus SL-C7xx, SL-Cxx00 or SL-6000x say y to enable the | 50 | If you have a Sharp Zaurus SL-C7xx, SL-Cxx00 or SL-6000x say y to enable the |
51 | backlight driver. | 51 | backlight driver. |
52 | 52 | ||
53 | config BACKLIGHT_LOCOMO | ||
54 | tristate "Sharp LOCOMO LCD/Backlight Driver" | ||
55 | depends on BACKLIGHT_DEVICE && SHARP_LOCOMO | ||
56 | default y | ||
57 | help | ||
58 | If you have a Sharp Zaurus SL-5500 (Collie) or SL-5600 (Poodle) say y to | ||
59 | enable the LCD/backlight driver. | ||
60 | |||
53 | config BACKLIGHT_HP680 | 61 | config BACKLIGHT_HP680 |
54 | tristate "HP Jornada 680 Backlight Driver" | 62 | tristate "HP Jornada 680 Backlight Driver" |
55 | depends on BACKLIGHT_DEVICE && SH_HP6XX | 63 | depends on BACKLIGHT_DEVICE && SH_HP6XX |
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index 744210c38e74..65e5553fc849 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile | |||
@@ -4,4 +4,4 @@ obj-$(CONFIG_LCD_CLASS_DEVICE) += lcd.o | |||
4 | obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o | 4 | obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o |
5 | obj-$(CONFIG_BACKLIGHT_CORGI) += corgi_bl.o | 5 | obj-$(CONFIG_BACKLIGHT_CORGI) += corgi_bl.o |
6 | obj-$(CONFIG_BACKLIGHT_HP680) += hp680_bl.o | 6 | obj-$(CONFIG_BACKLIGHT_HP680) += hp680_bl.o |
7 | obj-$(CONFIG_SHARP_LOCOMO) += locomolcd.o | 7 | obj-$(CONFIG_BACKLIGHT_LOCOMO) += locomolcd.o |
diff --git a/drivers/video/backlight/hp680_bl.c b/drivers/video/backlight/hp680_bl.c index a71e984c93d4..ffc72ae3ada8 100644 --- a/drivers/video/backlight/hp680_bl.c +++ b/drivers/video/backlight/hp680_bl.c | |||
@@ -27,7 +27,7 @@ | |||
27 | 27 | ||
28 | static int hp680bl_suspended; | 28 | static int hp680bl_suspended; |
29 | static int current_intensity = 0; | 29 | static int current_intensity = 0; |
30 | static spinlock_t bl_lock = SPIN_LOCK_UNLOCKED; | 30 | static DEFINE_SPINLOCK(bl_lock); |
31 | static struct backlight_device *hp680_backlight_device; | 31 | static struct backlight_device *hp680_backlight_device; |
32 | 32 | ||
33 | static void hp680bl_send_intensity(struct backlight_device *bd) | 33 | static void hp680bl_send_intensity(struct backlight_device *bd) |
diff --git a/drivers/video/backlight/locomolcd.c b/drivers/video/backlight/locomolcd.c index 60831bb23685..bd879b7ec119 100644 --- a/drivers/video/backlight/locomolcd.c +++ b/drivers/video/backlight/locomolcd.c | |||
@@ -17,6 +17,8 @@ | |||
17 | #include <linux/delay.h> | 17 | #include <linux/delay.h> |
18 | #include <linux/device.h> | 18 | #include <linux/device.h> |
19 | #include <linux/interrupt.h> | 19 | #include <linux/interrupt.h> |
20 | #include <linux/fb.h> | ||
21 | #include <linux/backlight.h> | ||
20 | 22 | ||
21 | #include <asm/hardware/locomo.h> | 23 | #include <asm/hardware/locomo.h> |
22 | #include <asm/irq.h> | 24 | #include <asm/irq.h> |
@@ -25,7 +27,10 @@ | |||
25 | 27 | ||
26 | #include "../../../arch/arm/mach-sa1100/generic.h" | 28 | #include "../../../arch/arm/mach-sa1100/generic.h" |
27 | 29 | ||
30 | static struct backlight_device *locomolcd_bl_device; | ||
28 | static struct locomo_dev *locomolcd_dev; | 31 | static struct locomo_dev *locomolcd_dev; |
32 | static unsigned long locomolcd_flags; | ||
33 | #define LOCOMOLCD_SUSPENDED 0x01 | ||
29 | 34 | ||
30 | static void locomolcd_on(int comadj) | 35 | static void locomolcd_on(int comadj) |
31 | { | 36 | { |
@@ -89,12 +94,10 @@ void locomolcd_power(int on) | |||
89 | } | 94 | } |
90 | 95 | ||
91 | /* read comadj */ | 96 | /* read comadj */ |
92 | if (comadj == -1) { | 97 | if (comadj == -1 && machine_is_collie()) |
93 | if (machine_is_poodle()) | 98 | comadj = 128; |
94 | comadj = 118; | 99 | if (comadj == -1 && machine_is_poodle()) |
95 | if (machine_is_collie()) | 100 | comadj = 118; |
96 | comadj = 128; | ||
97 | } | ||
98 | 101 | ||
99 | if (on) | 102 | if (on) |
100 | locomolcd_on(comadj); | 103 | locomolcd_on(comadj); |
@@ -105,26 +108,100 @@ void locomolcd_power(int on) | |||
105 | } | 108 | } |
106 | EXPORT_SYMBOL(locomolcd_power); | 109 | EXPORT_SYMBOL(locomolcd_power); |
107 | 110 | ||
108 | static int poodle_lcd_probe(struct locomo_dev *dev) | 111 | |
112 | static int current_intensity; | ||
113 | |||
114 | static int locomolcd_set_intensity(struct backlight_device *bd) | ||
115 | { | ||
116 | int intensity = bd->props->brightness; | ||
117 | |||
118 | if (bd->props->power != FB_BLANK_UNBLANK) | ||
119 | intensity = 0; | ||
120 | if (bd->props->fb_blank != FB_BLANK_UNBLANK) | ||
121 | intensity = 0; | ||
122 | if (locomolcd_flags & LOCOMOLCD_SUSPENDED) | ||
123 | intensity = 0; | ||
124 | |||
125 | switch (intensity) { | ||
126 | /* AC and non-AC are handled differently, but produce same results in sharp code? */ | ||
127 | case 0: locomo_frontlight_set(locomolcd_dev, 0, 0, 161); break; | ||
128 | case 1: locomo_frontlight_set(locomolcd_dev, 117, 0, 161); break; | ||
129 | case 2: locomo_frontlight_set(locomolcd_dev, 163, 0, 148); break; | ||
130 | case 3: locomo_frontlight_set(locomolcd_dev, 194, 0, 161); break; | ||
131 | case 4: locomo_frontlight_set(locomolcd_dev, 194, 1, 161); break; | ||
132 | |||
133 | default: | ||
134 | return -ENODEV; | ||
135 | } | ||
136 | current_intensity = intensity; | ||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | static int locomolcd_get_intensity(struct backlight_device *bd) | ||
141 | { | ||
142 | return current_intensity; | ||
143 | } | ||
144 | |||
145 | static struct backlight_properties locomobl_data = { | ||
146 | .owner = THIS_MODULE, | ||
147 | .get_brightness = locomolcd_get_intensity, | ||
148 | .update_status = locomolcd_set_intensity, | ||
149 | .max_brightness = 4, | ||
150 | }; | ||
151 | |||
152 | #ifdef CONFIG_PM | ||
153 | static int locomolcd_suspend(struct locomo_dev *dev, pm_message_t state) | ||
154 | { | ||
155 | locomolcd_flags |= LOCOMOLCD_SUSPENDED; | ||
156 | locomolcd_set_intensity(locomolcd_bl_device); | ||
157 | return 0; | ||
158 | } | ||
159 | |||
160 | static int locomolcd_resume(struct locomo_dev *dev) | ||
161 | { | ||
162 | locomolcd_flags &= ~LOCOMOLCD_SUSPENDED; | ||
163 | locomolcd_set_intensity(locomolcd_bl_device); | ||
164 | return 0; | ||
165 | } | ||
166 | #else | ||
167 | #define locomolcd_suspend NULL | ||
168 | #define locomolcd_resume NULL | ||
169 | #endif | ||
170 | |||
171 | static int locomolcd_probe(struct locomo_dev *dev) | ||
109 | { | 172 | { |
110 | unsigned long flags; | 173 | unsigned long flags; |
111 | 174 | ||
112 | local_irq_save(flags); | 175 | local_irq_save(flags); |
113 | locomolcd_dev = dev; | 176 | locomolcd_dev = dev; |
114 | 177 | ||
178 | locomo_gpio_set_dir(dev, LOCOMO_GPIO_FL_VR, 0); | ||
179 | |||
115 | /* the poodle_lcd_power function is called for the first time | 180 | /* the poodle_lcd_power function is called for the first time |
116 | * from fs_initcall, which is before locomo is activated. | 181 | * from fs_initcall, which is before locomo is activated. |
117 | * We need to recall poodle_lcd_power here*/ | 182 | * We need to recall poodle_lcd_power here*/ |
118 | #ifdef CONFIG_MACH_POODLE | 183 | if (machine_is_poodle()) |
119 | locomolcd_power(1); | 184 | locomolcd_power(1); |
120 | #endif | 185 | |
121 | local_irq_restore(flags); | 186 | local_irq_restore(flags); |
187 | |||
188 | locomolcd_bl_device = backlight_device_register("locomo-bl", NULL, &locomobl_data); | ||
189 | |||
190 | if (IS_ERR (locomolcd_bl_device)) | ||
191 | return PTR_ERR (locomolcd_bl_device); | ||
192 | |||
193 | /* Set up frontlight so that screen is readable */ | ||
194 | locomobl_data.brightness = 2; | ||
195 | locomolcd_set_intensity(locomolcd_bl_device); | ||
196 | |||
122 | return 0; | 197 | return 0; |
123 | } | 198 | } |
124 | 199 | ||
125 | static int poodle_lcd_remove(struct locomo_dev *dev) | 200 | static int locomolcd_remove(struct locomo_dev *dev) |
126 | { | 201 | { |
127 | unsigned long flags; | 202 | unsigned long flags; |
203 | |||
204 | backlight_device_unregister(locomolcd_bl_device); | ||
128 | local_irq_save(flags); | 205 | local_irq_save(flags); |
129 | locomolcd_dev = NULL; | 206 | locomolcd_dev = NULL; |
130 | local_irq_restore(flags); | 207 | local_irq_restore(flags); |
@@ -136,19 +213,33 @@ static struct locomo_driver poodle_lcd_driver = { | |||
136 | .name = "locomo-backlight", | 213 | .name = "locomo-backlight", |
137 | }, | 214 | }, |
138 | .devid = LOCOMO_DEVID_BACKLIGHT, | 215 | .devid = LOCOMO_DEVID_BACKLIGHT, |
139 | .probe = poodle_lcd_probe, | 216 | .probe = locomolcd_probe, |
140 | .remove = poodle_lcd_remove, | 217 | .remove = locomolcd_remove, |
218 | .suspend = locomolcd_suspend, | ||
219 | .resume = locomolcd_resume, | ||
141 | }; | 220 | }; |
142 | 221 | ||
143 | static int __init poodle_lcd_init(void) | 222 | |
223 | static int __init locomolcd_init(void) | ||
144 | { | 224 | { |
145 | int ret = locomo_driver_register(&poodle_lcd_driver); | 225 | int ret = locomo_driver_register(&poodle_lcd_driver); |
146 | if (ret) return ret; | 226 | if (ret) |
227 | return ret; | ||
147 | 228 | ||
148 | #ifdef CONFIG_SA1100_COLLIE | 229 | #ifdef CONFIG_SA1100_COLLIE |
149 | sa1100fb_lcd_power = locomolcd_power; | 230 | sa1100fb_lcd_power = locomolcd_power; |
150 | #endif | 231 | #endif |
151 | return 0; | 232 | return 0; |
152 | } | 233 | } |
153 | device_initcall(poodle_lcd_init); | ||
154 | 234 | ||
235 | static void __exit locomolcd_exit(void) | ||
236 | { | ||
237 | locomo_driver_unregister(&poodle_lcd_driver); | ||
238 | } | ||
239 | |||
240 | module_init(locomolcd_init); | ||
241 | module_exit(locomolcd_exit); | ||
242 | |||
243 | MODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>, Pavel Machek <pavel@suse.cz>"); | ||
244 | MODULE_DESCRIPTION("Collie LCD driver"); | ||
245 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/cfbimgblt.c b/drivers/video/cfbimgblt.c index 8ba6152db2fd..ad8a89bf8eae 100644 --- a/drivers/video/cfbimgblt.c +++ b/drivers/video/cfbimgblt.c | |||
@@ -230,6 +230,7 @@ static inline void fast_imageblit(const struct fb_image *image, struct fb_info * | |||
230 | tab = cfb_tab16; | 230 | tab = cfb_tab16; |
231 | break; | 231 | break; |
232 | case 32: | 232 | case 32: |
233 | default: | ||
233 | tab = cfb_tab32; | 234 | tab = cfb_tab32; |
234 | break; | 235 | break; |
235 | } | 236 | } |
diff --git a/drivers/video/cirrusfb.c b/drivers/video/cirrusfb.c index 1103010af54a..dda240eb7360 100644 --- a/drivers/video/cirrusfb.c +++ b/drivers/video/cirrusfb.c | |||
@@ -2227,7 +2227,6 @@ static void cirrusfb_pci_unmap (struct cirrusfb_info *cinfo) | |||
2227 | release_region(0x3C0, 32); | 2227 | release_region(0x3C0, 32); |
2228 | pci_release_regions(pdev); | 2228 | pci_release_regions(pdev); |
2229 | framebuffer_release(cinfo->info); | 2229 | framebuffer_release(cinfo->info); |
2230 | pci_disable_device(pdev); | ||
2231 | } | 2230 | } |
2232 | #endif /* CONFIG_PCI */ | 2231 | #endif /* CONFIG_PCI */ |
2233 | 2232 | ||
@@ -2458,7 +2457,6 @@ err_release_regions: | |||
2458 | err_release_fb: | 2457 | err_release_fb: |
2459 | framebuffer_release(info); | 2458 | framebuffer_release(info); |
2460 | err_disable: | 2459 | err_disable: |
2461 | pci_disable_device(pdev); | ||
2462 | err_out: | 2460 | err_out: |
2463 | return ret; | 2461 | return ret; |
2464 | } | 2462 | } |
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 47ba1a79adcd..5dc4083552d8 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c | |||
@@ -125,6 +125,8 @@ static int softback_lines; | |||
125 | static int first_fb_vc; | 125 | static int first_fb_vc; |
126 | static int last_fb_vc = MAX_NR_CONSOLES - 1; | 126 | static int last_fb_vc = MAX_NR_CONSOLES - 1; |
127 | static int fbcon_is_default = 1; | 127 | static int fbcon_is_default = 1; |
128 | static int fbcon_has_exited; | ||
129 | |||
128 | /* font data */ | 130 | /* font data */ |
129 | static char fontname[40]; | 131 | static char fontname[40]; |
130 | 132 | ||
@@ -140,7 +142,6 @@ static const struct consw fb_con; | |||
140 | 142 | ||
141 | #define advance_row(p, delta) (unsigned short *)((unsigned long)(p) + (delta) * vc->vc_size_row) | 143 | #define advance_row(p, delta) (unsigned short *)((unsigned long)(p) + (delta) * vc->vc_size_row) |
142 | 144 | ||
143 | static void fbcon_free_font(struct display *); | ||
144 | static int fbcon_set_origin(struct vc_data *); | 145 | static int fbcon_set_origin(struct vc_data *); |
145 | 146 | ||
146 | #define CURSOR_DRAW_DELAY (1) | 147 | #define CURSOR_DRAW_DELAY (1) |
@@ -194,6 +195,9 @@ static void fbcon_redraw_move(struct vc_data *vc, struct display *p, | |||
194 | int line, int count, int dy); | 195 | int line, int count, int dy); |
195 | static void fbcon_modechanged(struct fb_info *info); | 196 | static void fbcon_modechanged(struct fb_info *info); |
196 | static void fbcon_set_all_vcs(struct fb_info *info); | 197 | static void fbcon_set_all_vcs(struct fb_info *info); |
198 | static void fbcon_start(void); | ||
199 | static void fbcon_exit(void); | ||
200 | static struct class_device *fbcon_class_device; | ||
197 | 201 | ||
198 | #ifdef CONFIG_MAC | 202 | #ifdef CONFIG_MAC |
199 | /* | 203 | /* |
@@ -252,7 +256,7 @@ static void fbcon_rotate_all(struct fb_info *info, u32 rotate) | |||
252 | if (!ops || ops->currcon < 0 || rotate > 3) | 256 | if (!ops || ops->currcon < 0 || rotate > 3) |
253 | return; | 257 | return; |
254 | 258 | ||
255 | for (i = 0; i < MAX_NR_CONSOLES; i++) { | 259 | for (i = first_fb_vc; i <= last_fb_vc; i++) { |
256 | vc = vc_cons[i].d; | 260 | vc = vc_cons[i].d; |
257 | if (!vc || vc->vc_mode != KD_TEXT || | 261 | if (!vc || vc->vc_mode != KD_TEXT || |
258 | registered_fb[con2fb_map[i]] != info) | 262 | registered_fb[con2fb_map[i]] != info) |
@@ -389,15 +393,18 @@ static void fb_flashcursor(void *private) | |||
389 | int c; | 393 | int c; |
390 | int mode; | 394 | int mode; |
391 | 395 | ||
392 | if (ops->currcon != -1) | 396 | acquire_console_sem(); |
397 | if (ops && ops->currcon != -1) | ||
393 | vc = vc_cons[ops->currcon].d; | 398 | vc = vc_cons[ops->currcon].d; |
394 | 399 | ||
395 | if (!vc || !CON_IS_VISIBLE(vc) || | 400 | if (!vc || !CON_IS_VISIBLE(vc) || |
396 | fbcon_is_inactive(vc, info) || | 401 | fbcon_is_inactive(vc, info) || |
397 | registered_fb[con2fb_map[vc->vc_num]] != info || | 402 | registered_fb[con2fb_map[vc->vc_num]] != info || |
398 | vc_cons[ops->currcon].d->vc_deccm != 1) | 403 | vc_cons[ops->currcon].d->vc_deccm != 1) { |
404 | release_console_sem(); | ||
399 | return; | 405 | return; |
400 | acquire_console_sem(); | 406 | } |
407 | |||
401 | p = &fb_display[vc->vc_num]; | 408 | p = &fb_display[vc->vc_num]; |
402 | c = scr_readw((u16 *) vc->vc_pos); | 409 | c = scr_readw((u16 *) vc->vc_pos); |
403 | mode = (!ops->cursor_flash || ops->cursor_state.enable) ? | 410 | mode = (!ops->cursor_flash || ops->cursor_state.enable) ? |
@@ -528,7 +535,7 @@ static int search_fb_in_map(int idx) | |||
528 | { | 535 | { |
529 | int i, retval = 0; | 536 | int i, retval = 0; |
530 | 537 | ||
531 | for (i = 0; i < MAX_NR_CONSOLES; i++) { | 538 | for (i = first_fb_vc; i <= last_fb_vc; i++) { |
532 | if (con2fb_map[i] == idx) | 539 | if (con2fb_map[i] == idx) |
533 | retval = 1; | 540 | retval = 1; |
534 | } | 541 | } |
@@ -539,7 +546,7 @@ static int search_for_mapped_con(void) | |||
539 | { | 546 | { |
540 | int i, retval = 0; | 547 | int i, retval = 0; |
541 | 548 | ||
542 | for (i = 0; i < MAX_NR_CONSOLES; i++) { | 549 | for (i = first_fb_vc; i <= last_fb_vc; i++) { |
543 | if (con2fb_map[i] != -1) | 550 | if (con2fb_map[i] != -1) |
544 | retval = 1; | 551 | retval = 1; |
545 | } | 552 | } |
@@ -561,6 +568,7 @@ static int fbcon_takeover(int show_logo) | |||
561 | 568 | ||
562 | err = take_over_console(&fb_con, first_fb_vc, last_fb_vc, | 569 | err = take_over_console(&fb_con, first_fb_vc, last_fb_vc, |
563 | fbcon_is_default); | 570 | fbcon_is_default); |
571 | |||
564 | if (err) { | 572 | if (err) { |
565 | for (i = first_fb_vc; i <= last_fb_vc; i++) { | 573 | for (i = first_fb_vc; i <= last_fb_vc; i++) { |
566 | con2fb_map[i] = -1; | 574 | con2fb_map[i] = -1; |
@@ -795,8 +803,8 @@ static int set_con2fb_map(int unit, int newidx, int user) | |||
795 | if (oldidx == newidx) | 803 | if (oldidx == newidx) |
796 | return 0; | 804 | return 0; |
797 | 805 | ||
798 | if (!info) | 806 | if (!info || fbcon_has_exited) |
799 | err = -EINVAL; | 807 | return -EINVAL; |
800 | 808 | ||
801 | if (!err && !search_for_mapped_con()) { | 809 | if (!err && !search_for_mapped_con()) { |
802 | info_idx = newidx; | 810 | info_idx = newidx; |
@@ -832,6 +840,9 @@ static int set_con2fb_map(int unit, int newidx, int user) | |||
832 | con2fb_init_display(vc, info, unit, show_logo); | 840 | con2fb_init_display(vc, info, unit, show_logo); |
833 | } | 841 | } |
834 | 842 | ||
843 | if (!search_fb_in_map(info_idx)) | ||
844 | info_idx = newidx; | ||
845 | |||
835 | release_console_sem(); | 846 | release_console_sem(); |
836 | return err; | 847 | return err; |
837 | } | 848 | } |
@@ -1034,6 +1045,7 @@ static const char *fbcon_startup(void) | |||
1034 | #endif /* CONFIG_MAC */ | 1045 | #endif /* CONFIG_MAC */ |
1035 | 1046 | ||
1036 | fbcon_add_cursor_timer(info); | 1047 | fbcon_add_cursor_timer(info); |
1048 | fbcon_has_exited = 0; | ||
1037 | return display_desc; | 1049 | return display_desc; |
1038 | } | 1050 | } |
1039 | 1051 | ||
@@ -1061,17 +1073,36 @@ static void fbcon_init(struct vc_data *vc, int init) | |||
1061 | 1073 | ||
1062 | /* If we are not the first console on this | 1074 | /* If we are not the first console on this |
1063 | fb, copy the font from that console */ | 1075 | fb, copy the font from that console */ |
1064 | t = &fb_display[svc->vc_num]; | 1076 | t = &fb_display[fg_console]; |
1065 | if (!vc->vc_font.data) { | 1077 | if (!p->fontdata) { |
1066 | vc->vc_font.data = (void *)(p->fontdata = t->fontdata); | 1078 | if (t->fontdata) { |
1067 | vc->vc_font.width = (*default_mode)->vc_font.width; | 1079 | struct vc_data *fvc = vc_cons[fg_console].d; |
1068 | vc->vc_font.height = (*default_mode)->vc_font.height; | 1080 | |
1069 | p->userfont = t->userfont; | 1081 | vc->vc_font.data = (void *)(p->fontdata = |
1070 | if (p->userfont) | 1082 | fvc->vc_font.data); |
1071 | REFCOUNT(p->fontdata)++; | 1083 | vc->vc_font.width = fvc->vc_font.width; |
1084 | vc->vc_font.height = fvc->vc_font.height; | ||
1085 | p->userfont = t->userfont; | ||
1086 | |||
1087 | if (p->userfont) | ||
1088 | REFCOUNT(p->fontdata)++; | ||
1089 | } else { | ||
1090 | const struct font_desc *font = NULL; | ||
1091 | |||
1092 | if (!fontname[0] || !(font = find_font(fontname))) | ||
1093 | font = get_default_font(info->var.xres, | ||
1094 | info->var.yres); | ||
1095 | vc->vc_font.width = font->width; | ||
1096 | vc->vc_font.height = font->height; | ||
1097 | vc->vc_font.data = (void *)(p->fontdata = font->data); | ||
1098 | vc->vc_font.charcount = 256; /* FIXME Need to | ||
1099 | support more fonts */ | ||
1100 | } | ||
1072 | } | 1101 | } |
1102 | |||
1073 | if (p->userfont) | 1103 | if (p->userfont) |
1074 | charcnt = FNTCHARCNT(p->fontdata); | 1104 | charcnt = FNTCHARCNT(p->fontdata); |
1105 | |||
1075 | vc->vc_can_do_color = (fb_get_color_depth(&info->var, &info->fix)!=1); | 1106 | vc->vc_can_do_color = (fb_get_color_depth(&info->var, &info->fix)!=1); |
1076 | vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800; | 1107 | vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800; |
1077 | if (charcnt == 256) { | 1108 | if (charcnt == 256) { |
@@ -1145,13 +1176,47 @@ static void fbcon_init(struct vc_data *vc, int init) | |||
1145 | ops->p = &fb_display[fg_console]; | 1176 | ops->p = &fb_display[fg_console]; |
1146 | } | 1177 | } |
1147 | 1178 | ||
1179 | static void fbcon_free_font(struct display *p) | ||
1180 | { | ||
1181 | if (p->userfont && p->fontdata && (--REFCOUNT(p->fontdata) == 0)) | ||
1182 | kfree(p->fontdata - FONT_EXTRA_WORDS * sizeof(int)); | ||
1183 | p->fontdata = NULL; | ||
1184 | p->userfont = 0; | ||
1185 | } | ||
1186 | |||
1148 | static void fbcon_deinit(struct vc_data *vc) | 1187 | static void fbcon_deinit(struct vc_data *vc) |
1149 | { | 1188 | { |
1150 | struct display *p = &fb_display[vc->vc_num]; | 1189 | struct display *p = &fb_display[vc->vc_num]; |
1190 | struct fb_info *info; | ||
1191 | struct fbcon_ops *ops; | ||
1192 | int idx; | ||
1151 | 1193 | ||
1152 | if (info_idx != -1) | ||
1153 | return; | ||
1154 | fbcon_free_font(p); | 1194 | fbcon_free_font(p); |
1195 | idx = con2fb_map[vc->vc_num]; | ||
1196 | |||
1197 | if (idx == -1) | ||
1198 | goto finished; | ||
1199 | |||
1200 | info = registered_fb[idx]; | ||
1201 | |||
1202 | if (!info) | ||
1203 | goto finished; | ||
1204 | |||
1205 | ops = info->fbcon_par; | ||
1206 | |||
1207 | if (!ops) | ||
1208 | goto finished; | ||
1209 | |||
1210 | if (CON_IS_VISIBLE(vc)) | ||
1211 | fbcon_del_cursor_timer(info); | ||
1212 | |||
1213 | ops->flags &= ~FBCON_FLAGS_INIT; | ||
1214 | finished: | ||
1215 | |||
1216 | if (!con_is_bound(&fb_con)) | ||
1217 | fbcon_exit(); | ||
1218 | |||
1219 | return; | ||
1155 | } | 1220 | } |
1156 | 1221 | ||
1157 | /* ====================================================================== */ | 1222 | /* ====================================================================== */ |
@@ -2099,12 +2164,11 @@ static int fbcon_switch(struct vc_data *vc) | |||
2099 | if (info->fbops->fb_set_par) | 2164 | if (info->fbops->fb_set_par) |
2100 | info->fbops->fb_set_par(info); | 2165 | info->fbops->fb_set_par(info); |
2101 | 2166 | ||
2102 | if (old_info != info) { | 2167 | if (old_info != info) |
2103 | fbcon_del_cursor_timer(old_info); | 2168 | fbcon_del_cursor_timer(old_info); |
2104 | fbcon_add_cursor_timer(info); | ||
2105 | } | ||
2106 | } | 2169 | } |
2107 | 2170 | ||
2171 | fbcon_add_cursor_timer(info); | ||
2108 | set_blitting_type(vc, info); | 2172 | set_blitting_type(vc, info); |
2109 | ops->cursor_reset = 1; | 2173 | ops->cursor_reset = 1; |
2110 | 2174 | ||
@@ -2222,14 +2286,6 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch) | |||
2222 | return 0; | 2286 | return 0; |
2223 | } | 2287 | } |
2224 | 2288 | ||
2225 | static void fbcon_free_font(struct display *p) | ||
2226 | { | ||
2227 | if (p->userfont && p->fontdata && (--REFCOUNT(p->fontdata) == 0)) | ||
2228 | kfree(p->fontdata - FONT_EXTRA_WORDS * sizeof(int)); | ||
2229 | p->fontdata = NULL; | ||
2230 | p->userfont = 0; | ||
2231 | } | ||
2232 | |||
2233 | static int fbcon_get_font(struct vc_data *vc, struct console_font *font) | 2289 | static int fbcon_get_font(struct vc_data *vc, struct console_font *font) |
2234 | { | 2290 | { |
2235 | u8 *fontdata = vc->vc_font.data; | 2291 | u8 *fontdata = vc->vc_font.data; |
@@ -2443,7 +2499,7 @@ static int fbcon_set_font(struct vc_data *vc, struct console_font *font, unsigne | |||
2443 | 2499 | ||
2444 | FNTSUM(new_data) = csum; | 2500 | FNTSUM(new_data) = csum; |
2445 | /* Check if the same font is on some other console already */ | 2501 | /* Check if the same font is on some other console already */ |
2446 | for (i = 0; i < MAX_NR_CONSOLES; i++) { | 2502 | for (i = first_fb_vc; i <= last_fb_vc; i++) { |
2447 | struct vc_data *tmp = vc_cons[i].d; | 2503 | struct vc_data *tmp = vc_cons[i].d; |
2448 | 2504 | ||
2449 | if (fb_display[i].userfont && | 2505 | if (fb_display[i].userfont && |
@@ -2768,7 +2824,7 @@ static void fbcon_set_all_vcs(struct fb_info *info) | |||
2768 | if (!ops || ops->currcon < 0) | 2824 | if (!ops || ops->currcon < 0) |
2769 | return; | 2825 | return; |
2770 | 2826 | ||
2771 | for (i = 0; i < MAX_NR_CONSOLES; i++) { | 2827 | for (i = first_fb_vc; i <= last_fb_vc; i++) { |
2772 | vc = vc_cons[i].d; | 2828 | vc = vc_cons[i].d; |
2773 | if (!vc || vc->vc_mode != KD_TEXT || | 2829 | if (!vc || vc->vc_mode != KD_TEXT || |
2774 | registered_fb[con2fb_map[i]] != info) | 2830 | registered_fb[con2fb_map[i]] != info) |
@@ -2830,22 +2886,57 @@ static int fbcon_mode_deleted(struct fb_info *info, | |||
2830 | return found; | 2886 | return found; |
2831 | } | 2887 | } |
2832 | 2888 | ||
2889 | static int fbcon_fb_unregistered(int idx) | ||
2890 | { | ||
2891 | int i; | ||
2892 | |||
2893 | for (i = first_fb_vc; i <= last_fb_vc; i++) { | ||
2894 | if (con2fb_map[i] == idx) | ||
2895 | con2fb_map[i] = -1; | ||
2896 | } | ||
2897 | |||
2898 | if (idx == info_idx) { | ||
2899 | info_idx = -1; | ||
2900 | |||
2901 | for (i = 0; i < FB_MAX; i++) { | ||
2902 | if (registered_fb[i] != NULL) { | ||
2903 | info_idx = i; | ||
2904 | break; | ||
2905 | } | ||
2906 | } | ||
2907 | } | ||
2908 | |||
2909 | if (info_idx != -1) { | ||
2910 | for (i = first_fb_vc; i <= last_fb_vc; i++) { | ||
2911 | if (con2fb_map[i] == -1) | ||
2912 | con2fb_map[i] = info_idx; | ||
2913 | } | ||
2914 | } | ||
2915 | |||
2916 | if (!num_registered_fb) | ||
2917 | unregister_con_driver(&fb_con); | ||
2918 | |||
2919 | return 0; | ||
2920 | } | ||
2921 | |||
2833 | static int fbcon_fb_registered(int idx) | 2922 | static int fbcon_fb_registered(int idx) |
2834 | { | 2923 | { |
2835 | int ret = 0, i; | 2924 | int ret = 0, i; |
2836 | 2925 | ||
2837 | if (info_idx == -1) { | 2926 | if (info_idx == -1) { |
2838 | for (i = 0; i < MAX_NR_CONSOLES; i++) { | 2927 | for (i = first_fb_vc; i <= last_fb_vc; i++) { |
2839 | if (con2fb_map_boot[i] == idx) { | 2928 | if (con2fb_map_boot[i] == idx) { |
2840 | info_idx = idx; | 2929 | info_idx = idx; |
2841 | break; | 2930 | break; |
2842 | } | 2931 | } |
2843 | } | 2932 | } |
2933 | |||
2844 | if (info_idx != -1) | 2934 | if (info_idx != -1) |
2845 | ret = fbcon_takeover(1); | 2935 | ret = fbcon_takeover(1); |
2846 | } else { | 2936 | } else { |
2847 | for (i = 0; i < MAX_NR_CONSOLES; i++) { | 2937 | for (i = first_fb_vc; i <= last_fb_vc; i++) { |
2848 | if (con2fb_map_boot[i] == idx) | 2938 | if (con2fb_map_boot[i] == idx && |
2939 | con2fb_map[i] == -1) | ||
2849 | set_con2fb_map(i, idx, 0); | 2940 | set_con2fb_map(i, idx, 0); |
2850 | } | 2941 | } |
2851 | } | 2942 | } |
@@ -2882,7 +2973,7 @@ static void fbcon_new_modelist(struct fb_info *info) | |||
2882 | struct fb_var_screeninfo var; | 2973 | struct fb_var_screeninfo var; |
2883 | struct fb_videomode *mode; | 2974 | struct fb_videomode *mode; |
2884 | 2975 | ||
2885 | for (i = 0; i < MAX_NR_CONSOLES; i++) { | 2976 | for (i = first_fb_vc; i <= last_fb_vc; i++) { |
2886 | if (registered_fb[con2fb_map[i]] != info) | 2977 | if (registered_fb[con2fb_map[i]] != info) |
2887 | continue; | 2978 | continue; |
2888 | if (!fb_display[i].mode) | 2979 | if (!fb_display[i].mode) |
@@ -2910,6 +3001,14 @@ static int fbcon_event_notify(struct notifier_block *self, | |||
2910 | struct fb_con2fbmap *con2fb; | 3001 | struct fb_con2fbmap *con2fb; |
2911 | int ret = 0; | 3002 | int ret = 0; |
2912 | 3003 | ||
3004 | /* | ||
3005 | * ignore all events except driver registration and deregistration | ||
3006 | * if fbcon is not active | ||
3007 | */ | ||
3008 | if (fbcon_has_exited && !(action == FB_EVENT_FB_REGISTERED || | ||
3009 | action == FB_EVENT_FB_UNREGISTERED)) | ||
3010 | goto done; | ||
3011 | |||
2913 | switch(action) { | 3012 | switch(action) { |
2914 | case FB_EVENT_SUSPEND: | 3013 | case FB_EVENT_SUSPEND: |
2915 | fbcon_suspended(info); | 3014 | fbcon_suspended(info); |
@@ -2930,6 +3029,9 @@ static int fbcon_event_notify(struct notifier_block *self, | |||
2930 | case FB_EVENT_FB_REGISTERED: | 3029 | case FB_EVENT_FB_REGISTERED: |
2931 | ret = fbcon_fb_registered(info->node); | 3030 | ret = fbcon_fb_registered(info->node); |
2932 | break; | 3031 | break; |
3032 | case FB_EVENT_FB_UNREGISTERED: | ||
3033 | ret = fbcon_fb_unregistered(info->node); | ||
3034 | break; | ||
2933 | case FB_EVENT_SET_CONSOLE_MAP: | 3035 | case FB_EVENT_SET_CONSOLE_MAP: |
2934 | con2fb = event->data; | 3036 | con2fb = event->data; |
2935 | ret = set_con2fb_map(con2fb->console - 1, | 3037 | ret = set_con2fb_map(con2fb->console - 1, |
@@ -2945,16 +3047,9 @@ static int fbcon_event_notify(struct notifier_block *self, | |||
2945 | case FB_EVENT_NEW_MODELIST: | 3047 | case FB_EVENT_NEW_MODELIST: |
2946 | fbcon_new_modelist(info); | 3048 | fbcon_new_modelist(info); |
2947 | break; | 3049 | break; |
2948 | case FB_EVENT_SET_CON_ROTATE: | ||
2949 | fbcon_rotate(info, *(int *)event->data); | ||
2950 | break; | ||
2951 | case FB_EVENT_GET_CON_ROTATE: | ||
2952 | ret = fbcon_get_rotate(info); | ||
2953 | break; | ||
2954 | case FB_EVENT_SET_CON_ROTATE_ALL: | ||
2955 | fbcon_rotate_all(info, *(int *)event->data); | ||
2956 | } | 3050 | } |
2957 | 3051 | ||
3052 | done: | ||
2958 | return ret; | 3053 | return ret; |
2959 | } | 3054 | } |
2960 | 3055 | ||
@@ -2992,27 +3087,181 @@ static struct notifier_block fbcon_event_notifier = { | |||
2992 | .notifier_call = fbcon_event_notify, | 3087 | .notifier_call = fbcon_event_notify, |
2993 | }; | 3088 | }; |
2994 | 3089 | ||
2995 | static int __init fb_console_init(void) | 3090 | static ssize_t store_rotate(struct class_device *class_device, |
3091 | const char *buf, size_t count) | ||
2996 | { | 3092 | { |
2997 | int i; | 3093 | struct fb_info *info; |
3094 | int rotate, idx; | ||
3095 | char **last = NULL; | ||
3096 | |||
3097 | if (fbcon_has_exited) | ||
3098 | return count; | ||
2998 | 3099 | ||
2999 | acquire_console_sem(); | 3100 | acquire_console_sem(); |
3000 | fb_register_client(&fbcon_event_notifier); | 3101 | idx = con2fb_map[fg_console]; |
3102 | |||
3103 | if (idx == -1 || registered_fb[idx] == NULL) | ||
3104 | goto err; | ||
3105 | |||
3106 | info = registered_fb[idx]; | ||
3107 | rotate = simple_strtoul(buf, last, 0); | ||
3108 | fbcon_rotate(info, rotate); | ||
3109 | err: | ||
3001 | release_console_sem(); | 3110 | release_console_sem(); |
3111 | return count; | ||
3112 | } | ||
3002 | 3113 | ||
3003 | for (i = 0; i < MAX_NR_CONSOLES; i++) | 3114 | static ssize_t store_rotate_all(struct class_device *class_device, |
3004 | con2fb_map[i] = -1; | 3115 | const char *buf, size_t count) |
3116 | { | ||
3117 | struct fb_info *info; | ||
3118 | int rotate, idx; | ||
3119 | char **last = NULL; | ||
3120 | |||
3121 | if (fbcon_has_exited) | ||
3122 | return count; | ||
3123 | |||
3124 | acquire_console_sem(); | ||
3125 | idx = con2fb_map[fg_console]; | ||
3126 | |||
3127 | if (idx == -1 || registered_fb[idx] == NULL) | ||
3128 | goto err; | ||
3005 | 3129 | ||
3130 | info = registered_fb[idx]; | ||
3131 | rotate = simple_strtoul(buf, last, 0); | ||
3132 | fbcon_rotate_all(info, rotate); | ||
3133 | err: | ||
3134 | release_console_sem(); | ||
3135 | return count; | ||
3136 | } | ||
3137 | |||
3138 | static ssize_t show_rotate(struct class_device *class_device, char *buf) | ||
3139 | { | ||
3140 | struct fb_info *info; | ||
3141 | int rotate = 0, idx; | ||
3142 | |||
3143 | if (fbcon_has_exited) | ||
3144 | return 0; | ||
3145 | |||
3146 | acquire_console_sem(); | ||
3147 | idx = con2fb_map[fg_console]; | ||
3148 | |||
3149 | if (idx == -1 || registered_fb[idx] == NULL) | ||
3150 | goto err; | ||
3151 | |||
3152 | info = registered_fb[idx]; | ||
3153 | rotate = fbcon_get_rotate(info); | ||
3154 | err: | ||
3155 | release_console_sem(); | ||
3156 | return snprintf(buf, PAGE_SIZE, "%d\n", rotate); | ||
3157 | } | ||
3158 | |||
3159 | static struct class_device_attribute class_device_attrs[] = { | ||
3160 | __ATTR(rotate, S_IRUGO|S_IWUSR, show_rotate, store_rotate), | ||
3161 | __ATTR(rotate_all, S_IWUSR, NULL, store_rotate_all), | ||
3162 | }; | ||
3163 | |||
3164 | static int fbcon_init_class_device(void) | ||
3165 | { | ||
3166 | int i; | ||
3167 | |||
3168 | for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) | ||
3169 | class_device_create_file(fbcon_class_device, | ||
3170 | &class_device_attrs[i]); | ||
3171 | return 0; | ||
3172 | } | ||
3173 | |||
3174 | static void fbcon_start(void) | ||
3175 | { | ||
3006 | if (num_registered_fb) { | 3176 | if (num_registered_fb) { |
3177 | int i; | ||
3178 | |||
3179 | acquire_console_sem(); | ||
3180 | |||
3007 | for (i = 0; i < FB_MAX; i++) { | 3181 | for (i = 0; i < FB_MAX; i++) { |
3008 | if (registered_fb[i] != NULL) { | 3182 | if (registered_fb[i] != NULL) { |
3009 | info_idx = i; | 3183 | info_idx = i; |
3010 | break; | 3184 | break; |
3011 | } | 3185 | } |
3012 | } | 3186 | } |
3187 | |||
3188 | release_console_sem(); | ||
3013 | fbcon_takeover(0); | 3189 | fbcon_takeover(0); |
3014 | } | 3190 | } |
3191 | } | ||
3192 | |||
3193 | static void fbcon_exit(void) | ||
3194 | { | ||
3195 | struct fb_info *info; | ||
3196 | int i, j, mapped; | ||
3197 | |||
3198 | if (fbcon_has_exited) | ||
3199 | return; | ||
3200 | |||
3201 | #ifdef CONFIG_ATARI | ||
3202 | free_irq(IRQ_AUTO_4, fbcon_vbl_handler); | ||
3203 | #endif | ||
3204 | #ifdef CONFIG_MAC | ||
3205 | if (MACH_IS_MAC && vbl_detected) | ||
3206 | free_irq(IRQ_MAC_VBL, fbcon_vbl_handler); | ||
3207 | #endif | ||
3208 | |||
3209 | kfree((void *)softback_buf); | ||
3210 | softback_buf = 0UL; | ||
3211 | |||
3212 | for (i = 0; i < FB_MAX; i++) { | ||
3213 | mapped = 0; | ||
3214 | info = registered_fb[i]; | ||
3215 | |||
3216 | if (info == NULL) | ||
3217 | continue; | ||
3218 | |||
3219 | for (j = first_fb_vc; j <= last_fb_vc; j++) { | ||
3220 | if (con2fb_map[j] == i) | ||
3221 | mapped = 1; | ||
3222 | } | ||
3223 | |||
3224 | if (mapped) { | ||
3225 | if (info->fbops->fb_release) | ||
3226 | info->fbops->fb_release(info, 0); | ||
3227 | module_put(info->fbops->owner); | ||
3228 | |||
3229 | if (info->fbcon_par) { | ||
3230 | fbcon_del_cursor_timer(info); | ||
3231 | kfree(info->fbcon_par); | ||
3232 | info->fbcon_par = NULL; | ||
3233 | } | ||
3015 | 3234 | ||
3235 | if (info->queue.func == fb_flashcursor) | ||
3236 | info->queue.func = NULL; | ||
3237 | } | ||
3238 | } | ||
3239 | |||
3240 | fbcon_has_exited = 1; | ||
3241 | } | ||
3242 | |||
3243 | static int __init fb_console_init(void) | ||
3244 | { | ||
3245 | int i; | ||
3246 | |||
3247 | acquire_console_sem(); | ||
3248 | fb_register_client(&fbcon_event_notifier); | ||
3249 | fbcon_class_device = | ||
3250 | class_device_create(fb_class, NULL, MKDEV(0, 0), NULL, "fbcon"); | ||
3251 | |||
3252 | if (IS_ERR(fbcon_class_device)) { | ||
3253 | printk(KERN_WARNING "Unable to create class_device " | ||
3254 | "for fbcon; errno = %ld\n", | ||
3255 | PTR_ERR(fbcon_class_device)); | ||
3256 | fbcon_class_device = NULL; | ||
3257 | } else | ||
3258 | fbcon_init_class_device(); | ||
3259 | |||
3260 | for (i = 0; i < MAX_NR_CONSOLES; i++) | ||
3261 | con2fb_map[i] = -1; | ||
3262 | |||
3263 | release_console_sem(); | ||
3264 | fbcon_start(); | ||
3016 | return 0; | 3265 | return 0; |
3017 | } | 3266 | } |
3018 | 3267 | ||
@@ -3020,12 +3269,24 @@ module_init(fb_console_init); | |||
3020 | 3269 | ||
3021 | #ifdef MODULE | 3270 | #ifdef MODULE |
3022 | 3271 | ||
3272 | static void __exit fbcon_deinit_class_device(void) | ||
3273 | { | ||
3274 | int i; | ||
3275 | |||
3276 | for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) | ||
3277 | class_device_remove_file(fbcon_class_device, | ||
3278 | &class_device_attrs[i]); | ||
3279 | } | ||
3280 | |||
3023 | static void __exit fb_console_exit(void) | 3281 | static void __exit fb_console_exit(void) |
3024 | { | 3282 | { |
3025 | acquire_console_sem(); | 3283 | acquire_console_sem(); |
3026 | fb_unregister_client(&fbcon_event_notifier); | 3284 | fb_unregister_client(&fbcon_event_notifier); |
3285 | fbcon_deinit_class_device(); | ||
3286 | class_device_destroy(fb_class, MKDEV(0, 0)); | ||
3287 | fbcon_exit(); | ||
3027 | release_console_sem(); | 3288 | release_console_sem(); |
3028 | give_up_console(&fb_con); | 3289 | unregister_con_driver(&fb_con); |
3029 | } | 3290 | } |
3030 | 3291 | ||
3031 | module_exit(fb_console_exit); | 3292 | module_exit(fb_console_exit); |
diff --git a/drivers/video/console/fbcon.h b/drivers/video/console/fbcon.h index c38c3d8e7a74..3487a636370a 100644 --- a/drivers/video/console/fbcon.h +++ b/drivers/video/console/fbcon.h | |||
@@ -175,6 +175,7 @@ extern void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info); | |||
175 | #endif | 175 | #endif |
176 | extern void fbcon_set_bitops(struct fbcon_ops *ops); | 176 | extern void fbcon_set_bitops(struct fbcon_ops *ops); |
177 | extern int soft_cursor(struct fb_info *info, struct fb_cursor *cursor); | 177 | extern int soft_cursor(struct fb_info *info, struct fb_cursor *cursor); |
178 | extern struct class *fb_class; | ||
178 | 179 | ||
179 | #define FBCON_ATTRIBUTE_UNDERLINE 1 | 180 | #define FBCON_ATTRIBUTE_UNDERLINE 1 |
180 | #define FBCON_ATTRIBUTE_REVERSE 2 | 181 | #define FBCON_ATTRIBUTE_REVERSE 2 |
diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c index 7f939d066a5a..c89f90edf8ac 100644 --- a/drivers/video/console/mdacon.c +++ b/drivers/video/console/mdacon.c | |||
@@ -308,7 +308,7 @@ static void __init mda_initialize(void) | |||
308 | outb_p(0x00, mda_gfx_port); | 308 | outb_p(0x00, mda_gfx_port); |
309 | } | 309 | } |
310 | 310 | ||
311 | static const char __init *mdacon_startup(void) | 311 | static const char *mdacon_startup(void) |
312 | { | 312 | { |
313 | mda_num_columns = 80; | 313 | mda_num_columns = 80; |
314 | mda_num_lines = 25; | 314 | mda_num_lines = 25; |
diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c index e99fe30e568c..03041311711b 100644 --- a/drivers/video/console/newport_con.c +++ b/drivers/video/console/newport_con.c | |||
@@ -51,6 +51,7 @@ static int topscan; | |||
51 | static int xcurs_correction = 29; | 51 | static int xcurs_correction = 29; |
52 | static int newport_xsize; | 52 | static int newport_xsize; |
53 | static int newport_ysize; | 53 | static int newport_ysize; |
54 | static int newport_has_init; | ||
54 | 55 | ||
55 | static int newport_set_def_font(int unit, struct console_font *op); | 56 | static int newport_set_def_font(int unit, struct console_font *op); |
56 | 57 | ||
@@ -283,6 +284,15 @@ static void newport_get_revisions(void) | |||
283 | xcurs_correction = 21; | 284 | xcurs_correction = 21; |
284 | } | 285 | } |
285 | 286 | ||
287 | static void newport_exit(void) | ||
288 | { | ||
289 | int i; | ||
290 | |||
291 | /* free memory used by user font */ | ||
292 | for (i = 0; i < MAX_NR_CONSOLES; i++) | ||
293 | newport_set_def_font(i, NULL); | ||
294 | } | ||
295 | |||
286 | /* Can't be __init, take_over_console may call it later */ | 296 | /* Can't be __init, take_over_console may call it later */ |
287 | static const char *newport_startup(void) | 297 | static const char *newport_startup(void) |
288 | { | 298 | { |
@@ -290,8 +300,10 @@ static const char *newport_startup(void) | |||
290 | 300 | ||
291 | if (!sgi_gfxaddr) | 301 | if (!sgi_gfxaddr) |
292 | return NULL; | 302 | return NULL; |
293 | npregs = (struct newport_regs *) /* ioremap cannot fail */ | 303 | |
294 | ioremap(sgi_gfxaddr, sizeof(struct newport_regs)); | 304 | if (!npregs) |
305 | npregs = (struct newport_regs *)/* ioremap cannot fail */ | ||
306 | ioremap(sgi_gfxaddr, sizeof(struct newport_regs)); | ||
295 | npregs->cset.config = NPORT_CFG_GD0; | 307 | npregs->cset.config = NPORT_CFG_GD0; |
296 | 308 | ||
297 | if (newport_wait(npregs)) | 309 | if (newport_wait(npregs)) |
@@ -307,11 +319,11 @@ static const char *newport_startup(void) | |||
307 | newport_reset(); | 319 | newport_reset(); |
308 | newport_get_revisions(); | 320 | newport_get_revisions(); |
309 | newport_get_screensize(); | 321 | newport_get_screensize(); |
322 | newport_has_init = 1; | ||
310 | 323 | ||
311 | return "SGI Newport"; | 324 | return "SGI Newport"; |
312 | 325 | ||
313 | out_unmap: | 326 | out_unmap: |
314 | iounmap((void *)npregs); | ||
315 | return NULL; | 327 | return NULL; |
316 | } | 328 | } |
317 | 329 | ||
@@ -324,11 +336,10 @@ static void newport_init(struct vc_data *vc, int init) | |||
324 | 336 | ||
325 | static void newport_deinit(struct vc_data *c) | 337 | static void newport_deinit(struct vc_data *c) |
326 | { | 338 | { |
327 | int i; | 339 | if (!con_is_bound(&newport_con) && newport_has_init) { |
328 | 340 | newport_exit(); | |
329 | /* free memory used by user font */ | 341 | newport_has_init = 0; |
330 | for (i = 0; i < MAX_NR_CONSOLES; i++) | 342 | } |
331 | newport_set_def_font(i, NULL); | ||
332 | } | 343 | } |
333 | 344 | ||
334 | static void newport_clear(struct vc_data *vc, int sy, int sx, int height, | 345 | static void newport_clear(struct vc_data *vc, int sy, int sx, int height, |
@@ -728,16 +739,23 @@ const struct consw newport_con = { | |||
728 | #ifdef MODULE | 739 | #ifdef MODULE |
729 | static int __init newport_console_init(void) | 740 | static int __init newport_console_init(void) |
730 | { | 741 | { |
742 | |||
743 | if (!sgi_gfxaddr) | ||
744 | return NULL; | ||
745 | |||
746 | if (!npregs) | ||
747 | npregs = (struct newport_regs *)/* ioremap cannot fail */ | ||
748 | ioremap(sgi_gfxaddr, sizeof(struct newport_regs)); | ||
749 | |||
731 | return take_over_console(&newport_con, 0, MAX_NR_CONSOLES - 1, 1); | 750 | return take_over_console(&newport_con, 0, MAX_NR_CONSOLES - 1, 1); |
732 | } | 751 | } |
752 | module_init(newport_console_init); | ||
733 | 753 | ||
734 | static void __exit newport_console_exit(void) | 754 | static void __exit newport_console_exit(void) |
735 | { | 755 | { |
736 | give_up_console(&newport_con); | 756 | give_up_console(&newport_con); |
737 | iounmap((void *)npregs); | 757 | iounmap((void *)npregs); |
738 | } | 758 | } |
739 | |||
740 | module_init(newport_console_init); | ||
741 | module_exit(newport_console_exit); | 759 | module_exit(newport_console_exit); |
742 | #endif | 760 | #endif |
743 | 761 | ||
diff --git a/drivers/video/console/promcon.c b/drivers/video/console/promcon.c index 04f42fcaac59..d6e6ad537f9f 100644 --- a/drivers/video/console/promcon.c +++ b/drivers/video/console/promcon.c | |||
@@ -109,7 +109,7 @@ promcon_end(struct vc_data *conp, char *b) | |||
109 | return b - p; | 109 | return b - p; |
110 | } | 110 | } |
111 | 111 | ||
112 | const char __init *promcon_startup(void) | 112 | const char *promcon_startup(void) |
113 | { | 113 | { |
114 | const char *display_desc = "PROM"; | 114 | const char *display_desc = "PROM"; |
115 | int node; | 115 | int node; |
@@ -133,7 +133,7 @@ const char __init *promcon_startup(void) | |||
133 | return display_desc; | 133 | return display_desc; |
134 | } | 134 | } |
135 | 135 | ||
136 | static void __init | 136 | static void |
137 | promcon_init_unimap(struct vc_data *conp) | 137 | promcon_init_unimap(struct vc_data *conp) |
138 | { | 138 | { |
139 | mm_segment_t old_fs = get_fs(); | 139 | mm_segment_t old_fs = get_fs(); |
diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c index fd5940f41271..45c4f227e56e 100644 --- a/drivers/video/console/sticon.c +++ b/drivers/video/console/sticon.c | |||
@@ -75,7 +75,7 @@ static inline void cursor_undrawn(void) | |||
75 | cursor_drawn = 0; | 75 | cursor_drawn = 0; |
76 | } | 76 | } |
77 | 77 | ||
78 | static const char *__init sticon_startup(void) | 78 | static const char *sticon_startup(void) |
79 | { | 79 | { |
80 | return "STI console"; | 80 | return "STI console"; |
81 | } | 81 | } |
diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index e64d42e2449e..f32b590730f2 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c | |||
@@ -114,6 +114,7 @@ static int vga_512_chars; | |||
114 | static int vga_video_font_height; | 114 | static int vga_video_font_height; |
115 | static int vga_scan_lines; | 115 | static int vga_scan_lines; |
116 | static unsigned int vga_rolled_over = 0; | 116 | static unsigned int vga_rolled_over = 0; |
117 | static int vga_init_done; | ||
117 | 118 | ||
118 | static int __init no_scroll(char *str) | 119 | static int __init no_scroll(char *str) |
119 | { | 120 | { |
@@ -190,7 +191,7 @@ static void vgacon_scrollback_init(int pitch) | |||
190 | } | 191 | } |
191 | } | 192 | } |
192 | 193 | ||
193 | static void __init vgacon_scrollback_startup(void) | 194 | static void vgacon_scrollback_startup(void) |
194 | { | 195 | { |
195 | vgacon_scrollback = alloc_bootmem(CONFIG_VGACON_SOFT_SCROLLBACK_SIZE | 196 | vgacon_scrollback = alloc_bootmem(CONFIG_VGACON_SOFT_SCROLLBACK_SIZE |
196 | * 1024); | 197 | * 1024); |
@@ -355,7 +356,7 @@ static int vgacon_scrolldelta(struct vc_data *c, int lines) | |||
355 | } | 356 | } |
356 | #endif /* CONFIG_VGACON_SOFT_SCROLLBACK */ | 357 | #endif /* CONFIG_VGACON_SOFT_SCROLLBACK */ |
357 | 358 | ||
358 | static const char __init *vgacon_startup(void) | 359 | static const char *vgacon_startup(void) |
359 | { | 360 | { |
360 | const char *display_desc = NULL; | 361 | const char *display_desc = NULL; |
361 | u16 saved1, saved2; | 362 | u16 saved1, saved2; |
@@ -523,7 +524,12 @@ static const char __init *vgacon_startup(void) | |||
523 | 524 | ||
524 | vgacon_xres = ORIG_VIDEO_COLS * VGA_FONTWIDTH; | 525 | vgacon_xres = ORIG_VIDEO_COLS * VGA_FONTWIDTH; |
525 | vgacon_yres = vga_scan_lines; | 526 | vgacon_yres = vga_scan_lines; |
526 | vgacon_scrollback_startup(); | 527 | |
528 | if (!vga_init_done) { | ||
529 | vgacon_scrollback_startup(); | ||
530 | vga_init_done = 1; | ||
531 | } | ||
532 | |||
527 | return display_desc; | 533 | return display_desc; |
528 | } | 534 | } |
529 | 535 | ||
@@ -531,10 +537,20 @@ static void vgacon_init(struct vc_data *c, int init) | |||
531 | { | 537 | { |
532 | unsigned long p; | 538 | unsigned long p; |
533 | 539 | ||
534 | /* We cannot be loaded as a module, therefore init is always 1 */ | 540 | /* |
541 | * We cannot be loaded as a module, therefore init is always 1, | ||
542 | * but vgacon_init can be called more than once, and init will | ||
543 | * not be 1. | ||
544 | */ | ||
535 | c->vc_can_do_color = vga_can_do_color; | 545 | c->vc_can_do_color = vga_can_do_color; |
536 | c->vc_cols = vga_video_num_columns; | 546 | |
537 | c->vc_rows = vga_video_num_lines; | 547 | /* set dimensions manually if init != 0 since vc_resize() will fail */ |
548 | if (init) { | ||
549 | c->vc_cols = vga_video_num_columns; | ||
550 | c->vc_rows = vga_video_num_lines; | ||
551 | } else | ||
552 | vc_resize(c, vga_video_num_columns, vga_video_num_lines); | ||
553 | |||
538 | c->vc_scan_lines = vga_scan_lines; | 554 | c->vc_scan_lines = vga_scan_lines; |
539 | c->vc_font.height = vga_video_font_height; | 555 | c->vc_font.height = vga_video_font_height; |
540 | c->vc_complement_mask = 0x7700; | 556 | c->vc_complement_mask = 0x7700; |
diff --git a/drivers/video/epson1355fb.c b/drivers/video/epson1355fb.c index 082759447bf6..f0a621ecc288 100644 --- a/drivers/video/epson1355fb.c +++ b/drivers/video/epson1355fb.c | |||
@@ -605,11 +605,6 @@ static void clearfb16(struct fb_info *info) | |||
605 | fb_writeb(0, dst); | 605 | fb_writeb(0, dst); |
606 | } | 606 | } |
607 | 607 | ||
608 | static void epson1355fb_platform_release(struct device *device) | ||
609 | { | ||
610 | dev_err(device, "This driver is broken, please bug the authors so they will fix it.\n"); | ||
611 | } | ||
612 | |||
613 | static int epson1355fb_remove(struct platform_device *dev) | 608 | static int epson1355fb_remove(struct platform_device *dev) |
614 | { | 609 | { |
615 | struct fb_info *info = platform_get_drvdata(dev); | 610 | struct fb_info *info = platform_get_drvdata(dev); |
@@ -733,13 +728,7 @@ static struct platform_driver epson1355fb_driver = { | |||
733 | }, | 728 | }, |
734 | }; | 729 | }; |
735 | 730 | ||
736 | static struct platform_device epson1355fb_device = { | 731 | static struct platform_device *epson1355fb_device; |
737 | .name = "epson1355fb", | ||
738 | .id = 0, | ||
739 | .dev = { | ||
740 | .release = epson1355fb_platform_release, | ||
741 | } | ||
742 | }; | ||
743 | 732 | ||
744 | int __init epson1355fb_init(void) | 733 | int __init epson1355fb_init(void) |
745 | { | 734 | { |
@@ -749,11 +738,21 @@ int __init epson1355fb_init(void) | |||
749 | return -ENODEV; | 738 | return -ENODEV; |
750 | 739 | ||
751 | ret = platform_driver_register(&epson1355fb_driver); | 740 | ret = platform_driver_register(&epson1355fb_driver); |
741 | |||
752 | if (!ret) { | 742 | if (!ret) { |
753 | ret = platform_device_register(&epson1355fb_device); | 743 | epson1355fb_device = platform_device_alloc("epson1355fb", 0); |
754 | if (ret) | 744 | |
745 | if (epson1355fb_device) | ||
746 | ret = platform_device_add(epson1355fb_device); | ||
747 | else | ||
748 | ret = -ENOMEM; | ||
749 | |||
750 | if (ret) { | ||
751 | platform_device_put(epson1355fb_device); | ||
755 | platform_driver_unregister(&epson1355fb_driver); | 752 | platform_driver_unregister(&epson1355fb_driver); |
753 | } | ||
756 | } | 754 | } |
755 | |||
757 | return ret; | 756 | return ret; |
758 | } | 757 | } |
759 | 758 | ||
@@ -762,7 +761,7 @@ module_init(epson1355fb_init); | |||
762 | #ifdef MODULE | 761 | #ifdef MODULE |
763 | static void __exit epson1355fb_exit(void) | 762 | static void __exit epson1355fb_exit(void) |
764 | { | 763 | { |
765 | platform_device_unregister(&epson1355fb_device); | 764 | platform_device_unregister(epson1355fb_device); |
766 | platform_driver_unregister(&epson1355fb_driver); | 765 | platform_driver_unregister(&epson1355fb_driver); |
767 | } | 766 | } |
768 | 767 | ||
diff --git a/drivers/video/fbcvt.c b/drivers/video/fbcvt.c index ac90883dc3aa..b5498999c4ec 100644 --- a/drivers/video/fbcvt.c +++ b/drivers/video/fbcvt.c | |||
@@ -376,4 +376,3 @@ int fb_find_mode_cvt(struct fb_videomode *mode, int margins, int rb) | |||
376 | 376 | ||
377 | return 0; | 377 | return 0; |
378 | } | 378 | } |
379 | EXPORT_SYMBOL(fb_find_mode_cvt); | ||
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 372aa1776827..31143afe7c95 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c | |||
@@ -34,7 +34,6 @@ | |||
34 | #endif | 34 | #endif |
35 | #include <linux/devfs_fs_kernel.h> | 35 | #include <linux/devfs_fs_kernel.h> |
36 | #include <linux/err.h> | 36 | #include <linux/err.h> |
37 | #include <linux/kernel.h> | ||
38 | #include <linux/device.h> | 37 | #include <linux/device.h> |
39 | #include <linux/efi.h> | 38 | #include <linux/efi.h> |
40 | 39 | ||
@@ -162,7 +161,6 @@ char* fb_get_buffer_offset(struct fb_info *info, struct fb_pixmap *buf, u32 size | |||
162 | } | 161 | } |
163 | 162 | ||
164 | #ifdef CONFIG_LOGO | 163 | #ifdef CONFIG_LOGO |
165 | #include <linux/linux_logo.h> | ||
166 | 164 | ||
167 | static inline unsigned safe_shift(unsigned d, int n) | 165 | static inline unsigned safe_shift(unsigned d, int n) |
168 | { | 166 | { |
@@ -336,11 +334,11 @@ static void fb_rotate_logo_ud(const u8 *in, u8 *out, u32 width, u32 height) | |||
336 | 334 | ||
337 | static void fb_rotate_logo_cw(const u8 *in, u8 *out, u32 width, u32 height) | 335 | static void fb_rotate_logo_cw(const u8 *in, u8 *out, u32 width, u32 height) |
338 | { | 336 | { |
339 | int i, j, w = width - 1; | 337 | int i, j, h = height - 1; |
340 | 338 | ||
341 | for (i = 0; i < height; i++) | 339 | for (i = 0; i < height; i++) |
342 | for (j = 0; j < width; j++) | 340 | for (j = 0; j < width; j++) |
343 | out[height * j + w - i] = *in++; | 341 | out[height * j + h - i] = *in++; |
344 | } | 342 | } |
345 | 343 | ||
346 | static void fb_rotate_logo_ccw(const u8 *in, u8 *out, u32 width, u32 height) | 344 | static void fb_rotate_logo_ccw(const u8 *in, u8 *out, u32 width, u32 height) |
@@ -358,24 +356,24 @@ static void fb_rotate_logo(struct fb_info *info, u8 *dst, | |||
358 | u32 tmp; | 356 | u32 tmp; |
359 | 357 | ||
360 | if (rotate == FB_ROTATE_UD) { | 358 | if (rotate == FB_ROTATE_UD) { |
361 | image->dx = info->var.xres - image->width; | ||
362 | image->dy = info->var.yres - image->height; | ||
363 | fb_rotate_logo_ud(image->data, dst, image->width, | 359 | fb_rotate_logo_ud(image->data, dst, image->width, |
364 | image->height); | 360 | image->height); |
361 | image->dx = info->var.xres - image->width; | ||
362 | image->dy = info->var.yres - image->height; | ||
365 | } else if (rotate == FB_ROTATE_CW) { | 363 | } else if (rotate == FB_ROTATE_CW) { |
366 | tmp = image->width; | ||
367 | image->width = image->height; | ||
368 | image->height = tmp; | ||
369 | image->dx = info->var.xres - image->height; | ||
370 | fb_rotate_logo_cw(image->data, dst, image->width, | 364 | fb_rotate_logo_cw(image->data, dst, image->width, |
371 | image->height); | 365 | image->height); |
372 | } else if (rotate == FB_ROTATE_CCW) { | ||
373 | tmp = image->width; | 366 | tmp = image->width; |
374 | image->width = image->height; | 367 | image->width = image->height; |
375 | image->height = tmp; | 368 | image->height = tmp; |
376 | image->dy = info->var.yres - image->width; | 369 | image->dx = info->var.xres - image->width; |
370 | } else if (rotate == FB_ROTATE_CCW) { | ||
377 | fb_rotate_logo_ccw(image->data, dst, image->width, | 371 | fb_rotate_logo_ccw(image->data, dst, image->width, |
378 | image->height); | 372 | image->height); |
373 | tmp = image->width; | ||
374 | image->width = image->height; | ||
375 | image->height = tmp; | ||
376 | image->dy = info->var.yres - image->height; | ||
379 | } | 377 | } |
380 | 378 | ||
381 | image->data = dst; | 379 | image->data = dst; |
@@ -435,7 +433,7 @@ int fb_prepare_logo(struct fb_info *info, int rotate) | |||
435 | depth = info->var.green.length; | 433 | depth = info->var.green.length; |
436 | } | 434 | } |
437 | 435 | ||
438 | if (info->fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR) { | 436 | if (info->fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR && depth > 4) { |
439 | /* assume console colormap */ | 437 | /* assume console colormap */ |
440 | depth = 4; | 438 | depth = 4; |
441 | } | 439 | } |
@@ -1278,8 +1276,8 @@ static struct file_operations fb_fops = { | |||
1278 | #endif | 1276 | #endif |
1279 | }; | 1277 | }; |
1280 | 1278 | ||
1281 | static struct class *fb_class; | 1279 | struct class *fb_class; |
1282 | 1280 | EXPORT_SYMBOL(fb_class); | |
1283 | /** | 1281 | /** |
1284 | * register_framebuffer - registers a frame buffer device | 1282 | * register_framebuffer - registers a frame buffer device |
1285 | * @fb_info: frame buffer info structure | 1283 | * @fb_info: frame buffer info structure |
@@ -1355,6 +1353,7 @@ register_framebuffer(struct fb_info *fb_info) | |||
1355 | int | 1353 | int |
1356 | unregister_framebuffer(struct fb_info *fb_info) | 1354 | unregister_framebuffer(struct fb_info *fb_info) |
1357 | { | 1355 | { |
1356 | struct fb_event event; | ||
1358 | int i; | 1357 | int i; |
1359 | 1358 | ||
1360 | i = fb_info->node; | 1359 | i = fb_info->node; |
@@ -1362,13 +1361,17 @@ unregister_framebuffer(struct fb_info *fb_info) | |||
1362 | return -EINVAL; | 1361 | return -EINVAL; |
1363 | devfs_remove("fb/%d", i); | 1362 | devfs_remove("fb/%d", i); |
1364 | 1363 | ||
1365 | if (fb_info->pixmap.addr && (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT)) | 1364 | if (fb_info->pixmap.addr && |
1365 | (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT)) | ||
1366 | kfree(fb_info->pixmap.addr); | 1366 | kfree(fb_info->pixmap.addr); |
1367 | fb_destroy_modelist(&fb_info->modelist); | 1367 | fb_destroy_modelist(&fb_info->modelist); |
1368 | registered_fb[i]=NULL; | 1368 | registered_fb[i]=NULL; |
1369 | num_registered_fb--; | 1369 | num_registered_fb--; |
1370 | fb_cleanup_class_device(fb_info); | 1370 | fb_cleanup_class_device(fb_info); |
1371 | class_device_destroy(fb_class, MKDEV(FB_MAJOR, i)); | 1371 | class_device_destroy(fb_class, MKDEV(FB_MAJOR, i)); |
1372 | event.info = fb_info; | ||
1373 | blocking_notifier_call_chain(&fb_notifier_list, | ||
1374 | FB_EVENT_FB_UNREGISTERED, &event); | ||
1372 | return 0; | 1375 | return 0; |
1373 | } | 1376 | } |
1374 | 1377 | ||
@@ -1491,28 +1494,6 @@ int fb_new_modelist(struct fb_info *info) | |||
1491 | return err; | 1494 | return err; |
1492 | } | 1495 | } |
1493 | 1496 | ||
1494 | /** | ||
1495 | * fb_con_duit - user<->fbcon passthrough | ||
1496 | * @info: struct fb_info | ||
1497 | * @event: notification event to be passed to fbcon | ||
1498 | * @data: private data | ||
1499 | * | ||
1500 | * DESCRIPTION | ||
1501 | * This function is an fbcon-user event passing channel | ||
1502 | * which bypasses fbdev. This is hopefully temporary | ||
1503 | * until a user interface for fbcon is created | ||
1504 | */ | ||
1505 | int fb_con_duit(struct fb_info *info, int event, void *data) | ||
1506 | { | ||
1507 | struct fb_event evnt; | ||
1508 | |||
1509 | evnt.info = info; | ||
1510 | evnt.data = data; | ||
1511 | |||
1512 | return blocking_notifier_call_chain(&fb_notifier_list, event, &evnt); | ||
1513 | } | ||
1514 | EXPORT_SYMBOL(fb_con_duit); | ||
1515 | |||
1516 | static char *video_options[FB_MAX]; | 1497 | static char *video_options[FB_MAX]; |
1517 | static int ofonly; | 1498 | static int ofonly; |
1518 | 1499 | ||
@@ -1622,6 +1603,5 @@ EXPORT_SYMBOL(fb_set_suspend); | |||
1622 | EXPORT_SYMBOL(fb_register_client); | 1603 | EXPORT_SYMBOL(fb_register_client); |
1623 | EXPORT_SYMBOL(fb_unregister_client); | 1604 | EXPORT_SYMBOL(fb_unregister_client); |
1624 | EXPORT_SYMBOL(fb_get_options); | 1605 | EXPORT_SYMBOL(fb_get_options); |
1625 | EXPORT_SYMBOL(fb_new_modelist); | ||
1626 | 1606 | ||
1627 | MODULE_LICENSE("GPL"); | 1607 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c index 53beeb4a9998..3ccfff715a51 100644 --- a/drivers/video/fbmon.c +++ b/drivers/video/fbmon.c | |||
@@ -29,9 +29,9 @@ | |||
29 | #include <linux/tty.h> | 29 | #include <linux/tty.h> |
30 | #include <linux/fb.h> | 30 | #include <linux/fb.h> |
31 | #include <linux/module.h> | 31 | #include <linux/module.h> |
32 | #include <linux/pci.h> | ||
32 | #include <video/edid.h> | 33 | #include <video/edid.h> |
33 | #ifdef CONFIG_PPC_OF | 34 | #ifdef CONFIG_PPC_OF |
34 | #include <linux/pci.h> | ||
35 | #include <asm/prom.h> | 35 | #include <asm/prom.h> |
36 | #include <asm/pci-bridge.h> | 36 | #include <asm/pci-bridge.h> |
37 | #endif | 37 | #endif |
@@ -605,6 +605,7 @@ static int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs) | |||
605 | block = edid + DETAILED_TIMING_DESCRIPTIONS_START; | 605 | block = edid + DETAILED_TIMING_DESCRIPTIONS_START; |
606 | 606 | ||
607 | DPRINTK(" Monitor Operating Limits: "); | 607 | DPRINTK(" Monitor Operating Limits: "); |
608 | |||
608 | for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) { | 609 | for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) { |
609 | if (edid_is_limits_block(block)) { | 610 | if (edid_is_limits_block(block)) { |
610 | specs->hfmin = H_MIN_RATE * 1000; | 611 | specs->hfmin = H_MIN_RATE * 1000; |
@@ -618,11 +619,12 @@ static int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs) | |||
618 | break; | 619 | break; |
619 | } | 620 | } |
620 | } | 621 | } |
621 | 622 | ||
622 | /* estimate monitor limits based on modes supported */ | 623 | /* estimate monitor limits based on modes supported */ |
623 | if (retval) { | 624 | if (retval) { |
624 | struct fb_videomode *modes; | 625 | struct fb_videomode *modes, *mode; |
625 | int num_modes, i, hz, hscan, pixclock; | 626 | int num_modes, i, hz, hscan, pixclock; |
627 | int vtotal, htotal; | ||
626 | 628 | ||
627 | modes = fb_create_modedb(edid, &num_modes); | 629 | modes = fb_create_modedb(edid, &num_modes); |
628 | if (!modes) { | 630 | if (!modes) { |
@@ -632,20 +634,38 @@ static int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs) | |||
632 | 634 | ||
633 | retval = 0; | 635 | retval = 0; |
634 | for (i = 0; i < num_modes; i++) { | 636 | for (i = 0; i < num_modes; i++) { |
635 | hz = modes[i].refresh; | 637 | mode = &modes[i]; |
636 | pixclock = PICOS2KHZ(modes[i].pixclock) * 1000; | 638 | pixclock = PICOS2KHZ(modes[i].pixclock) * 1000; |
637 | hscan = (modes[i].yres * 105 * hz + 5000)/100; | 639 | htotal = mode->xres + mode->right_margin + mode->hsync_len |
640 | + mode->left_margin; | ||
641 | vtotal = mode->yres + mode->lower_margin + mode->vsync_len | ||
642 | + mode->upper_margin; | ||
643 | |||
644 | if (mode->vmode & FB_VMODE_INTERLACED) | ||
645 | vtotal /= 2; | ||
646 | |||
647 | if (mode->vmode & FB_VMODE_DOUBLE) | ||
648 | vtotal *= 2; | ||
649 | |||
650 | hscan = (pixclock + htotal / 2) / htotal; | ||
651 | hscan = (hscan + 500) / 1000 * 1000; | ||
652 | hz = (hscan + vtotal / 2) / vtotal; | ||
638 | 653 | ||
639 | if (specs->dclkmax == 0 || specs->dclkmax < pixclock) | 654 | if (specs->dclkmax == 0 || specs->dclkmax < pixclock) |
640 | specs->dclkmax = pixclock; | 655 | specs->dclkmax = pixclock; |
656 | |||
641 | if (specs->dclkmin == 0 || specs->dclkmin > pixclock) | 657 | if (specs->dclkmin == 0 || specs->dclkmin > pixclock) |
642 | specs->dclkmin = pixclock; | 658 | specs->dclkmin = pixclock; |
659 | |||
643 | if (specs->hfmax == 0 || specs->hfmax < hscan) | 660 | if (specs->hfmax == 0 || specs->hfmax < hscan) |
644 | specs->hfmax = hscan; | 661 | specs->hfmax = hscan; |
662 | |||
645 | if (specs->hfmin == 0 || specs->hfmin > hscan) | 663 | if (specs->hfmin == 0 || specs->hfmin > hscan) |
646 | specs->hfmin = hscan; | 664 | specs->hfmin = hscan; |
665 | |||
647 | if (specs->vfmax == 0 || specs->vfmax < hz) | 666 | if (specs->vfmax == 0 || specs->vfmax < hz) |
648 | specs->vfmax = hz; | 667 | specs->vfmax = hz; |
668 | |||
649 | if (specs->vfmin == 0 || specs->vfmin > hz) | 669 | if (specs->vfmin == 0 || specs->vfmin > hz) |
650 | specs->vfmin = hz; | 670 | specs->vfmin = hz; |
651 | } | 671 | } |
@@ -1281,8 +1301,7 @@ int fb_validate_mode(const struct fb_var_screeninfo *var, struct fb_info *info) | |||
1281 | -EINVAL : 0; | 1301 | -EINVAL : 0; |
1282 | } | 1302 | } |
1283 | 1303 | ||
1284 | #if defined(CONFIG_FB_FIRMWARE_EDID) && defined(__i386__) | 1304 | #if defined(CONFIG_FIRMWARE_EDID) && defined(CONFIG_X86) |
1285 | #include <linux/pci.h> | ||
1286 | 1305 | ||
1287 | /* | 1306 | /* |
1288 | * We need to ensure that the EDID block is only returned for | 1307 | * We need to ensure that the EDID block is only returned for |
diff --git a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c index 3ceb8c1b392e..4f78f234473d 100644 --- a/drivers/video/fbsysfs.c +++ b/drivers/video/fbsysfs.c | |||
@@ -100,13 +100,22 @@ static int mode_string(char *buf, unsigned int offset, | |||
100 | const struct fb_videomode *mode) | 100 | const struct fb_videomode *mode) |
101 | { | 101 | { |
102 | char m = 'U'; | 102 | char m = 'U'; |
103 | char v = 'p'; | ||
104 | |||
103 | if (mode->flag & FB_MODE_IS_DETAILED) | 105 | if (mode->flag & FB_MODE_IS_DETAILED) |
104 | m = 'D'; | 106 | m = 'D'; |
105 | if (mode->flag & FB_MODE_IS_VESA) | 107 | if (mode->flag & FB_MODE_IS_VESA) |
106 | m = 'V'; | 108 | m = 'V'; |
107 | if (mode->flag & FB_MODE_IS_STANDARD) | 109 | if (mode->flag & FB_MODE_IS_STANDARD) |
108 | m = 'S'; | 110 | m = 'S'; |
109 | return snprintf(&buf[offset], PAGE_SIZE - offset, "%c:%dx%d-%d\n", m, mode->xres, mode->yres, mode->refresh); | 111 | |
112 | if (mode->vmode & FB_VMODE_INTERLACED) | ||
113 | v = 'i'; | ||
114 | if (mode->vmode & FB_VMODE_DOUBLE) | ||
115 | v = 'd'; | ||
116 | |||
117 | return snprintf(&buf[offset], PAGE_SIZE - offset, "%c:%dx%d%c-%d\n", | ||
118 | m, mode->xres, mode->yres, v, mode->refresh); | ||
110 | } | 119 | } |
111 | 120 | ||
112 | static ssize_t store_mode(struct class_device *class_device, const char * buf, | 121 | static ssize_t store_mode(struct class_device *class_device, const char * buf, |
@@ -238,45 +247,6 @@ static ssize_t show_rotate(struct class_device *class_device, char *buf) | |||
238 | return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->var.rotate); | 247 | return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->var.rotate); |
239 | } | 248 | } |
240 | 249 | ||
241 | static ssize_t store_con_rotate(struct class_device *class_device, | ||
242 | const char *buf, size_t count) | ||
243 | { | ||
244 | struct fb_info *fb_info = class_get_devdata(class_device); | ||
245 | int rotate; | ||
246 | char **last = NULL; | ||
247 | |||
248 | acquire_console_sem(); | ||
249 | rotate = simple_strtoul(buf, last, 0); | ||
250 | fb_con_duit(fb_info, FB_EVENT_SET_CON_ROTATE, &rotate); | ||
251 | release_console_sem(); | ||
252 | return count; | ||
253 | } | ||
254 | |||
255 | static ssize_t store_con_rotate_all(struct class_device *class_device, | ||
256 | const char *buf, size_t count) | ||
257 | { | ||
258 | struct fb_info *fb_info = class_get_devdata(class_device); | ||
259 | int rotate; | ||
260 | char **last = NULL; | ||
261 | |||
262 | acquire_console_sem(); | ||
263 | rotate = simple_strtoul(buf, last, 0); | ||
264 | fb_con_duit(fb_info, FB_EVENT_SET_CON_ROTATE_ALL, &rotate); | ||
265 | release_console_sem(); | ||
266 | return count; | ||
267 | } | ||
268 | |||
269 | static ssize_t show_con_rotate(struct class_device *class_device, char *buf) | ||
270 | { | ||
271 | struct fb_info *fb_info = class_get_devdata(class_device); | ||
272 | int rotate; | ||
273 | |||
274 | acquire_console_sem(); | ||
275 | rotate = fb_con_duit(fb_info, FB_EVENT_GET_CON_ROTATE, NULL); | ||
276 | release_console_sem(); | ||
277 | return snprintf(buf, PAGE_SIZE, "%d\n", rotate); | ||
278 | } | ||
279 | |||
280 | static ssize_t store_virtual(struct class_device *class_device, | 250 | static ssize_t store_virtual(struct class_device *class_device, |
281 | const char * buf, size_t count) | 251 | const char * buf, size_t count) |
282 | { | 252 | { |
@@ -493,8 +463,6 @@ static struct class_device_attribute class_device_attrs[] = { | |||
493 | __ATTR(name, S_IRUGO, show_name, NULL), | 463 | __ATTR(name, S_IRUGO, show_name, NULL), |
494 | __ATTR(stride, S_IRUGO, show_stride, NULL), | 464 | __ATTR(stride, S_IRUGO, show_stride, NULL), |
495 | __ATTR(rotate, S_IRUGO|S_IWUSR, show_rotate, store_rotate), | 465 | __ATTR(rotate, S_IRUGO|S_IWUSR, show_rotate, store_rotate), |
496 | __ATTR(con_rotate, S_IRUGO|S_IWUSR, show_con_rotate, store_con_rotate), | ||
497 | __ATTR(con_rotate_all, S_IWUSR, NULL, store_con_rotate_all), | ||
498 | __ATTR(state, S_IRUGO|S_IWUSR, show_fbstate, store_fbstate), | 466 | __ATTR(state, S_IRUGO|S_IWUSR, show_fbstate, store_fbstate), |
499 | #ifdef CONFIG_FB_BACKLIGHT | 467 | #ifdef CONFIG_FB_BACKLIGHT |
500 | __ATTR(bl_curve, S_IRUGO|S_IWUSR, show_bl_curve, store_bl_curve), | 468 | __ATTR(bl_curve, S_IRUGO|S_IWUSR, show_bl_curve, store_bl_curve), |
diff --git a/drivers/video/geode/gx1fb_core.c b/drivers/video/geode/gx1fb_core.c index 20e69156d728..4d3a8871d3d1 100644 --- a/drivers/video/geode/gx1fb_core.c +++ b/drivers/video/geode/gx1fb_core.c | |||
@@ -376,8 +376,6 @@ static int __init gx1fb_probe(struct pci_dev *pdev, const struct pci_device_id * | |||
376 | release_mem_region(gx1_gx_base() + 0x8300, 0x100); | 376 | release_mem_region(gx1_gx_base() + 0x8300, 0x100); |
377 | } | 377 | } |
378 | 378 | ||
379 | pci_disable_device(pdev); | ||
380 | |||
381 | if (info) | 379 | if (info) |
382 | framebuffer_release(info); | 380 | framebuffer_release(info); |
383 | return ret; | 381 | return ret; |
@@ -399,7 +397,6 @@ static void gx1fb_remove(struct pci_dev *pdev) | |||
399 | iounmap(par->dc_regs); | 397 | iounmap(par->dc_regs); |
400 | release_mem_region(gx1_gx_base() + 0x8300, 0x100); | 398 | release_mem_region(gx1_gx_base() + 0x8300, 0x100); |
401 | 399 | ||
402 | pci_disable_device(pdev); | ||
403 | pci_set_drvdata(pdev, NULL); | 400 | pci_set_drvdata(pdev, NULL); |
404 | 401 | ||
405 | framebuffer_release(info); | 402 | framebuffer_release(info); |
diff --git a/drivers/video/geode/gxfb_core.c b/drivers/video/geode/gxfb_core.c index 89c34b15f5d4..5ef12a3dfa50 100644 --- a/drivers/video/geode/gxfb_core.c +++ b/drivers/video/geode/gxfb_core.c | |||
@@ -354,8 +354,6 @@ static int __init gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *i | |||
354 | pci_release_region(pdev, 2); | 354 | pci_release_region(pdev, 2); |
355 | } | 355 | } |
356 | 356 | ||
357 | pci_disable_device(pdev); | ||
358 | |||
359 | if (info) | 357 | if (info) |
360 | framebuffer_release(info); | 358 | framebuffer_release(info); |
361 | return ret; | 359 | return ret; |
@@ -377,7 +375,6 @@ static void gxfb_remove(struct pci_dev *pdev) | |||
377 | iounmap(par->dc_regs); | 375 | iounmap(par->dc_regs); |
378 | pci_release_region(pdev, 2); | 376 | pci_release_region(pdev, 2); |
379 | 377 | ||
380 | pci_disable_device(pdev); | ||
381 | pci_set_drvdata(pdev, NULL); | 378 | pci_set_drvdata(pdev, NULL); |
382 | 379 | ||
383 | framebuffer_release(info); | 380 | framebuffer_release(info); |
diff --git a/drivers/video/i810/i810_main.c b/drivers/video/i810/i810_main.c index 44aa2ffff973..a1f7d80f0ac1 100644 --- a/drivers/video/i810/i810_main.c +++ b/drivers/video/i810/i810_main.c | |||
@@ -2110,9 +2110,6 @@ static void i810fb_release_resource(struct fb_info *info, | |||
2110 | if (par->res_flags & MMIO_REQ) | 2110 | if (par->res_flags & MMIO_REQ) |
2111 | release_mem_region(par->mmio_start_phys, MMIO_SIZE); | 2111 | release_mem_region(par->mmio_start_phys, MMIO_SIZE); |
2112 | 2112 | ||
2113 | if (par->res_flags & PCI_DEVICE_ENABLED) | ||
2114 | pci_disable_device(par->dev); | ||
2115 | |||
2116 | framebuffer_release(info); | 2113 | framebuffer_release(info); |
2117 | 2114 | ||
2118 | } | 2115 | } |
diff --git a/drivers/video/imacfb.c b/drivers/video/imacfb.c new file mode 100644 index 000000000000..7b1c168c834d --- /dev/null +++ b/drivers/video/imacfb.c | |||
@@ -0,0 +1,345 @@ | |||
1 | /* | ||
2 | * framebuffer driver for Intel Based Mac's | ||
3 | * | ||
4 | * (c) 2006 Edgar Hucek <gimli@dark-green.com> | ||
5 | * Original imac driver written by Gerd Knorr <kraxel@goldbach.in-berlin.de> | ||
6 | * | ||
7 | */ | ||
8 | |||
9 | #include <linux/delay.h> | ||
10 | #include <linux/errno.h> | ||
11 | #include <linux/fb.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/ioport.h> | ||
15 | #include <linux/mm.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/platform_device.h> | ||
18 | #include <linux/slab.h> | ||
19 | #include <linux/string.h> | ||
20 | #include <linux/tty.h> | ||
21 | |||
22 | #include <asm/io.h> | ||
23 | |||
24 | #include <video/vga.h> | ||
25 | |||
26 | typedef enum _MAC_TYPE { | ||
27 | M_I17, | ||
28 | M_I20, | ||
29 | M_MINI, | ||
30 | M_MACBOOK, | ||
31 | M_NEW | ||
32 | } MAC_TYPE; | ||
33 | |||
34 | /* --------------------------------------------------------------------- */ | ||
35 | |||
36 | static struct fb_var_screeninfo imacfb_defined __initdata = { | ||
37 | .activate = FB_ACTIVATE_NOW, | ||
38 | .height = -1, | ||
39 | .width = -1, | ||
40 | .right_margin = 32, | ||
41 | .upper_margin = 16, | ||
42 | .lower_margin = 4, | ||
43 | .vsync_len = 4, | ||
44 | .vmode = FB_VMODE_NONINTERLACED, | ||
45 | }; | ||
46 | |||
47 | static struct fb_fix_screeninfo imacfb_fix __initdata = { | ||
48 | .id = "IMAC VGA", | ||
49 | .type = FB_TYPE_PACKED_PIXELS, | ||
50 | .accel = FB_ACCEL_NONE, | ||
51 | .visual = FB_VISUAL_TRUECOLOR, | ||
52 | }; | ||
53 | |||
54 | static int inverse; | ||
55 | static int model = M_NEW; | ||
56 | static int manual_height; | ||
57 | static int manual_width; | ||
58 | |||
59 | #define DEFAULT_FB_MEM 1024*1024*16 | ||
60 | |||
61 | /* --------------------------------------------------------------------- */ | ||
62 | |||
63 | static int imacfb_setcolreg(unsigned regno, unsigned red, unsigned green, | ||
64 | unsigned blue, unsigned transp, | ||
65 | struct fb_info *info) | ||
66 | { | ||
67 | /* | ||
68 | * Set a single color register. The values supplied are | ||
69 | * already rounded down to the hardware's capabilities | ||
70 | * (according to the entries in the `var' structure). Return | ||
71 | * != 0 for invalid regno. | ||
72 | */ | ||
73 | |||
74 | if (regno >= info->cmap.len) | ||
75 | return 1; | ||
76 | |||
77 | if (regno < 16) { | ||
78 | red >>= 8; | ||
79 | green >>= 8; | ||
80 | blue >>= 8; | ||
81 | ((u32 *)(info->pseudo_palette))[regno] = | ||
82 | (red << info->var.red.offset) | | ||
83 | (green << info->var.green.offset) | | ||
84 | (blue << info->var.blue.offset); | ||
85 | } | ||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | static struct fb_ops imacfb_ops = { | ||
90 | .owner = THIS_MODULE, | ||
91 | .fb_setcolreg = imacfb_setcolreg, | ||
92 | .fb_fillrect = cfb_fillrect, | ||
93 | .fb_copyarea = cfb_copyarea, | ||
94 | .fb_imageblit = cfb_imageblit, | ||
95 | }; | ||
96 | |||
97 | static int __init imacfb_setup(char *options) | ||
98 | { | ||
99 | char *this_opt; | ||
100 | |||
101 | if (!options || !*options) | ||
102 | return 0; | ||
103 | |||
104 | while ((this_opt = strsep(&options, ",")) != NULL) { | ||
105 | if (!*this_opt) continue; | ||
106 | |||
107 | if (!strcmp(this_opt, "inverse")) | ||
108 | inverse = 1; | ||
109 | else if (!strcmp(this_opt, "i17")) | ||
110 | model = M_I17; | ||
111 | else if (!strcmp(this_opt, "i20")) | ||
112 | model = M_I20; | ||
113 | else if (!strcmp(this_opt, "mini")) | ||
114 | model = M_MINI; | ||
115 | else if (!strcmp(this_opt, "macbook")) | ||
116 | model = M_MACBOOK; | ||
117 | else if (!strncmp(this_opt, "height:", 7)) | ||
118 | manual_height = simple_strtoul(this_opt+7, NULL, 0); | ||
119 | else if (!strncmp(this_opt, "width:", 6)) | ||
120 | manual_width = simple_strtoul(this_opt+6, NULL, 0); | ||
121 | } | ||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | static int __init imacfb_probe(struct platform_device *dev) | ||
126 | { | ||
127 | struct fb_info *info; | ||
128 | int err; | ||
129 | unsigned int size_vmode; | ||
130 | unsigned int size_remap; | ||
131 | unsigned int size_total; | ||
132 | |||
133 | screen_info.lfb_depth = 32; | ||
134 | screen_info.lfb_size = DEFAULT_FB_MEM / 0x10000; | ||
135 | screen_info.pages=1; | ||
136 | screen_info.blue_size = 8; | ||
137 | screen_info.blue_pos = 0; | ||
138 | screen_info.green_size = 8; | ||
139 | screen_info.green_pos = 8; | ||
140 | screen_info.red_size = 8; | ||
141 | screen_info.red_pos = 16; | ||
142 | screen_info.rsvd_size = 8; | ||
143 | screen_info.rsvd_pos = 24; | ||
144 | |||
145 | switch (model) { | ||
146 | case M_I17: | ||
147 | screen_info.lfb_width = 1440; | ||
148 | screen_info.lfb_height = 900; | ||
149 | screen_info.lfb_linelength = 1472 * 4; | ||
150 | screen_info.lfb_base = 0x80010000; | ||
151 | break; | ||
152 | case M_NEW: | ||
153 | case M_I20: | ||
154 | screen_info.lfb_width = 1680; | ||
155 | screen_info.lfb_height = 1050; | ||
156 | screen_info.lfb_linelength = 1728 * 4; | ||
157 | screen_info.lfb_base = 0x80010000; | ||
158 | break; | ||
159 | case M_MINI: | ||
160 | screen_info.lfb_width = 1024; | ||
161 | screen_info.lfb_height = 768; | ||
162 | screen_info.lfb_linelength = 2048 * 4; | ||
163 | screen_info.lfb_base = 0x80000000; | ||
164 | break; | ||
165 | case M_MACBOOK: | ||
166 | screen_info.lfb_width = 1280; | ||
167 | screen_info.lfb_height = 800; | ||
168 | screen_info.lfb_linelength = 2048 * 4; | ||
169 | screen_info.lfb_base = 0x80000000; | ||
170 | break; | ||
171 | } | ||
172 | |||
173 | /* if the user wants to manually specify height/width, | ||
174 | we will override the defaults */ | ||
175 | /* TODO: eventually get auto-detection working */ | ||
176 | if (manual_height > 0) | ||
177 | screen_info.lfb_height = manual_height; | ||
178 | if (manual_width > 0) | ||
179 | screen_info.lfb_width = manual_width; | ||
180 | |||
181 | imacfb_fix.smem_start = screen_info.lfb_base; | ||
182 | imacfb_defined.bits_per_pixel = screen_info.lfb_depth; | ||
183 | imacfb_defined.xres = screen_info.lfb_width; | ||
184 | imacfb_defined.yres = screen_info.lfb_height; | ||
185 | imacfb_fix.line_length = screen_info.lfb_linelength; | ||
186 | |||
187 | /* size_vmode -- that is the amount of memory needed for the | ||
188 | * used video mode, i.e. the minimum amount of | ||
189 | * memory we need. */ | ||
190 | size_vmode = imacfb_defined.yres * imacfb_fix.line_length; | ||
191 | |||
192 | /* size_total -- all video memory we have. Used for | ||
193 | * entries, ressource allocation and bounds | ||
194 | * checking. */ | ||
195 | size_total = screen_info.lfb_size * 65536; | ||
196 | if (size_total < size_vmode) | ||
197 | size_total = size_vmode; | ||
198 | |||
199 | /* size_remap -- the amount of video memory we are going to | ||
200 | * use for imacfb. With modern cards it is no | ||
201 | * option to simply use size_total as that | ||
202 | * wastes plenty of kernel address space. */ | ||
203 | size_remap = size_vmode * 2; | ||
204 | if (size_remap < size_vmode) | ||
205 | size_remap = size_vmode; | ||
206 | if (size_remap > size_total) | ||
207 | size_remap = size_total; | ||
208 | imacfb_fix.smem_len = size_remap; | ||
209 | |||
210 | #ifndef __i386__ | ||
211 | screen_info.imacpm_seg = 0; | ||
212 | #endif | ||
213 | |||
214 | if (!request_mem_region(imacfb_fix.smem_start, size_total, "imacfb")) { | ||
215 | printk(KERN_WARNING | ||
216 | "imacfb: cannot reserve video memory at 0x%lx\n", | ||
217 | imacfb_fix.smem_start); | ||
218 | /* We cannot make this fatal. Sometimes this comes from magic | ||
219 | spaces our resource handlers simply don't know about */ | ||
220 | } | ||
221 | |||
222 | info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev); | ||
223 | if (!info) { | ||
224 | err = -ENOMEM; | ||
225 | goto err_release_mem; | ||
226 | } | ||
227 | info->pseudo_palette = info->par; | ||
228 | info->par = NULL; | ||
229 | |||
230 | info->screen_base = ioremap(imacfb_fix.smem_start, imacfb_fix.smem_len); | ||
231 | if (!info->screen_base) { | ||
232 | printk(KERN_ERR "imacfb: abort, cannot ioremap video memory " | ||
233 | "0x%x @ 0x%lx\n", | ||
234 | imacfb_fix.smem_len, imacfb_fix.smem_start); | ||
235 | err = -EIO; | ||
236 | goto err_unmap; | ||
237 | } | ||
238 | |||
239 | printk(KERN_INFO "imacfb: framebuffer at 0x%lx, mapped to 0x%p, " | ||
240 | "using %dk, total %dk\n", | ||
241 | imacfb_fix.smem_start, info->screen_base, | ||
242 | size_remap/1024, size_total/1024); | ||
243 | printk(KERN_INFO "imacfb: mode is %dx%dx%d, linelength=%d, pages=%d\n", | ||
244 | imacfb_defined.xres, imacfb_defined.yres, | ||
245 | imacfb_defined.bits_per_pixel, imacfb_fix.line_length, | ||
246 | screen_info.pages); | ||
247 | |||
248 | imacfb_defined.xres_virtual = imacfb_defined.xres; | ||
249 | imacfb_defined.yres_virtual = imacfb_fix.smem_len / | ||
250 | imacfb_fix.line_length; | ||
251 | printk(KERN_INFO "imacfb: scrolling: redraw\n"); | ||
252 | imacfb_defined.yres_virtual = imacfb_defined.yres; | ||
253 | |||
254 | /* some dummy values for timing to make fbset happy */ | ||
255 | imacfb_defined.pixclock = 10000000 / imacfb_defined.xres * | ||
256 | 1000 / imacfb_defined.yres; | ||
257 | imacfb_defined.left_margin = (imacfb_defined.xres / 8) & 0xf8; | ||
258 | imacfb_defined.hsync_len = (imacfb_defined.xres / 8) & 0xf8; | ||
259 | |||
260 | imacfb_defined.red.offset = screen_info.red_pos; | ||
261 | imacfb_defined.red.length = screen_info.red_size; | ||
262 | imacfb_defined.green.offset = screen_info.green_pos; | ||
263 | imacfb_defined.green.length = screen_info.green_size; | ||
264 | imacfb_defined.blue.offset = screen_info.blue_pos; | ||
265 | imacfb_defined.blue.length = screen_info.blue_size; | ||
266 | imacfb_defined.transp.offset = screen_info.rsvd_pos; | ||
267 | imacfb_defined.transp.length = screen_info.rsvd_size; | ||
268 | |||
269 | printk(KERN_INFO "imacfb: %s: " | ||
270 | "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n", | ||
271 | "Truecolor", | ||
272 | screen_info.rsvd_size, | ||
273 | screen_info.red_size, | ||
274 | screen_info.green_size, | ||
275 | screen_info.blue_size, | ||
276 | screen_info.rsvd_pos, | ||
277 | screen_info.red_pos, | ||
278 | screen_info.green_pos, | ||
279 | screen_info.blue_pos); | ||
280 | |||
281 | imacfb_fix.ypanstep = 0; | ||
282 | imacfb_fix.ywrapstep = 0; | ||
283 | |||
284 | /* request failure does not faze us, as vgacon probably has this | ||
285 | * region already (FIXME) */ | ||
286 | request_region(0x3c0, 32, "imacfb"); | ||
287 | |||
288 | info->fbops = &imacfb_ops; | ||
289 | info->var = imacfb_defined; | ||
290 | info->fix = imacfb_fix; | ||
291 | info->flags = FBINFO_FLAG_DEFAULT; | ||
292 | |||
293 | if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) { | ||
294 | err = -ENOMEM; | ||
295 | goto err_unmap; | ||
296 | } | ||
297 | if (register_framebuffer(info)<0) { | ||
298 | err = -EINVAL; | ||
299 | goto err_fb_dealoc; | ||
300 | } | ||
301 | printk(KERN_INFO "fb%d: %s frame buffer device\n", | ||
302 | info->node, info->fix.id); | ||
303 | return 0; | ||
304 | |||
305 | err_fb_dealoc: | ||
306 | fb_dealloc_cmap(&info->cmap); | ||
307 | err_unmap: | ||
308 | iounmap(info->screen_base); | ||
309 | framebuffer_release(info); | ||
310 | err_release_mem: | ||
311 | release_mem_region(imacfb_fix.smem_start, size_total); | ||
312 | return err; | ||
313 | } | ||
314 | |||
315 | static struct platform_driver imacfb_driver = { | ||
316 | .probe = imacfb_probe, | ||
317 | .driver = { | ||
318 | .name = "imacfb", | ||
319 | }, | ||
320 | }; | ||
321 | |||
322 | static struct platform_device imacfb_device = { | ||
323 | .name = "imacfb", | ||
324 | }; | ||
325 | |||
326 | static int __init imacfb_init(void) | ||
327 | { | ||
328 | int ret; | ||
329 | char *option = NULL; | ||
330 | |||
331 | /* ignore error return of fb_get_options */ | ||
332 | fb_get_options("imacfb", &option); | ||
333 | imacfb_setup(option); | ||
334 | ret = platform_driver_register(&imacfb_driver); | ||
335 | |||
336 | if (!ret) { | ||
337 | ret = platform_device_register(&imacfb_device); | ||
338 | if (ret) | ||
339 | platform_driver_unregister(&imacfb_driver); | ||
340 | } | ||
341 | return ret; | ||
342 | } | ||
343 | module_init(imacfb_init); | ||
344 | |||
345 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/macmodes.c b/drivers/video/macmodes.c index c0385c6f7db5..d21321ca7c39 100644 --- a/drivers/video/macmodes.c +++ b/drivers/video/macmodes.c | |||
@@ -327,7 +327,6 @@ int mac_var_to_vmode(const struct fb_var_screeninfo *var, int *vmode, | |||
327 | } | 327 | } |
328 | return -EINVAL; | 328 | return -EINVAL; |
329 | } | 329 | } |
330 | EXPORT_SYMBOL(mac_var_to_vmode); | ||
331 | 330 | ||
332 | /** | 331 | /** |
333 | * mac_map_monitor_sense - Convert monitor sense to vmode | 332 | * mac_map_monitor_sense - Convert monitor sense to vmode |
@@ -371,8 +370,9 @@ EXPORT_SYMBOL(mac_map_monitor_sense); | |||
371 | * | 370 | * |
372 | */ | 371 | */ |
373 | 372 | ||
374 | int __init mac_find_mode(struct fb_var_screeninfo *var, struct fb_info *info, | 373 | int __devinit mac_find_mode(struct fb_var_screeninfo *var, |
375 | const char *mode_option, unsigned int default_bpp) | 374 | struct fb_info *info, const char *mode_option, |
375 | unsigned int default_bpp) | ||
376 | { | 376 | { |
377 | const struct fb_videomode *db = NULL; | 377 | const struct fb_videomode *db = NULL; |
378 | unsigned int dbsize = 0; | 378 | unsigned int dbsize = 0; |
diff --git a/drivers/video/macmodes.h b/drivers/video/macmodes.h index 232f5a09a499..babeb81f467d 100644 --- a/drivers/video/macmodes.h +++ b/drivers/video/macmodes.h | |||
@@ -55,9 +55,10 @@ extern int mac_vmode_to_var(int vmode, int cmode, | |||
55 | extern int mac_var_to_vmode(const struct fb_var_screeninfo *var, int *vmode, | 55 | extern int mac_var_to_vmode(const struct fb_var_screeninfo *var, int *vmode, |
56 | int *cmode); | 56 | int *cmode); |
57 | extern int mac_map_monitor_sense(int sense); | 57 | extern int mac_map_monitor_sense(int sense); |
58 | extern int __init mac_find_mode(struct fb_var_screeninfo *var, | 58 | extern int __devinit mac_find_mode(struct fb_var_screeninfo *var, |
59 | struct fb_info *info, const char *mode_option, | 59 | struct fb_info *info, |
60 | unsigned int default_bpp); | 60 | const char *mode_option, |
61 | unsigned int default_bpp); | ||
61 | 62 | ||
62 | 63 | ||
63 | /* | 64 | /* |
diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c index 26a1c618a205..ff5454601e22 100644 --- a/drivers/video/modedb.c +++ b/drivers/video/modedb.c | |||
@@ -259,6 +259,10 @@ static const struct fb_videomode modedb[] = { | |||
259 | /* 1152x768, 60 Hz, PowerBook G4 Titanium I and II */ | 259 | /* 1152x768, 60 Hz, PowerBook G4 Titanium I and II */ |
260 | NULL, 60, 1152, 768, 15386, 158, 26, 29, 3, 136, 6, | 260 | NULL, 60, 1152, 768, 15386, 158, 26, 29, 3, 136, 6, |
261 | FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED | 261 | FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED |
262 | }, { | ||
263 | /* 1366x768, 60 Hz, 47.403 kHz hsync, WXGA 16:9 aspect ratio */ | ||
264 | NULL, 60, 1366, 768, 13806, 120, 10, 14, 3, 32, 5, | ||
265 | 0, FB_VMODE_NONINTERLACED | ||
262 | }, | 266 | }, |
263 | }; | 267 | }; |
264 | 268 | ||
@@ -787,8 +791,9 @@ struct fb_videomode *fb_find_best_mode(struct fb_var_screeninfo *var, | |||
787 | if (diff > d) { | 791 | if (diff > d) { |
788 | diff = d; | 792 | diff = d; |
789 | best = mode; | 793 | best = mode; |
790 | } else if (diff == d && mode->refresh > best->refresh) | 794 | } else if (diff == d && best && |
791 | best = mode; | 795 | mode->refresh > best->refresh) |
796 | best = mode; | ||
792 | } | 797 | } |
793 | } | 798 | } |
794 | return best; | 799 | return best; |
@@ -1016,8 +1021,6 @@ EXPORT_SYMBOL(fb_videomode_to_var); | |||
1016 | EXPORT_SYMBOL(fb_var_to_videomode); | 1021 | EXPORT_SYMBOL(fb_var_to_videomode); |
1017 | EXPORT_SYMBOL(fb_mode_is_equal); | 1022 | EXPORT_SYMBOL(fb_mode_is_equal); |
1018 | EXPORT_SYMBOL(fb_add_videomode); | 1023 | EXPORT_SYMBOL(fb_add_videomode); |
1019 | EXPORT_SYMBOL(fb_delete_videomode); | ||
1020 | EXPORT_SYMBOL(fb_destroy_modelist); | ||
1021 | EXPORT_SYMBOL(fb_match_mode); | 1024 | EXPORT_SYMBOL(fb_match_mode); |
1022 | EXPORT_SYMBOL(fb_find_best_mode); | 1025 | EXPORT_SYMBOL(fb_find_best_mode); |
1023 | EXPORT_SYMBOL(fb_find_nearest_mode); | 1026 | EXPORT_SYMBOL(fb_find_nearest_mode); |
diff --git a/drivers/video/neofb.c b/drivers/video/neofb.c index 24b12f71d5a8..2f156b724d1c 100644 --- a/drivers/video/neofb.c +++ b/drivers/video/neofb.c | |||
@@ -1333,17 +1333,22 @@ static int neofb_blank(int blank_mode, struct fb_info *info) | |||
1333 | * run "setterm -powersave powerdown" to take advantage | 1333 | * run "setterm -powersave powerdown" to take advantage |
1334 | */ | 1334 | */ |
1335 | struct neofb_par *par = info->par; | 1335 | struct neofb_par *par = info->par; |
1336 | int seqflags, lcdflags, dpmsflags, reg; | 1336 | int seqflags, lcdflags, dpmsflags, reg, tmpdisp; |
1337 | |||
1338 | 1337 | ||
1339 | /* | 1338 | /* |
1340 | * Reload the value stored in the register, if sensible. It might have | 1339 | * Read back the register bits related to display configuration. They might |
1341 | * been changed via FN keystroke. | 1340 | * have been changed underneath the driver via Fn key stroke. |
1341 | */ | ||
1342 | neoUnlock(); | ||
1343 | tmpdisp = vga_rgfx(NULL, 0x20) & 0x03; | ||
1344 | neoLock(&par->state); | ||
1345 | |||
1346 | /* In case we blank the screen, we want to store the possibly new | ||
1347 | * configuration in the driver. During un-blank, we re-apply this setting, | ||
1348 | * since the LCD bit will be cleared in order to switch off the backlight. | ||
1342 | */ | 1349 | */ |
1343 | if (par->PanelDispCntlRegRead) { | 1350 | if (par->PanelDispCntlRegRead) { |
1344 | neoUnlock(); | 1351 | par->PanelDispCntlReg1 = tmpdisp; |
1345 | par->PanelDispCntlReg1 = vga_rgfx(NULL, 0x20) & 0x03; | ||
1346 | neoLock(&par->state); | ||
1347 | } | 1352 | } |
1348 | par->PanelDispCntlRegRead = !blank_mode; | 1353 | par->PanelDispCntlRegRead = !blank_mode; |
1349 | 1354 | ||
@@ -1378,12 +1383,21 @@ static int neofb_blank(int blank_mode, struct fb_info *info) | |||
1378 | break; | 1383 | break; |
1379 | case FB_BLANK_NORMAL: /* just blank screen (backlight stays on) */ | 1384 | case FB_BLANK_NORMAL: /* just blank screen (backlight stays on) */ |
1380 | seqflags = VGA_SR01_SCREEN_OFF; /* Disable sequencer */ | 1385 | seqflags = VGA_SR01_SCREEN_OFF; /* Disable sequencer */ |
1381 | lcdflags = par->PanelDispCntlReg1 & 0x02; /* LCD normal */ | 1386 | /* |
1387 | * During a blank operation with the LID shut, we might store "LCD off" | ||
1388 | * by mistake. Due to timing issues, the BIOS may switch the lights | ||
1389 | * back on, and we turn it back off once we "unblank". | ||
1390 | * | ||
1391 | * So here is an attempt to implement ">=" - if we are in the process | ||
1392 | * of unblanking, and the LCD bit is unset in the driver but set in the | ||
1393 | * register, we must keep it. | ||
1394 | */ | ||
1395 | lcdflags = ((par->PanelDispCntlReg1 | tmpdisp) & 0x02); /* LCD normal */ | ||
1382 | dpmsflags = 0x00; /* no hsync/vsync suppression */ | 1396 | dpmsflags = 0x00; /* no hsync/vsync suppression */ |
1383 | break; | 1397 | break; |
1384 | case FB_BLANK_UNBLANK: /* unblank */ | 1398 | case FB_BLANK_UNBLANK: /* unblank */ |
1385 | seqflags = 0; /* Enable sequencer */ | 1399 | seqflags = 0; /* Enable sequencer */ |
1386 | lcdflags = par->PanelDispCntlReg1 & 0x02; /* LCD normal */ | 1400 | lcdflags = ((par->PanelDispCntlReg1 | tmpdisp) & 0x02); /* LCD normal */ |
1387 | dpmsflags = 0x00; /* no hsync/vsync suppression */ | 1401 | dpmsflags = 0x00; /* no hsync/vsync suppression */ |
1388 | #ifdef CONFIG_TOSHIBA | 1402 | #ifdef CONFIG_TOSHIBA |
1389 | /* Do we still need this ? */ | 1403 | /* Do we still need this ? */ |
diff --git a/drivers/video/nvidia/nv_hw.c b/drivers/video/nvidia/nv_hw.c index 99c3a8e6a237..9ed640d35728 100644 --- a/drivers/video/nvidia/nv_hw.c +++ b/drivers/video/nvidia/nv_hw.c | |||
@@ -886,7 +886,10 @@ void NVCalcStateExt(struct nvidia_par *par, | |||
886 | case NV_ARCH_20: | 886 | case NV_ARCH_20: |
887 | case NV_ARCH_30: | 887 | case NV_ARCH_30: |
888 | default: | 888 | default: |
889 | if (((par->Chipset & 0xffff) == 0x01A0) || | 889 | if ((par->Chipset & 0xfff0) == 0x0240) { |
890 | state->arbitration0 = 256; | ||
891 | state->arbitration1 = 0x0480; | ||
892 | } else if (((par->Chipset & 0xffff) == 0x01A0) || | ||
890 | ((par->Chipset & 0xffff) == 0x01f0)) { | 893 | ((par->Chipset & 0xffff) == 0x01f0)) { |
891 | nForceUpdateArbitrationSettings(VClk, | 894 | nForceUpdateArbitrationSettings(VClk, |
892 | pixelDepth * 8, | 895 | pixelDepth * 8, |
@@ -1235,6 +1238,7 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state) | |||
1235 | break; | 1238 | break; |
1236 | case 0x0160: | 1239 | case 0x0160: |
1237 | case 0x01D0: | 1240 | case 0x01D0: |
1241 | case 0x0240: | ||
1238 | NV_WR32(par->PMC, 0x1700, | 1242 | NV_WR32(par->PMC, 0x1700, |
1239 | NV_RD32(par->PFB, 0x020C)); | 1243 | NV_RD32(par->PFB, 0x020C)); |
1240 | NV_WR32(par->PMC, 0x1704, 0); | 1244 | NV_WR32(par->PMC, 0x1704, 0); |
@@ -1359,7 +1363,9 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state) | |||
1359 | if(((par->Chipset & 0xfff0) | 1363 | if(((par->Chipset & 0xfff0) |
1360 | != 0x0160) && | 1364 | != 0x0160) && |
1361 | ((par->Chipset & 0xfff0) | 1365 | ((par->Chipset & 0xfff0) |
1362 | != 0x0220)) | 1366 | != 0x0220) && |
1367 | ((par->Chipset & 0xfff0) | ||
1368 | != 0x240)) | ||
1363 | NV_WR32(par->PGRAPH, | 1369 | NV_WR32(par->PGRAPH, |
1364 | 0x6900 + i*4, | 1370 | 0x6900 + i*4, |
1365 | NV_RD32(par->PFB, | 1371 | NV_RD32(par->PFB, |
diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c index 03a7c1e9ce38..7b5cffb27851 100644 --- a/drivers/video/nvidia/nvidia.c +++ b/drivers/video/nvidia/nvidia.c | |||
@@ -67,359 +67,10 @@ | |||
67 | #define MAX_CURS 32 | 67 | #define MAX_CURS 32 |
68 | 68 | ||
69 | static struct pci_device_id nvidiafb_pci_tbl[] = { | 69 | static struct pci_device_id nvidiafb_pci_tbl[] = { |
70 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_TNT, | 70 | {PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, |
71 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | 71 | PCI_BASE_CLASS_DISPLAY << 16, 0xff0000, 0}, |
72 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_TNT2, | 72 | { 0, } |
73 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
74 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_UTNT2, | ||
75 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
76 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_TNT_UNKNOWN, | ||
77 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
78 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_VTNT2, | ||
79 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
80 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_UVTNT2, | ||
81 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
82 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_ITNT2, | ||
83 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
84 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_SDR, | ||
85 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
86 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_DDR, | ||
87 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
88 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO, | ||
89 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
90 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX, | ||
91 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
92 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX2, | ||
93 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
94 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GO, | ||
95 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
96 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO2_MXR, | ||
97 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
98 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS, | ||
99 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
100 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS2, | ||
101 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
102 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_ULTRA, | ||
103 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
104 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO2_PRO, | ||
105 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
106 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_460, | ||
107 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
108 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440, | ||
109 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
110 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_420, | ||
111 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
112 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440_SE, | ||
113 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
114 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO, | ||
115 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
116 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO, | ||
117 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
118 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_460_GO, | ||
119 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
120 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO_M32, | ||
121 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
122 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_500XGL, | ||
123 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
124 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO_M64, | ||
125 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
126 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_200, | ||
127 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
128 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_550XGL, | ||
129 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
130 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_500_GOGL, | ||
131 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
132 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_410_GO_M16, | ||
133 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
134 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440_8X, | ||
135 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
136 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440SE_8X, | ||
137 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
138 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_420_8X, | ||
139 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
140 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_4000, | ||
141 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
142 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_448_GO, | ||
143 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
144 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_488_GO, | ||
145 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
146 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_580_XGL, | ||
147 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
148 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_MAC, | ||
149 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
150 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_280_NVS, | ||
151 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
152 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_380_XGL, | ||
153 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
154 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_IGEFORCE2, | ||
155 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
156 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3, | ||
157 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
158 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3_1, | ||
159 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
160 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3_2, | ||
161 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
162 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_DDC, | ||
163 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
164 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4600, | ||
165 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
166 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4400, | ||
167 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
168 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4200, | ||
169 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
170 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_900XGL, | ||
171 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
172 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_750XGL, | ||
173 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
174 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_700XGL, | ||
175 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
176 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800, | ||
177 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
178 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800_8X, | ||
179 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
180 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800SE, | ||
181 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
182 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_4200_GO, | ||
183 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
184 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_980_XGL, | ||
185 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
186 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_780_XGL, | ||
187 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
188 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_700_GOGL, | ||
189 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
190 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5800_ULTRA, | ||
191 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
192 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5800, | ||
193 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
194 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_2000, | ||
195 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
196 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_1000, | ||
197 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
198 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5600_ULTRA, | ||
199 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
200 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5600, | ||
201 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
202 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5600SE, | ||
203 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
204 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5600, | ||
205 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
206 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5650, | ||
207 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
208 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_GO700, | ||
209 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
210 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200, | ||
211 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
212 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200_ULTRA, | ||
213 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
214 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200_1, | ||
215 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
216 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200SE, | ||
217 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
218 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5200, | ||
219 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
220 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5250, | ||
221 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
222 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5250_32, | ||
223 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
224 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO_5200, | ||
225 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
226 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_NVS_280_PCI, | ||
227 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
228 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_500, | ||
229 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
230 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5300, | ||
231 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
232 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5100, | ||
233 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
234 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900_ULTRA, | ||
235 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
236 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900, | ||
237 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
238 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900XT, | ||
239 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
240 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5950_ULTRA, | ||
241 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
242 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_3000, | ||
243 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
244 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700_ULTRA, | ||
245 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
246 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700, | ||
247 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
248 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700LE, | ||
249 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
250 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700VE, | ||
251 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
252 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5700_1, | ||
253 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
254 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5700_2, | ||
255 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
256 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_GO1000, | ||
257 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
258 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_1100, | ||
259 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
260 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5500, | ||
261 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
262 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5100, | ||
263 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
264 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_700, | ||
265 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
266 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900ZT, | ||
267 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
268 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6800_ULTRA, | ||
269 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
270 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6800, | ||
271 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
272 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6800_LE, | ||
273 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
274 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6800_GT, | ||
275 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
276 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_4000, | ||
277 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
278 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6600_GT, | ||
279 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
280 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6600, | ||
281 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
282 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6610_XL, | ||
283 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
284 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_540, | ||
285 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
286 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6200, | ||
287 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
288 | {PCI_VENDOR_ID_NVIDIA, PCIE_DEVICE_ID_NVIDIA_GEFORCE_6800_ALT1, | ||
289 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
290 | {PCI_VENDOR_ID_NVIDIA, PCIE_DEVICE_ID_NVIDIA_GEFORCE_6600_ALT1, | ||
291 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
292 | {PCI_VENDOR_ID_NVIDIA, PCIE_DEVICE_ID_NVIDIA_GEFORCE_6600_ALT2, | ||
293 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
294 | {PCI_VENDOR_ID_NVIDIA, PCIE_DEVICE_ID_NVIDIA_GEFORCE_6200_ALT1, | ||
295 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
296 | {PCI_VENDOR_ID_NVIDIA, PCIE_DEVICE_ID_NVIDIA_GEFORCE_6800_GT, | ||
297 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
298 | {PCI_VENDOR_ID_NVIDIA, PCIE_DEVICE_ID_NVIDIA_QUADRO_NVS280, | ||
299 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
300 | {PCI_VENDOR_ID_NVIDIA, 0x0252, | ||
301 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
302 | {PCI_VENDOR_ID_NVIDIA, 0x0313, | ||
303 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
304 | {PCI_VENDOR_ID_NVIDIA, 0x0316, | ||
305 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
306 | {PCI_VENDOR_ID_NVIDIA, 0x0317, | ||
307 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
308 | {PCI_VENDOR_ID_NVIDIA, 0x031D, | ||
309 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
310 | {PCI_VENDOR_ID_NVIDIA, 0x031E, | ||
311 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
312 | {PCI_VENDOR_ID_NVIDIA, 0x031F, | ||
313 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
314 | {PCI_VENDOR_ID_NVIDIA, 0x0329, | ||
315 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
316 | {PCI_VENDOR_ID_NVIDIA, 0x032F, | ||
317 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
318 | {PCI_VENDOR_ID_NVIDIA, 0x0345, | ||
319 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
320 | {PCI_VENDOR_ID_NVIDIA, 0x0349, | ||
321 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
322 | {PCI_VENDOR_ID_NVIDIA, 0x034B, | ||
323 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
324 | {PCI_VENDOR_ID_NVIDIA, 0x034F, | ||
325 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
326 | {PCI_VENDOR_ID_NVIDIA, 0x00c0, | ||
327 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
328 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_GEFORCE_6800A, | ||
329 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
330 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_GEFORCE_6800A_LE, | ||
331 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
332 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_GEFORCE_GO_6800, | ||
333 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
334 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_GEFORCE_GO_6800_ULTRA, | ||
335 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
336 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_QUADRO_FX_GO1400, | ||
337 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
338 | {PCI_VENDOR_ID_NVIDIA, 0x00cd, | ||
339 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
340 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_QUADRO_FX_1400, | ||
341 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
342 | {PCI_VENDOR_ID_NVIDIA, 0x0142, | ||
343 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
344 | {PCI_VENDOR_ID_NVIDIA, 0x0143, | ||
345 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
346 | {PCI_VENDOR_ID_NVIDIA, 0x0144, | ||
347 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
348 | {PCI_VENDOR_ID_NVIDIA, 0x0145, | ||
349 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
350 | {PCI_VENDOR_ID_NVIDIA, 0x0146, | ||
351 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
352 | {PCI_VENDOR_ID_NVIDIA, 0x0147, | ||
353 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
354 | {PCI_VENDOR_ID_NVIDIA, 0x0148, | ||
355 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
356 | {PCI_VENDOR_ID_NVIDIA, 0x0149, | ||
357 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
358 | {PCI_VENDOR_ID_NVIDIA, 0x014b, | ||
359 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
360 | {PCI_VENDOR_ID_NVIDIA, 0x14c, | ||
361 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
362 | {PCI_VENDOR_ID_NVIDIA, 0x014d, | ||
363 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
364 | {PCI_VENDOR_ID_NVIDIA, 0x0160, | ||
365 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
366 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6200_TURBOCACHE, | ||
367 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
368 | {PCI_VENDOR_ID_NVIDIA, 0x0162, | ||
369 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
370 | {PCI_VENDOR_ID_NVIDIA, 0x0163, | ||
371 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
372 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6200, | ||
373 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
374 | {PCI_VENDOR_ID_NVIDIA, 0x0165, | ||
375 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
376 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6250, | ||
377 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
378 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6200_1, | ||
379 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
380 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6250_1, | ||
381 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
382 | {PCI_VENDOR_ID_NVIDIA, 0x0169, | ||
383 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
384 | {PCI_VENDOR_ID_NVIDIA, 0x016b, | ||
385 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
386 | {PCI_VENDOR_ID_NVIDIA, 0x016c, | ||
387 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
388 | {PCI_VENDOR_ID_NVIDIA, 0x016d, | ||
389 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
390 | {PCI_VENDOR_ID_NVIDIA, 0x016e, | ||
391 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
392 | {PCI_VENDOR_ID_NVIDIA, 0x0210, | ||
393 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
394 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6800B, | ||
395 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
396 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6800B_LE, | ||
397 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
398 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6800B_GT, | ||
399 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
400 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_7800_GT, | ||
401 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
402 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_7800_GTX, | ||
403 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
404 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_7800, | ||
405 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
406 | {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_7800_GTX, | ||
407 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
408 | {PCI_VENDOR_ID_NVIDIA, 0x021d, | ||
409 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
410 | {PCI_VENDOR_ID_NVIDIA, 0x021e, | ||
411 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
412 | {PCI_VENDOR_ID_NVIDIA, 0x0220, | ||
413 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
414 | {PCI_VENDOR_ID_NVIDIA, 0x0221, | ||
415 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
416 | {PCI_VENDOR_ID_NVIDIA, 0x0222, | ||
417 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
418 | {PCI_VENDOR_ID_NVIDIA, 0x0228, | ||
419 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
420 | {0,} /* terminate list */ | ||
421 | }; | 73 | }; |
422 | |||
423 | MODULE_DEVICE_TABLE(pci, nvidiafb_pci_tbl); | 74 | MODULE_DEVICE_TABLE(pci, nvidiafb_pci_tbl); |
424 | 75 | ||
425 | /* command line data, set in nvidiafb_setup() */ | 76 | /* command line data, set in nvidiafb_setup() */ |
@@ -1465,10 +1116,10 @@ static u32 __devinit nvidia_get_chipset(struct fb_info *info) | |||
1465 | struct nvidia_par *par = info->par; | 1116 | struct nvidia_par *par = info->par; |
1466 | u32 id = (par->pci_dev->vendor << 16) | par->pci_dev->device; | 1117 | u32 id = (par->pci_dev->vendor << 16) | par->pci_dev->device; |
1467 | 1118 | ||
1468 | printk("nvidiafb: PCI id - %x\n", id); | 1119 | printk(KERN_INFO PFX "Device ID: %x \n", id); |
1120 | |||
1469 | if ((id & 0xfff0) == 0x00f0) { | 1121 | if ((id & 0xfff0) == 0x00f0) { |
1470 | /* pci-e */ | 1122 | /* pci-e */ |
1471 | printk("nvidiafb: PCI-E card\n"); | ||
1472 | id = NV_RD32(par->REGS, 0x1800); | 1123 | id = NV_RD32(par->REGS, 0x1800); |
1473 | 1124 | ||
1474 | if ((id & 0x0000ffff) == 0x000010DE) | 1125 | if ((id & 0x0000ffff) == 0x000010DE) |
@@ -1476,9 +1127,9 @@ static u32 __devinit nvidia_get_chipset(struct fb_info *info) | |||
1476 | else if ((id & 0xffff0000) == 0xDE100000) /* wrong endian */ | 1127 | else if ((id & 0xffff0000) == 0xDE100000) /* wrong endian */ |
1477 | id = 0x10DE0000 | ((id << 8) & 0x0000ff00) | | 1128 | id = 0x10DE0000 | ((id << 8) & 0x0000ff00) | |
1478 | ((id >> 8) & 0x000000ff); | 1129 | ((id >> 8) & 0x000000ff); |
1130 | printk(KERN_INFO PFX "Subsystem ID: %x \n", id); | ||
1479 | } | 1131 | } |
1480 | 1132 | ||
1481 | printk("nvidiafb: Actual id - %x\n", id); | ||
1482 | return id; | 1133 | return id; |
1483 | } | 1134 | } |
1484 | 1135 | ||
@@ -1520,6 +1171,7 @@ static u32 __devinit nvidia_get_arch(struct fb_info *info) | |||
1520 | case 0x0210: | 1171 | case 0x0210: |
1521 | case 0x0220: | 1172 | case 0x0220: |
1522 | case 0x0230: | 1173 | case 0x0230: |
1174 | case 0x0240: | ||
1523 | case 0x0290: | 1175 | case 0x0290: |
1524 | case 0x0390: | 1176 | case 0x0390: |
1525 | arch = NV_ARCH_40; | 1177 | arch = NV_ARCH_40; |
@@ -1567,7 +1219,7 @@ static int __devinit nvidiafb_probe(struct pci_dev *pd, | |||
1567 | 1219 | ||
1568 | if (pci_request_regions(pd, "nvidiafb")) { | 1220 | if (pci_request_regions(pd, "nvidiafb")) { |
1569 | printk(KERN_ERR PFX "cannot request PCI regions\n"); | 1221 | printk(KERN_ERR PFX "cannot request PCI regions\n"); |
1570 | goto err_out_request; | 1222 | goto err_out_enable; |
1571 | } | 1223 | } |
1572 | 1224 | ||
1573 | par->FlatPanel = flatpanel; | 1225 | par->FlatPanel = flatpanel; |
@@ -1596,7 +1248,6 @@ static int __devinit nvidiafb_probe(struct pci_dev *pd, | |||
1596 | } | 1248 | } |
1597 | 1249 | ||
1598 | par->Chipset = nvidia_get_chipset(info); | 1250 | par->Chipset = nvidia_get_chipset(info); |
1599 | printk(KERN_INFO PFX "nVidia device/chipset %X\n", par->Chipset); | ||
1600 | par->Architecture = nvidia_get_arch(info); | 1251 | par->Architecture = nvidia_get_arch(info); |
1601 | 1252 | ||
1602 | if (par->Architecture == 0) { | 1253 | if (par->Architecture == 0) { |
@@ -1687,10 +1338,8 @@ err_out_free_base1: | |||
1687 | nvidia_delete_i2c_busses(par); | 1338 | nvidia_delete_i2c_busses(par); |
1688 | err_out_arch: | 1339 | err_out_arch: |
1689 | iounmap(par->REGS); | 1340 | iounmap(par->REGS); |
1690 | err_out_free_base0: | 1341 | err_out_free_base0: |
1691 | pci_release_regions(pd); | 1342 | pci_release_regions(pd); |
1692 | err_out_request: | ||
1693 | pci_disable_device(pd); | ||
1694 | err_out_enable: | 1343 | err_out_enable: |
1695 | kfree(info->pixmap.addr); | 1344 | kfree(info->pixmap.addr); |
1696 | err_out_kfree: | 1345 | err_out_kfree: |
@@ -1720,7 +1369,6 @@ static void __exit nvidiafb_remove(struct pci_dev *pd) | |||
1720 | nvidia_delete_i2c_busses(par); | 1369 | nvidia_delete_i2c_busses(par); |
1721 | iounmap(par->REGS); | 1370 | iounmap(par->REGS); |
1722 | pci_release_regions(pd); | 1371 | pci_release_regions(pd); |
1723 | pci_disable_device(pd); | ||
1724 | kfree(info->pixmap.addr); | 1372 | kfree(info->pixmap.addr); |
1725 | framebuffer_release(info); | 1373 | framebuffer_release(info); |
1726 | pci_set_drvdata(pd, NULL); | 1374 | pci_set_drvdata(pd, NULL); |
diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c index d4384ab1df65..12af58c5cf1f 100644 --- a/drivers/video/riva/fbdev.c +++ b/drivers/video/riva/fbdev.c | |||
@@ -2152,7 +2152,6 @@ err_iounmap_ctrl_base: | |||
2152 | err_release_region: | 2152 | err_release_region: |
2153 | pci_release_regions(pd); | 2153 | pci_release_regions(pd); |
2154 | err_disable_device: | 2154 | err_disable_device: |
2155 | pci_disable_device(pd); | ||
2156 | err_free_pixmap: | 2155 | err_free_pixmap: |
2157 | kfree(info->pixmap.addr); | 2156 | kfree(info->pixmap.addr); |
2158 | err_framebuffer_release: | 2157 | err_framebuffer_release: |
@@ -2187,7 +2186,6 @@ static void __exit rivafb_remove(struct pci_dev *pd) | |||
2187 | if (par->riva.Architecture == NV_ARCH_03) | 2186 | if (par->riva.Architecture == NV_ARCH_03) |
2188 | iounmap(par->riva.PRAMIN); | 2187 | iounmap(par->riva.PRAMIN); |
2189 | pci_release_regions(pd); | 2188 | pci_release_regions(pd); |
2190 | pci_disable_device(pd); | ||
2191 | kfree(info->pixmap.addr); | 2189 | kfree(info->pixmap.addr); |
2192 | framebuffer_release(info); | 2190 | framebuffer_release(info); |
2193 | pci_set_drvdata(pd, NULL); | 2191 | pci_set_drvdata(pd, NULL); |
diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c index 9451932fbaf2..fbc411850686 100644 --- a/drivers/video/s3c2410fb.c +++ b/drivers/video/s3c2410fb.c | |||
@@ -641,6 +641,7 @@ static int __init s3c2410fb_probe(struct platform_device *pdev) | |||
641 | int ret; | 641 | int ret; |
642 | int irq; | 642 | int irq; |
643 | int i; | 643 | int i; |
644 | u32 lcdcon1; | ||
644 | 645 | ||
645 | mach_info = pdev->dev.platform_data; | 646 | mach_info = pdev->dev.platform_data; |
646 | if (mach_info == NULL) { | 647 | if (mach_info == NULL) { |
@@ -672,6 +673,11 @@ static int __init s3c2410fb_probe(struct platform_device *pdev) | |||
672 | 673 | ||
673 | memcpy(&info->regs, &mach_info->regs, sizeof(info->regs)); | 674 | memcpy(&info->regs, &mach_info->regs, sizeof(info->regs)); |
674 | 675 | ||
676 | /* Stop the video and unset ENVID if set */ | ||
677 | info->regs.lcdcon1 &= ~S3C2410_LCDCON1_ENVID; | ||
678 | lcdcon1 = readl(S3C2410_LCDCON1); | ||
679 | writel(lcdcon1 & ~S3C2410_LCDCON1_ENVID, S3C2410_LCDCON1); | ||
680 | |||
675 | info->mach_info = pdev->dev.platform_data; | 681 | info->mach_info = pdev->dev.platform_data; |
676 | 682 | ||
677 | fbinfo->fix.type = FB_TYPE_PACKED_PIXELS; | 683 | fbinfo->fix.type = FB_TYPE_PACKED_PIXELS; |
@@ -794,15 +800,14 @@ dealloc_fb: | |||
794 | * shutdown the lcd controller | 800 | * shutdown the lcd controller |
795 | */ | 801 | */ |
796 | 802 | ||
797 | static void s3c2410fb_stop_lcd(void) | 803 | static void s3c2410fb_stop_lcd(struct s3c2410fb_info *fbi) |
798 | { | 804 | { |
799 | unsigned long flags; | 805 | unsigned long flags; |
800 | unsigned long tmp; | ||
801 | 806 | ||
802 | local_irq_save(flags); | 807 | local_irq_save(flags); |
803 | 808 | ||
804 | tmp = readl(S3C2410_LCDCON1); | 809 | fbi->regs.lcdcon1 &= ~S3C2410_LCDCON1_ENVID; |
805 | writel(tmp & ~S3C2410_LCDCON1_ENVID, S3C2410_LCDCON1); | 810 | writel(fbi->regs.lcdcon1, S3C2410_LCDCON1); |
806 | 811 | ||
807 | local_irq_restore(flags); | 812 | local_irq_restore(flags); |
808 | } | 813 | } |
@@ -816,7 +821,7 @@ static int s3c2410fb_remove(struct platform_device *pdev) | |||
816 | struct s3c2410fb_info *info = fbinfo->par; | 821 | struct s3c2410fb_info *info = fbinfo->par; |
817 | int irq; | 822 | int irq; |
818 | 823 | ||
819 | s3c2410fb_stop_lcd(); | 824 | s3c2410fb_stop_lcd(info); |
820 | msleep(1); | 825 | msleep(1); |
821 | 826 | ||
822 | s3c2410fb_unmap_video_memory(info); | 827 | s3c2410fb_unmap_video_memory(info); |
@@ -844,7 +849,7 @@ static int s3c2410fb_suspend(struct platform_device *dev, pm_message_t state) | |||
844 | struct fb_info *fbinfo = platform_get_drvdata(dev); | 849 | struct fb_info *fbinfo = platform_get_drvdata(dev); |
845 | struct s3c2410fb_info *info = fbinfo->par; | 850 | struct s3c2410fb_info *info = fbinfo->par; |
846 | 851 | ||
847 | s3c2410fb_stop_lcd(); | 852 | s3c2410fb_stop_lcd(info); |
848 | 853 | ||
849 | /* sleep before disabling the clock, we need to ensure | 854 | /* sleep before disabling the clock, we need to ensure |
850 | * the LCD DMA engine is not going to get back on the bus | 855 | * the LCD DMA engine is not going to get back on the bus |
diff --git a/drivers/video/savage/savagefb.h b/drivers/video/savage/savagefb.h index 58cfdfb41833..e648a6c0f6d9 100644 --- a/drivers/video/savage/savagefb.h +++ b/drivers/video/savage/savagefb.h | |||
@@ -147,7 +147,27 @@ struct xtimings { | |||
147 | int interlaced; | 147 | int interlaced; |
148 | }; | 148 | }; |
149 | 149 | ||
150 | struct savage_reg { | ||
151 | unsigned char MiscOutReg; /* Misc */ | ||
152 | unsigned char CRTC[25]; /* Crtc Controller */ | ||
153 | unsigned char Sequencer[5]; /* Video Sequencer */ | ||
154 | unsigned char Graphics[9]; /* Video Graphics */ | ||
155 | unsigned char Attribute[21]; /* Video Atribute */ | ||
150 | 156 | ||
157 | unsigned int mode, refresh; | ||
158 | unsigned char SR08, SR0E, SR0F; | ||
159 | unsigned char SR10, SR11, SR12, SR13, SR15, SR18, SR29, SR30; | ||
160 | unsigned char SR54[8]; | ||
161 | unsigned char Clock; | ||
162 | unsigned char CR31, CR32, CR33, CR34, CR36, CR3A, CR3B, CR3C; | ||
163 | unsigned char CR40, CR41, CR42, CR43, CR45; | ||
164 | unsigned char CR50, CR51, CR53, CR55, CR58, CR5B, CR5D, CR5E; | ||
165 | unsigned char CR60, CR63, CR65, CR66, CR67, CR68, CR69, CR6D, CR6F; | ||
166 | unsigned char CR86, CR88; | ||
167 | unsigned char CR90, CR91, CRB0; | ||
168 | unsigned int STREAMS[22]; /* yuck, streams regs */ | ||
169 | unsigned int MMPR0, MMPR1, MMPR2, MMPR3; | ||
170 | }; | ||
151 | /* --------------------------------------------------------------------- */ | 171 | /* --------------------------------------------------------------------- */ |
152 | 172 | ||
153 | #define NR_PALETTE 256 | 173 | #define NR_PALETTE 256 |
@@ -167,6 +187,8 @@ struct savagefb_par { | |||
167 | struct pci_dev *pcidev; | 187 | struct pci_dev *pcidev; |
168 | savage_chipset chip; | 188 | savage_chipset chip; |
169 | struct savagefb_i2c_chan chan; | 189 | struct savagefb_i2c_chan chan; |
190 | struct savage_reg state; | ||
191 | struct savage_reg save; | ||
170 | unsigned char *edid; | 192 | unsigned char *edid; |
171 | u32 pseudo_palette[16]; | 193 | u32 pseudo_palette[16]; |
172 | int paletteEnabled; | 194 | int paletteEnabled; |
@@ -179,6 +201,7 @@ struct savagefb_par { | |||
179 | int minClock; | 201 | int minClock; |
180 | int numClocks; | 202 | int numClocks; |
181 | int clock[4]; | 203 | int clock[4]; |
204 | int MCLK, REFCLK, LCDclk; | ||
182 | struct { | 205 | struct { |
183 | u8 __iomem *vbase; | 206 | u8 __iomem *vbase; |
184 | u32 pbase; | 207 | u32 pbase; |
@@ -196,7 +219,6 @@ struct savagefb_par { | |||
196 | 219 | ||
197 | volatile u32 __iomem *bci_base; | 220 | volatile u32 __iomem *bci_base; |
198 | unsigned int bci_ptr; | 221 | unsigned int bci_ptr; |
199 | |||
200 | u32 cob_offset; | 222 | u32 cob_offset; |
201 | u32 cob_size; | 223 | u32 cob_size; |
202 | int cob_index; | 224 | int cob_index; |
@@ -204,7 +226,6 @@ struct savagefb_par { | |||
204 | void (*SavageWaitIdle) (struct savagefb_par *par); | 226 | void (*SavageWaitIdle) (struct savagefb_par *par); |
205 | void (*SavageWaitFifo) (struct savagefb_par *par, int space); | 227 | void (*SavageWaitFifo) (struct savagefb_par *par, int space); |
206 | 228 | ||
207 | int MCLK, REFCLK, LCDclk; | ||
208 | int HorizScaleFactor; | 229 | int HorizScaleFactor; |
209 | 230 | ||
210 | /* Panels size */ | 231 | /* Panels size */ |
@@ -217,26 +238,6 @@ struct savagefb_par { | |||
217 | 238 | ||
218 | int depth; | 239 | int depth; |
219 | int vwidth; | 240 | int vwidth; |
220 | |||
221 | unsigned char MiscOutReg; /* Misc */ | ||
222 | unsigned char CRTC[25]; /* Crtc Controller */ | ||
223 | unsigned char Sequencer[5]; /* Video Sequencer */ | ||
224 | unsigned char Graphics[9]; /* Video Graphics */ | ||
225 | unsigned char Attribute[21]; /* Video Atribute */ | ||
226 | |||
227 | unsigned int mode, refresh; | ||
228 | unsigned char SR08, SR0E, SR0F; | ||
229 | unsigned char SR10, SR11, SR12, SR13, SR15, SR18, SR29, SR30; | ||
230 | unsigned char SR54[8]; | ||
231 | unsigned char Clock; | ||
232 | unsigned char CR31, CR32, CR33, CR34, CR36, CR3A, CR3B, CR3C; | ||
233 | unsigned char CR40, CR41, CR42, CR43, CR45; | ||
234 | unsigned char CR50, CR51, CR53, CR55, CR58, CR5B, CR5D, CR5E; | ||
235 | unsigned char CR60, CR63, CR65, CR66, CR67, CR68, CR69, CR6D, CR6F; | ||
236 | unsigned char CR86, CR88; | ||
237 | unsigned char CR90, CR91, CRB0; | ||
238 | unsigned int STREAMS[22]; /* yuck, streams regs */ | ||
239 | unsigned int MMPR0, MMPR1, MMPR2, MMPR3; | ||
240 | }; | 241 | }; |
241 | 242 | ||
242 | #define BCI_BD_BW_DISABLE 0x10000000 | 243 | #define BCI_BD_BW_DISABLE 0x10000000 |
diff --git a/drivers/video/savage/savagefb_driver.c b/drivers/video/savage/savagefb_driver.c index 0da624e6524f..78883cf66a4d 100644 --- a/drivers/video/savage/savagefb_driver.c +++ b/drivers/video/savage/savagefb_driver.c | |||
@@ -86,15 +86,15 @@ MODULE_DESCRIPTION("FBDev driver for S3 Savage PCI/AGP Chips"); | |||
86 | 86 | ||
87 | /* --------------------------------------------------------------------- */ | 87 | /* --------------------------------------------------------------------- */ |
88 | 88 | ||
89 | static void vgaHWSeqReset (struct savagefb_par *par, int start) | 89 | static void vgaHWSeqReset(struct savagefb_par *par, int start) |
90 | { | 90 | { |
91 | if (start) | 91 | if (start) |
92 | VGAwSEQ (0x00, 0x01, par); /* Synchronous Reset */ | 92 | VGAwSEQ(0x00, 0x01, par); /* Synchronous Reset */ |
93 | else | 93 | else |
94 | VGAwSEQ (0x00, 0x03, par); /* End Reset */ | 94 | VGAwSEQ(0x00, 0x03, par); /* End Reset */ |
95 | } | 95 | } |
96 | 96 | ||
97 | static void vgaHWProtect (struct savagefb_par *par, int on) | 97 | static void vgaHWProtect(struct savagefb_par *par, int on) |
98 | { | 98 | { |
99 | unsigned char tmp; | 99 | unsigned char tmp; |
100 | 100 | ||
@@ -102,10 +102,10 @@ static void vgaHWProtect (struct savagefb_par *par, int on) | |||
102 | /* | 102 | /* |
103 | * Turn off screen and disable sequencer. | 103 | * Turn off screen and disable sequencer. |
104 | */ | 104 | */ |
105 | tmp = VGArSEQ (0x01, par); | 105 | tmp = VGArSEQ(0x01, par); |
106 | 106 | ||
107 | vgaHWSeqReset (par, 1); /* start synchronous reset */ | 107 | vgaHWSeqReset(par, 1); /* start synchronous reset */ |
108 | VGAwSEQ (0x01, tmp | 0x20, par);/* disable the display */ | 108 | VGAwSEQ(0x01, tmp | 0x20, par);/* disable the display */ |
109 | 109 | ||
110 | VGAenablePalette(par); | 110 | VGAenablePalette(par); |
111 | } else { | 111 | } else { |
@@ -113,75 +113,76 @@ static void vgaHWProtect (struct savagefb_par *par, int on) | |||
113 | * Reenable sequencer, then turn on screen. | 113 | * Reenable sequencer, then turn on screen. |
114 | */ | 114 | */ |
115 | 115 | ||
116 | tmp = VGArSEQ (0x01, par); | 116 | tmp = VGArSEQ(0x01, par); |
117 | 117 | ||
118 | VGAwSEQ (0x01, tmp & ~0x20, par);/* reenable display */ | 118 | VGAwSEQ(0x01, tmp & ~0x20, par);/* reenable display */ |
119 | vgaHWSeqReset (par, 0); /* clear synchronous reset */ | 119 | vgaHWSeqReset(par, 0); /* clear synchronous reset */ |
120 | 120 | ||
121 | VGAdisablePalette(par); | 121 | VGAdisablePalette(par); |
122 | } | 122 | } |
123 | } | 123 | } |
124 | 124 | ||
125 | static void vgaHWRestore (struct savagefb_par *par) | 125 | static void vgaHWRestore(struct savagefb_par *par, struct savage_reg *reg) |
126 | { | 126 | { |
127 | int i; | 127 | int i; |
128 | 128 | ||
129 | VGAwMISC (par->MiscOutReg, par); | 129 | VGAwMISC(reg->MiscOutReg, par); |
130 | 130 | ||
131 | for (i = 1; i < 5; i++) | 131 | for (i = 1; i < 5; i++) |
132 | VGAwSEQ (i, par->Sequencer[i], par); | 132 | VGAwSEQ(i, reg->Sequencer[i], par); |
133 | 133 | ||
134 | /* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 or | 134 | /* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 or |
135 | CRTC[17] */ | 135 | CRTC[17] */ |
136 | VGAwCR (17, par->CRTC[17] & ~0x80, par); | 136 | VGAwCR(17, reg->CRTC[17] & ~0x80, par); |
137 | 137 | ||
138 | for (i = 0; i < 25; i++) | 138 | for (i = 0; i < 25; i++) |
139 | VGAwCR (i, par->CRTC[i], par); | 139 | VGAwCR(i, reg->CRTC[i], par); |
140 | 140 | ||
141 | for (i = 0; i < 9; i++) | 141 | for (i = 0; i < 9; i++) |
142 | VGAwGR (i, par->Graphics[i], par); | 142 | VGAwGR(i, reg->Graphics[i], par); |
143 | 143 | ||
144 | VGAenablePalette(par); | 144 | VGAenablePalette(par); |
145 | 145 | ||
146 | for (i = 0; i < 21; i++) | 146 | for (i = 0; i < 21; i++) |
147 | VGAwATTR (i, par->Attribute[i], par); | 147 | VGAwATTR(i, reg->Attribute[i], par); |
148 | 148 | ||
149 | VGAdisablePalette(par); | 149 | VGAdisablePalette(par); |
150 | } | 150 | } |
151 | 151 | ||
152 | static void vgaHWInit (struct fb_var_screeninfo *var, | 152 | static void vgaHWInit(struct fb_var_screeninfo *var, |
153 | struct savagefb_par *par, | 153 | struct savagefb_par *par, |
154 | struct xtimings *timings) | 154 | struct xtimings *timings, |
155 | struct savage_reg *reg) | ||
155 | { | 156 | { |
156 | par->MiscOutReg = 0x23; | 157 | reg->MiscOutReg = 0x23; |
157 | 158 | ||
158 | if (!(timings->sync & FB_SYNC_HOR_HIGH_ACT)) | 159 | if (!(timings->sync & FB_SYNC_HOR_HIGH_ACT)) |
159 | par->MiscOutReg |= 0x40; | 160 | reg->MiscOutReg |= 0x40; |
160 | 161 | ||
161 | if (!(timings->sync & FB_SYNC_VERT_HIGH_ACT)) | 162 | if (!(timings->sync & FB_SYNC_VERT_HIGH_ACT)) |
162 | par->MiscOutReg |= 0x80; | 163 | reg->MiscOutReg |= 0x80; |
163 | 164 | ||
164 | /* | 165 | /* |
165 | * Time Sequencer | 166 | * Time Sequencer |
166 | */ | 167 | */ |
167 | par->Sequencer[0x00] = 0x00; | 168 | reg->Sequencer[0x00] = 0x00; |
168 | par->Sequencer[0x01] = 0x01; | 169 | reg->Sequencer[0x01] = 0x01; |
169 | par->Sequencer[0x02] = 0x0F; | 170 | reg->Sequencer[0x02] = 0x0F; |
170 | par->Sequencer[0x03] = 0x00; /* Font select */ | 171 | reg->Sequencer[0x03] = 0x00; /* Font select */ |
171 | par->Sequencer[0x04] = 0x0E; /* Misc */ | 172 | reg->Sequencer[0x04] = 0x0E; /* Misc */ |
172 | 173 | ||
173 | /* | 174 | /* |
174 | * CRTC Controller | 175 | * CRTC Controller |
175 | */ | 176 | */ |
176 | par->CRTC[0x00] = (timings->HTotal >> 3) - 5; | 177 | reg->CRTC[0x00] = (timings->HTotal >> 3) - 5; |
177 | par->CRTC[0x01] = (timings->HDisplay >> 3) - 1; | 178 | reg->CRTC[0x01] = (timings->HDisplay >> 3) - 1; |
178 | par->CRTC[0x02] = (timings->HSyncStart >> 3) - 1; | 179 | reg->CRTC[0x02] = (timings->HSyncStart >> 3) - 1; |
179 | par->CRTC[0x03] = (((timings->HSyncEnd >> 3) - 1) & 0x1f) | 0x80; | 180 | reg->CRTC[0x03] = (((timings->HSyncEnd >> 3) - 1) & 0x1f) | 0x80; |
180 | par->CRTC[0x04] = (timings->HSyncStart >> 3); | 181 | reg->CRTC[0x04] = (timings->HSyncStart >> 3); |
181 | par->CRTC[0x05] = ((((timings->HSyncEnd >> 3) - 1) & 0x20) << 2) | | 182 | reg->CRTC[0x05] = ((((timings->HSyncEnd >> 3) - 1) & 0x20) << 2) | |
182 | (((timings->HSyncEnd >> 3)) & 0x1f); | 183 | (((timings->HSyncEnd >> 3)) & 0x1f); |
183 | par->CRTC[0x06] = (timings->VTotal - 2) & 0xFF; | 184 | reg->CRTC[0x06] = (timings->VTotal - 2) & 0xFF; |
184 | par->CRTC[0x07] = (((timings->VTotal - 2) & 0x100) >> 8) | | 185 | reg->CRTC[0x07] = (((timings->VTotal - 2) & 0x100) >> 8) | |
185 | (((timings->VDisplay - 1) & 0x100) >> 7) | | 186 | (((timings->VDisplay - 1) & 0x100) >> 7) | |
186 | ((timings->VSyncStart & 0x100) >> 6) | | 187 | ((timings->VSyncStart & 0x100) >> 6) | |
187 | (((timings->VSyncStart - 1) & 0x100) >> 5) | | 188 | (((timings->VSyncStart - 1) & 0x100) >> 5) | |
@@ -189,27 +190,27 @@ static void vgaHWInit (struct fb_var_screeninfo *var, | |||
189 | (((timings->VTotal - 2) & 0x200) >> 4) | | 190 | (((timings->VTotal - 2) & 0x200) >> 4) | |
190 | (((timings->VDisplay - 1) & 0x200) >> 3) | | 191 | (((timings->VDisplay - 1) & 0x200) >> 3) | |
191 | ((timings->VSyncStart & 0x200) >> 2); | 192 | ((timings->VSyncStart & 0x200) >> 2); |
192 | par->CRTC[0x08] = 0x00; | 193 | reg->CRTC[0x08] = 0x00; |
193 | par->CRTC[0x09] = (((timings->VSyncStart - 1) & 0x200) >> 4) | 0x40; | 194 | reg->CRTC[0x09] = (((timings->VSyncStart - 1) & 0x200) >> 4) | 0x40; |
194 | 195 | ||
195 | if (timings->dblscan) | 196 | if (timings->dblscan) |
196 | par->CRTC[0x09] |= 0x80; | 197 | reg->CRTC[0x09] |= 0x80; |
197 | 198 | ||
198 | par->CRTC[0x0a] = 0x00; | 199 | reg->CRTC[0x0a] = 0x00; |
199 | par->CRTC[0x0b] = 0x00; | 200 | reg->CRTC[0x0b] = 0x00; |
200 | par->CRTC[0x0c] = 0x00; | 201 | reg->CRTC[0x0c] = 0x00; |
201 | par->CRTC[0x0d] = 0x00; | 202 | reg->CRTC[0x0d] = 0x00; |
202 | par->CRTC[0x0e] = 0x00; | 203 | reg->CRTC[0x0e] = 0x00; |
203 | par->CRTC[0x0f] = 0x00; | 204 | reg->CRTC[0x0f] = 0x00; |
204 | par->CRTC[0x10] = timings->VSyncStart & 0xff; | 205 | reg->CRTC[0x10] = timings->VSyncStart & 0xff; |
205 | par->CRTC[0x11] = (timings->VSyncEnd & 0x0f) | 0x20; | 206 | reg->CRTC[0x11] = (timings->VSyncEnd & 0x0f) | 0x20; |
206 | par->CRTC[0x12] = (timings->VDisplay - 1) & 0xff; | 207 | reg->CRTC[0x12] = (timings->VDisplay - 1) & 0xff; |
207 | par->CRTC[0x13] = var->xres_virtual >> 4; | 208 | reg->CRTC[0x13] = var->xres_virtual >> 4; |
208 | par->CRTC[0x14] = 0x00; | 209 | reg->CRTC[0x14] = 0x00; |
209 | par->CRTC[0x15] = (timings->VSyncStart - 1) & 0xff; | 210 | reg->CRTC[0x15] = (timings->VSyncStart - 1) & 0xff; |
210 | par->CRTC[0x16] = (timings->VSyncEnd - 1) & 0xff; | 211 | reg->CRTC[0x16] = (timings->VSyncEnd - 1) & 0xff; |
211 | par->CRTC[0x17] = 0xc3; | 212 | reg->CRTC[0x17] = 0xc3; |
212 | par->CRTC[0x18] = 0xff; | 213 | reg->CRTC[0x18] = 0xff; |
213 | 214 | ||
214 | /* | 215 | /* |
215 | * are these unnecessary? | 216 | * are these unnecessary? |
@@ -220,38 +221,38 @@ static void vgaHWInit (struct fb_var_screeninfo *var, | |||
220 | /* | 221 | /* |
221 | * Graphics Display Controller | 222 | * Graphics Display Controller |
222 | */ | 223 | */ |
223 | par->Graphics[0x00] = 0x00; | 224 | reg->Graphics[0x00] = 0x00; |
224 | par->Graphics[0x01] = 0x00; | 225 | reg->Graphics[0x01] = 0x00; |
225 | par->Graphics[0x02] = 0x00; | 226 | reg->Graphics[0x02] = 0x00; |
226 | par->Graphics[0x03] = 0x00; | 227 | reg->Graphics[0x03] = 0x00; |
227 | par->Graphics[0x04] = 0x00; | 228 | reg->Graphics[0x04] = 0x00; |
228 | par->Graphics[0x05] = 0x40; | 229 | reg->Graphics[0x05] = 0x40; |
229 | par->Graphics[0x06] = 0x05; /* only map 64k VGA memory !!!! */ | 230 | reg->Graphics[0x06] = 0x05; /* only map 64k VGA memory !!!! */ |
230 | par->Graphics[0x07] = 0x0F; | 231 | reg->Graphics[0x07] = 0x0F; |
231 | par->Graphics[0x08] = 0xFF; | 232 | reg->Graphics[0x08] = 0xFF; |
232 | 233 | ||
233 | 234 | ||
234 | par->Attribute[0x00] = 0x00; /* standard colormap translation */ | 235 | reg->Attribute[0x00] = 0x00; /* standard colormap translation */ |
235 | par->Attribute[0x01] = 0x01; | 236 | reg->Attribute[0x01] = 0x01; |
236 | par->Attribute[0x02] = 0x02; | 237 | reg->Attribute[0x02] = 0x02; |
237 | par->Attribute[0x03] = 0x03; | 238 | reg->Attribute[0x03] = 0x03; |
238 | par->Attribute[0x04] = 0x04; | 239 | reg->Attribute[0x04] = 0x04; |
239 | par->Attribute[0x05] = 0x05; | 240 | reg->Attribute[0x05] = 0x05; |
240 | par->Attribute[0x06] = 0x06; | 241 | reg->Attribute[0x06] = 0x06; |
241 | par->Attribute[0x07] = 0x07; | 242 | reg->Attribute[0x07] = 0x07; |
242 | par->Attribute[0x08] = 0x08; | 243 | reg->Attribute[0x08] = 0x08; |
243 | par->Attribute[0x09] = 0x09; | 244 | reg->Attribute[0x09] = 0x09; |
244 | par->Attribute[0x0a] = 0x0A; | 245 | reg->Attribute[0x0a] = 0x0A; |
245 | par->Attribute[0x0b] = 0x0B; | 246 | reg->Attribute[0x0b] = 0x0B; |
246 | par->Attribute[0x0c] = 0x0C; | 247 | reg->Attribute[0x0c] = 0x0C; |
247 | par->Attribute[0x0d] = 0x0D; | 248 | reg->Attribute[0x0d] = 0x0D; |
248 | par->Attribute[0x0e] = 0x0E; | 249 | reg->Attribute[0x0e] = 0x0E; |
249 | par->Attribute[0x0f] = 0x0F; | 250 | reg->Attribute[0x0f] = 0x0F; |
250 | par->Attribute[0x10] = 0x41; | 251 | reg->Attribute[0x10] = 0x41; |
251 | par->Attribute[0x11] = 0xFF; | 252 | reg->Attribute[0x11] = 0xFF; |
252 | par->Attribute[0x12] = 0x0F; | 253 | reg->Attribute[0x12] = 0x0F; |
253 | par->Attribute[0x13] = 0x00; | 254 | reg->Attribute[0x13] = 0x00; |
254 | par->Attribute[0x14] = 0x00; | 255 | reg->Attribute[0x14] = 0x00; |
255 | } | 256 | } |
256 | 257 | ||
257 | /* -------------------- Hardware specific routines ------------------------- */ | 258 | /* -------------------- Hardware specific routines ------------------------- */ |
@@ -304,15 +305,15 @@ savage2000_waitidle(struct savagefb_par *par) | |||
304 | while ((savage_in32(0x48C60, par) & 0x009fffff)); | 305 | while ((savage_in32(0x48C60, par) & 0x009fffff)); |
305 | } | 306 | } |
306 | 307 | ||
307 | 308 | #ifdef CONFIG_FB_SAVAGE_ACCEL | |
308 | static void | 309 | static void |
309 | SavageSetup2DEngine (struct savagefb_par *par) | 310 | SavageSetup2DEngine(struct savagefb_par *par) |
310 | { | 311 | { |
311 | unsigned long GlobalBitmapDescriptor; | 312 | unsigned long GlobalBitmapDescriptor; |
312 | 313 | ||
313 | GlobalBitmapDescriptor = 1 | 8 | BCI_BD_BW_DISABLE; | 314 | GlobalBitmapDescriptor = 1 | 8 | BCI_BD_BW_DISABLE; |
314 | BCI_BD_SET_BPP (GlobalBitmapDescriptor, par->depth); | 315 | BCI_BD_SET_BPP(GlobalBitmapDescriptor, par->depth); |
315 | BCI_BD_SET_STRIDE (GlobalBitmapDescriptor, par->vwidth); | 316 | BCI_BD_SET_STRIDE(GlobalBitmapDescriptor, par->vwidth); |
316 | 317 | ||
317 | switch(par->chip) { | 318 | switch(par->chip) { |
318 | case S3_SAVAGE3D: | 319 | case S3_SAVAGE3D: |
@@ -361,32 +362,48 @@ SavageSetup2DEngine (struct savagefb_par *par) | |||
361 | vga_out8(0x3d5, 0x0c, par); | 362 | vga_out8(0x3d5, 0x0c, par); |
362 | 363 | ||
363 | /* Set stride to use GBD. */ | 364 | /* Set stride to use GBD. */ |
364 | vga_out8 (0x3d4, 0x50, par); | 365 | vga_out8(0x3d4, 0x50, par); |
365 | vga_out8 (0x3d5, vga_in8(0x3d5, par) | 0xC1, par); | 366 | vga_out8(0x3d5, vga_in8(0x3d5, par) | 0xC1, par); |
366 | 367 | ||
367 | /* Enable 2D engine. */ | 368 | /* Enable 2D engine. */ |
368 | vga_out8 (0x3d4, 0x40, par); | 369 | vga_out8(0x3d4, 0x40, par); |
369 | vga_out8 (0x3d5, 0x01, par); | 370 | vga_out8(0x3d5, 0x01, par); |
370 | 371 | ||
371 | savage_out32 (MONO_PAT_0, ~0, par); | 372 | savage_out32(MONO_PAT_0, ~0, par); |
372 | savage_out32 (MONO_PAT_1, ~0, par); | 373 | savage_out32(MONO_PAT_1, ~0, par); |
373 | 374 | ||
374 | /* Setup plane masks */ | 375 | /* Setup plane masks */ |
375 | savage_out32 (0x8128, ~0, par); /* enable all write planes */ | 376 | savage_out32(0x8128, ~0, par); /* enable all write planes */ |
376 | savage_out32 (0x812C, ~0, par); /* enable all read planes */ | 377 | savage_out32(0x812C, ~0, par); /* enable all read planes */ |
377 | savage_out16 (0x8134, 0x27, par); | 378 | savage_out16(0x8134, 0x27, par); |
378 | savage_out16 (0x8136, 0x07, par); | 379 | savage_out16(0x8136, 0x07, par); |
379 | 380 | ||
380 | /* Now set the GBD */ | 381 | /* Now set the GBD */ |
381 | par->bci_ptr = 0; | 382 | par->bci_ptr = 0; |
382 | par->SavageWaitFifo (par, 4); | 383 | par->SavageWaitFifo(par, 4); |
383 | 384 | ||
384 | BCI_SEND( BCI_CMD_SETREG | (1 << 16) | BCI_GBD1 ); | 385 | BCI_SEND(BCI_CMD_SETREG | (1 << 16) | BCI_GBD1); |
385 | BCI_SEND( 0 ); | 386 | BCI_SEND(0); |
386 | BCI_SEND( BCI_CMD_SETREG | (1 << 16) | BCI_GBD2 ); | 387 | BCI_SEND(BCI_CMD_SETREG | (1 << 16) | BCI_GBD2); |
387 | BCI_SEND( GlobalBitmapDescriptor ); | 388 | BCI_SEND(GlobalBitmapDescriptor); |
388 | } | 389 | } |
389 | 390 | ||
391 | static void savagefb_set_clip(struct fb_info *info) | ||
392 | { | ||
393 | struct savagefb_par *par = info->par; | ||
394 | int cmd; | ||
395 | |||
396 | cmd = BCI_CMD_NOP | BCI_CMD_CLIP_NEW; | ||
397 | par->bci_ptr = 0; | ||
398 | par->SavageWaitFifo(par,3); | ||
399 | BCI_SEND(cmd); | ||
400 | BCI_SEND(BCI_CLIP_TL(0, 0)); | ||
401 | BCI_SEND(BCI_CLIP_BR(0xfff, 0xfff)); | ||
402 | } | ||
403 | #else | ||
404 | static void SavageSetup2DEngine(struct savagefb_par *par) {} | ||
405 | |||
406 | #endif | ||
390 | 407 | ||
391 | static void SavageCalcClock(long freq, int min_m, int min_n1, int max_n1, | 408 | static void SavageCalcClock(long freq, int min_m, int min_n1, int max_n1, |
392 | int min_n2, int max_n2, long freq_min, | 409 | int min_n2, int max_n2, long freq_min, |
@@ -398,11 +415,11 @@ static void SavageCalcClock(long freq, int min_m, int min_n1, int max_n1, | |||
398 | unsigned char n1, n2, best_n1=16+2, best_n2=2, best_m=125+2; | 415 | unsigned char n1, n2, best_n1=16+2, best_n2=2, best_m=125+2; |
399 | 416 | ||
400 | if (freq < freq_min / (1 << max_n2)) { | 417 | if (freq < freq_min / (1 << max_n2)) { |
401 | printk (KERN_ERR "invalid frequency %ld Khz\n", freq); | 418 | printk(KERN_ERR "invalid frequency %ld Khz\n", freq); |
402 | freq = freq_min / (1 << max_n2); | 419 | freq = freq_min / (1 << max_n2); |
403 | } | 420 | } |
404 | if (freq > freq_max / (1 << min_n2)) { | 421 | if (freq > freq_max / (1 << min_n2)) { |
405 | printk (KERN_ERR "invalid frequency %ld Khz\n", freq); | 422 | printk(KERN_ERR "invalid frequency %ld Khz\n", freq); |
406 | freq = freq_max / (1 << min_n2); | 423 | freq = freq_max / (1 << min_n2); |
407 | } | 424 | } |
408 | 425 | ||
@@ -453,12 +470,12 @@ static int common_calc_clock(long freq, int min_m, int min_n1, int max_n1, | |||
453 | BASE_FREQ; | 470 | BASE_FREQ; |
454 | if (m < min_m + 2 || m > 127+2) | 471 | if (m < min_m + 2 || m > 127+2) |
455 | continue; | 472 | continue; |
456 | if((m * BASE_FREQ >= freq_min * n1) && | 473 | if ((m * BASE_FREQ >= freq_min * n1) && |
457 | (m * BASE_FREQ <= freq_max * n1)) { | 474 | (m * BASE_FREQ <= freq_max * n1)) { |
458 | diff = freq * (1 << n2) * n1 - BASE_FREQ * m; | 475 | diff = freq * (1 << n2) * n1 - BASE_FREQ * m; |
459 | if(diff < 0) | 476 | if (diff < 0) |
460 | diff = -diff; | 477 | diff = -diff; |
461 | if(diff < best_diff) { | 478 | if (diff < best_diff) { |
462 | best_diff = diff; | 479 | best_diff = diff; |
463 | best_m = m; | 480 | best_m = m; |
464 | best_n1 = n1; | 481 | best_n1 = n1; |
@@ -468,7 +485,7 @@ static int common_calc_clock(long freq, int min_m, int min_n1, int max_n1, | |||
468 | } | 485 | } |
469 | } | 486 | } |
470 | 487 | ||
471 | if(max_n1 == 63) | 488 | if (max_n1 == 63) |
472 | *ndiv = (best_n1 - 2) | (best_n2 << 6); | 489 | *ndiv = (best_n1 - 2) | (best_n2 << 6); |
473 | else | 490 | else |
474 | *ndiv = (best_n1 - 2) | (best_n2 << 5); | 491 | *ndiv = (best_n1 - 2) | (best_n2 << 5); |
@@ -488,23 +505,23 @@ static void SavagePrintRegs(void) | |||
488 | int vgaCRReg = 0x3d5; | 505 | int vgaCRReg = 0x3d5; |
489 | 506 | ||
490 | printk(KERN_DEBUG "SR x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE " | 507 | printk(KERN_DEBUG "SR x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE " |
491 | "xF" ); | 508 | "xF"); |
492 | 509 | ||
493 | for( i = 0; i < 0x70; i++ ) { | 510 | for (i = 0; i < 0x70; i++) { |
494 | if( !(i % 16) ) | 511 | if (!(i % 16)) |
495 | printk(KERN_DEBUG "\nSR%xx ", i >> 4 ); | 512 | printk(KERN_DEBUG "\nSR%xx ", i >> 4); |
496 | vga_out8( 0x3c4, i, par); | 513 | vga_out8(0x3c4, i, par); |
497 | printk(KERN_DEBUG " %02x", vga_in8(0x3c5, par) ); | 514 | printk(KERN_DEBUG " %02x", vga_in8(0x3c5, par)); |
498 | } | 515 | } |
499 | 516 | ||
500 | printk(KERN_DEBUG "\n\nCR x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC " | 517 | printk(KERN_DEBUG "\n\nCR x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC " |
501 | "xD xE xF" ); | 518 | "xD xE xF"); |
502 | 519 | ||
503 | for( i = 0; i < 0xB7; i++ ) { | 520 | for (i = 0; i < 0xB7; i++) { |
504 | if( !(i % 16) ) | 521 | if (!(i % 16)) |
505 | printk(KERN_DEBUG "\nCR%xx ", i >> 4 ); | 522 | printk(KERN_DEBUG "\nCR%xx ", i >> 4); |
506 | vga_out8( vgaCRIndex, i, par); | 523 | vga_out8(vgaCRIndex, i, par); |
507 | printk(KERN_DEBUG " %02x", vga_in8(vgaCRReg, par) ); | 524 | printk(KERN_DEBUG " %02x", vga_in8(vgaCRReg, par)); |
508 | } | 525 | } |
509 | 526 | ||
510 | printk(KERN_DEBUG "\n\n"); | 527 | printk(KERN_DEBUG "\n\n"); |
@@ -513,156 +530,309 @@ static void SavagePrintRegs(void) | |||
513 | 530 | ||
514 | /* --------------------------------------------------------------------- */ | 531 | /* --------------------------------------------------------------------- */ |
515 | 532 | ||
516 | static void savage_get_default_par(struct savagefb_par *par) | 533 | static void savage_get_default_par(struct savagefb_par *par, struct savage_reg *reg) |
517 | { | 534 | { |
518 | unsigned char cr3a, cr53, cr66; | 535 | unsigned char cr3a, cr53, cr66; |
519 | 536 | ||
520 | vga_out16 (0x3d4, 0x4838, par); | 537 | vga_out16(0x3d4, 0x4838, par); |
521 | vga_out16 (0x3d4, 0xa039, par); | 538 | vga_out16(0x3d4, 0xa039, par); |
522 | vga_out16 (0x3c4, 0x0608, par); | 539 | vga_out16(0x3c4, 0x0608, par); |
523 | 540 | ||
524 | vga_out8 (0x3d4, 0x66, par); | 541 | vga_out8(0x3d4, 0x66, par); |
525 | cr66 = vga_in8 (0x3d5, par); | 542 | cr66 = vga_in8(0x3d5, par); |
526 | vga_out8 (0x3d5, cr66 | 0x80, par); | 543 | vga_out8(0x3d5, cr66 | 0x80, par); |
527 | vga_out8 (0x3d4, 0x3a, par); | 544 | vga_out8(0x3d4, 0x3a, par); |
528 | cr3a = vga_in8 (0x3d5, par); | 545 | cr3a = vga_in8(0x3d5, par); |
529 | vga_out8 (0x3d5, cr3a | 0x80, par); | 546 | vga_out8(0x3d5, cr3a | 0x80, par); |
530 | vga_out8 (0x3d4, 0x53, par); | 547 | vga_out8(0x3d4, 0x53, par); |
531 | cr53 = vga_in8 (0x3d5, par); | 548 | cr53 = vga_in8(0x3d5, par); |
532 | vga_out8 (0x3d5, cr53 & 0x7f, par); | 549 | vga_out8(0x3d5, cr53 & 0x7f, par); |
533 | 550 | ||
534 | vga_out8 (0x3d4, 0x66, par); | 551 | vga_out8(0x3d4, 0x66, par); |
535 | vga_out8 (0x3d5, cr66, par); | 552 | vga_out8(0x3d5, cr66, par); |
536 | vga_out8 (0x3d4, 0x3a, par); | 553 | vga_out8(0x3d4, 0x3a, par); |
537 | vga_out8 (0x3d5, cr3a, par); | 554 | vga_out8(0x3d5, cr3a, par); |
538 | 555 | ||
539 | vga_out8 (0x3d4, 0x66, par); | 556 | vga_out8(0x3d4, 0x66, par); |
540 | vga_out8 (0x3d5, cr66, par); | 557 | vga_out8(0x3d5, cr66, par); |
541 | vga_out8 (0x3d4, 0x3a, par); | 558 | vga_out8(0x3d4, 0x3a, par); |
542 | vga_out8 (0x3d5, cr3a, par); | 559 | vga_out8(0x3d5, cr3a, par); |
543 | 560 | ||
544 | /* unlock extended seq regs */ | 561 | /* unlock extended seq regs */ |
545 | vga_out8 (0x3c4, 0x08, par); | 562 | vga_out8(0x3c4, 0x08, par); |
546 | par->SR08 = vga_in8 (0x3c5, par); | 563 | reg->SR08 = vga_in8(0x3c5, par); |
547 | vga_out8 (0x3c5, 0x06, par); | 564 | vga_out8(0x3c5, 0x06, par); |
548 | 565 | ||
549 | /* now save all the extended regs we need */ | 566 | /* now save all the extended regs we need */ |
550 | vga_out8 (0x3d4, 0x31, par); | 567 | vga_out8(0x3d4, 0x31, par); |
551 | par->CR31 = vga_in8 (0x3d5, par); | 568 | reg->CR31 = vga_in8(0x3d5, par); |
552 | vga_out8 (0x3d4, 0x32, par); | 569 | vga_out8(0x3d4, 0x32, par); |
553 | par->CR32 = vga_in8 (0x3d5, par); | 570 | reg->CR32 = vga_in8(0x3d5, par); |
554 | vga_out8 (0x3d4, 0x34, par); | 571 | vga_out8(0x3d4, 0x34, par); |
555 | par->CR34 = vga_in8 (0x3d5, par); | 572 | reg->CR34 = vga_in8(0x3d5, par); |
556 | vga_out8 (0x3d4, 0x36, par); | 573 | vga_out8(0x3d4, 0x36, par); |
557 | par->CR36 = vga_in8 (0x3d5, par); | 574 | reg->CR36 = vga_in8(0x3d5, par); |
558 | vga_out8 (0x3d4, 0x3a, par); | 575 | vga_out8(0x3d4, 0x3a, par); |
559 | par->CR3A = vga_in8 (0x3d5, par); | 576 | reg->CR3A = vga_in8(0x3d5, par); |
560 | vga_out8 (0x3d4, 0x40, par); | 577 | vga_out8(0x3d4, 0x40, par); |
561 | par->CR40 = vga_in8 (0x3d5, par); | 578 | reg->CR40 = vga_in8(0x3d5, par); |
562 | vga_out8 (0x3d4, 0x42, par); | 579 | vga_out8(0x3d4, 0x42, par); |
563 | par->CR42 = vga_in8 (0x3d5, par); | 580 | reg->CR42 = vga_in8(0x3d5, par); |
564 | vga_out8 (0x3d4, 0x45, par); | 581 | vga_out8(0x3d4, 0x45, par); |
565 | par->CR45 = vga_in8 (0x3d5, par); | 582 | reg->CR45 = vga_in8(0x3d5, par); |
566 | vga_out8 (0x3d4, 0x50, par); | 583 | vga_out8(0x3d4, 0x50, par); |
567 | par->CR50 = vga_in8 (0x3d5, par); | 584 | reg->CR50 = vga_in8(0x3d5, par); |
568 | vga_out8 (0x3d4, 0x51, par); | 585 | vga_out8(0x3d4, 0x51, par); |
569 | par->CR51 = vga_in8 (0x3d5, par); | 586 | reg->CR51 = vga_in8(0x3d5, par); |
570 | vga_out8 (0x3d4, 0x53, par); | 587 | vga_out8(0x3d4, 0x53, par); |
571 | par->CR53 = vga_in8 (0x3d5, par); | 588 | reg->CR53 = vga_in8(0x3d5, par); |
572 | vga_out8 (0x3d4, 0x58, par); | 589 | vga_out8(0x3d4, 0x58, par); |
573 | par->CR58 = vga_in8 (0x3d5, par); | 590 | reg->CR58 = vga_in8(0x3d5, par); |
574 | vga_out8 (0x3d4, 0x60, par); | 591 | vga_out8(0x3d4, 0x60, par); |
575 | par->CR60 = vga_in8 (0x3d5, par); | 592 | reg->CR60 = vga_in8(0x3d5, par); |
576 | vga_out8 (0x3d4, 0x66, par); | 593 | vga_out8(0x3d4, 0x66, par); |
577 | par->CR66 = vga_in8 (0x3d5, par); | 594 | reg->CR66 = vga_in8(0x3d5, par); |
578 | vga_out8 (0x3d4, 0x67, par); | 595 | vga_out8(0x3d4, 0x67, par); |
579 | par->CR67 = vga_in8 (0x3d5, par); | 596 | reg->CR67 = vga_in8(0x3d5, par); |
580 | vga_out8 (0x3d4, 0x68, par); | 597 | vga_out8(0x3d4, 0x68, par); |
581 | par->CR68 = vga_in8 (0x3d5, par); | 598 | reg->CR68 = vga_in8(0x3d5, par); |
582 | vga_out8 (0x3d4, 0x69, par); | 599 | vga_out8(0x3d4, 0x69, par); |
583 | par->CR69 = vga_in8 (0x3d5, par); | 600 | reg->CR69 = vga_in8(0x3d5, par); |
584 | vga_out8 (0x3d4, 0x6f, par); | 601 | vga_out8(0x3d4, 0x6f, par); |
585 | par->CR6F = vga_in8 (0x3d5, par); | 602 | reg->CR6F = vga_in8(0x3d5, par); |
586 | 603 | ||
587 | vga_out8 (0x3d4, 0x33, par); | 604 | vga_out8(0x3d4, 0x33, par); |
588 | par->CR33 = vga_in8 (0x3d5, par); | 605 | reg->CR33 = vga_in8(0x3d5, par); |
589 | vga_out8 (0x3d4, 0x86, par); | 606 | vga_out8(0x3d4, 0x86, par); |
590 | par->CR86 = vga_in8 (0x3d5, par); | 607 | reg->CR86 = vga_in8(0x3d5, par); |
591 | vga_out8 (0x3d4, 0x88, par); | 608 | vga_out8(0x3d4, 0x88, par); |
592 | par->CR88 = vga_in8 (0x3d5, par); | 609 | reg->CR88 = vga_in8(0x3d5, par); |
593 | vga_out8 (0x3d4, 0x90, par); | 610 | vga_out8(0x3d4, 0x90, par); |
594 | par->CR90 = vga_in8 (0x3d5, par); | 611 | reg->CR90 = vga_in8(0x3d5, par); |
595 | vga_out8 (0x3d4, 0x91, par); | 612 | vga_out8(0x3d4, 0x91, par); |
596 | par->CR91 = vga_in8 (0x3d5, par); | 613 | reg->CR91 = vga_in8(0x3d5, par); |
597 | vga_out8 (0x3d4, 0xb0, par); | 614 | vga_out8(0x3d4, 0xb0, par); |
598 | par->CRB0 = vga_in8 (0x3d5, par) | 0x80; | 615 | reg->CRB0 = vga_in8(0x3d5, par) | 0x80; |
616 | |||
617 | /* extended mode timing regs */ | ||
618 | vga_out8(0x3d4, 0x3b, par); | ||
619 | reg->CR3B = vga_in8(0x3d5, par); | ||
620 | vga_out8(0x3d4, 0x3c, par); | ||
621 | reg->CR3C = vga_in8(0x3d5, par); | ||
622 | vga_out8(0x3d4, 0x43, par); | ||
623 | reg->CR43 = vga_in8(0x3d5, par); | ||
624 | vga_out8(0x3d4, 0x5d, par); | ||
625 | reg->CR5D = vga_in8(0x3d5, par); | ||
626 | vga_out8(0x3d4, 0x5e, par); | ||
627 | reg->CR5E = vga_in8(0x3d5, par); | ||
628 | vga_out8(0x3d4, 0x65, par); | ||
629 | reg->CR65 = vga_in8(0x3d5, par); | ||
630 | |||
631 | /* save seq extended regs for DCLK PLL programming */ | ||
632 | vga_out8(0x3c4, 0x0e, par); | ||
633 | reg->SR0E = vga_in8(0x3c5, par); | ||
634 | vga_out8(0x3c4, 0x0f, par); | ||
635 | reg->SR0F = vga_in8(0x3c5, par); | ||
636 | vga_out8(0x3c4, 0x10, par); | ||
637 | reg->SR10 = vga_in8(0x3c5, par); | ||
638 | vga_out8(0x3c4, 0x11, par); | ||
639 | reg->SR11 = vga_in8(0x3c5, par); | ||
640 | vga_out8(0x3c4, 0x12, par); | ||
641 | reg->SR12 = vga_in8(0x3c5, par); | ||
642 | vga_out8(0x3c4, 0x13, par); | ||
643 | reg->SR13 = vga_in8(0x3c5, par); | ||
644 | vga_out8(0x3c4, 0x29, par); | ||
645 | reg->SR29 = vga_in8(0x3c5, par); | ||
646 | |||
647 | vga_out8(0x3c4, 0x15, par); | ||
648 | reg->SR15 = vga_in8(0x3c5, par); | ||
649 | vga_out8(0x3c4, 0x30, par); | ||
650 | reg->SR30 = vga_in8(0x3c5, par); | ||
651 | vga_out8(0x3c4, 0x18, par); | ||
652 | reg->SR18 = vga_in8(0x3c5, par); | ||
653 | |||
654 | /* Save flat panel expansion regsters. */ | ||
655 | if (par->chip == S3_SAVAGE_MX) { | ||
656 | int i; | ||
657 | |||
658 | for (i = 0; i < 8; i++) { | ||
659 | vga_out8(0x3c4, 0x54+i, par); | ||
660 | reg->SR54[i] = vga_in8(0x3c5, par); | ||
661 | } | ||
662 | } | ||
663 | |||
664 | vga_out8(0x3d4, 0x66, par); | ||
665 | cr66 = vga_in8(0x3d5, par); | ||
666 | vga_out8(0x3d5, cr66 | 0x80, par); | ||
667 | vga_out8(0x3d4, 0x3a, par); | ||
668 | cr3a = vga_in8(0x3d5, par); | ||
669 | vga_out8(0x3d5, cr3a | 0x80, par); | ||
670 | |||
671 | /* now save MIU regs */ | ||
672 | if (par->chip != S3_SAVAGE_MX) { | ||
673 | reg->MMPR0 = savage_in32(FIFO_CONTROL_REG, par); | ||
674 | reg->MMPR1 = savage_in32(MIU_CONTROL_REG, par); | ||
675 | reg->MMPR2 = savage_in32(STREAMS_TIMEOUT_REG, par); | ||
676 | reg->MMPR3 = savage_in32(MISC_TIMEOUT_REG, par); | ||
677 | } | ||
678 | |||
679 | vga_out8(0x3d4, 0x3a, par); | ||
680 | vga_out8(0x3d5, cr3a, par); | ||
681 | vga_out8(0x3d4, 0x66, par); | ||
682 | vga_out8(0x3d5, cr66, par); | ||
683 | } | ||
684 | |||
685 | static void savage_set_default_par(struct savagefb_par *par, | ||
686 | struct savage_reg *reg) | ||
687 | { | ||
688 | unsigned char cr3a, cr53, cr66; | ||
689 | |||
690 | vga_out16(0x3d4, 0x4838, par); | ||
691 | vga_out16(0x3d4, 0xa039, par); | ||
692 | vga_out16(0x3c4, 0x0608, par); | ||
693 | |||
694 | vga_out8(0x3d4, 0x66, par); | ||
695 | cr66 = vga_in8(0x3d5, par); | ||
696 | vga_out8(0x3d5, cr66 | 0x80, par); | ||
697 | vga_out8(0x3d4, 0x3a, par); | ||
698 | cr3a = vga_in8(0x3d5, par); | ||
699 | vga_out8(0x3d5, cr3a | 0x80, par); | ||
700 | vga_out8(0x3d4, 0x53, par); | ||
701 | cr53 = vga_in8(0x3d5, par); | ||
702 | vga_out8(0x3d5, cr53 & 0x7f, par); | ||
703 | |||
704 | vga_out8(0x3d4, 0x66, par); | ||
705 | vga_out8(0x3d5, cr66, par); | ||
706 | vga_out8(0x3d4, 0x3a, par); | ||
707 | vga_out8(0x3d5, cr3a, par); | ||
708 | |||
709 | vga_out8(0x3d4, 0x66, par); | ||
710 | vga_out8(0x3d5, cr66, par); | ||
711 | vga_out8(0x3d4, 0x3a, par); | ||
712 | vga_out8(0x3d5, cr3a, par); | ||
713 | |||
714 | /* unlock extended seq regs */ | ||
715 | vga_out8(0x3c4, 0x08, par); | ||
716 | vga_out8(0x3c5, reg->SR08, par); | ||
717 | vga_out8(0x3c5, 0x06, par); | ||
718 | |||
719 | /* now restore all the extended regs we need */ | ||
720 | vga_out8(0x3d4, 0x31, par); | ||
721 | vga_out8(0x3d5, reg->CR31, par); | ||
722 | vga_out8(0x3d4, 0x32, par); | ||
723 | vga_out8(0x3d5, reg->CR32, par); | ||
724 | vga_out8(0x3d4, 0x34, par); | ||
725 | vga_out8(0x3d5, reg->CR34, par); | ||
726 | vga_out8(0x3d4, 0x36, par); | ||
727 | vga_out8(0x3d5,reg->CR36, par); | ||
728 | vga_out8(0x3d4, 0x3a, par); | ||
729 | vga_out8(0x3d5, reg->CR3A, par); | ||
730 | vga_out8(0x3d4, 0x40, par); | ||
731 | vga_out8(0x3d5, reg->CR40, par); | ||
732 | vga_out8(0x3d4, 0x42, par); | ||
733 | vga_out8(0x3d5, reg->CR42, par); | ||
734 | vga_out8(0x3d4, 0x45, par); | ||
735 | vga_out8(0x3d5, reg->CR45, par); | ||
736 | vga_out8(0x3d4, 0x50, par); | ||
737 | vga_out8(0x3d5, reg->CR50, par); | ||
738 | vga_out8(0x3d4, 0x51, par); | ||
739 | vga_out8(0x3d5, reg->CR51, par); | ||
740 | vga_out8(0x3d4, 0x53, par); | ||
741 | vga_out8(0x3d5, reg->CR53, par); | ||
742 | vga_out8(0x3d4, 0x58, par); | ||
743 | vga_out8(0x3d5, reg->CR58, par); | ||
744 | vga_out8(0x3d4, 0x60, par); | ||
745 | vga_out8(0x3d5, reg->CR60, par); | ||
746 | vga_out8(0x3d4, 0x66, par); | ||
747 | vga_out8(0x3d5, reg->CR66, par); | ||
748 | vga_out8(0x3d4, 0x67, par); | ||
749 | vga_out8(0x3d5, reg->CR67, par); | ||
750 | vga_out8(0x3d4, 0x68, par); | ||
751 | vga_out8(0x3d5, reg->CR68, par); | ||
752 | vga_out8(0x3d4, 0x69, par); | ||
753 | vga_out8(0x3d5, reg->CR69, par); | ||
754 | vga_out8(0x3d4, 0x6f, par); | ||
755 | vga_out8(0x3d5, reg->CR6F, par); | ||
756 | |||
757 | vga_out8(0x3d4, 0x33, par); | ||
758 | vga_out8(0x3d5, reg->CR33, par); | ||
759 | vga_out8(0x3d4, 0x86, par); | ||
760 | vga_out8(0x3d5, reg->CR86, par); | ||
761 | vga_out8(0x3d4, 0x88, par); | ||
762 | vga_out8(0x3d5, reg->CR88, par); | ||
763 | vga_out8(0x3d4, 0x90, par); | ||
764 | vga_out8(0x3d5, reg->CR90, par); | ||
765 | vga_out8(0x3d4, 0x91, par); | ||
766 | vga_out8(0x3d5, reg->CR91, par); | ||
767 | vga_out8(0x3d4, 0xb0, par); | ||
768 | vga_out8(0x3d5, reg->CRB0, par); | ||
599 | 769 | ||
600 | /* extended mode timing regs */ | 770 | /* extended mode timing regs */ |
601 | vga_out8 (0x3d4, 0x3b, par); | 771 | vga_out8(0x3d4, 0x3b, par); |
602 | par->CR3B = vga_in8 (0x3d5, par); | 772 | vga_out8(0x3d5, reg->CR3B, par); |
603 | vga_out8 (0x3d4, 0x3c, par); | 773 | vga_out8(0x3d4, 0x3c, par); |
604 | par->CR3C = vga_in8 (0x3d5, par); | 774 | vga_out8(0x3d5, reg->CR3C, par); |
605 | vga_out8 (0x3d4, 0x43, par); | 775 | vga_out8(0x3d4, 0x43, par); |
606 | par->CR43 = vga_in8 (0x3d5, par); | 776 | vga_out8(0x3d5, reg->CR43, par); |
607 | vga_out8 (0x3d4, 0x5d, par); | 777 | vga_out8(0x3d4, 0x5d, par); |
608 | par->CR5D = vga_in8 (0x3d5, par); | 778 | vga_out8(0x3d5, reg->CR5D, par); |
609 | vga_out8 (0x3d4, 0x5e, par); | 779 | vga_out8(0x3d4, 0x5e, par); |
610 | par->CR5E = vga_in8 (0x3d5, par); | 780 | vga_out8(0x3d5, reg->CR5E, par); |
611 | vga_out8 (0x3d4, 0x65, par); | 781 | vga_out8(0x3d4, 0x65, par); |
612 | par->CR65 = vga_in8 (0x3d5, par); | 782 | vga_out8(0x3d5, reg->CR65, par); |
613 | 783 | ||
614 | /* save seq extended regs for DCLK PLL programming */ | 784 | /* save seq extended regs for DCLK PLL programming */ |
615 | vga_out8 (0x3c4, 0x0e, par); | 785 | vga_out8(0x3c4, 0x0e, par); |
616 | par->SR0E = vga_in8 (0x3c5, par); | 786 | vga_out8(0x3c5, reg->SR0E, par); |
617 | vga_out8 (0x3c4, 0x0f, par); | 787 | vga_out8(0x3c4, 0x0f, par); |
618 | par->SR0F = vga_in8 (0x3c5, par); | 788 | vga_out8(0x3c5, reg->SR0F, par); |
619 | vga_out8 (0x3c4, 0x10, par); | 789 | vga_out8(0x3c4, 0x10, par); |
620 | par->SR10 = vga_in8 (0x3c5, par); | 790 | vga_out8(0x3c5, reg->SR10, par); |
621 | vga_out8 (0x3c4, 0x11, par); | 791 | vga_out8(0x3c4, 0x11, par); |
622 | par->SR11 = vga_in8 (0x3c5, par); | 792 | vga_out8(0x3c5, reg->SR11, par); |
623 | vga_out8 (0x3c4, 0x12, par); | 793 | vga_out8(0x3c4, 0x12, par); |
624 | par->SR12 = vga_in8 (0x3c5, par); | 794 | vga_out8(0x3c5, reg->SR12, par); |
625 | vga_out8 (0x3c4, 0x13, par); | 795 | vga_out8(0x3c4, 0x13, par); |
626 | par->SR13 = vga_in8 (0x3c5, par); | 796 | vga_out8(0x3c5, reg->SR13, par); |
627 | vga_out8 (0x3c4, 0x29, par); | 797 | vga_out8(0x3c4, 0x29, par); |
628 | par->SR29 = vga_in8 (0x3c5, par); | 798 | vga_out8(0x3c5, reg->SR29, par); |
629 | 799 | ||
630 | vga_out8 (0x3c4, 0x15, par); | 800 | vga_out8(0x3c4, 0x15, par); |
631 | par->SR15 = vga_in8 (0x3c5, par); | 801 | vga_out8(0x3c5, reg->SR15, par); |
632 | vga_out8 (0x3c4, 0x30, par); | 802 | vga_out8(0x3c4, 0x30, par); |
633 | par->SR30 = vga_in8 (0x3c5, par); | 803 | vga_out8(0x3c5, reg->SR30, par); |
634 | vga_out8 (0x3c4, 0x18, par); | 804 | vga_out8(0x3c4, 0x18, par); |
635 | par->SR18 = vga_in8 (0x3c5, par); | 805 | vga_out8(0x3c5, reg->SR18, par); |
636 | 806 | ||
637 | /* Save flat panel expansion regsters. */ | 807 | /* Save flat panel expansion regsters. */ |
638 | if (par->chip == S3_SAVAGE_MX) { | 808 | if (par->chip == S3_SAVAGE_MX) { |
639 | int i; | 809 | int i; |
640 | 810 | ||
641 | for (i = 0; i < 8; i++) { | 811 | for (i = 0; i < 8; i++) { |
642 | vga_out8 (0x3c4, 0x54+i, par); | 812 | vga_out8(0x3c4, 0x54+i, par); |
643 | par->SR54[i] = vga_in8 (0x3c5, par); | 813 | vga_out8(0x3c5, reg->SR54[i], par); |
644 | } | 814 | } |
645 | } | 815 | } |
646 | 816 | ||
647 | vga_out8 (0x3d4, 0x66, par); | 817 | vga_out8(0x3d4, 0x66, par); |
648 | cr66 = vga_in8 (0x3d5, par); | 818 | cr66 = vga_in8(0x3d5, par); |
649 | vga_out8 (0x3d5, cr66 | 0x80, par); | 819 | vga_out8(0x3d5, cr66 | 0x80, par); |
650 | vga_out8 (0x3d4, 0x3a, par); | 820 | vga_out8(0x3d4, 0x3a, par); |
651 | cr3a = vga_in8 (0x3d5, par); | 821 | cr3a = vga_in8(0x3d5, par); |
652 | vga_out8 (0x3d5, cr3a | 0x80, par); | 822 | vga_out8(0x3d5, cr3a | 0x80, par); |
653 | 823 | ||
654 | /* now save MIU regs */ | 824 | /* now save MIU regs */ |
655 | if (par->chip != S3_SAVAGE_MX) { | 825 | if (par->chip != S3_SAVAGE_MX) { |
656 | par->MMPR0 = savage_in32(FIFO_CONTROL_REG, par); | 826 | savage_out32(FIFO_CONTROL_REG, reg->MMPR0, par); |
657 | par->MMPR1 = savage_in32(MIU_CONTROL_REG, par); | 827 | savage_out32(MIU_CONTROL_REG, reg->MMPR1, par); |
658 | par->MMPR2 = savage_in32(STREAMS_TIMEOUT_REG, par); | 828 | savage_out32(STREAMS_TIMEOUT_REG, reg->MMPR2, par); |
659 | par->MMPR3 = savage_in32(MISC_TIMEOUT_REG, par); | 829 | savage_out32(MISC_TIMEOUT_REG, reg->MMPR3, par); |
660 | } | 830 | } |
661 | 831 | ||
662 | vga_out8 (0x3d4, 0x3a, par); | 832 | vga_out8(0x3d4, 0x3a, par); |
663 | vga_out8 (0x3d5, cr3a, par); | 833 | vga_out8(0x3d5, cr3a, par); |
664 | vga_out8 (0x3d4, 0x66, par); | 834 | vga_out8(0x3d4, 0x66, par); |
665 | vga_out8 (0x3d5, cr66, par); | 835 | vga_out8(0x3d5, cr66, par); |
666 | } | 836 | } |
667 | 837 | ||
668 | static void savage_update_var(struct fb_var_screeninfo *var, struct fb_videomode *modedb) | 838 | static void savage_update_var(struct fb_var_screeninfo *var, struct fb_videomode *modedb) |
@@ -683,8 +853,8 @@ static void savage_update_var(struct fb_var_screeninfo *var, struct fb_videomode | |||
683 | var->vmode = modedb->vmode; | 853 | var->vmode = modedb->vmode; |
684 | } | 854 | } |
685 | 855 | ||
686 | static int savagefb_check_var (struct fb_var_screeninfo *var, | 856 | static int savagefb_check_var(struct fb_var_screeninfo *var, |
687 | struct fb_info *info) | 857 | struct fb_info *info) |
688 | { | 858 | { |
689 | struct savagefb_par *par = info->par; | 859 | struct savagefb_par *par = info->par; |
690 | int memlen, vramlen, mode_valid = 0; | 860 | int memlen, vramlen, mode_valid = 0; |
@@ -750,10 +920,10 @@ static int savagefb_check_var (struct fb_var_screeninfo *var, | |||
750 | if (par->SavagePanelWidth && | 920 | if (par->SavagePanelWidth && |
751 | (var->xres > par->SavagePanelWidth || | 921 | (var->xres > par->SavagePanelWidth || |
752 | var->yres > par->SavagePanelHeight)) { | 922 | var->yres > par->SavagePanelHeight)) { |
753 | printk (KERN_INFO "Mode (%dx%d) larger than the LCD panel " | 923 | printk(KERN_INFO "Mode (%dx%d) larger than the LCD panel " |
754 | "(%dx%d)\n", var->xres, var->yres, | 924 | "(%dx%d)\n", var->xres, var->yres, |
755 | par->SavagePanelWidth, | 925 | par->SavagePanelWidth, |
756 | par->SavagePanelHeight); | 926 | par->SavagePanelHeight); |
757 | return -1; | 927 | return -1; |
758 | } | 928 | } |
759 | 929 | ||
@@ -788,8 +958,9 @@ static int savagefb_check_var (struct fb_var_screeninfo *var, | |||
788 | } | 958 | } |
789 | 959 | ||
790 | 960 | ||
791 | static int savagefb_decode_var (struct fb_var_screeninfo *var, | 961 | static int savagefb_decode_var(struct fb_var_screeninfo *var, |
792 | struct savagefb_par *par) | 962 | struct savagefb_par *par, |
963 | struct savage_reg *reg) | ||
793 | { | 964 | { |
794 | struct xtimings timings; | 965 | struct xtimings timings; |
795 | int width, dclk, i, j; /*, refresh; */ | 966 | int width, dclk, i, j; /*, refresh; */ |
@@ -799,7 +970,7 @@ static int savagefb_decode_var (struct fb_var_screeninfo *var, | |||
799 | 970 | ||
800 | DBG("savagefb_decode_var"); | 971 | DBG("savagefb_decode_var"); |
801 | 972 | ||
802 | memset (&timings, 0, sizeof(timings)); | 973 | memset(&timings, 0, sizeof(timings)); |
803 | 974 | ||
804 | if (!pixclock) pixclock = 10000; /* 10ns = 100MHz */ | 975 | if (!pixclock) pixclock = 10000; /* 10ns = 100MHz */ |
805 | timings.Clock = 1000000000 / pixclock; | 976 | timings.Clock = 1000000000 / pixclock; |
@@ -831,39 +1002,39 @@ static int savagefb_decode_var (struct fb_var_screeninfo *var, | |||
831 | * This will allocate the datastructure and initialize all of the | 1002 | * This will allocate the datastructure and initialize all of the |
832 | * generic VGA registers. | 1003 | * generic VGA registers. |
833 | */ | 1004 | */ |
834 | vgaHWInit (var, par, &timings); | 1005 | vgaHWInit(var, par, &timings, reg); |
835 | 1006 | ||
836 | /* We need to set CR67 whether or not we use the BIOS. */ | 1007 | /* We need to set CR67 whether or not we use the BIOS. */ |
837 | 1008 | ||
838 | dclk = timings.Clock; | 1009 | dclk = timings.Clock; |
839 | par->CR67 = 0x00; | 1010 | reg->CR67 = 0x00; |
840 | 1011 | ||
841 | switch( var->bits_per_pixel ) { | 1012 | switch(var->bits_per_pixel) { |
842 | case 8: | 1013 | case 8: |
843 | if( (par->chip == S3_SAVAGE2000) && (dclk >= 230000) ) | 1014 | if ((par->chip == S3_SAVAGE2000) && (dclk >= 230000)) |
844 | par->CR67 = 0x10; /* 8bpp, 2 pixels/clock */ | 1015 | reg->CR67 = 0x10; /* 8bpp, 2 pixels/clock */ |
845 | else | 1016 | else |
846 | par->CR67 = 0x00; /* 8bpp, 1 pixel/clock */ | 1017 | reg->CR67 = 0x00; /* 8bpp, 1 pixel/clock */ |
847 | break; | 1018 | break; |
848 | case 15: | 1019 | case 15: |
849 | if ( S3_SAVAGE_MOBILE_SERIES(par->chip) || | 1020 | if (S3_SAVAGE_MOBILE_SERIES(par->chip) || |
850 | ((par->chip == S3_SAVAGE2000) && (dclk >= 230000)) ) | 1021 | ((par->chip == S3_SAVAGE2000) && (dclk >= 230000))) |
851 | par->CR67 = 0x30; /* 15bpp, 2 pixel/clock */ | 1022 | reg->CR67 = 0x30; /* 15bpp, 2 pixel/clock */ |
852 | else | 1023 | else |
853 | par->CR67 = 0x20; /* 15bpp, 1 pixels/clock */ | 1024 | reg->CR67 = 0x20; /* 15bpp, 1 pixels/clock */ |
854 | break; | 1025 | break; |
855 | case 16: | 1026 | case 16: |
856 | if( S3_SAVAGE_MOBILE_SERIES(par->chip) || | 1027 | if (S3_SAVAGE_MOBILE_SERIES(par->chip) || |
857 | ((par->chip == S3_SAVAGE2000) && (dclk >= 230000)) ) | 1028 | ((par->chip == S3_SAVAGE2000) && (dclk >= 230000))) |
858 | par->CR67 = 0x50; /* 16bpp, 2 pixel/clock */ | 1029 | reg->CR67 = 0x50; /* 16bpp, 2 pixel/clock */ |
859 | else | 1030 | else |
860 | par->CR67 = 0x40; /* 16bpp, 1 pixels/clock */ | 1031 | reg->CR67 = 0x40; /* 16bpp, 1 pixels/clock */ |
861 | break; | 1032 | break; |
862 | case 24: | 1033 | case 24: |
863 | par->CR67 = 0x70; | 1034 | reg->CR67 = 0x70; |
864 | break; | 1035 | break; |
865 | case 32: | 1036 | case 32: |
866 | par->CR67 = 0xd0; | 1037 | reg->CR67 = 0xd0; |
867 | break; | 1038 | break; |
868 | } | 1039 | } |
869 | 1040 | ||
@@ -872,61 +1043,61 @@ static int savagefb_decode_var (struct fb_var_screeninfo *var, | |||
872 | * match. Fall back to traditional register-crunching. | 1043 | * match. Fall back to traditional register-crunching. |
873 | */ | 1044 | */ |
874 | 1045 | ||
875 | vga_out8 (0x3d4, 0x3a, par); | 1046 | vga_out8(0x3d4, 0x3a, par); |
876 | tmp = vga_in8 (0x3d5, par); | 1047 | tmp = vga_in8(0x3d5, par); |
877 | if (1 /*FIXME:psav->pci_burst*/) | 1048 | if (1 /*FIXME:psav->pci_burst*/) |
878 | par->CR3A = (tmp & 0x7f) | 0x15; | 1049 | reg->CR3A = (tmp & 0x7f) | 0x15; |
879 | else | 1050 | else |
880 | par->CR3A = tmp | 0x95; | 1051 | reg->CR3A = tmp | 0x95; |
881 | 1052 | ||
882 | par->CR53 = 0x00; | 1053 | reg->CR53 = 0x00; |
883 | par->CR31 = 0x8c; | 1054 | reg->CR31 = 0x8c; |
884 | par->CR66 = 0x89; | 1055 | reg->CR66 = 0x89; |
885 | 1056 | ||
886 | vga_out8 (0x3d4, 0x58, par); | 1057 | vga_out8(0x3d4, 0x58, par); |
887 | par->CR58 = vga_in8 (0x3d5, par) & 0x80; | 1058 | reg->CR58 = vga_in8(0x3d5, par) & 0x80; |
888 | par->CR58 |= 0x13; | 1059 | reg->CR58 |= 0x13; |
889 | 1060 | ||
890 | par->SR15 = 0x03 | 0x80; | 1061 | reg->SR15 = 0x03 | 0x80; |
891 | par->SR18 = 0x00; | 1062 | reg->SR18 = 0x00; |
892 | par->CR43 = par->CR45 = par->CR65 = 0x00; | 1063 | reg->CR43 = reg->CR45 = reg->CR65 = 0x00; |
893 | 1064 | ||
894 | vga_out8 (0x3d4, 0x40, par); | 1065 | vga_out8(0x3d4, 0x40, par); |
895 | par->CR40 = vga_in8 (0x3d5, par) & ~0x01; | 1066 | reg->CR40 = vga_in8(0x3d5, par) & ~0x01; |
896 | 1067 | ||
897 | par->MMPR0 = 0x010400; | 1068 | reg->MMPR0 = 0x010400; |
898 | par->MMPR1 = 0x00; | 1069 | reg->MMPR1 = 0x00; |
899 | par->MMPR2 = 0x0808; | 1070 | reg->MMPR2 = 0x0808; |
900 | par->MMPR3 = 0x08080810; | 1071 | reg->MMPR3 = 0x08080810; |
901 | 1072 | ||
902 | SavageCalcClock (dclk, 1, 1, 127, 0, 4, 180000, 360000, &m, &n, &r); | 1073 | SavageCalcClock(dclk, 1, 1, 127, 0, 4, 180000, 360000, &m, &n, &r); |
903 | /* m = 107; n = 4; r = 2; */ | 1074 | /* m = 107; n = 4; r = 2; */ |
904 | 1075 | ||
905 | if (par->MCLK <= 0) { | 1076 | if (par->MCLK <= 0) { |
906 | par->SR10 = 255; | 1077 | reg->SR10 = 255; |
907 | par->SR11 = 255; | 1078 | reg->SR11 = 255; |
908 | } else { | 1079 | } else { |
909 | common_calc_clock (par->MCLK, 1, 1, 31, 0, 3, 135000, 270000, | 1080 | common_calc_clock(par->MCLK, 1, 1, 31, 0, 3, 135000, 270000, |
910 | &par->SR11, &par->SR10); | 1081 | ®->SR11, ®->SR10); |
911 | /* par->SR10 = 80; // MCLK == 286000 */ | 1082 | /* reg->SR10 = 80; // MCLK == 286000 */ |
912 | /* par->SR11 = 125; */ | 1083 | /* reg->SR11 = 125; */ |
913 | } | 1084 | } |
914 | 1085 | ||
915 | par->SR12 = (r << 6) | (n & 0x3f); | 1086 | reg->SR12 = (r << 6) | (n & 0x3f); |
916 | par->SR13 = m & 0xff; | 1087 | reg->SR13 = m & 0xff; |
917 | par->SR29 = (r & 4) | (m & 0x100) >> 5 | (n & 0x40) >> 2; | 1088 | reg->SR29 = (r & 4) | (m & 0x100) >> 5 | (n & 0x40) >> 2; |
918 | 1089 | ||
919 | if (var->bits_per_pixel < 24) | 1090 | if (var->bits_per_pixel < 24) |
920 | par->MMPR0 -= 0x8000; | 1091 | reg->MMPR0 -= 0x8000; |
921 | else | 1092 | else |
922 | par->MMPR0 -= 0x4000; | 1093 | reg->MMPR0 -= 0x4000; |
923 | 1094 | ||
924 | if (timings.interlaced) | 1095 | if (timings.interlaced) |
925 | par->CR42 = 0x20; | 1096 | reg->CR42 = 0x20; |
926 | else | 1097 | else |
927 | par->CR42 = 0x00; | 1098 | reg->CR42 = 0x00; |
928 | 1099 | ||
929 | par->CR34 = 0x10; /* display fifo */ | 1100 | reg->CR34 = 0x10; /* display fifo */ |
930 | 1101 | ||
931 | i = ((((timings.HTotal >> 3) - 5) & 0x100) >> 8) | | 1102 | i = ((((timings.HTotal >> 3) - 5) & 0x100) >> 8) | |
932 | ((((timings.HDisplay >> 3) - 1) & 0x100) >> 7) | | 1103 | ((((timings.HDisplay >> 3) - 1) & 0x100) >> 7) | |
@@ -938,77 +1109,77 @@ static int savagefb_decode_var (struct fb_var_screeninfo *var, | |||
938 | if ((timings.HSyncEnd >> 3) - (timings.HSyncStart >> 3) > 32) | 1109 | if ((timings.HSyncEnd >> 3) - (timings.HSyncStart >> 3) > 32) |
939 | i |= 0x20; | 1110 | i |= 0x20; |
940 | 1111 | ||
941 | j = (par->CRTC[0] + ((i & 0x01) << 8) + | 1112 | j = (reg->CRTC[0] + ((i & 0x01) << 8) + |
942 | par->CRTC[4] + ((i & 0x10) << 4) + 1) / 2; | 1113 | reg->CRTC[4] + ((i & 0x10) << 4) + 1) / 2; |
943 | 1114 | ||
944 | if (j - (par->CRTC[4] + ((i & 0x10) << 4)) < 4) { | 1115 | if (j - (reg->CRTC[4] + ((i & 0x10) << 4)) < 4) { |
945 | if (par->CRTC[4] + ((i & 0x10) << 4) + 4 <= | 1116 | if (reg->CRTC[4] + ((i & 0x10) << 4) + 4 <= |
946 | par->CRTC[0] + ((i & 0x01) << 8)) | 1117 | reg->CRTC[0] + ((i & 0x01) << 8)) |
947 | j = par->CRTC[4] + ((i & 0x10) << 4) + 4; | 1118 | j = reg->CRTC[4] + ((i & 0x10) << 4) + 4; |
948 | else | 1119 | else |
949 | j = par->CRTC[0] + ((i & 0x01) << 8) + 1; | 1120 | j = reg->CRTC[0] + ((i & 0x01) << 8) + 1; |
950 | } | 1121 | } |
951 | 1122 | ||
952 | par->CR3B = j & 0xff; | 1123 | reg->CR3B = j & 0xff; |
953 | i |= (j & 0x100) >> 2; | 1124 | i |= (j & 0x100) >> 2; |
954 | par->CR3C = (par->CRTC[0] + ((i & 0x01) << 8)) / 2; | 1125 | reg->CR3C = (reg->CRTC[0] + ((i & 0x01) << 8)) / 2; |
955 | par->CR5D = i; | 1126 | reg->CR5D = i; |
956 | par->CR5E = (((timings.VTotal - 2) & 0x400) >> 10) | | 1127 | reg->CR5E = (((timings.VTotal - 2) & 0x400) >> 10) | |
957 | (((timings.VDisplay - 1) & 0x400) >> 9) | | 1128 | (((timings.VDisplay - 1) & 0x400) >> 9) | |
958 | (((timings.VSyncStart) & 0x400) >> 8) | | 1129 | (((timings.VSyncStart) & 0x400) >> 8) | |
959 | (((timings.VSyncStart) & 0x400) >> 6) | 0x40; | 1130 | (((timings.VSyncStart) & 0x400) >> 6) | 0x40; |
960 | width = (var->xres_virtual * ((var->bits_per_pixel+7) / 8)) >> 3; | 1131 | width = (var->xres_virtual * ((var->bits_per_pixel+7) / 8)) >> 3; |
961 | par->CR91 = par->CRTC[19] = 0xff & width; | 1132 | reg->CR91 = reg->CRTC[19] = 0xff & width; |
962 | par->CR51 = (0x300 & width) >> 4; | 1133 | reg->CR51 = (0x300 & width) >> 4; |
963 | par->CR90 = 0x80 | (width >> 8); | 1134 | reg->CR90 = 0x80 | (width >> 8); |
964 | par->MiscOutReg |= 0x0c; | 1135 | reg->MiscOutReg |= 0x0c; |
965 | 1136 | ||
966 | /* Set frame buffer description. */ | 1137 | /* Set frame buffer description. */ |
967 | 1138 | ||
968 | if (var->bits_per_pixel <= 8) | 1139 | if (var->bits_per_pixel <= 8) |
969 | par->CR50 = 0; | 1140 | reg->CR50 = 0; |
970 | else if (var->bits_per_pixel <= 16) | 1141 | else if (var->bits_per_pixel <= 16) |
971 | par->CR50 = 0x10; | 1142 | reg->CR50 = 0x10; |
972 | else | 1143 | else |
973 | par->CR50 = 0x30; | 1144 | reg->CR50 = 0x30; |
974 | 1145 | ||
975 | if (var->xres_virtual <= 640) | 1146 | if (var->xres_virtual <= 640) |
976 | par->CR50 |= 0x40; | 1147 | reg->CR50 |= 0x40; |
977 | else if (var->xres_virtual == 800) | 1148 | else if (var->xres_virtual == 800) |
978 | par->CR50 |= 0x80; | 1149 | reg->CR50 |= 0x80; |
979 | else if (var->xres_virtual == 1024) | 1150 | else if (var->xres_virtual == 1024) |
980 | par->CR50 |= 0x00; | 1151 | reg->CR50 |= 0x00; |
981 | else if (var->xres_virtual == 1152) | 1152 | else if (var->xres_virtual == 1152) |
982 | par->CR50 |= 0x01; | 1153 | reg->CR50 |= 0x01; |
983 | else if (var->xres_virtual == 1280) | 1154 | else if (var->xres_virtual == 1280) |
984 | par->CR50 |= 0xc0; | 1155 | reg->CR50 |= 0xc0; |
985 | else if (var->xres_virtual == 1600) | 1156 | else if (var->xres_virtual == 1600) |
986 | par->CR50 |= 0x81; | 1157 | reg->CR50 |= 0x81; |
987 | else | 1158 | else |
988 | par->CR50 |= 0xc1; /* Use GBD */ | 1159 | reg->CR50 |= 0xc1; /* Use GBD */ |
989 | 1160 | ||
990 | if( par->chip == S3_SAVAGE2000 ) | 1161 | if (par->chip == S3_SAVAGE2000) |
991 | par->CR33 = 0x08; | 1162 | reg->CR33 = 0x08; |
992 | else | 1163 | else |
993 | par->CR33 = 0x20; | 1164 | reg->CR33 = 0x20; |
994 | 1165 | ||
995 | par->CRTC[0x17] = 0xeb; | 1166 | reg->CRTC[0x17] = 0xeb; |
996 | 1167 | ||
997 | par->CR67 |= 1; | 1168 | reg->CR67 |= 1; |
998 | 1169 | ||
999 | vga_out8(0x3d4, 0x36, par); | 1170 | vga_out8(0x3d4, 0x36, par); |
1000 | par->CR36 = vga_in8 (0x3d5, par); | 1171 | reg->CR36 = vga_in8(0x3d5, par); |
1001 | vga_out8 (0x3d4, 0x68, par); | 1172 | vga_out8(0x3d4, 0x68, par); |
1002 | par->CR68 = vga_in8 (0x3d5, par); | 1173 | reg->CR68 = vga_in8(0x3d5, par); |
1003 | par->CR69 = 0; | 1174 | reg->CR69 = 0; |
1004 | vga_out8 (0x3d4, 0x6f, par); | 1175 | vga_out8(0x3d4, 0x6f, par); |
1005 | par->CR6F = vga_in8 (0x3d5, par); | 1176 | reg->CR6F = vga_in8(0x3d5, par); |
1006 | vga_out8 (0x3d4, 0x86, par); | 1177 | vga_out8(0x3d4, 0x86, par); |
1007 | par->CR86 = vga_in8 (0x3d5, par); | 1178 | reg->CR86 = vga_in8(0x3d5, par); |
1008 | vga_out8 (0x3d4, 0x88, par); | 1179 | vga_out8(0x3d4, 0x88, par); |
1009 | par->CR88 = vga_in8 (0x3d5, par) | 0x08; | 1180 | reg->CR88 = vga_in8(0x3d5, par) | 0x08; |
1010 | vga_out8 (0x3d4, 0xb0, par); | 1181 | vga_out8(0x3d4, 0xb0, par); |
1011 | par->CRB0 = vga_in8 (0x3d5, par) | 0x80; | 1182 | reg->CRB0 = vga_in8(0x3d5, par) | 0x80; |
1012 | 1183 | ||
1013 | return 0; | 1184 | return 0; |
1014 | } | 1185 | } |
@@ -1037,11 +1208,11 @@ static int savagefb_setcolreg(unsigned regno, | |||
1037 | 1208 | ||
1038 | switch (info->var.bits_per_pixel) { | 1209 | switch (info->var.bits_per_pixel) { |
1039 | case 8: | 1210 | case 8: |
1040 | vga_out8 (0x3c8, regno, par); | 1211 | vga_out8(0x3c8, regno, par); |
1041 | 1212 | ||
1042 | vga_out8 (0x3c9, red >> 10, par); | 1213 | vga_out8(0x3c9, red >> 10, par); |
1043 | vga_out8 (0x3c9, green >> 10, par); | 1214 | vga_out8(0x3c9, green >> 10, par); |
1044 | vga_out8 (0x3c9, blue >> 10, par); | 1215 | vga_out8(0x3c9, blue >> 10, par); |
1045 | break; | 1216 | break; |
1046 | 1217 | ||
1047 | case 16: | 1218 | case 16: |
@@ -1075,21 +1246,21 @@ static int savagefb_setcolreg(unsigned regno, | |||
1075 | return 0; | 1246 | return 0; |
1076 | } | 1247 | } |
1077 | 1248 | ||
1078 | static void savagefb_set_par_int (struct savagefb_par *par) | 1249 | static void savagefb_set_par_int(struct savagefb_par *par, struct savage_reg *reg) |
1079 | { | 1250 | { |
1080 | unsigned char tmp, cr3a, cr66, cr67; | 1251 | unsigned char tmp, cr3a, cr66, cr67; |
1081 | 1252 | ||
1082 | DBG ("savagefb_set_par_int"); | 1253 | DBG("savagefb_set_par_int"); |
1083 | 1254 | ||
1084 | par->SavageWaitIdle (par); | 1255 | par->SavageWaitIdle(par); |
1085 | 1256 | ||
1086 | vga_out8 (0x3c2, 0x23, par); | 1257 | vga_out8(0x3c2, 0x23, par); |
1087 | 1258 | ||
1088 | vga_out16 (0x3d4, 0x4838, par); | 1259 | vga_out16(0x3d4, 0x4838, par); |
1089 | vga_out16 (0x3d4, 0xa539, par); | 1260 | vga_out16(0x3d4, 0xa539, par); |
1090 | vga_out16 (0x3c4, 0x0608, par); | 1261 | vga_out16(0x3c4, 0x0608, par); |
1091 | 1262 | ||
1092 | vgaHWProtect (par, 1); | 1263 | vgaHWProtect(par, 1); |
1093 | 1264 | ||
1094 | /* | 1265 | /* |
1095 | * Some Savage/MX and /IX systems go nuts when trying to exit the | 1266 | * Some Savage/MX and /IX systems go nuts when trying to exit the |
@@ -1099,203 +1270,202 @@ static void savagefb_set_par_int (struct savagefb_par *par) | |||
1099 | */ | 1270 | */ |
1100 | 1271 | ||
1101 | VerticalRetraceWait(par); | 1272 | VerticalRetraceWait(par); |
1102 | vga_out8 (0x3d4, 0x67, par); | 1273 | vga_out8(0x3d4, 0x67, par); |
1103 | cr67 = vga_in8 (0x3d5, par); | 1274 | cr67 = vga_in8(0x3d5, par); |
1104 | vga_out8 (0x3d5, cr67/*par->CR67*/ & ~0x0c, par); /* no STREAMS yet */ | 1275 | vga_out8(0x3d5, cr67/*par->CR67*/ & ~0x0c, par); /* no STREAMS yet */ |
1105 | 1276 | ||
1106 | vga_out8 (0x3d4, 0x23, par); | 1277 | vga_out8(0x3d4, 0x23, par); |
1107 | vga_out8 (0x3d5, 0x00, par); | 1278 | vga_out8(0x3d5, 0x00, par); |
1108 | vga_out8 (0x3d4, 0x26, par); | 1279 | vga_out8(0x3d4, 0x26, par); |
1109 | vga_out8 (0x3d5, 0x00, par); | 1280 | vga_out8(0x3d5, 0x00, par); |
1110 | 1281 | ||
1111 | /* restore extended regs */ | 1282 | /* restore extended regs */ |
1112 | vga_out8 (0x3d4, 0x66, par); | 1283 | vga_out8(0x3d4, 0x66, par); |
1113 | vga_out8 (0x3d5, par->CR66, par); | 1284 | vga_out8(0x3d5, reg->CR66, par); |
1114 | vga_out8 (0x3d4, 0x3a, par); | 1285 | vga_out8(0x3d4, 0x3a, par); |
1115 | vga_out8 (0x3d5, par->CR3A, par); | 1286 | vga_out8(0x3d5, reg->CR3A, par); |
1116 | vga_out8 (0x3d4, 0x31, par); | 1287 | vga_out8(0x3d4, 0x31, par); |
1117 | vga_out8 (0x3d5, par->CR31, par); | 1288 | vga_out8(0x3d5, reg->CR31, par); |
1118 | vga_out8 (0x3d4, 0x32, par); | 1289 | vga_out8(0x3d4, 0x32, par); |
1119 | vga_out8 (0x3d5, par->CR32, par); | 1290 | vga_out8(0x3d5, reg->CR32, par); |
1120 | vga_out8 (0x3d4, 0x58, par); | 1291 | vga_out8(0x3d4, 0x58, par); |
1121 | vga_out8 (0x3d5, par->CR58, par); | 1292 | vga_out8(0x3d5, reg->CR58, par); |
1122 | vga_out8 (0x3d4, 0x53, par); | 1293 | vga_out8(0x3d4, 0x53, par); |
1123 | vga_out8 (0x3d5, par->CR53 & 0x7f, par); | 1294 | vga_out8(0x3d5, reg->CR53 & 0x7f, par); |
1124 | 1295 | ||
1125 | vga_out16 (0x3c4, 0x0608, par); | 1296 | vga_out16(0x3c4, 0x0608, par); |
1126 | 1297 | ||
1127 | /* Restore DCLK registers. */ | 1298 | /* Restore DCLK registers. */ |
1128 | 1299 | ||
1129 | vga_out8 (0x3c4, 0x0e, par); | 1300 | vga_out8(0x3c4, 0x0e, par); |
1130 | vga_out8 (0x3c5, par->SR0E, par); | 1301 | vga_out8(0x3c5, reg->SR0E, par); |
1131 | vga_out8 (0x3c4, 0x0f, par); | 1302 | vga_out8(0x3c4, 0x0f, par); |
1132 | vga_out8 (0x3c5, par->SR0F, par); | 1303 | vga_out8(0x3c5, reg->SR0F, par); |
1133 | vga_out8 (0x3c4, 0x29, par); | 1304 | vga_out8(0x3c4, 0x29, par); |
1134 | vga_out8 (0x3c5, par->SR29, par); | 1305 | vga_out8(0x3c5, reg->SR29, par); |
1135 | vga_out8 (0x3c4, 0x15, par); | 1306 | vga_out8(0x3c4, 0x15, par); |
1136 | vga_out8 (0x3c5, par->SR15, par); | 1307 | vga_out8(0x3c5, reg->SR15, par); |
1137 | 1308 | ||
1138 | /* Restore flat panel expansion regsters. */ | 1309 | /* Restore flat panel expansion regsters. */ |
1139 | if( par->chip == S3_SAVAGE_MX ) { | 1310 | if (par->chip == S3_SAVAGE_MX) { |
1140 | int i; | 1311 | int i; |
1141 | 1312 | ||
1142 | for( i = 0; i < 8; i++ ) { | 1313 | for (i = 0; i < 8; i++) { |
1143 | vga_out8 (0x3c4, 0x54+i, par); | 1314 | vga_out8(0x3c4, 0x54+i, par); |
1144 | vga_out8 (0x3c5, par->SR54[i], par); | 1315 | vga_out8(0x3c5, reg->SR54[i], par); |
1145 | } | 1316 | } |
1146 | } | 1317 | } |
1147 | 1318 | ||
1148 | vgaHWRestore (par); | 1319 | vgaHWRestore (par, reg); |
1149 | 1320 | ||
1150 | /* extended mode timing registers */ | 1321 | /* extended mode timing registers */ |
1151 | vga_out8 (0x3d4, 0x53, par); | 1322 | vga_out8(0x3d4, 0x53, par); |
1152 | vga_out8 (0x3d5, par->CR53, par); | 1323 | vga_out8(0x3d5, reg->CR53, par); |
1153 | vga_out8 (0x3d4, 0x5d, par); | 1324 | vga_out8(0x3d4, 0x5d, par); |
1154 | vga_out8 (0x3d5, par->CR5D, par); | 1325 | vga_out8(0x3d5, reg->CR5D, par); |
1155 | vga_out8 (0x3d4, 0x5e, par); | 1326 | vga_out8(0x3d4, 0x5e, par); |
1156 | vga_out8 (0x3d5, par->CR5E, par); | 1327 | vga_out8(0x3d5, reg->CR5E, par); |
1157 | vga_out8 (0x3d4, 0x3b, par); | 1328 | vga_out8(0x3d4, 0x3b, par); |
1158 | vga_out8 (0x3d5, par->CR3B, par); | 1329 | vga_out8(0x3d5, reg->CR3B, par); |
1159 | vga_out8 (0x3d4, 0x3c, par); | 1330 | vga_out8(0x3d4, 0x3c, par); |
1160 | vga_out8 (0x3d5, par->CR3C, par); | 1331 | vga_out8(0x3d5, reg->CR3C, par); |
1161 | vga_out8 (0x3d4, 0x43, par); | 1332 | vga_out8(0x3d4, 0x43, par); |
1162 | vga_out8 (0x3d5, par->CR43, par); | 1333 | vga_out8(0x3d5, reg->CR43, par); |
1163 | vga_out8 (0x3d4, 0x65, par); | 1334 | vga_out8(0x3d4, 0x65, par); |
1164 | vga_out8 (0x3d5, par->CR65, par); | 1335 | vga_out8(0x3d5, reg->CR65, par); |
1165 | 1336 | ||
1166 | /* restore the desired video mode with cr67 */ | 1337 | /* restore the desired video mode with cr67 */ |
1167 | vga_out8 (0x3d4, 0x67, par); | 1338 | vga_out8(0x3d4, 0x67, par); |
1168 | /* following part not present in X11 driver */ | 1339 | /* following part not present in X11 driver */ |
1169 | cr67 = vga_in8 (0x3d5, par) & 0xf; | 1340 | cr67 = vga_in8(0x3d5, par) & 0xf; |
1170 | vga_out8 (0x3d5, 0x50 | cr67, par); | 1341 | vga_out8(0x3d5, 0x50 | cr67, par); |
1171 | udelay (10000); | 1342 | udelay(10000); |
1172 | vga_out8 (0x3d4, 0x67, par); | 1343 | vga_out8(0x3d4, 0x67, par); |
1173 | /* end of part */ | 1344 | /* end of part */ |
1174 | vga_out8 (0x3d5, par->CR67 & ~0x0c, par); | 1345 | vga_out8(0x3d5, reg->CR67 & ~0x0c, par); |
1175 | 1346 | ||
1176 | /* other mode timing and extended regs */ | 1347 | /* other mode timing and extended regs */ |
1177 | vga_out8 (0x3d4, 0x34, par); | 1348 | vga_out8(0x3d4, 0x34, par); |
1178 | vga_out8 (0x3d5, par->CR34, par); | 1349 | vga_out8(0x3d5, reg->CR34, par); |
1179 | vga_out8 (0x3d4, 0x40, par); | 1350 | vga_out8(0x3d4, 0x40, par); |
1180 | vga_out8 (0x3d5, par->CR40, par); | 1351 | vga_out8(0x3d5, reg->CR40, par); |
1181 | vga_out8 (0x3d4, 0x42, par); | 1352 | vga_out8(0x3d4, 0x42, par); |
1182 | vga_out8 (0x3d5, par->CR42, par); | 1353 | vga_out8(0x3d5, reg->CR42, par); |
1183 | vga_out8 (0x3d4, 0x45, par); | 1354 | vga_out8(0x3d4, 0x45, par); |
1184 | vga_out8 (0x3d5, par->CR45, par); | 1355 | vga_out8(0x3d5, reg->CR45, par); |
1185 | vga_out8 (0x3d4, 0x50, par); | 1356 | vga_out8(0x3d4, 0x50, par); |
1186 | vga_out8 (0x3d5, par->CR50, par); | 1357 | vga_out8(0x3d5, reg->CR50, par); |
1187 | vga_out8 (0x3d4, 0x51, par); | 1358 | vga_out8(0x3d4, 0x51, par); |
1188 | vga_out8 (0x3d5, par->CR51, par); | 1359 | vga_out8(0x3d5, reg->CR51, par); |
1189 | 1360 | ||
1190 | /* memory timings */ | 1361 | /* memory timings */ |
1191 | vga_out8 (0x3d4, 0x36, par); | 1362 | vga_out8(0x3d4, 0x36, par); |
1192 | vga_out8 (0x3d5, par->CR36, par); | 1363 | vga_out8(0x3d5, reg->CR36, par); |
1193 | vga_out8 (0x3d4, 0x60, par); | 1364 | vga_out8(0x3d4, 0x60, par); |
1194 | vga_out8 (0x3d5, par->CR60, par); | 1365 | vga_out8(0x3d5, reg->CR60, par); |
1195 | vga_out8 (0x3d4, 0x68, par); | 1366 | vga_out8(0x3d4, 0x68, par); |
1196 | vga_out8 (0x3d5, par->CR68, par); | 1367 | vga_out8(0x3d5, reg->CR68, par); |
1197 | vga_out8 (0x3d4, 0x69, par); | 1368 | vga_out8(0x3d4, 0x69, par); |
1198 | vga_out8 (0x3d5, par->CR69, par); | 1369 | vga_out8(0x3d5, reg->CR69, par); |
1199 | vga_out8 (0x3d4, 0x6f, par); | 1370 | vga_out8(0x3d4, 0x6f, par); |
1200 | vga_out8 (0x3d5, par->CR6F, par); | 1371 | vga_out8(0x3d5, reg->CR6F, par); |
1201 | 1372 | ||
1202 | vga_out8 (0x3d4, 0x33, par); | 1373 | vga_out8(0x3d4, 0x33, par); |
1203 | vga_out8 (0x3d5, par->CR33, par); | 1374 | vga_out8(0x3d5, reg->CR33, par); |
1204 | vga_out8 (0x3d4, 0x86, par); | 1375 | vga_out8(0x3d4, 0x86, par); |
1205 | vga_out8 (0x3d5, par->CR86, par); | 1376 | vga_out8(0x3d5, reg->CR86, par); |
1206 | vga_out8 (0x3d4, 0x88, par); | 1377 | vga_out8(0x3d4, 0x88, par); |
1207 | vga_out8 (0x3d5, par->CR88, par); | 1378 | vga_out8(0x3d5, reg->CR88, par); |
1208 | vga_out8 (0x3d4, 0x90, par); | 1379 | vga_out8(0x3d4, 0x90, par); |
1209 | vga_out8 (0x3d5, par->CR90, par); | 1380 | vga_out8(0x3d5, reg->CR90, par); |
1210 | vga_out8 (0x3d4, 0x91, par); | 1381 | vga_out8(0x3d4, 0x91, par); |
1211 | vga_out8 (0x3d5, par->CR91, par); | 1382 | vga_out8(0x3d5, reg->CR91, par); |
1212 | 1383 | ||
1213 | if (par->chip == S3_SAVAGE4) { | 1384 | if (par->chip == S3_SAVAGE4) { |
1214 | vga_out8 (0x3d4, 0xb0, par); | 1385 | vga_out8(0x3d4, 0xb0, par); |
1215 | vga_out8 (0x3d5, par->CRB0, par); | 1386 | vga_out8(0x3d5, reg->CRB0, par); |
1216 | } | 1387 | } |
1217 | 1388 | ||
1218 | vga_out8 (0x3d4, 0x32, par); | 1389 | vga_out8(0x3d4, 0x32, par); |
1219 | vga_out8 (0x3d5, par->CR32, par); | 1390 | vga_out8(0x3d5, reg->CR32, par); |
1220 | 1391 | ||
1221 | /* unlock extended seq regs */ | 1392 | /* unlock extended seq regs */ |
1222 | vga_out8 (0x3c4, 0x08, par); | 1393 | vga_out8(0x3c4, 0x08, par); |
1223 | vga_out8 (0x3c5, 0x06, par); | 1394 | vga_out8(0x3c5, 0x06, par); |
1224 | 1395 | ||
1225 | /* Restore extended sequencer regs for MCLK. SR10 == 255 indicates | 1396 | /* Restore extended sequencer regs for MCLK. SR10 == 255 indicates |
1226 | * that we should leave the default SR10 and SR11 values there. | 1397 | * that we should leave the default SR10 and SR11 values there. |
1227 | */ | 1398 | */ |
1228 | if (par->SR10 != 255) { | 1399 | if (reg->SR10 != 255) { |
1229 | vga_out8 (0x3c4, 0x10, par); | 1400 | vga_out8(0x3c4, 0x10, par); |
1230 | vga_out8 (0x3c5, par->SR10, par); | 1401 | vga_out8(0x3c5, reg->SR10, par); |
1231 | vga_out8 (0x3c4, 0x11, par); | 1402 | vga_out8(0x3c4, 0x11, par); |
1232 | vga_out8 (0x3c5, par->SR11, par); | 1403 | vga_out8(0x3c5, reg->SR11, par); |
1233 | } | 1404 | } |
1234 | 1405 | ||
1235 | /* restore extended seq regs for dclk */ | 1406 | /* restore extended seq regs for dclk */ |
1236 | vga_out8 (0x3c4, 0x0e, par); | 1407 | vga_out8(0x3c4, 0x0e, par); |
1237 | vga_out8 (0x3c5, par->SR0E, par); | 1408 | vga_out8(0x3c5, reg->SR0E, par); |
1238 | vga_out8 (0x3c4, 0x0f, par); | 1409 | vga_out8(0x3c4, 0x0f, par); |
1239 | vga_out8 (0x3c5, par->SR0F, par); | 1410 | vga_out8(0x3c5, reg->SR0F, par); |
1240 | vga_out8 (0x3c4, 0x12, par); | 1411 | vga_out8(0x3c4, 0x12, par); |
1241 | vga_out8 (0x3c5, par->SR12, par); | 1412 | vga_out8(0x3c5, reg->SR12, par); |
1242 | vga_out8 (0x3c4, 0x13, par); | 1413 | vga_out8(0x3c4, 0x13, par); |
1243 | vga_out8 (0x3c5, par->SR13, par); | 1414 | vga_out8(0x3c5, reg->SR13, par); |
1244 | vga_out8 (0x3c4, 0x29, par); | 1415 | vga_out8(0x3c4, 0x29, par); |
1245 | vga_out8 (0x3c5, par->SR29, par); | 1416 | vga_out8(0x3c5, reg->SR29, par); |
1246 | 1417 | vga_out8(0x3c4, 0x18, par); | |
1247 | vga_out8 (0x3c4, 0x18, par); | 1418 | vga_out8(0x3c5, reg->SR18, par); |
1248 | vga_out8 (0x3c5, par->SR18, par); | ||
1249 | 1419 | ||
1250 | /* load new m, n pll values for dclk & mclk */ | 1420 | /* load new m, n pll values for dclk & mclk */ |
1251 | vga_out8 (0x3c4, 0x15, par); | 1421 | vga_out8(0x3c4, 0x15, par); |
1252 | tmp = vga_in8 (0x3c5, par) & ~0x21; | 1422 | tmp = vga_in8(0x3c5, par) & ~0x21; |
1253 | 1423 | ||
1254 | vga_out8 (0x3c5, tmp | 0x03, par); | 1424 | vga_out8(0x3c5, tmp | 0x03, par); |
1255 | vga_out8 (0x3c5, tmp | 0x23, par); | 1425 | vga_out8(0x3c5, tmp | 0x23, par); |
1256 | vga_out8 (0x3c5, tmp | 0x03, par); | 1426 | vga_out8(0x3c5, tmp | 0x03, par); |
1257 | vga_out8 (0x3c5, par->SR15, par); | 1427 | vga_out8(0x3c5, reg->SR15, par); |
1258 | udelay (100); | 1428 | udelay(100); |
1259 | 1429 | ||
1260 | vga_out8 (0x3c4, 0x30, par); | 1430 | vga_out8(0x3c4, 0x30, par); |
1261 | vga_out8 (0x3c5, par->SR30, par); | 1431 | vga_out8(0x3c5, reg->SR30, par); |
1262 | vga_out8 (0x3c4, 0x08, par); | 1432 | vga_out8(0x3c4, 0x08, par); |
1263 | vga_out8 (0x3c5, par->SR08, par); | 1433 | vga_out8(0x3c5, reg->SR08, par); |
1264 | 1434 | ||
1265 | /* now write out cr67 in full, possibly starting STREAMS */ | 1435 | /* now write out cr67 in full, possibly starting STREAMS */ |
1266 | VerticalRetraceWait(par); | 1436 | VerticalRetraceWait(par); |
1267 | vga_out8 (0x3d4, 0x67, par); | 1437 | vga_out8(0x3d4, 0x67, par); |
1268 | vga_out8 (0x3d5, par->CR67, par); | 1438 | vga_out8(0x3d5, reg->CR67, par); |
1269 | 1439 | ||
1270 | vga_out8 (0x3d4, 0x66, par); | 1440 | vga_out8(0x3d4, 0x66, par); |
1271 | cr66 = vga_in8 (0x3d5, par); | 1441 | cr66 = vga_in8(0x3d5, par); |
1272 | vga_out8 (0x3d5, cr66 | 0x80, par); | 1442 | vga_out8(0x3d5, cr66 | 0x80, par); |
1273 | vga_out8 (0x3d4, 0x3a, par); | 1443 | vga_out8(0x3d4, 0x3a, par); |
1274 | cr3a = vga_in8 (0x3d5, par); | 1444 | cr3a = vga_in8(0x3d5, par); |
1275 | vga_out8 (0x3d5, cr3a | 0x80, par); | 1445 | vga_out8(0x3d5, cr3a | 0x80, par); |
1276 | 1446 | ||
1277 | if (par->chip != S3_SAVAGE_MX) { | 1447 | if (par->chip != S3_SAVAGE_MX) { |
1278 | VerticalRetraceWait(par); | 1448 | VerticalRetraceWait(par); |
1279 | savage_out32 (FIFO_CONTROL_REG, par->MMPR0, par); | 1449 | savage_out32(FIFO_CONTROL_REG, reg->MMPR0, par); |
1280 | par->SavageWaitIdle (par); | 1450 | par->SavageWaitIdle(par); |
1281 | savage_out32 (MIU_CONTROL_REG, par->MMPR1, par); | 1451 | savage_out32(MIU_CONTROL_REG, reg->MMPR1, par); |
1282 | par->SavageWaitIdle (par); | 1452 | par->SavageWaitIdle(par); |
1283 | savage_out32 (STREAMS_TIMEOUT_REG, par->MMPR2, par); | 1453 | savage_out32(STREAMS_TIMEOUT_REG, reg->MMPR2, par); |
1284 | par->SavageWaitIdle (par); | 1454 | par->SavageWaitIdle(par); |
1285 | savage_out32 (MISC_TIMEOUT_REG, par->MMPR3, par); | 1455 | savage_out32(MISC_TIMEOUT_REG, reg->MMPR3, par); |
1286 | } | 1456 | } |
1287 | 1457 | ||
1288 | vga_out8 (0x3d4, 0x66, par); | 1458 | vga_out8(0x3d4, 0x66, par); |
1289 | vga_out8 (0x3d5, cr66, par); | 1459 | vga_out8(0x3d5, cr66, par); |
1290 | vga_out8 (0x3d4, 0x3a, par); | 1460 | vga_out8(0x3d4, 0x3a, par); |
1291 | vga_out8 (0x3d5, cr3a, par); | 1461 | vga_out8(0x3d5, cr3a, par); |
1292 | 1462 | ||
1293 | SavageSetup2DEngine (par); | 1463 | SavageSetup2DEngine(par); |
1294 | vgaHWProtect (par, 0); | 1464 | vgaHWProtect(par, 0); |
1295 | } | 1465 | } |
1296 | 1466 | ||
1297 | static void savagefb_update_start (struct savagefb_par *par, | 1467 | static void savagefb_update_start(struct savagefb_par *par, |
1298 | struct fb_var_screeninfo *var) | 1468 | struct fb_var_screeninfo *var) |
1299 | { | 1469 | { |
1300 | int base; | 1470 | int base; |
1301 | 1471 | ||
@@ -1305,8 +1475,8 @@ static void savagefb_update_start (struct savagefb_par *par, | |||
1305 | /* now program the start address registers */ | 1475 | /* now program the start address registers */ |
1306 | vga_out16(0x3d4, (base & 0x00ff00) | 0x0c, par); | 1476 | vga_out16(0x3d4, (base & 0x00ff00) | 0x0c, par); |
1307 | vga_out16(0x3d4, ((base & 0x00ff) << 8) | 0x0d, par); | 1477 | vga_out16(0x3d4, ((base & 0x00ff) << 8) | 0x0d, par); |
1308 | vga_out8 (0x3d4, 0x69, par); | 1478 | vga_out8(0x3d4, 0x69, par); |
1309 | vga_out8 (0x3d5, (base & 0x7f0000) >> 16, par); | 1479 | vga_out8(0x3d5, (base & 0x7f0000) >> 16, par); |
1310 | } | 1480 | } |
1311 | 1481 | ||
1312 | 1482 | ||
@@ -1325,29 +1495,14 @@ static void savagefb_set_fix(struct fb_info *info) | |||
1325 | 1495 | ||
1326 | } | 1496 | } |
1327 | 1497 | ||
1328 | #if defined(CONFIG_FB_SAVAGE_ACCEL) | 1498 | static int savagefb_set_par(struct fb_info *info) |
1329 | static void savagefb_set_clip(struct fb_info *info) | ||
1330 | { | ||
1331 | struct savagefb_par *par = info->par; | ||
1332 | int cmd; | ||
1333 | |||
1334 | cmd = BCI_CMD_NOP | BCI_CMD_CLIP_NEW; | ||
1335 | par->bci_ptr = 0; | ||
1336 | par->SavageWaitFifo(par,3); | ||
1337 | BCI_SEND(cmd); | ||
1338 | BCI_SEND(BCI_CLIP_TL(0, 0)); | ||
1339 | BCI_SEND(BCI_CLIP_BR(0xfff, 0xfff)); | ||
1340 | } | ||
1341 | #endif | ||
1342 | |||
1343 | static int savagefb_set_par (struct fb_info *info) | ||
1344 | { | 1499 | { |
1345 | struct savagefb_par *par = info->par; | 1500 | struct savagefb_par *par = info->par; |
1346 | struct fb_var_screeninfo *var = &info->var; | 1501 | struct fb_var_screeninfo *var = &info->var; |
1347 | int err; | 1502 | int err; |
1348 | 1503 | ||
1349 | DBG("savagefb_set_par"); | 1504 | DBG("savagefb_set_par"); |
1350 | err = savagefb_decode_var (var, par); | 1505 | err = savagefb_decode_var(var, par, &par->state); |
1351 | if (err) | 1506 | if (err) |
1352 | return err; | 1507 | return err; |
1353 | 1508 | ||
@@ -1366,8 +1521,8 @@ static int savagefb_set_par (struct fb_info *info) | |||
1366 | par->maxClock = par->dacSpeedBpp; | 1521 | par->maxClock = par->dacSpeedBpp; |
1367 | par->minClock = 10000; | 1522 | par->minClock = 10000; |
1368 | 1523 | ||
1369 | savagefb_set_par_int (par); | 1524 | savagefb_set_par_int(par, &par->state); |
1370 | fb_set_cmap (&info->cmap, info); | 1525 | fb_set_cmap(&info->cmap, info); |
1371 | savagefb_set_fix(info); | 1526 | savagefb_set_fix(info); |
1372 | savagefb_set_clip(info); | 1527 | savagefb_set_clip(info); |
1373 | 1528 | ||
@@ -1378,12 +1533,12 @@ static int savagefb_set_par (struct fb_info *info) | |||
1378 | /* | 1533 | /* |
1379 | * Pan or Wrap the Display | 1534 | * Pan or Wrap the Display |
1380 | */ | 1535 | */ |
1381 | static int savagefb_pan_display (struct fb_var_screeninfo *var, | 1536 | static int savagefb_pan_display(struct fb_var_screeninfo *var, |
1382 | struct fb_info *info) | 1537 | struct fb_info *info) |
1383 | { | 1538 | { |
1384 | struct savagefb_par *par = info->par; | 1539 | struct savagefb_par *par = info->par; |
1385 | 1540 | ||
1386 | savagefb_update_start (par, var); | 1541 | savagefb_update_start(par, var); |
1387 | return 0; | 1542 | return 0; |
1388 | } | 1543 | } |
1389 | 1544 | ||
@@ -1440,6 +1595,22 @@ static int savagefb_blank(int blank, struct fb_info *info) | |||
1440 | return (blank == FB_BLANK_NORMAL) ? 1 : 0; | 1595 | return (blank == FB_BLANK_NORMAL) ? 1 : 0; |
1441 | } | 1596 | } |
1442 | 1597 | ||
1598 | static void savagefb_save_state(struct fb_info *info) | ||
1599 | { | ||
1600 | struct savagefb_par *par = info->par; | ||
1601 | |||
1602 | savage_get_default_par(par, &par->save); | ||
1603 | } | ||
1604 | |||
1605 | static void savagefb_restore_state(struct fb_info *info) | ||
1606 | { | ||
1607 | struct savagefb_par *par = info->par; | ||
1608 | |||
1609 | savagefb_blank(FB_BLANK_POWERDOWN, info); | ||
1610 | savage_set_default_par(par, &par->save); | ||
1611 | savagefb_blank(FB_BLANK_UNBLANK, info); | ||
1612 | } | ||
1613 | |||
1443 | static struct fb_ops savagefb_ops = { | 1614 | static struct fb_ops savagefb_ops = { |
1444 | .owner = THIS_MODULE, | 1615 | .owner = THIS_MODULE, |
1445 | .fb_check_var = savagefb_check_var, | 1616 | .fb_check_var = savagefb_check_var, |
@@ -1447,6 +1618,8 @@ static struct fb_ops savagefb_ops = { | |||
1447 | .fb_setcolreg = savagefb_setcolreg, | 1618 | .fb_setcolreg = savagefb_setcolreg, |
1448 | .fb_pan_display = savagefb_pan_display, | 1619 | .fb_pan_display = savagefb_pan_display, |
1449 | .fb_blank = savagefb_blank, | 1620 | .fb_blank = savagefb_blank, |
1621 | .fb_save_state = savagefb_save_state, | ||
1622 | .fb_restore_state = savagefb_restore_state, | ||
1450 | #if defined(CONFIG_FB_SAVAGE_ACCEL) | 1623 | #if defined(CONFIG_FB_SAVAGE_ACCEL) |
1451 | .fb_fillrect = savagefb_fillrect, | 1624 | .fb_fillrect = savagefb_fillrect, |
1452 | .fb_copyarea = savagefb_copyarea, | 1625 | .fb_copyarea = savagefb_copyarea, |
@@ -1479,59 +1652,59 @@ static struct fb_var_screeninfo __devinitdata savagefb_var800x600x8 = { | |||
1479 | .vmode = FB_VMODE_NONINTERLACED | 1652 | .vmode = FB_VMODE_NONINTERLACED |
1480 | }; | 1653 | }; |
1481 | 1654 | ||
1482 | static void savage_enable_mmio (struct savagefb_par *par) | 1655 | static void savage_enable_mmio(struct savagefb_par *par) |
1483 | { | 1656 | { |
1484 | unsigned char val; | 1657 | unsigned char val; |
1485 | 1658 | ||
1486 | DBG ("savage_enable_mmio\n"); | 1659 | DBG("savage_enable_mmio\n"); |
1487 | 1660 | ||
1488 | val = vga_in8 (0x3c3, par); | 1661 | val = vga_in8(0x3c3, par); |
1489 | vga_out8 (0x3c3, val | 0x01, par); | 1662 | vga_out8(0x3c3, val | 0x01, par); |
1490 | val = vga_in8 (0x3cc, par); | 1663 | val = vga_in8(0x3cc, par); |
1491 | vga_out8 (0x3c2, val | 0x01, par); | 1664 | vga_out8(0x3c2, val | 0x01, par); |
1492 | 1665 | ||
1493 | if (par->chip >= S3_SAVAGE4) { | 1666 | if (par->chip >= S3_SAVAGE4) { |
1494 | vga_out8 (0x3d4, 0x40, par); | 1667 | vga_out8(0x3d4, 0x40, par); |
1495 | val = vga_in8 (0x3d5, par); | 1668 | val = vga_in8(0x3d5, par); |
1496 | vga_out8 (0x3d5, val | 1, par); | 1669 | vga_out8(0x3d5, val | 1, par); |
1497 | } | 1670 | } |
1498 | } | 1671 | } |
1499 | 1672 | ||
1500 | 1673 | ||
1501 | static void savage_disable_mmio (struct savagefb_par *par) | 1674 | static void savage_disable_mmio(struct savagefb_par *par) |
1502 | { | 1675 | { |
1503 | unsigned char val; | 1676 | unsigned char val; |
1504 | 1677 | ||
1505 | DBG ("savage_disable_mmio\n"); | 1678 | DBG("savage_disable_mmio\n"); |
1506 | 1679 | ||
1507 | if(par->chip >= S3_SAVAGE4 ) { | 1680 | if (par->chip >= S3_SAVAGE4) { |
1508 | vga_out8 (0x3d4, 0x40, par); | 1681 | vga_out8(0x3d4, 0x40, par); |
1509 | val = vga_in8 (0x3d5, par); | 1682 | val = vga_in8(0x3d5, par); |
1510 | vga_out8 (0x3d5, val | 1, par); | 1683 | vga_out8(0x3d5, val | 1, par); |
1511 | } | 1684 | } |
1512 | } | 1685 | } |
1513 | 1686 | ||
1514 | 1687 | ||
1515 | static int __devinit savage_map_mmio (struct fb_info *info) | 1688 | static int __devinit savage_map_mmio(struct fb_info *info) |
1516 | { | 1689 | { |
1517 | struct savagefb_par *par = info->par; | 1690 | struct savagefb_par *par = info->par; |
1518 | DBG ("savage_map_mmio"); | 1691 | DBG("savage_map_mmio"); |
1519 | 1692 | ||
1520 | if (S3_SAVAGE3D_SERIES (par->chip)) | 1693 | if (S3_SAVAGE3D_SERIES(par->chip)) |
1521 | par->mmio.pbase = pci_resource_start (par->pcidev, 0) + | 1694 | par->mmio.pbase = pci_resource_start(par->pcidev, 0) + |
1522 | SAVAGE_NEWMMIO_REGBASE_S3; | 1695 | SAVAGE_NEWMMIO_REGBASE_S3; |
1523 | else | 1696 | else |
1524 | par->mmio.pbase = pci_resource_start (par->pcidev, 0) + | 1697 | par->mmio.pbase = pci_resource_start(par->pcidev, 0) + |
1525 | SAVAGE_NEWMMIO_REGBASE_S4; | 1698 | SAVAGE_NEWMMIO_REGBASE_S4; |
1526 | 1699 | ||
1527 | par->mmio.len = SAVAGE_NEWMMIO_REGSIZE; | 1700 | par->mmio.len = SAVAGE_NEWMMIO_REGSIZE; |
1528 | 1701 | ||
1529 | par->mmio.vbase = ioremap (par->mmio.pbase, par->mmio.len); | 1702 | par->mmio.vbase = ioremap(par->mmio.pbase, par->mmio.len); |
1530 | if (!par->mmio.vbase) { | 1703 | if (!par->mmio.vbase) { |
1531 | printk ("savagefb: unable to map memory mapped IO\n"); | 1704 | printk("savagefb: unable to map memory mapped IO\n"); |
1532 | return -ENOMEM; | 1705 | return -ENOMEM; |
1533 | } else | 1706 | } else |
1534 | printk (KERN_INFO "savagefb: mapped io at %p\n", | 1707 | printk(KERN_INFO "savagefb: mapped io at %p\n", |
1535 | par->mmio.vbase); | 1708 | par->mmio.vbase); |
1536 | 1709 | ||
1537 | info->fix.mmio_start = par->mmio.pbase; | 1710 | info->fix.mmio_start = par->mmio.pbase; |
@@ -1540,15 +1713,15 @@ static int __devinit savage_map_mmio (struct fb_info *info) | |||
1540 | par->bci_base = (u32 __iomem *)(par->mmio.vbase + BCI_BUFFER_OFFSET); | 1713 | par->bci_base = (u32 __iomem *)(par->mmio.vbase + BCI_BUFFER_OFFSET); |
1541 | par->bci_ptr = 0; | 1714 | par->bci_ptr = 0; |
1542 | 1715 | ||
1543 | savage_enable_mmio (par); | 1716 | savage_enable_mmio(par); |
1544 | 1717 | ||
1545 | return 0; | 1718 | return 0; |
1546 | } | 1719 | } |
1547 | 1720 | ||
1548 | static void savage_unmap_mmio (struct fb_info *info) | 1721 | static void savage_unmap_mmio(struct fb_info *info) |
1549 | { | 1722 | { |
1550 | struct savagefb_par *par = info->par; | 1723 | struct savagefb_par *par = info->par; |
1551 | DBG ("savage_unmap_mmio"); | 1724 | DBG("savage_unmap_mmio"); |
1552 | 1725 | ||
1553 | savage_disable_mmio(par); | 1726 | savage_disable_mmio(par); |
1554 | 1727 | ||
@@ -1558,46 +1731,46 @@ static void savage_unmap_mmio (struct fb_info *info) | |||
1558 | } | 1731 | } |
1559 | } | 1732 | } |
1560 | 1733 | ||
1561 | static int __devinit savage_map_video (struct fb_info *info, | 1734 | static int __devinit savage_map_video(struct fb_info *info, |
1562 | int video_len) | 1735 | int video_len) |
1563 | { | 1736 | { |
1564 | struct savagefb_par *par = info->par; | 1737 | struct savagefb_par *par = info->par; |
1565 | int resource; | 1738 | int resource; |
1566 | 1739 | ||
1567 | DBG("savage_map_video"); | 1740 | DBG("savage_map_video"); |
1568 | 1741 | ||
1569 | if (S3_SAVAGE3D_SERIES (par->chip)) | 1742 | if (S3_SAVAGE3D_SERIES(par->chip)) |
1570 | resource = 0; | 1743 | resource = 0; |
1571 | else | 1744 | else |
1572 | resource = 1; | 1745 | resource = 1; |
1573 | 1746 | ||
1574 | par->video.pbase = pci_resource_start (par->pcidev, resource); | 1747 | par->video.pbase = pci_resource_start(par->pcidev, resource); |
1575 | par->video.len = video_len; | 1748 | par->video.len = video_len; |
1576 | par->video.vbase = ioremap (par->video.pbase, par->video.len); | 1749 | par->video.vbase = ioremap(par->video.pbase, par->video.len); |
1577 | 1750 | ||
1578 | if (!par->video.vbase) { | 1751 | if (!par->video.vbase) { |
1579 | printk ("savagefb: unable to map screen memory\n"); | 1752 | printk("savagefb: unable to map screen memory\n"); |
1580 | return -ENOMEM; | 1753 | return -ENOMEM; |
1581 | } else | 1754 | } else |
1582 | printk (KERN_INFO "savagefb: mapped framebuffer at %p, " | 1755 | printk(KERN_INFO "savagefb: mapped framebuffer at %p, " |
1583 | "pbase == %x\n", par->video.vbase, par->video.pbase); | 1756 | "pbase == %x\n", par->video.vbase, par->video.pbase); |
1584 | 1757 | ||
1585 | info->fix.smem_start = par->video.pbase; | 1758 | info->fix.smem_start = par->video.pbase; |
1586 | info->fix.smem_len = par->video.len - par->cob_size; | 1759 | info->fix.smem_len = par->video.len - par->cob_size; |
1587 | info->screen_base = par->video.vbase; | 1760 | info->screen_base = par->video.vbase; |
1588 | 1761 | ||
1589 | #ifdef CONFIG_MTRR | 1762 | #ifdef CONFIG_MTRR |
1590 | par->video.mtrr = mtrr_add (par->video.pbase, video_len, | 1763 | par->video.mtrr = mtrr_add(par->video.pbase, video_len, |
1591 | MTRR_TYPE_WRCOMB, 1); | 1764 | MTRR_TYPE_WRCOMB, 1); |
1592 | #endif | 1765 | #endif |
1593 | 1766 | ||
1594 | /* Clear framebuffer, it's all white in memory after boot */ | 1767 | /* Clear framebuffer, it's all white in memory after boot */ |
1595 | memset_io (par->video.vbase, 0, par->video.len); | 1768 | memset_io(par->video.vbase, 0, par->video.len); |
1596 | 1769 | ||
1597 | return 0; | 1770 | return 0; |
1598 | } | 1771 | } |
1599 | 1772 | ||
1600 | static void savage_unmap_video (struct fb_info *info) | 1773 | static void savage_unmap_video(struct fb_info *info) |
1601 | { | 1774 | { |
1602 | struct savagefb_par *par = info->par; | 1775 | struct savagefb_par *par = info->par; |
1603 | 1776 | ||
@@ -1605,16 +1778,16 @@ static void savage_unmap_video (struct fb_info *info) | |||
1605 | 1778 | ||
1606 | if (par->video.vbase) { | 1779 | if (par->video.vbase) { |
1607 | #ifdef CONFIG_MTRR | 1780 | #ifdef CONFIG_MTRR |
1608 | mtrr_del (par->video.mtrr, par->video.pbase, par->video.len); | 1781 | mtrr_del(par->video.mtrr, par->video.pbase, par->video.len); |
1609 | #endif | 1782 | #endif |
1610 | 1783 | ||
1611 | iounmap (par->video.vbase); | 1784 | iounmap(par->video.vbase); |
1612 | par->video.vbase = NULL; | 1785 | par->video.vbase = NULL; |
1613 | info->screen_base = NULL; | 1786 | info->screen_base = NULL; |
1614 | } | 1787 | } |
1615 | } | 1788 | } |
1616 | 1789 | ||
1617 | static int savage_init_hw (struct savagefb_par *par) | 1790 | static int savage_init_hw(struct savagefb_par *par) |
1618 | { | 1791 | { |
1619 | unsigned char config1, m, n, n1, n2, sr8, cr3f, cr66 = 0, tmp; | 1792 | unsigned char config1, m, n, n1, n2, sr8, cr3f, cr66 = 0, tmp; |
1620 | 1793 | ||
@@ -1656,7 +1829,7 @@ static int savage_init_hw (struct savagefb_par *par) | |||
1656 | 1829 | ||
1657 | switch (par->chip) { | 1830 | switch (par->chip) { |
1658 | case S3_SAVAGE3D: | 1831 | case S3_SAVAGE3D: |
1659 | videoRam = RamSavage3D[ (config1 & 0xC0) >> 6 ] * 1024; | 1832 | videoRam = RamSavage3D[(config1 & 0xC0) >> 6 ] * 1024; |
1660 | break; | 1833 | break; |
1661 | 1834 | ||
1662 | case S3_SAVAGE4: | 1835 | case S3_SAVAGE4: |
@@ -1667,22 +1840,22 @@ static int savage_init_hw (struct savagefb_par *par) | |||
1667 | * can do it different... | 1840 | * can do it different... |
1668 | */ | 1841 | */ |
1669 | vga_out8(0x3d4, 0x68, par); /* memory control 1 */ | 1842 | vga_out8(0x3d4, 0x68, par); /* memory control 1 */ |
1670 | if( (vga_in8(0x3d5, par) & 0xC0) == (0x01 << 6) ) | 1843 | if ((vga_in8(0x3d5, par) & 0xC0) == (0x01 << 6)) |
1671 | RamSavage4[1] = 8; | 1844 | RamSavage4[1] = 8; |
1672 | 1845 | ||
1673 | /*FALLTHROUGH*/ | 1846 | /*FALLTHROUGH*/ |
1674 | 1847 | ||
1675 | case S3_SAVAGE2000: | 1848 | case S3_SAVAGE2000: |
1676 | videoRam = RamSavage4[ (config1 & 0xE0) >> 5 ] * 1024; | 1849 | videoRam = RamSavage4[(config1 & 0xE0) >> 5] * 1024; |
1677 | break; | 1850 | break; |
1678 | 1851 | ||
1679 | case S3_SAVAGE_MX: | 1852 | case S3_SAVAGE_MX: |
1680 | case S3_SUPERSAVAGE: | 1853 | case S3_SUPERSAVAGE: |
1681 | videoRam = RamSavageMX[ (config1 & 0x0E) >> 1 ] * 1024; | 1854 | videoRam = RamSavageMX[(config1 & 0x0E) >> 1] * 1024; |
1682 | break; | 1855 | break; |
1683 | 1856 | ||
1684 | case S3_PROSAVAGE: | 1857 | case S3_PROSAVAGE: |
1685 | videoRam = RamSavageNB[ (config1 & 0xE0) >> 5 ] * 1024; | 1858 | videoRam = RamSavageNB[(config1 & 0xE0) >> 5] * 1024; |
1686 | break; | 1859 | break; |
1687 | 1860 | ||
1688 | default: | 1861 | default: |
@@ -1693,31 +1866,31 @@ static int savage_init_hw (struct savagefb_par *par) | |||
1693 | 1866 | ||
1694 | videoRambytes = videoRam * 1024; | 1867 | videoRambytes = videoRam * 1024; |
1695 | 1868 | ||
1696 | printk (KERN_INFO "savagefb: probed videoram: %dk\n", videoRam); | 1869 | printk(KERN_INFO "savagefb: probed videoram: %dk\n", videoRam); |
1697 | 1870 | ||
1698 | /* reset graphics engine to avoid memory corruption */ | 1871 | /* reset graphics engine to avoid memory corruption */ |
1699 | vga_out8 (0x3d4, 0x66, par); | 1872 | vga_out8(0x3d4, 0x66, par); |
1700 | cr66 = vga_in8 (0x3d5, par); | 1873 | cr66 = vga_in8(0x3d5, par); |
1701 | vga_out8 (0x3d5, cr66 | 0x02, par); | 1874 | vga_out8(0x3d5, cr66 | 0x02, par); |
1702 | udelay (10000); | 1875 | udelay(10000); |
1703 | 1876 | ||
1704 | vga_out8 (0x3d4, 0x66, par); | 1877 | vga_out8(0x3d4, 0x66, par); |
1705 | vga_out8 (0x3d5, cr66 & ~0x02, par); /* clear reset flag */ | 1878 | vga_out8(0x3d5, cr66 & ~0x02, par); /* clear reset flag */ |
1706 | udelay (10000); | 1879 | udelay(10000); |
1707 | 1880 | ||
1708 | 1881 | ||
1709 | /* | 1882 | /* |
1710 | * reset memory interface, 3D engine, AGP master, PCI master, | 1883 | * reset memory interface, 3D engine, AGP master, PCI master, |
1711 | * master engine unit, motion compensation/LPB | 1884 | * master engine unit, motion compensation/LPB |
1712 | */ | 1885 | */ |
1713 | vga_out8 (0x3d4, 0x3f, par); | 1886 | vga_out8(0x3d4, 0x3f, par); |
1714 | cr3f = vga_in8 (0x3d5, par); | 1887 | cr3f = vga_in8(0x3d5, par); |
1715 | vga_out8 (0x3d5, cr3f | 0x08, par); | 1888 | vga_out8(0x3d5, cr3f | 0x08, par); |
1716 | udelay (10000); | 1889 | udelay(10000); |
1717 | 1890 | ||
1718 | vga_out8 (0x3d4, 0x3f, par); | 1891 | vga_out8(0x3d4, 0x3f, par); |
1719 | vga_out8 (0x3d5, cr3f & ~0x08, par); /* clear reset flags */ | 1892 | vga_out8(0x3d5, cr3f & ~0x08, par); /* clear reset flags */ |
1720 | udelay (10000); | 1893 | udelay(10000); |
1721 | 1894 | ||
1722 | /* Savage ramdac speeds */ | 1895 | /* Savage ramdac speeds */ |
1723 | par->numClocks = 4; | 1896 | par->numClocks = 4; |
@@ -1740,7 +1913,7 @@ static int savage_init_hw (struct savagefb_par *par) | |||
1740 | n1 = n & 0x1f; | 1913 | n1 = n & 0x1f; |
1741 | n2 = (n >> 5) & 0x03; | 1914 | n2 = (n >> 5) & 0x03; |
1742 | par->MCLK = ((1431818 * (m+2)) / (n1+2) / (1 << n2) + 50) / 100; | 1915 | par->MCLK = ((1431818 * (m+2)) / (n1+2) / (1 << n2) + 50) / 100; |
1743 | printk (KERN_INFO "savagefb: Detected current MCLK value of %d kHz\n", | 1916 | printk(KERN_INFO "savagefb: Detected current MCLK value of %d kHz\n", |
1744 | par->MCLK); | 1917 | par->MCLK); |
1745 | 1918 | ||
1746 | /* check for DVI/flat panel */ | 1919 | /* check for DVI/flat panel */ |
@@ -1769,12 +1942,12 @@ static int savage_init_hw (struct savagefb_par *par) | |||
1769 | /* Check LCD panel parrmation */ | 1942 | /* Check LCD panel parrmation */ |
1770 | 1943 | ||
1771 | if (par->display_type == DISP_LCD) { | 1944 | if (par->display_type == DISP_LCD) { |
1772 | unsigned char cr6b = VGArCR( 0x6b, par); | 1945 | unsigned char cr6b = VGArCR(0x6b, par); |
1773 | 1946 | ||
1774 | int panelX = (VGArSEQ (0x61, par) + | 1947 | int panelX = (VGArSEQ(0x61, par) + |
1775 | ((VGArSEQ (0x66, par) & 0x02) << 7) + 1) * 8; | 1948 | ((VGArSEQ(0x66, par) & 0x02) << 7) + 1) * 8; |
1776 | int panelY = (VGArSEQ (0x69, par) + | 1949 | int panelY = (VGArSEQ(0x69, par) + |
1777 | ((VGArSEQ (0x6e, par) & 0x70) << 4) + 1); | 1950 | ((VGArSEQ(0x6e, par) & 0x70) << 4) + 1); |
1778 | 1951 | ||
1779 | char * sTechnology = "Unknown"; | 1952 | char * sTechnology = "Unknown"; |
1780 | 1953 | ||
@@ -1796,26 +1969,26 @@ static int savage_init_hw (struct savagefb_par *par) | |||
1796 | ActiveDUO = 0x80 | 1969 | ActiveDUO = 0x80 |
1797 | }; | 1970 | }; |
1798 | 1971 | ||
1799 | if ((VGArSEQ (0x39, par) & 0x03) == 0) { | 1972 | if ((VGArSEQ(0x39, par) & 0x03) == 0) { |
1800 | sTechnology = "TFT"; | 1973 | sTechnology = "TFT"; |
1801 | } else if ((VGArSEQ (0x30, par) & 0x01) == 0) { | 1974 | } else if ((VGArSEQ(0x30, par) & 0x01) == 0) { |
1802 | sTechnology = "DSTN"; | 1975 | sTechnology = "DSTN"; |
1803 | } else { | 1976 | } else { |
1804 | sTechnology = "STN"; | 1977 | sTechnology = "STN"; |
1805 | } | 1978 | } |
1806 | 1979 | ||
1807 | printk (KERN_INFO "savagefb: %dx%d %s LCD panel detected %s\n", | 1980 | printk(KERN_INFO "savagefb: %dx%d %s LCD panel detected %s\n", |
1808 | panelX, panelY, sTechnology, | 1981 | panelX, panelY, sTechnology, |
1809 | cr6b & ActiveLCD ? "and active" : "but not active"); | 1982 | cr6b & ActiveLCD ? "and active" : "but not active"); |
1810 | 1983 | ||
1811 | if( cr6b & ActiveLCD ) { | 1984 | if (cr6b & ActiveLCD) { |
1812 | /* | 1985 | /* |
1813 | * If the LCD is active and panel expansion is enabled, | 1986 | * If the LCD is active and panel expansion is enabled, |
1814 | * we probably want to kill the HW cursor. | 1987 | * we probably want to kill the HW cursor. |
1815 | */ | 1988 | */ |
1816 | 1989 | ||
1817 | printk (KERN_INFO "savagefb: Limiting video mode to " | 1990 | printk(KERN_INFO "savagefb: Limiting video mode to " |
1818 | "%dx%d\n", panelX, panelY ); | 1991 | "%dx%d\n", panelX, panelY); |
1819 | 1992 | ||
1820 | par->SavagePanelWidth = panelX; | 1993 | par->SavagePanelWidth = panelX; |
1821 | par->SavagePanelHeight = panelY; | 1994 | par->SavagePanelHeight = panelY; |
@@ -1824,9 +1997,10 @@ static int savage_init_hw (struct savagefb_par *par) | |||
1824 | par->display_type = DISP_CRT; | 1997 | par->display_type = DISP_CRT; |
1825 | } | 1998 | } |
1826 | 1999 | ||
1827 | savage_get_default_par (par); | 2000 | savage_get_default_par(par, &par->state); |
2001 | par->save = par->state; | ||
1828 | 2002 | ||
1829 | if( S3_SAVAGE4_SERIES(par->chip) ) { | 2003 | if (S3_SAVAGE4_SERIES(par->chip)) { |
1830 | /* | 2004 | /* |
1831 | * The Savage4 and ProSavage have COB coherency bugs which | 2005 | * The Savage4 and ProSavage have COB coherency bugs which |
1832 | * render the buffer useless. We disable it. | 2006 | * render the buffer useless. We disable it. |
@@ -1845,9 +2019,9 @@ static int savage_init_hw (struct savagefb_par *par) | |||
1845 | return videoRambytes; | 2019 | return videoRambytes; |
1846 | } | 2020 | } |
1847 | 2021 | ||
1848 | static int __devinit savage_init_fb_info (struct fb_info *info, | 2022 | static int __devinit savage_init_fb_info(struct fb_info *info, |
1849 | struct pci_dev *dev, | 2023 | struct pci_dev *dev, |
1850 | const struct pci_device_id *id) | 2024 | const struct pci_device_id *id) |
1851 | { | 2025 | { |
1852 | struct savagefb_par *par = info->par; | 2026 | struct savagefb_par *par = info->par; |
1853 | int err = 0; | 2027 | int err = 0; |
@@ -1863,63 +2037,63 @@ static int __devinit savage_init_fb_info (struct fb_info *info, | |||
1863 | switch (info->fix.accel) { | 2037 | switch (info->fix.accel) { |
1864 | case FB_ACCEL_SUPERSAVAGE: | 2038 | case FB_ACCEL_SUPERSAVAGE: |
1865 | par->chip = S3_SUPERSAVAGE; | 2039 | par->chip = S3_SUPERSAVAGE; |
1866 | snprintf (info->fix.id, 16, "SuperSavage"); | 2040 | snprintf(info->fix.id, 16, "SuperSavage"); |
1867 | break; | 2041 | break; |
1868 | case FB_ACCEL_SAVAGE4: | 2042 | case FB_ACCEL_SAVAGE4: |
1869 | par->chip = S3_SAVAGE4; | 2043 | par->chip = S3_SAVAGE4; |
1870 | snprintf (info->fix.id, 16, "Savage4"); | 2044 | snprintf(info->fix.id, 16, "Savage4"); |
1871 | break; | 2045 | break; |
1872 | case FB_ACCEL_SAVAGE3D: | 2046 | case FB_ACCEL_SAVAGE3D: |
1873 | par->chip = S3_SAVAGE3D; | 2047 | par->chip = S3_SAVAGE3D; |
1874 | snprintf (info->fix.id, 16, "Savage3D"); | 2048 | snprintf(info->fix.id, 16, "Savage3D"); |
1875 | break; | 2049 | break; |
1876 | case FB_ACCEL_SAVAGE3D_MV: | 2050 | case FB_ACCEL_SAVAGE3D_MV: |
1877 | par->chip = S3_SAVAGE3D; | 2051 | par->chip = S3_SAVAGE3D; |
1878 | snprintf (info->fix.id, 16, "Savage3D-MV"); | 2052 | snprintf(info->fix.id, 16, "Savage3D-MV"); |
1879 | break; | 2053 | break; |
1880 | case FB_ACCEL_SAVAGE2000: | 2054 | case FB_ACCEL_SAVAGE2000: |
1881 | par->chip = S3_SAVAGE2000; | 2055 | par->chip = S3_SAVAGE2000; |
1882 | snprintf (info->fix.id, 16, "Savage2000"); | 2056 | snprintf(info->fix.id, 16, "Savage2000"); |
1883 | break; | 2057 | break; |
1884 | case FB_ACCEL_SAVAGE_MX_MV: | 2058 | case FB_ACCEL_SAVAGE_MX_MV: |
1885 | par->chip = S3_SAVAGE_MX; | 2059 | par->chip = S3_SAVAGE_MX; |
1886 | snprintf (info->fix.id, 16, "Savage/MX-MV"); | 2060 | snprintf(info->fix.id, 16, "Savage/MX-MV"); |
1887 | break; | 2061 | break; |
1888 | case FB_ACCEL_SAVAGE_MX: | 2062 | case FB_ACCEL_SAVAGE_MX: |
1889 | par->chip = S3_SAVAGE_MX; | 2063 | par->chip = S3_SAVAGE_MX; |
1890 | snprintf (info->fix.id, 16, "Savage/MX"); | 2064 | snprintf(info->fix.id, 16, "Savage/MX"); |
1891 | break; | 2065 | break; |
1892 | case FB_ACCEL_SAVAGE_IX_MV: | 2066 | case FB_ACCEL_SAVAGE_IX_MV: |
1893 | par->chip = S3_SAVAGE_MX; | 2067 | par->chip = S3_SAVAGE_MX; |
1894 | snprintf (info->fix.id, 16, "Savage/IX-MV"); | 2068 | snprintf(info->fix.id, 16, "Savage/IX-MV"); |
1895 | break; | 2069 | break; |
1896 | case FB_ACCEL_SAVAGE_IX: | 2070 | case FB_ACCEL_SAVAGE_IX: |
1897 | par->chip = S3_SAVAGE_MX; | 2071 | par->chip = S3_SAVAGE_MX; |
1898 | snprintf (info->fix.id, 16, "Savage/IX"); | 2072 | snprintf(info->fix.id, 16, "Savage/IX"); |
1899 | break; | 2073 | break; |
1900 | case FB_ACCEL_PROSAVAGE_PM: | 2074 | case FB_ACCEL_PROSAVAGE_PM: |
1901 | par->chip = S3_PROSAVAGE; | 2075 | par->chip = S3_PROSAVAGE; |
1902 | snprintf (info->fix.id, 16, "ProSavagePM"); | 2076 | snprintf(info->fix.id, 16, "ProSavagePM"); |
1903 | break; | 2077 | break; |
1904 | case FB_ACCEL_PROSAVAGE_KM: | 2078 | case FB_ACCEL_PROSAVAGE_KM: |
1905 | par->chip = S3_PROSAVAGE; | 2079 | par->chip = S3_PROSAVAGE; |
1906 | snprintf (info->fix.id, 16, "ProSavageKM"); | 2080 | snprintf(info->fix.id, 16, "ProSavageKM"); |
1907 | break; | 2081 | break; |
1908 | case FB_ACCEL_S3TWISTER_P: | 2082 | case FB_ACCEL_S3TWISTER_P: |
1909 | par->chip = S3_PROSAVAGE; | 2083 | par->chip = S3_PROSAVAGE; |
1910 | snprintf (info->fix.id, 16, "TwisterP"); | 2084 | snprintf(info->fix.id, 16, "TwisterP"); |
1911 | break; | 2085 | break; |
1912 | case FB_ACCEL_S3TWISTER_K: | 2086 | case FB_ACCEL_S3TWISTER_K: |
1913 | par->chip = S3_PROSAVAGE; | 2087 | par->chip = S3_PROSAVAGE; |
1914 | snprintf (info->fix.id, 16, "TwisterK"); | 2088 | snprintf(info->fix.id, 16, "TwisterK"); |
1915 | break; | 2089 | break; |
1916 | case FB_ACCEL_PROSAVAGE_DDR: | 2090 | case FB_ACCEL_PROSAVAGE_DDR: |
1917 | par->chip = S3_PROSAVAGE; | 2091 | par->chip = S3_PROSAVAGE; |
1918 | snprintf (info->fix.id, 16, "ProSavageDDR"); | 2092 | snprintf(info->fix.id, 16, "ProSavageDDR"); |
1919 | break; | 2093 | break; |
1920 | case FB_ACCEL_PROSAVAGE_DDRK: | 2094 | case FB_ACCEL_PROSAVAGE_DDRK: |
1921 | par->chip = S3_PROSAVAGE; | 2095 | par->chip = S3_PROSAVAGE; |
1922 | snprintf (info->fix.id, 16, "ProSavage8"); | 2096 | snprintf(info->fix.id, 16, "ProSavage8"); |
1923 | break; | 2097 | break; |
1924 | } | 2098 | } |
1925 | 2099 | ||
@@ -1960,7 +2134,7 @@ static int __devinit savage_init_fb_info (struct fb_info *info, | |||
1960 | info->pixmap.buf_align = 4; | 2134 | info->pixmap.buf_align = 4; |
1961 | info->pixmap.access_align = 32; | 2135 | info->pixmap.access_align = 32; |
1962 | 2136 | ||
1963 | err = fb_alloc_cmap (&info->cmap, NR_PALETTE, 0); | 2137 | err = fb_alloc_cmap(&info->cmap, NR_PALETTE, 0); |
1964 | if (!err) | 2138 | if (!err) |
1965 | info->flags |= FBINFO_HWACCEL_COPYAREA | | 2139 | info->flags |= FBINFO_HWACCEL_COPYAREA | |
1966 | FBINFO_HWACCEL_FILLRECT | | 2140 | FBINFO_HWACCEL_FILLRECT | |
@@ -1972,8 +2146,8 @@ static int __devinit savage_init_fb_info (struct fb_info *info, | |||
1972 | 2146 | ||
1973 | /* --------------------------------------------------------------------- */ | 2147 | /* --------------------------------------------------------------------- */ |
1974 | 2148 | ||
1975 | static int __devinit savagefb_probe (struct pci_dev* dev, | 2149 | static int __devinit savagefb_probe(struct pci_dev* dev, |
1976 | const struct pci_device_id* id) | 2150 | const struct pci_device_id* id) |
1977 | { | 2151 | { |
1978 | struct fb_info *info; | 2152 | struct fb_info *info; |
1979 | struct savagefb_par *par; | 2153 | struct savagefb_par *par; |
@@ -2085,12 +2259,12 @@ static int __devinit savagefb_probe (struct pci_dev* dev, | |||
2085 | fb_destroy_modedb(info->monspecs.modedb); | 2259 | fb_destroy_modedb(info->monspecs.modedb); |
2086 | info->monspecs.modedb = NULL; | 2260 | info->monspecs.modedb = NULL; |
2087 | 2261 | ||
2088 | err = register_framebuffer (info); | 2262 | err = register_framebuffer(info); |
2089 | if (err < 0) | 2263 | if (err < 0) |
2090 | goto failed; | 2264 | goto failed; |
2091 | 2265 | ||
2092 | printk (KERN_INFO "fb: S3 %s frame buffer device\n", | 2266 | printk(KERN_INFO "fb: S3 %s frame buffer device\n", |
2093 | info->fix.id); | 2267 | info->fix.id); |
2094 | 2268 | ||
2095 | /* | 2269 | /* |
2096 | * Our driver data | 2270 | * Our driver data |
@@ -2103,10 +2277,10 @@ static int __devinit savagefb_probe (struct pci_dev* dev, | |||
2103 | #ifdef CONFIG_FB_SAVAGE_I2C | 2277 | #ifdef CONFIG_FB_SAVAGE_I2C |
2104 | savagefb_delete_i2c_busses(info); | 2278 | savagefb_delete_i2c_busses(info); |
2105 | #endif | 2279 | #endif |
2106 | fb_alloc_cmap (&info->cmap, 0, 0); | 2280 | fb_alloc_cmap(&info->cmap, 0, 0); |
2107 | savage_unmap_video(info); | 2281 | savage_unmap_video(info); |
2108 | failed_video: | 2282 | failed_video: |
2109 | savage_unmap_mmio (info); | 2283 | savage_unmap_mmio(info); |
2110 | failed_mmio: | 2284 | failed_mmio: |
2111 | kfree(info->pixmap.addr); | 2285 | kfree(info->pixmap.addr); |
2112 | failed_init: | 2286 | failed_init: |
@@ -2117,7 +2291,7 @@ static int __devinit savagefb_probe (struct pci_dev* dev, | |||
2117 | return err; | 2291 | return err; |
2118 | } | 2292 | } |
2119 | 2293 | ||
2120 | static void __devexit savagefb_remove (struct pci_dev *dev) | 2294 | static void __devexit savagefb_remove(struct pci_dev *dev) |
2121 | { | 2295 | { |
2122 | struct fb_info *info = pci_get_drvdata(dev); | 2296 | struct fb_info *info = pci_get_drvdata(dev); |
2123 | 2297 | ||
@@ -2129,16 +2303,16 @@ static void __devexit savagefb_remove (struct pci_dev *dev) | |||
2129 | * we will be leaving hooks that could cause | 2303 | * we will be leaving hooks that could cause |
2130 | * oopsen laying around. | 2304 | * oopsen laying around. |
2131 | */ | 2305 | */ |
2132 | if (unregister_framebuffer (info)) | 2306 | if (unregister_framebuffer(info)) |
2133 | printk (KERN_WARNING "savagefb: danger danger! " | 2307 | printk(KERN_WARNING "savagefb: danger danger! " |
2134 | "Oopsen imminent!\n"); | 2308 | "Oopsen imminent!\n"); |
2135 | 2309 | ||
2136 | #ifdef CONFIG_FB_SAVAGE_I2C | 2310 | #ifdef CONFIG_FB_SAVAGE_I2C |
2137 | savagefb_delete_i2c_busses(info); | 2311 | savagefb_delete_i2c_busses(info); |
2138 | #endif | 2312 | #endif |
2139 | fb_alloc_cmap (&info->cmap, 0, 0); | 2313 | fb_alloc_cmap(&info->cmap, 0, 0); |
2140 | savage_unmap_video (info); | 2314 | savage_unmap_video(info); |
2141 | savage_unmap_mmio (info); | 2315 | savage_unmap_mmio(info); |
2142 | kfree(info->pixmap.addr); | 2316 | kfree(info->pixmap.addr); |
2143 | pci_release_regions(dev); | 2317 | pci_release_regions(dev); |
2144 | framebuffer_release(info); | 2318 | framebuffer_release(info); |
@@ -2151,7 +2325,7 @@ static void __devexit savagefb_remove (struct pci_dev *dev) | |||
2151 | } | 2325 | } |
2152 | } | 2326 | } |
2153 | 2327 | ||
2154 | static int savagefb_suspend (struct pci_dev* dev, pm_message_t state) | 2328 | static int savagefb_suspend(struct pci_dev* dev, pm_message_t state) |
2155 | { | 2329 | { |
2156 | struct fb_info *info = pci_get_drvdata(dev); | 2330 | struct fb_info *info = pci_get_drvdata(dev); |
2157 | struct savagefb_par *par = info->par; | 2331 | struct savagefb_par *par = info->par; |
@@ -2177,6 +2351,7 @@ static int savagefb_suspend (struct pci_dev* dev, pm_message_t state) | |||
2177 | info->fbops->fb_sync(info); | 2351 | info->fbops->fb_sync(info); |
2178 | 2352 | ||
2179 | savagefb_blank(FB_BLANK_POWERDOWN, info); | 2353 | savagefb_blank(FB_BLANK_POWERDOWN, info); |
2354 | savage_set_default_par(par, &par->save); | ||
2180 | savage_disable_mmio(par); | 2355 | savage_disable_mmio(par); |
2181 | pci_save_state(dev); | 2356 | pci_save_state(dev); |
2182 | pci_disable_device(dev); | 2357 | pci_disable_device(dev); |
@@ -2186,7 +2361,7 @@ static int savagefb_suspend (struct pci_dev* dev, pm_message_t state) | |||
2186 | return 0; | 2361 | return 0; |
2187 | } | 2362 | } |
2188 | 2363 | ||
2189 | static int savagefb_resume (struct pci_dev* dev) | 2364 | static int savagefb_resume(struct pci_dev* dev) |
2190 | { | 2365 | { |
2191 | struct fb_info *info = pci_get_drvdata(dev); | 2366 | struct fb_info *info = pci_get_drvdata(dev); |
2192 | struct savagefb_par *par = info->par; | 2367 | struct savagefb_par *par = info->par; |
@@ -2210,15 +2385,15 @@ static int savagefb_resume (struct pci_dev* dev) | |||
2210 | pci_set_power_state(dev, PCI_D0); | 2385 | pci_set_power_state(dev, PCI_D0); |
2211 | pci_restore_state(dev); | 2386 | pci_restore_state(dev); |
2212 | 2387 | ||
2213 | if(pci_enable_device(dev)) | 2388 | if (pci_enable_device(dev)) |
2214 | DBG("err"); | 2389 | DBG("err"); |
2215 | 2390 | ||
2216 | pci_set_master(dev); | 2391 | pci_set_master(dev); |
2217 | savage_enable_mmio(par); | 2392 | savage_enable_mmio(par); |
2218 | savage_init_hw(par); | 2393 | savage_init_hw(par); |
2219 | savagefb_set_par (info); | 2394 | savagefb_set_par(info); |
2395 | fb_set_suspend(info, 0); | ||
2220 | savagefb_blank(FB_BLANK_UNBLANK, info); | 2396 | savagefb_blank(FB_BLANK_UNBLANK, info); |
2221 | fb_set_suspend (info, 0); | ||
2222 | release_console_sem(); | 2397 | release_console_sem(); |
2223 | 2398 | ||
2224 | return 0; | 2399 | return 0; |
@@ -2311,10 +2486,10 @@ static struct pci_driver savagefb_driver = { | |||
2311 | 2486 | ||
2312 | /* **************************** exit-time only **************************** */ | 2487 | /* **************************** exit-time only **************************** */ |
2313 | 2488 | ||
2314 | static void __exit savage_done (void) | 2489 | static void __exit savage_done(void) |
2315 | { | 2490 | { |
2316 | DBG("savage_done"); | 2491 | DBG("savage_done"); |
2317 | pci_unregister_driver (&savagefb_driver); | 2492 | pci_unregister_driver(&savagefb_driver); |
2318 | } | 2493 | } |
2319 | 2494 | ||
2320 | 2495 | ||
@@ -2345,7 +2520,7 @@ static int __init savagefb_init(void) | |||
2345 | return -ENODEV; | 2520 | return -ENODEV; |
2346 | 2521 | ||
2347 | savagefb_setup(option); | 2522 | savagefb_setup(option); |
2348 | return pci_register_driver (&savagefb_driver); | 2523 | return pci_register_driver(&savagefb_driver); |
2349 | 2524 | ||
2350 | } | 2525 | } |
2351 | 2526 | ||
diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c index 8adf5bf91eee..c63c0e721b82 100644 --- a/drivers/video/sis/sis_main.c +++ b/drivers/video/sis/sis_main.c | |||
@@ -275,7 +275,7 @@ sisfb_search_mode(char *name, BOOLEAN quiet) | |||
275 | static void __devinit | 275 | static void __devinit |
276 | sisfb_get_vga_mode_from_kernel(void) | 276 | sisfb_get_vga_mode_from_kernel(void) |
277 | { | 277 | { |
278 | #if (defined(__i386__) || defined(__x86_64__)) && defined(CONFIG_VIDEO_SELECT) | 278 | #ifdef CONFIG_X86 |
279 | char mymode[32]; | 279 | char mymode[32]; |
280 | int mydepth = screen_info.lfb_depth; | 280 | int mydepth = screen_info.lfb_depth; |
281 | 281 | ||
diff --git a/drivers/video/skeletonfb.c b/drivers/video/skeletonfb.c index 9b707771d757..67f429e93189 100644 --- a/drivers/video/skeletonfb.c +++ b/drivers/video/skeletonfb.c | |||
@@ -906,11 +906,6 @@ static void __exit xxxfb_exit(void) | |||
906 | } | 906 | } |
907 | #endif | 907 | #endif |
908 | 908 | ||
909 | MODULE_LICENSE("GPL"); | ||
910 | module_init(xxxfb_init); | ||
911 | module_exit(xxxfb_exit); | ||
912 | |||
913 | |||
914 | /* | 909 | /* |
915 | * Setup | 910 | * Setup |
916 | */ | 911 | */ |
diff --git a/drivers/video/tgafb.c b/drivers/video/tgafb.c index 7398bd48ba6c..6c2c78ab9827 100644 --- a/drivers/video/tgafb.c +++ b/drivers/video/tgafb.c | |||
@@ -26,7 +26,6 @@ | |||
26 | #include <linux/selection.h> | 26 | #include <linux/selection.h> |
27 | #include <asm/io.h> | 27 | #include <asm/io.h> |
28 | #include <video/tgafb.h> | 28 | #include <video/tgafb.h> |
29 | #include <linux/selection.h> | ||
30 | 29 | ||
31 | /* | 30 | /* |
32 | * Local functions. | 31 | * Local functions. |
diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c index b0b9acfdd430..5718924b677f 100644 --- a/drivers/video/vesafb.c +++ b/drivers/video/vesafb.c | |||
@@ -51,7 +51,7 @@ static int inverse = 0; | |||
51 | static int mtrr = 0; /* disable mtrr */ | 51 | static int mtrr = 0; /* disable mtrr */ |
52 | static int vram_remap __initdata = 0; /* Set amount of memory to be used */ | 52 | static int vram_remap __initdata = 0; /* Set amount of memory to be used */ |
53 | static int vram_total __initdata = 0; /* Set total amount of memory */ | 53 | static int vram_total __initdata = 0; /* Set total amount of memory */ |
54 | static int pmi_setpal = 0; /* pmi for palette changes ??? */ | 54 | static int pmi_setpal = 1; /* pmi for palette changes ??? */ |
55 | static int ypan = 0; /* 0..nothing, 1..ypan, 2..ywrap */ | 55 | static int ypan = 0; /* 0..nothing, 1..ypan, 2..ywrap */ |
56 | static unsigned short *pmi_base = NULL; | 56 | static unsigned short *pmi_base = NULL; |
57 | static void (*pmi_start)(void); | 57 | static void (*pmi_start)(void); |
@@ -80,15 +80,30 @@ static int vesafb_pan_display(struct fb_var_screeninfo *var, | |||
80 | return 0; | 80 | return 0; |
81 | } | 81 | } |
82 | 82 | ||
83 | static void vesa_setpalette(int regno, unsigned red, unsigned green, | 83 | static int vesa_setpalette(int regno, unsigned red, unsigned green, |
84 | unsigned blue) | 84 | unsigned blue) |
85 | { | 85 | { |
86 | int shift = 16 - depth; | 86 | int shift = 16 - depth; |
87 | int err = -EINVAL; | ||
88 | |||
89 | /* | ||
90 | * Try VGA registers first... | ||
91 | */ | ||
92 | if (vga_compat) { | ||
93 | outb_p(regno, dac_reg); | ||
94 | outb_p(red >> shift, dac_val); | ||
95 | outb_p(green >> shift, dac_val); | ||
96 | outb_p(blue >> shift, dac_val); | ||
97 | err = 0; | ||
98 | } | ||
87 | 99 | ||
88 | #ifdef __i386__ | 100 | #ifdef __i386__ |
89 | struct { u_char blue, green, red, pad; } entry; | 101 | /* |
102 | * Fallback to the PMI.... | ||
103 | */ | ||
104 | if (err && pmi_setpal) { | ||
105 | struct { u_char blue, green, red, pad; } entry; | ||
90 | 106 | ||
91 | if (pmi_setpal) { | ||
92 | entry.red = red >> shift; | 107 | entry.red = red >> shift; |
93 | entry.green = green >> shift; | 108 | entry.green = green >> shift; |
94 | entry.blue = blue >> shift; | 109 | entry.blue = blue >> shift; |
@@ -102,26 +117,19 @@ static void vesa_setpalette(int regno, unsigned red, unsigned green, | |||
102 | "d" (regno), /* EDX */ | 117 | "d" (regno), /* EDX */ |
103 | "D" (&entry), /* EDI */ | 118 | "D" (&entry), /* EDI */ |
104 | "S" (&pmi_pal)); /* ESI */ | 119 | "S" (&pmi_pal)); /* ESI */ |
105 | return; | 120 | err = 0; |
106 | } | 121 | } |
107 | #endif | 122 | #endif |
108 | 123 | ||
109 | /* | 124 | return err; |
110 | * without protected mode interface and if VGA compatible, | ||
111 | * try VGA registers... | ||
112 | */ | ||
113 | if (vga_compat) { | ||
114 | outb_p(regno, dac_reg); | ||
115 | outb_p(red >> shift, dac_val); | ||
116 | outb_p(green >> shift, dac_val); | ||
117 | outb_p(blue >> shift, dac_val); | ||
118 | } | ||
119 | } | 125 | } |
120 | 126 | ||
121 | static int vesafb_setcolreg(unsigned regno, unsigned red, unsigned green, | 127 | static int vesafb_setcolreg(unsigned regno, unsigned red, unsigned green, |
122 | unsigned blue, unsigned transp, | 128 | unsigned blue, unsigned transp, |
123 | struct fb_info *info) | 129 | struct fb_info *info) |
124 | { | 130 | { |
131 | int err = 0; | ||
132 | |||
125 | /* | 133 | /* |
126 | * Set a single color register. The values supplied are | 134 | * Set a single color register. The values supplied are |
127 | * already rounded down to the hardware's capabilities | 135 | * already rounded down to the hardware's capabilities |
@@ -133,7 +141,7 @@ static int vesafb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
133 | return 1; | 141 | return 1; |
134 | 142 | ||
135 | if (info->var.bits_per_pixel == 8) | 143 | if (info->var.bits_per_pixel == 8) |
136 | vesa_setpalette(regno,red,green,blue); | 144 | err = vesa_setpalette(regno,red,green,blue); |
137 | else if (regno < 16) { | 145 | else if (regno < 16) { |
138 | switch (info->var.bits_per_pixel) { | 146 | switch (info->var.bits_per_pixel) { |
139 | case 16: | 147 | case 16: |
@@ -164,7 +172,7 @@ static int vesafb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
164 | } | 172 | } |
165 | } | 173 | } |
166 | 174 | ||
167 | return 0; | 175 | return err; |
168 | } | 176 | } |
169 | 177 | ||
170 | static struct fb_ops vesafb_ops = { | 178 | static struct fb_ops vesafb_ops = { |
@@ -460,9 +468,7 @@ static struct platform_driver vesafb_driver = { | |||
460 | }, | 468 | }, |
461 | }; | 469 | }; |
462 | 470 | ||
463 | static struct platform_device vesafb_device = { | 471 | static struct platform_device *vesafb_device; |
464 | .name = "vesafb", | ||
465 | }; | ||
466 | 472 | ||
467 | static int __init vesafb_init(void) | 473 | static int __init vesafb_init(void) |
468 | { | 474 | { |
@@ -475,10 +481,19 @@ static int __init vesafb_init(void) | |||
475 | ret = platform_driver_register(&vesafb_driver); | 481 | ret = platform_driver_register(&vesafb_driver); |
476 | 482 | ||
477 | if (!ret) { | 483 | if (!ret) { |
478 | ret = platform_device_register(&vesafb_device); | 484 | vesafb_device = platform_device_alloc("vesafb", 0); |
479 | if (ret) | 485 | |
486 | if (vesafb_device) | ||
487 | ret = platform_device_add(vesafb_device); | ||
488 | else | ||
489 | ret = -ENOMEM; | ||
490 | |||
491 | if (ret) { | ||
492 | platform_device_put(vesafb_device); | ||
480 | platform_driver_unregister(&vesafb_driver); | 493 | platform_driver_unregister(&vesafb_driver); |
494 | } | ||
481 | } | 495 | } |
496 | |||
482 | return ret; | 497 | return ret; |
483 | } | 498 | } |
484 | module_init(vesafb_init); | 499 | module_init(vesafb_init); |
diff --git a/drivers/video/vfb.c b/drivers/video/vfb.c index 77eed1fd9943..d073ffb6e1f9 100644 --- a/drivers/video/vfb.c +++ b/drivers/video/vfb.c | |||
@@ -398,12 +398,6 @@ static int __init vfb_setup(char *options) | |||
398 | * Initialisation | 398 | * Initialisation |
399 | */ | 399 | */ |
400 | 400 | ||
401 | static void vfb_platform_release(struct device *device) | ||
402 | { | ||
403 | // This is called when the reference count goes to zero. | ||
404 | dev_err(device, "This driver is broken, please bug the authors so they will fix it.\n"); | ||
405 | } | ||
406 | |||
407 | static int __init vfb_probe(struct platform_device *dev) | 401 | static int __init vfb_probe(struct platform_device *dev) |
408 | { | 402 | { |
409 | struct fb_info *info; | 403 | struct fb_info *info; |
@@ -482,13 +476,7 @@ static struct platform_driver vfb_driver = { | |||
482 | }, | 476 | }, |
483 | }; | 477 | }; |
484 | 478 | ||
485 | static struct platform_device vfb_device = { | 479 | static struct platform_device *vfb_device; |
486 | .name = "vfb", | ||
487 | .id = 0, | ||
488 | .dev = { | ||
489 | .release = vfb_platform_release, | ||
490 | } | ||
491 | }; | ||
492 | 480 | ||
493 | static int __init vfb_init(void) | 481 | static int __init vfb_init(void) |
494 | { | 482 | { |
@@ -508,10 +496,19 @@ static int __init vfb_init(void) | |||
508 | ret = platform_driver_register(&vfb_driver); | 496 | ret = platform_driver_register(&vfb_driver); |
509 | 497 | ||
510 | if (!ret) { | 498 | if (!ret) { |
511 | ret = platform_device_register(&vfb_device); | 499 | vfb_device = platform_device_alloc("vfb", 0); |
512 | if (ret) | 500 | |
501 | if (vfb_device) | ||
502 | ret = platform_device_add(vfb_device); | ||
503 | else | ||
504 | ret = -ENOMEM; | ||
505 | |||
506 | if (ret) { | ||
507 | platform_device_put(vfb_device); | ||
513 | platform_driver_unregister(&vfb_driver); | 508 | platform_driver_unregister(&vfb_driver); |
509 | } | ||
514 | } | 510 | } |
511 | |||
515 | return ret; | 512 | return ret; |
516 | } | 513 | } |
517 | 514 | ||
@@ -520,7 +517,7 @@ module_init(vfb_init); | |||
520 | #ifdef MODULE | 517 | #ifdef MODULE |
521 | static void __exit vfb_exit(void) | 518 | static void __exit vfb_exit(void) |
522 | { | 519 | { |
523 | platform_device_unregister(&vfb_device); | 520 | platform_device_unregister(vfb_device); |
524 | platform_driver_unregister(&vfb_driver); | 521 | platform_driver_unregister(&vfb_driver); |
525 | } | 522 | } |
526 | 523 | ||
diff --git a/drivers/video/vga16fb.c b/drivers/video/vga16fb.c index 4fd2a272e03d..3c404c9bd36c 100644 --- a/drivers/video/vga16fb.c +++ b/drivers/video/vga16fb.c | |||
@@ -1334,9 +1334,8 @@ static int vga16fb_setup(char *options) | |||
1334 | } | 1334 | } |
1335 | #endif | 1335 | #endif |
1336 | 1336 | ||
1337 | static int __init vga16fb_probe(struct device *device) | 1337 | static int __init vga16fb_probe(struct platform_device *dev) |
1338 | { | 1338 | { |
1339 | struct platform_device *dev = to_platform_device(device); | ||
1340 | struct fb_info *info; | 1339 | struct fb_info *info; |
1341 | struct vga16fb_par *par; | 1340 | struct vga16fb_par *par; |
1342 | int i; | 1341 | int i; |
@@ -1403,7 +1402,7 @@ static int __init vga16fb_probe(struct device *device) | |||
1403 | 1402 | ||
1404 | printk(KERN_INFO "fb%d: %s frame buffer device\n", | 1403 | printk(KERN_INFO "fb%d: %s frame buffer device\n", |
1405 | info->node, info->fix.id); | 1404 | info->node, info->fix.id); |
1406 | dev_set_drvdata(device, info); | 1405 | platform_set_drvdata(dev, info); |
1407 | 1406 | ||
1408 | return 0; | 1407 | return 0; |
1409 | 1408 | ||
@@ -1417,9 +1416,9 @@ static int __init vga16fb_probe(struct device *device) | |||
1417 | return ret; | 1416 | return ret; |
1418 | } | 1417 | } |
1419 | 1418 | ||
1420 | static int vga16fb_remove(struct device *device) | 1419 | static int vga16fb_remove(struct platform_device *dev) |
1421 | { | 1420 | { |
1422 | struct fb_info *info = dev_get_drvdata(device); | 1421 | struct fb_info *info = platform_get_drvdata(dev); |
1423 | 1422 | ||
1424 | if (info) { | 1423 | if (info) { |
1425 | unregister_framebuffer(info); | 1424 | unregister_framebuffer(info); |
@@ -1432,16 +1431,15 @@ static int vga16fb_remove(struct device *device) | |||
1432 | return 0; | 1431 | return 0; |
1433 | } | 1432 | } |
1434 | 1433 | ||
1435 | static struct device_driver vga16fb_driver = { | 1434 | static struct platform_driver vga16fb_driver = { |
1436 | .name = "vga16fb", | ||
1437 | .bus = &platform_bus_type, | ||
1438 | .probe = vga16fb_probe, | 1435 | .probe = vga16fb_probe, |
1439 | .remove = vga16fb_remove, | 1436 | .remove = vga16fb_remove, |
1437 | .driver = { | ||
1438 | .name = "vga16fb", | ||
1439 | }, | ||
1440 | }; | 1440 | }; |
1441 | 1441 | ||
1442 | static struct platform_device vga16fb_device = { | 1442 | static struct platform_device *vga16fb_device; |
1443 | .name = "vga16fb", | ||
1444 | }; | ||
1445 | 1443 | ||
1446 | static int __init vga16fb_init(void) | 1444 | static int __init vga16fb_init(void) |
1447 | { | 1445 | { |
@@ -1454,12 +1452,20 @@ static int __init vga16fb_init(void) | |||
1454 | 1452 | ||
1455 | vga16fb_setup(option); | 1453 | vga16fb_setup(option); |
1456 | #endif | 1454 | #endif |
1457 | ret = driver_register(&vga16fb_driver); | 1455 | ret = platform_driver_register(&vga16fb_driver); |
1458 | 1456 | ||
1459 | if (!ret) { | 1457 | if (!ret) { |
1460 | ret = platform_device_register(&vga16fb_device); | 1458 | vga16fb_device = platform_device_alloc("vga16fb", 0); |
1461 | if (ret) | 1459 | |
1462 | driver_unregister(&vga16fb_driver); | 1460 | if (vga16fb_device) |
1461 | ret = platform_device_add(vga16fb_device); | ||
1462 | else | ||
1463 | ret = -ENOMEM; | ||
1464 | |||
1465 | if (ret) { | ||
1466 | platform_device_put(vga16fb_device); | ||
1467 | platform_driver_unregister(&vga16fb_driver); | ||
1468 | } | ||
1463 | } | 1469 | } |
1464 | 1470 | ||
1465 | return ret; | 1471 | return ret; |
@@ -1467,8 +1473,8 @@ static int __init vga16fb_init(void) | |||
1467 | 1473 | ||
1468 | static void __exit vga16fb_exit(void) | 1474 | static void __exit vga16fb_exit(void) |
1469 | { | 1475 | { |
1470 | platform_device_unregister(&vga16fb_device); | 1476 | platform_device_unregister(vga16fb_device); |
1471 | driver_unregister(&vga16fb_driver); | 1477 | platform_driver_unregister(&vga16fb_driver); |
1472 | } | 1478 | } |
1473 | 1479 | ||
1474 | MODULE_LICENSE("GPL"); | 1480 | MODULE_LICENSE("GPL"); |