diff options
Diffstat (limited to 'drivers/char')
29 files changed, 1464 insertions, 86 deletions
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 39a9f8cc6412..2af12fc45115 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig | |||
@@ -409,14 +409,6 @@ config SGI_MBCS | |||
409 | If you have an SGI Altix with an attached SABrick | 409 | If you have an SGI Altix with an attached SABrick |
410 | say Y or M here, otherwise say N. | 410 | say Y or M here, otherwise say N. |
411 | 411 | ||
412 | config MSPEC | ||
413 | tristate "Memory special operations driver" | ||
414 | depends on IA64 | ||
415 | help | ||
416 | If you have an ia64 and you want to enable memory special | ||
417 | operations support (formerly known as fetchop), say Y here, | ||
418 | otherwise say N. | ||
419 | |||
420 | source "drivers/serial/Kconfig" | 412 | source "drivers/serial/Kconfig" |
421 | 413 | ||
422 | config UNIX98_PTYS | 414 | config UNIX98_PTYS |
diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c index c39200161688..5ff457b41efb 100644 --- a/drivers/char/agp/generic.c +++ b/drivers/char/agp/generic.c | |||
@@ -1054,7 +1054,7 @@ void *agp_generic_alloc_page(struct agp_bridge_data *bridge) | |||
1054 | { | 1054 | { |
1055 | struct page * page; | 1055 | struct page * page; |
1056 | 1056 | ||
1057 | page = alloc_page(GFP_KERNEL); | 1057 | page = alloc_page(GFP_KERNEL | GFP_DMA32); |
1058 | if (page == NULL) | 1058 | if (page == NULL) |
1059 | return NULL; | 1059 | return NULL; |
1060 | 1060 | ||
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index d1ede7db5a12..555b3a8ab49c 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c | |||
@@ -169,7 +169,7 @@ static void *i8xx_alloc_pages(void) | |||
169 | { | 169 | { |
170 | struct page * page; | 170 | struct page * page; |
171 | 171 | ||
172 | page = alloc_pages(GFP_KERNEL, 2); | 172 | page = alloc_pages(GFP_KERNEL | GFP_DMA32, 2); |
173 | if (page == NULL) | 173 | if (page == NULL) |
174 | return NULL; | 174 | return NULL; |
175 | 175 | ||
@@ -387,11 +387,7 @@ static void intel_i830_init_gtt_entries(void) | |||
387 | /* We obtain the size of the GTT, which is also stored (for some | 387 | /* We obtain the size of the GTT, which is also stored (for some |
388 | * reason) at the top of stolen memory. Then we add 4KB to that | 388 | * reason) at the top of stolen memory. Then we add 4KB to that |
389 | * for the video BIOS popup, which is also stored in there. */ | 389 | * for the video BIOS popup, which is also stored in there. */ |
390 | 390 | size = agp_bridge->driver->fetch_size() + 4; | |
391 | if (IS_I965) | ||
392 | size = 512 + 4; | ||
393 | else | ||
394 | size = agp_bridge->driver->fetch_size() + 4; | ||
395 | 391 | ||
396 | if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82830_HB || | 392 | if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82830_HB || |
397 | agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) { | 393 | agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) { |
@@ -805,6 +801,26 @@ static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge) | |||
805 | 801 | ||
806 | return 0; | 802 | return 0; |
807 | } | 803 | } |
804 | |||
805 | /* | ||
806 | * The i965 supports 36-bit physical addresses, but to keep | ||
807 | * the format of the GTT the same, the bits that don't fit | ||
808 | * in a 32-bit word are shifted down to bits 4..7. | ||
809 | * | ||
810 | * Gcc is smart enough to notice that "(addr >> 28) & 0xf0" | ||
811 | * is always zero on 32-bit architectures, so no need to make | ||
812 | * this conditional. | ||
813 | */ | ||
814 | static unsigned long intel_i965_mask_memory(struct agp_bridge_data *bridge, | ||
815 | unsigned long addr, int type) | ||
816 | { | ||
817 | /* Shift high bits down */ | ||
818 | addr |= (addr >> 28) & 0xf0; | ||
819 | |||
820 | /* Type checking must be done elsewhere */ | ||
821 | return addr | bridge->driver->masks[type].mask; | ||
822 | } | ||
823 | |||
808 | static int intel_i965_fetch_size(void) | 824 | static int intel_i965_fetch_size(void) |
809 | { | 825 | { |
810 | struct aper_size_info_fixed *values; | 826 | struct aper_size_info_fixed *values; |
@@ -832,7 +848,8 @@ static int intel_i965_fetch_size(void) | |||
832 | 848 | ||
833 | agp_bridge->previous_size = agp_bridge->current_size = (void *)(values + offset); | 849 | agp_bridge->previous_size = agp_bridge->current_size = (void *)(values + offset); |
834 | 850 | ||
835 | return values[offset].size; | 851 | /* The i965 GTT is always sized as if it had a 512kB aperture size */ |
852 | return 512; | ||
836 | } | 853 | } |
837 | 854 | ||
838 | /* The intel i965 automatically initializes the agp aperture during POST. | 855 | /* The intel i965 automatically initializes the agp aperture during POST. |
@@ -1584,7 +1601,7 @@ static struct agp_bridge_driver intel_i965_driver = { | |||
1584 | .fetch_size = intel_i965_fetch_size, | 1601 | .fetch_size = intel_i965_fetch_size, |
1585 | .cleanup = intel_i915_cleanup, | 1602 | .cleanup = intel_i915_cleanup, |
1586 | .tlb_flush = intel_i810_tlbflush, | 1603 | .tlb_flush = intel_i810_tlbflush, |
1587 | .mask_memory = intel_i810_mask_memory, | 1604 | .mask_memory = intel_i965_mask_memory, |
1588 | .masks = intel_i810_masks, | 1605 | .masks = intel_i810_masks, |
1589 | .agp_enable = intel_i810_agp_enable, | 1606 | .agp_enable = intel_i810_agp_enable, |
1590 | .cache_flush = global_cache_flush, | 1607 | .cache_flush = global_cache_flush, |
diff --git a/drivers/char/agp/uninorth-agp.c b/drivers/char/agp/uninorth-agp.c index 91b71e750ee1..dffc19382f7e 100644 --- a/drivers/char/agp/uninorth-agp.c +++ b/drivers/char/agp/uninorth-agp.c | |||
@@ -27,32 +27,42 @@ | |||
27 | static int uninorth_rev; | 27 | static int uninorth_rev; |
28 | static int is_u3; | 28 | static int is_u3; |
29 | 29 | ||
30 | static char __devinitdata *aperture = NULL; | ||
30 | 31 | ||
31 | static int uninorth_fetch_size(void) | 32 | static int uninorth_fetch_size(void) |
32 | { | 33 | { |
33 | int i; | 34 | int i, size = 0; |
34 | u32 temp; | 35 | struct aper_size_info_32 *values = |
35 | struct aper_size_info_32 *values; | 36 | A_SIZE_32(agp_bridge->driver->aperture_sizes); |
36 | 37 | ||
37 | pci_read_config_dword(agp_bridge->dev, UNI_N_CFG_GART_BASE, &temp); | 38 | if (aperture) { |
38 | temp &= ~(0xfffff000); | 39 | char *save = aperture; |
39 | values = A_SIZE_32(agp_bridge->driver->aperture_sizes); | 40 | |
40 | 41 | size = memparse(aperture, &aperture) >> 20; | |
41 | for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) { | 42 | aperture = save; |
42 | if (temp == values[i].size_value) { | 43 | |
43 | agp_bridge->previous_size = | 44 | for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) |
44 | agp_bridge->current_size = (void *) (values + i); | 45 | if (size == values[i].size) |
45 | agp_bridge->aperture_size_idx = i; | 46 | break; |
46 | return values[i].size; | 47 | |
48 | if (i == agp_bridge->driver->num_aperture_sizes) { | ||
49 | printk(KERN_ERR PFX "Invalid aperture size, using" | ||
50 | " default\n"); | ||
51 | size = 0; | ||
52 | aperture = NULL; | ||
47 | } | 53 | } |
48 | } | 54 | } |
49 | 55 | ||
50 | agp_bridge->previous_size = | 56 | if (!size) { |
51 | agp_bridge->current_size = (void *) (values + 1); | 57 | for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) |
52 | agp_bridge->aperture_size_idx = 1; | 58 | if (values[i].size == 32) |
53 | return values[1].size; | 59 | break; |
60 | } | ||
54 | 61 | ||
55 | return 0; | 62 | agp_bridge->previous_size = |
63 | agp_bridge->current_size = (void *)(values + i); | ||
64 | agp_bridge->aperture_size_idx = i; | ||
65 | return values[i].size; | ||
56 | } | 66 | } |
57 | 67 | ||
58 | static void uninorth_tlbflush(struct agp_memory *mem) | 68 | static void uninorth_tlbflush(struct agp_memory *mem) |
@@ -683,5 +693,11 @@ static void __exit agp_uninorth_cleanup(void) | |||
683 | module_init(agp_uninorth_init); | 693 | module_init(agp_uninorth_init); |
684 | module_exit(agp_uninorth_cleanup); | 694 | module_exit(agp_uninorth_cleanup); |
685 | 695 | ||
696 | module_param(aperture, charp, 0); | ||
697 | MODULE_PARM_DESC(aperture, | ||
698 | "Aperture size, must be power of two between 4MB and an\n" | ||
699 | "\t\tupper limit specific to the UniNorth revision.\n" | ||
700 | "\t\tDefault: 32M"); | ||
701 | |||
686 | MODULE_AUTHOR("Ben Herrenschmidt & Paul Mackerras"); | 702 | MODULE_AUTHOR("Ben Herrenschmidt & Paul Mackerras"); |
687 | MODULE_LICENSE("GPL"); | 703 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/char/drm/drm_bufs.c b/drivers/char/drm/drm_bufs.c index 029baea33b62..6eafff13dab6 100644 --- a/drivers/char/drm/drm_bufs.c +++ b/drivers/char/drm/drm_bufs.c | |||
@@ -237,6 +237,8 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset, | |||
237 | 237 | ||
238 | list = drm_alloc(sizeof(*list), DRM_MEM_MAPS); | 238 | list = drm_alloc(sizeof(*list), DRM_MEM_MAPS); |
239 | if (!list) { | 239 | if (!list) { |
240 | if (map->type == _DRM_REGISTERS) | ||
241 | drm_ioremapfree(map->handle, map->size, dev); | ||
240 | drm_free(map, sizeof(*map), DRM_MEM_MAPS); | 242 | drm_free(map, sizeof(*map), DRM_MEM_MAPS); |
241 | return -EINVAL; | 243 | return -EINVAL; |
242 | } | 244 | } |
@@ -252,6 +254,8 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset, | |||
252 | map->offset; | 254 | map->offset; |
253 | ret = drm_map_handle(dev, &list->hash, user_token, 0); | 255 | ret = drm_map_handle(dev, &list->hash, user_token, 0); |
254 | if (ret) { | 256 | if (ret) { |
257 | if (map->type == _DRM_REGISTERS) | ||
258 | drm_ioremapfree(map->handle, map->size, dev); | ||
255 | drm_free(map, sizeof(*map), DRM_MEM_MAPS); | 259 | drm_free(map, sizeof(*map), DRM_MEM_MAPS); |
256 | drm_free(list, sizeof(*list), DRM_MEM_MAPS); | 260 | drm_free(list, sizeof(*list), DRM_MEM_MAPS); |
257 | mutex_unlock(&dev->struct_mutex); | 261 | mutex_unlock(&dev->struct_mutex); |
diff --git a/drivers/char/drm/drm_sysfs.c b/drivers/char/drm/drm_sysfs.c index 51ad98c685c3..ba4b8de83cf0 100644 --- a/drivers/char/drm/drm_sysfs.c +++ b/drivers/char/drm/drm_sysfs.c | |||
@@ -42,13 +42,24 @@ static CLASS_ATTR(version, S_IRUGO, version_show, NULL); | |||
42 | struct class *drm_sysfs_create(struct module *owner, char *name) | 42 | struct class *drm_sysfs_create(struct module *owner, char *name) |
43 | { | 43 | { |
44 | struct class *class; | 44 | struct class *class; |
45 | int err; | ||
45 | 46 | ||
46 | class = class_create(owner, name); | 47 | class = class_create(owner, name); |
47 | if (!class) | 48 | if (!class) { |
48 | return class; | 49 | err = -ENOMEM; |
50 | goto err_out; | ||
51 | } | ||
52 | |||
53 | err = class_create_file(class, &class_attr_version); | ||
54 | if (err) | ||
55 | goto err_out_class; | ||
49 | 56 | ||
50 | class_create_file(class, &class_attr_version); | ||
51 | return class; | 57 | return class; |
58 | |||
59 | err_out_class: | ||
60 | class_destroy(class); | ||
61 | err_out: | ||
62 | return ERR_PTR(err); | ||
52 | } | 63 | } |
53 | 64 | ||
54 | /** | 65 | /** |
@@ -96,20 +107,36 @@ static struct class_device_attribute class_device_attrs[] = { | |||
96 | struct class_device *drm_sysfs_device_add(struct class *cs, drm_head_t *head) | 107 | struct class_device *drm_sysfs_device_add(struct class *cs, drm_head_t *head) |
97 | { | 108 | { |
98 | struct class_device *class_dev; | 109 | struct class_device *class_dev; |
99 | int i; | 110 | int i, j, err; |
100 | 111 | ||
101 | class_dev = class_device_create(cs, NULL, | 112 | class_dev = class_device_create(cs, NULL, |
102 | MKDEV(DRM_MAJOR, head->minor), | 113 | MKDEV(DRM_MAJOR, head->minor), |
103 | &(head->dev->pdev)->dev, | 114 | &(head->dev->pdev)->dev, |
104 | "card%d", head->minor); | 115 | "card%d", head->minor); |
105 | if (!class_dev) | 116 | if (!class_dev) { |
106 | return NULL; | 117 | err = -ENOMEM; |
118 | goto err_out; | ||
119 | } | ||
107 | 120 | ||
108 | class_set_devdata(class_dev, head); | 121 | class_set_devdata(class_dev, head); |
109 | 122 | ||
110 | for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) | 123 | for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) { |
111 | class_device_create_file(class_dev, &class_device_attrs[i]); | 124 | err = class_device_create_file(class_dev, |
125 | &class_device_attrs[i]); | ||
126 | if (err) | ||
127 | goto err_out_files; | ||
128 | } | ||
129 | |||
112 | return class_dev; | 130 | return class_dev; |
131 | |||
132 | err_out_files: | ||
133 | if (i > 0) | ||
134 | for (j = 0; j < i; j++) | ||
135 | class_device_remove_file(class_dev, | ||
136 | &class_device_attrs[i]); | ||
137 | class_device_unregister(class_dev); | ||
138 | err_out: | ||
139 | return ERR_PTR(err); | ||
113 | } | 140 | } |
114 | 141 | ||
115 | /** | 142 | /** |
diff --git a/drivers/char/drm/mga_drv.c b/drivers/char/drm/mga_drv.c index e30f556b79f1..be49dbb9ec3f 100644 --- a/drivers/char/drm/mga_drv.c +++ b/drivers/char/drm/mga_drv.c | |||
@@ -47,6 +47,7 @@ static struct drm_driver driver = { | |||
47 | DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | | 47 | DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | |
48 | DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | | 48 | DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | |
49 | DRIVER_IRQ_VBL, | 49 | DRIVER_IRQ_VBL, |
50 | .dev_priv_size = sizeof(drm_mga_buf_priv_t), | ||
50 | .load = mga_driver_load, | 51 | .load = mga_driver_load, |
51 | .unload = mga_driver_unload, | 52 | .unload = mga_driver_unload, |
52 | .lastclose = mga_driver_lastclose, | 53 | .lastclose = mga_driver_lastclose, |
diff --git a/drivers/char/drm/r300_cmdbuf.c b/drivers/char/drm/r300_cmdbuf.c index 26bdf2ca59d7..d14477ba3679 100644 --- a/drivers/char/drm/r300_cmdbuf.c +++ b/drivers/char/drm/r300_cmdbuf.c | |||
@@ -538,6 +538,36 @@ static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv, | |||
538 | return 0; | 538 | return 0; |
539 | } | 539 | } |
540 | 540 | ||
541 | static __inline__ int r300_emit_indx_buffer(drm_radeon_private_t *dev_priv, | ||
542 | drm_radeon_kcmd_buffer_t *cmdbuf) | ||
543 | { | ||
544 | u32 *cmd = (u32 *) cmdbuf->buf; | ||
545 | int count, ret; | ||
546 | RING_LOCALS; | ||
547 | |||
548 | count=(cmd[0]>>16) & 0x3fff; | ||
549 | |||
550 | if ((cmd[1] & 0x8000ffff) != 0x80000810) { | ||
551 | DRM_ERROR("Invalid indx_buffer reg address %08X\n", cmd[1]); | ||
552 | return DRM_ERR(EINVAL); | ||
553 | } | ||
554 | ret = r300_check_offset(dev_priv, cmd[2]); | ||
555 | if (ret) { | ||
556 | DRM_ERROR("Invalid indx_buffer offset is %08X\n", cmd[2]); | ||
557 | return DRM_ERR(EINVAL); | ||
558 | } | ||
559 | |||
560 | BEGIN_RING(count+2); | ||
561 | OUT_RING(cmd[0]); | ||
562 | OUT_RING_TABLE((int *)(cmdbuf->buf + 4), count + 1); | ||
563 | ADVANCE_RING(); | ||
564 | |||
565 | cmdbuf->buf += (count+2)*4; | ||
566 | cmdbuf->bufsz -= (count+2)*4; | ||
567 | |||
568 | return 0; | ||
569 | } | ||
570 | |||
541 | static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv, | 571 | static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv, |
542 | drm_radeon_kcmd_buffer_t *cmdbuf) | 572 | drm_radeon_kcmd_buffer_t *cmdbuf) |
543 | { | 573 | { |
@@ -578,10 +608,11 @@ static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv, | |||
578 | case RADEON_CNTL_BITBLT_MULTI: | 608 | case RADEON_CNTL_BITBLT_MULTI: |
579 | return r300_emit_bitblt_multi(dev_priv, cmdbuf); | 609 | return r300_emit_bitblt_multi(dev_priv, cmdbuf); |
580 | 610 | ||
611 | case RADEON_CP_INDX_BUFFER: /* DRAW_INDX_2 without INDX_BUFFER seems to lock up the gpu */ | ||
612 | return r300_emit_indx_buffer(dev_priv, cmdbuf); | ||
581 | case RADEON_CP_3D_DRAW_IMMD_2: /* triggers drawing using in-packet vertex data */ | 613 | case RADEON_CP_3D_DRAW_IMMD_2: /* triggers drawing using in-packet vertex data */ |
582 | case RADEON_CP_3D_DRAW_VBUF_2: /* triggers drawing of vertex buffers setup elsewhere */ | 614 | case RADEON_CP_3D_DRAW_VBUF_2: /* triggers drawing of vertex buffers setup elsewhere */ |
583 | case RADEON_CP_3D_DRAW_INDX_2: /* triggers drawing using indices to vertex buffer */ | 615 | case RADEON_CP_3D_DRAW_INDX_2: /* triggers drawing using indices to vertex buffer */ |
584 | case RADEON_CP_INDX_BUFFER: /* DRAW_INDX_2 without INDX_BUFFER seems to lock up the gpu */ | ||
585 | case RADEON_WAIT_FOR_IDLE: | 616 | case RADEON_WAIT_FOR_IDLE: |
586 | case RADEON_CP_NOP: | 617 | case RADEON_CP_NOP: |
587 | /* these packets are safe */ | 618 | /* these packets are safe */ |
diff --git a/drivers/char/drm/radeon_state.c b/drivers/char/drm/radeon_state.c index feac5f005d47..6e04fdd732ac 100644 --- a/drivers/char/drm/radeon_state.c +++ b/drivers/char/drm/radeon_state.c | |||
@@ -275,6 +275,8 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t * | |||
275 | unsigned int *cmdsz) | 275 | unsigned int *cmdsz) |
276 | { | 276 | { |
277 | u32 *cmd = (u32 *) cmdbuf->buf; | 277 | u32 *cmd = (u32 *) cmdbuf->buf; |
278 | u32 offset, narrays; | ||
279 | int count, i, k; | ||
278 | 280 | ||
279 | *cmdsz = 2 + ((cmd[0] & RADEON_CP_PACKET_COUNT_MASK) >> 16); | 281 | *cmdsz = 2 + ((cmd[0] & RADEON_CP_PACKET_COUNT_MASK) >> 16); |
280 | 282 | ||
@@ -288,10 +290,106 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t * | |||
288 | return DRM_ERR(EINVAL); | 290 | return DRM_ERR(EINVAL); |
289 | } | 291 | } |
290 | 292 | ||
291 | /* Check client state and fix it up if necessary */ | 293 | switch(cmd[0] & 0xff00) { |
292 | if (cmd[0] & 0x8000) { /* MSB of opcode: next DWORD GUI_CNTL */ | 294 | /* XXX Are there old drivers needing other packets? */ |
293 | u32 offset; | ||
294 | 295 | ||
296 | case RADEON_3D_DRAW_IMMD: | ||
297 | case RADEON_3D_DRAW_VBUF: | ||
298 | case RADEON_3D_DRAW_INDX: | ||
299 | case RADEON_WAIT_FOR_IDLE: | ||
300 | case RADEON_CP_NOP: | ||
301 | case RADEON_3D_CLEAR_ZMASK: | ||
302 | /* case RADEON_CP_NEXT_CHAR: | ||
303 | case RADEON_CP_PLY_NEXTSCAN: | ||
304 | case RADEON_CP_SET_SCISSORS: */ /* probably safe but will never need them? */ | ||
305 | /* these packets are safe */ | ||
306 | break; | ||
307 | |||
308 | case RADEON_CP_3D_DRAW_IMMD_2: | ||
309 | case RADEON_CP_3D_DRAW_VBUF_2: | ||
310 | case RADEON_CP_3D_DRAW_INDX_2: | ||
311 | case RADEON_3D_CLEAR_HIZ: | ||
312 | /* safe but r200 only */ | ||
313 | if (dev_priv->microcode_version != UCODE_R200) { | ||
314 | DRM_ERROR("Invalid 3d packet for r100-class chip\n"); | ||
315 | return DRM_ERR(EINVAL); | ||
316 | } | ||
317 | break; | ||
318 | |||
319 | case RADEON_3D_LOAD_VBPNTR: | ||
320 | count = (cmd[0] >> 16) & 0x3fff; | ||
321 | |||
322 | if (count > 18) { /* 12 arrays max */ | ||
323 | DRM_ERROR("Too large payload in 3D_LOAD_VBPNTR (count=%d)\n", | ||
324 | count); | ||
325 | return DRM_ERR(EINVAL); | ||
326 | } | ||
327 | |||
328 | /* carefully check packet contents */ | ||
329 | narrays = cmd[1] & ~0xc000; | ||
330 | k = 0; | ||
331 | i = 2; | ||
332 | while ((k < narrays) && (i < (count + 2))) { | ||
333 | i++; /* skip attribute field */ | ||
334 | if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &cmd[i])) { | ||
335 | DRM_ERROR | ||
336 | ("Invalid offset (k=%d i=%d) in 3D_LOAD_VBPNTR packet.\n", | ||
337 | k, i); | ||
338 | return DRM_ERR(EINVAL); | ||
339 | } | ||
340 | k++; | ||
341 | i++; | ||
342 | if (k == narrays) | ||
343 | break; | ||
344 | /* have one more to process, they come in pairs */ | ||
345 | if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &cmd[i])) { | ||
346 | DRM_ERROR | ||
347 | ("Invalid offset (k=%d i=%d) in 3D_LOAD_VBPNTR packet.\n", | ||
348 | k, i); | ||
349 | return DRM_ERR(EINVAL); | ||
350 | } | ||
351 | k++; | ||
352 | i++; | ||
353 | } | ||
354 | /* do the counts match what we expect ? */ | ||
355 | if ((k != narrays) || (i != (count + 2))) { | ||
356 | DRM_ERROR | ||
357 | ("Malformed 3D_LOAD_VBPNTR packet (k=%d i=%d narrays=%d count+1=%d).\n", | ||
358 | k, i, narrays, count + 1); | ||
359 | return DRM_ERR(EINVAL); | ||
360 | } | ||
361 | break; | ||
362 | |||
363 | case RADEON_3D_RNDR_GEN_INDX_PRIM: | ||
364 | if (dev_priv->microcode_version != UCODE_R100) { | ||
365 | DRM_ERROR("Invalid 3d packet for r200-class chip\n"); | ||
366 | return DRM_ERR(EINVAL); | ||
367 | } | ||
368 | if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &cmd[1])) { | ||
369 | DRM_ERROR("Invalid rndr_gen_indx offset\n"); | ||
370 | return DRM_ERR(EINVAL); | ||
371 | } | ||
372 | break; | ||
373 | |||
374 | case RADEON_CP_INDX_BUFFER: | ||
375 | if (dev_priv->microcode_version != UCODE_R200) { | ||
376 | DRM_ERROR("Invalid 3d packet for r100-class chip\n"); | ||
377 | return DRM_ERR(EINVAL); | ||
378 | } | ||
379 | if ((cmd[1] & 0x8000ffff) != 0x80000810) { | ||
380 | DRM_ERROR("Invalid indx_buffer reg address %08X\n", cmd[1]); | ||
381 | return DRM_ERR(EINVAL); | ||
382 | } | ||
383 | if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &cmd[2])) { | ||
384 | DRM_ERROR("Invalid indx_buffer offset is %08X\n", cmd[2]); | ||
385 | return DRM_ERR(EINVAL); | ||
386 | } | ||
387 | break; | ||
388 | |||
389 | case RADEON_CNTL_HOSTDATA_BLT: | ||
390 | case RADEON_CNTL_PAINT_MULTI: | ||
391 | case RADEON_CNTL_BITBLT_MULTI: | ||
392 | /* MSB of opcode: next DWORD GUI_CNTL */ | ||
295 | if (cmd[1] & (RADEON_GMC_SRC_PITCH_OFFSET_CNTL | 393 | if (cmd[1] & (RADEON_GMC_SRC_PITCH_OFFSET_CNTL |
296 | | RADEON_GMC_DST_PITCH_OFFSET_CNTL)) { | 394 | | RADEON_GMC_DST_PITCH_OFFSET_CNTL)) { |
297 | offset = cmd[2] << 10; | 395 | offset = cmd[2] << 10; |
@@ -313,6 +411,11 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t * | |||
313 | } | 411 | } |
314 | cmd[3] = (cmd[3] & 0xffc00000) | offset >> 10; | 412 | cmd[3] = (cmd[3] & 0xffc00000) | offset >> 10; |
315 | } | 413 | } |
414 | break; | ||
415 | |||
416 | default: | ||
417 | DRM_ERROR("Invalid packet type %x\n", cmd[0] & 0xff00); | ||
418 | return DRM_ERR(EINVAL); | ||
316 | } | 419 | } |
317 | 420 | ||
318 | return 0; | 421 | return 0; |
diff --git a/drivers/char/drm/savage_bci.c b/drivers/char/drm/savage_bci.c index 59c7520bf9a2..a9a84f88df5e 100644 --- a/drivers/char/drm/savage_bci.c +++ b/drivers/char/drm/savage_bci.c | |||
@@ -728,6 +728,7 @@ static int savage_do_init_bci(drm_device_t * dev, drm_savage_init_t * init) | |||
728 | dev_priv->status = NULL; | 728 | dev_priv->status = NULL; |
729 | } | 729 | } |
730 | if (dev_priv->dma_type == SAVAGE_DMA_AGP && init->buffers_offset) { | 730 | if (dev_priv->dma_type == SAVAGE_DMA_AGP && init->buffers_offset) { |
731 | dev->agp_buffer_token = init->buffers_offset; | ||
731 | dev->agp_buffer_map = drm_core_findmap(dev, | 732 | dev->agp_buffer_map = drm_core_findmap(dev, |
732 | init->buffers_offset); | 733 | init->buffers_offset); |
733 | if (!dev->agp_buffer_map) { | 734 | if (!dev->agp_buffer_map) { |
diff --git a/drivers/char/drm/savage_state.c b/drivers/char/drm/savage_state.c index ef2581d16146..1ca1e9cb5a33 100644 --- a/drivers/char/drm/savage_state.c +++ b/drivers/char/drm/savage_state.c | |||
@@ -994,7 +994,7 @@ int savage_bci_cmdbuf(DRM_IOCTL_ARGS) | |||
994 | if (cmdbuf.size) { | 994 | if (cmdbuf.size) { |
995 | kcmd_addr = drm_alloc(cmdbuf.size * 8, DRM_MEM_DRIVER); | 995 | kcmd_addr = drm_alloc(cmdbuf.size * 8, DRM_MEM_DRIVER); |
996 | if (kcmd_addr == NULL) | 996 | if (kcmd_addr == NULL) |
997 | return ENOMEM; | 997 | return DRM_ERR(ENOMEM); |
998 | 998 | ||
999 | if (DRM_COPY_FROM_USER(kcmd_addr, cmdbuf.cmd_addr, | 999 | if (DRM_COPY_FROM_USER(kcmd_addr, cmdbuf.cmd_addr, |
1000 | cmdbuf.size * 8)) | 1000 | cmdbuf.size * 8)) |
diff --git a/drivers/char/ftape/zftape/zftape-buffers.c b/drivers/char/ftape/zftape/zftape-buffers.c index da06f138334e..7ebce2ec7897 100644 --- a/drivers/char/ftape/zftape/zftape-buffers.c +++ b/drivers/char/ftape/zftape/zftape-buffers.c | |||
@@ -85,7 +85,7 @@ int zft_vmalloc_once(void *new, size_t size) | |||
85 | peak_memory = used_memory; | 85 | peak_memory = used_memory; |
86 | } | 86 | } |
87 | TRACE_ABORT(0, ft_t_noise, | 87 | TRACE_ABORT(0, ft_t_noise, |
88 | "allocated buffer @ %p, %d bytes", *(void **)new, size); | 88 | "allocated buffer @ %p, %zd bytes", *(void **)new, size); |
89 | } | 89 | } |
90 | int zft_vmalloc_always(void *new, size_t size) | 90 | int zft_vmalloc_always(void *new, size_t size) |
91 | { | 91 | { |
@@ -101,7 +101,7 @@ void zft_vfree(void *old, size_t size) | |||
101 | if (*(void **)old) { | 101 | if (*(void **)old) { |
102 | vfree(*(void **)old); | 102 | vfree(*(void **)old); |
103 | used_memory -= size; | 103 | used_memory -= size; |
104 | TRACE(ft_t_noise, "released buffer @ %p, %d bytes", | 104 | TRACE(ft_t_noise, "released buffer @ %p, %zd bytes", |
105 | *(void **)old, size); | 105 | *(void **)old, size); |
106 | *(void **)old = NULL; | 106 | *(void **)old = NULL; |
107 | } | 107 | } |
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 34a4fd13fa81..c47add8e47df 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c | |||
@@ -376,13 +376,23 @@ static void free_recv_msg_list(struct list_head *q) | |||
376 | } | 376 | } |
377 | } | 377 | } |
378 | 378 | ||
379 | static void free_smi_msg_list(struct list_head *q) | ||
380 | { | ||
381 | struct ipmi_smi_msg *msg, *msg2; | ||
382 | |||
383 | list_for_each_entry_safe(msg, msg2, q, link) { | ||
384 | list_del(&msg->link); | ||
385 | ipmi_free_smi_msg(msg); | ||
386 | } | ||
387 | } | ||
388 | |||
379 | static void clean_up_interface_data(ipmi_smi_t intf) | 389 | static void clean_up_interface_data(ipmi_smi_t intf) |
380 | { | 390 | { |
381 | int i; | 391 | int i; |
382 | struct cmd_rcvr *rcvr, *rcvr2; | 392 | struct cmd_rcvr *rcvr, *rcvr2; |
383 | struct list_head list; | 393 | struct list_head list; |
384 | 394 | ||
385 | free_recv_msg_list(&intf->waiting_msgs); | 395 | free_smi_msg_list(&intf->waiting_msgs); |
386 | free_recv_msg_list(&intf->waiting_events); | 396 | free_recv_msg_list(&intf->waiting_events); |
387 | 397 | ||
388 | /* Wholesale remove all the entries from the list in the | 398 | /* Wholesale remove all the entries from the list in the |
@@ -1844,7 +1854,7 @@ static ssize_t provides_dev_sdrs_show(struct device *dev, | |||
1844 | struct bmc_device *bmc = dev_get_drvdata(dev); | 1854 | struct bmc_device *bmc = dev_get_drvdata(dev); |
1845 | 1855 | ||
1846 | return snprintf(buf, 10, "%u\n", | 1856 | return snprintf(buf, 10, "%u\n", |
1847 | bmc->id.device_revision && 0x80 >> 7); | 1857 | (bmc->id.device_revision & 0x80) >> 7); |
1848 | } | 1858 | } |
1849 | 1859 | ||
1850 | static ssize_t revision_show(struct device *dev, struct device_attribute *attr, | 1860 | static ssize_t revision_show(struct device *dev, struct device_attribute *attr, |
@@ -1853,7 +1863,7 @@ static ssize_t revision_show(struct device *dev, struct device_attribute *attr, | |||
1853 | struct bmc_device *bmc = dev_get_drvdata(dev); | 1863 | struct bmc_device *bmc = dev_get_drvdata(dev); |
1854 | 1864 | ||
1855 | return snprintf(buf, 20, "%u\n", | 1865 | return snprintf(buf, 20, "%u\n", |
1856 | bmc->id.device_revision && 0x0F); | 1866 | bmc->id.device_revision & 0x0F); |
1857 | } | 1867 | } |
1858 | 1868 | ||
1859 | static ssize_t firmware_rev_show(struct device *dev, | 1869 | static ssize_t firmware_rev_show(struct device *dev, |
@@ -2108,7 +2118,7 @@ static int ipmi_bmc_register(ipmi_smi_t intf) | |||
2108 | dev_set_drvdata(&bmc->dev->dev, bmc); | 2118 | dev_set_drvdata(&bmc->dev->dev, bmc); |
2109 | kref_init(&bmc->refcount); | 2119 | kref_init(&bmc->refcount); |
2110 | 2120 | ||
2111 | rv = platform_device_register(bmc->dev); | 2121 | rv = platform_device_add(bmc->dev); |
2112 | mutex_unlock(&ipmidriver_mutex); | 2122 | mutex_unlock(&ipmidriver_mutex); |
2113 | if (rv) { | 2123 | if (rv) { |
2114 | printk(KERN_ERR | 2124 | printk(KERN_ERR |
@@ -3232,7 +3242,9 @@ void ipmi_smi_msg_received(ipmi_smi_t intf, | |||
3232 | report the error immediately. */ | 3242 | report the error immediately. */ |
3233 | if ((msg->rsp_size >= 3) && (msg->rsp[2] != 0) | 3243 | if ((msg->rsp_size >= 3) && (msg->rsp[2] != 0) |
3234 | && (msg->rsp[2] != IPMI_NODE_BUSY_ERR) | 3244 | && (msg->rsp[2] != IPMI_NODE_BUSY_ERR) |
3235 | && (msg->rsp[2] != IPMI_LOST_ARBITRATION_ERR)) | 3245 | && (msg->rsp[2] != IPMI_LOST_ARBITRATION_ERR) |
3246 | && (msg->rsp[2] != IPMI_BUS_ERR) | ||
3247 | && (msg->rsp[2] != IPMI_NAK_ON_WRITE_ERR)) | ||
3236 | { | 3248 | { |
3237 | int chan = msg->rsp[3] & 0xf; | 3249 | int chan = msg->rsp[3] & 0xf; |
3238 | 3250 | ||
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index e5cfb1fa47d1..bb1fac104fda 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c | |||
@@ -1211,7 +1211,7 @@ static void intf_mem_outb(struct si_sm_io *io, unsigned int offset, | |||
1211 | static unsigned char intf_mem_inw(struct si_sm_io *io, unsigned int offset) | 1211 | static unsigned char intf_mem_inw(struct si_sm_io *io, unsigned int offset) |
1212 | { | 1212 | { |
1213 | return (readw((io->addr)+(offset * io->regspacing)) >> io->regshift) | 1213 | return (readw((io->addr)+(offset * io->regspacing)) >> io->regshift) |
1214 | && 0xff; | 1214 | & 0xff; |
1215 | } | 1215 | } |
1216 | 1216 | ||
1217 | static void intf_mem_outw(struct si_sm_io *io, unsigned int offset, | 1217 | static void intf_mem_outw(struct si_sm_io *io, unsigned int offset, |
@@ -1223,7 +1223,7 @@ static void intf_mem_outw(struct si_sm_io *io, unsigned int offset, | |||
1223 | static unsigned char intf_mem_inl(struct si_sm_io *io, unsigned int offset) | 1223 | static unsigned char intf_mem_inl(struct si_sm_io *io, unsigned int offset) |
1224 | { | 1224 | { |
1225 | return (readl((io->addr)+(offset * io->regspacing)) >> io->regshift) | 1225 | return (readl((io->addr)+(offset * io->regspacing)) >> io->regshift) |
1226 | && 0xff; | 1226 | & 0xff; |
1227 | } | 1227 | } |
1228 | 1228 | ||
1229 | static void intf_mem_outl(struct si_sm_io *io, unsigned int offset, | 1229 | static void intf_mem_outl(struct si_sm_io *io, unsigned int offset, |
@@ -1236,7 +1236,7 @@ static void intf_mem_outl(struct si_sm_io *io, unsigned int offset, | |||
1236 | static unsigned char mem_inq(struct si_sm_io *io, unsigned int offset) | 1236 | static unsigned char mem_inq(struct si_sm_io *io, unsigned int offset) |
1237 | { | 1237 | { |
1238 | return (readq((io->addr)+(offset * io->regspacing)) >> io->regshift) | 1238 | return (readq((io->addr)+(offset * io->regspacing)) >> io->regshift) |
1239 | && 0xff; | 1239 | & 0xff; |
1240 | } | 1240 | } |
1241 | 1241 | ||
1242 | static void mem_outq(struct si_sm_io *io, unsigned int offset, | 1242 | static void mem_outq(struct si_sm_io *io, unsigned int offset, |
@@ -1867,7 +1867,7 @@ static int ipmi_pci_resume(struct pci_dev *pdev) | |||
1867 | 1867 | ||
1868 | static struct pci_device_id ipmi_pci_devices[] = { | 1868 | static struct pci_device_id ipmi_pci_devices[] = { |
1869 | { PCI_DEVICE(PCI_HP_VENDOR_ID, PCI_MMC_DEVICE_ID) }, | 1869 | { PCI_DEVICE(PCI_HP_VENDOR_ID, PCI_MMC_DEVICE_ID) }, |
1870 | { PCI_DEVICE_CLASS(PCI_ERMC_CLASSCODE, PCI_ERMC_CLASSCODE) } | 1870 | { PCI_DEVICE_CLASS(PCI_ERMC_CLASSCODE, PCI_ERMC_CLASSCODE_MASK) } |
1871 | }; | 1871 | }; |
1872 | MODULE_DEVICE_TABLE(pci, ipmi_pci_devices); | 1872 | MODULE_DEVICE_TABLE(pci, ipmi_pci_devices); |
1873 | 1873 | ||
@@ -2346,7 +2346,7 @@ static int try_smi_init(struct smi_info *new_smi) | |||
2346 | new_smi->dev = &new_smi->pdev->dev; | 2346 | new_smi->dev = &new_smi->pdev->dev; |
2347 | new_smi->dev->driver = &ipmi_driver; | 2347 | new_smi->dev->driver = &ipmi_driver; |
2348 | 2348 | ||
2349 | rv = platform_device_register(new_smi->pdev); | 2349 | rv = platform_device_add(new_smi->pdev); |
2350 | if (rv) { | 2350 | if (rv) { |
2351 | printk(KERN_ERR | 2351 | printk(KERN_ERR |
2352 | "ipmi_si_intf:" | 2352 | "ipmi_si_intf:" |
diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c index e9e9bf31c369..58c955e390b3 100644 --- a/drivers/char/isicom.c +++ b/drivers/char/isicom.c | |||
@@ -1062,11 +1062,12 @@ static void isicom_shutdown_port(struct isi_port *port) | |||
1062 | static void isicom_close(struct tty_struct *tty, struct file *filp) | 1062 | static void isicom_close(struct tty_struct *tty, struct file *filp) |
1063 | { | 1063 | { |
1064 | struct isi_port *port = tty->driver_data; | 1064 | struct isi_port *port = tty->driver_data; |
1065 | struct isi_board *card = port->card; | 1065 | struct isi_board *card; |
1066 | unsigned long flags; | 1066 | unsigned long flags; |
1067 | 1067 | ||
1068 | if (!port) | 1068 | if (!port) |
1069 | return; | 1069 | return; |
1070 | card = port->card; | ||
1070 | if (isicom_paranoia_check(port, tty->name, "isicom_close")) | 1071 | if (isicom_paranoia_check(port, tty->name, "isicom_close")) |
1071 | return; | 1072 | return; |
1072 | 1073 | ||
diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c index b401383808c2..96cb1f07332b 100644 --- a/drivers/char/moxa.c +++ b/drivers/char/moxa.c | |||
@@ -130,6 +130,7 @@ static moxa_isa_board_conf moxa_isa_boards[] = | |||
130 | typedef struct _moxa_pci_devinfo { | 130 | typedef struct _moxa_pci_devinfo { |
131 | ushort busNum; | 131 | ushort busNum; |
132 | ushort devNum; | 132 | ushort devNum; |
133 | struct pci_dev *pdev; | ||
133 | } moxa_pci_devinfo; | 134 | } moxa_pci_devinfo; |
134 | 135 | ||
135 | typedef struct _moxa_board_conf { | 136 | typedef struct _moxa_board_conf { |
@@ -324,6 +325,9 @@ static int moxa_get_PCI_conf(struct pci_dev *p, int board_type, moxa_board_conf | |||
324 | board->busType = MOXA_BUS_TYPE_PCI; | 325 | board->busType = MOXA_BUS_TYPE_PCI; |
325 | board->pciInfo.busNum = p->bus->number; | 326 | board->pciInfo.busNum = p->bus->number; |
326 | board->pciInfo.devNum = p->devfn >> 3; | 327 | board->pciInfo.devNum = p->devfn >> 3; |
328 | board->pciInfo.pdev = p; | ||
329 | /* don't lose the reference in the next pci_get_device iteration */ | ||
330 | pci_dev_get(p); | ||
327 | 331 | ||
328 | return (0); | 332 | return (0); |
329 | } | 333 | } |
@@ -493,6 +497,11 @@ static void __exit moxa_exit(void) | |||
493 | if (tty_unregister_driver(moxaDriver)) | 497 | if (tty_unregister_driver(moxaDriver)) |
494 | printk("Couldn't unregister MOXA Intellio family serial driver\n"); | 498 | printk("Couldn't unregister MOXA Intellio family serial driver\n"); |
495 | put_tty_driver(moxaDriver); | 499 | put_tty_driver(moxaDriver); |
500 | |||
501 | for (i = 0; i < MAX_BOARDS; i++) | ||
502 | if (moxa_boards[i].busType == MOXA_BUS_TYPE_PCI) | ||
503 | pci_dev_put(moxa_boards[i].pciInfo.pdev); | ||
504 | |||
496 | if (verbose) | 505 | if (verbose) |
497 | printk("Done\n"); | 506 | printk("Done\n"); |
498 | } | 507 | } |
diff --git a/drivers/char/mspec.c b/drivers/char/mspec.c index 5c0dec39cf6c..235e89226112 100644 --- a/drivers/char/mspec.c +++ b/drivers/char/mspec.c | |||
@@ -72,7 +72,11 @@ enum { | |||
72 | MSPEC_UNCACHED | 72 | MSPEC_UNCACHED |
73 | }; | 73 | }; |
74 | 74 | ||
75 | #ifdef CONFIG_SGI_SN | ||
75 | static int is_sn2; | 76 | static int is_sn2; |
77 | #else | ||
78 | #define is_sn2 0 | ||
79 | #endif | ||
76 | 80 | ||
77 | /* | 81 | /* |
78 | * One of these structures is allocated when an mspec region is mmaped. The | 82 | * One of these structures is allocated when an mspec region is mmaped. The |
@@ -211,7 +215,7 @@ mspec_nopfn(struct vm_area_struct *vma, unsigned long address) | |||
211 | if (vdata->type == MSPEC_FETCHOP) | 215 | if (vdata->type == MSPEC_FETCHOP) |
212 | paddr = TO_AMO(maddr); | 216 | paddr = TO_AMO(maddr); |
213 | else | 217 | else |
214 | paddr = __pa(TO_CAC(maddr)); | 218 | paddr = maddr & ~__IA64_UNCACHED_OFFSET; |
215 | 219 | ||
216 | pfn = paddr >> PAGE_SHIFT; | 220 | pfn = paddr >> PAGE_SHIFT; |
217 | 221 | ||
@@ -335,6 +339,7 @@ mspec_init(void) | |||
335 | * The fetchop device only works on SN2 hardware, uncached and cached | 339 | * The fetchop device only works on SN2 hardware, uncached and cached |
336 | * memory drivers should both be valid on all ia64 hardware | 340 | * memory drivers should both be valid on all ia64 hardware |
337 | */ | 341 | */ |
342 | #ifdef CONFIG_SGI_SN | ||
338 | if (ia64_platform_is("sn2")) { | 343 | if (ia64_platform_is("sn2")) { |
339 | is_sn2 = 1; | 344 | is_sn2 = 1; |
340 | if (is_shub2()) { | 345 | if (is_shub2()) { |
@@ -363,6 +368,7 @@ mspec_init(void) | |||
363 | goto free_scratch_pages; | 368 | goto free_scratch_pages; |
364 | } | 369 | } |
365 | } | 370 | } |
371 | #endif | ||
366 | ret = misc_register(&cached_miscdev); | 372 | ret = misc_register(&cached_miscdev); |
367 | if (ret) { | 373 | if (ret) { |
368 | printk(KERN_ERR "%s: failed to register device %i\n", | 374 | printk(KERN_ERR "%s: failed to register device %i\n", |
diff --git a/drivers/char/rio/host.h b/drivers/char/rio/host.h index ee2ddea7a63a..23d0681fe491 100644 --- a/drivers/char/rio/host.h +++ b/drivers/char/rio/host.h | |||
@@ -44,6 +44,7 @@ | |||
44 | ** the host. | 44 | ** the host. |
45 | */ | 45 | */ |
46 | struct Host { | 46 | struct Host { |
47 | struct pci_dev *pdev; | ||
47 | unsigned char Type; /* RIO_EISA, RIO_MCA, ... */ | 48 | unsigned char Type; /* RIO_EISA, RIO_MCA, ... */ |
48 | unsigned char Ivec; /* POLLED or ivec number */ | 49 | unsigned char Ivec; /* POLLED or ivec number */ |
49 | unsigned char Mode; /* Control stuff */ | 50 | unsigned char Mode; /* Control stuff */ |
diff --git a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c index c382df0f82f6..7ac68cb3bedd 100644 --- a/drivers/char/rio/rio_linux.c +++ b/drivers/char/rio/rio_linux.c | |||
@@ -1017,6 +1017,10 @@ static int __init rio_init(void) | |||
1017 | rio_dprintk(RIO_DEBUG_PROBE, "Hmm Tested ok, uniqid = %x.\n", p->RIOHosts[p->RIONumHosts].UniqueNum); | 1017 | rio_dprintk(RIO_DEBUG_PROBE, "Hmm Tested ok, uniqid = %x.\n", p->RIOHosts[p->RIONumHosts].UniqueNum); |
1018 | 1018 | ||
1019 | fix_rio_pci(pdev); | 1019 | fix_rio_pci(pdev); |
1020 | |||
1021 | p->RIOHosts[p->RIONumHosts].pdev = pdev; | ||
1022 | pci_dev_get(pdev); | ||
1023 | |||
1020 | p->RIOLastPCISearch = 0; | 1024 | p->RIOLastPCISearch = 0; |
1021 | p->RIONumHosts++; | 1025 | p->RIONumHosts++; |
1022 | found++; | 1026 | found++; |
@@ -1066,6 +1070,9 @@ static int __init rio_init(void) | |||
1066 | ((readb(&p->RIOHosts[p->RIONumHosts].Unique[1]) & 0xFF) << 8) | ((readb(&p->RIOHosts[p->RIONumHosts].Unique[2]) & 0xFF) << 16) | ((readb(&p->RIOHosts[p->RIONumHosts].Unique[3]) & 0xFF) << 24); | 1070 | ((readb(&p->RIOHosts[p->RIONumHosts].Unique[1]) & 0xFF) << 8) | ((readb(&p->RIOHosts[p->RIONumHosts].Unique[2]) & 0xFF) << 16) | ((readb(&p->RIOHosts[p->RIONumHosts].Unique[3]) & 0xFF) << 24); |
1067 | rio_dprintk(RIO_DEBUG_PROBE, "Hmm Tested ok, uniqid = %x.\n", p->RIOHosts[p->RIONumHosts].UniqueNum); | 1071 | rio_dprintk(RIO_DEBUG_PROBE, "Hmm Tested ok, uniqid = %x.\n", p->RIOHosts[p->RIONumHosts].UniqueNum); |
1068 | 1072 | ||
1073 | p->RIOHosts[p->RIONumHosts].pdev = pdev; | ||
1074 | pci_dev_get(pdev); | ||
1075 | |||
1069 | p->RIOLastPCISearch = 0; | 1076 | p->RIOLastPCISearch = 0; |
1070 | p->RIONumHosts++; | 1077 | p->RIONumHosts++; |
1071 | found++; | 1078 | found++; |
@@ -1181,6 +1188,8 @@ static void __exit rio_exit(void) | |||
1181 | } | 1188 | } |
1182 | /* It is safe/allowed to del_timer a non-active timer */ | 1189 | /* It is safe/allowed to del_timer a non-active timer */ |
1183 | del_timer(&hp->timer); | 1190 | del_timer(&hp->timer); |
1191 | if (hp->Type == RIO_PCI) | ||
1192 | pci_dev_put(hp->pdev); | ||
1184 | } | 1193 | } |
1185 | 1194 | ||
1186 | if (misc_deregister(&rio_fw_device) < 0) { | 1195 | if (misc_deregister(&rio_fw_device) < 0) { |
diff --git a/drivers/char/tlclk.c b/drivers/char/tlclk.c index 2444a0e24b31..244d30a03fef 100644 --- a/drivers/char/tlclk.c +++ b/drivers/char/tlclk.c | |||
@@ -792,15 +792,14 @@ static int __init tlclk_init(void) | |||
792 | ret = misc_register(&tlclk_miscdev); | 792 | ret = misc_register(&tlclk_miscdev); |
793 | if (ret < 0) { | 793 | if (ret < 0) { |
794 | printk(KERN_ERR "tlclk: misc_register returns %d.\n", ret); | 794 | printk(KERN_ERR "tlclk: misc_register returns %d.\n", ret); |
795 | ret = -EBUSY; | ||
796 | goto out3; | 795 | goto out3; |
797 | } | 796 | } |
798 | 797 | ||
799 | tlclk_device = platform_device_register_simple("telco_clock", | 798 | tlclk_device = platform_device_register_simple("telco_clock", |
800 | -1, NULL, 0); | 799 | -1, NULL, 0); |
801 | if (!tlclk_device) { | 800 | if (IS_ERR(tlclk_device)) { |
802 | printk(KERN_ERR "tlclk: platform_device_register failed.\n"); | 801 | printk(KERN_ERR "tlclk: platform_device_register failed.\n"); |
803 | ret = -EBUSY; | 802 | ret = PTR_ERR(tlclk_device); |
804 | goto out4; | 803 | goto out4; |
805 | } | 804 | } |
806 | 805 | ||
diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig index 89e46d6dfc4e..0187b1185323 100644 --- a/drivers/char/watchdog/Kconfig +++ b/drivers/char/watchdog/Kconfig | |||
@@ -13,7 +13,7 @@ config WATCHDOG | |||
13 | subsequently opening the file and then failing to write to it for | 13 | subsequently opening the file and then failing to write to it for |
14 | longer than 1 minute will result in rebooting the machine. This | 14 | longer than 1 minute will result in rebooting the machine. This |
15 | could be useful for a networked machine that needs to come back | 15 | could be useful for a networked machine that needs to come back |
16 | online as fast as possible after a lock-up. There's both a watchdog | 16 | on-line as fast as possible after a lock-up. There's both a watchdog |
17 | implementation entirely in software (which can sometimes fail to | 17 | implementation entirely in software (which can sometimes fail to |
18 | reboot the machine) and a driver for hardware watchdog boards, which | 18 | reboot the machine) and a driver for hardware watchdog boards, which |
19 | are more robust and can also keep track of the temperature inside | 19 | are more robust and can also keep track of the temperature inside |
@@ -60,7 +60,7 @@ config SOFT_WATCHDOG | |||
60 | 60 | ||
61 | # ARM Architecture | 61 | # ARM Architecture |
62 | 62 | ||
63 | config AT91_WATCHDOG | 63 | config AT91RM9200_WATCHDOG |
64 | tristate "AT91RM9200 watchdog" | 64 | tristate "AT91RM9200 watchdog" |
65 | depends on WATCHDOG && ARCH_AT91RM9200 | 65 | depends on WATCHDOG && ARCH_AT91RM9200 |
66 | help | 66 | help |
@@ -71,7 +71,7 @@ config 21285_WATCHDOG | |||
71 | tristate "DC21285 watchdog" | 71 | tristate "DC21285 watchdog" |
72 | depends on WATCHDOG && FOOTBRIDGE | 72 | depends on WATCHDOG && FOOTBRIDGE |
73 | help | 73 | help |
74 | The Intel Footbridge chip contains a builtin watchdog circuit. Say Y | 74 | The Intel Footbridge chip contains a built-in watchdog circuit. Say Y |
75 | here if you wish to use this. Alternatively say M to compile the | 75 | here if you wish to use this. Alternatively say M to compile the |
76 | driver as a module, which will be called wdt285. | 76 | driver as a module, which will be called wdt285. |
77 | 77 | ||
@@ -269,11 +269,11 @@ config IB700_WDT | |||
269 | Most people will say N. | 269 | Most people will say N. |
270 | 270 | ||
271 | config IBMASR | 271 | config IBMASR |
272 | tristate "IBM Automatic Server Restart" | 272 | tristate "IBM Automatic Server Restart" |
273 | depends on WATCHDOG && X86 | 273 | depends on WATCHDOG && X86 |
274 | help | 274 | help |
275 | This is the driver for the IBM Automatic Server Restart watchdog | 275 | This is the driver for the IBM Automatic Server Restart watchdog |
276 | timer builtin into some eServer xSeries machines. | 276 | timer built-in into some eServer xSeries machines. |
277 | 277 | ||
278 | To compile this driver as a module, choose M here: the | 278 | To compile this driver as a module, choose M here: the |
279 | module will be called ibmasr. | 279 | module will be called ibmasr. |
@@ -316,13 +316,16 @@ config I8XX_TCO | |||
316 | To compile this driver as a module, choose M here: the | 316 | To compile this driver as a module, choose M here: the |
317 | module will be called i8xx_tco. | 317 | module will be called i8xx_tco. |
318 | 318 | ||
319 | Note: This driver will be removed in the near future. Please | ||
320 | use the Intel TCO Timer/Watchdog driver. | ||
321 | |||
319 | config ITCO_WDT | 322 | config ITCO_WDT |
320 | tristate "Intel TCO Timer/Watchdog (EXPERIMENTAL)" | 323 | tristate "Intel TCO Timer/Watchdog" |
321 | depends on WATCHDOG && (X86 || IA64) && PCI && EXPERIMENTAL | 324 | depends on WATCHDOG && (X86 || IA64) && PCI |
322 | ---help--- | 325 | ---help--- |
323 | Hardware driver for the intel TCO timer based watchdog devices. | 326 | Hardware driver for the intel TCO timer based watchdog devices. |
324 | These drivers are included in the Intel 82801 I/O Controller | 327 | These drivers are included in the Intel 82801 I/O Controller |
325 | Hub family 'from ICH0 up to ICH7) and in the Intel 6300ESB | 328 | Hub family (from ICH0 up to ICH8) and in the Intel 6300ESB |
326 | controller hub. | 329 | controller hub. |
327 | 330 | ||
328 | The TCO (Total Cost of Ownership) timer is a watchdog timer | 331 | The TCO (Total Cost of Ownership) timer is a watchdog timer |
@@ -395,6 +398,26 @@ config CPU5_WDT | |||
395 | To compile this driver as a module, choose M here: the | 398 | To compile this driver as a module, choose M here: the |
396 | module will be called cpu5wdt. | 399 | module will be called cpu5wdt. |
397 | 400 | ||
401 | config SMSC37B787_WDT | ||
402 | tristate "Winbond SMsC37B787 Watchdog Timer" | ||
403 | depends on WATCHDOG && X86 | ||
404 | ---help--- | ||
405 | This is the driver for the hardware watchdog component on the | ||
406 | Winbond SMsC37B787 chipset as used on the NetRunner Mainboard | ||
407 | from Vision Systems and maybe others. | ||
408 | |||
409 | This watchdog simply watches your kernel to make sure it doesn't | ||
410 | freeze, and if it does, it reboots your computer after a certain | ||
411 | amount of time. | ||
412 | |||
413 | Usually a userspace daemon will notify the kernel WDT driver that | ||
414 | userspace is still alive, at regular intervals. | ||
415 | |||
416 | To compile this driver as a module, choose M here: the | ||
417 | module will be called smsc37b787_wdt. | ||
418 | |||
419 | Most people will say N. | ||
420 | |||
398 | config W83627HF_WDT | 421 | config W83627HF_WDT |
399 | tristate "W83627HF Watchdog Timer" | 422 | tristate "W83627HF Watchdog Timer" |
400 | depends on WATCHDOG && X86 | 423 | depends on WATCHDOG && X86 |
@@ -410,6 +433,21 @@ config W83627HF_WDT | |||
410 | 433 | ||
411 | Most people will say N. | 434 | Most people will say N. |
412 | 435 | ||
436 | config W83697HF_WDT | ||
437 | tristate "W83697HF/W83697HG Watchdog Timer" | ||
438 | depends on WATCHDOG && X86 | ||
439 | ---help--- | ||
440 | This is the driver for the hardware watchdog on the W83697HF/HG | ||
441 | chipset as used in Dedibox/VIA motherboards (and likely others). | ||
442 | This watchdog simply watches your kernel to make sure it doesn't | ||
443 | freeze, and if it does, it reboots your computer after a certain | ||
444 | amount of time. | ||
445 | |||
446 | To compile this driver as a module, choose M here: the | ||
447 | module will be called w83697hf_wdt. | ||
448 | |||
449 | Most people will say N. | ||
450 | |||
413 | config W83877F_WDT | 451 | config W83877F_WDT |
414 | tristate "W83877F (EMACS) Watchdog Timer" | 452 | tristate "W83877F (EMACS) Watchdog Timer" |
415 | depends on WATCHDOG && X86 | 453 | depends on WATCHDOG && X86 |
@@ -443,7 +481,7 @@ config MACHZ_WDT | |||
443 | depends on WATCHDOG && X86 | 481 | depends on WATCHDOG && X86 |
444 | ---help--- | 482 | ---help--- |
445 | If you are using a ZF Micro MachZ processor, say Y here, otherwise | 483 | If you are using a ZF Micro MachZ processor, say Y here, otherwise |
446 | N. This is the driver for the watchdog timer builtin on that | 484 | N. This is the driver for the watchdog timer built-in on that |
447 | processor using ZF-Logic interface. This watchdog simply watches | 485 | processor using ZF-Logic interface. This watchdog simply watches |
448 | your kernel to make sure it doesn't freeze, and if it does, it | 486 | your kernel to make sure it doesn't freeze, and if it does, it |
449 | reboots your computer after a certain amount of time. | 487 | reboots your computer after a certain amount of time. |
@@ -472,7 +510,6 @@ config SBC_EPX_C3_WATCHDOG | |||
472 | To compile this driver as a module, choose M here: the | 510 | To compile this driver as a module, choose M here: the |
473 | module will be called sbc_epx_c3. | 511 | module will be called sbc_epx_c3. |
474 | 512 | ||
475 | |||
476 | # PowerPC Architecture | 513 | # PowerPC Architecture |
477 | 514 | ||
478 | config 8xx_WDT | 515 | config 8xx_WDT |
@@ -502,7 +539,7 @@ config WATCHDOG_RTAS | |||
502 | help | 539 | help |
503 | This driver adds watchdog support for the RTAS watchdog. | 540 | This driver adds watchdog support for the RTAS watchdog. |
504 | 541 | ||
505 | To compile this driver as a module, choose M here. The module | 542 | To compile this driver as a module, choose M here. The module |
506 | will be called wdrtas. | 543 | will be called wdrtas. |
507 | 544 | ||
508 | # MIPS Architecture | 545 | # MIPS Architecture |
@@ -556,7 +593,7 @@ config SH_WDT_MMAP | |||
556 | help | 593 | help |
557 | If you say Y here, user applications will be able to mmap the | 594 | If you say Y here, user applications will be able to mmap the |
558 | WDT/CPG registers. | 595 | WDT/CPG registers. |
559 | # | 596 | |
560 | # SPARC64 Architecture | 597 | # SPARC64 Architecture |
561 | 598 | ||
562 | config WATCHDOG_CP1XXX | 599 | config WATCHDOG_CP1XXX |
diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile index 7f70abad465a..36440497047c 100644 --- a/drivers/char/watchdog/Makefile +++ b/drivers/char/watchdog/Makefile | |||
@@ -23,7 +23,7 @@ obj-$(CONFIG_WDTPCI) += wdt_pci.o | |||
23 | obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o | 23 | obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o |
24 | 24 | ||
25 | # ARM Architecture | 25 | # ARM Architecture |
26 | obj-$(CONFIG_AT91_WATCHDOG) += at91_wdt.o | 26 | obj-$(CONFIG_AT91RM9200_WATCHDOG) += at91rm9200_wdt.o |
27 | obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o | 27 | obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o |
28 | obj-$(CONFIG_21285_WATCHDOG) += wdt285.o | 28 | obj-$(CONFIG_21285_WATCHDOG) += wdt285.o |
29 | obj-$(CONFIG_977_WATCHDOG) += wdt977.o | 29 | obj-$(CONFIG_977_WATCHDOG) += wdt977.o |
@@ -53,7 +53,9 @@ obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o | |||
53 | obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o | 53 | obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o |
54 | obj-$(CONFIG_SBC8360_WDT) += sbc8360.o | 54 | obj-$(CONFIG_SBC8360_WDT) += sbc8360.o |
55 | obj-$(CONFIG_CPU5_WDT) += cpu5wdt.o | 55 | obj-$(CONFIG_CPU5_WDT) += cpu5wdt.o |
56 | obj-$(CONFIG_SMSC37B787_WDT) += smsc37b787_wdt.o | ||
56 | obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o | 57 | obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o |
58 | obj-$(CONFIG_W83697HF_WDT) += w83697hf_wdt.o | ||
57 | obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o | 59 | obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o |
58 | obj-$(CONFIG_W83977F_WDT) += w83977f_wdt.o | 60 | obj-$(CONFIG_W83977F_WDT) += w83977f_wdt.o |
59 | obj-$(CONFIG_MACHZ_WDT) += machzwd.o | 61 | obj-$(CONFIG_MACHZ_WDT) += machzwd.o |
diff --git a/drivers/char/watchdog/at91_wdt.c b/drivers/char/watchdog/at91rm9200_wdt.c index 4e7a1145e78f..4e7a1145e78f 100644 --- a/drivers/char/watchdog/at91_wdt.c +++ b/drivers/char/watchdog/at91rm9200_wdt.c | |||
diff --git a/drivers/char/watchdog/iTCO_wdt.c b/drivers/char/watchdog/iTCO_wdt.c index aaac94db0d8b..b6f29cb8bd39 100644 --- a/drivers/char/watchdog/iTCO_wdt.c +++ b/drivers/char/watchdog/iTCO_wdt.c | |||
@@ -35,6 +35,10 @@ | |||
35 | * 82801GDH (ICH7DH) : document number 307013-002, 307014-009, | 35 | * 82801GDH (ICH7DH) : document number 307013-002, 307014-009, |
36 | * 82801GBM (ICH7-M) : document number 307013-002, 307014-009, | 36 | * 82801GBM (ICH7-M) : document number 307013-002, 307014-009, |
37 | * 82801GHM (ICH7-M DH) : document number 307013-002, 307014-009, | 37 | * 82801GHM (ICH7-M DH) : document number 307013-002, 307014-009, |
38 | * 82801HB (ICH8) : document number 313056-002, 313057-004, | ||
39 | * 82801HR (ICH8R) : document number 313056-002, 313057-004, | ||
40 | * 82801HH (ICH8DH) : document number 313056-002, 313057-004, | ||
41 | * 82801HO (ICH8DO) : document number 313056-002, 313057-004, | ||
38 | * 6300ESB (6300ESB) : document number 300641-003 | 42 | * 6300ESB (6300ESB) : document number 300641-003 |
39 | */ | 43 | */ |
40 | 44 | ||
@@ -45,7 +49,7 @@ | |||
45 | /* Module and version information */ | 49 | /* Module and version information */ |
46 | #define DRV_NAME "iTCO_wdt" | 50 | #define DRV_NAME "iTCO_wdt" |
47 | #define DRV_VERSION "1.00" | 51 | #define DRV_VERSION "1.00" |
48 | #define DRV_RELDATE "30-Jul-2006" | 52 | #define DRV_RELDATE "08-Oct-2006" |
49 | #define PFX DRV_NAME ": " | 53 | #define PFX DRV_NAME ": " |
50 | 54 | ||
51 | /* Includes */ | 55 | /* Includes */ |
@@ -85,6 +89,9 @@ enum iTCO_chipsets { | |||
85 | TCO_ICH7, /* ICH7 & ICH7R */ | 89 | TCO_ICH7, /* ICH7 & ICH7R */ |
86 | TCO_ICH7M, /* ICH7-M */ | 90 | TCO_ICH7M, /* ICH7-M */ |
87 | TCO_ICH7MDH, /* ICH7-M DH */ | 91 | TCO_ICH7MDH, /* ICH7-M DH */ |
92 | TCO_ICH8, /* ICH8 & ICH8R */ | ||
93 | TCO_ICH8DH, /* ICH8DH */ | ||
94 | TCO_ICH8DO, /* ICH8DO */ | ||
88 | }; | 95 | }; |
89 | 96 | ||
90 | static struct { | 97 | static struct { |
@@ -108,6 +115,9 @@ static struct { | |||
108 | {"ICH7 or ICH7R", 2}, | 115 | {"ICH7 or ICH7R", 2}, |
109 | {"ICH7-M", 2}, | 116 | {"ICH7-M", 2}, |
110 | {"ICH7-M DH", 2}, | 117 | {"ICH7-M DH", 2}, |
118 | {"ICH8 or ICH8R", 2}, | ||
119 | {"ICH8DH", 2}, | ||
120 | {"ICH8DO", 2}, | ||
111 | {NULL,0} | 121 | {NULL,0} |
112 | }; | 122 | }; |
113 | 123 | ||
@@ -135,6 +145,9 @@ static struct pci_device_id iTCO_wdt_pci_tbl[] = { | |||
135 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7 }, | 145 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7 }, |
136 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7M }, | 146 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7M }, |
137 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_31, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7MDH }, | 147 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_31, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7MDH }, |
148 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH8 }, | ||
149 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH8DH }, | ||
150 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH8DO }, | ||
138 | { 0, }, /* End of list */ | 151 | { 0, }, /* End of list */ |
139 | }; | 152 | }; |
140 | MODULE_DEVICE_TABLE (pci, iTCO_wdt_pci_tbl); | 153 | MODULE_DEVICE_TABLE (pci, iTCO_wdt_pci_tbl); |
@@ -355,7 +368,8 @@ static int iTCO_wdt_get_timeleft (int *time_left) | |||
355 | spin_unlock(&iTCO_wdt_private.io_lock); | 368 | spin_unlock(&iTCO_wdt_private.io_lock); |
356 | 369 | ||
357 | *time_left = (val8 * 6) / 10; | 370 | *time_left = (val8 * 6) / 10; |
358 | } | 371 | } else |
372 | return -EINVAL; | ||
359 | return 0; | 373 | return 0; |
360 | } | 374 | } |
361 | 375 | ||
@@ -426,7 +440,6 @@ static int iTCO_wdt_ioctl (struct inode *inode, struct file *file, | |||
426 | { | 440 | { |
427 | int new_options, retval = -EINVAL; | 441 | int new_options, retval = -EINVAL; |
428 | int new_heartbeat; | 442 | int new_heartbeat; |
429 | int time_left; | ||
430 | void __user *argp = (void __user *)arg; | 443 | void __user *argp = (void __user *)arg; |
431 | int __user *p = argp; | 444 | int __user *p = argp; |
432 | static struct watchdog_info ident = { | 445 | static struct watchdog_info ident = { |
@@ -486,6 +499,8 @@ static int iTCO_wdt_ioctl (struct inode *inode, struct file *file, | |||
486 | 499 | ||
487 | case WDIOC_GETTIMELEFT: | 500 | case WDIOC_GETTIMELEFT: |
488 | { | 501 | { |
502 | int time_left; | ||
503 | |||
489 | if (iTCO_wdt_get_timeleft(&time_left)) | 504 | if (iTCO_wdt_get_timeleft(&time_left)) |
490 | return -EINVAL; | 505 | return -EINVAL; |
491 | 506 | ||
diff --git a/drivers/char/watchdog/s3c2410_wdt.c b/drivers/char/watchdog/s3c2410_wdt.c index 68b1ca976d53..18cb050c3862 100644 --- a/drivers/char/watchdog/s3c2410_wdt.c +++ b/drivers/char/watchdog/s3c2410_wdt.c | |||
@@ -380,18 +380,21 @@ static int s3c2410wdt_probe(struct platform_device *pdev) | |||
380 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | 380 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); |
381 | if (res == NULL) { | 381 | if (res == NULL) { |
382 | printk(KERN_INFO PFX "failed to get irq resource\n"); | 382 | printk(KERN_INFO PFX "failed to get irq resource\n"); |
383 | iounmap(wdt_base); | ||
383 | return -ENOENT; | 384 | return -ENOENT; |
384 | } | 385 | } |
385 | 386 | ||
386 | ret = request_irq(res->start, s3c2410wdt_irq, 0, pdev->name, pdev); | 387 | ret = request_irq(res->start, s3c2410wdt_irq, 0, pdev->name, pdev); |
387 | if (ret != 0) { | 388 | if (ret != 0) { |
388 | printk(KERN_INFO PFX "failed to install irq (%d)\n", ret); | 389 | printk(KERN_INFO PFX "failed to install irq (%d)\n", ret); |
390 | iounmap(wdt_base); | ||
389 | return ret; | 391 | return ret; |
390 | } | 392 | } |
391 | 393 | ||
392 | wdt_clock = clk_get(&pdev->dev, "watchdog"); | 394 | wdt_clock = clk_get(&pdev->dev, "watchdog"); |
393 | if (wdt_clock == NULL) { | 395 | if (wdt_clock == NULL) { |
394 | printk(KERN_INFO PFX "failed to find watchdog clock source\n"); | 396 | printk(KERN_INFO PFX "failed to find watchdog clock source\n"); |
397 | iounmap(wdt_base); | ||
395 | return -ENOENT; | 398 | return -ENOENT; |
396 | } | 399 | } |
397 | 400 | ||
@@ -415,6 +418,7 @@ static int s3c2410wdt_probe(struct platform_device *pdev) | |||
415 | if (ret) { | 418 | if (ret) { |
416 | printk (KERN_ERR PFX "cannot register miscdev on minor=%d (%d)\n", | 419 | printk (KERN_ERR PFX "cannot register miscdev on minor=%d (%d)\n", |
417 | WATCHDOG_MINOR, ret); | 420 | WATCHDOG_MINOR, ret); |
421 | iounmap(wdt_base); | ||
418 | return ret; | 422 | return ret; |
419 | } | 423 | } |
420 | 424 | ||
@@ -451,6 +455,7 @@ static int s3c2410wdt_remove(struct platform_device *dev) | |||
451 | wdt_clock = NULL; | 455 | wdt_clock = NULL; |
452 | } | 456 | } |
453 | 457 | ||
458 | iounmap(wdt_base); | ||
454 | misc_deregister(&s3c2410wdt_miscdev); | 459 | misc_deregister(&s3c2410wdt_miscdev); |
455 | return 0; | 460 | return 0; |
456 | } | 461 | } |
diff --git a/drivers/char/watchdog/sc1200wdt.c b/drivers/char/watchdog/sc1200wdt.c index d8d0f28e0acf..e3239833e4b0 100644 --- a/drivers/char/watchdog/sc1200wdt.c +++ b/drivers/char/watchdog/sc1200wdt.c | |||
@@ -392,7 +392,7 @@ static int __init sc1200wdt_init(void) | |||
392 | if (io == -1) { | 392 | if (io == -1) { |
393 | printk(KERN_ERR PFX "io parameter must be specified\n"); | 393 | printk(KERN_ERR PFX "io parameter must be specified\n"); |
394 | ret = -EINVAL; | 394 | ret = -EINVAL; |
395 | goto out_clean; | 395 | goto out_pnp; |
396 | } | 396 | } |
397 | 397 | ||
398 | #if defined CONFIG_PNP | 398 | #if defined CONFIG_PNP |
@@ -405,7 +405,7 @@ static int __init sc1200wdt_init(void) | |||
405 | if (!request_region(io, io_len, SC1200_MODULE_NAME)) { | 405 | if (!request_region(io, io_len, SC1200_MODULE_NAME)) { |
406 | printk(KERN_ERR PFX "Unable to register IO port %#x\n", io); | 406 | printk(KERN_ERR PFX "Unable to register IO port %#x\n", io); |
407 | ret = -EBUSY; | 407 | ret = -EBUSY; |
408 | goto out_clean; | 408 | goto out_pnp; |
409 | } | 409 | } |
410 | 410 | ||
411 | ret = sc1200wdt_probe(); | 411 | ret = sc1200wdt_probe(); |
@@ -435,6 +435,11 @@ out_rbt: | |||
435 | out_io: | 435 | out_io: |
436 | release_region(io, io_len); | 436 | release_region(io, io_len); |
437 | 437 | ||
438 | out_pnp: | ||
439 | #if defined CONFIG_PNP | ||
440 | if (isapnp) | ||
441 | pnp_unregister_driver(&scl200wdt_pnp_driver); | ||
442 | #endif | ||
438 | goto out_clean; | 443 | goto out_clean; |
439 | } | 444 | } |
440 | 445 | ||
diff --git a/drivers/char/watchdog/smsc37b787_wdt.c b/drivers/char/watchdog/smsc37b787_wdt.c new file mode 100644 index 000000000000..9f56913b484f --- /dev/null +++ b/drivers/char/watchdog/smsc37b787_wdt.c | |||
@@ -0,0 +1,627 @@ | |||
1 | /* | ||
2 | * SMsC 37B787 Watchdog Timer driver for Linux 2.6.x.x | ||
3 | * | ||
4 | * Based on acquirewdt.c by Alan Cox <alan@redhat.com> | ||
5 | * and some other existing drivers | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * as published by the Free Software Foundation; either version | ||
10 | * 2 of the License, or (at your option) any later version. | ||
11 | * | ||
12 | * The authors do NOT admit liability nor provide warranty for | ||
13 | * any of this software. This material is provided "AS-IS" in | ||
14 | * the hope that it may be useful for others. | ||
15 | * | ||
16 | * (C) Copyright 2003-2006 Sven Anders <anders@anduras.de> | ||
17 | * | ||
18 | * History: | ||
19 | * 2003 - Created version 1.0 for Linux 2.4.x. | ||
20 | * 2006 - Ported to Linux 2.6, added nowayout and MAGICCLOSE | ||
21 | * features. Released version 1.1 | ||
22 | * | ||
23 | * Theory of operation: | ||
24 | * | ||
25 | * A Watchdog Timer (WDT) is a hardware circuit that can | ||
26 | * reset the computer system in case of a software fault. | ||
27 | * You probably knew that already. | ||
28 | * | ||
29 | * Usually a userspace daemon will notify the kernel WDT driver | ||
30 | * via the /dev/watchdog special device file that userspace is | ||
31 | * still alive, at regular intervals. When such a notification | ||
32 | * occurs, the driver will usually tell the hardware watchdog | ||
33 | * that everything is in order, and that the watchdog should wait | ||
34 | * for yet another little while to reset the system. | ||
35 | * If userspace fails (RAM error, kernel bug, whatever), the | ||
36 | * notifications cease to occur, and the hardware watchdog will | ||
37 | * reset the system (causing a reboot) after the timeout occurs. | ||
38 | * | ||
39 | * Create device with: | ||
40 | * mknod /dev/watchdog c 10 130 | ||
41 | * | ||
42 | * For an example userspace keep-alive daemon, see: | ||
43 | * Documentation/watchdog/watchdog.txt | ||
44 | */ | ||
45 | |||
46 | #include <linux/module.h> | ||
47 | #include <linux/moduleparam.h> | ||
48 | #include <linux/types.h> | ||
49 | #include <linux/miscdevice.h> | ||
50 | #include <linux/watchdog.h> | ||
51 | #include <linux/delay.h> | ||
52 | #include <linux/fs.h> | ||
53 | #include <linux/ioport.h> | ||
54 | #include <linux/notifier.h> | ||
55 | #include <linux/reboot.h> | ||
56 | #include <linux/init.h> | ||
57 | #include <linux/spinlock.h> | ||
58 | |||
59 | #include <asm/io.h> | ||
60 | #include <asm/uaccess.h> | ||
61 | #include <asm/system.h> | ||
62 | |||
63 | /* enable support for minutes as units? */ | ||
64 | /* (does not always work correctly, so disabled by default!) */ | ||
65 | #define SMSC_SUPPORT_MINUTES | ||
66 | #undef SMSC_SUPPORT_MINUTES | ||
67 | |||
68 | #define MAX_TIMEOUT 255 | ||
69 | |||
70 | #define UNIT_SECOND 0 | ||
71 | #define UNIT_MINUTE 1 | ||
72 | |||
73 | #define MODNAME "smsc37b787_wdt: " | ||
74 | #define VERSION "1.1" | ||
75 | |||
76 | #define IOPORT 0x3F0 | ||
77 | #define IOPORT_SIZE 2 | ||
78 | #define IODEV_NO 8 | ||
79 | |||
80 | static int unit = UNIT_SECOND; /* timer's unit */ | ||
81 | static int timeout = 60; /* timeout value: default is 60 "units" */ | ||
82 | static unsigned long timer_enabled = 0; /* is the timer enabled? */ | ||
83 | |||
84 | static char expect_close; /* is the close expected? */ | ||
85 | |||
86 | static spinlock_t io_lock; /* to guard the watchdog from io races */ | ||
87 | |||
88 | static int nowayout = WATCHDOG_NOWAYOUT; | ||
89 | |||
90 | /* -- Low level function ----------------------------------------*/ | ||
91 | |||
92 | /* unlock the IO chip */ | ||
93 | |||
94 | static inline void open_io_config(void) | ||
95 | { | ||
96 | outb(0x55, IOPORT); | ||
97 | mdelay(1); | ||
98 | outb(0x55, IOPORT); | ||
99 | } | ||
100 | |||
101 | /* lock the IO chip */ | ||
102 | static inline void close_io_config(void) | ||
103 | { | ||
104 | outb(0xAA, IOPORT); | ||
105 | } | ||
106 | |||
107 | /* select the IO device */ | ||
108 | static inline void select_io_device(unsigned char devno) | ||
109 | { | ||
110 | outb(0x07, IOPORT); | ||
111 | outb(devno, IOPORT+1); | ||
112 | } | ||
113 | |||
114 | /* write to the control register */ | ||
115 | static inline void write_io_cr(unsigned char reg, unsigned char data) | ||
116 | { | ||
117 | outb(reg, IOPORT); | ||
118 | outb(data, IOPORT+1); | ||
119 | } | ||
120 | |||
121 | /* read from the control register */ | ||
122 | static inline char read_io_cr(unsigned char reg) | ||
123 | { | ||
124 | outb(reg, IOPORT); | ||
125 | return inb(IOPORT+1); | ||
126 | } | ||
127 | |||
128 | /* -- Medium level functions ------------------------------------*/ | ||
129 | |||
130 | static inline void gpio_bit12(unsigned char reg) | ||
131 | { | ||
132 | // -- General Purpose I/O Bit 1.2 -- | ||
133 | // Bit 0, In/Out: 0 = Output, 1 = Input | ||
134 | // Bit 1, Polarity: 0 = No Invert, 1 = Invert | ||
135 | // Bit 2, Group Enable Intr.: 0 = Disable, 1 = Enable | ||
136 | // Bit 3/4, Function select: 00 = GPI/O, 01 = WDT, 10 = P17, | ||
137 | // 11 = Either Edge Triggered Intr. 2 | ||
138 | // Bit 5/6 (Reserved) | ||
139 | // Bit 7, Output Type: 0 = Push Pull Bit, 1 = Open Drain | ||
140 | write_io_cr(0xE2, reg); | ||
141 | } | ||
142 | |||
143 | static inline void gpio_bit13(unsigned char reg) | ||
144 | { | ||
145 | // -- General Purpose I/O Bit 1.3 -- | ||
146 | // Bit 0, In/Out: 0 = Output, 1 = Input | ||
147 | // Bit 1, Polarity: 0 = No Invert, 1 = Invert | ||
148 | // Bit 2, Group Enable Intr.: 0 = Disable, 1 = Enable | ||
149 | // Bit 3, Function select: 0 = GPI/O, 1 = LED | ||
150 | // Bit 4-6 (Reserved) | ||
151 | // Bit 7, Output Type: 0 = Push Pull Bit, 1 = Open Drain | ||
152 | write_io_cr(0xE3, reg); | ||
153 | } | ||
154 | |||
155 | static inline void wdt_timer_units(unsigned char new_units) | ||
156 | { | ||
157 | // -- Watchdog timer units -- | ||
158 | // Bit 0-6 (Reserved) | ||
159 | // Bit 7, WDT Time-out Value Units Select | ||
160 | // (0 = Minutes, 1 = Seconds) | ||
161 | write_io_cr(0xF1, new_units); | ||
162 | } | ||
163 | |||
164 | static inline void wdt_timeout_value(unsigned char new_timeout) | ||
165 | { | ||
166 | // -- Watchdog Timer Time-out Value -- | ||
167 | // Bit 0-7 Binary coded units (0=Disabled, 1..255) | ||
168 | write_io_cr(0xF2, new_timeout); | ||
169 | } | ||
170 | |||
171 | static inline void wdt_timer_conf(unsigned char conf) | ||
172 | { | ||
173 | // -- Watchdog timer configuration -- | ||
174 | // Bit 0 Joystick enable: 0* = No Reset, 1 = Reset WDT upon Gameport I/O | ||
175 | // Bit 1 Keyboard enable: 0* = No Reset, 1 = Reset WDT upon KBD Intr. | ||
176 | // Bit 2 Mouse enable: 0* = No Reset, 1 = Reset WDT upon Mouse Intr. | ||
177 | // Bit 3 Reset the timer | ||
178 | // (Wrong in SMsC documentation? Given as: PowerLED Timout Enabled) | ||
179 | // Bit 4-7 WDT Interrupt Mapping: (0000* = Disabled, | ||
180 | // 0001=IRQ1, 0010=(Invalid), 0011=IRQ3 to 1111=IRQ15) | ||
181 | write_io_cr(0xF3, conf); | ||
182 | } | ||
183 | |||
184 | static inline void wdt_timer_ctrl(unsigned char reg) | ||
185 | { | ||
186 | // -- Watchdog timer control -- | ||
187 | // Bit 0 Status Bit: 0 = Timer counting, 1 = Timeout occured | ||
188 | // Bit 1 Power LED Toggle: 0 = Disable Toggle, 1 = Toggle at 1 Hz | ||
189 | // Bit 2 Force Timeout: 1 = Forces WD timeout event (self-cleaning) | ||
190 | // Bit 3 P20 Force Timeout enabled: | ||
191 | // 0 = P20 activity does not generate the WD timeout event | ||
192 | // 1 = P20 Allows rising edge of P20, from the keyboard | ||
193 | // controller, to force the WD timeout event. | ||
194 | // Bit 4 (Reserved) | ||
195 | // -- Soft power management -- | ||
196 | // Bit 5 Stop Counter: 1 = Stop software power down counter | ||
197 | // set via register 0xB8, (self-cleaning) | ||
198 | // (Upon read: 0 = Counter running, 1 = Counter stopped) | ||
199 | // Bit 6 Restart Counter: 1 = Restart software power down counter | ||
200 | // set via register 0xB8, (self-cleaning) | ||
201 | // Bit 7 SPOFF: 1 = Force software power down (self-cleaning) | ||
202 | |||
203 | write_io_cr(0xF4, reg); | ||
204 | } | ||
205 | |||
206 | /* -- Higher level functions ------------------------------------*/ | ||
207 | |||
208 | /* initialize watchdog */ | ||
209 | |||
210 | static void wb_smsc_wdt_initialize(void) | ||
211 | { | ||
212 | unsigned char old; | ||
213 | |||
214 | spin_lock(&io_lock); | ||
215 | open_io_config(); | ||
216 | select_io_device(IODEV_NO); | ||
217 | |||
218 | // enable the watchdog | ||
219 | gpio_bit13(0x08); // Select pin 80 = LED not GPIO | ||
220 | gpio_bit12(0x0A); // Set pin 79 = WDT not GPIO/Output/Polarity=Invert | ||
221 | |||
222 | // disable the timeout | ||
223 | wdt_timeout_value(0); | ||
224 | |||
225 | // reset control register | ||
226 | wdt_timer_ctrl(0x00); | ||
227 | |||
228 | // reset configuration register | ||
229 | wdt_timer_conf(0x00); | ||
230 | |||
231 | // read old (timer units) register | ||
232 | old = read_io_cr(0xF1) & 0x7F; | ||
233 | if (unit == UNIT_SECOND) old |= 0x80; // set to seconds | ||
234 | |||
235 | // set the watchdog timer units | ||
236 | wdt_timer_units(old); | ||
237 | |||
238 | close_io_config(); | ||
239 | spin_unlock(&io_lock); | ||
240 | } | ||
241 | |||
242 | /* shutdown the watchdog */ | ||
243 | |||
244 | static void wb_smsc_wdt_shutdown(void) | ||
245 | { | ||
246 | spin_lock(&io_lock); | ||
247 | open_io_config(); | ||
248 | select_io_device(IODEV_NO); | ||
249 | |||
250 | // disable the watchdog | ||
251 | gpio_bit13(0x09); | ||
252 | gpio_bit12(0x09); | ||
253 | |||
254 | // reset watchdog config register | ||
255 | wdt_timer_conf(0x00); | ||
256 | |||
257 | // reset watchdog control register | ||
258 | wdt_timer_ctrl(0x00); | ||
259 | |||
260 | // disable timeout | ||
261 | wdt_timeout_value(0x00); | ||
262 | |||
263 | close_io_config(); | ||
264 | spin_unlock(&io_lock); | ||
265 | } | ||
266 | |||
267 | /* set timeout => enable watchdog */ | ||
268 | |||
269 | static void wb_smsc_wdt_set_timeout(unsigned char new_timeout) | ||
270 | { | ||
271 | spin_lock(&io_lock); | ||
272 | open_io_config(); | ||
273 | select_io_device(IODEV_NO); | ||
274 | |||
275 | // set Power LED to blink, if we enable the timeout | ||
276 | wdt_timer_ctrl((new_timeout == 0) ? 0x00 : 0x02); | ||
277 | |||
278 | // set timeout value | ||
279 | wdt_timeout_value(new_timeout); | ||
280 | |||
281 | close_io_config(); | ||
282 | spin_unlock(&io_lock); | ||
283 | } | ||
284 | |||
285 | /* get timeout */ | ||
286 | |||
287 | static unsigned char wb_smsc_wdt_get_timeout(void) | ||
288 | { | ||
289 | unsigned char set_timeout; | ||
290 | |||
291 | spin_lock(&io_lock); | ||
292 | open_io_config(); | ||
293 | select_io_device(IODEV_NO); | ||
294 | set_timeout = read_io_cr(0xF2); | ||
295 | close_io_config(); | ||
296 | spin_unlock(&io_lock); | ||
297 | |||
298 | return set_timeout; | ||
299 | } | ||
300 | |||
301 | /* disable watchdog */ | ||
302 | |||
303 | static void wb_smsc_wdt_disable(void) | ||
304 | { | ||
305 | // set the timeout to 0 to disable the watchdog | ||
306 | wb_smsc_wdt_set_timeout(0); | ||
307 | } | ||
308 | |||
309 | /* enable watchdog by setting the current timeout */ | ||
310 | |||
311 | static void wb_smsc_wdt_enable(void) | ||
312 | { | ||
313 | // set the current timeout... | ||
314 | wb_smsc_wdt_set_timeout(timeout); | ||
315 | } | ||
316 | |||
317 | /* reset the timer */ | ||
318 | |||
319 | static void wb_smsc_wdt_reset_timer(void) | ||
320 | { | ||
321 | spin_lock(&io_lock); | ||
322 | open_io_config(); | ||
323 | select_io_device(IODEV_NO); | ||
324 | |||
325 | // reset the timer | ||
326 | wdt_timeout_value(timeout); | ||
327 | wdt_timer_conf(0x08); | ||
328 | |||
329 | close_io_config(); | ||
330 | spin_unlock(&io_lock); | ||
331 | } | ||
332 | |||
333 | /* return, if the watchdog is enabled (timeout is set...) */ | ||
334 | |||
335 | static int wb_smsc_wdt_status(void) | ||
336 | { | ||
337 | return (wb_smsc_wdt_get_timeout() == 0) ? 0 : WDIOF_KEEPALIVEPING; | ||
338 | } | ||
339 | |||
340 | |||
341 | /* -- File operations -------------------------------------------*/ | ||
342 | |||
343 | /* open => enable watchdog and set initial timeout */ | ||
344 | |||
345 | static int wb_smsc_wdt_open(struct inode *inode, struct file *file) | ||
346 | { | ||
347 | /* /dev/watchdog can only be opened once */ | ||
348 | |||
349 | if (test_and_set_bit(0, &timer_enabled)) | ||
350 | return -EBUSY; | ||
351 | |||
352 | if (nowayout) | ||
353 | __module_get(THIS_MODULE); | ||
354 | |||
355 | /* Reload and activate timer */ | ||
356 | wb_smsc_wdt_enable(); | ||
357 | |||
358 | printk(KERN_INFO MODNAME "Watchdog enabled. Timeout set to %d %s.\n", timeout, (unit == UNIT_SECOND) ? "second(s)" : "minute(s)"); | ||
359 | |||
360 | return nonseekable_open(inode, file); | ||
361 | } | ||
362 | |||
363 | /* close => shut off the timer */ | ||
364 | |||
365 | static int wb_smsc_wdt_release(struct inode *inode, struct file *file) | ||
366 | { | ||
367 | /* Shut off the timer. */ | ||
368 | |||
369 | if (expect_close == 42) { | ||
370 | wb_smsc_wdt_disable(); | ||
371 | printk(KERN_INFO MODNAME "Watchdog disabled, sleeping again...\n"); | ||
372 | } else { | ||
373 | printk(KERN_CRIT MODNAME "Unexpected close, not stopping watchdog!\n"); | ||
374 | wb_smsc_wdt_reset_timer(); | ||
375 | } | ||
376 | |||
377 | clear_bit(0, &timer_enabled); | ||
378 | expect_close = 0; | ||
379 | return 0; | ||
380 | } | ||
381 | |||
382 | /* write => update the timer to keep the machine alive */ | ||
383 | |||
384 | static ssize_t wb_smsc_wdt_write(struct file *file, const char __user *data, | ||
385 | size_t len, loff_t *ppos) | ||
386 | { | ||
387 | /* See if we got the magic character 'V' and reload the timer */ | ||
388 | if (len) { | ||
389 | if (!nowayout) { | ||
390 | size_t i; | ||
391 | |||
392 | /* reset expect flag */ | ||
393 | expect_close = 0; | ||
394 | |||
395 | /* scan to see whether or not we got the magic character */ | ||
396 | for (i = 0; i != len; i++) { | ||
397 | char c; | ||
398 | if (get_user(c, data+i)) | ||
399 | return -EFAULT; | ||
400 | if (c == 'V') | ||
401 | expect_close = 42; | ||
402 | } | ||
403 | } | ||
404 | |||
405 | /* someone wrote to us, we should reload the timer */ | ||
406 | wb_smsc_wdt_reset_timer(); | ||
407 | } | ||
408 | return len; | ||
409 | } | ||
410 | |||
411 | /* ioctl => control interface */ | ||
412 | |||
413 | static int wb_smsc_wdt_ioctl(struct inode *inode, struct file *file, | ||
414 | unsigned int cmd, unsigned long arg) | ||
415 | { | ||
416 | int new_timeout; | ||
417 | |||
418 | union { | ||
419 | struct watchdog_info __user *ident; | ||
420 | int __user *i; | ||
421 | } uarg; | ||
422 | |||
423 | static struct watchdog_info ident = { | ||
424 | .options = WDIOF_KEEPALIVEPING | | ||
425 | WDIOF_SETTIMEOUT | | ||
426 | WDIOF_MAGICCLOSE, | ||
427 | .firmware_version = 0, | ||
428 | .identity = "SMsC 37B787 Watchdog" | ||
429 | }; | ||
430 | |||
431 | uarg.i = (int __user *)arg; | ||
432 | |||
433 | switch (cmd) { | ||
434 | default: | ||
435 | return -ENOTTY; | ||
436 | |||
437 | case WDIOC_GETSUPPORT: | ||
438 | return copy_to_user(uarg.ident, &ident, | ||
439 | sizeof(ident)) ? -EFAULT : 0; | ||
440 | |||
441 | case WDIOC_GETSTATUS: | ||
442 | return put_user(wb_smsc_wdt_status(), uarg.i); | ||
443 | |||
444 | case WDIOC_GETBOOTSTATUS: | ||
445 | return put_user(0, uarg.i); | ||
446 | |||
447 | case WDIOC_KEEPALIVE: | ||
448 | wb_smsc_wdt_reset_timer(); | ||
449 | return 0; | ||
450 | |||
451 | case WDIOC_SETTIMEOUT: | ||
452 | if (get_user(new_timeout, uarg.i)) | ||
453 | return -EFAULT; | ||
454 | |||
455 | // the API states this is given in secs | ||
456 | if (unit == UNIT_MINUTE) | ||
457 | new_timeout /= 60; | ||
458 | |||
459 | if (new_timeout < 0 || new_timeout > MAX_TIMEOUT) | ||
460 | return -EINVAL; | ||
461 | |||
462 | timeout = new_timeout; | ||
463 | wb_smsc_wdt_set_timeout(timeout); | ||
464 | |||
465 | // fall through and return the new timeout... | ||
466 | |||
467 | case WDIOC_GETTIMEOUT: | ||
468 | |||
469 | new_timeout = timeout; | ||
470 | |||
471 | if (unit == UNIT_MINUTE) | ||
472 | new_timeout *= 60; | ||
473 | |||
474 | return put_user(new_timeout, uarg.i); | ||
475 | |||
476 | case WDIOC_SETOPTIONS: | ||
477 | { | ||
478 | int options, retval = -EINVAL; | ||
479 | |||
480 | if (get_user(options, uarg.i)) | ||
481 | return -EFAULT; | ||
482 | |||
483 | if (options & WDIOS_DISABLECARD) { | ||
484 | wb_smsc_wdt_disable(); | ||
485 | retval = 0; | ||
486 | } | ||
487 | |||
488 | if (options & WDIOS_ENABLECARD) { | ||
489 | wb_smsc_wdt_enable(); | ||
490 | retval = 0; | ||
491 | } | ||
492 | |||
493 | return retval; | ||
494 | } | ||
495 | } | ||
496 | } | ||
497 | |||
498 | /* -- Notifier funtions -----------------------------------------*/ | ||
499 | |||
500 | static int wb_smsc_wdt_notify_sys(struct notifier_block *this, unsigned long code, void *unused) | ||
501 | { | ||
502 | if (code == SYS_DOWN || code == SYS_HALT) | ||
503 | { | ||
504 | // set timeout to 0, to avoid possible race-condition | ||
505 | timeout = 0; | ||
506 | wb_smsc_wdt_disable(); | ||
507 | } | ||
508 | return NOTIFY_DONE; | ||
509 | } | ||
510 | |||
511 | /* -- Module's structures ---------------------------------------*/ | ||
512 | |||
513 | static struct file_operations wb_smsc_wdt_fops = | ||
514 | { | ||
515 | .owner = THIS_MODULE, | ||
516 | .llseek = no_llseek, | ||
517 | .write = wb_smsc_wdt_write, | ||
518 | .ioctl = wb_smsc_wdt_ioctl, | ||
519 | .open = wb_smsc_wdt_open, | ||
520 | .release = wb_smsc_wdt_release, | ||
521 | }; | ||
522 | |||
523 | static struct notifier_block wb_smsc_wdt_notifier = | ||
524 | { | ||
525 | .notifier_call = wb_smsc_wdt_notify_sys, | ||
526 | }; | ||
527 | |||
528 | static struct miscdevice wb_smsc_wdt_miscdev = | ||
529 | { | ||
530 | .minor = WATCHDOG_MINOR, | ||
531 | .name = "watchdog", | ||
532 | .fops = &wb_smsc_wdt_fops, | ||
533 | }; | ||
534 | |||
535 | /* -- Module init functions -------------------------------------*/ | ||
536 | |||
537 | /* module's "constructor" */ | ||
538 | |||
539 | static int __init wb_smsc_wdt_init(void) | ||
540 | { | ||
541 | int ret; | ||
542 | |||
543 | spin_lock_init(&io_lock); | ||
544 | |||
545 | printk("SMsC 37B787 watchdog component driver " VERSION " initialising...\n"); | ||
546 | |||
547 | if (!request_region(IOPORT, IOPORT_SIZE, "SMsC 37B787 watchdog")) { | ||
548 | printk(KERN_ERR MODNAME "Unable to register IO port %#x\n", IOPORT); | ||
549 | ret = -EBUSY; | ||
550 | goto out_pnp; | ||
551 | } | ||
552 | |||
553 | // set new maximum, if it's too big | ||
554 | if (timeout > MAX_TIMEOUT) | ||
555 | timeout = MAX_TIMEOUT; | ||
556 | |||
557 | // init the watchdog timer | ||
558 | wb_smsc_wdt_initialize(); | ||
559 | |||
560 | ret = register_reboot_notifier(&wb_smsc_wdt_notifier); | ||
561 | if (ret) { | ||
562 | printk(KERN_ERR MODNAME "Unable to register reboot notifier err = %d\n", ret); | ||
563 | goto out_io; | ||
564 | } | ||
565 | |||
566 | ret = misc_register(&wb_smsc_wdt_miscdev); | ||
567 | if (ret) { | ||
568 | printk(KERN_ERR MODNAME "Unable to register miscdev on minor %d\n", WATCHDOG_MINOR); | ||
569 | goto out_rbt; | ||
570 | } | ||
571 | |||
572 | // output info | ||
573 | printk(KERN_INFO MODNAME "Timeout set to %d %s.\n", timeout, (unit == UNIT_SECOND) ? "second(s)" : "minute(s)"); | ||
574 | printk(KERN_INFO MODNAME "Watchdog initialized and sleeping (nowayout=%d)...\n", nowayout); | ||
575 | |||
576 | // ret = 0 | ||
577 | |||
578 | out_clean: | ||
579 | return ret; | ||
580 | |||
581 | out_rbt: | ||
582 | unregister_reboot_notifier(&wb_smsc_wdt_notifier); | ||
583 | |||
584 | out_io: | ||
585 | release_region(IOPORT, IOPORT_SIZE); | ||
586 | |||
587 | out_pnp: | ||
588 | goto out_clean; | ||
589 | } | ||
590 | |||
591 | /* module's "destructor" */ | ||
592 | |||
593 | static void __exit wb_smsc_wdt_exit(void) | ||
594 | { | ||
595 | /* Stop the timer before we leave */ | ||
596 | if (!nowayout) | ||
597 | { | ||
598 | wb_smsc_wdt_shutdown(); | ||
599 | printk(KERN_INFO MODNAME "Watchdog disabled.\n"); | ||
600 | } | ||
601 | |||
602 | misc_deregister(&wb_smsc_wdt_miscdev); | ||
603 | unregister_reboot_notifier(&wb_smsc_wdt_notifier); | ||
604 | release_region(IOPORT, IOPORT_SIZE); | ||
605 | |||
606 | printk("SMsC 37B787 watchdog component driver removed.\n"); | ||
607 | } | ||
608 | |||
609 | module_init(wb_smsc_wdt_init); | ||
610 | module_exit(wb_smsc_wdt_exit); | ||
611 | |||
612 | MODULE_AUTHOR("Sven Anders <anders@anduras.de>"); | ||
613 | MODULE_DESCRIPTION("Driver for SMsC 37B787 watchdog component (Version " VERSION ")"); | ||
614 | MODULE_LICENSE("GPL"); | ||
615 | |||
616 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); | ||
617 | |||
618 | #ifdef SMSC_SUPPORT_MINUTES | ||
619 | module_param(unit, int, 0); | ||
620 | MODULE_PARM_DESC(unit, "set unit to use, 0=seconds or 1=minutes, default is 0"); | ||
621 | #endif | ||
622 | |||
623 | module_param(timeout, int, 0); | ||
624 | MODULE_PARM_DESC(timeout, "range is 1-255 units, default is 60"); | ||
625 | |||
626 | module_param(nowayout, int, 0); | ||
627 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); | ||
diff --git a/drivers/char/watchdog/w83627hf_wdt.c b/drivers/char/watchdog/w83627hf_wdt.c index b4adc527e687..07d4bff27226 100644 --- a/drivers/char/watchdog/w83627hf_wdt.c +++ b/drivers/char/watchdog/w83627hf_wdt.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/notifier.h> | 33 | #include <linux/notifier.h> |
34 | #include <linux/reboot.h> | 34 | #include <linux/reboot.h> |
35 | #include <linux/init.h> | 35 | #include <linux/init.h> |
36 | #include <linux/spinlock.h> | ||
36 | 37 | ||
37 | #include <asm/io.h> | 38 | #include <asm/io.h> |
38 | #include <asm/uaccess.h> | 39 | #include <asm/uaccess.h> |
@@ -44,6 +45,7 @@ | |||
44 | 45 | ||
45 | static unsigned long wdt_is_open; | 46 | static unsigned long wdt_is_open; |
46 | static char expect_close; | 47 | static char expect_close; |
48 | static spinlock_t io_lock; | ||
47 | 49 | ||
48 | /* You must set this - there is no sane way to probe for this board. */ | 50 | /* You must set this - there is no sane way to probe for this board. */ |
49 | static int wdt_io = 0x2E; | 51 | static int wdt_io = 0x2E; |
@@ -110,12 +112,16 @@ w83627hf_init(void) | |||
110 | static void | 112 | static void |
111 | wdt_ctrl(int timeout) | 113 | wdt_ctrl(int timeout) |
112 | { | 114 | { |
115 | spin_lock(&io_lock); | ||
116 | |||
113 | w83627hf_select_wd_register(); | 117 | w83627hf_select_wd_register(); |
114 | 118 | ||
115 | outb_p(0xF6, WDT_EFER); /* Select CRF6 */ | 119 | outb_p(0xF6, WDT_EFER); /* Select CRF6 */ |
116 | outb_p(timeout, WDT_EFDR); /* Write Timeout counter to CRF6 */ | 120 | outb_p(timeout, WDT_EFDR); /* Write Timeout counter to CRF6 */ |
117 | 121 | ||
118 | w83627hf_unselect_wd_register(); | 122 | w83627hf_unselect_wd_register(); |
123 | |||
124 | spin_unlock(&io_lock); | ||
119 | } | 125 | } |
120 | 126 | ||
121 | static int | 127 | static int |
@@ -303,6 +309,8 @@ wdt_init(void) | |||
303 | { | 309 | { |
304 | int ret; | 310 | int ret; |
305 | 311 | ||
312 | spin_lock_init(&io_lock); | ||
313 | |||
306 | printk(KERN_INFO "WDT driver for the Winbond(TM) W83627HF Super I/O chip initialising.\n"); | 314 | printk(KERN_INFO "WDT driver for the Winbond(TM) W83627HF Super I/O chip initialising.\n"); |
307 | 315 | ||
308 | if (wdt_set_heartbeat(timeout)) { | 316 | if (wdt_set_heartbeat(timeout)) { |
diff --git a/drivers/char/watchdog/w83697hf_wdt.c b/drivers/char/watchdog/w83697hf_wdt.c new file mode 100644 index 000000000000..7768b55487c8 --- /dev/null +++ b/drivers/char/watchdog/w83697hf_wdt.c | |||
@@ -0,0 +1,450 @@ | |||
1 | /* | ||
2 | * w83697hf/hg WDT driver | ||
3 | * | ||
4 | * (c) Copyright 2006 Samuel Tardieu <sam@rfc1149.net> | ||
5 | * (c) Copyright 2006 Marcus Junker <junker@anduras.de> | ||
6 | * | ||
7 | * Based on w83627hf_wdt.c which is based on advantechwdt.c | ||
8 | * which is based on wdt.c. | ||
9 | * Original copyright messages: | ||
10 | * | ||
11 | * (c) Copyright 2003 Pádraig Brady <P@draigBrady.com> | ||
12 | * | ||
13 | * (c) Copyright 2000-2001 Marek Michalkiewicz <marekm@linux.org.pl> | ||
14 | * | ||
15 | * (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved. | ||
16 | * http://www.redhat.com | ||
17 | * | ||
18 | * This program is free software; you can redistribute it and/or | ||
19 | * modify it under the terms of the GNU General Public License | ||
20 | * as published by the Free Software Foundation; either version | ||
21 | * 2 of the License, or (at your option) any later version. | ||
22 | * | ||
23 | * Neither Marcus Junker nor ANDURAS AG admit liability nor provide | ||
24 | * warranty for any of this software. This material is provided | ||
25 | * "AS-IS" and at no charge. | ||
26 | */ | ||
27 | |||
28 | #include <linux/module.h> | ||
29 | #include <linux/moduleparam.h> | ||
30 | #include <linux/types.h> | ||
31 | #include <linux/miscdevice.h> | ||
32 | #include <linux/watchdog.h> | ||
33 | #include <linux/fs.h> | ||
34 | #include <linux/ioport.h> | ||
35 | #include <linux/notifier.h> | ||
36 | #include <linux/reboot.h> | ||
37 | #include <linux/init.h> | ||
38 | #include <linux/spinlock.h> | ||
39 | |||
40 | #include <asm/io.h> | ||
41 | #include <asm/uaccess.h> | ||
42 | #include <asm/system.h> | ||
43 | |||
44 | #define WATCHDOG_NAME "w83697hf/hg WDT" | ||
45 | #define PFX WATCHDOG_NAME ": " | ||
46 | #define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */ | ||
47 | |||
48 | static unsigned long wdt_is_open; | ||
49 | static char expect_close; | ||
50 | static spinlock_t io_lock; | ||
51 | |||
52 | /* You must set this - there is no sane way to probe for this board. */ | ||
53 | static int wdt_io = 0x2e; | ||
54 | module_param(wdt_io, int, 0); | ||
55 | MODULE_PARM_DESC(wdt_io, "w83697hf/hg WDT io port (default 0x2e, 0 = autodetect)"); | ||
56 | |||
57 | static int timeout = WATCHDOG_TIMEOUT; /* in seconds */ | ||
58 | module_param(timeout, int, 0); | ||
59 | MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=255, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) "."); | ||
60 | |||
61 | static int nowayout = WATCHDOG_NOWAYOUT; | ||
62 | module_param(nowayout, int, 0); | ||
63 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); | ||
64 | |||
65 | /* | ||
66 | * Kernel methods. | ||
67 | */ | ||
68 | |||
69 | #define W83697HF_EFER (wdt_io+0) /* Extended Function Enable Register */ | ||
70 | #define W83697HF_EFIR (wdt_io+0) /* Extended Function Index Register (same as EFER) */ | ||
71 | #define W83697HF_EFDR (wdt_io+1) /* Extended Function Data Register */ | ||
72 | |||
73 | static inline void | ||
74 | w83697hf_unlock(void) | ||
75 | { | ||
76 | outb_p(0x87, W83697HF_EFER); /* Enter extended function mode */ | ||
77 | outb_p(0x87, W83697HF_EFER); /* Again according to manual */ | ||
78 | } | ||
79 | |||
80 | static inline void | ||
81 | w83697hf_lock(void) | ||
82 | { | ||
83 | outb_p(0xAA, W83697HF_EFER); /* Leave extended function mode */ | ||
84 | } | ||
85 | |||
86 | /* | ||
87 | * The three functions w83697hf_get_reg(), w83697hf_set_reg() and | ||
88 | * w83697hf_write_timeout() must be called with the device unlocked. | ||
89 | */ | ||
90 | |||
91 | static unsigned char | ||
92 | w83697hf_get_reg(unsigned char reg) | ||
93 | { | ||
94 | outb_p(reg, W83697HF_EFIR); | ||
95 | return inb_p(W83697HF_EFDR); | ||
96 | } | ||
97 | |||
98 | static void | ||
99 | w83697hf_set_reg(unsigned char reg, unsigned char data) | ||
100 | { | ||
101 | outb_p(reg, W83697HF_EFIR); | ||
102 | outb_p(data, W83697HF_EFDR); | ||
103 | } | ||
104 | |||
105 | static void | ||
106 | w83697hf_write_timeout(int timeout) | ||
107 | { | ||
108 | w83697hf_set_reg(0xF4, timeout); /* Write Timeout counter to CRF4 */ | ||
109 | } | ||
110 | |||
111 | static void | ||
112 | w83697hf_select_wdt(void) | ||
113 | { | ||
114 | w83697hf_unlock(); | ||
115 | w83697hf_set_reg(0x07, 0x08); /* Switch to logic device 8 (GPIO2) */ | ||
116 | } | ||
117 | |||
118 | static inline void | ||
119 | w83697hf_deselect_wdt(void) | ||
120 | { | ||
121 | w83697hf_lock(); | ||
122 | } | ||
123 | |||
124 | static void | ||
125 | w83697hf_init(void) | ||
126 | { | ||
127 | unsigned char bbuf; | ||
128 | |||
129 | w83697hf_select_wdt(); | ||
130 | |||
131 | bbuf = w83697hf_get_reg(0x29); | ||
132 | bbuf &= ~0x60; | ||
133 | bbuf |= 0x20; | ||
134 | w83697hf_set_reg(0x29, bbuf); /* Set pin 119 to WDTO# mode (= CR29, WDT0) */ | ||
135 | |||
136 | bbuf = w83697hf_get_reg(0xF3); | ||
137 | bbuf &= ~0x04; | ||
138 | w83697hf_set_reg(0xF3, bbuf); /* Count mode is seconds */ | ||
139 | |||
140 | w83697hf_deselect_wdt(); | ||
141 | } | ||
142 | |||
143 | static int | ||
144 | wdt_ping(void) | ||
145 | { | ||
146 | spin_lock(&io_lock); | ||
147 | w83697hf_select_wdt(); | ||
148 | |||
149 | w83697hf_write_timeout(timeout); | ||
150 | |||
151 | w83697hf_deselect_wdt(); | ||
152 | spin_unlock(&io_lock); | ||
153 | return 0; | ||
154 | } | ||
155 | |||
156 | static int | ||
157 | wdt_enable(void) | ||
158 | { | ||
159 | spin_lock(&io_lock); | ||
160 | w83697hf_select_wdt(); | ||
161 | |||
162 | w83697hf_write_timeout(timeout); | ||
163 | w83697hf_set_reg(0x30, 1); /* Enable timer */ | ||
164 | |||
165 | w83697hf_deselect_wdt(); | ||
166 | spin_unlock(&io_lock); | ||
167 | return 0; | ||
168 | } | ||
169 | |||
170 | static int | ||
171 | wdt_disable(void) | ||
172 | { | ||
173 | spin_lock(&io_lock); | ||
174 | w83697hf_select_wdt(); | ||
175 | |||
176 | w83697hf_set_reg(0x30, 0); /* Disable timer */ | ||
177 | w83697hf_write_timeout(0); | ||
178 | |||
179 | w83697hf_deselect_wdt(); | ||
180 | spin_unlock(&io_lock); | ||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | static int | ||
185 | wdt_set_heartbeat(int t) | ||
186 | { | ||
187 | if ((t < 1) || (t > 255)) | ||
188 | return -EINVAL; | ||
189 | |||
190 | timeout = t; | ||
191 | return 0; | ||
192 | } | ||
193 | |||
194 | static ssize_t | ||
195 | wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) | ||
196 | { | ||
197 | if (count) { | ||
198 | if (!nowayout) { | ||
199 | size_t i; | ||
200 | |||
201 | expect_close = 0; | ||
202 | |||
203 | for (i = 0; i != count; i++) { | ||
204 | char c; | ||
205 | if (get_user(c, buf+i)) | ||
206 | return -EFAULT; | ||
207 | if (c == 'V') | ||
208 | expect_close = 42; | ||
209 | } | ||
210 | } | ||
211 | wdt_ping(); | ||
212 | } | ||
213 | return count; | ||
214 | } | ||
215 | |||
216 | static int | ||
217 | wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | ||
218 | unsigned long arg) | ||
219 | { | ||
220 | void __user *argp = (void __user *)arg; | ||
221 | int __user *p = argp; | ||
222 | int new_timeout; | ||
223 | static struct watchdog_info ident = { | ||
224 | .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, | ||
225 | .firmware_version = 1, | ||
226 | .identity = "W83697HF WDT", | ||
227 | }; | ||
228 | |||
229 | switch (cmd) { | ||
230 | case WDIOC_GETSUPPORT: | ||
231 | if (copy_to_user(argp, &ident, sizeof(ident))) | ||
232 | return -EFAULT; | ||
233 | break; | ||
234 | |||
235 | case WDIOC_GETSTATUS: | ||
236 | case WDIOC_GETBOOTSTATUS: | ||
237 | return put_user(0, p); | ||
238 | |||
239 | case WDIOC_KEEPALIVE: | ||
240 | wdt_ping(); | ||
241 | break; | ||
242 | |||
243 | case WDIOC_SETTIMEOUT: | ||
244 | if (get_user(new_timeout, p)) | ||
245 | return -EFAULT; | ||
246 | if (wdt_set_heartbeat(new_timeout)) | ||
247 | return -EINVAL; | ||
248 | wdt_ping(); | ||
249 | /* Fall */ | ||
250 | |||
251 | case WDIOC_GETTIMEOUT: | ||
252 | return put_user(timeout, p); | ||
253 | |||
254 | case WDIOC_SETOPTIONS: | ||
255 | { | ||
256 | int options, retval = -EINVAL; | ||
257 | |||
258 | if (get_user(options, p)) | ||
259 | return -EFAULT; | ||
260 | |||
261 | if (options & WDIOS_DISABLECARD) { | ||
262 | wdt_disable(); | ||
263 | retval = 0; | ||
264 | } | ||
265 | |||
266 | if (options & WDIOS_ENABLECARD) { | ||
267 | wdt_enable(); | ||
268 | retval = 0; | ||
269 | } | ||
270 | |||
271 | return retval; | ||
272 | } | ||
273 | |||
274 | default: | ||
275 | return -ENOTTY; | ||
276 | } | ||
277 | return 0; | ||
278 | } | ||
279 | |||
280 | static int | ||
281 | wdt_open(struct inode *inode, struct file *file) | ||
282 | { | ||
283 | if (test_and_set_bit(0, &wdt_is_open)) | ||
284 | return -EBUSY; | ||
285 | /* | ||
286 | * Activate | ||
287 | */ | ||
288 | |||
289 | wdt_enable(); | ||
290 | return nonseekable_open(inode, file); | ||
291 | } | ||
292 | |||
293 | static int | ||
294 | wdt_close(struct inode *inode, struct file *file) | ||
295 | { | ||
296 | if (expect_close == 42) { | ||
297 | wdt_disable(); | ||
298 | } else { | ||
299 | printk (KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); | ||
300 | wdt_ping(); | ||
301 | } | ||
302 | expect_close = 0; | ||
303 | clear_bit(0, &wdt_is_open); | ||
304 | return 0; | ||
305 | } | ||
306 | |||
307 | /* | ||
308 | * Notifier for system down | ||
309 | */ | ||
310 | |||
311 | static int | ||
312 | wdt_notify_sys(struct notifier_block *this, unsigned long code, | ||
313 | void *unused) | ||
314 | { | ||
315 | if (code == SYS_DOWN || code == SYS_HALT) { | ||
316 | /* Turn the WDT off */ | ||
317 | wdt_disable(); | ||
318 | } | ||
319 | return NOTIFY_DONE; | ||
320 | } | ||
321 | |||
322 | /* | ||
323 | * Kernel Interfaces | ||
324 | */ | ||
325 | |||
326 | static struct file_operations wdt_fops = { | ||
327 | .owner = THIS_MODULE, | ||
328 | .llseek = no_llseek, | ||
329 | .write = wdt_write, | ||
330 | .ioctl = wdt_ioctl, | ||
331 | .open = wdt_open, | ||
332 | .release = wdt_close, | ||
333 | }; | ||
334 | |||
335 | static struct miscdevice wdt_miscdev = { | ||
336 | .minor = WATCHDOG_MINOR, | ||
337 | .name = "watchdog", | ||
338 | .fops = &wdt_fops, | ||
339 | }; | ||
340 | |||
341 | /* | ||
342 | * The WDT needs to learn about soft shutdowns in order to | ||
343 | * turn the timebomb registers off. | ||
344 | */ | ||
345 | |||
346 | static struct notifier_block wdt_notifier = { | ||
347 | .notifier_call = wdt_notify_sys, | ||
348 | }; | ||
349 | |||
350 | static int | ||
351 | w83697hf_check_wdt(void) | ||
352 | { | ||
353 | if (!request_region(wdt_io, 2, WATCHDOG_NAME)) { | ||
354 | printk (KERN_ERR PFX "I/O address 0x%x already in use\n", wdt_io); | ||
355 | return -EIO; | ||
356 | } | ||
357 | |||
358 | printk (KERN_DEBUG PFX "Looking for watchdog at address 0x%x\n", wdt_io); | ||
359 | w83697hf_unlock(); | ||
360 | if (w83697hf_get_reg(0x20) == 0x60) { | ||
361 | printk (KERN_INFO PFX "watchdog found at address 0x%x\n", wdt_io); | ||
362 | w83697hf_lock(); | ||
363 | return 0; | ||
364 | } | ||
365 | w83697hf_lock(); /* Reprotect in case it was a compatible device */ | ||
366 | |||
367 | printk (KERN_INFO PFX "watchdog not found at address 0x%x\n", wdt_io); | ||
368 | release_region(wdt_io, 2); | ||
369 | return -EIO; | ||
370 | } | ||
371 | |||
372 | static int w83697hf_ioports[] = { 0x2e, 0x4e, 0x00 }; | ||
373 | |||
374 | static int __init | ||
375 | wdt_init(void) | ||
376 | { | ||
377 | int ret, i, found = 0; | ||
378 | |||
379 | spin_lock_init(&io_lock); | ||
380 | |||
381 | printk (KERN_INFO PFX "WDT driver for W83697HF/HG initializing\n"); | ||
382 | |||
383 | if (wdt_io == 0) { | ||
384 | /* we will autodetect the W83697HF/HG watchdog */ | ||
385 | for (i = 0; ((!found) && (w83697hf_ioports[i] != 0)); i++) { | ||
386 | wdt_io = w83697hf_ioports[i]; | ||
387 | if (!w83697hf_check_wdt()) | ||
388 | found++; | ||
389 | } | ||
390 | } else { | ||
391 | if (!w83697hf_check_wdt()) | ||
392 | found++; | ||
393 | } | ||
394 | |||
395 | if (!found) { | ||
396 | printk (KERN_ERR PFX "No W83697HF/HG could be found\n"); | ||
397 | ret = -EIO; | ||
398 | goto out; | ||
399 | } | ||
400 | |||
401 | w83697hf_init(); | ||
402 | wdt_disable(); /* Disable watchdog until first use */ | ||
403 | |||
404 | if (wdt_set_heartbeat(timeout)) { | ||
405 | wdt_set_heartbeat(WATCHDOG_TIMEOUT); | ||
406 | printk (KERN_INFO PFX "timeout value must be 1<=timeout<=255, using %d\n", | ||
407 | WATCHDOG_TIMEOUT); | ||
408 | } | ||
409 | |||
410 | ret = register_reboot_notifier(&wdt_notifier); | ||
411 | if (ret != 0) { | ||
412 | printk (KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", | ||
413 | ret); | ||
414 | goto unreg_regions; | ||
415 | } | ||
416 | |||
417 | ret = misc_register(&wdt_miscdev); | ||
418 | if (ret != 0) { | ||
419 | printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", | ||
420 | WATCHDOG_MINOR, ret); | ||
421 | goto unreg_reboot; | ||
422 | } | ||
423 | |||
424 | printk (KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n", | ||
425 | timeout, nowayout); | ||
426 | |||
427 | out: | ||
428 | return ret; | ||
429 | unreg_reboot: | ||
430 | unregister_reboot_notifier(&wdt_notifier); | ||
431 | unreg_regions: | ||
432 | release_region(wdt_io, 2); | ||
433 | goto out; | ||
434 | } | ||
435 | |||
436 | static void __exit | ||
437 | wdt_exit(void) | ||
438 | { | ||
439 | misc_deregister(&wdt_miscdev); | ||
440 | unregister_reboot_notifier(&wdt_notifier); | ||
441 | release_region(wdt_io, 2); | ||
442 | } | ||
443 | |||
444 | module_init(wdt_init); | ||
445 | module_exit(wdt_exit); | ||
446 | |||
447 | MODULE_LICENSE("GPL"); | ||
448 | MODULE_AUTHOR("Marcus Junker <junker@anduras.de>, Samuel Tardieu <sam@rfc1149.net>"); | ||
449 | MODULE_DESCRIPTION("w83697hf/hg WDT driver"); | ||
450 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); | ||