summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/base/attribute_container.c5
-rw-r--r--drivers/base/class.c10
-rw-r--r--drivers/base/firmware_class.c9
-rw-r--r--drivers/base/map.c3
-rw-r--r--drivers/base/platform.c3
-rw-r--r--drivers/block/cciss.c639
-rw-r--r--drivers/block/cciss.h10
-rw-r--r--drivers/block/cciss_cmd.h8
-rw-r--r--drivers/block/cciss_scsi.c69
-rw-r--r--drivers/block/pktcdvd.c85
-rw-r--r--drivers/char/amiserial.c4
-rw-r--r--drivers/char/watchdog/Kconfig93
-rw-r--r--drivers/char/watchdog/Makefile7
-rw-r--r--drivers/char/watchdog/i6300esb.c527
-rw-r--r--drivers/char/watchdog/ibmasr.c405
-rw-r--r--drivers/char/watchdog/mv64x60_wdt.c252
-rw-r--r--drivers/char/watchdog/pcwd_pci.c44
-rw-r--r--drivers/char/watchdog/s3c2410_wdt.c2
-rw-r--r--drivers/char/watchdog/sbc8360.c414
-rw-r--r--drivers/char/watchdog/w83977f_wdt.c543
-rw-r--r--drivers/i2c/busses/i2c-keywest.c1
-rw-r--r--drivers/ide/ide-iops.c41
-rw-r--r--drivers/ide/pci/cmd64x.c2
-rw-r--r--drivers/ide/pci/hpt34x.c2
-rw-r--r--drivers/input/keyboard/Kconfig11
-rw-r--r--drivers/input/keyboard/Makefile1
-rw-r--r--drivers/input/keyboard/spitzkbd.c478
-rw-r--r--drivers/input/touchscreen/Kconfig6
-rw-r--r--drivers/input/touchscreen/corgi_ts.c70
-rw-r--r--drivers/isdn/sc/init.c4
-rw-r--r--drivers/media/radio/radio-aimslab.c2
-rw-r--r--drivers/media/radio/radio-aztech.c2
-rw-r--r--drivers/media/radio/radio-cadet.c2
-rw-r--r--drivers/media/radio/radio-gemtek.c2
-rw-r--r--drivers/media/radio/radio-rtrack2.c2
-rw-r--r--drivers/media/radio/radio-sf16fmi.c2
-rw-r--r--drivers/media/radio/radio-sf16fmr2.c2
-rw-r--r--drivers/media/radio/radio-terratec.c2
-rw-r--r--drivers/media/radio/radio-typhoon.c2
-rw-r--r--drivers/media/radio/radio-zoltrix.c2
-rw-r--r--drivers/media/video/cx88/cx88-dvb.c7
-rw-r--r--drivers/net/arcnet/com90io.c4
-rw-r--r--drivers/net/wireless/orinoco_cs.c1
-rw-r--r--drivers/pcmcia/pcmcia_ioctl.c12
-rw-r--r--drivers/sbus/char/display7seg.c2
-rw-r--r--drivers/tc/zs.c2
-rw-r--r--drivers/video/Kconfig3
-rw-r--r--drivers/video/backlight/corgi_bl.c25
-rw-r--r--drivers/video/console/fbcon.c18
-rw-r--r--drivers/video/console/fbcon.h2
-rw-r--r--drivers/video/console/font_10x18.c4
-rw-r--r--drivers/video/console/font_6x11.c4
-rw-r--r--drivers/video/console/font_7x14.c4
-rw-r--r--drivers/video/console/font_8x16.c4
-rw-r--r--drivers/video/console/font_8x8.c4
-rw-r--r--drivers/video/console/font_acorn_8x8.c4
-rw-r--r--drivers/video/console/font_mini_4x6.c4
-rw-r--r--drivers/video/console/font_pearl_8x8.c4
-rw-r--r--drivers/video/console/font_sun12x22.c4
-rw-r--r--drivers/video/console/font_sun8x16.c4
-rw-r--r--drivers/video/console/fonts.c9
-rw-r--r--drivers/video/matrox/matroxfb_base.c13
-rw-r--r--drivers/video/pm3fb.c3
63 files changed, 3438 insertions, 471 deletions
diff --git a/drivers/base/attribute_container.c b/drivers/base/attribute_container.c
index 373e7b7..6b2eb6f 100644
--- a/drivers/base/attribute_container.c
+++ b/drivers/base/attribute_container.c
@@ -152,12 +152,13 @@ attribute_container_add_device(struct device *dev,
if (!cont->match(cont, dev))
continue;
- ic = kmalloc(sizeof(struct internal_container), GFP_KERNEL);
+
+ ic = kzalloc(sizeof(*ic), GFP_KERNEL);
if (!ic) {
dev_printk(KERN_ERR, dev, "failed to allocate class container\n");
continue;
}
- memset(ic, 0, sizeof(struct internal_container));
+
ic->cont = cont;
class_device_initialize(&ic->classdev);
ic->classdev.dev = get_device(dev);
diff --git a/drivers/base/class.c b/drivers/base/class.c
index d164c32..3b112e3 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -189,12 +189,11 @@ struct class *class_create(struct module *owner, char *name)
struct class *cls;
int retval;
- cls = kmalloc(sizeof(struct class), GFP_KERNEL);
+ cls = kzalloc(sizeof(*cls), GFP_KERNEL);
if (!cls) {
retval = -ENOMEM;
goto error;
}
- memset(cls, 0x00, sizeof(struct class));
cls->name = name;
cls->owner = owner;
@@ -500,13 +499,13 @@ int class_device_add(struct class_device *class_dev)
/* add the needed attributes to this device */
if (MAJOR(class_dev->devt)) {
struct class_device_attribute *attr;
- attr = kmalloc(sizeof(*attr), GFP_KERNEL);
+ attr = kzalloc(sizeof(*attr), GFP_KERNEL);
if (!attr) {
error = -ENOMEM;
kobject_del(&class_dev->kobj);
goto register_done;
}
- memset(attr, sizeof(*attr), 0x00);
+
attr->attr.name = "dev";
attr->attr.mode = S_IRUGO;
attr->attr.owner = parent->owner;
@@ -577,12 +576,11 @@ struct class_device *class_device_create(struct class *cls, dev_t devt,
if (cls == NULL || IS_ERR(cls))
goto error;
- class_dev = kmalloc(sizeof(struct class_device), GFP_KERNEL);
+ class_dev = kzalloc(sizeof(*class_dev), GFP_KERNEL);
if (!class_dev) {
retval = -ENOMEM;
goto error;
}
- memset(class_dev, 0x00, sizeof(struct class_device));
class_dev->devt = devt;
class_dev->dev = device;
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 5bfa2e9..4acb2c5 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -301,9 +301,9 @@ fw_register_class_device(struct class_device **class_dev_p,
const char *fw_name, struct device *device)
{
int retval;
- struct firmware_priv *fw_priv = kmalloc(sizeof (struct firmware_priv),
+ struct firmware_priv *fw_priv = kzalloc(sizeof(*fw_priv),
GFP_KERNEL);
- struct class_device *class_dev = kmalloc(sizeof (struct class_device),
+ struct class_device *class_dev = kzalloc(sizeof(*class_dev),
GFP_KERNEL);
*class_dev_p = NULL;
@@ -313,8 +313,6 @@ fw_register_class_device(struct class_device **class_dev_p,
retval = -ENOMEM;
goto error_kfree;
}
- memset(fw_priv, 0, sizeof (*fw_priv));
- memset(class_dev, 0, sizeof (*class_dev));
init_completion(&fw_priv->completion);
fw_priv->attr_data = firmware_attr_data_tmpl;
@@ -402,14 +400,13 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
if (!firmware_p)
return -EINVAL;
- *firmware_p = firmware = kmalloc(sizeof (struct firmware), GFP_KERNEL);
+ *firmware_p = firmware = kzalloc(sizeof(*firmware), GFP_KERNEL);
if (!firmware) {
printk(KERN_ERR "%s: kmalloc(struct firmware) failed\n",
__FUNCTION__);
retval = -ENOMEM;
goto out;
}
- memset(firmware, 0, sizeof (*firmware));
retval = fw_setup_class_device(firmware, &class_dev, name, device,
hotplug);
diff --git a/drivers/base/map.c b/drivers/base/map.c
index 2f455d8..b449dae 100644
--- a/drivers/base/map.c
+++ b/drivers/base/map.c
@@ -135,7 +135,7 @@ retry:
struct kobj_map *kobj_map_init(kobj_probe_t *base_probe, struct semaphore *sem)
{
struct kobj_map *p = kmalloc(sizeof(struct kobj_map), GFP_KERNEL);
- struct probe *base = kmalloc(sizeof(struct probe), GFP_KERNEL);
+ struct probe *base = kzalloc(sizeof(*base), GFP_KERNEL);
int i;
if ((p == NULL) || (base == NULL)) {
@@ -144,7 +144,6 @@ struct kobj_map *kobj_map_init(kobj_probe_t *base_probe, struct semaphore *sem)
return NULL;
}
- memset(base, 0, sizeof(struct probe));
base->dev = 1;
base->range = ~0;
base->get = base_probe;
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 3a5f4c9..361e204 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -225,13 +225,12 @@ struct platform_device *platform_device_register_simple(char *name, unsigned int
struct platform_object *pobj;
int retval;
- pobj = kmalloc(sizeof(struct platform_object) + sizeof(struct resource) * num, GFP_KERNEL);
+ pobj = kzalloc(sizeof(*pobj) + sizeof(struct resource) * num, GFP_KERNEL);
if (!pobj) {
retval = -ENOMEM;
goto error;
}
- memset(pobj, 0, sizeof(*pobj));
pobj->pdev.name = name;
pobj->pdev.id = id;
pobj->pdev.dev.release = platform_device_release_simple;
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index 28f2c17..c56f995 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -47,14 +47,14 @@
#include <linux/completion.h>
#define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
-#define DRIVER_NAME "HP CISS Driver (v 2.6.6)"
-#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,6,6)
+#define DRIVER_NAME "HP CISS Driver (v 2.6.8)"
+#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,6,8)
/* Embedded module documentation macros - see modules.h */
MODULE_AUTHOR("Hewlett-Packard Company");
-MODULE_DESCRIPTION("Driver for HP Controller SA5xxx SA6xxx version 2.6.6");
+MODULE_DESCRIPTION("Driver for HP Controller SA5xxx SA6xxx version 2.6.8");
MODULE_SUPPORTED_DEVICE("HP SA5i SA5i+ SA532 SA5300 SA5312 SA641 SA642 SA6400"
- " SA6i P600 P800 E400 E300");
+ " SA6i P600 P800 P400 P400i E200 E200i");
MODULE_LICENSE("GPL");
#include "cciss_cmd.h"
@@ -83,12 +83,22 @@ static const struct pci_device_id cciss_pci_device_id[] = {
0x0E11, 0x4091, 0, 0, 0},
{ PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSA,
0x103C, 0x3225, 0, 0, 0},
- { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSB,
+ { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC,
0x103c, 0x3223, 0, 0, 0},
{ PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC,
- 0x103c, 0x3231, 0, 0, 0},
+ 0x103c, 0x3234, 0, 0, 0},
{ PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC,
- 0x103c, 0x3233, 0, 0, 0},
+ 0x103c, 0x3235, 0, 0, 0},
+ { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD,
+ 0x103c, 0x3211, 0, 0, 0},
+ { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD,
+ 0x103c, 0x3212, 0, 0, 0},
+ { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD,
+ 0x103c, 0x3213, 0, 0, 0},
+ { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD,
+ 0x103c, 0x3214, 0, 0, 0},
+ { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD,
+ 0x103c, 0x3215, 0, 0, 0},
{0,}
};
MODULE_DEVICE_TABLE(pci, cciss_pci_device_id);
@@ -111,8 +121,13 @@ static struct board_type products[] = {
{ 0x40910E11, "Smart Array 6i", &SA5_access},
{ 0x3225103C, "Smart Array P600", &SA5_access},
{ 0x3223103C, "Smart Array P800", &SA5_access},
- { 0x3231103C, "Smart Array E400", &SA5_access},
- { 0x3233103C, "Smart Array E300", &SA5_access},
+ { 0x3234103C, "Smart Array P400", &SA5_access},
+ { 0x3235103C, "Smart Array P400i", &SA5_access},
+ { 0x3211103C, "Smart Array E200i", &SA5_access},
+ { 0x3212103C, "Smart Array E200", &SA5_access},
+ { 0x3213103C, "Smart Array E200i", &SA5_access},
+ { 0x3214103C, "Smart Array E200i", &SA5_access},
+ { 0x3215103C, "Smart Array E200i", &SA5_access},
};
/* How long to wait (in millesconds) for board to go into simple mode */
@@ -140,15 +155,26 @@ static int cciss_ioctl(struct inode *inode, struct file *filep,
static int revalidate_allvol(ctlr_info_t *host);
static int cciss_revalidate(struct gendisk *disk);
-static int deregister_disk(struct gendisk *disk);
-static int register_new_disk(ctlr_info_t *h);
+static int rebuild_lun_table(ctlr_info_t *h, struct gendisk *del_disk);
+static int deregister_disk(struct gendisk *disk, drive_info_struct *drv, int clear_all);
+static void cciss_read_capacity(int ctlr, int logvol, ReadCapdata_struct *buf,
+ int withirq, unsigned int *total_size, unsigned int *block_size);
+static void cciss_geometry_inquiry(int ctlr, int logvol,
+ int withirq, unsigned int total_size,
+ unsigned int block_size, InquiryData_struct *inq_buff,
+ drive_info_struct *drv);
static void cciss_getgeometry(int cntl_num);
static void start_io( ctlr_info_t *h);
static int sendcmd( __u8 cmd, int ctlr, void *buff, size_t size,
unsigned int use_unit_num, unsigned int log_unit, __u8 page_code,
unsigned char *scsi3addr, int cmd_type);
+static int sendcmd_withirq(__u8 cmd, int ctlr, void *buff, size_t size,
+ unsigned int use_unit_num, unsigned int log_unit, __u8 page_code,
+ int cmd_type);
+
+static void fail_all_cmds(unsigned long ctlr);
#ifdef CONFIG_PROC_FS
static int cciss_proc_get_info(char *buffer, char **start, off_t offset,
@@ -265,7 +291,7 @@ static int cciss_proc_get_info(char *buffer, char **start, off_t offset,
for(i=0; i<=h->highest_lun; i++) {
drv = &h->drv[i];
- if (drv->block_size == 0)
+ if (drv->heads == 0)
continue;
vol_sz = drv->nr_blocks;
@@ -363,6 +389,8 @@ static CommandList_struct * cmd_alloc(ctlr_info_t *h, int get_from_pool)
return NULL;
memset(c, 0, sizeof(CommandList_struct));
+ c->cmdindex = -1;
+
c->err_info = (ErrorInfo_struct *)pci_alloc_consistent(
h->pdev, sizeof(ErrorInfo_struct),
&err_dma_handle);
@@ -393,6 +421,8 @@ static CommandList_struct * cmd_alloc(ctlr_info_t *h, int get_from_pool)
err_dma_handle = h->errinfo_pool_dhandle
+ i*sizeof(ErrorInfo_struct);
h->nr_allocs++;
+
+ c->cmdindex = i;
}
c->busaddr = (__u32) cmd_dma_handle;
@@ -453,6 +483,11 @@ static int cciss_open(struct inode *inode, struct file *filep)
printk(KERN_DEBUG "cciss_open %s\n", inode->i_bdev->bd_disk->disk_name);
#endif /* CCISS_DEBUG */
+ if (host->busy_initializing)
+ return -EBUSY;
+
+ if (host->busy_initializing || drv->busy_configuring)
+ return -EBUSY;
/*
* Root is allowed to open raw volume zero even if it's not configured
* so array config can still work. Root is also allowed to open any
@@ -796,10 +831,10 @@ static int cciss_ioctl(struct inode *inode, struct file *filep,
return(0);
}
case CCISS_DEREGDISK:
- return deregister_disk(disk);
+ return rebuild_lun_table(host, disk);
case CCISS_REGNEWD:
- return register_new_disk(host);
+ return rebuild_lun_table(host, NULL);
case CCISS_PASSTHRU:
{
@@ -1143,48 +1178,323 @@ static int revalidate_allvol(ctlr_info_t *host)
return 0;
}
-static int deregister_disk(struct gendisk *disk)
+/* This function will check the usage_count of the drive to be updated/added.
+ * If the usage_count is zero then the drive information will be updated and
+ * the disk will be re-registered with the kernel. If not then it will be
+ * left alone for the next reboot. The exception to this is disk 0 which
+ * will always be left registered with the kernel since it is also the
+ * controller node. Any changes to disk 0 will show up on the next
+ * reboot.
+*/
+static void cciss_update_drive_info(int ctlr, int drv_index)
+ {
+ ctlr_info_t *h = hba[ctlr];
+ struct gendisk *disk;
+ ReadCapdata_struct *size_buff = NULL;
+ InquiryData_struct *inq_buff = NULL;
+ unsigned int block_size;
+ unsigned int total_size;
+ unsigned long flags = 0;
+ int ret = 0;
+
+ /* if the disk already exists then deregister it before proceeding*/
+ if (h->drv[drv_index].raid_level != -1){
+ spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
+ h->drv[drv_index].busy_configuring = 1;
+ spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+ ret = deregister_disk(h->gendisk[drv_index],
+ &h->drv[drv_index], 0);
+ h->drv[drv_index].busy_configuring = 0;
+ }
+
+ /* If the disk is in use return */
+ if (ret)
+ return;
+
+
+ /* Get information about the disk and modify the driver sturcture */
+ size_buff = kmalloc(sizeof( ReadCapdata_struct), GFP_KERNEL);
+ if (size_buff == NULL)
+ goto mem_msg;
+ inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL);
+ if (inq_buff == NULL)
+ goto mem_msg;
+
+ cciss_read_capacity(ctlr, drv_index, size_buff, 1,
+ &total_size, &block_size);
+ cciss_geometry_inquiry(ctlr, drv_index, 1, total_size, block_size,
+ inq_buff, &h->drv[drv_index]);
+
+ ++h->num_luns;
+ disk = h->gendisk[drv_index];
+ set_capacity(disk, h->drv[drv_index].nr_blocks);
+
+
+ /* if it's the controller it's already added */
+ if (drv_index){
+ disk->queue = blk_init_queue(do_cciss_request, &h->lock);
+
+ /* Set up queue information */
+ disk->queue->backing_dev_info.ra_pages = READ_AHEAD;
+ blk_queue_bounce_limit(disk->queue, hba[ctlr]->pdev->dma_mask);
+
+ /* This is a hardware imposed limit. */
+ blk_queue_max_hw_segments(disk->queue, MAXSGENTRIES);
+
+ /* This is a limit in the driver and could be eliminated. */
+ blk_queue_max_phys_segments(disk->queue, MAXSGENTRIES);
+
+ blk_queue_max_sectors(disk->queue, 512);
+
+ disk->queue->queuedata = hba[ctlr];
+
+ blk_queue_hardsect_size(disk->queue,
+ hba[ctlr]->drv[drv_index].block_size);
+
+ h->drv[drv_index].queue = disk->queue;
+ add_disk(disk);
+ }
+
+freeret:
+ kfree(size_buff);
+ kfree(inq_buff);
+ return;
+mem_msg:
+ printk(KERN_ERR "cciss: out of memory\n");
+ goto freeret;
+}
+
+/* This function will find the first index of the controllers drive array
+ * that has a -1 for the raid_level and will return that index. This is
+ * where new drives will be added. If the index to be returned is greater
+ * than the highest_lun index for the controller then highest_lun is set
+ * to this new index. If there are no available indexes then -1 is returned.
+*/
+static int cciss_find_free_drive_index(int ctlr)
{
+ int i;
+
+ for (i=0; i < CISS_MAX_LUN; i++){
+ if (hba[ctlr]->drv[i].raid_level == -1){
+ if (i > hba[ctlr]->highest_lun)
+ hba[ctlr]->highest_lun = i;
+ return i;
+ }
+ }
+ return -1;
+}
+
+/* This function will add and remove logical drives from the Logical
+ * drive array of the controller and maintain persistancy of ordering
+ * so that mount points are preserved until the next reboot. This allows
+ * for the removal of logical drives in the middle of the drive array
+ * without a re-ordering of those drives.
+ * INPUT
+ * h = The controller to perform the operations on
+ * del_disk = The disk to remove if specified. If the value given
+ * is NULL then no disk is removed.
+*/
+static int rebuild_lun_table(ctlr_info_t *h, struct gendisk *del_disk)
+{
+ int ctlr = h->ctlr;
+ int num_luns;
+ ReportLunData_struct *ld_buff = NULL;
+ drive_info_struct *drv = NULL;
+ int return_code;
+ int listlength = 0;
+ int i;
+ int drv_found;
+ int drv_index = 0;
+ __u32 lunid = 0;
unsigned long flags;
+
+ /* Set busy_configuring flag for this operation */
+ spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
+ if (h->num_luns >= CISS_MAX_LUN){
+ spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+ return -EINVAL;
+ }
+
+ if (h->busy_configuring){
+ spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+ return -EBUSY;
+ }
+ h->busy_configuring = 1;
+
+ /* if del_disk is NULL then we are being called to add a new disk
+ * and update the logical drive table. If it is not NULL then
+ * we will check if the disk is in use or not.
+ */
+ if (del_disk != NULL){
+ drv = get_drv(del_disk);
+ drv->busy_configuring = 1;
+ spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+ return_code = deregister_disk(del_disk, drv, 1);
+ drv->busy_configuring = 0;
+ h->busy_configuring = 0;
+ return return_code;
+ } else {
+ spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+ if (!capable(CAP_SYS_RAWIO))
+ return -EPERM;
+
+ ld_buff = kzalloc(sizeof(ReportLunData_struct), GFP_KERNEL);
+ if (ld_buff == NULL)
+ goto mem_msg;
+
+ return_code = sendcmd_withirq(CISS_REPORT_LOG, ctlr, ld_buff,
+ sizeof(ReportLunData_struct), 0, 0, 0,
+ TYPE_CMD);
+
+ if (return_code == IO_OK){
+ listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[0])) << 24;
+ listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[1])) << 16;
+ listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[2])) << 8;
+ listlength |= 0xff & (unsigned int)(ld_buff->LUNListLength[3]);
+ } else{ /* reading number of logical volumes failed */
+ printk(KERN_WARNING "cciss: report logical volume"
+ " command failed\n");
+ listlength = 0;
+ goto freeret;
+ }
+
+ num_luns = listlength / 8; /* 8 bytes per entry */
+ if (num_luns > CISS_MAX_LUN){
+ num_luns = CISS_MAX_LUN;
+ printk(KERN_WARNING "cciss: more luns configured"
+ " on controller than can be handled by"
+ " this driver.\n");
+ }
+
+ /* Compare controller drive array to drivers drive array.
+ * Check for updates in the drive information and any new drives
+ * on the controller.
+ */
+ for (i=0; i < num_luns; i++){
+ int j;
+
+ drv_found = 0;
+
+ lunid = (0xff &
+ (unsigned int)(ld_buff->LUN[i][3])) << 24;
+ lunid |= (0xff &
+ (unsigned int)(ld_buff->LUN[i][2])) << 16;
+ lunid |= (0xff &
+ (unsigned int)(ld_buff->LUN[i][1])) << 8;
+ lunid |= 0xff &
+ (unsigned int)(ld_buff->LUN[i][0]);
+
+ /* Find if the LUN is already in the drive array
+ * of the controller. If so then update its info
+ * if not is use. If it does not exist then find
+ * the first free index and add it.
+ */
+ for (j=0; j <= h->highest_lun; j++){
+ if (h->drv[j].LunID == lunid){
+ drv_index = j;
+ drv_found = 1;
+ }
+ }
+
+ /* check if the drive was found already in the array */
+ if (!drv_found){
+ drv_index = cciss_find_free_drive_index(ctlr);
+ if (drv_index == -1)
+ goto freeret;
+
+ }
+ h->drv[drv_index].LunID = lunid;
+ cciss_update_drive_info(ctlr, drv_index);
+ } /* end for */
+ } /* end else */
+
+freeret:
+ kfree(ld_buff);
+ h->busy_configuring = 0;
+ /* We return -1 here to tell the ACU that we have registered/updated
+ * all of the drives that we can and to keep it from calling us
+ * additional times.
+ */
+ return -1;
+mem_msg:
+ printk(KERN_ERR "cciss: out of memory\n");
+ goto freeret;
+}
+
+/* This function will deregister the disk and it's queue from the
+ * kernel. It must be called with the controller lock held and the
+ * drv structures busy_configuring flag set. It's parameters are:
+ *
+ * disk = This is the disk to be deregistered
+ * drv = This is the drive_info_struct associated with the disk to be
+ * deregistered. It contains information about the disk used
+ * by the driver.
+ * clear_all = This flag determines whether or not the disk information
+ * is going to be completely cleared out and the highest_lun
+ * reset. Sometimes we want to clear out information about
+ * the disk in preperation for re-adding it. In this case
+ * the highest_lun should be left unchanged and the LunID
+ * should not be cleared.
+*/
+static int deregister_disk(struct gendisk *disk, drive_info_struct *drv,
+ int clear_all)
+{
ctlr_info_t *h = get_host(disk);
- drive_info_struct *drv = get_drv(disk);
- int ctlr = h->ctlr;
if (!capable(CAP_SYS_RAWIO))
return -EPERM;
- spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
/* make sure logical volume is NOT is use */
- if( drv->usage_count > 1) {
- spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+ if(clear_all || (h->gendisk[0] == disk)) {
+ if (drv->usage_count > 1)
return -EBUSY;
}
- drv->usage_count++;
- spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+ else
+ if( drv->usage_count > 0 )
+ return -EBUSY;
- /* invalidate the devices and deregister the disk */
- if (disk->flags & GENHD_FL_UP)
+ /* invalidate the devices and deregister the disk. If it is disk
+ * zero do not deregister it but just zero out it's values. This
+ * allows us to delete disk zero but keep the controller registered.
+ */
+ if (h->gendisk[0] != disk){
+ if (disk->flags & GENHD_FL_UP){
+ blk_cleanup_queue(disk->queue);
del_gendisk(disk);
+ drv->queue = NULL;
+ }
+ }
+
+ --h->num_luns;
+ /* zero out the disk size info */
+ drv->nr_blocks = 0;
+ drv->block_size = 0;
+ drv->heads = 0;
+ drv->sectors = 0;
+ drv->cylinders = 0;
+ drv->raid_level = -1; /* This can be used as a flag variable to
+ * indicate that this element of the drive
+ * array is free.
+ */
+
+ if (clear_all){
/* check to see if it was the last disk */
if (drv == h->drv + h->highest_lun) {
/* if so, find the new hightest lun */
int i, newhighest =-1;
for(i=0; i<h->highest_lun; i++) {
/* if the disk has size > 0, it is available */
- if (h->drv[i].nr_blocks)
+ if (h->drv[i].heads)
newhighest = i;
}
h->highest_lun = newhighest;
-
}
- --h->num_luns;
- /* zero out the disk size info */
- drv->nr_blocks = 0;
- drv->block_size = 0;
- drv->cylinders = 0;
+
drv->LunID = 0;
+ }
return(0);
}
+
static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff,
size_t size,
unsigned int use_unit_num, /* 0: address the controller,
@@ -1420,8 +1730,10 @@ case CMD_HARDWARE_ERR:
}
}
/* unlock the buffers from DMA */
+ buff_dma_handle.val32.lower = c->SG[0].Addr.lower;
+ buff_dma_handle.val32.upper = c->SG[0].Addr.upper;
pci_unmap_single( h->pdev, (dma_addr_t) buff_dma_handle.val,
- size, PCI_DMA_BIDIRECTIONAL);
+ c->SG[0].Len, PCI_DMA_BIDIRECTIONAL);
cmd_free(h, c, 0);
return(return_status);
@@ -1495,164 +1807,6 @@ cciss_read_capacity(int ctlr, int logvol, ReadCapdata_struct *buf,
return;
}
-static int register_new_disk(ctlr_info_t *h)
-{
- struct gendisk *disk;
- int ctlr = h->ctlr;
- int i;
- int num_luns;
- int logvol;
- int new_lun_found = 0;
- int new_lun_index = 0;
- int free_index_found = 0;
- int free_index = 0;
- ReportLunData_struct *ld_buff = NULL;
- ReadCapdata_struct *size_buff = NULL;
- InquiryData_struct *inq_buff = NULL;
- int return_code;
- int listlength = 0;
- __u32 lunid = 0;
- unsigned int block_size;
- unsigned int total_size;
-
- if (!capable(CAP_SYS_RAWIO))
- return -EPERM;
- /* if we have no space in our disk array left to add anything */
- if( h->num_luns >= CISS_MAX_LUN)
- return -EINVAL;
-
- ld_buff = kmalloc(sizeof(ReportLunData_struct), GFP_KERNEL);
- if (ld_buff == NULL)
- goto mem_msg;
- memset(ld_buff, 0, sizeof(ReportLunData_struct));
- size_buff = kmalloc(sizeof( ReadCapdata_struct), GFP_KERNEL);
- if (size_buff == NULL)
- goto mem_msg;
- inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL);
- if (inq_buff == NULL)
- goto mem_msg;
-
- return_code = sendcmd_withirq(CISS_REPORT_LOG, ctlr, ld_buff,
- sizeof(ReportLunData_struct), 0, 0, 0, TYPE_CMD);
-
- if( return_code == IO_OK)
- {
-
- // printk("LUN Data\n--------------------------\n");
-
- listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[0])) << 24;
- listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[1])) << 16;
- listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[2])) << 8;
- listlength |= 0xff & (unsigned int)(ld_buff->LUNListLength[3]);
- } else /* reading number of logical volumes failed */
- {
- printk(KERN_WARNING "cciss: report logical volume"
- " command failed\n");
- listlength = 0;
- goto free_err;
- }
- num_luns = listlength / 8; // 8 bytes pre entry
- if (num_luns > CISS_MAX_LUN)
- {
- num_luns = CISS_MAX_LUN;
- }
-#ifdef CCISS_DEBUG
- printk(KERN_DEBUG "Length = %x %x %x %x = %d\n", ld_buff->LUNListLength[0],
- ld_buff->LUNListLength[1], ld_buff->LUNListLength[2],
- ld_buff->LUNListLength[3], num_luns);
-#endif
- for(i=0; i< num_luns; i++)
- {
- int j;
- int lunID_found = 0;
-
- lunid = (0xff & (unsigned int)(ld_buff->LUN[i][3])) << 24;
- lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][2])) << 16;
- lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][1])) << 8;
- lunid |= 0xff & (unsigned int)(ld_buff->LUN[i][0]);
-
- /* check to see if this is a new lun */
- for(j=0; j <= h->highest_lun; j++)
- {
-#ifdef CCISS_DEBUG
- printk("Checking %d %x against %x\n", j,h->drv[j].LunID,
- lunid);
-#endif /* CCISS_DEBUG */
- if (h->drv[j].LunID == lunid)
- {
- lunID_found = 1;
- break;
- }
-
- }
- if( lunID_found == 1)
- continue;
- else
- { /* It is the new lun we have been looking for */
-#ifdef CCISS_DEBUG
- printk("new lun found at %d\n", i);
-#endif /* CCISS_DEBUG */
- new_lun_index = i;
- new_lun_found = 1;
- break;
- }
- }
- if (!new_lun_found)
- {
- printk(KERN_WARNING "cciss: New Logical Volume not found\n");
- goto free_err;
- }
- /* Now find the free index */
- for(i=0; i <CISS_MAX_LUN; i++)
- {
-#ifdef CCISS_DEBUG
- printk("Checking Index %d\n", i);
-#endif /* CCISS_DEBUG */
- if(h->drv[i].LunID == 0)
- {
-#ifdef CCISS_DEBUG
- printk("free index found at %d\n", i);
-#endif /* CCISS_DEBUG */
- free_index_found = 1;
- free_index = i;
- break;
- }
- }
- if (!free_index_found)
- {
- printk(KERN_WARNING "cciss: unable to find free slot for disk\n");
- goto free_err;
- }
-
- logvol = free_index;
- h->drv[logvol].LunID = lunid;
- /* there could be gaps in lun numbers, track hightest */
- if(h->highest_lun < lunid)
- h->highest_lun = logvol;
- cciss_read_capacity(ctlr, logvol, size_buff, 1,
- &total_size, &block_size);
- cciss_geometry_inquiry(ctlr, logvol, 1, total_size, block_size,
- inq_buff, &h->drv[logvol]);
- h->drv[logvol].usage_count = 0;
- ++h->num_luns;
- /* setup partitions per disk */
- disk = h->gendisk[logvol];
- set_capacity(disk, h->drv[logvol].nr_blocks);
- /* if it's the controller it's already added */
- if(logvol)
- add_disk(disk);
-freeret:
- kfree(ld_buff);
- kfree(size_buff);
- kfree(inq_buff);
- return (logvol);
-mem_msg:
- printk(KERN_ERR "cciss: out of memory\n");
-free_err:
- logvol = -1;
- goto freeret;
-}
-
static int cciss_revalidate(struct gendisk *disk)
{
ctlr_info_t *h = get_host(disk);
@@ -1859,8 +2013,10 @@ resend_cmd1:
cleanup1:
/* unlock the data buffer from DMA */
+ buff_dma_handle.val32.lower = c->SG[0].Addr.lower;
+ buff_dma_handle.val32.upper = c->SG[0].Addr.upper;
pci_unmap_single(info_p->pdev, (dma_addr_t) buff_dma_handle.val,
- size, PCI_DMA_BIDIRECTIONAL);
+ c->SG[0].Len, PCI_DMA_BIDIRECTIONAL);
cmd_free(info_p, c, 1);
return (status);
}
@@ -2111,7 +2267,11 @@ queue:
/* fill in the request */
drv = creq->rq_disk->private_data;
c->Header.ReplyQueue = 0; // unused in simple mode
- c->Header.Tag.lower = c->busaddr; // use the physical address the cmd block for tag
+ /* got command from pool, so use the command block index instead */
+ /* for direct lookups. */
+ /* The first 2 bits are reserved for controller error reporting. */
+ c->Header.Tag.lower = (c->cmdindex << 3);
+ c->Header.Tag.lower |= 0x04; /* flag for direct lookup. */
c->Header.LUN.LogDev.VolId= drv->LunID;
c->Header.LUN.LogDev.Mode = 1;
c->Request.CDBLen = 10; // 12 byte commands not in FW yet;
@@ -2186,7 +2346,7 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs)
ctlr_info_t *h = dev_id;
CommandList_struct *c;
unsigned long flags;
- __u32 a, a1;
+ __u32 a, a1, a2;
int j;
int start_queue = h->next_to_run;
@@ -2204,10 +2364,21 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs)
while((a = h->access.command_completed(h)) != FIFO_EMPTY)
{
a1 = a;
+ if ((a & 0x04)) {
+ a2 = (a >> 3);
+ if (a2 >= NR_CMDS) {
+ printk(KERN_WARNING "cciss: controller cciss%d failed, stopping.\n", h->ctlr);
+ fail_all_cmds(h->ctlr);
+ return IRQ_HANDLED;
+ }
+
+ c = h->cmd_pool + a2;
+ a = c->busaddr;
+
+ } else {
a &= ~3;
- if ((c = h->cmpQ) == NULL)
- {
- printk(KERN_WARNING "cciss: Completion of %08lx ignored\n", (unsigned long)a1);
+ if ((c = h->cmpQ) == NULL) {
+ printk(KERN_WARNING "cciss: Completion of %08x ignored\n", a1);
continue;
}
while(c->busaddr != a) {
@@ -2215,6 +2386,7 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs)
if (c == h->cmpQ)
break;
}
+ }
/*
* If we've found the command, take it off the
* completion Q and free it
@@ -2634,12 +2806,16 @@ static void cciss_getgeometry(int cntl_num)
#endif /* CCISS_DEBUG */
hba[cntl_num]->highest_lun = hba[cntl_num]->num_luns-1;
- for(i=0; i< hba[cntl_num]->num_luns; i++)
+// for(i=0; i< hba[cntl_num]->num_luns; i++)
+ for(i=0; i < CISS_MAX_LUN; i++)
{
-
- lunid = (0xff & (unsigned int)(ld_buff->LUN[i][3])) << 24;
- lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][2])) << 16;
- lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][1])) << 8;
+ if (i < hba[cntl_num]->num_luns){
+ lunid = (0xff & (unsigned int)(ld_buff->LUN[i][3]))
+ << 24;
+ lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][2]))
+ << 16;
+ lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][1]))
+ << 8;
lunid |= 0xff & (unsigned int)(ld_buff->LUN[i][0]);
hba[cntl_num]->drv[i].LunID = lunid;
@@ -2647,13 +2823,18 @@ static void cciss_getgeometry(int cntl_num)
#ifdef CCISS_DEBUG
printk(KERN_DEBUG "LUN[%d]: %x %x %x %x = %x\n", i,
- ld_buff->LUN[i][0], ld_buff->LUN[i][1],ld_buff->LUN[i][2],
- ld_buff->LUN[i][3], hba[cntl_num]->drv[i].LunID);
+ ld_buff->LUN[i][0], ld_buff->LUN[i][1],
+ ld_buff->LUN[i][2], ld_buff->LUN[i][3],
+ hba[cntl_num]->drv[i].LunID);
#endif /* CCISS_DEBUG */
cciss_read_capacity(cntl_num, i, size_buff, 0,
&total_size, &block_size);
- cciss_geometry_inquiry(cntl_num, i, 0, total_size, block_size,
- inq_buff, &hba[cntl_num]->drv[i]);
+ cciss_geometry_inquiry(cntl_num, i, 0, total_size,
+ block_size, inq_buff, &hba[cntl_num]->drv[i]);
+ } else {
+ /* initialize raid_level to indicate a free space */
+ hba[cntl_num]->drv[i].raid_level = -1;
+ }
}
kfree(ld_buff);
kfree(size_buff);
@@ -2727,6 +2908,9 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
i = alloc_cciss_hba();
if(i < 0)
return (-1);
+
+ hba[i]->busy_initializing = 1;
+
if (cciss_pci_init(hba[i], pdev) != 0)
goto clean1;
@@ -2849,6 +3033,7 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
add_disk(disk);
}
+ hba[i]->busy_initializing = 0;
return(1);
clean4:
@@ -2869,6 +3054,7 @@ clean2:
clean1:
release_io_mem(hba[i]);
free_hba(i);
+ hba[i]->busy_initializing = 0;
return(-1);
}
@@ -2913,9 +3099,10 @@ static void __devexit cciss_remove_one (struct pci_dev *pdev)
/* remove it from the disk list */
for (j = 0; j < NWD; j++) {
struct gendisk *disk = hba[i]->gendisk[j];
- if (disk->flags & GENHD_FL_UP)
- blk_cleanup_queue(disk->queue);
+ if (disk->flags & GENHD_FL_UP) {
del_gendisk(disk);
+ blk_cleanup_queue(disk->queue);
+ }
}
pci_free_consistent(hba[i]->pdev, NR_CMDS * sizeof(CommandList_struct),
@@ -2964,5 +3151,43 @@ static void __exit cciss_cleanup(void)
remove_proc_entry("cciss", proc_root_driver);
}
+static void fail_all_cmds(unsigned long ctlr)
+{
+ /* If we get here, the board is apparently dead. */
+ ctlr_info_t *h = hba[ctlr];
+ CommandList_struct *c;
+ unsigned long flags;
+
+ printk(KERN_WARNING "cciss%d: controller not responding.\n", h->ctlr);
+ h->alive = 0; /* the controller apparently died... */
+
+ spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
+
+ pci_disable_device(h->pdev); /* Make sure it is really dead. */
+
+ /* move everything off the request queue onto the completed queue */
+ while( (c = h->reqQ) != NULL ) {
+ removeQ(&(h->reqQ), c);
+ h->Qdepth--;
+ addQ (&(h->cmpQ), c);
+ }
+
+ /* Now, fail everything on the completed queue with a HW error */
+ while( (c = h->cmpQ) != NULL ) {
+ removeQ(&h->cmpQ, c);
+ c->err_info->CommandStatus = CMD_HARDWARE_ERR;
+ if (c->cmd_type == CMD_RWREQ) {
+ complete_command(h, c, 0);
+ } else if (c->cmd_type == CMD_IOCTL_PEND)
+ complete(c->waiting);
+#ifdef CONFIG_CISS_SCSI_TAPE
+ else if (c->cmd_type == CMD_SCSI)
+ complete_scsi_command(c, 0, 0);
+#endif
+ }
+ spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+ return;
+}
+
module_init(cciss_init);
module_exit(cciss_cleanup);
diff --git a/drivers/block/cciss.h b/drivers/block/cciss.h
index 566587d..ef277ba 100644
--- a/drivers/block/cciss.h
+++ b/drivers/block/cciss.h
@@ -35,7 +35,13 @@ typedef struct _drive_info_struct
int heads;
int sectors;
int cylinders;
- int raid_level;
+ int raid_level; /* set to -1 to indicate that
+ * the drive is not in use/configured
+ */
+ int busy_configuring; /*This is set when the drive is being removed
+ *to prevent it from being opened or it's queue
+ *from being started.
+ */
} drive_info_struct;
struct ctlr_info
@@ -83,6 +89,7 @@ struct ctlr_info
int nr_allocs;
int nr_frees;
int busy_configuring;
+ int busy_initializing;
/* This element holds the zero based queue number of the last
* queue to be started. It is used for fairness.
@@ -94,6 +101,7 @@ struct ctlr_info
#ifdef CONFIG_CISS_SCSI_TAPE
void *scsi_ctlr; /* ptr to structure containing scsi related stuff */
#endif
+ unsigned char alive;
};
/* Defining the diffent access_menthods */
diff --git a/drivers/block/cciss_cmd.h b/drivers/block/cciss_cmd.h
index a88a888..53fea54 100644
--- a/drivers/block/cciss_cmd.h
+++ b/drivers/block/cciss_cmd.h
@@ -226,6 +226,10 @@ typedef struct _ErrorInfo_struct {
#define CMD_MSG_DONE 0x04
#define CMD_MSG_TIMEOUT 0x05
+/* This structure needs to be divisible by 8 for new
+ * indexing method.
+ */
+#define PADSIZE (sizeof(long) - 4)
typedef struct _CommandList_struct {
CommandListHeader_struct Header;
RequestBlock_struct Request;
@@ -236,14 +240,14 @@ typedef struct _CommandList_struct {
ErrorInfo_struct * err_info; /* pointer to the allocated mem */
int ctlr;
int cmd_type;
+ long cmdindex;
struct _CommandList_struct *prev;
struct _CommandList_struct *next;
struct request * rq;
struct completion *waiting;
int retry_count;
-#ifdef CONFIG_CISS_SCSI_TAPE
void * scsi_cmd;
-#endif
+ char pad[PADSIZE];
} CommandList_struct;
//Configuration Table Structure
diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c
index f16e3ca..e183a3e 100644
--- a/drivers/block/cciss_scsi.c
+++ b/drivers/block/cciss_scsi.c
@@ -93,6 +93,7 @@ struct cciss_scsi_cmd_stack_elem_t {
CommandList_struct cmd;
ErrorInfo_struct Err;
__u32 busaddr;
+ __u32 pad;
};
#pragma pack()
@@ -877,7 +878,7 @@ cciss_scsi_interpret_error(CommandList_struct *cp)
static int
cciss_scsi_do_inquiry(ctlr_info_t *c, unsigned char *scsi3addr,
- InquiryData_struct *buf)
+ unsigned char *buf, unsigned char bufsize)
{
int rc;
CommandList_struct *cp;
@@ -900,11 +901,10 @@ cciss_scsi_do_inquiry(ctlr_info_t *c, unsigned char *scsi3addr,
cdb[1] = 0;
cdb[2] = 0;
cdb[3] = 0;
- cdb[4] = sizeof(*buf) & 0xff;
+ cdb[4] = bufsize;
cdb[5] = 0;
rc = cciss_scsi_do_simple_cmd(c, cp, scsi3addr, cdb,
- 6, (unsigned char *) buf,
- sizeof(*buf), XFER_READ);
+ 6, buf, bufsize, XFER_READ);
if (rc != 0) return rc; /* something went wrong */
@@ -1000,9 +1000,10 @@ cciss_update_non_disk_devices(int cntl_num, int hostno)
that though.
*/
-
+#define OBDR_TAPE_INQ_SIZE 49
+#define OBDR_TAPE_SIG "$DR-10"
ReportLunData_struct *ld_buff;
- InquiryData_struct *inq_buff;
+ unsigned char *inq_buff;
unsigned char scsi3addr[8];
ctlr_info_t *c;
__u32 num_luns=0;
@@ -1020,7 +1021,7 @@ cciss_update_non_disk_devices(int cntl_num, int hostno)
return;
}
memset(ld_buff, 0, reportlunsize);
- inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL);
+ inq_buff = kmalloc(OBDR_TAPE_INQ_SIZE, GFP_KERNEL);
if (inq_buff == NULL) {
printk(KERN_ERR "cciss: out of memory\n");
kfree(ld_buff);
@@ -1051,19 +1052,36 @@ cciss_update_non_disk_devices(int cntl_num, int hostno)
/* for each physical lun, do an inquiry */
if (ld_buff->LUN[i][3] & 0xC0) continue;
- memset(inq_buff, 0, sizeof(InquiryData_struct));
+ memset(inq_buff, 0, OBDR_TAPE_INQ_SIZE);
memcpy(&scsi3addr[0], &ld_buff->LUN[i][0], 8);
- if (cciss_scsi_do_inquiry(hba[cntl_num],
- scsi3addr, inq_buff) != 0)
- {
+ if (cciss_scsi_do_inquiry(hba[cntl_num], scsi3addr, inq_buff,
+ (unsigned char) OBDR_TAPE_INQ_SIZE) != 0) {
/* Inquiry failed (msg printed already) */
devtype = 0; /* so we will skip this device. */
} else /* what kind of device is this? */
- devtype = (inq_buff->data_byte[0] & 0x1f);
+ devtype = (inq_buff[0] & 0x1f);
switch (devtype)
{
+ case 0x05: /* CD-ROM */ {
+
+ /* We don't *really* support actual CD-ROM devices,
+ * just this "One Button Disaster Recovery" tape drive
+ * which temporarily pretends to be a CD-ROM drive.
+ * So we check that the device is really an OBDR tape
+ * device by checking for "$DR-10" in bytes 43-48 of
+ * the inquiry data.
+ */
+ char obdr_sig[7];
+
+ strncpy(obdr_sig, &inq_buff[43], 6);
+ obdr_sig[6] = '\0';
+ if (strncmp(obdr_sig, OBDR_TAPE_SIG, 6) != 0)
+ /* Not OBDR device, ignore it. */
+ break;
+ }
+ /* fall through . . . */
case 0x01: /* sequential access, (tape) */
case 0x08: /* medium changer */
if (ncurrent >= CCISS_MAX_SCSI_DEVS_PER_HBA) {
@@ -1126,6 +1144,7 @@ cciss_scsi_proc_info(struct Scsi_Host *sh,
int buflen, datalen;
ctlr_info_t *ci;
+ int i;
int cntl_num;
@@ -1136,8 +1155,28 @@ cciss_scsi_proc_info(struct Scsi_Host *sh,
cntl_num = ci->ctlr; /* Get our index into the hba[] array */
if (func == 0) { /* User is reading from /proc/scsi/ciss*?/?* */
- buflen = sprintf(buffer, "hostnum=%d\n", sh->host_no);
-
+ buflen = sprintf(buffer, "cciss%d: SCSI host: %d\n",
+ cntl_num, sh->host_no);
+
+ /* this information is needed by apps to know which cciss
+ device corresponds to which scsi host number without
+ having to open a scsi target device node. The device
+ information is not a duplicate of /proc/scsi/scsi because
+ the two may be out of sync due to scsi hotplug, rather
+ this info is for an app to be able to use to know how to
+ get them back in sync. */
+
+ for (i=0;i<ccissscsi[cntl_num].ndevices;i++) {
+ struct cciss_scsi_dev_t *sd = &ccissscsi[cntl_num].dev[i];
+ buflen += sprintf(&buffer[buflen], "c%db%dt%dl%d %02d "
+ "0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
+ sh->host_no, sd->bus, sd->target, sd->lun,
+ sd->devtype,
+ sd->scsi3addr[0], sd->scsi3addr[1],
+ sd->scsi3addr[2], sd->scsi3addr[3],
+ sd->scsi3addr[4], sd->scsi3addr[5],
+ sd->scsi3addr[6], sd->scsi3addr[7]);
+ }
datalen = buflen - offset;
if (datalen < 0) { /* they're reading past EOF. */
datalen = 0;
@@ -1399,7 +1438,7 @@ cciss_proc_tape_report(int ctlr, unsigned char *buffer, off_t *pos, off_t *len)
CPQ_TAPE_LOCK(ctlr, flags);
size = sprintf(buffer + *len,
- " Sequential access devices: %d\n\n",
+ "Sequential access devices: %d\n\n",
ccissscsi[ctlr].ndevices);
CPQ_TAPE_UNLOCK(ctlr, flags);
*pos += size; *len += size;
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index 7b83834..7e22a58 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -5,29 +5,41 @@
* May be copied or modified under the terms of the GNU General Public
* License. See linux/COPYING for more information.
*
- * Packet writing layer for ATAPI and SCSI CD-R, CD-RW, DVD-R, and
- * DVD-RW devices (aka an exercise in block layer masturbation)
+ * Packet writing layer for ATAPI and SCSI CD-RW, DVD+RW, DVD-RW and
+ * DVD-RAM devices.
*
+ * Theory of operation:
*
- * TODO: (circa order of when I will fix it)
- * - Only able to write on CD-RW media right now.
- * - check host application code on media and set it in write page
- * - interface for UDF <-> packet to negotiate a new location when a write
- * fails.
- * - handle OPC, especially for -RW media
+ * At the lowest level, there is the standard driver for the CD/DVD device,
+ * typically ide-cd.c or sr.c. This driver can handle read and write requests,
+ * but it doesn't know anything about the special restrictions that apply to
+ * packet writing. One restriction is that write requests must be aligned to
+ * packet boundaries on the physical media, and the size of a write request
+ * must be equal to the packet size. Another restriction is that a
+ * GPCMD_FLUSH_CACHE command has to be issued to the drive before a read
+ * command, if the previous command was a write.
*
- * Theory of operation:
+ * The purpose of the packet writing driver is to hide these restrictions from
+ * higher layers, such as file systems, and present a block device that can be
+ * randomly read and written using 2kB-sized blocks.
+ *
+ * The lowest layer in the packet writing driver is the packet I/O scheduler.
+ * Its data is defined by the struct packet_iosched and includes two bio
+ * queues with pending read and write requests. These queues are processed
+ * by the pkt_iosched_process_queue() function. The write requests in this
+ * queue are already properly aligned and sized. This layer is responsible for
+ * issuing the flush cache commands and scheduling the I/O in a good order.
*
- * We use a custom make_request_fn function that forwards reads directly to
- * the underlying CD device. Write requests are either attached directly to
- * a live packet_data object, or simply stored sequentially in a list for
- * later processing by the kcdrwd kernel thread. This driver doesn't use
- * any elevator functionally as defined by the elevator_s struct, but the
- * underlying CD device uses a standard elevator.
+ * The next layer transforms unaligned write requests to aligned writes. This
+ * transformation requires reading missing pieces of data from the underlying
+ * block device, assembling the pieces to full packets and queuing them to the
+ * packet I/O scheduler.
*
- * This strategy makes it possible to do very late merging of IO requests.
- * A new bio sent to pkt_make_request can be merged with a live packet_data
- * object even if the object is in the data gathering state.
+ * At the top layer there is a custom make_request_fn function that forwards
+ * read requests directly to the iosched queue and puts write requests in the
+ * unaligned write queue. A kernel thread performs the necessary read
+ * gathering to convert the unaligned writes to aligned writes and then feeds
+ * them to the packet I/O scheduler.
*
*************************************************************************/
@@ -100,10 +112,9 @@ static struct bio *pkt_bio_alloc(int nr_iovecs)
goto no_bio;
bio_init(bio);
- bvl = kmalloc(nr_iovecs * sizeof(struct bio_vec), GFP_KERNEL);
+ bvl = kcalloc(nr_iovecs, sizeof(struct bio_vec), GFP_KERNEL);
if (!bvl)
goto no_bvl;
- memset(bvl, 0, nr_iovecs * sizeof(struct bio_vec));
bio->bi_max_vecs = nr_iovecs;
bio->bi_io_vec = bvl;
@@ -125,10 +136,9 @@ static struct packet_data *pkt_alloc_packet_data(void)
int i;
struct packet_data *pkt;
- pkt = kmalloc(sizeof(struct packet_data), GFP_KERNEL);
+ pkt = kzalloc(sizeof(struct packet_data), GFP_KERNEL);
if (!pkt)
goto no_pkt;
- memset(pkt, 0, sizeof(struct packet_data));
pkt->w_bio = pkt_bio_alloc(PACKET_MAX_SIZE);
if (!pkt->w_bio)
@@ -659,7 +669,6 @@ static void pkt_make_local_copy(struct packet_data *pkt, struct page **pages, in
}
offs += CD_FRAMESIZE;
if (offs >= PAGE_SIZE) {
- BUG_ON(offs > PAGE_SIZE);
offs = 0;
p++;
}
@@ -724,12 +733,6 @@ static void pkt_gather_data(struct pktcdvd_device *pd, struct packet_data *pkt)
atomic_set(&pkt->io_wait, 0);
atomic_set(&pkt->io_errors, 0);
- if (pkt->cache_valid) {
- VPRINTK("pkt_gather_data: zone %llx cached\n",
- (unsigned long long)pkt->sector);
- goto out_account;
- }
-
/*
* Figure out which frames we need to read before we can write.
*/
@@ -738,6 +741,7 @@ static void pkt_gather_data(struct pktcdvd_device *pd, struct packet_data *pkt)
for (bio = pkt->orig_bios; bio; bio = bio->bi_next) {
int first_frame = (bio->bi_sector - pkt->sector) / (CD_FRAMESIZE >> 9);
int num_frames = bio->bi_size / CD_FRAMESIZE;
+ pd->stats.secs_w += num_frames * (CD_FRAMESIZE >> 9);
BUG_ON(first_frame < 0);
BUG_ON(first_frame + num_frames > pkt->frames);
for (f = first_frame; f < first_frame + num_frames; f++)
@@ -745,6 +749,12 @@ static void pkt_gather_data(struct pktcdvd_device *pd, struct packet_data *pkt)
}
spin_unlock(&pkt->lock);
+ if (pkt->cache_valid) {
+ VPRINTK("pkt_gather_data: zone %llx cached\n",
+ (unsigned long long)pkt->sector);
+ goto out_account;
+ }
+
/*
* Schedule reads for missing parts of the packet.
*/
@@ -778,7 +788,6 @@ out_account:
frames_read, (unsigned long long)pkt->sector);
pd->stats.pkt_started++;
pd->stats.secs_rg += frames_read * (CD_FRAMESIZE >> 9);
- pd->stats.secs_w += pd->settings.size;
}
/*
@@ -794,10 +803,11 @@ static struct packet_data *pkt_get_packet_data(struct pktcdvd_device *pd, int zo
list_del_init(&pkt->list);
if (pkt->sector != zone)
pkt->cache_valid = 0;
- break;
+ return pkt;
}
}
- return pkt;
+ BUG();
+ return NULL;
}
static void pkt_put_packet_data(struct pktcdvd_device *pd, struct packet_data *pkt)
@@ -941,12 +951,10 @@ try_next_bio:
}
pkt = pkt_get_packet_data(pd, zone);
- BUG_ON(!pkt);
pd->current_sector = zone + pd->settings.size;
pkt->sector = zone;
pkt->frames = pd->settings.size >> 2;
- BUG_ON(pkt->frames > PACKET_MAX_SIZE);
pkt->write_size = 0;
/*
@@ -1636,6 +1644,10 @@ static int pkt_probe_settings(struct pktcdvd_device *pd)
printk("pktcdvd: detected zero packet size!\n");
pd->settings.size = 128;
}
+ if (pd->settings.size > PACKET_MAX_SECTORS) {
+ printk("pktcdvd: packet size is too big\n");
+ return -ENXIO;
+ }
pd->settings.fp = ti.fp;
pd->offset = (be32_to_cpu(ti.track_start) << 2) & (pd->settings.size - 1);
@@ -2198,7 +2210,6 @@ static int pkt_make_request(request_queue_t *q, struct bio *bio)
* No matching packet found. Store the bio in the work queue.
*/
node = mempool_alloc(pd->rb_pool, GFP_NOIO);
- BUG_ON(!node);
node->bio = bio;
spin_lock(&pd->lock);
BUG_ON(pd->bio_queue_size < 0);
@@ -2406,7 +2417,6 @@ static int pkt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, u
struct pktcdvd_device *pd = inode->i_bdev->bd_disk->private_data;
VPRINTK("pkt_ioctl: cmd %x, dev %d:%d\n", cmd, imajor(inode), iminor(inode));
- BUG_ON(!pd);
switch (cmd) {
/*
@@ -2477,10 +2487,9 @@ static int pkt_setup_dev(struct pkt_ctrl_command *ctrl_cmd)
return -EBUSY;
}
- pd = kmalloc(sizeof(struct pktcdvd_device), GFP_KERNEL);
+ pd = kzalloc(sizeof(struct pktcdvd_device), GFP_KERNEL);
if (!pd)
return ret;
- memset(pd, 0, sizeof(struct pktcdvd_device));
pd->rb_pool = mempool_create(PKT_RB_POOL_SIZE, pkt_rb_alloc, pkt_rb_free, NULL);
if (!pd->rb_pool)
diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c
index 2a36561..a124f8c 100644
--- a/drivers/char/amiserial.c
+++ b/drivers/char/amiserial.c
@@ -2053,10 +2053,6 @@ static int __init rs_init(void)
state->icount.rx = state->icount.tx = 0;
state->icount.frame = state->icount.parity = 0;
state->icount.overrun = state->icount.brk = 0;
- /*
- if(state->port && check_region(state->port,REGION_LENGTH(state)))
- continue;
- */
printk(KERN_INFO "ttyS%d is the amiga builtin serial port\n",
state->line);
diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig
index fa789ea..344001b 100644
--- a/drivers/char/watchdog/Kconfig
+++ b/drivers/char/watchdog/Kconfig
@@ -84,6 +84,17 @@ config 977_WATCHDOG
Not sure? It's safe to say N.
+config IXP2000_WATCHDOG
+ tristate "IXP2000 Watchdog"
+ depends on WATCHDOG && ARCH_IXP2000
+ help
+ Say Y here if to include support for the watchdog timer
+ in the Intel IXP2000(2400, 2800, 2850) network processors.
+ This driver can be built as a module by choosing M. The module
+ will be called ixp2000_wdt.
+
+ Say N if you are unsure.
+
config IXP4XX_WATCHDOG
tristate "IXP4xx Watchdog"
depends on WATCHDOG && ARCH_IXP4XX
@@ -100,17 +111,6 @@ config IXP4XX_WATCHDOG
Say N if you are unsure.
-config IXP2000_WATCHDOG
- tristate "IXP2000 Watchdog"
- depends on WATCHDOG && ARCH_IXP2000
- help
- Say Y here if to include support for the watchdog timer
- in the Intel IXP2000(2400, 2800, 2850) network processors.
- This driver can be built as a module by choosing M. The module
- will be called ixp2000_wdt.
-
- Say N if you are unsure.
-
config S3C2410_WATCHDOG
tristate "S3C2410 Watchdog"
depends on WATCHDOG && ARCH_S3C2410
@@ -233,6 +233,16 @@ config IB700_WDT
Most people will say N.
+config IBMASR
+ tristate "IBM Automatic Server Restart"
+ depends on WATCHDOG && X86
+ help
+ This is the driver for the IBM Automatic Server Restart watchdog
+ timer builtin into some eServer xSeries machines.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ibmasr.
+
config WAFER_WDT
tristate "ICP Wafer 5823 Single Board Computer Watchdog"
depends on WATCHDOG && X86
@@ -243,6 +253,16 @@ config WAFER_WDT
To compile this driver as a module, choose M here: the
module will be called wafer5823wdt.
+config I6300ESB_WDT
+ tristate "Intel 6300ESB Timer/Watchdog"
+ depends on WATCHDOG && X86 && PCI
+ ---help---
+ Hardware driver for the watchdog timer built into the Intel
+ 6300ESB controller hub.
+
+ To compile this driver as a module, choose M here: the
+ module will be called i6300esb.
+
config I8XX_TCO
tristate "Intel i8xx TCO Timer/Watchdog"
depends on WATCHDOG && (X86 || IA64) && PCI
@@ -298,6 +318,19 @@ config 60XX_WDT
You can compile this driver directly into the kernel, or use
it as a module. The module will be called sbc60xxwdt.
+config SBC8360_WDT
+ tristate "SBC8360 Watchdog Timer"
+ depends on WATCHDOG && X86
+ ---help---
+
+ This is the driver for the hardware watchdog on the SBC8360 Single
+ Board Computer produced by Axiomtek Co., Ltd. (www.axiomtek.com).
+
+ To compile this driver as a module, choose M here: the
+ module will be called sbc8360.ko.
+
+ Most people will say N.
+
config CPU5_WDT
tristate "SMA CPU5 Watchdog"
depends on WATCHDOG && X86
@@ -336,6 +369,19 @@ config W83877F_WDT
Most people will say N.
+config W83977F_WDT
+ tristate "W83977F (PCM-5335) Watchdog Timer"
+ depends on WATCHDOG && X86
+ ---help---
+ This is the driver for the hardware watchdog on the W83977F I/O chip
+ as used in AAEON's PCM-5335 SBC (and likely others). This
+ watchdog simply watches your kernel to make sure it doesn't freeze,
+ and if it does, it reboots your computer after a certain amount of
+ time.
+
+ To compile this driver as a module, choose M here: the
+ module will be called w83977f_wdt.
+
config MACHZ_WDT
tristate "ZF MachZ Watchdog"
depends on WATCHDOG && X86
@@ -355,6 +401,10 @@ config 8xx_WDT
tristate "MPC8xx Watchdog Timer"
depends on WATCHDOG && 8xx
+config MV64X60_WDT
+ tristate "MV64X60 (Marvell Discovery) Watchdog Timer"
+ depends on WATCHDOG && MV64X60
+
config BOOKE_WDT
tristate "PowerPC Book-E Watchdog Timer"
depends on WATCHDOG && (BOOKE || 4xx)
@@ -362,6 +412,17 @@ config BOOKE_WDT
Please see Documentation/watchdog/watchdog-api.txt for
more information.
+# PPC64 Architecture
+
+config WATCHDOG_RTAS
+ tristate "RTAS watchdog"
+ depends on WATCHDOG && PPC_RTAS
+ help
+ This driver adds watchdog support for the RTAS watchdog.
+
+ To compile this driver as a module, choose M here. The module
+ will be called wdrtas.
+
# MIPS Architecture
config INDYDOG
@@ -430,16 +491,6 @@ config WATCHDOG_RIO
machines. The watchdog timeout period is normally one minute but
can be changed with a boot-time parameter.
-# ppc64 RTAS watchdog
-config WATCHDOG_RTAS
- tristate "RTAS watchdog"
- depends on WATCHDOG && PPC_RTAS
- help
- This driver adds watchdog support for the RTAS watchdog.
-
- To compile this driver as a module, choose M here. The module
- will be called wdrtas.
-
#
# ISA-based Watchdog Cards
#
diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile
index bc6f5fe..cfd0a39 100644
--- a/drivers/char/watchdog/Makefile
+++ b/drivers/char/watchdog/Makefile
@@ -39,22 +39,27 @@ obj-$(CONFIG_ALIM7101_WDT) += alim7101_wdt.o
obj-$(CONFIG_SC520_WDT) += sc520_wdt.o
obj-$(CONFIG_EUROTECH_WDT) += eurotechwdt.o
obj-$(CONFIG_IB700_WDT) += ib700wdt.o
+obj-$(CONFIG_IBMASR) += ibmasr.o
obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o
+obj-$(CONFIG_I6300ESB_WDT) += i6300esb.o
obj-$(CONFIG_I8XX_TCO) += i8xx_tco.o
obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o
obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o
obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o
+obj-$(CONFIG_SBC8360_WDT) += sbc8360.o
obj-$(CONFIG_CPU5_WDT) += cpu5wdt.o
obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o
obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o
+obj-$(CONFIG_W83977F_WDT) += w83977f_wdt.o
obj-$(CONFIG_MACHZ_WDT) += machzwd.o
# PowerPC Architecture
obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o
+obj-$(CONFIG_MV64X60_WDT) += mv64x60_wdt.o
+obj-$(CONFIG_BOOKE_WDT) += booke_wdt.o
# PPC64 Architecture
obj-$(CONFIG_WATCHDOG_RTAS) += wdrtas.o
-obj-$(CONFIG_BOOKE_WDT) += booke_wdt.o
# MIPS Architecture
obj-$(CONFIG_INDYDOG) += indydog.o
diff --git a/drivers/char/watchdog/i6300esb.c b/drivers/char/watchdog/i6300esb.c
new file mode 100644
index 0000000..93785f1
--- /dev/null
+++ b/drivers/char/watchdog/i6300esb.c
@@ -0,0 +1,527 @@
+/*
+ * i6300esb: Watchdog timer driver for Intel 6300ESB chipset
+ *
+ * (c) Copyright 2004 Google Inc.
+ * (c) Copyright 2005 David Härdeman <david@2gen.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * based on i810-tco.c which is in turn based on softdog.c
+ *
+ * The timer is implemented in the following I/O controller hubs:
+ * (See the intel documentation on http://developer.intel.com.)
+ * 6300ESB chip : document number 300641-003
+ *
+ * 2004YYZZ Ross Biro
+ * Initial version 0.01
+ * 2004YYZZ Ross Biro
+ * Version 0.02
+ * 20050210 David Härdeman <david@2gen.com>
+ * Ported driver to kernel 2.6
+ */
+
+/*
+ * Includes, defines, variables, module parameters, ...
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+/* Module and version information */
+#define ESB_VERSION "0.03"
+#define ESB_MODULE_NAME "i6300ESB timer"
+#define ESB_DRIVER_NAME ESB_MODULE_NAME ", v" ESB_VERSION
+#define PFX ESB_MODULE_NAME ": "
+
+/* PCI configuration registers */
+#define ESB_CONFIG_REG 0x60 /* Config register */
+#define ESB_LOCK_REG 0x68 /* WDT lock register */
+
+/* Memory mapped registers */
+#define ESB_TIMER1_REG BASEADDR + 0x00 /* Timer1 value after each reset */
+#define ESB_TIMER2_REG BASEADDR + 0x04 /* Timer2 value after each reset */
+#define ESB_GINTSR_REG BASEADDR + 0x08 /* General Interrupt Status Register */
+#define ESB_RELOAD_REG BASEADDR + 0x0c /* Reload register */
+
+/* Lock register bits */
+#define ESB_WDT_FUNC ( 0x01 << 2 ) /* Watchdog functionality */
+#define ESB_WDT_ENABLE ( 0x01 << 1 ) /* Enable WDT */
+#define ESB_WDT_LOCK ( 0x01 << 0 ) /* Lock (nowayout) */
+
+/* Config register bits */
+#define ESB_WDT_REBOOT ( 0x01 << 5 ) /* Enable reboot on timeout */
+#define ESB_WDT_FREQ ( 0x01 << 2 ) /* Decrement frequency */
+#define ESB_WDT_INTTYPE ( 0x11 << 0 ) /* Interrupt type on timer1 timeout */
+
+/* Reload register bits */
+#define ESB_WDT_RELOAD ( 0x01 << 8 ) /* prevent timeout */
+
+/* Magic constants */
+#define ESB_UNLOCK1 0x80 /* Step 1 to unlock reset registers */
+#define ESB_UNLOCK2 0x86 /* Step 2 to unlock reset registers */
+
+/* internal variables */
+static void __iomem *BASEADDR;
+static spinlock_t esb_lock; /* Guards the hardware */
+static unsigned long timer_alive;
+static struct pci_dev *esb_pci;
+static unsigned short triggered; /* The status of the watchdog upon boot */
+static char esb_expect_close;
+
+/* module parameters */
+#define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat (1<heartbeat<2*1023) */
+static int heartbeat = WATCHDOG_HEARTBEAT; /* in seconds */
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (1<heartbeat<2046, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+/*
+ * Some i6300ESB specific functions
+ */
+
+/*
+ * Prepare for reloading the timer by unlocking the proper registers.
+ * This is performed by first writing 0x80 followed by 0x86 to the
+ * reload register. After this the appropriate registers can be written
+ * to once before they need to be unlocked again.
+ */
+static inline void esb_unlock_registers(void) {
+ writeb(ESB_UNLOCK1, ESB_RELOAD_REG);
+ writeb(ESB_UNLOCK2, ESB_RELOAD_REG);
+}
+
+static void esb_timer_start(void)
+{
+ u8 val;
+
+ /* Enable or Enable + Lock? */
+ val = 0x02 | (nowayout ? 0x01 : 0x00);
+
+ pci_write_config_byte(esb_pci, ESB_LOCK_REG, val);
+}
+
+static int esb_timer_stop(void)
+{
+ u8 val;
+
+ spin_lock(&esb_lock);
+ /* First, reset timers as suggested by the docs */
+ esb_unlock_registers();
+ writew(ESB_WDT_RELOAD, ESB_RELOAD_REG);
+ /* Then disable the WDT */
+ pci_write_config_byte(esb_pci, ESB_LOCK_REG, 0x0);
+ pci_read_config_byte(esb_pci, ESB_LOCK_REG, &val);
+ spin_unlock(&esb_lock);
+
+ /* Returns 0 if the timer was disabled, non-zero otherwise */
+ return (val & 0x01);
+}
+
+static void esb_timer_keepalive(void)
+{
+ spin_lock(&esb_lock);
+ esb_unlock_registers();
+ writew(ESB_WDT_RELOAD, ESB_RELOAD_REG);
+ /* FIXME: Do we need to flush anything here? */
+ spin_unlock(&esb_lock);
+}
+
+static int esb_timer_set_heartbeat(int time)
+{
+ u32 val;
+
+ if (time < 0x1 || time > (2 * 0x03ff))
+ return -EINVAL;
+
+ spin_lock(&esb_lock);
+
+ /* We shift by 9, so if we are passed a value of 1 sec,
+ * val will be 1 << 9 = 512, then write that to two
+ * timers => 2 * 512 = 1024 (which is decremented at 1KHz)
+ */
+ val = time << 9;
+
+ /* Write timer 1 */
+ esb_unlock_registers();
+ writel(val, ESB_TIMER1_REG);
+
+ /* Write timer 2 */
+ esb_unlock_registers();
+ writel(val, ESB_TIMER2_REG);
+
+ /* Reload */
+ esb_unlock_registers();
+ writew(ESB_WDT_RELOAD, ESB_RELOAD_REG);
+
+ /* FIXME: Do we need to flush everything out? */
+
+ /* Done */
+ heartbeat = time;
+ spin_unlock(&esb_lock);
+ return 0;
+}
+
+static int esb_timer_read (void)
+{
+ u32 count;
+
+ /* This isn't documented, and doesn't take into
+ * acount which stage is running, but it looks
+ * like a 20 bit count down, so we might as well report it.
+ */
+ pci_read_config_dword(esb_pci, 0x64, &count);
+ return (int)count;
+}
+
+/*
+ * /dev/watchdog handling
+ */
+
+static int esb_open (struct inode *inode, struct file *file)
+{
+ /* /dev/watchdog can only be opened once */
+ if (test_and_set_bit(0, &timer_alive))
+ return -EBUSY;
+
+ /* Reload and activate timer */
+ esb_timer_keepalive ();
+ esb_timer_start ();
+
+ return nonseekable_open(inode, file);
+}
+
+static int esb_release (struct inode *inode, struct file *file)
+{
+ /* Shut off the timer. */
+ if (esb_expect_close == 42) {
+ esb_timer_stop ();
+ } else {
+ printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
+ esb_timer_keepalive ();
+ }
+ clear_bit(0, &timer_alive);
+ esb_expect_close = 0;
+ return 0;
+}
+
+static ssize_t esb_write (struct file *file, const char __user *data,
+ size_t len, loff_t * ppos)
+{
+ /* See if we got the magic character 'V' and reload the timer */
+ if (len) {
+ if (!nowayout) {
+ size_t i;
+
+ /* note: just in case someone wrote the magic character
+ * five months ago... */
+ esb_expect_close = 0;
+
+ /* scan to see whether or not we got the magic character */
+ for (i = 0; i != len; i++) {
+ char c;
+ if(get_user(c, data+i))
+ return -EFAULT;
+ if (c == 'V')
+ esb_expect_close = 42;
+ }
+ }
+
+ /* someone wrote to us, we should reload the timer */
+ esb_timer_keepalive ();
+ }
+ return len;
+}
+
+static int esb_ioctl (struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int new_options, retval = -EINVAL;
+ int new_heartbeat;
+ void __user *argp = (void __user *)arg;
+ int __user *p = argp;
+ static struct watchdog_info ident = {
+ .options = WDIOF_SETTIMEOUT |
+ WDIOF_KEEPALIVEPING |
+ WDIOF_MAGICCLOSE,
+ .firmware_version = 0,
+ .identity = ESB_MODULE_NAME,
+ };
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ return copy_to_user(argp, &ident,
+ sizeof (ident)) ? -EFAULT : 0;
+
+ case WDIOC_GETSTATUS:
+ return put_user (esb_timer_read(), p);
+
+ case WDIOC_GETBOOTSTATUS:
+ return put_user (triggered, p);
+
+ case WDIOC_KEEPALIVE:
+ esb_timer_keepalive ();
+ return 0;
+
+ case WDIOC_SETOPTIONS:
+ {
+ if (get_user (new_options, p))
+ return -EFAULT;
+
+ if (new_options & WDIOS_DISABLECARD) {
+ esb_timer_stop ();
+ retval = 0;
+ }
+
+ if (new_options & WDIOS_ENABLECARD) {
+ esb_timer_keepalive ();
+ esb_timer_start ();
+ retval = 0;
+ }
+
+ return retval;
+ }
+
+ case WDIOC_SETTIMEOUT:
+ {
+ if (get_user(new_heartbeat, p))
+ return -EFAULT;
+
+ if (esb_timer_set_heartbeat(new_heartbeat))
+ return -EINVAL;
+
+ esb_timer_keepalive ();
+ /* Fall */
+ }
+
+ case WDIOC_GETTIMEOUT:
+ return put_user(heartbeat, p);
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+
+/*
+ * Notify system
+ */
+
+static int esb_notify_sys (struct notifier_block *this, unsigned long code, void *unused)
+{
+ if (code==SYS_DOWN || code==SYS_HALT) {
+ /* Turn the WDT off */
+ esb_timer_stop ();
+ }
+
+ return NOTIFY_DONE;
+}
+
+/*
+ * Kernel Interfaces
+ */
+
+static struct file_operations esb_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = esb_write,
+ .ioctl = esb_ioctl,
+ .open = esb_open,
+ .release = esb_release,
+};
+
+static struct miscdevice esb_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &esb_fops,
+};
+
+static struct notifier_block esb_notifier = {
+ .notifier_call = esb_notify_sys,
+};
+
+/*
+ * Data for PCI driver interface
+ *
+ * This data only exists for exporting the supported
+ * PCI ids via MODULE_DEVICE_TABLE. We do not actually
+ * register a pci_driver, because someone else might one day
+ * want to register another driver on the same PCI id.
+ */
+static struct pci_device_id esb_pci_tbl[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_9), },
+ { 0, }, /* End of list */
+};
+MODULE_DEVICE_TABLE (pci, esb_pci_tbl);
+
+/*
+ * Init & exit routines
+ */
+
+static unsigned char __init esb_getdevice (void)
+{
+ u8 val1;
+ unsigned short val2;
+
+ struct pci_dev *dev = NULL;
+ /*
+ * Find the PCI device
+ */
+
+ for_each_pci_dev(dev) {
+ if (pci_match_id(esb_pci_tbl, dev)) {
+ esb_pci = dev;
+ break;
+ }
+ }
+
+ if (esb_pci) {
+ if (pci_enable_device(esb_pci)) {
+ printk (KERN_ERR PFX "failed to enable device\n");
+ goto err_devput;
+ }
+
+ if (pci_request_region(esb_pci, 0, ESB_MODULE_NAME)) {
+ printk (KERN_ERR PFX "failed to request region\n");
+ goto err_disable;
+ }
+
+ BASEADDR = ioremap(pci_resource_start(esb_pci, 0),
+ pci_resource_len(esb_pci, 0));
+ if (BASEADDR == NULL) {
+ /* Something's wrong here, BASEADDR has to be set */
+ printk (KERN_ERR PFX "failed to get BASEADDR\n");
+ goto err_release;
+ }
+
+ /*
+ * The watchdog has two timers, it can be setup so that the
+ * expiry of timer1 results in an interrupt and the expiry of
+ * timer2 results in a reboot. We set it to not generate
+ * any interrupts as there is not much we can do with it
+ * right now.
+ *
+ * We also enable reboots and set the timer frequency to
+ * the PCI clock divided by 2^15 (approx 1KHz).
+ */
+ pci_write_config_word(esb_pci, ESB_CONFIG_REG, 0x0003);
+
+ /* Check that the WDT isn't already locked */
+ pci_read_config_byte(esb_pci, ESB_LOCK_REG, &val1);
+ if (val1 & ESB_WDT_LOCK)
+ printk (KERN_WARNING PFX "nowayout already set\n");
+
+ /* Set the timer to watchdog mode and disable it for now */
+ pci_write_config_byte(esb_pci, ESB_LOCK_REG, 0x00);
+
+ /* Check if the watchdog was previously triggered */
+ esb_unlock_registers();
+ val2 = readw(ESB_RELOAD_REG);
+ triggered = (val2 & (0x01 << 9) >> 9);
+
+ /* Reset trigger flag and timers */
+ esb_unlock_registers();
+ writew((0x11 << 8), ESB_RELOAD_REG);
+
+ /* Done */
+ return 1;
+
+err_release:
+ pci_release_region(esb_pci, 0);
+err_disable:
+ pci_disable_device(esb_pci);
+err_devput:
+ pci_dev_put(esb_pci);
+ }
+ return 0;
+}
+
+static int __init watchdog_init (void)
+{
+ int ret;
+
+ spin_lock_init(&esb_lock);
+
+ /* Check whether or not the hardware watchdog is there */
+ if (!esb_getdevice () || esb_pci == NULL)
+ return -ENODEV;
+
+ /* Check that the heartbeat value is within it's range ; if not reset to the default */
+ if (esb_timer_set_heartbeat (heartbeat)) {
+ esb_timer_set_heartbeat (WATCHDOG_HEARTBEAT);
+ printk(KERN_INFO PFX "heartbeat value must be 1<heartbeat<2046, using %d\n",
+ heartbeat);
+ }
+
+ ret = register_reboot_notifier(&esb_notifier);
+ if (ret != 0) {
+ printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
+ ret);
+ goto err_unmap;
+ }
+
+ ret = misc_register(&esb_miscdev);
+ if (ret != 0) {
+ printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+ WATCHDOG_MINOR, ret);
+ goto err_notifier;
+ }
+
+ esb_timer_stop ();
+
+ printk (KERN_INFO PFX "initialized (0x%p). heartbeat=%d sec (nowayout=%d)\n",
+ BASEADDR, heartbeat, nowayout);
+
+ return 0;
+
+err_notifier:
+ unregister_reboot_notifier(&esb_notifier);
+err_unmap:
+ iounmap(BASEADDR);
+/* err_release: */
+ pci_release_region(esb_pci, 0);
+/* err_disable: */
+ pci_disable_device(esb_pci);
+/* err_devput: */
+ pci_dev_put(esb_pci);
+ return ret;
+}
+
+static void __exit watchdog_cleanup (void)
+{
+ /* Stop the timer before we leave */
+ if (!nowayout)
+ esb_timer_stop ();
+
+ /* Deregister */
+ misc_deregister(&esb_miscdev);
+ unregister_reboot_notifier(&esb_notifier);
+ iounmap(BASEADDR);
+ pci_release_region(esb_pci, 0);
+ pci_disable_device(esb_pci);
+ pci_dev_put(esb_pci);
+}
+
+module_init(watchdog_init);
+module_exit(watchdog_cleanup);
+
+MODULE_AUTHOR("Ross Biro and David Härdeman");
+MODULE_DESCRIPTION("Watchdog driver for Intel 6300ESB chipsets");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/ibmasr.c b/drivers/char/watchdog/ibmasr.c
new file mode 100644
index 0000000..294c474
--- /dev/null
+++ b/drivers/char/watchdog/ibmasr.c
@@ -0,0 +1,405 @@
+/*
+ * IBM Automatic Server Restart driver.
+ *
+ * Copyright (c) 2005 Andrey Panin <pazke@donpac.ru>
+ *
+ * Based on driver written by Pete Reynolds.
+ * Copyright (c) IBM Corporation, 1998-2004.
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU Public License, incorporated herein by reference.
+ */
+
+#include <linux/config.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/timer.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/dmi.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+
+enum {
+ ASMTYPE_UNKNOWN,
+ ASMTYPE_TOPAZ,
+ ASMTYPE_JASPER,
+ ASMTYPE_PEARL,
+ ASMTYPE_JUNIPER,
+ ASMTYPE_SPRUCE,
+};
+
+#define PFX "ibmasr: "
+
+#define TOPAZ_ASR_REG_OFFSET 4
+#define TOPAZ_ASR_TOGGLE 0x40
+#define TOPAZ_ASR_DISABLE 0x80
+
+/* PEARL ASR S/W REGISTER SUPERIO PORT ADDRESSES */
+#define PEARL_BASE 0xe04
+#define PEARL_WRITE 0xe06
+#define PEARL_READ 0xe07
+
+#define PEARL_ASR_DISABLE_MASK 0x80 /* bit 7: disable = 1, enable = 0 */
+#define PEARL_ASR_TOGGLE_MASK 0x40 /* bit 6: 0, then 1, then 0 */
+
+/* JASPER OFFSET FROM SIO BASE ADDR TO ASR S/W REGISTERS. */
+#define JASPER_ASR_REG_OFFSET 0x38
+
+#define JASPER_ASR_DISABLE_MASK 0x01 /* bit 0: disable = 1, enable = 0 */
+#define JASPER_ASR_TOGGLE_MASK 0x02 /* bit 1: 0, then 1, then 0 */
+
+#define JUNIPER_BASE_ADDRESS 0x54b /* Base address of Juniper ASR */
+#define JUNIPER_ASR_DISABLE_MASK 0x01 /* bit 0: disable = 1 enable = 0 */
+#define JUNIPER_ASR_TOGGLE_MASK 0x02 /* bit 1: 0, then 1, then 0 */
+
+#define SPRUCE_BASE_ADDRESS 0x118e /* Base address of Spruce ASR */
+#define SPRUCE_ASR_DISABLE_MASK 0x01 /* bit 1: disable = 1 enable = 0 */
+#define SPRUCE_ASR_TOGGLE_MASK 0x02 /* bit 0: 0, then 1, then 0 */
+
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+
+static unsigned long asr_is_open;
+static char asr_expect_close;
+
+static unsigned int asr_type, asr_base, asr_length;
+static unsigned int asr_read_addr, asr_write_addr;
+static unsigned char asr_toggle_mask, asr_disable_mask;
+
+static void asr_toggle(void)
+{
+ unsigned char reg = inb(asr_read_addr);
+
+ outb(reg & ~asr_toggle_mask, asr_write_addr);
+ reg = inb(asr_read_addr);
+
+ outb(reg | asr_toggle_mask, asr_write_addr);
+ reg = inb(asr_read_addr);
+
+ outb(reg & ~asr_toggle_mask, asr_write_addr);
+ reg = inb(asr_read_addr);
+}
+
+static void asr_enable(void)
+{
+ unsigned char reg;
+
+ if (asr_type == ASMTYPE_TOPAZ) {
+ /* asr_write_addr == asr_read_addr */
+ reg = inb(asr_read_addr);
+ outb(reg & ~(TOPAZ_ASR_TOGGLE | TOPAZ_ASR_DISABLE),
+ asr_read_addr);
+ } else {
+ /*
+ * First make sure the hardware timer is reset by toggling
+ * ASR hardware timer line.
+ */
+ asr_toggle();
+
+ reg = inb(asr_read_addr);
+ outb(reg & ~asr_disable_mask, asr_write_addr);
+ }
+ reg = inb(asr_read_addr);
+}
+
+static void asr_disable(void)
+{
+ unsigned char reg = inb(asr_read_addr);
+
+ if (asr_type == ASMTYPE_TOPAZ)
+ /* asr_write_addr == asr_read_addr */
+ outb(reg | TOPAZ_ASR_TOGGLE | TOPAZ_ASR_DISABLE,
+ asr_read_addr);
+ else {
+ outb(reg | asr_toggle_mask, asr_write_addr);
+ reg = inb(asr_read_addr);
+
+ outb(reg | asr_disable_mask, asr_write_addr);
+ }
+ reg = inb(asr_read_addr);
+}
+
+static int __init asr_get_base_address(void)
+{
+ unsigned char low, high;
+ const char *type = "";
+
+ asr_length = 1;
+
+ switch (asr_type) {
+ case ASMTYPE_TOPAZ:
+ /* SELECT SuperIO CHIP FOR QUERYING (WRITE 0x07 TO BOTH 0x2E and 0x2F) */
+ outb(0x07, 0x2e);
+ outb(0x07, 0x2f);
+
+ /* SELECT AND READ THE HIGH-NIBBLE OF THE GPIO BASE ADDRESS */
+ outb(0x60, 0x2e);
+ high = inb(0x2f);
+
+ /* SELECT AND READ THE LOW-NIBBLE OF THE GPIO BASE ADDRESS */
+ outb(0x61, 0x2e);
+ low = inb(0x2f);
+
+ asr_base = (high << 16) | low;
+ asr_read_addr = asr_write_addr =
+ asr_base + TOPAZ_ASR_REG_OFFSET;
+ asr_length = 5;
+
+ break;
+
+ case ASMTYPE_JASPER:
+ type = "Jaspers ";
+
+ /* FIXME: need to use pci_config_lock here, but it's not exported */
+
+/* spin_lock_irqsave(&pci_config_lock, flags);*/
+
+ /* Select the SuperIO chip in the PCI I/O port register */
+ outl(0x8000f858, 0xcf8);
+
+ /*
+ * Read the base address for the SuperIO chip.
+ * Only the lower 16 bits are valid, but the address is word
+ * aligned so the last bit must be masked off.
+ */
+ asr_base = inl(0xcfc) & 0xfffe;
+
+/* spin_unlock_irqrestore(&pci_config_lock, flags);*/
+
+ asr_read_addr = asr_write_addr =
+ asr_base + JASPER_ASR_REG_OFFSET;
+ asr_toggle_mask = JASPER_ASR_TOGGLE_MASK;
+ asr_disable_mask = JASPER_ASR_DISABLE_MASK;
+ asr_length = JASPER_ASR_REG_OFFSET + 1;
+
+ break;
+
+ case ASMTYPE_PEARL:
+ type = "Pearls ";
+ asr_base = PEARL_BASE;
+ asr_read_addr = PEARL_READ;
+ asr_write_addr = PEARL_WRITE;
+ asr_toggle_mask = PEARL_ASR_TOGGLE_MASK;
+ asr_disable_mask = PEARL_ASR_DISABLE_MASK;
+ asr_length = 4;
+ break;
+
+ case ASMTYPE_JUNIPER:
+ type = "Junipers ";
+ asr_base = JUNIPER_BASE_ADDRESS;
+ asr_read_addr = asr_write_addr = asr_base;
+ asr_toggle_mask = JUNIPER_ASR_TOGGLE_MASK;
+ asr_disable_mask = JUNIPER_ASR_DISABLE_MASK;
+ break;
+
+ case ASMTYPE_SPRUCE:
+ type = "Spruce's ";
+ asr_base = SPRUCE_BASE_ADDRESS;
+ asr_read_addr = asr_write_addr = asr_base;
+ asr_toggle_mask = SPRUCE_ASR_TOGGLE_MASK;
+ asr_disable_mask = SPRUCE_ASR_DISABLE_MASK;
+ break;
+ }
+
+ if (!request_region(asr_base, asr_length, "ibmasr")) {
+ printk(KERN_ERR PFX "address %#x already in use\n",
+ asr_base);
+ return -EBUSY;
+ }
+
+ printk(KERN_INFO PFX "found %sASR @ addr %#x\n", type, asr_base);
+
+ return 0;
+}
+
+
+static ssize_t asr_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ if (count) {
+ if (!nowayout) {
+ size_t i;
+
+ /* In case it was set long ago */
+ asr_expect_close = 0;
+
+ for (i = 0; i != count; i++) {
+ char c;
+ if (get_user(c, buf + i))
+ return -EFAULT;
+ if (c == 'V')
+ asr_expect_close = 42;
+ }
+ }
+ asr_toggle();
+ }
+ return count;
+}
+
+static int asr_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ static const struct watchdog_info ident = {
+ .options = WDIOF_KEEPALIVEPING |
+ WDIOF_MAGICCLOSE,
+ .identity = "IBM ASR"
+ };
+ void __user *argp = (void __user *)arg;
+ int __user *p = argp;
+ int heartbeat;
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ return copy_to_user(argp, &ident, sizeof(ident)) ?
+ -EFAULT : 0;
+
+ case WDIOC_GETSTATUS:
+ case WDIOC_GETBOOTSTATUS:
+ return put_user(0, p);
+
+ case WDIOC_KEEPALIVE:
+ asr_toggle();
+ return 0;
+
+ /*
+ * The hardware has a fixed timeout value, so no WDIOC_SETTIMEOUT
+ * and WDIOC_GETTIMEOUT always returns 256.
+ */
+ case WDIOC_GETTIMEOUT:
+ heartbeat = 256;
+ return put_user(heartbeat, p);
+
+ case WDIOC_SETOPTIONS: {
+ int new_options, retval = -EINVAL;
+
+ if (get_user(new_options, p))
+ return -EFAULT;
+
+ if (new_options & WDIOS_DISABLECARD) {
+ asr_disable();
+ retval = 0;
+ }
+
+ if (new_options & WDIOS_ENABLECARD) {
+ asr_enable();
+ asr_toggle();
+ retval = 0;
+ }
+
+ return retval;
+ }
+ }
+
+ return -ENOIOCTLCMD;
+}
+
+static int asr_open(struct inode *inode, struct file *file)
+{
+ if(test_and_set_bit(0, &asr_is_open))
+ return -EBUSY;
+
+ asr_toggle();
+ asr_enable();
+
+ return nonseekable_open(inode, file);
+}
+
+static int asr_release(struct inode *inode, struct file *file)
+{
+ if (asr_expect_close == 42)
+ asr_disable();
+ else {
+ printk(KERN_CRIT PFX "unexpected close, not stopping watchdog!\n");
+ asr_toggle();
+ }
+ clear_bit(0, &asr_is_open);
+ asr_expect_close = 0;
+ return 0;
+}
+
+static struct file_operations asr_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = asr_write,
+ .ioctl = asr_ioctl,
+ .open = asr_open,
+ .release = asr_release,
+};
+
+static struct miscdevice asr_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &asr_fops,
+};
+
+
+struct ibmasr_id {
+ const char *desc;
+ int type;
+};
+
+static struct ibmasr_id __initdata ibmasr_id_table[] = {
+ { "IBM Automatic Server Restart - eserver xSeries 220", ASMTYPE_TOPAZ },
+ { "IBM Automatic Server Restart - Machine Type 8673", ASMTYPE_PEARL },
+ { "IBM Automatic Server Restart - Machine Type 8480", ASMTYPE_JASPER },
+ { "IBM Automatic Server Restart - Machine Type 8482", ASMTYPE_JUNIPER },
+ { "IBM Automatic Server Restart - Machine Type 8648", ASMTYPE_SPRUCE },
+ { NULL }
+};
+
+static int __init ibmasr_init(void)
+{
+ struct ibmasr_id *id;
+ int rc;
+
+ for (id = ibmasr_id_table; id->desc; id++) {
+ if (dmi_find_device(DMI_DEV_TYPE_OTHER, id->desc, NULL)) {
+ asr_type = id->type;
+ break;
+ }
+ }
+
+ if (!asr_type)
+ return -ENODEV;
+
+ rc = misc_register(&asr_miscdev);
+ if (rc < 0) {
+ printk(KERN_ERR PFX "failed to register misc device\n");
+ return rc;
+ }
+
+ rc = asr_get_base_address();
+ if (rc) {
+ misc_deregister(&asr_miscdev);
+ return rc;
+ }
+
+ return 0;
+}
+
+static void __exit ibmasr_exit(void)
+{
+ if (!nowayout)
+ asr_disable();
+
+ misc_deregister(&asr_miscdev);
+
+ release_region(asr_base, asr_length);
+}
+
+module_init(ibmasr_init);
+module_exit(ibmasr_exit);
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+MODULE_DESCRIPTION("IBM Automatic Server Restart driver");
+MODULE_AUTHOR("Andrey Panin");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/mv64x60_wdt.c b/drivers/char/watchdog/mv64x60_wdt.c
new file mode 100644
index 0000000..1436aea
--- /dev/null
+++ b/drivers/char/watchdog/mv64x60_wdt.c
@@ -0,0 +1,252 @@
+/*
+ * mv64x60_wdt.c - MV64X60 (Marvell Discovery) watchdog userspace interface
+ *
+ * Author: James Chapman <jchapman@katalix.com>
+ *
+ * Platform-specific setup code should configure the dog to generate
+ * interrupt or reset as required. This code only enables/disables
+ * and services the watchdog.
+ *
+ * Derived from mpc8xx_wdt.c, with the following copyright.
+ *
+ * 2002 (c) Florian Schirmer <jolt@tuxbox.org> This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#include <linux/config.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/watchdog.h>
+#include <asm/mv64x60.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+/* MV64x60 WDC (config) register access definitions */
+#define MV64x60_WDC_CTL1_MASK (3 << 24)
+#define MV64x60_WDC_CTL1(val) ((val & 3) << 24)
+#define MV64x60_WDC_CTL2_MASK (3 << 26)
+#define MV64x60_WDC_CTL2(val) ((val & 3) << 26)
+
+/* Flags bits */
+#define MV64x60_WDOG_FLAG_OPENED 0
+#define MV64x60_WDOG_FLAG_ENABLED 1
+
+static unsigned long wdt_flags;
+static int wdt_status;
+static void __iomem *mv64x60_regs;
+static int mv64x60_wdt_timeout;
+
+static void mv64x60_wdt_reg_write(u32 val)
+{
+ /* Allow write only to CTL1 / CTL2 fields, retaining values in
+ * other fields.
+ */
+ u32 data = readl(mv64x60_regs + MV64x60_WDT_WDC);
+ data &= ~(MV64x60_WDC_CTL1_MASK | MV64x60_WDC_CTL2_MASK);
+ data |= val;
+ writel(data, mv64x60_regs + MV64x60_WDT_WDC);
+}
+
+static void mv64x60_wdt_service(void)
+{
+ /* Write 01 followed by 10 to CTL2 */
+ mv64x60_wdt_reg_write(MV64x60_WDC_CTL2(0x01));
+ mv64x60_wdt_reg_write(MV64x60_WDC_CTL2(0x02));
+}
+
+static void mv64x60_wdt_handler_disable(void)
+{
+ if (test_and_clear_bit(MV64x60_WDOG_FLAG_ENABLED, &wdt_flags)) {
+ /* Write 01 followed by 10 to CTL1 */
+ mv64x60_wdt_reg_write(MV64x60_WDC_CTL1(0x01));
+ mv64x60_wdt_reg_write(MV64x60_WDC_CTL1(0x02));
+ printk(KERN_NOTICE "mv64x60_wdt: watchdog deactivated\n");
+ }
+}
+
+static void mv64x60_wdt_handler_enable(void)
+{
+ if (!test_and_set_bit(MV64x60_WDOG_FLAG_ENABLED, &wdt_flags)) {
+ /* Write 01 followed by 10 to CTL1 */
+ mv64x60_wdt_reg_write(MV64x60_WDC_CTL1(0x01));
+ mv64x60_wdt_reg_write(MV64x60_WDC_CTL1(0x02));
+ printk(KERN_NOTICE "mv64x60_wdt: watchdog activated\n");
+ }
+}
+
+static int mv64x60_wdt_open(struct inode *inode, struct file *file)
+{
+ if (test_and_set_bit(MV64x60_WDOG_FLAG_OPENED, &wdt_flags))
+ return -EBUSY;
+
+ mv64x60_wdt_service();
+ mv64x60_wdt_handler_enable();
+
+ return 0;
+}
+
+static int mv64x60_wdt_release(struct inode *inode, struct file *file)
+{
+ mv64x60_wdt_service();
+
+#if !defined(CONFIG_WATCHDOG_NOWAYOUT)
+ mv64x60_wdt_handler_disable();
+#endif
+
+ clear_bit(MV64x60_WDOG_FLAG_OPENED, &wdt_flags);
+
+ return 0;
+}
+
+static ssize_t mv64x60_wdt_write(struct file *file, const char *data,
+ size_t len, loff_t * ppos)
+{
+ if (*ppos != file->f_pos)
+ return -ESPIPE;
+
+ if (len)
+ mv64x60_wdt_service();
+
+ return len;
+}
+
+static int mv64x60_wdt_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int timeout;
+ static struct watchdog_info info = {
+ .options = WDIOF_KEEPALIVEPING,
+ .firmware_version = 0,
+ .identity = "MV64x60 watchdog",
+ };
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ if (copy_to_user((void *)arg, &info, sizeof(info)))
+ return -EFAULT;
+ break;
+
+ case WDIOC_GETSTATUS:
+ case WDIOC_GETBOOTSTATUS:
+ if (put_user(wdt_status, (int *)arg))
+ return -EFAULT;
+ wdt_status &= ~WDIOF_KEEPALIVEPING;
+ break;
+
+ case WDIOC_GETTEMP:
+ return -EOPNOTSUPP;
+
+ case WDIOC_SETOPTIONS:
+ return -EOPNOTSUPP;
+
+ case WDIOC_KEEPALIVE:
+ mv64x60_wdt_service();
+ wdt_status |= WDIOF_KEEPALIVEPING;
+ break;
+
+ case WDIOC_SETTIMEOUT:
+ return -EOPNOTSUPP;
+
+ case WDIOC_GETTIMEOUT:
+ timeout = mv64x60_wdt_timeout * HZ;
+ if (put_user(timeout, (int *)arg))
+ return -EFAULT;
+ break;
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+
+ return 0;
+}
+
+static struct file_operations mv64x60_wdt_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = mv64x60_wdt_write,
+ .ioctl = mv64x60_wdt_ioctl,
+ .open = mv64x60_wdt_open,
+ .release = mv64x60_wdt_release,
+};
+
+static struct miscdevice mv64x60_wdt_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &mv64x60_wdt_fops,
+};
+
+static int __devinit mv64x60_wdt_probe(struct device *dev)
+{
+ struct platform_device *pd = to_platform_device(dev);
+ struct mv64x60_wdt_pdata *pdata = pd->dev.platform_data;
+ int bus_clk = 133;
+
+ mv64x60_wdt_timeout = 10;
+ if (pdata) {
+ mv64x60_wdt_timeout = pdata->timeout;
+ bus_clk = pdata->bus_clk;
+ }
+
+ mv64x60_regs = mv64x60_get_bridge_vbase();
+
+ writel((mv64x60_wdt_timeout * (bus_clk * 1000000)) >> 8,
+ mv64x60_regs + MV64x60_WDT_WDC);
+
+ return misc_register(&mv64x60_wdt_miscdev);
+}
+
+static int __devexit mv64x60_wdt_remove(struct device *dev)
+{
+ misc_deregister(&mv64x60_wdt_miscdev);
+
+ mv64x60_wdt_service();
+ mv64x60_wdt_handler_disable();
+
+ return 0;
+}
+
+static struct device_driver mv64x60_wdt_driver = {
+ .name = MV64x60_WDT_NAME,
+ .bus = &platform_bus_type,
+ .probe = mv64x60_wdt_probe,
+ .remove = __devexit_p(mv64x60_wdt_remove),
+};
+
+static struct platform_device *mv64x60_wdt_dev;
+
+static int __init mv64x60_wdt_init(void)
+{
+ int ret;
+
+ printk(KERN_INFO "MV64x60 watchdog driver\n");
+
+ mv64x60_wdt_dev = platform_device_register_simple(MV64x60_WDT_NAME,
+ -1, NULL, 0);
+ if (IS_ERR(mv64x60_wdt_dev)) {
+ ret = PTR_ERR(mv64x60_wdt_dev);
+ goto out;
+ }
+
+ ret = driver_register(&mv64x60_wdt_driver);
+ out:
+ return ret;
+}
+
+static void __exit mv64x60_wdt_exit(void)
+{
+ driver_unregister(&mv64x60_wdt_driver);
+ platform_device_unregister(mv64x60_wdt_dev);
+}
+
+module_init(mv64x60_wdt_init);
+module_exit(mv64x60_wdt_exit);
+
+MODULE_AUTHOR("James Chapman <jchapman@katalix.com>");
+MODULE_DESCRIPTION("MV64x60 watchdog driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/pcwd_pci.c b/drivers/char/watchdog/pcwd_pci.c
index 2b13afb..5a80adb 100644
--- a/drivers/char/watchdog/pcwd_pci.c
+++ b/drivers/char/watchdog/pcwd_pci.c
@@ -29,27 +29,29 @@
* Includes, defines, variables, module parameters, ...
*/
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/types.h>
-#include <linux/delay.h>
-#include <linux/miscdevice.h>
-#include <linux/watchdog.h>
-#include <linux/notifier.h>
-#include <linux/reboot.h>
-#include <linux/init.h>
-#include <linux/fs.h>
-#include <linux/pci.h>
-#include <linux/ioport.h>
-#include <linux/spinlock.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
+#include <linux/config.h> /* For CONFIG_WATCHDOG_NOWAYOUT/... */
+#include <linux/module.h> /* For module specific items */
+#include <linux/moduleparam.h> /* For new moduleparam's */
+#include <linux/types.h> /* For standard types (like size_t) */
+#include <linux/errno.h> /* For the -ENODEV/... values */
+#include <linux/kernel.h> /* For printk/panic/... */
+#include <linux/delay.h> /* For mdelay function */
+#include <linux/miscdevice.h> /* For MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR) */
+#include <linux/watchdog.h> /* For the watchdog specific items */
+#include <linux/notifier.h> /* For notifier support */
+#include <linux/reboot.h> /* For reboot_notifier stuff */
+#include <linux/init.h> /* For __init/__exit/... */
+#include <linux/fs.h> /* For file operations */
+#include <linux/pci.h> /* For pci functions */
+#include <linux/ioport.h> /* For io-port access */
+#include <linux/spinlock.h> /* For spin_lock/spin_unlock/... */
+
+#include <asm/uaccess.h> /* For copy_to_user/put_user/... */
+#include <asm/io.h> /* For inb/outb/... */
/* Module and version information */
#define WATCHDOG_VERSION "1.01"
-#define WATCHDOG_DATE "15 Mar 2005"
+#define WATCHDOG_DATE "02 Sep 2005"
#define WATCHDOG_DRIVER_NAME "PCI-PC Watchdog"
#define WATCHDOG_NAME "pcwd_pci"
#define PFX WATCHDOG_NAME ": "
@@ -335,12 +337,14 @@ static int pcipcwd_ioctl(struct inode *inode, struct file *file,
return -EFAULT;
if (new_options & WDIOS_DISABLECARD) {
- pcipcwd_stop();
+ if (pcipcwd_stop())
+ return -EIO;
retval = 0;
}
if (new_options & WDIOS_ENABLECARD) {
- pcipcwd_start();
+ if (pcipcwd_start())
+ return -EIO;
retval = 0;
}
diff --git a/drivers/char/watchdog/s3c2410_wdt.c b/drivers/char/watchdog/s3c2410_wdt.c
index 8b292bf..3625b26 100644
--- a/drivers/char/watchdog/s3c2410_wdt.c
+++ b/drivers/char/watchdog/s3c2410_wdt.c
@@ -464,7 +464,7 @@ static void s3c2410wdt_shutdown(struct device *dev)
static unsigned long wtcon_save;
static unsigned long wtdat_save;
-static int s3c2410wdt_suspend(struct device *dev, u32 state, u32 level)
+static int s3c2410wdt_suspend(struct device *dev, pm_message_t state, u32 level)
{
if (level == SUSPEND_POWER_DOWN) {
/* Save watchdog state, and turn it off. */
diff --git a/drivers/char/watchdog/sbc8360.c b/drivers/char/watchdog/sbc8360.c
new file mode 100644
index 0000000..c6cbf80
--- /dev/null
+++ b/drivers/char/watchdog/sbc8360.c
@@ -0,0 +1,414 @@
+/*
+ * SBC8360 Watchdog driver
+ *
+ * (c) Copyright 2005 Webcon, Inc.
+ *
+ * Based on ib700wdt.c, which is based on advantechwdt.c which is based
+ * on acquirewdt.c which is based on wdt.c.
+ *
+ * (c) Copyright 2001 Charles Howes <chowes@vsol.net>
+ *
+ * Based on advantechwdt.c which is based on acquirewdt.c which
+ * is based on wdt.c.
+ *
+ * (c) Copyright 2000-2001 Marek Michalkiewicz <marekm@linux.org.pl>
+ *
+ * Based on acquirewdt.c which is based on wdt.c.
+ * Original copyright messages:
+ *
+ * (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
+ * http://www.redhat.com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
+ * warranty for any of this software. This material is provided
+ * "AS-IS" and at no charge.
+ *
+ * (c) Copyright 1995 Alan Cox <alan@redhat.com>
+ *
+ * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
+ * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
+ * Added timeout module option to override default
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/notifier.h>
+#include <linux/fs.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/moduleparam.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+static unsigned long sbc8360_is_open;
+static spinlock_t sbc8360_lock;
+static char expect_close;
+
+#define PFX "sbc8360: "
+
+/*
+ *
+ * Watchdog Timer Configuration
+ *
+ * The function of the watchdog timer is to reset the system automatically
+ * and is defined at I/O port 0120H and 0121H. To enable the watchdog timer
+ * and allow the system to reset, write appropriate values from the table
+ * below to I/O port 0120H and 0121H. To disable the timer, write a zero
+ * value to I/O port 0121H for the system to stop the watchdog function.
+ *
+ * The following describes how the timer should be programmed (according to
+ * the vendor documentation)
+ *
+ * Enabling Watchdog:
+ * MOV AX,000AH (enable, phase I)
+ * MOV DX,0120H
+ * OUT DX,AX
+ * MOV AX,000BH (enable, phase II)
+ * MOV DX,0120H
+ * OUT DX,AX
+ * MOV AX,000nH (set multiplier n, from 1-4)
+ * MOV DX,0120H
+ * OUT DX,AX
+ * MOV AX,000mH (set base timer m, from 0-F)
+ * MOV DX,0121H
+ * OUT DX,AX
+ *
+ * Reset timer:
+ * MOV AX,000mH (same as set base timer, above)
+ * MOV DX,0121H
+ * OUT DX,AX
+ *
+ * Disabling Watchdog:
+ * MOV AX,0000H (a zero value)
+ * MOV DX,0120H
+ * OUT DX,AX
+ *
+ * Watchdog timeout configuration values:
+ * N
+ * M | 1 2 3 4
+ * --|----------------------------------
+ * 0 | 0.5s 5s 50s 100s
+ * 1 | 1s 10s 100s 200s
+ * 2 | 1.5s 15s 150s 300s
+ * 3 | 2s 20s 200s 400s
+ * 4 | 2.5s 25s 250s 500s
+ * 5 | 3s 30s 300s 600s
+ * 6 | 3.5s 35s 350s 700s
+ * 7 | 4s 40s 400s 800s
+ * 8 | 4.5s 45s 450s 900s
+ * 9 | 5s 50s 500s 1000s
+ * A | 5.5s 55s 550s 1100s
+ * B | 6s 60s 600s 1200s
+ * C | 6.5s 65s 650s 1300s
+ * D | 7s 70s 700s 1400s
+ * E | 7.5s 75s 750s 1500s
+ * F | 8s 80s 800s 1600s
+ *
+ * Another way to say the same things is:
+ * For N=1, Timeout = (M+1) * 0.5s
+ * For N=2, Timeout = (M+1) * 5s
+ * For N=3, Timeout = (M+1) * 50s
+ * For N=4, Timeout = (M+1) * 100s
+ *
+ */
+
+static int wd_times[64][2] = {
+ {0, 1}, /* 0 = 0.5s */
+ {1, 1}, /* 1 = 1s */
+ {2, 1}, /* 2 = 1.5s */
+ {3, 1}, /* 3 = 2s */
+ {4, 1}, /* 4 = 2.5s */
+ {5, 1}, /* 5 = 3s */
+ {6, 1}, /* 6 = 3.5s */
+ {7, 1}, /* 7 = 4s */
+ {8, 1}, /* 8 = 4.5s */
+ {9, 1}, /* 9 = 5s */
+ {0xA, 1}, /* 10 = 5.5s */
+ {0xB, 1}, /* 11 = 6s */
+ {0xC, 1}, /* 12 = 6.5s */
+ {0xD, 1}, /* 13 = 7s */
+ {0xE, 1}, /* 14 = 7.5s */
+ {0xF, 1}, /* 15 = 8s */
+ {0, 2}, /* 16 = 5s */
+ {1, 2}, /* 17 = 10s */
+ {2, 2}, /* 18 = 15s */
+ {3, 2}, /* 19 = 20s */
+ {4, 2}, /* 20 = 25s */
+ {5, 2}, /* 21 = 30s */
+ {6, 2}, /* 22 = 35s */
+ {7, 2}, /* 23 = 40s */
+ {8, 2}, /* 24 = 45s */
+ {9, 2}, /* 25 = 50s */
+ {0xA, 2}, /* 26 = 55s */
+ {0xB, 2}, /* 27 = 60s */
+ {0xC, 2}, /* 28 = 65s */
+ {0xD, 2}, /* 29 = 70s */
+ {0xE, 2}, /* 30 = 75s */
+ {0xF, 2}, /* 31 = 80s */
+ {0, 3}, /* 32 = 50s */
+ {1, 3}, /* 33 = 100s */
+ {2, 3}, /* 34 = 150s */
+ {3, 3}, /* 35 = 200s */
+ {4, 3}, /* 36 = 250s */
+ {5, 3}, /* 37 = 300s */
+ {6, 3}, /* 38 = 350s */
+ {7, 3}, /* 39 = 400s */
+ {8, 3}, /* 40 = 450s */
+ {9, 3}, /* 41 = 500s */
+ {0xA, 3}, /* 42 = 550s */
+ {0xB, 3}, /* 43 = 600s */
+ {0xC, 3}, /* 44 = 650s */
+ {0xD, 3}, /* 45 = 700s */
+ {0xE, 3}, /* 46 = 750s */
+ {0xF, 3}, /* 47 = 800s */
+ {0, 4}, /* 48 = 100s */
+ {1, 4}, /* 49 = 200s */
+ {2, 4}, /* 50 = 300s */
+ {3, 4}, /* 51 = 400s */
+ {4, 4}, /* 52 = 500s */
+ {5, 4}, /* 53 = 600s */
+ {6, 4}, /* 54 = 700s */
+ {7, 4}, /* 55 = 800s */
+ {8, 4}, /* 56 = 900s */
+ {9, 4}, /* 57 = 1000s */
+ {0xA, 4}, /* 58 = 1100s */
+ {0xB, 4}, /* 59 = 1200s */
+ {0xC, 4}, /* 60 = 1300s */
+ {0xD, 4}, /* 61 = 1400s */
+ {0xE, 4}, /* 62 = 1500s */
+ {0xF, 4} /* 63 = 1600s */
+};
+
+#define SBC8360_ENABLE 0x120
+#define SBC8360_BASETIME 0x121
+
+static int timeout = 27;
+static int wd_margin = 0xB;
+static int wd_multiplier = 2;
+static int nowayout = WATCHDOG_NOWAYOUT;
+
+module_param(timeout, int, 27);
+MODULE_PARM_DESC(timeout, "Index into timeout table (0-63) (default=27 (60s))");
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout,
+ "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+/*
+ * Kernel methods.
+ */
+
+/* Activate and pre-configure watchdog */
+static void sbc8360_activate(void)
+{
+ /* Enable the watchdog */
+ outb(0x0A, SBC8360_ENABLE);
+ msleep_interruptible(100);
+ outb(0x0B, SBC8360_ENABLE);
+ msleep_interruptible(100);
+ /* Set timeout multiplier */
+ outb(wd_multiplier, SBC8360_ENABLE);
+ msleep_interruptible(100);
+ /* Nothing happens until first sbc8360_ping() */
+}
+
+/* Kernel pings watchdog */
+static void sbc8360_ping(void)
+{
+ /* Write the base timer register */
+ outb(wd_margin, SBC8360_BASETIME);
+}
+
+/* Userspace pings kernel driver, or requests clean close */
+static ssize_t sbc8360_write(struct file *file, const char __user * buf,
+ size_t count, loff_t * ppos)
+{
+ if (count) {
+ if (!nowayout) {
+ size_t i;
+
+ /* In case it was set long ago */
+ expect_close = 0;
+
+ for (i = 0; i != count; i++) {
+ char c;
+ if (get_user(c, buf + i))
+ return -EFAULT;
+ if (c == 'V')
+ expect_close = 42;
+ }
+ }
+ sbc8360_ping();
+ }
+ return count;
+}
+
+static int sbc8360_open(struct inode *inode, struct file *file)
+{
+ spin_lock(&sbc8360_lock);
+ if (test_and_set_bit(0, &sbc8360_is_open)) {
+ spin_unlock(&sbc8360_lock);
+ return -EBUSY;
+ }
+ if (nowayout)
+ __module_get(THIS_MODULE);
+
+ /* Activate and ping once to start the countdown */
+ spin_unlock(&sbc8360_lock);
+ sbc8360_activate();
+ sbc8360_ping();
+ return nonseekable_open(inode, file);
+}
+
+static int sbc8360_close(struct inode *inode, struct file *file)
+{
+ spin_lock(&sbc8360_lock);
+ if (expect_close == 42)
+ outb(0, SBC8360_ENABLE);
+ else
+ printk(KERN_CRIT PFX
+ "SBC8360 device closed unexpectedly. SBC8360 will not stop!\n");
+
+ clear_bit(0, &sbc8360_is_open);
+ expect_close = 0;
+ spin_unlock(&sbc8360_lock);
+ return 0;
+}
+
+/*
+ * Notifier for system down
+ */
+
+static int sbc8360_notify_sys(struct notifier_block *this, unsigned long code,
+ void *unused)
+{
+ if (code == SYS_DOWN || code == SYS_HALT) {
+ /* Disable the SBC8360 Watchdog */
+ outb(0, SBC8360_ENABLE);
+ }
+ return NOTIFY_DONE;
+}
+
+/*
+ * Kernel Interfaces
+ */
+
+static struct file_operations sbc8360_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = sbc8360_write,
+ .open = sbc8360_open,
+ .release = sbc8360_close,
+};
+
+static struct miscdevice sbc8360_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &sbc8360_fops,
+};
+
+/*
+ * The SBC8360 needs to learn about soft shutdowns in order to
+ * turn the timebomb registers off.
+ */
+
+static struct notifier_block sbc8360_notifier = {
+ .notifier_call = sbc8360_notify_sys,
+};
+
+static int __init sbc8360_init(void)
+{
+ int res;
+ unsigned long int mseconds = 60000;
+
+ spin_lock_init(&sbc8360_lock);
+ res = misc_register(&sbc8360_miscdev);
+ if (res) {
+ printk(KERN_ERR PFX "failed to register misc device\n");
+ goto out_nomisc;
+ }
+
+ if (!request_region(SBC8360_ENABLE, 1, "SBC8360")) {
+ printk(KERN_ERR PFX "ENABLE method I/O %X is not available.\n",
+ SBC8360_ENABLE);
+ res = -EIO;
+ goto out_noenablereg;
+ }
+ if (!request_region(SBC8360_BASETIME, 1, "SBC8360")) {
+ printk(KERN_ERR PFX
+ "BASETIME method I/O %X is not available.\n",
+ SBC8360_BASETIME);
+ res = -EIO;
+ goto out_nobasetimereg;
+ }
+
+ res = register_reboot_notifier(&sbc8360_notifier);
+ if (res) {
+ printk(KERN_ERR PFX "Failed to register reboot notifier.\n");
+ goto out_noreboot;
+ }
+
+ if (timeout < 0 || timeout > 63) {
+ printk(KERN_ERR PFX "Invalid timeout index (must be 0-63).\n");
+ res = -EINVAL;
+ goto out_noreboot;
+ }
+
+ wd_margin = wd_times[timeout][0];
+ wd_multiplier = wd_times[timeout][1];
+
+ if (wd_multiplier == 1)
+ mseconds = (wd_margin + 1) * 500;
+ else if (wd_multiplier == 2)
+ mseconds = (wd_margin + 1) * 5000;
+ else if (wd_multiplier == 3)
+ mseconds = (wd_margin + 1) * 50000;
+ else if (wd_multiplier == 4)
+ mseconds = (wd_margin + 1) * 100000;
+
+ /* My kingdom for the ability to print "0.5 seconds" in the kernel! */
+ printk(KERN_INFO PFX "Timeout set at %ld ms.\n", mseconds);
+
+ return 0;
+
+ out_noreboot:
+ release_region(SBC8360_ENABLE, 1);
+ release_region(SBC8360_BASETIME, 1);
+ out_noenablereg:
+ out_nobasetimereg:
+ misc_deregister(&sbc8360_miscdev);
+ out_nomisc:
+ return res;
+}
+
+static void __exit sbc8360_exit(void)
+{
+ misc_deregister(&sbc8360_miscdev);
+ unregister_reboot_notifier(&sbc8360_notifier);
+ release_region(SBC8360_ENABLE, 1);
+ release_region(SBC8360_BASETIME, 1);
+}
+
+module_init(sbc8360_init);
+module_exit(sbc8360_exit);
+
+MODULE_AUTHOR("Ian E. Morgan <imorgan@webcon.ca>");
+MODULE_DESCRIPTION("SBC8360 watchdog driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+
+/* end of sbc8360.c */
diff --git a/drivers/char/watchdog/w83977f_wdt.c b/drivers/char/watchdog/w83977f_wdt.c
new file mode 100644
index 0000000..a7ff64c
--- /dev/null
+++ b/drivers/char/watchdog/w83977f_wdt.c
@@ -0,0 +1,543 @@
+/*
+ * W83977F Watchdog Timer Driver for Winbond W83977F I/O Chip
+ *
+ * (c) Copyright 2005 Jose Goncalves <jose.goncalves@inov.pt>
+ *
+ * Based on w83877f_wdt.c by Scott Jennings,
+ * and wdt977.c by Woody Suwalski
+ *
+ * -----------------------
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/watchdog.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#define WATCHDOG_VERSION "1.00"
+#define WATCHDOG_NAME "W83977F WDT"
+#define PFX WATCHDOG_NAME ": "
+#define DRIVER_VERSION WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n"
+
+#define IO_INDEX_PORT 0x3F0
+#define IO_DATA_PORT (IO_INDEX_PORT+1)
+
+#define UNLOCK_DATA 0x87
+#define LOCK_DATA 0xAA
+#define DEVICE_REGISTER 0x07
+
+#define DEFAULT_TIMEOUT 45 /* default timeout in seconds */
+
+static int timeout = DEFAULT_TIMEOUT;
+static int timeoutW; /* timeout in watchdog counter units */
+static unsigned long timer_alive;
+static int testmode;
+static char expect_close;
+static spinlock_t spinlock;
+
+module_param(timeout, int, 0);
+MODULE_PARM_DESC(timeout,"Watchdog timeout in seconds (15..7635), default=" __MODULE_STRING(DEFAULT_TIMEOUT) ")");
+module_param(testmode, int, 0);
+MODULE_PARM_DESC(testmode,"Watchdog testmode (1 = no reboot), default=0");
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+/*
+ * Start the watchdog
+ */
+
+static int wdt_start(void)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&spinlock, flags);
+
+ /* Unlock the SuperIO chip */
+ outb_p(UNLOCK_DATA,IO_INDEX_PORT);
+ outb_p(UNLOCK_DATA,IO_INDEX_PORT);
+
+ /*
+ * Select device Aux2 (device=8) to set watchdog regs F2, F3 and F4.
+ * F2 has the timeout in watchdog counter units.
+ * F3 is set to enable watchdog LED blink at timeout.
+ * F4 is used to just clear the TIMEOUT'ed state (bit 0).
+ */
+ outb_p(DEVICE_REGISTER,IO_INDEX_PORT);
+ outb_p(0x08,IO_DATA_PORT);
+ outb_p(0xF2,IO_INDEX_PORT);
+ outb_p(timeoutW,IO_DATA_PORT);
+ outb_p(0xF3,IO_INDEX_PORT);
+ outb_p(0x08,IO_DATA_PORT);
+ outb_p(0xF4,IO_INDEX_PORT);
+ outb_p(0x00,IO_DATA_PORT);
+
+ /* Set device Aux2 active */
+ outb_p(0x30,IO_INDEX_PORT);
+ outb_p(0x01,IO_DATA_PORT);
+
+ /*
+ * Select device Aux1 (dev=7) to set GP16 as the watchdog output
+ * (in reg E6) and GP13 as the watchdog LED output (in reg E3).
+ * Map GP16 at pin 119.
+ * In test mode watch the bit 0 on F4 to indicate "triggered" or
+ * check watchdog LED on SBC.
+ */
+ outb_p(DEVICE_REGISTER,IO_INDEX_PORT);
+ outb_p(0x07,IO_DATA_PORT);
+ if (!testmode)
+ {
+ unsigned pin_map;
+
+ outb_p(0xE6,IO_INDEX_PORT);
+ outb_p(0x0A,IO_DATA_PORT);
+ outb_p(0x2C,IO_INDEX_PORT);
+ pin_map = inb_p(IO_DATA_PORT);
+ pin_map |= 0x10;
+ pin_map &= ~(0x20);
+ outb_p(0x2C,IO_INDEX_PORT);
+ outb_p(pin_map,IO_DATA_PORT);
+ }
+ outb_p(0xE3,IO_INDEX_PORT);
+ outb_p(0x08,IO_DATA_PORT);
+
+ /* Set device Aux1 active */
+ outb_p(0x30,IO_INDEX_PORT);
+ outb_p(0x01,IO_DATA_PORT);
+
+ /* Lock the SuperIO chip */
+ outb_p(LOCK_DATA,IO_INDEX_PORT);
+
+ spin_unlock_irqrestore(&spinlock, flags);
+
+ printk(KERN_INFO PFX "activated.\n");
+
+ return 0;
+}
+
+/*
+ * Stop the watchdog
+ */
+
+static int wdt_stop(void)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&spinlock, flags);
+
+ /* Unlock the SuperIO chip */
+ outb_p(UNLOCK_DATA,IO_INDEX_PORT);
+ outb_p(UNLOCK_DATA,IO_INDEX_PORT);
+
+ /*
+ * Select device Aux2 (device=8) to set watchdog regs F2, F3 and F4.
+ * F2 is reset to its default value (watchdog timer disabled).
+ * F3 is reset to its default state.
+ * F4 clears the TIMEOUT'ed state (bit 0) - back to default.
+ */
+ outb_p(DEVICE_REGISTER,IO_INDEX_PORT);
+ outb_p(0x08,IO_DATA_PORT);
+ outb_p(0xF2,IO_INDEX_PORT);
+ outb_p(0xFF,IO_DATA_PORT);
+ outb_p(0xF3,IO_INDEX_PORT);
+ outb_p(0x00,IO_DATA_PORT);
+ outb_p(0xF4,IO_INDEX_PORT);
+ outb_p(0x00,IO_DATA_PORT);
+ outb_p(0xF2,IO_INDEX_PORT);
+ outb_p(0x00,IO_DATA_PORT);
+
+ /*
+ * Select device Aux1 (dev=7) to set GP16 (in reg E6) and
+ * Gp13 (in reg E3) as inputs.
+ */
+ outb_p(DEVICE_REGISTER,IO_INDEX_PORT);
+ outb_p(0x07,IO_DATA_PORT);
+ if (!testmode)
+ {
+ outb_p(0xE6,IO_INDEX_PORT);
+ outb_p(0x01,IO_DATA_PORT);
+ }
+ outb_p(0xE3,IO_INDEX_PORT);
+ outb_p(0x01,IO_DATA_PORT);
+
+ /* Lock the SuperIO chip */
+ outb_p(LOCK_DATA,IO_INDEX_PORT);
+
+ spin_unlock_irqrestore(&spinlock, flags);
+
+ printk(KERN_INFO PFX "shutdown.\n");
+
+ return 0;
+}
+
+/*
+ * Send a keepalive ping to the watchdog
+ * This is done by simply re-writing the timeout to reg. 0xF2
+ */
+
+static int wdt_keepalive(void)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&spinlock, flags);
+
+ /* Unlock the SuperIO chip */
+ outb_p(UNLOCK_DATA,IO_INDEX_PORT);
+ outb_p(UNLOCK_DATA,IO_INDEX_PORT);
+
+ /* Select device Aux2 (device=8) to kick watchdog reg F2 */
+ outb_p(DEVICE_REGISTER,IO_INDEX_PORT);
+ outb_p(0x08,IO_DATA_PORT);
+ outb_p(0xF2,IO_INDEX_PORT);
+ outb_p(timeoutW,IO_DATA_PORT);
+
+ /* Lock the SuperIO chip */
+ outb_p(LOCK_DATA,IO_INDEX_PORT);
+
+ spin_unlock_irqrestore(&spinlock, flags);
+
+ return 0;
+}
+
+/*
+ * Set the watchdog timeout value
+ */
+
+static int wdt_set_timeout(int t)
+{
+ int tmrval;
+
+ /*
+ * Convert seconds to watchdog counter time units, rounding up.
+ * On PCM-5335 watchdog units are 30 seconds/step with 15 sec startup
+ * value. This information is supplied in the PCM-5335 manual and was
+ * checked by me on a real board. This is a bit strange because W83977f
+ * datasheet says counter unit is in minutes!
+ */
+ if (t < 15)
+ return -EINVAL;
+
+ tmrval = ((t + 15) + 29) / 30;
+
+ if (tmrval > 255)
+ return -EINVAL;
+
+ /*
+ * timeout is the timeout in seconds,
+ * timeoutW is the timeout in watchdog counter units.
+ */
+ timeoutW = tmrval;
+ timeout = (timeoutW * 30) - 15;
+ return 0;
+}
+
+/*
+ * Get the watchdog status
+ */
+
+static int wdt_get_status(int *status)
+{
+ int new_status;
+ unsigned long flags;
+
+ spin_lock_irqsave(&spinlock, flags);
+
+ /* Unlock the SuperIO chip */
+ outb_p(UNLOCK_DATA,IO_INDEX_PORT);
+ outb_p(UNLOCK_DATA,IO_INDEX_PORT);
+
+ /* Select device Aux2 (device=8) to read watchdog reg F4 */
+ outb_p(DEVICE_REGISTER,IO_INDEX_PORT);
+ outb_p(0x08,IO_DATA_PORT);
+ outb_p(0xF4,IO_INDEX_PORT);
+ new_status = inb_p(IO_DATA_PORT);
+
+ /* Lock the SuperIO chip */
+ outb_p(LOCK_DATA,IO_INDEX_PORT);
+
+ spin_unlock_irqrestore(&spinlock, flags);
+
+ *status = 0;
+ if (new_status & 1)
+ *status |= WDIOF_CARDRESET;
+
+ return 0;
+}
+
+
+/*
+ * /dev/watchdog handling
+ */
+
+static int wdt_open(struct inode *inode, struct file *file)
+{
+ /* If the watchdog is alive we don't need to start it again */
+ if( test_and_set_bit(0, &timer_alive) )
+ return -EBUSY;
+
+ if (nowayout)
+ __module_get(THIS_MODULE);
+
+ wdt_start();
+ return nonseekable_open(inode, file);
+}
+
+static int wdt_release(struct inode *inode, struct file *file)
+{
+ /*
+ * Shut off the timer.
+ * Lock it in if it's a module and we set nowayout
+ */
+ if (expect_close == 42)
+ {
+ wdt_stop();
+ clear_bit(0, &timer_alive);
+ } else {
+ wdt_keepalive();
+ printk(KERN_CRIT PFX "unexpected close, not stopping watchdog!\n");
+ }
+ expect_close = 0;
+ return 0;
+}
+
+/*
+ * wdt_write:
+ * @file: file handle to the watchdog
+ * @buf: buffer to write (unused as data does not matter here
+ * @count: count of bytes
+ * @ppos: pointer to the position to write. No seeks allowed
+ *
+ * A write to a watchdog device is defined as a keepalive signal. Any
+ * write of data will do, as we we don't define content meaning.
+ */
+
+static ssize_t wdt_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ /* See if we got the magic character 'V' and reload the timer */
+ if(count)
+ {
+ if (!nowayout)
+ {
+ size_t ofs;
+
+ /* note: just in case someone wrote the magic character long ago */
+ expect_close = 0;
+
+ /* scan to see whether or not we got the magic character */
+ for(ofs = 0; ofs != count; ofs++)
+ {
+ char c;
+ if (get_user(c, buf + ofs))
+ return -EFAULT;
+ if (c == 'V') {
+ expect_close = 42;
+ }
+ }
+ }
+
+ /* someone wrote to us, we should restart timer */
+ wdt_keepalive();
+ }
+ return count;
+}
+
+/*
+ * wdt_ioctl:
+ * @inode: inode of the device
+ * @file: file handle to the device
+ * @cmd: watchdog command
+ * @arg: argument pointer
+ *
+ * The watchdog API defines a common set of functions for all watchdogs
+ * according to their available features.
+ */
+
+static struct watchdog_info ident = {
+ .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
+ .firmware_version = 1,
+ .identity = WATCHDOG_NAME,
+};
+
+static int wdt_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int status;
+ int new_options, retval = -EINVAL;
+ int new_timeout;
+ union {
+ struct watchdog_info __user *ident;
+ int __user *i;
+ } uarg;
+
+ uarg.i = (int __user *)arg;
+
+ switch(cmd)
+ {
+ default:
+ return -ENOIOCTLCMD;
+
+ case WDIOC_GETSUPPORT:
+ return copy_to_user(uarg.ident, &ident, sizeof(ident)) ? -EFAULT : 0;
+
+ case WDIOC_GETSTATUS:
+ wdt_get_status(&status);
+ return put_user(status, uarg.i);
+
+ case WDIOC_GETBOOTSTATUS:
+ return put_user(0, uarg.i);
+
+ case WDIOC_KEEPALIVE:
+ wdt_keepalive();
+ return 0;
+
+ case WDIOC_SETOPTIONS:
+ if (get_user (new_options, uarg.i))
+ return -EFAULT;
+
+ if (new_options & WDIOS_DISABLECARD) {
+ wdt_stop();
+ retval = 0;
+ }
+
+ if (new_options & WDIOS_ENABLECARD) {
+ wdt_start();
+ retval = 0;
+ }
+
+ return retval;
+
+ case WDIOC_SETTIMEOUT:
+ if (get_user(new_timeout, uarg.i))
+ return -EFAULT;
+
+ if (wdt_set_timeout(new_timeout))
+ return -EINVAL;
+
+ wdt_keepalive();
+ /* Fall */
+
+ case WDIOC_GETTIMEOUT:
+ return put_user(timeout, uarg.i);
+
+ }
+}
+
+static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
+ void *unused)
+{
+ if (code==SYS_DOWN || code==SYS_HALT)
+ wdt_stop();
+ return NOTIFY_DONE;
+}
+
+static struct file_operations wdt_fops=
+{
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = wdt_write,
+ .ioctl = wdt_ioctl,
+ .open = wdt_open,
+ .release = wdt_release,
+};
+
+static struct miscdevice wdt_miscdev=
+{
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &wdt_fops,
+};
+
+static struct notifier_block wdt_notifier = {
+ .notifier_call = wdt_notify_sys,
+};
+
+static int __init w83977f_wdt_init(void)
+{
+ int rc;
+
+ printk(KERN_INFO PFX DRIVER_VERSION);
+
+ spin_lock_init(&spinlock);
+
+ /*
+ * Check that the timeout value is within it's range ;
+ * if not reset to the default
+ */
+ if (wdt_set_timeout(timeout)) {
+ wdt_set_timeout(DEFAULT_TIMEOUT);
+ printk(KERN_INFO PFX "timeout value must be 15<=timeout<=7635, using %d\n",
+ DEFAULT_TIMEOUT);
+ }
+
+ if (!request_region(IO_INDEX_PORT, 2, WATCHDOG_NAME))
+ {
+ printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
+ IO_INDEX_PORT);
+ rc = -EIO;
+ goto err_out;
+ }
+
+ rc = misc_register(&wdt_miscdev);
+ if (rc)
+ {
+ printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+ wdt_miscdev.minor, rc);
+ goto err_out_region;
+ }
+
+ rc = register_reboot_notifier(&wdt_notifier);
+ if (rc)
+ {
+ printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
+ rc);
+ goto err_out_miscdev;
+ }
+
+ printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d testmode=%d)\n",
+ timeout, nowayout, testmode);
+
+ return 0;
+
+err_out_miscdev:
+ misc_deregister(&wdt_miscdev);
+err_out_region:
+ release_region(IO_INDEX_PORT,2);
+err_out:
+ return rc;
+}
+
+static void __exit w83977f_wdt_exit(void)
+{
+ wdt_stop();
+ misc_deregister(&wdt_miscdev);
+ unregister_reboot_notifier(&wdt_notifier);
+ release_region(IO_INDEX_PORT,2);
+}
+
+module_init(w83977f_wdt_init);
+module_exit(w83977f_wdt_exit);
+
+MODULE_AUTHOR("Jose Goncalves <jose.goncalves@inov.pt>");
+MODULE_DESCRIPTION("Driver for watchdog timer in W83977F I/O chip");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/i2c/busses/i2c-keywest.c b/drivers/i2c/busses/i2c-keywest.c
index 37b49c2..eff5896 100644
--- a/drivers/i2c/busses/i2c-keywest.c
+++ b/drivers/i2c/busses/i2c-keywest.c
@@ -611,7 +611,6 @@ create_iface(struct device_node *np, struct device *dev)
for (i=0; i<nchan; i++) {
struct keywest_chan* chan = &iface->channels[i];
- u8 addr;
sprintf(chan->adapter.name, "%s %d", np->parent->name, i);
chan->iface = iface;
diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
index b443b04..0b0aa4f 100644
--- a/drivers/ide/ide-iops.c
+++ b/drivers/ide/ide-iops.c
@@ -601,44 +601,15 @@ EXPORT_SYMBOL(ide_wait_stat);
*/
u8 eighty_ninty_three (ide_drive_t *drive)
{
-#if 0
- if (!HWIF(drive)->udma_four)
+ if(HWIF(drive)->udma_four == 0)
+ return 0;
+ if (!(drive->id->hw_config & 0x6000))
return 0;
-
- if (drive->id->major_rev_num) {
- int hssbd = 0;
- int i;
- /*
- * Determine highest Supported SPEC
- */
- for (i=1; i<=15; i++)
- if (drive->id->major_rev_num & (1<<i))
- hssbd++;
-
- switch (hssbd) {
- case 7:
- case 6:
- case 5:
- /* ATA-4 and older do not support above Ultra 33 */
- default:
- return 0;
- }
- }
-
- return ((u8) (
-#ifndef CONFIG_IDEDMA_IVB
- (drive->id->hw_config & 0x4000) &&
-#endif /* CONFIG_IDEDMA_IVB */
- (drive->id->hw_config & 0x6000)) ? 1 : 0);
-
-#else
-
- return ((u8) ((HWIF(drive)->udma_four) &&
#ifndef CONFIG_IDEDMA_IVB
- (drive->id->hw_config & 0x4000) &&
+ if(!(drive->id->hw_config & 0x4000))
+ return 0;
#endif /* CONFIG_IDEDMA_IVB */
- (drive->id->hw_config & 0x6000)) ? 1 : 0);
-#endif
+ return 1;
}
EXPORT_SYMBOL(eighty_ninty_three);
diff --git a/drivers/ide/pci/cmd64x.c b/drivers/ide/pci/cmd64x.c
index 3de9ab8..3d9c7af 100644
--- a/drivers/ide/pci/cmd64x.c
+++ b/drivers/ide/pci/cmd64x.c
@@ -608,7 +608,7 @@ static unsigned int __devinit init_chipset_cmd64x(struct pci_dev *dev, const cha
#ifdef __i386__
if (dev->resource[PCI_ROM_RESOURCE].start) {
- pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+ pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
printk(KERN_INFO "%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start);
}
#endif
diff --git a/drivers/ide/pci/hpt34x.c b/drivers/ide/pci/hpt34x.c
index bbde462..be334da 100644
--- a/drivers/ide/pci/hpt34x.c
+++ b/drivers/ide/pci/hpt34x.c
@@ -173,7 +173,7 @@ static unsigned int __devinit init_chipset_hpt34x(struct pci_dev *dev, const cha
if (cmd & PCI_COMMAND_MEMORY) {
if (pci_resource_start(dev, PCI_ROM_RESOURCE)) {
- pci_write_config_byte(dev, PCI_ROM_ADDRESS,
+ pci_write_config_dword(dev, PCI_ROM_ADDRESS,
dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
printk(KERN_INFO "HPT345: ROM enabled at 0x%08lx\n",
dev->resource[PCI_ROM_RESOURCE].start);
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index e55dee3..444f775 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -132,6 +132,17 @@ config KEYBOARD_CORGI
To compile this driver as a module, choose M here: the
module will be called corgikbd.
+config KEYBOARD_SPITZ
+ tristate "Spitz keyboard"
+ depends on PXA_SHARPSL
+ default y
+ help
+ Say Y here to enable the keyboard on the Sharp Zaurus SL-C1000,
+ SL-C3000 and Sl-C3100 series of PDAs.
+
+ To compile this driver as a module, choose M here: the
+ module will be called spitzkbd.
+
config KEYBOARD_MAPLE
tristate "Maple bus keyboard"
depends on SH_DREAMCAST && MAPLE
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index b02eece..9ce0b87 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_KEYBOARD_LOCOMO) += locomokbd.o
obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o
obj-$(CONFIG_KEYBOARD_98KBD) += 98kbd.o
obj-$(CONFIG_KEYBOARD_CORGI) += corgikbd.o
+obj-$(CONFIG_KEYBOARD_SPITZ) += spitzkbd.o
obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o
obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o
diff --git a/drivers/input/keyboard/spitzkbd.c b/drivers/input/keyboard/spitzkbd.c
new file mode 100644
index 0000000..1714045
--- /dev/null
+++ b/drivers/input/keyboard/spitzkbd.c
@@ -0,0 +1,478 @@
+/*
+ * Keyboard driver for Sharp Spitz, Borzoi and Akita (SL-Cxx00 series)
+ *
+ * Copyright (c) 2005 Richard Purdie
+ *
+ * Based on corgikbd.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <asm/irq.h>
+
+#include <asm/arch/spitz.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/pxa-regs.h>
+
+#define KB_ROWS 7
+#define KB_COLS 11
+#define KB_ROWMASK(r) (1 << (r))
+#define SCANCODE(r,c) (((r)<<4) + (c) + 1)
+#define NR_SCANCODES ((KB_ROWS<<4) + 1)
+
+#define HINGE_SCAN_INTERVAL (150) /* ms */
+
+#define SPITZ_KEY_CALENDER KEY_F1
+#define SPITZ_KEY_ADDRESS KEY_F2
+#define SPITZ_KEY_FN KEY_F3
+#define SPITZ_KEY_CANCEL KEY_F4
+#define SPITZ_KEY_EXOK KEY_F5
+#define SPITZ_KEY_EXCANCEL KEY_F6
+#define SPITZ_KEY_EXJOGDOWN KEY_F7
+#define SPITZ_KEY_EXJOGUP KEY_F8
+#define SPITZ_KEY_JAP1 KEY_LEFTALT
+#define SPITZ_KEY_JAP2 KEY_RIGHTCTRL
+#define SPITZ_KEY_SYNC KEY_F9
+#define SPITZ_KEY_MAIL KEY_F10
+#define SPITZ_KEY_OK KEY_F11
+#define SPITZ_KEY_MENU KEY_F12
+
+static unsigned char spitzkbd_keycode[NR_SCANCODES] = {
+ 0, /* 0 */
+ KEY_LEFTCTRL, KEY_1, KEY_3, KEY_5, KEY_6, KEY_7, KEY_9, KEY_0, KEY_BACKSPACE, SPITZ_KEY_EXOK, SPITZ_KEY_EXCANCEL, 0, 0, 0, 0, 0, /* 1-16 */
+ 0, KEY_2, KEY_4, KEY_R, KEY_Y, KEY_8, KEY_I, KEY_O, KEY_P, SPITZ_KEY_EXJOGDOWN, SPITZ_KEY_EXJOGUP, 0, 0, 0, 0, 0, /* 17-32 */
+ KEY_TAB, KEY_Q, KEY_E, KEY_T, KEY_G, KEY_U, KEY_J, KEY_K, 0, 0, 0, 0, 0, 0, 0, 0, /* 33-48 */
+ SPITZ_KEY_CALENDER, KEY_W, KEY_S, KEY_F, KEY_V, KEY_H, KEY_M, KEY_L, 0, 0, KEY_RIGHTSHIFT, 0, 0, 0, 0, 0, /* 49-64 */
+ SPITZ_KEY_ADDRESS, KEY_A, KEY_D, KEY_C, KEY_B, KEY_N, KEY_DOT, 0, KEY_ENTER, KEY_LEFTSHIFT, 0, 0, 0, 0, 0, 0, /* 65-80 */
+ SPITZ_KEY_MAIL, KEY_Z, KEY_X, KEY_MINUS, KEY_SPACE, KEY_COMMA, 0, KEY_UP, 0, 0, SPITZ_KEY_FN, 0, 0, 0, 0, 0, /* 81-96 */
+ KEY_SYSRQ, SPITZ_KEY_JAP1, SPITZ_KEY_JAP2, SPITZ_KEY_CANCEL, SPITZ_KEY_OK, SPITZ_KEY_MENU, KEY_LEFT, KEY_DOWN, KEY_RIGHT, 0, 0, 0, 0, 0, 0, 0 /* 97-112 */
+};
+
+static int spitz_strobes[] = {
+ SPITZ_GPIO_KEY_STROBE0,
+ SPITZ_GPIO_KEY_STROBE1,
+ SPITZ_GPIO_KEY_STROBE2,
+ SPITZ_GPIO_KEY_STROBE3,
+ SPITZ_GPIO_KEY_STROBE4,
+ SPITZ_GPIO_KEY_STROBE5,
+ SPITZ_GPIO_KEY_STROBE6,
+ SPITZ_GPIO_KEY_STROBE7,
+ SPITZ_GPIO_KEY_STROBE8,
+ SPITZ_GPIO_KEY_STROBE9,
+ SPITZ_GPIO_KEY_STROBE10,
+};
+
+static int spitz_senses[] = {
+ SPITZ_GPIO_KEY_SENSE0,
+ SPITZ_GPIO_KEY_SENSE1,
+ SPITZ_GPIO_KEY_SENSE2,
+ SPITZ_GPIO_KEY_SENSE3,
+ SPITZ_GPIO_KEY_SENSE4,
+ SPITZ_GPIO_KEY_SENSE5,
+ SPITZ_GPIO_KEY_SENSE6,
+};
+
+struct spitzkbd {
+ unsigned char keycode[ARRAY_SIZE(spitzkbd_keycode)];
+ struct input_dev input;
+ char phys[32];
+
+ spinlock_t lock;
+ struct timer_list timer;
+ struct timer_list htimer;
+
+ unsigned int suspended;
+ unsigned long suspend_jiffies;
+};
+
+#define KB_DISCHARGE_DELAY 10
+#define KB_ACTIVATE_DELAY 10
+
+/* Helper functions for reading the keyboard matrix
+ * Note: We should really be using pxa_gpio_mode to alter GPDR but it
+ * requires a function call per GPIO bit which is excessive
+ * when we need to access 11 bits at once, multiple times.
+ * These functions must be called within local_irq_save()/local_irq_restore()
+ * or similar.
+ */
+static inline void spitzkbd_discharge_all(void)
+{
+ /* STROBE All HiZ */
+ GPCR0 = SPITZ_GPIO_G0_STROBE_BIT;
+ GPDR0 &= ~SPITZ_GPIO_G0_STROBE_BIT;
+ GPCR1 = SPITZ_GPIO_G1_STROBE_BIT;
+ GPDR1 &= ~SPITZ_GPIO_G1_STROBE_BIT;
+ GPCR2 = SPITZ_GPIO_G2_STROBE_BIT;
+ GPDR2 &= ~SPITZ_GPIO_G2_STROBE_BIT;
+ GPCR3 = SPITZ_GPIO_G3_STROBE_BIT;
+ GPDR3 &= ~SPITZ_GPIO_G3_STROBE_BIT;
+}
+
+static inline void spitzkbd_activate_all(void)
+{
+ /* STROBE ALL -> High */
+ GPSR0 = SPITZ_GPIO_G0_STROBE_BIT;
+ GPDR0 |= SPITZ_GPIO_G0_STROBE_BIT;
+ GPSR1 = SPITZ_GPIO_G1_STROBE_BIT;
+ GPDR1 |= SPITZ_GPIO_G1_STROBE_BIT;
+ GPSR2 = SPITZ_GPIO_G2_STROBE_BIT;
+ GPDR2 |= SPITZ_GPIO_G2_STROBE_BIT;
+ GPSR3 = SPITZ_GPIO_G3_STROBE_BIT;
+ GPDR3 |= SPITZ_GPIO_G3_STROBE_BIT;
+
+ udelay(KB_DISCHARGE_DELAY);
+
+ /* Clear any interrupts we may have triggered when altering the GPIO lines */
+ GEDR0 = SPITZ_GPIO_G0_SENSE_BIT;
+ GEDR1 = SPITZ_GPIO_G1_SENSE_BIT;
+ GEDR2 = SPITZ_GPIO_G2_SENSE_BIT;
+ GEDR3 = SPITZ_GPIO_G3_SENSE_BIT;
+}
+
+static inline void spitzkbd_activate_col(int col)
+{
+ int gpio = spitz_strobes[col];
+ GPDR0 &= ~SPITZ_GPIO_G0_STROBE_BIT;
+ GPDR1 &= ~SPITZ_GPIO_G1_STROBE_BIT;
+ GPDR2 &= ~SPITZ_GPIO_G2_STROBE_BIT;
+ GPDR3 &= ~SPITZ_GPIO_G3_STROBE_BIT;
+ GPSR(gpio) = GPIO_bit(gpio);
+ GPDR(gpio) |= GPIO_bit(gpio);
+}
+
+static inline void spitzkbd_reset_col(int col)
+{
+ int gpio = spitz_strobes[col];
+ GPDR0 &= ~SPITZ_GPIO_G0_STROBE_BIT;
+ GPDR1 &= ~SPITZ_GPIO_G1_STROBE_BIT;
+ GPDR2 &= ~SPITZ_GPIO_G2_STROBE_BIT;
+ GPDR3 &= ~SPITZ_GPIO_G3_STROBE_BIT;
+ GPCR(gpio) = GPIO_bit(gpio);
+ GPDR(gpio) |= GPIO_bit(gpio);
+}
+
+static inline int spitzkbd_get_row_status(int col)
+{
+ return ((GPLR0 >> 12) & 0x01) | ((GPLR0 >> 16) & 0x02)
+ | ((GPLR2 >> 25) & 0x04) | ((GPLR1 << 1) & 0x08)
+ | ((GPLR1 >> 0) & 0x10) | ((GPLR1 >> 1) & 0x60);
+}
+
+/*
+ * The spitz keyboard only generates interrupts when a key is pressed.
+ * When a key is pressed, we enable a timer which then scans the
+ * keyboard to detect when the key is released.
+ */
+
+/* Scan the hardware keyboard and push any changes up through the input layer */
+static void spitzkbd_scankeyboard(struct spitzkbd *spitzkbd_data, struct pt_regs *regs)
+{
+ unsigned int row, col, rowd;
+ unsigned long flags;
+ unsigned int num_pressed, pwrkey = ((GPLR(SPITZ_GPIO_ON_KEY) & GPIO_bit(SPITZ_GPIO_ON_KEY)) != 0);
+
+ if (spitzkbd_data->suspended)
+ return;
+
+ spin_lock_irqsave(&spitzkbd_data->lock, flags);
+
+ if (regs)
+ input_regs(&spitzkbd_data->input, regs);
+
+ num_pressed = 0;
+ for (col = 0; col < KB_COLS; col++) {
+ /*
+ * Discharge the output driver capacitatance
+ * in the keyboard matrix. (Yes it is significant..)
+ */
+
+ spitzkbd_discharge_all();
+ udelay(KB_DISCHARGE_DELAY);
+
+ spitzkbd_activate_col(col);
+ udelay(KB_ACTIVATE_DELAY);
+
+ rowd = spitzkbd_get_row_status(col);
+ for (row = 0; row < KB_ROWS; row++) {
+ unsigned int scancode, pressed;
+
+ scancode = SCANCODE(row, col);
+ pressed = rowd & KB_ROWMASK(row);
+
+ input_report_key(&spitzkbd_data->input, spitzkbd_data->keycode[scancode], pressed);
+
+ if (pressed)
+ num_pressed++;
+ }
+ spitzkbd_reset_col(col);
+ }
+
+ spitzkbd_activate_all();
+
+ input_report_key(&spitzkbd_data->input, SPITZ_KEY_SYNC, (GPLR(SPITZ_GPIO_SYNC) & GPIO_bit(SPITZ_GPIO_SYNC)) != 0 );
+ input_report_key(&spitzkbd_data->input, KEY_SUSPEND, pwrkey);
+
+ if (pwrkey && time_after(jiffies, spitzkbd_data->suspend_jiffies + msecs_to_jiffies(1000))) {
+ input_event(&spitzkbd_data->input, EV_PWR, KEY_SUSPEND, 1);
+ spitzkbd_data->suspend_jiffies = jiffies;
+ }
+
+ input_sync(&spitzkbd_data->input);
+
+ /* if any keys are pressed, enable the timer */
+ if (num_pressed)
+ mod_timer(&spitzkbd_data->timer, jiffies + msecs_to_jiffies(100));
+
+ spin_unlock_irqrestore(&spitzkbd_data->lock, flags);
+}
+
+/*
+ * spitz keyboard interrupt handler.
+ */
+static irqreturn_t spitzkbd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct spitzkbd *spitzkbd_data = dev_id;
+
+ if (!timer_pending(&spitzkbd_data->timer)) {
+ /** wait chattering delay **/
+ udelay(20);
+ spitzkbd_scankeyboard(spitzkbd_data, regs);
+ }
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * spitz timer checking for released keys
+ */
+static void spitzkbd_timer_callback(unsigned long data)
+{
+ struct spitzkbd *spitzkbd_data = (struct spitzkbd *) data;
+ spitzkbd_scankeyboard(spitzkbd_data, NULL);
+}
+
+/*
+ * The hinge switches generate an interrupt.
+ * We debounce the switches and pass them to the input system.
+ */
+
+static irqreturn_t spitzkbd_hinge_isr(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct spitzkbd *spitzkbd_data = dev_id;
+
+ if (!timer_pending(&spitzkbd_data->htimer))
+ mod_timer(&spitzkbd_data->htimer, jiffies + msecs_to_jiffies(HINGE_SCAN_INTERVAL));
+
+ return IRQ_HANDLED;
+}
+
+#define HINGE_STABLE_COUNT 2
+static int sharpsl_hinge_state;
+static int hinge_count;
+
+static void spitzkbd_hinge_timer(unsigned long data)
+{
+ struct spitzkbd *spitzkbd_data = (struct spitzkbd *) data;
+ unsigned long state;
+ unsigned long flags;
+
+ state = GPLR(SPITZ_GPIO_SWA) & (GPIO_bit(SPITZ_GPIO_SWA)|GPIO_bit(SPITZ_GPIO_SWB));
+ if (state != sharpsl_hinge_state) {
+ hinge_count = 0;
+ sharpsl_hinge_state = state;
+ } else if (hinge_count < HINGE_STABLE_COUNT) {
+ hinge_count++;
+ }
+
+ if (hinge_count >= HINGE_STABLE_COUNT) {
+ spin_lock_irqsave(&spitzkbd_data->lock, flags);
+
+ input_report_switch(&spitzkbd_data->input, SW_0, ((GPLR(SPITZ_GPIO_SWA) & GPIO_bit(SPITZ_GPIO_SWA)) != 0));
+ input_report_switch(&spitzkbd_data->input, SW_1, ((GPLR(SPITZ_GPIO_SWB) & GPIO_bit(SPITZ_GPIO_SWB)) != 0));
+ input_sync(&spitzkbd_data->input);
+
+ spin_unlock_irqrestore(&spitzkbd_data->lock, flags);
+ } else {
+ mod_timer(&spitzkbd_data->htimer, jiffies + msecs_to_jiffies(HINGE_SCAN_INTERVAL));
+ }
+}
+
+#ifdef CONFIG_PM
+static int spitzkbd_suspend(struct device *dev, pm_message_t state, uint32_t level)
+{
+ if (level == SUSPEND_POWER_DOWN) {
+ int i;
+ struct spitzkbd *spitzkbd = dev_get_drvdata(dev);
+ spitzkbd->suspended = 1;
+
+ /* Set Strobe lines as inputs - *except* strobe line 0 leave this
+ enabled so we can detect a power button press for resume */
+ for (i = 1; i < SPITZ_KEY_STROBE_NUM; i++)
+ pxa_gpio_mode(spitz_strobes[i] | GPIO_IN);
+ }
+ return 0;
+}
+
+static int spitzkbd_resume(struct device *dev, uint32_t level)
+{
+ if (level == RESUME_POWER_ON) {
+ int i;
+ struct spitzkbd *spitzkbd = dev_get_drvdata(dev);
+
+ for (i = 0; i < SPITZ_KEY_STROBE_NUM; i++)
+ pxa_gpio_mode(spitz_strobes[i] | GPIO_OUT | GPIO_DFLT_HIGH);
+
+ /* Upon resume, ignore the suspend key for a short while */
+ spitzkbd->suspend_jiffies = jiffies;
+ spitzkbd->suspended = 0;
+ }
+ return 0;
+}
+#else
+#define spitzkbd_suspend NULL
+#define spitzkbd_resume NULL
+#endif
+
+static int __init spitzkbd_probe(struct device *dev)
+{
+ int i;
+ struct spitzkbd *spitzkbd;
+
+ spitzkbd = kzalloc(sizeof(struct spitzkbd), GFP_KERNEL);
+ if (!spitzkbd)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev,spitzkbd);
+ strcpy(spitzkbd->phys, "spitzkbd/input0");
+
+ spin_lock_init(&spitzkbd->lock);
+
+ /* Init Keyboard rescan timer */
+ init_timer(&spitzkbd->timer);
+ spitzkbd->timer.function = spitzkbd_timer_callback;
+ spitzkbd->timer.data = (unsigned long) spitzkbd;
+
+ /* Init Hinge Timer */
+ init_timer(&spitzkbd->htimer);
+ spitzkbd->htimer.function = spitzkbd_hinge_timer;
+ spitzkbd->htimer.data = (unsigned long) spitzkbd;
+
+ spitzkbd->suspend_jiffies=jiffies;
+
+ init_input_dev(&spitzkbd->input);
+ spitzkbd->input.private = spitzkbd;
+ spitzkbd->input.name = "Spitz Keyboard";
+ spitzkbd->input.dev = dev;
+ spitzkbd->input.phys = spitzkbd->phys;
+ spitzkbd->input.id.bustype = BUS_HOST;
+ spitzkbd->input.id.vendor = 0x0001;
+ spitzkbd->input.id.product = 0x0001;
+ spitzkbd->input.id.version = 0x0100;
+ spitzkbd->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_PWR) | BIT(EV_SW);
+ spitzkbd->input.keycode = spitzkbd->keycode;
+ spitzkbd->input.keycodesize = sizeof(unsigned char);
+ spitzkbd->input.keycodemax = ARRAY_SIZE(spitzkbd_keycode);
+
+ memcpy(spitzkbd->keycode, spitzkbd_keycode, sizeof(spitzkbd->keycode));
+ for (i = 0; i < ARRAY_SIZE(spitzkbd_keycode); i++)
+ set_bit(spitzkbd->keycode[i], spitzkbd->input.keybit);
+ clear_bit(0, spitzkbd->input.keybit);
+ set_bit(SW_0, spitzkbd->input.swbit);
+ set_bit(SW_1, spitzkbd->input.swbit);
+
+ input_register_device(&spitzkbd->input);
+ mod_timer(&spitzkbd->htimer, jiffies + msecs_to_jiffies(HINGE_SCAN_INTERVAL));
+
+ /* Setup sense interrupts - RisingEdge Detect, sense lines as inputs */
+ for (i = 0; i < SPITZ_KEY_SENSE_NUM; i++) {
+ pxa_gpio_mode(spitz_senses[i] | GPIO_IN);
+ if (request_irq(IRQ_GPIO(spitz_senses[i]), spitzkbd_interrupt,
+ SA_INTERRUPT, "Spitzkbd Sense", spitzkbd))
+ printk(KERN_WARNING "spitzkbd: Can't get Sense IRQ: %d!\n", i);
+ else
+ set_irq_type(IRQ_GPIO(spitz_senses[i]),IRQT_RISING);
+ }
+
+ /* Set Strobe lines as outputs - set high */
+ for (i = 0; i < SPITZ_KEY_STROBE_NUM; i++)
+ pxa_gpio_mode(spitz_strobes[i] | GPIO_OUT | GPIO_DFLT_HIGH);
+
+ pxa_gpio_mode(SPITZ_GPIO_SYNC | GPIO_IN);
+ pxa_gpio_mode(SPITZ_GPIO_ON_KEY | GPIO_IN);
+ pxa_gpio_mode(SPITZ_GPIO_SWA | GPIO_IN);
+ pxa_gpio_mode(SPITZ_GPIO_SWB | GPIO_IN);
+
+ request_irq(SPITZ_IRQ_GPIO_SYNC, spitzkbd_interrupt, SA_INTERRUPT, "Spitzkbd Sync", spitzkbd);
+ request_irq(SPITZ_IRQ_GPIO_ON_KEY, spitzkbd_interrupt, SA_INTERRUPT, "Spitzkbd PwrOn", spitzkbd);
+ request_irq(SPITZ_IRQ_GPIO_SWA, spitzkbd_hinge_isr, SA_INTERRUPT, "Spitzkbd SWA", spitzkbd);
+ request_irq(SPITZ_IRQ_GPIO_SWB, spitzkbd_hinge_isr, SA_INTERRUPT, "Spitzkbd SWB", spitzkbd);
+
+ set_irq_type(SPITZ_IRQ_GPIO_SYNC, IRQT_BOTHEDGE);
+ set_irq_type(SPITZ_IRQ_GPIO_ON_KEY, IRQT_BOTHEDGE);
+ set_irq_type(SPITZ_IRQ_GPIO_SWA, IRQT_BOTHEDGE);
+ set_irq_type(SPITZ_IRQ_GPIO_SWB, IRQT_BOTHEDGE);
+
+ printk(KERN_INFO "input: Spitz Keyboard Registered\n");
+
+ return 0;
+}
+
+static int spitzkbd_remove(struct device *dev)
+{
+ int i;
+ struct spitzkbd *spitzkbd = dev_get_drvdata(dev);
+
+ for (i = 0; i < SPITZ_KEY_SENSE_NUM; i++)
+ free_irq(IRQ_GPIO(spitz_senses[i]), spitzkbd);
+
+ free_irq(SPITZ_IRQ_GPIO_SYNC, spitzkbd);
+ free_irq(SPITZ_IRQ_GPIO_ON_KEY, spitzkbd);
+ free_irq(SPITZ_IRQ_GPIO_SWA, spitzkbd);
+ free_irq(SPITZ_IRQ_GPIO_SWB, spitzkbd);
+
+ del_timer_sync(&spitzkbd->htimer);
+ del_timer_sync(&spitzkbd->timer);
+
+ input_unregister_device(&spitzkbd->input);
+
+ kfree(spitzkbd);
+
+ return 0;
+}
+
+static struct device_driver spitzkbd_driver = {
+ .name = "spitz-keyboard",
+ .bus = &platform_bus_type,
+ .probe = spitzkbd_probe,
+ .remove = spitzkbd_remove,
+ .suspend = spitzkbd_suspend,
+ .resume = spitzkbd_resume,
+};
+
+static int __devinit spitzkbd_init(void)
+{
+ return driver_register(&spitzkbd_driver);
+}
+
+static void __exit spitzkbd_exit(void)
+{
+ driver_unregister(&spitzkbd_driver);
+}
+
+module_init(spitzkbd_init);
+module_exit(spitzkbd_exit);
+
+MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>");
+MODULE_DESCRIPTION("Spitz Keyboard Driver");
+MODULE_LICENSE("GPLv2");
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 0489af5..21d55ed 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -24,17 +24,17 @@ config TOUCHSCREEN_BITSY
module will be called h3600_ts_input.
config TOUCHSCREEN_CORGI
- tristate "Corgi touchscreen (for Sharp SL-C7xx)"
+ tristate "SharpSL (Corgi and Spitz series) touchscreen driver"
depends on PXA_SHARPSL
default y
help
Say Y here to enable the driver for the touchscreen on the
- Sharp SL-C7xx series of PDAs.
+ Sharp SL-C7xx and SL-Cxx00 series of PDAs.
If unsure, say N.
To compile this driver as a module, choose M here: the
- module will be called ads7846_ts.
+ module will be called corgi_ts.
config TOUCHSCREEN_GUNZE
tristate "Gunze AHL-51S touchscreen"
diff --git a/drivers/input/touchscreen/corgi_ts.c b/drivers/input/touchscreen/corgi_ts.c
index 5d19261..4c7fbe5 100644
--- a/drivers/input/touchscreen/corgi_ts.c
+++ b/drivers/input/touchscreen/corgi_ts.c
@@ -1,5 +1,5 @@
/*
- * Touchscreen driver for Sharp Corgi models (SL-C7xx)
+ * Touchscreen driver for Sharp SL-C7xx and SL-Cxx00 models
*
* Copyright (c) 2004-2005 Richard Purdie
*
@@ -19,7 +19,7 @@
#include <linux/slab.h>
#include <asm/irq.h>
-#include <asm/arch/corgi.h>
+#include <asm/arch/sharpsl.h>
#include <asm/arch/hardware.h>
#include <asm/arch/pxa-regs.h>
@@ -47,15 +47,20 @@ struct corgi_ts {
struct ts_event tc;
int pendown;
int power_mode;
+ int irq_gpio;
+ struct corgits_machinfo *machinfo;
};
-#define STATUS_HSYNC (GPLR(CORGI_GPIO_HSYNC) & GPIO_bit(CORGI_GPIO_HSYNC))
-
-#define SyncHS() while((STATUS_HSYNC) == 0); while((STATUS_HSYNC) != 0);
+#ifdef CONFIG_PXA25x
#define CCNT(a) asm volatile ("mrc p14, 0, %0, C1, C0, 0" : "=r"(a))
#define PMNC_GET(x) asm volatile ("mrc p14, 0, %0, C0, C0, 0" : "=r"(x))
#define PMNC_SET(x) asm volatile ("mcr p14, 0, %0, C0, C0, 0" : : "r"(x))
-
+#endif
+#ifdef CONFIG_PXA27x
+#define CCNT(a) asm volatile ("mrc p14, 0, %0, C1, C1, 0" : "=r"(a))
+#define PMNC_GET(x) asm volatile ("mrc p14, 0, %0, C0, C1, 0" : "=r"(x))
+#define PMNC_SET(x) asm volatile ("mcr p14, 0, %0, C0, C1, 0" : : "r"(x))
+#endif
/* ADS7846 Touch Screen Controller bit definitions */
#define ADSCTRL_PD0 (1u << 0) /* PD0 */
@@ -66,12 +71,11 @@ struct corgi_ts {
#define ADSCTRL_STS (1u << 7) /* Start Bit */
/* External Functions */
-extern unsigned long w100fb_get_hsynclen(struct device *dev);
extern unsigned int get_clk_frequency_khz(int info);
-static unsigned long calc_waittime(void)
+static unsigned long calc_waittime(struct corgi_ts *corgi_ts)
{
- unsigned long hsync_len = w100fb_get_hsynclen(&corgifb_device.dev);
+ unsigned long hsync_len = corgi_ts->machinfo->get_hsync_len();
if (hsync_len)
return get_clk_frequency_khz(0)*1000/hsync_len;
@@ -79,7 +83,8 @@ static unsigned long calc_waittime(void)
return 0;
}
-static int sync_receive_data_send_cmd(int doRecive, int doSend, unsigned int address, unsigned long wait_time)
+static int sync_receive_data_send_cmd(struct corgi_ts *corgi_ts, int doRecive, int doSend,
+ unsigned int address, unsigned long wait_time)
{
unsigned long timer1 = 0, timer2, pmnc = 0;
int pos = 0;
@@ -90,7 +95,7 @@ static int sync_receive_data_send_cmd(int doRecive, int doSend, unsigned int add
PMNC_SET(0x01);
/* polling HSync */
- SyncHS();
+ corgi_ts->machinfo->wait_hsync();
/* get CCNT */
CCNT(timer1);
}
@@ -109,7 +114,7 @@ static int sync_receive_data_send_cmd(int doRecive, int doSend, unsigned int add
CCNT(timer2);
if (timer2-timer1 > wait_time) {
/* too slow - timeout, try again */
- SyncHS();
+ corgi_ts->machinfo->wait_hsync();
/* get OSCR */
CCNT(timer1);
/* Wait after HSync */
@@ -133,23 +138,23 @@ static int read_xydata(struct corgi_ts *corgi_ts)
/* critical section */
local_irq_save(flags);
corgi_ssp_ads7846_lock();
- wait_time=calc_waittime();
+ wait_time = calc_waittime(corgi_ts);
/* Y-axis */
- sync_receive_data_send_cmd(0, 1, 1u, wait_time);
+ sync_receive_data_send_cmd(corgi_ts, 0, 1, 1u, wait_time);
/* Y-axis */
- sync_receive_data_send_cmd(1, 1, 1u, wait_time);
+ sync_receive_data_send_cmd(corgi_ts, 1, 1, 1u, wait_time);
/* X-axis */
- y = sync_receive_data_send_cmd(1, 1, 5u, wait_time);
+ y = sync_receive_data_send_cmd(corgi_ts, 1, 1, 5u, wait_time);
/* Z1 */
- x = sync_receive_data_send_cmd(1, 1, 3u, wait_time);
+ x = sync_receive_data_send_cmd(corgi_ts, 1, 1, 3u, wait_time);
/* Z2 */
- z1 = sync_receive_data_send_cmd(1, 1, 4u, wait_time);
- z2 = sync_receive_data_send_cmd(1, 0, 4u, wait_time);
+ z1 = sync_receive_data_send_cmd(corgi_ts, 1, 1, 4u, wait_time);
+ z2 = sync_receive_data_send_cmd(corgi_ts, 1, 0, 4u, wait_time);
/* Power-Down Enable */
corgi_ssp_ads7846_put((1u << ADSCTRL_ADR_SH) | ADSCTRL_STS);
@@ -189,9 +194,9 @@ static void new_data(struct corgi_ts *corgi_ts, struct pt_regs *regs)
static void ts_interrupt_main(struct corgi_ts *corgi_ts, int isTimer, struct pt_regs *regs)
{
- if ((GPLR(CORGI_GPIO_TP_INT) & GPIO_bit(CORGI_GPIO_TP_INT)) == 0) {
+ if ((GPLR(IRQ_TO_GPIO(corgi_ts->irq_gpio)) & GPIO_bit(IRQ_TO_GPIO(corgi_ts->irq_gpio))) == 0) {
/* Disable Interrupt */
- set_irq_type(CORGI_IRQ_GPIO_TP_INT, IRQT_NOEDGE);
+ set_irq_type(corgi_ts->irq_gpio, IRQT_NOEDGE);
if (read_xydata(corgi_ts)) {
corgi_ts->pendown = 1;
new_data(corgi_ts, regs);
@@ -210,7 +215,7 @@ static void ts_interrupt_main(struct corgi_ts *corgi_ts, int isTimer, struct pt_
}
/* Enable Falling Edge */
- set_irq_type(CORGI_IRQ_GPIO_TP_INT, IRQT_FALLING);
+ set_irq_type(corgi_ts->irq_gpio, IRQT_FALLING);
corgi_ts->pendown = 0;
}
}
@@ -254,7 +259,7 @@ static int corgits_resume(struct device *dev, uint32_t level)
corgi_ssp_ads7846_putget((4u << ADSCTRL_ADR_SH) | ADSCTRL_STS);
/* Enable Falling Edge */
- set_irq_type(CORGI_IRQ_GPIO_TP_INT, IRQT_FALLING);
+ set_irq_type(corgi_ts->irq_gpio, IRQT_FALLING);
corgi_ts->power_mode = PWR_MODE_ACTIVE;
}
return 0;
@@ -267,6 +272,7 @@ static int corgits_resume(struct device *dev, uint32_t level)
static int __init corgits_probe(struct device *dev)
{
struct corgi_ts *corgi_ts;
+ struct platform_device *pdev = to_platform_device(dev);
if (!(corgi_ts = kmalloc(sizeof(struct corgi_ts), GFP_KERNEL)))
return -ENOMEM;
@@ -275,6 +281,14 @@ static int __init corgits_probe(struct device *dev)
memset(corgi_ts, 0, sizeof(struct corgi_ts));
+ corgi_ts->machinfo = dev->platform_data;
+ corgi_ts->irq_gpio = platform_get_irq(pdev, 0);
+
+ if (corgi_ts->irq_gpio < 0) {
+ kfree(corgi_ts);
+ return -ENODEV;
+ }
+
init_input_dev(&corgi_ts->input);
corgi_ts->input.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
corgi_ts->input.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
@@ -293,8 +307,7 @@ static int __init corgits_probe(struct device *dev)
corgi_ts->input.id.product = 0x0002;
corgi_ts->input.id.version = 0x0100;
- pxa_gpio_mode(CORGI_GPIO_TP_INT | GPIO_IN);
- pxa_gpio_mode(CORGI_GPIO_HSYNC | GPIO_IN);
+ pxa_gpio_mode(IRQ_TO_GPIO(corgi_ts->irq_gpio) | GPIO_IN);
/* Initiaize ADS7846 Difference Reference mode */
corgi_ssp_ads7846_putget((1u << ADSCTRL_ADR_SH) | ADSCTRL_STS);
@@ -313,14 +326,14 @@ static int __init corgits_probe(struct device *dev)
input_register_device(&corgi_ts->input);
corgi_ts->power_mode = PWR_MODE_ACTIVE;
- if (request_irq(CORGI_IRQ_GPIO_TP_INT, ts_interrupt, SA_INTERRUPT, "ts", corgi_ts)) {
+ if (request_irq(corgi_ts->irq_gpio, ts_interrupt, SA_INTERRUPT, "ts", corgi_ts)) {
input_unregister_device(&corgi_ts->input);
kfree(corgi_ts);
return -EBUSY;
}
/* Enable Falling Edge */
- set_irq_type(CORGI_IRQ_GPIO_TP_INT, IRQT_FALLING);
+ set_irq_type(corgi_ts->irq_gpio, IRQT_FALLING);
printk(KERN_INFO "input: Corgi Touchscreen Registered\n");
@@ -331,8 +344,9 @@ static int corgits_remove(struct device *dev)
{
struct corgi_ts *corgi_ts = dev_get_drvdata(dev);
- free_irq(CORGI_IRQ_GPIO_TP_INT, NULL);
+ free_irq(corgi_ts->irq_gpio, NULL);
del_timer_sync(&corgi_ts->timer);
+ corgi_ts->machinfo->put_hsync();
input_unregister_device(&corgi_ts->input);
kfree(corgi_ts);
return 0;
diff --git a/drivers/isdn/sc/init.c b/drivers/isdn/sc/init.c
index 40b0df0..1ebed04 100644
--- a/drivers/isdn/sc/init.c
+++ b/drivers/isdn/sc/init.c
@@ -87,7 +87,7 @@ static int __init sc_init(void)
*/
for (i = 0 ; i < MAX_IO_REGS - 1 ; i++) {
if(!request_region(io[b] + i * 0x400, 1, "sc test")) {
- pr_debug("check_region for 0x%x failed\n", io[b] + i * 0x400);
+ pr_debug("request_region for 0x%x failed\n", io[b] + i * 0x400);
io[b] = 0;
break;
} else
@@ -181,7 +181,7 @@ static int __init sc_init(void)
for (i = SRAM_MIN ; i < SRAM_MAX ; i += SRAM_PAGESIZE) {
pr_debug("Checking RAM address 0x%x...\n", i);
if(request_region(i, SRAM_PAGESIZE, "sc test")) {
- pr_debug(" check_region succeeded\n");
+ pr_debug(" request_region succeeded\n");
model = identify_board(i, io[b]);
release_region(i, SRAM_PAGESIZE);
if (model >= 0) {
diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c
index 8b4ad70..877c770 100644
--- a/drivers/media/radio/radio-aimslab.c
+++ b/drivers/media/radio/radio-aimslab.c
@@ -29,7 +29,7 @@
#include <linux/module.h> /* Modules */
#include <linux/init.h> /* Initdata */
-#include <linux/ioport.h> /* check_region, request_region */
+#include <linux/ioport.h> /* request_region */
#include <linux/delay.h> /* udelay */
#include <asm/io.h> /* outb, outb_p */
#include <asm/uaccess.h> /* copy to/from user */
diff --git a/drivers/media/radio/radio-aztech.c b/drivers/media/radio/radio-aztech.c
index 013c835..5319a9c 100644
--- a/drivers/media/radio/radio-aztech.c
+++ b/drivers/media/radio/radio-aztech.c
@@ -26,7 +26,7 @@
#include <linux/module.h> /* Modules */
#include <linux/init.h> /* Initdata */
-#include <linux/ioport.h> /* check_region, request_region */
+#include <linux/ioport.h> /* request_region */
#include <linux/delay.h> /* udelay */
#include <asm/io.h> /* outb, outb_p */
#include <asm/uaccess.h> /* copy to/from user */
diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c
index 53d399b..022913d 100644
--- a/drivers/media/radio/radio-cadet.c
+++ b/drivers/media/radio/radio-cadet.c
@@ -29,7 +29,7 @@
#include <linux/module.h> /* Modules */
#include <linux/init.h> /* Initdata */
-#include <linux/ioport.h> /* check_region, request_region */
+#include <linux/ioport.h> /* request_region */
#include <linux/delay.h> /* udelay */
#include <asm/io.h> /* outb, outb_p */
#include <asm/uaccess.h> /* copy to/from user */
diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c
index 202bfe6..6418f03 100644
--- a/drivers/media/radio/radio-gemtek.c
+++ b/drivers/media/radio/radio-gemtek.c
@@ -17,7 +17,7 @@
#include <linux/module.h> /* Modules */
#include <linux/init.h> /* Initdata */
-#include <linux/ioport.h> /* check_region, request_region */
+#include <linux/ioport.h> /* request_region */
#include <linux/delay.h> /* udelay */
#include <asm/io.h> /* outb, outb_p */
#include <asm/uaccess.h> /* copy to/from user */
diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c
index c00245d..b2256d6 100644
--- a/drivers/media/radio/radio-rtrack2.c
+++ b/drivers/media/radio/radio-rtrack2.c
@@ -10,7 +10,7 @@
#include <linux/module.h> /* Modules */
#include <linux/init.h> /* Initdata */
-#include <linux/ioport.h> /* check_region, request_region */
+#include <linux/ioport.h> /* request_region */
#include <linux/delay.h> /* udelay */
#include <asm/io.h> /* outb, outb_p */
#include <asm/uaccess.h> /* copy to/from user */
diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c
index 3a464a0..6f03ce4 100644
--- a/drivers/media/radio/radio-sf16fmi.c
+++ b/drivers/media/radio/radio-sf16fmi.c
@@ -18,7 +18,7 @@
#include <linux/kernel.h> /* __setup */
#include <linux/module.h> /* Modules */
#include <linux/init.h> /* Initdata */
-#include <linux/ioport.h> /* check_region, request_region */
+#include <linux/ioport.h> /* request_region */
#include <linux/delay.h> /* udelay */
#include <linux/videodev.h> /* kernel radio structs */
#include <linux/isapnp.h>
diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c
index 0732efd..71971e9 100644
--- a/drivers/media/radio/radio-sf16fmr2.c
+++ b/drivers/media/radio/radio-sf16fmr2.c
@@ -14,7 +14,7 @@
#include <linux/module.h> /* Modules */
#include <linux/init.h> /* Initdata */
-#include <linux/ioport.h> /* check_region, request_region */
+#include <linux/ioport.h> /* request_region */
#include <linux/delay.h> /* udelay */
#include <asm/io.h> /* outb, outb_p */
#include <asm/uaccess.h> /* copy to/from user */
diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c
index 248d67f..b03573c 100644
--- a/drivers/media/radio/radio-terratec.c
+++ b/drivers/media/radio/radio-terratec.c
@@ -25,7 +25,7 @@
#include <linux/module.h> /* Modules */
#include <linux/init.h> /* Initdata */
-#include <linux/ioport.h> /* check_region, request_region */
+#include <linux/ioport.h> /* request_region */
#include <linux/delay.h> /* udelay */
#include <asm/io.h> /* outb, outb_p */
#include <asm/uaccess.h> /* copy to/from user */
diff --git a/drivers/media/radio/radio-typhoon.c b/drivers/media/radio/radio-typhoon.c
index d7da901..f304f3c 100644
--- a/drivers/media/radio/radio-typhoon.c
+++ b/drivers/media/radio/radio-typhoon.c
@@ -31,7 +31,7 @@
#include <linux/module.h> /* Modules */
#include <linux/init.h> /* Initdata */
-#include <linux/ioport.h> /* check_region, request_region */
+#include <linux/ioport.h> /* request_region */
#include <linux/proc_fs.h> /* radio card status report */
#include <asm/io.h> /* outb, outb_p */
#include <asm/uaccess.h> /* copy to/from user */
diff --git a/drivers/media/radio/radio-zoltrix.c b/drivers/media/radio/radio-zoltrix.c
index 342f92d..4c6d6fb 100644
--- a/drivers/media/radio/radio-zoltrix.c
+++ b/drivers/media/radio/radio-zoltrix.c
@@ -28,7 +28,7 @@
#include <linux/module.h> /* Modules */
#include <linux/init.h> /* Initdata */
-#include <linux/ioport.h> /* check_region, request_region */
+#include <linux/ioport.h> /* request_region */
#include <linux/delay.h> /* udelay, msleep */
#include <asm/io.h> /* outb, outb_p */
#include <asm/uaccess.h> /* copy to/from user */
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index c9106b1..4334744 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -221,9 +221,7 @@ static int lgdt330x_pll_set(struct dvb_frontend* fe,
int err;
/* Put the analog decoder in standby to keep it quiet */
- if (core->tda9887_conf) {
- cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL);
- }
+ cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL);
dvb_pll_configure(core->pll_desc, buf, params->frequency, 0);
dprintk(1, "%s: tuner at 0x%02x bytes: 0x%02x 0x%02x 0x%02x 0x%02x\n",
@@ -402,6 +400,9 @@ static int dvb_register(struct cx8802_dev *dev)
dev->dvb.frontend->ops->info.frequency_max = dev->core->pll_desc->max;
}
+ /* Put the analog decoder in standby to keep it quiet */
+ cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL);
+
/* register everything */
return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev);
}
diff --git a/drivers/net/arcnet/com90io.c b/drivers/net/arcnet/com90io.c
index 52c77cb..1f03027 100644
--- a/drivers/net/arcnet/com90io.c
+++ b/drivers/net/arcnet/com90io.c
@@ -160,7 +160,7 @@ static int __init com90io_probe(struct net_device *dev)
return -ENODEV;
}
if (!request_region(ioaddr, ARCNET_TOTAL_SIZE, "com90io probe")) {
- BUGMSG(D_INIT_REASONS, "IO check_region %x-%x failed.\n",
+ BUGMSG(D_INIT_REASONS, "IO request_region %x-%x failed.\n",
ioaddr, ioaddr + ARCNET_TOTAL_SIZE - 1);
return -ENXIO;
}
@@ -242,7 +242,7 @@ static int __init com90io_found(struct net_device *dev)
BUGMSG(D_NORMAL, "Can't get IRQ %d!\n", dev->irq);
return -ENODEV;
}
- /* Reserve the I/O region - guaranteed to work by check_region */
+ /* Reserve the I/O region */
if (!request_region(dev->base_addr, ARCNET_TOTAL_SIZE, "arcnet (COM90xx-IO)")) {
free_irq(dev->irq, dev);
return -EBUSY;
diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c
index d1fb1ba..bedd7f9f 100644
--- a/drivers/net/wireless/orinoco_cs.c
+++ b/drivers/net/wireless/orinoco_cs.c
@@ -629,6 +629,7 @@ static struct pcmcia_device_id orinoco_cs_ids[] = {
PCMCIA_DEVICE_PROD_ID12("Cabletron", "RoamAbout 802.11 DS", 0x32d445f5, 0xedeffd90),
PCMCIA_DEVICE_PROD_ID12("corega K.K.", "Wireless LAN PCC-11", 0x5261440f, 0xa6405584),
PCMCIA_DEVICE_PROD_ID12("corega K.K.", "Wireless LAN PCCA-11", 0x5261440f, 0xdf6115f9),
+ PCMCIA_DEVICE_PROD_ID12("corega_K.K.", "Wireless_LAN_PCCB-11", 0x29e33311, 0xee7a27ae),
PCMCIA_DEVICE_PROD_ID12("D", "Link DRC-650 11Mbps WLAN Card", 0x71b18589, 0xf144e3ac),
PCMCIA_DEVICE_PROD_ID12("D", "Link DWL-650 11Mbps WLAN Card", 0x71b18589, 0xb6f1b0ab),
PCMCIA_DEVICE_PROD_ID12("ELSA", "AirLancer MC-11", 0x4507a33a, 0xef54f0e3),
diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c
index 39ba640..80969f7 100644
--- a/drivers/pcmcia/pcmcia_ioctl.c
+++ b/drivers/pcmcia/pcmcia_ioctl.c
@@ -376,6 +376,7 @@ static int ds_open(struct inode *inode, struct file *file)
socket_t i = iminor(inode);
struct pcmcia_socket *s;
user_info_t *user;
+ static int warning_printed = 0;
ds_dbg(0, "ds_open(socket %d)\n", i);
@@ -407,6 +408,17 @@ static int ds_open(struct inode *inode, struct file *file)
s->user = user;
file->private_data = user;
+ if (!warning_printed) {
+ printk(KERN_INFO "pcmcia: Detected deprecated PCMCIA ioctl "
+ "usage.\n");
+ printk(KERN_INFO "pcmcia: This interface will soon be removed from "
+ "the kernel; please expect breakage unless you upgrade "
+ "to new tools.\n");
+ printk(KERN_INFO "pcmcia: see http://www.kernel.org/pub/linux/"
+ "utils/kernel/pcmcia/pcmcia.html for details.\n");
+ warning_printed = 1;
+ }
+
if (s->pcmcia_state.present)
queue_event(user, CS_EVENT_CARD_INSERTION);
return 0;
diff --git a/drivers/sbus/char/display7seg.c b/drivers/sbus/char/display7seg.c
index dbad7f3..24ed589 100644
--- a/drivers/sbus/char/display7seg.c
+++ b/drivers/sbus/char/display7seg.c
@@ -14,7 +14,7 @@
#include <linux/major.h>
#include <linux/init.h>
#include <linux/miscdevice.h>
-#include <linux/ioport.h> /* request_region, check_region */
+#include <linux/ioport.h> /* request_region */
#include <asm/atomic.h>
#include <asm/ebus.h> /* EBus device */
#include <asm/oplib.h> /* OpenProm Library */
diff --git a/drivers/tc/zs.c b/drivers/tc/zs.c
index 4382ee6..6bed871 100644
--- a/drivers/tc/zs.c
+++ b/drivers/tc/zs.c
@@ -1683,7 +1683,7 @@ static void __init probe_sccs(void)
#ifndef CONFIG_SERIAL_DEC_CONSOLE
/*
* We're called early and memory managment isn't up, yet.
- * Thus check_region would fail.
+ * Thus request_region would fail.
*/
if (!request_region((unsigned long)
zs_channels[n_channels].control,
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 615874e..31ee13e 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -753,7 +753,8 @@ config FB_I810_GTF
config FB_I810_I2C
bool "Enable DDC Support"
- depends on FB_I810 && I2C && FB_I810_GTF
+ depends on FB_I810 && FB_I810_GTF
+ select I2C
select I2C_ALGOBIT
help
diff --git a/drivers/video/backlight/corgi_bl.c b/drivers/video/backlight/corgi_bl.c
index 353cb3f..a328176 100644
--- a/drivers/video/backlight/corgi_bl.c
+++ b/drivers/video/backlight/corgi_bl.c
@@ -43,18 +43,10 @@ static void corgibl_send_intensity(int intensity)
intensity &= CORGI_LIMIT_MASK;
}
- /* Skip 0x20 as it will blank the display */
- if (intensity >= 0x20)
- intensity++;
-
spin_lock_irqsave(&bl_lock, flags);
- /* Bits 0-4 are accessed via the SSP interface */
- corgi_ssp_blduty_set(intensity & 0x1f);
- /* Bit 5 is via SCOOP */
- if (intensity & 0x0020)
- set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_BACKLIGHT_CONT);
- else
- reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_BACKLIGHT_CONT);
+
+ corgibl_mach_set_intensity(intensity);
+
spin_unlock_irqrestore(&bl_lock, flags);
}
@@ -113,8 +105,8 @@ static int corgibl_get_power(struct backlight_device *bd)
static int corgibl_set_intensity(struct backlight_device *bd, int intensity)
{
- if (intensity > CORGI_MAX_INTENSITY)
- intensity = CORGI_MAX_INTENSITY;
+ if (intensity > corgibl_data.max_brightness)
+ intensity = corgibl_data.max_brightness;
corgibl_send_intensity(intensity);
current_intensity=intensity;
return 0;
@@ -141,7 +133,6 @@ static struct backlight_properties corgibl_data = {
.owner = THIS_MODULE,
.get_power = corgibl_get_power,
.set_power = corgibl_set_power,
- .max_brightness = CORGI_MAX_INTENSITY,
.get_brightness = corgibl_get_intensity,
.set_brightness = corgibl_set_intensity,
};
@@ -150,12 +141,18 @@ static struct backlight_device *corgi_backlight_device;
static int __init corgibl_probe(struct device *dev)
{
+ struct corgibl_machinfo *machinfo = dev->platform_data;
+
+ corgibl_data.max_brightness = machinfo->max_intensity;
+ corgibl_mach_set_intensity = machinfo->set_bl_intensity;
+
corgi_backlight_device = backlight_device_register ("corgi-bl",
NULL, &corgibl_data);
if (IS_ERR (corgi_backlight_device))
return PTR_ERR (corgi_backlight_device);
corgibl_set_intensity(NULL, CORGI_DEFAULT_INTENSITY);
+ corgibl_limit_intensity(0);
printk("Corgi Backlight Driver Initialized.\n");
return 0;
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index 2e93224..0fc8bb4 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -767,7 +767,7 @@ static const char *fbcon_startup(void)
const char *display_desc = "frame buffer device";
struct display *p = &fb_display[fg_console];
struct vc_data *vc = vc_cons[fg_console].d;
- struct font_desc *font = NULL;
+ const struct font_desc *font = NULL;
struct module *owner;
struct fb_info *info = NULL;
struct fbcon_ops *ops;
@@ -841,7 +841,7 @@ static const char *fbcon_startup(void)
info->var.yres);
vc->vc_font.width = font->width;
vc->vc_font.height = font->height;
- vc->vc_font.data = p->fontdata = font->data;
+ vc->vc_font.data = (void *)(p->fontdata = font->data);
vc->vc_font.charcount = 256; /* FIXME Need to support more fonts */
}
@@ -941,7 +941,7 @@ static void fbcon_init(struct vc_data *vc, int init)
fb, copy the font from that console */
t = &fb_display[svc->vc_num];
if (!vc->vc_font.data) {
- vc->vc_font.data = p->fontdata = t->fontdata;
+ vc->vc_font.data = (void *)(p->fontdata = t->fontdata);
vc->vc_font.width = (*default_mode)->vc_font.width;
vc->vc_font.height = (*default_mode)->vc_font.height;
p->userfont = t->userfont;
@@ -1188,7 +1188,7 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
return;
t = &fb_display[svc->vc_num];
if (!vc->vc_font.data) {
- vc->vc_font.data = p->fontdata = t->fontdata;
+ vc->vc_font.data = (void *)(p->fontdata = t->fontdata);
vc->vc_font.width = (*default_mode)->vc_font.width;
vc->vc_font.height = (*default_mode)->vc_font.height;
p->userfont = t->userfont;
@@ -1687,6 +1687,8 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir,
case SM_DOWN:
if (count > vc->vc_rows) /* Maximum realistic size */
count = vc->vc_rows;
+ if (logo_shown >= 0)
+ goto redraw_down;
switch (p->scrollmode) {
case SCROLL_MOVE:
ops->bmove(vc, info, t, 0, t + count, 0,
@@ -2148,7 +2150,7 @@ static int fbcon_get_font(struct vc_data *vc, struct console_font *font)
}
static int fbcon_do_set_font(struct vc_data *vc, int w, int h,
- u8 * data, int userfont)
+ const u8 * data, int userfont)
{
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
struct display *p = &fb_display[vc->vc_num];
@@ -2166,7 +2168,7 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h,
cnt = FNTCHARCNT(data);
else
cnt = 256;
- vc->vc_font.data = p->fontdata = data;
+ vc->vc_font.data = (void *)(p->fontdata = data);
if ((p->userfont = userfont))
REFCOUNT(data)++;
vc->vc_font.width = w;
@@ -2323,7 +2325,7 @@ static int fbcon_set_font(struct vc_data *vc, struct console_font *font, unsigne
tmp->vc_font.width == w &&
!memcmp(fb_display[i].fontdata, new_data, size)) {
kfree(new_data - FONT_EXTRA_WORDS * sizeof(int));
- new_data = fb_display[i].fontdata;
+ new_data = (u8 *)fb_display[i].fontdata;
break;
}
}
@@ -2333,7 +2335,7 @@ static int fbcon_set_font(struct vc_data *vc, struct console_font *font, unsigne
static int fbcon_set_def_font(struct vc_data *vc, struct console_font *font, char *name)
{
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
- struct font_desc *f;
+ const struct font_desc *f;
if (!name)
f = get_default_font(info->var.xres, info->var.yres);
diff --git a/drivers/video/console/fbcon.h b/drivers/video/console/fbcon.h
index 08befaf..0738cd6 100644
--- a/drivers/video/console/fbcon.h
+++ b/drivers/video/console/fbcon.h
@@ -30,7 +30,7 @@ struct display {
/* Filled in by the frame buffer device */
u_short inverse; /* != 0 text black on white as default */
/* Filled in by the low-level console driver */
- u_char *fontdata;
+ const u_char *fontdata;
int userfont; /* != 0 if fontdata kmalloc()ed */
u_short scrollmode; /* Scroll Method */
short yscroll; /* Hardware scrolling */
diff --git a/drivers/video/console/font_10x18.c b/drivers/video/console/font_10x18.c
index ff0af96..e6aa0ea 100644
--- a/drivers/video/console/font_10x18.c
+++ b/drivers/video/console/font_10x18.c
@@ -7,7 +7,7 @@
#define FONTDATAMAX 9216
-static unsigned char fontdata_10x18[FONTDATAMAX] = {
+static const unsigned char fontdata_10x18[FONTDATAMAX] = {
/* 0 0x00 '^@' */
0x00, 0x00, /* 0000000000 */
@@ -5132,7 +5132,7 @@ static unsigned char fontdata_10x18[FONTDATAMAX] = {
};
-struct font_desc font_10x18 = {
+const struct font_desc font_10x18 = {
FONT10x18_IDX,
"10x18",
10,
diff --git a/drivers/video/console/font_6x11.c b/drivers/video/console/font_6x11.c
index c52f129..89976cd 100644
--- a/drivers/video/console/font_6x11.c
+++ b/drivers/video/console/font_6x11.c
@@ -8,7 +8,7 @@
#define FONTDATAMAX (11*256)
-static unsigned char fontdata_6x11[FONTDATAMAX] = {
+static const unsigned char fontdata_6x11[FONTDATAMAX] = {
/* 0 0x00 '^@' */
0x00, /* 00000000 */
@@ -3341,7 +3341,7 @@ static unsigned char fontdata_6x11[FONTDATAMAX] = {
};
-struct font_desc font_vga_6x11 = {
+const struct font_desc font_vga_6x11 = {
VGA6x11_IDX,
"ProFont6x11",
6,
diff --git a/drivers/video/console/font_7x14.c b/drivers/video/console/font_7x14.c
index 1fa7fcf..bbf1166 100644
--- a/drivers/video/console/font_7x14.c
+++ b/drivers/video/console/font_7x14.c
@@ -7,7 +7,7 @@
#define FONTDATAMAX 3584
-static unsigned char fontdata_7x14[FONTDATAMAX] = {
+static const unsigned char fontdata_7x14[FONTDATAMAX] = {
/* 0 0x00 '^@' */
0x00, /* 0000000 */
@@ -4108,7 +4108,7 @@ static unsigned char fontdata_7x14[FONTDATAMAX] = {
};
-struct font_desc font_7x14 = {
+const struct font_desc font_7x14 = {
FONT7x14_IDX,
"7x14",
7,
diff --git a/drivers/video/console/font_8x16.c b/drivers/video/console/font_8x16.c
index e6f8dba..74fe86f 100644
--- a/drivers/video/console/font_8x16.c
+++ b/drivers/video/console/font_8x16.c
@@ -8,7 +8,7 @@
#define FONTDATAMAX 4096
-static unsigned char fontdata_8x16[FONTDATAMAX] = {
+static const unsigned char fontdata_8x16[FONTDATAMAX] = {
/* 0 0x00 '^@' */
0x00, /* 00000000 */
@@ -4621,7 +4621,7 @@ static unsigned char fontdata_8x16[FONTDATAMAX] = {
};
-struct font_desc font_vga_8x16 = {
+const struct font_desc font_vga_8x16 = {
VGA8x16_IDX,
"VGA8x16",
8,
diff --git a/drivers/video/console/font_8x8.c b/drivers/video/console/font_8x8.c
index 57fbe26..26199f8 100644
--- a/drivers/video/console/font_8x8.c
+++ b/drivers/video/console/font_8x8.c
@@ -8,7 +8,7 @@
#define FONTDATAMAX 2048
-static unsigned char fontdata_8x8[FONTDATAMAX] = {
+static const unsigned char fontdata_8x8[FONTDATAMAX] = {
/* 0 0x00 '^@' */
0x00, /* 00000000 */
@@ -2573,7 +2573,7 @@ static unsigned char fontdata_8x8[FONTDATAMAX] = {
};
-struct font_desc font_vga_8x8 = {
+const struct font_desc font_vga_8x8 = {
VGA8x8_IDX,
"VGA8x8",
8,
diff --git a/drivers/video/console/font_acorn_8x8.c b/drivers/video/console/font_acorn_8x8.c
index d565505..2d2e396 100644
--- a/drivers/video/console/font_acorn_8x8.c
+++ b/drivers/video/console/font_acorn_8x8.c
@@ -3,7 +3,7 @@
#include <linux/config.h>
#include <linux/font.h>
-static unsigned char acorndata_8x8[] = {
+static const unsigned char acorndata_8x8[] = {
/* 00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ^@ */
/* 01 */ 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e, /* ^A */
/* 02 */ 0x7e, 0xff, 0xbd, 0xff, 0xc3, 0xe7, 0xff, 0x7e, /* ^B */
@@ -262,7 +262,7 @@ static unsigned char acorndata_8x8[] = {
/* FF */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
-struct font_desc font_acorn_8x8 = {
+const struct font_desc font_acorn_8x8 = {
ACORN8x8_IDX,
"Acorn8x8",
8,
diff --git a/drivers/video/console/font_mini_4x6.c b/drivers/video/console/font_mini_4x6.c
index 593b955..d818234 100644
--- a/drivers/video/console/font_mini_4x6.c
+++ b/drivers/video/console/font_mini_4x6.c
@@ -43,7 +43,7 @@ __END__;
#define FONTDATAMAX 1536
-static unsigned char fontdata_mini_4x6[FONTDATAMAX] = {
+static const unsigned char fontdata_mini_4x6[FONTDATAMAX] = {
/*{*/
/* Char 0: ' ' */
@@ -2147,7 +2147,7 @@ static unsigned char fontdata_mini_4x6[FONTDATAMAX] = {
/*}*/
};
-struct font_desc font_mini_4x6 = {
+const struct font_desc font_mini_4x6 = {
MINI4x6_IDX,
"MINI4x6",
4,
diff --git a/drivers/video/console/font_pearl_8x8.c b/drivers/video/console/font_pearl_8x8.c
index 5fa95f1..e646c88 100644
--- a/drivers/video/console/font_pearl_8x8.c
+++ b/drivers/video/console/font_pearl_8x8.c
@@ -13,7 +13,7 @@
#define FONTDATAMAX 2048
-static unsigned char fontdata_pearl8x8[FONTDATAMAX] = {
+static const unsigned char fontdata_pearl8x8[FONTDATAMAX] = {
/* 0 0x00 '^@' */
0x00, /* 00000000 */
@@ -2577,7 +2577,7 @@ static unsigned char fontdata_pearl8x8[FONTDATAMAX] = {
};
-struct font_desc font_pearl_8x8 = {
+const struct font_desc font_pearl_8x8 = {
PEARL8x8_IDX,
"PEARL8x8",
8,
diff --git a/drivers/video/console/font_sun12x22.c b/drivers/video/console/font_sun12x22.c
index c7bd967..ab5eb93 100644
--- a/drivers/video/console/font_sun12x22.c
+++ b/drivers/video/console/font_sun12x22.c
@@ -2,7 +2,7 @@
#define FONTDATAMAX 11264
-static unsigned char fontdata_sun12x22[FONTDATAMAX] = {
+static const unsigned char fontdata_sun12x22[FONTDATAMAX] = {
/* 0 0x00 '^@' */
0x00, 0x00, /* 000000000000 */
@@ -6151,7 +6151,7 @@ static unsigned char fontdata_sun12x22[FONTDATAMAX] = {
};
-struct font_desc font_sun_12x22 = {
+const struct font_desc font_sun_12x22 = {
SUN12x22_IDX,
"SUN12x22",
12,
diff --git a/drivers/video/console/font_sun8x16.c b/drivers/video/console/font_sun8x16.c
index 2af3ab3..41f910f 100644
--- a/drivers/video/console/font_sun8x16.c
+++ b/drivers/video/console/font_sun8x16.c
@@ -2,7 +2,7 @@
#define FONTDATAMAX 4096
-static unsigned char fontdata_sun8x16[FONTDATAMAX] = {
+static const unsigned char fontdata_sun8x16[FONTDATAMAX] = {
/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
/* */ 0x00,0x00,0x7e,0x81,0xa5,0x81,0x81,0xbd,0x99,0x81,0x81,0x7e,0x00,0x00,0x00,0x00,
/* */ 0x00,0x00,0x7e,0xff,0xdb,0xff,0xff,0xc3,0xe7,0xff,0xff,0x7e,0x00,0x00,0x00,0x00,
@@ -261,7 +261,7 @@ static unsigned char fontdata_sun8x16[FONTDATAMAX] = {
/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};
-struct font_desc font_sun_8x16 = {
+const struct font_desc font_sun_8x16 = {
SUN8x16_IDX,
"SUN8x16",
8,
diff --git a/drivers/video/console/fonts.c b/drivers/video/console/fonts.c
index e79b297..4fd07d9 100644
--- a/drivers/video/console/fonts.c
+++ b/drivers/video/console/fonts.c
@@ -23,7 +23,7 @@
#define NO_FONTS
-static struct font_desc *fonts[] = {
+static const struct font_desc *fonts[] = {
#ifdef CONFIG_FONT_8x8
#undef NO_FONTS
&font_vga_8x8,
@@ -84,7 +84,7 @@ static struct font_desc *fonts[] = {
*
*/
-struct font_desc *find_font(char *name)
+const struct font_desc *find_font(const char *name)
{
unsigned int i;
@@ -108,10 +108,10 @@ struct font_desc *find_font(char *name)
*
*/
-struct font_desc *get_default_font(int xres, int yres)
+const struct font_desc *get_default_font(int xres, int yres)
{
int i, c, cc;
- struct font_desc *f, *g;
+ const struct font_desc *f, *g;
g = NULL;
cc = -10000;
@@ -138,7 +138,6 @@ struct font_desc *get_default_font(int xres, int yres)
return g;
}
-EXPORT_SYMBOL(fonts);
EXPORT_SYMBOL(find_font);
EXPORT_SYMBOL(get_default_font);
diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c
index 98e00d8..e02da41 100644
--- a/drivers/video/matrox/matroxfb_base.c
+++ b/drivers/video/matrox/matroxfb_base.c
@@ -1285,7 +1285,7 @@ static int matroxfb_getmemory(WPMINFO unsigned int maxSize, unsigned int *realSi
vaddr_t vm;
unsigned int offs;
unsigned int offs2;
- unsigned char store;
+ unsigned char store, orig;
unsigned char bytes[32];
unsigned char* tmp;
@@ -1298,7 +1298,8 @@ static int matroxfb_getmemory(WPMINFO unsigned int maxSize, unsigned int *realSi
if (maxSize > 0x2000000) maxSize = 0x2000000;
mga_outb(M_EXTVGA_INDEX, 0x03);
- mga_outb(M_EXTVGA_DATA, mga_inb(M_EXTVGA_DATA) | 0x80);
+ orig = mga_inb(M_EXTVGA_DATA);
+ mga_outb(M_EXTVGA_DATA, orig | 0x80);
store = mga_readb(vm, 0x1234);
tmp = bytes;
@@ -1323,7 +1324,7 @@ static int matroxfb_getmemory(WPMINFO unsigned int maxSize, unsigned int *realSi
mga_writeb(vm, 0x1234, store);
mga_outb(M_EXTVGA_INDEX, 0x03);
- mga_outb(M_EXTVGA_DATA, mga_inb(M_EXTVGA_DATA) & ~0x80);
+ mga_outb(M_EXTVGA_DATA, orig);
*realSize = offs - 0x100000;
#ifdef CONFIG_FB_MATROX_MILLENIUM
@@ -1858,6 +1859,8 @@ static int initMatrox2(WPMINFO struct board* b){
to yres_virtual * xres_virtual < 2^32 */
}
matroxfb_init_fix(PMINFO2);
+ ACCESS_FBINFO(fbcon.screen_base) = vaddr_va(ACCESS_FBINFO(video.vbase));
+ matroxfb_update_fix(PMINFO2);
/* Normalize values (namely yres_virtual) */
matroxfb_check_var(&vesafb_defined, &ACCESS_FBINFO(fbcon));
/* And put it into "current" var. Do NOT program hardware yet, or we'll not take over
@@ -2010,11 +2013,11 @@ static int matroxfb_probe(struct pci_dev* pdev, const struct pci_device_id* dumm
}
/* not match... */
if (!b->vendor)
- return -1;
+ return -ENODEV;
if (dev > 0) {
/* not requested one... */
dev--;
- return -1;
+ return -ENODEV;
}
pci_read_config_dword(pdev, PCI_COMMAND, &cmd);
if (pci_enable_device(pdev)) {
diff --git a/drivers/video/pm3fb.c b/drivers/video/pm3fb.c
index e0dad94..2e11b60 100644
--- a/drivers/video/pm3fb.c
+++ b/drivers/video/pm3fb.c
@@ -67,6 +67,7 @@
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/ioport.h>
+#include <linux/ctype.h>
#include <video/fbcon.h>
#include <video/fbcon-mfb.h>
@@ -2594,7 +2595,7 @@ static char *pm3fb_boardnum_setup(char *options, unsigned long *bn)
{
char *next;
- if (!(CHAR_IS_NUM(options[0]))) {
+ if (!(isdigit(options[0]))) {
(*bn) = 0;
return (options);
}
OpenPOWER on IntegriCloud