diff options
Diffstat (limited to 'drivers')
133 files changed, 4290 insertions, 1258 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/paride/pf.c b/drivers/block/paride/pf.c index 711d2f3..94af920 100644 --- a/drivers/block/paride/pf.c +++ b/drivers/block/paride/pf.c @@ -750,6 +750,14 @@ static int pf_ready(void) static struct request_queue *pf_queue; +static void pf_end_request(int uptodate) +{ + if (pf_req) { + end_request(pf_req, uptodate); + pf_req = NULL; + } +} + static void do_pf_request(request_queue_t * q) { if (pf_busy) @@ -765,7 +773,7 @@ repeat: pf_count = pf_req->current_nr_sectors; if (pf_block + pf_count > get_capacity(pf_req->rq_disk)) { - end_request(pf_req, 0); + pf_end_request(0); goto repeat; } @@ -780,7 +788,7 @@ repeat: pi_do_claimed(pf_current->pi, do_pf_write); else { pf_busy = 0; - end_request(pf_req, 0); + pf_end_request(0); goto repeat; } } @@ -798,9 +806,11 @@ static int pf_next_buf(void) if (!pf_count) return 1; spin_lock_irqsave(&pf_spin_lock, saved_flags); - end_request(pf_req, 1); - pf_count = pf_req->current_nr_sectors; - pf_buf = pf_req->buffer; + pf_end_request(1); + if (pf_req) { + pf_count = pf_req->current_nr_sectors; + pf_buf = pf_req->buffer; + } spin_unlock_irqrestore(&pf_spin_lock, saved_flags); return 1; } @@ -810,7 +820,7 @@ static inline void next_request(int success) unsigned long saved_flags; spin_lock_irqsave(&pf_spin_lock, saved_flags); - end_request(pf_req, success); + pf_end_request(success); pf_busy = 0; do_pf_request(pf_queue); spin_unlock_irqrestore(&pf_spin_lock, saved_flags); 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/block/scsi_ioctl.c b/drivers/block/scsi_ioctl.c index 856c227..079ec34 100644 --- a/drivers/block/scsi_ioctl.c +++ b/drivers/block/scsi_ioctl.c @@ -168,6 +168,7 @@ static int verify_command(struct file *file, unsigned char *cmd) safe_for_write(WRITE_VERIFY_12), safe_for_write(WRITE_16), safe_for_write(WRITE_LONG), + safe_for_write(WRITE_LONG_2), safe_for_write(ERASE), safe_for_write(GPCMD_MODE_SELECT_10), safe_for_write(MODE_SELECT), diff --git a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c index 67d96b5..57c48bb 100644 --- a/drivers/bluetooth/hci_usb.c +++ b/drivers/bluetooth/hci_usb.c @@ -65,13 +65,15 @@ #endif static int ignore = 0; +static int ignore_csr = 0; +static int ignore_sniffer = 0; static int reset = 0; #ifdef CONFIG_BT_HCIUSB_SCO static int isoc = 2; #endif -#define VERSION "2.8" +#define VERSION "2.9" static struct usb_driver hci_usb_driver; @@ -98,6 +100,9 @@ static struct usb_device_id bluetooth_ids[] = { MODULE_DEVICE_TABLE (usb, bluetooth_ids); static struct usb_device_id blacklist_ids[] = { + /* CSR BlueCore devices */ + { USB_DEVICE(0x0a12, 0x0001), .driver_info = HCI_CSR }, + /* Broadcom BCM2033 without firmware */ { USB_DEVICE(0x0a5c, 0x2033), .driver_info = HCI_IGNORE }, @@ -836,6 +841,12 @@ static int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id if (ignore || id->driver_info & HCI_IGNORE) return -ENODEV; + if (ignore_csr && id->driver_info & HCI_CSR) + return -ENODEV; + + if (ignore_sniffer && id->driver_info & HCI_SNIFFER) + return -ENODEV; + if (intf->cur_altsetting->desc.bInterfaceNumber > 0) return -ENODEV; @@ -1061,6 +1072,12 @@ module_exit(hci_usb_exit); module_param(ignore, bool, 0644); MODULE_PARM_DESC(ignore, "Ignore devices from the matching table"); +module_param(ignore_csr, bool, 0644); +MODULE_PARM_DESC(ignore_csr, "Ignore devices with id 0a12:0001"); + +module_param(ignore_sniffer, bool, 0644); +MODULE_PARM_DESC(ignore_sniffer, "Ignore devices with id 0a12:0002"); + module_param(reset, bool, 0644); MODULE_PARM_DESC(reset, "Send HCI reset command on initialization"); diff --git a/drivers/bluetooth/hci_usb.h b/drivers/bluetooth/hci_usb.h index 29936b4..37100a6 100644 --- a/drivers/bluetooth/hci_usb.h +++ b/drivers/bluetooth/hci_usb.h @@ -31,9 +31,10 @@ #define HCI_IGNORE 0x01 #define HCI_RESET 0x02 #define HCI_DIGIANSWER 0x04 -#define HCI_SNIFFER 0x08 -#define HCI_BROKEN_ISOC 0x10 +#define HCI_CSR 0x08 +#define HCI_SNIFFER 0x10 #define HCI_BCM92035 0x20 +#define HCI_BROKEN_ISOC 0x40 #define HCI_MAX_IFACE_NUM 3 diff --git a/drivers/char/agp/hp-agp.c b/drivers/char/agp/hp-agp.c index 99762b6..de5d6d2 100644 --- a/drivers/char/agp/hp-agp.c +++ b/drivers/char/agp/hp-agp.c @@ -252,7 +252,7 @@ hp_zx1_configure (void) readl(hp->ioc_regs+HP_ZX1_PDIR_BASE); writel(hp->io_tlb_ps, hp->ioc_regs+HP_ZX1_TCNFG); readl(hp->ioc_regs+HP_ZX1_TCNFG); - writel(~(HP_ZX1_IOVA_SIZE-1), hp->ioc_regs+HP_ZX1_IMASK); + writel((unsigned int)(~(HP_ZX1_IOVA_SIZE-1)), hp->ioc_regs+HP_ZX1_IMASK); readl(hp->ioc_regs+HP_ZX1_IMASK); writel(hp->iova_base|1, hp->ioc_regs+HP_ZX1_IBASE); readl(hp->ioc_regs+HP_ZX1_IBASE); 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/epca.c b/drivers/char/epca.c index 58d3738..407708a 100644 --- a/drivers/char/epca.c +++ b/drivers/char/epca.c @@ -534,7 +534,7 @@ static void shutdown(struct channel *ch) unsigned long flags; struct tty_struct *tty; - struct board_chan *bc; + struct board_chan __iomem *bc; if (!(ch->asyncflags & ASYNC_INITIALIZED)) return; @@ -618,7 +618,7 @@ static int pc_write(struct tty_struct * tty, struct channel *ch; unsigned long flags; int remain; - struct board_chan *bc; + struct board_chan __iomem *bc; /* ---------------------------------------------------------------- pc_write is primarily called directly by the kernel routine @@ -685,7 +685,7 @@ static int pc_write(struct tty_struct * tty, ------------------------------------------------------------------- */ dataLen = min(bytesAvailable, dataLen); - memcpy(ch->txptr + head, buf, dataLen); + memcpy_toio(ch->txptr + head, buf, dataLen); buf += dataLen; head += dataLen; amountCopied += dataLen; @@ -726,7 +726,7 @@ static int pc_write_room(struct tty_struct *tty) struct channel *ch; unsigned long flags; unsigned int head, tail; - struct board_chan *bc; + struct board_chan __iomem *bc; remain = 0; @@ -773,7 +773,7 @@ static int pc_chars_in_buffer(struct tty_struct *tty) int remain; unsigned long flags; struct channel *ch; - struct board_chan *bc; + struct board_chan __iomem *bc; /* --------------------------------------------------------- verifyChannel returns the channel from the tty struct @@ -830,7 +830,7 @@ static void pc_flush_buffer(struct tty_struct *tty) unsigned int tail; unsigned long flags; struct channel *ch; - struct board_chan *bc; + struct board_chan __iomem *bc; /* --------------------------------------------------------- verifyChannel returns the channel from the tty struct if it is valid. This serves as a sanity check. @@ -976,7 +976,7 @@ static int pc_open(struct tty_struct *tty, struct file * filp) struct channel *ch; unsigned long flags; int line, retval, boardnum; - struct board_chan *bc; + struct board_chan __iomem *bc; unsigned int head; line = tty->index; @@ -1041,7 +1041,7 @@ static int pc_open(struct tty_struct *tty, struct file * filp) ch->statusflags = 0; /* Save boards current modem status */ - ch->imodem = bc->mstat; + ch->imodem = readb(&bc->mstat); /* ---------------------------------------------------------------- Set receive head and tail ptrs to each other. This indicates @@ -1399,10 +1399,10 @@ static void post_fep_init(unsigned int crd) { /* Begin post_fep_init */ int i; - unsigned char *memaddr; - struct global_data *gd; + void __iomem *memaddr; + struct global_data __iomem *gd; struct board_info *bd; - struct board_chan *bc; + struct board_chan __iomem *bc; struct channel *ch; int shrinkmem = 0, lowwater ; @@ -1461,7 +1461,7 @@ static void post_fep_init(unsigned int crd) 8 and 64 of these structures. -------------------------------------------------------------------- */ - bc = (struct board_chan *)(memaddr + CHANSTRUCT); + bc = memaddr + CHANSTRUCT; /* ------------------------------------------------------------------- The below assignment will set gd to point at the BEGINING of @@ -1470,7 +1470,7 @@ static void post_fep_init(unsigned int crd) pointer begins at 0xd10. ---------------------------------------------------------------------- */ - gd = (struct global_data *)(memaddr + GLOBAL); + gd = memaddr + GLOBAL; /* -------------------------------------------------------------------- XEPORTS (address 0xc22) points at the number of channels the @@ -1493,6 +1493,7 @@ static void post_fep_init(unsigned int crd) for (i = 0; i < bd->numports; i++, ch++, bc++) { /* Begin for each port */ unsigned long flags; + u16 tseg, rseg; ch->brdchan = bc; ch->mailbox = gd; @@ -1553,50 +1554,53 @@ static void post_fep_init(unsigned int crd) shrinkmem = 0; } + tseg = readw(&bc->tseg); + rseg = readw(&bc->rseg); + switch (bd->type) { case PCIXEM: case PCIXRJ: case PCIXR: /* Cover all the 2MEG cards */ - ch->txptr = memaddr + (((bc->tseg) << 4) & 0x1fffff); - ch->rxptr = memaddr + (((bc->rseg) << 4) & 0x1fffff); - ch->txwin = FEPWIN | ((bc->tseg) >> 11); - ch->rxwin = FEPWIN | ((bc->rseg) >> 11); + ch->txptr = memaddr + ((tseg << 4) & 0x1fffff); + ch->rxptr = memaddr + ((rseg << 4) & 0x1fffff); + ch->txwin = FEPWIN | (tseg >> 11); + ch->rxwin = FEPWIN | (rseg >> 11); break; case PCXEM: case EISAXEM: /* Cover all the 32K windowed cards */ /* Mask equal to window size - 1 */ - ch->txptr = memaddr + (((bc->tseg) << 4) & 0x7fff); - ch->rxptr = memaddr + (((bc->rseg) << 4) & 0x7fff); - ch->txwin = FEPWIN | ((bc->tseg) >> 11); - ch->rxwin = FEPWIN | ((bc->rseg) >> 11); + ch->txptr = memaddr + ((tseg << 4) & 0x7fff); + ch->rxptr = memaddr + ((rseg << 4) & 0x7fff); + ch->txwin = FEPWIN | (tseg >> 11); + ch->rxwin = FEPWIN | (rseg >> 11); break; case PCXEVE: case PCXE: - ch->txptr = memaddr + (((bc->tseg - bd->memory_seg) << 4) & 0x1fff); - ch->txwin = FEPWIN | ((bc->tseg - bd->memory_seg) >> 9); - ch->rxptr = memaddr + (((bc->rseg - bd->memory_seg) << 4) & 0x1fff); - ch->rxwin = FEPWIN | ((bc->rseg - bd->memory_seg) >>9 ); + ch->txptr = memaddr + (((tseg - bd->memory_seg) << 4) & 0x1fff); + ch->txwin = FEPWIN | ((tseg - bd->memory_seg) >> 9); + ch->rxptr = memaddr + (((rseg - bd->memory_seg) << 4) & 0x1fff); + ch->rxwin = FEPWIN | ((rseg - bd->memory_seg) >>9 ); break; case PCXI: case PC64XE: - ch->txptr = memaddr + ((bc->tseg - bd->memory_seg) << 4); - ch->rxptr = memaddr + ((bc->rseg - bd->memory_seg) << 4); + ch->txptr = memaddr + ((tseg - bd->memory_seg) << 4); + ch->rxptr = memaddr + ((rseg - bd->memory_seg) << 4); ch->txwin = ch->rxwin = 0; break; } /* End switch bd->type */ ch->txbufhead = 0; - ch->txbufsize = bc->tmax + 1; + ch->txbufsize = readw(&bc->tmax) + 1; ch->rxbufhead = 0; - ch->rxbufsize = bc->rmax + 1; + ch->rxbufsize = readw(&bc->rmax) + 1; lowwater = ch->txbufsize >= 2000 ? 1024 : (ch->txbufsize / 2); @@ -1718,11 +1722,11 @@ static void epcapoll(unsigned long ignored) static void doevent(int crd) { /* Begin doevent */ - void *eventbuf; + void __iomem *eventbuf; struct channel *ch, *chan0; static struct tty_struct *tty; struct board_info *bd; - struct board_chan *bc; + struct board_chan __iomem *bc; unsigned int tail, head; int event, channel; int mstat, lstat; @@ -1817,7 +1821,7 @@ static void doevent(int crd) static void fepcmd(struct channel *ch, int cmd, int word_or_byte, int byte2, int ncmds, int bytecmd) { /* Begin fepcmd */ - unchar *memaddr; + unchar __iomem *memaddr; unsigned int head, cmdTail, cmdStart, cmdMax; long count; int n; @@ -2000,7 +2004,7 @@ static void epcaparam(struct tty_struct *tty, struct channel *ch) unsigned int cmdHead; struct termios *ts; - struct board_chan *bc; + struct board_chan __iomem *bc; unsigned mval, hflow, cflag, iflag; bc = ch->brdchan; @@ -2010,7 +2014,7 @@ static void epcaparam(struct tty_struct *tty, struct channel *ch) ts = tty->termios; if ((ts->c_cflag & CBAUD) == 0) { /* Begin CBAUD detected */ cmdHead = readw(&bc->rin); - bc->rout = cmdHead; + writew(cmdHead, &bc->rout); cmdHead = readw(&bc->tin); /* Changing baud in mid-stream transmission can be wonderful */ /* --------------------------------------------------------------- @@ -2116,7 +2120,7 @@ static void receive_data(struct channel *ch) unchar *rptr; struct termios *ts = NULL; struct tty_struct *tty; - struct board_chan *bc; + struct board_chan __iomem *bc; int dataToRead, wrapgap, bytesAvailable; unsigned int tail, head; unsigned int wrapmask; @@ -2154,7 +2158,7 @@ static void receive_data(struct channel *ch) --------------------------------------------------------------------- */ if (!tty || !ts || !(ts->c_cflag & CREAD)) { - bc->rout = head; + writew(head, &bc->rout); return; } @@ -2270,7 +2274,7 @@ static int info_ioctl(struct tty_struct *tty, struct file * file, static int pc_tiocmget(struct tty_struct *tty, struct file *file) { struct channel *ch = (struct channel *) tty->driver_data; - struct board_chan *bc; + struct board_chan __iomem *bc; unsigned int mstat, mflag = 0; unsigned long flags; @@ -2351,7 +2355,7 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file, unsigned long flags; unsigned int mflag, mstat; unsigned char startc, stopc; - struct board_chan *bc; + struct board_chan __iomem *bc; struct channel *ch = (struct channel *) tty->driver_data; void __user *argp = (void __user *)arg; @@ -2633,7 +2637,7 @@ static void pc_start(struct tty_struct *tty) spin_lock_irqsave(&epca_lock, flags); /* Just in case output was resumed because of a change in Digi-flow */ if (ch->statusflags & TXSTOPPED) { /* Begin transmit resume requested */ - struct board_chan *bc; + struct board_chan __iomem *bc; globalwinon(ch); bc = ch->brdchan; if (ch->statusflags & LOWWAIT) @@ -2727,7 +2731,7 @@ void digi_send_break(struct channel *ch, int msec) static void setup_empty_event(struct tty_struct *tty, struct channel *ch) { /* Begin setup_empty_event */ - struct board_chan *bc = ch->brdchan; + struct board_chan __iomem *bc = ch->brdchan; globalwinon(ch); ch->statusflags |= EMPTYWAIT; diff --git a/drivers/char/epca.h b/drivers/char/epca.h index 20eeb5a..456d6c8 100644 --- a/drivers/char/epca.h +++ b/drivers/char/epca.h @@ -128,17 +128,17 @@ struct channel unsigned long c_cflag; unsigned long c_lflag; unsigned long c_oflag; - unsigned char *txptr; - unsigned char *rxptr; + unsigned char __iomem *txptr; + unsigned char __iomem *rxptr; unsigned char *tmp_buf; struct board_info *board; - struct board_chan *brdchan; + struct board_chan __iomem *brdchan; struct digi_struct digiext; struct tty_struct *tty; wait_queue_head_t open_wait; wait_queue_head_t close_wait; struct work_struct tqueue; - struct global_data *mailbox; + struct global_data __iomem *mailbox; }; struct board_info @@ -149,8 +149,8 @@ struct board_info unsigned short numports; unsigned long port; unsigned long membase; - unsigned char __iomem *re_map_port; - unsigned char *re_map_membase; + void __iomem *re_map_port; + void __iomem *re_map_membase; unsigned long memory_seg; void ( * memwinon ) (struct board_info *, unsigned int) ; void ( * memwinoff ) (struct board_info *, unsigned int) ; diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index cddb789..f921776 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c @@ -839,9 +839,6 @@ int __init hvc_init(void) hvc_driver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(hvc_driver, &hvc_ops); - if (tty_register_driver(hvc_driver)) - panic("Couldn't register hvc console driver\n"); - /* Always start the kthread because there can be hotplug vty adapters * added later. */ hvc_task = kthread_run(khvcd, NULL, "khvcd"); @@ -851,6 +848,9 @@ int __init hvc_init(void) return -EIO; } + if (tty_register_driver(hvc_driver)) + panic("Couldn't register hvc console driver\n"); + return 0; } module_init(hvc_init); diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 1e33cb0..e91268e 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -810,13 +810,14 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines) * from the top and bottom of cursor position */ old_origin += (vc->vc_y - new_rows/2) * old_row_size; - end = old_origin + new_screen_size; + end = old_origin + (old_row_size * new_rows); } } else /* * Cursor near the top, copy contents from the top of buffer */ - end = (old_rows > new_rows) ? old_origin + new_screen_size : + end = (old_rows > new_rows) ? old_origin + + (old_row_size * new_rows) : vc->vc_scr_end; update_attr(vc); 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/mpcore_wdt.c b/drivers/char/watchdog/mpcore_wdt.c index c694eee..75ca84e 100644 --- a/drivers/char/watchdog/mpcore_wdt.c +++ b/drivers/char/watchdog/mpcore_wdt.c @@ -30,6 +30,8 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/device.h> + +#include <asm/hardware/arm_twd.h> #include <asm/uaccess.h> struct mpcore_wdt { 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/firmware/dell_rbu.c b/drivers/firmware/dell_rbu.c index 3b865f3..b667823 100644 --- a/drivers/firmware/dell_rbu.c +++ b/drivers/firmware/dell_rbu.c @@ -50,7 +50,7 @@ MODULE_AUTHOR("Abhay Salunke <abhay_salunke@dell.com>"); MODULE_DESCRIPTION("Driver for updating BIOS image on DELL systems"); MODULE_LICENSE("GPL"); -MODULE_VERSION("1.0"); +MODULE_VERSION("2.0"); #define BIOS_SCAN_LIMIT 0xffffffff #define MAX_IMAGE_LENGTH 16 @@ -65,10 +65,11 @@ static struct _rbu_data { unsigned long packet_write_count; unsigned long num_packets; unsigned long packetsize; + int entry_created; } rbu_data; -static char image_type[MAX_IMAGE_LENGTH] = "mono"; -module_param_string(image_type, image_type, sizeof(image_type), 0); +static char image_type[MAX_IMAGE_LENGTH + 1] = "mono"; +module_param_string(image_type, image_type, sizeof (image_type), 0); MODULE_PARM_DESC(image_type, "BIOS image type. choose- mono or packet"); struct packet_data { @@ -114,7 +115,7 @@ static int fill_last_packet(void *data, size_t length) if ((rbu_data.packet_write_count + length) > rbu_data.packetsize) { pr_debug("dell_rbu:%s: packet size data " - "overrun\n", __FUNCTION__); + "overrun\n", __FUNCTION__); return -EINVAL; } @@ -146,12 +147,14 @@ static int create_packet(size_t length) pr_debug("create_packet: packetsize not specified\n"); return -EINVAL; } + spin_unlock(&rbu_data.lock); + newpacket = kmalloc(sizeof (struct packet_data), GFP_KERNEL); + spin_lock(&rbu_data.lock); - newpacket = kmalloc(sizeof(struct packet_data), GFP_KERNEL); if (!newpacket) { printk(KERN_WARNING - "dell_rbu:%s: failed to allocate new " - "packet\n", __FUNCTION__); + "dell_rbu:%s: failed to allocate new " + "packet\n", __FUNCTION__); return -ENOMEM; } @@ -160,15 +163,17 @@ static int create_packet(size_t length) * there is no upper limit on memory * address for packetized mechanism */ - newpacket->data = (unsigned char *)__get_free_pages(GFP_KERNEL, - ordernum); + spin_unlock(&rbu_data.lock); + newpacket->data = (unsigned char *) __get_free_pages(GFP_KERNEL, + ordernum); + spin_lock(&rbu_data.lock); pr_debug("create_packet: newpacket %p\n", newpacket->data); if (!newpacket->data) { printk(KERN_WARNING - "dell_rbu:%s: failed to allocate new " - "packet\n", __FUNCTION__); + "dell_rbu:%s: failed to allocate new " + "packet\n", __FUNCTION__); kfree(newpacket); return -ENOMEM; } @@ -204,9 +209,8 @@ static int packetize_data(void *data, size_t length) return rc; } -static int -do_packet_read(char *data, struct list_head *ptemp_list, - int length, int bytes_read, int *list_read_count) +static int do_packet_read(char *data, struct list_head *ptemp_list, + int length, int bytes_read, int *list_read_count) { void *ptemp_buf; struct packet_data *newpacket = NULL; @@ -239,7 +243,7 @@ do_packet_read(char *data, struct list_head *ptemp_list, return bytes_copied; } -static int packet_read_list(char *data, size_t * pread_length) +static int packet_read_list(char *data, size_t *pread_length) { struct list_head *ptemp_list; int temp_count = 0; @@ -258,8 +262,7 @@ static int packet_read_list(char *data, size_t * pread_length) ptemp_list = (&packet_data_head.list)->next; while (!list_empty(ptemp_list)) { bytes_copied = do_packet_read(pdest, ptemp_list, - remaining_bytes, bytes_read, - &temp_count); + remaining_bytes, bytes_read, &temp_count); remaining_bytes -= bytes_copied; bytes_read += bytes_copied; pdest += bytes_copied; @@ -287,7 +290,7 @@ static void packet_empty_list(void) ptemp_list = (&packet_data_head.list)->next; while (!list_empty(ptemp_list)) { newpacket = - list_entry(ptemp_list, struct packet_data, list); + list_entry(ptemp_list, struct packet_data, list); pnext_list = ptemp_list->next; list_del(ptemp_list); ptemp_list = pnext_list; @@ -296,8 +299,8 @@ static void packet_empty_list(void) * to make sure there are no stale RBU packets left in memory */ memset(newpacket->data, 0, rbu_data.packetsize); - free_pages((unsigned long)newpacket->data, - newpacket->ordernum); + free_pages((unsigned long) newpacket->data, + newpacket->ordernum); kfree(newpacket); } rbu_data.packet_write_count = 0; @@ -319,14 +322,13 @@ static void img_update_free(void) * BIOS image copied in memory. */ memset(rbu_data.image_update_buffer, 0, - rbu_data.image_update_buffer_size); + rbu_data.image_update_buffer_size); if (rbu_data.dma_alloc == 1) dma_free_coherent(NULL, rbu_data.bios_image_size, - rbu_data.image_update_buffer, - dell_rbu_dmaaddr); + rbu_data.image_update_buffer, dell_rbu_dmaaddr); else - free_pages((unsigned long)rbu_data.image_update_buffer, - rbu_data.image_update_ordernum); + free_pages((unsigned long) rbu_data.image_update_buffer, + rbu_data.image_update_ordernum); /* * Re-initialize the rbu_data variables after a free @@ -366,7 +368,7 @@ static int img_update_realloc(unsigned long size) */ if ((size != 0) && (rbu_data.image_update_buffer == NULL)) { printk(KERN_ERR "dell_rbu:%s: corruption " - "check failed\n", __FUNCTION__); + "check failed\n", __FUNCTION__); return -EINVAL; } /* @@ -385,17 +387,16 @@ static int img_update_realloc(unsigned long size) ordernum = get_order(size); image_update_buffer = - (unsigned char *)__get_free_pages(GFP_KERNEL, ordernum); + (unsigned char *) __get_free_pages(GFP_KERNEL, ordernum); img_buf_phys_addr = - (unsigned long)virt_to_phys(image_update_buffer); + (unsigned long) virt_to_phys(image_update_buffer); if (img_buf_phys_addr > BIOS_SCAN_LIMIT) { - free_pages((unsigned long)image_update_buffer, ordernum); + free_pages((unsigned long) image_update_buffer, ordernum); ordernum = -1; image_update_buffer = dma_alloc_coherent(NULL, size, - &dell_rbu_dmaaddr, - GFP_KERNEL); + &dell_rbu_dmaaddr, GFP_KERNEL); dma_alloc = 1; } @@ -405,13 +406,13 @@ static int img_update_realloc(unsigned long size) rbu_data.image_update_buffer = image_update_buffer; rbu_data.image_update_buffer_size = size; rbu_data.bios_image_size = - rbu_data.image_update_buffer_size; + rbu_data.image_update_buffer_size; rbu_data.image_update_ordernum = ordernum; rbu_data.dma_alloc = dma_alloc; rc = 0; } else { pr_debug("Not enough memory for image update:" - "size = %ld\n", size); + "size = %ld\n", size); rc = -ENOMEM; } @@ -438,7 +439,7 @@ static ssize_t read_packet_data(char *buffer, loff_t pos, size_t count) if (pos > imagesize) { retval = 0; printk(KERN_WARNING "dell_rbu:read_packet_data: " - "data underrun\n"); + "data underrun\n"); goto read_rbu_data_exit; } @@ -468,11 +469,11 @@ static ssize_t read_rbu_mono_data(char *buffer, loff_t pos, size_t count) /* check to see if we have something to return */ if ((rbu_data.image_update_buffer == NULL) || - (rbu_data.bios_image_size == 0)) { + (rbu_data.bios_image_size == 0)) { pr_debug("read_rbu_data_mono: image_update_buffer %p ," - "bios_image_size %lu\n", - rbu_data.image_update_buffer, - rbu_data.bios_image_size); + "bios_image_size %lu\n", + rbu_data.image_update_buffer, + rbu_data.bios_image_size); ret_count = -ENOMEM; goto read_rbu_data_exit; } @@ -497,8 +498,8 @@ static ssize_t read_rbu_mono_data(char *buffer, loff_t pos, size_t count) return ret_count; } -static ssize_t -read_rbu_data(struct kobject *kobj, char *buffer, loff_t pos, size_t count) +static ssize_t read_rbu_data(struct kobject *kobj, char *buffer, + loff_t pos, size_t count) { ssize_t ret_count = 0; @@ -515,62 +516,20 @@ read_rbu_data(struct kobject *kobj, char *buffer, loff_t pos, size_t count) return ret_count; } -static ssize_t -read_rbu_image_type(struct kobject *kobj, char *buffer, loff_t pos, - size_t count) -{ - int size = 0; - if (!pos) - size = sprintf(buffer, "%s\n", image_type); - return size; -} - -static ssize_t -write_rbu_image_type(struct kobject *kobj, char *buffer, loff_t pos, - size_t count) -{ - int rc = count; - spin_lock(&rbu_data.lock); - - if (strlen(buffer) < MAX_IMAGE_LENGTH) - sscanf(buffer, "%s", image_type); - else - printk(KERN_WARNING "dell_rbu: image_type is invalid" - "max chars = %d, \n incoming str--%s-- \n", - MAX_IMAGE_LENGTH, buffer); - - /* we must free all previous allocations */ - packet_empty_list(); - img_update_free(); - - spin_unlock(&rbu_data.lock); - return rc; - -} - -static struct bin_attribute rbu_data_attr = { - .attr = {.name = "data",.owner = THIS_MODULE,.mode = 0444}, - .read = read_rbu_data, -}; - -static struct bin_attribute rbu_image_type_attr = { - .attr = {.name = "image_type",.owner = THIS_MODULE,.mode = 0644}, - .read = read_rbu_image_type, - .write = write_rbu_image_type, -}; - static void callbackfn_rbu(const struct firmware *fw, void *context) { int rc = 0; - if (!fw || !fw->size) + if (!fw || !fw->size) { + rbu_data.entry_created = 0; return; + } spin_lock(&rbu_data.lock); if (!strcmp(image_type, "mono")) { if (!img_update_realloc(fw->size)) memcpy(rbu_data.image_update_buffer, - fw->data, fw->size); + fw->data, fw->size); } else if (!strcmp(image_type, "packet")) { if (!rbu_data.packetsize) rbu_data.packetsize = fw->size; @@ -584,14 +543,103 @@ static void callbackfn_rbu(const struct firmware *fw, void *context) spin_unlock(&rbu_data.lock); rc = request_firmware_nowait(THIS_MODULE, FW_ACTION_NOHOTPLUG, - "dell_rbu", &rbu_device->dev, - &context, callbackfn_rbu); + "dell_rbu", &rbu_device->dev, &context, callbackfn_rbu); if (rc) printk(KERN_ERR - "dell_rbu:%s request_firmware_nowait failed" - " %d\n", __FUNCTION__, rc); + "dell_rbu:%s request_firmware_nowait failed" + " %d\n", __FUNCTION__, rc); + else + rbu_data.entry_created = 1; +} + +static ssize_t read_rbu_image_type(struct kobject *kobj, char *buffer, + loff_t pos, size_t count) +{ + int size = 0; + if (!pos) + size = sprintf(buffer, "%s\n", image_type); + return size; +} + +static ssize_t write_rbu_image_type(struct kobject *kobj, char *buffer, + loff_t pos, size_t count) +{ + int rc = count; + int req_firm_rc = 0; + int i; + spin_lock(&rbu_data.lock); + /* + * Find the first newline or space + */ + for (i = 0; i < count; ++i) + if (buffer[i] == '\n' || buffer[i] == ' ') { + buffer[i] = '\0'; + break; + } + if (i == count) + buffer[count] = '\0'; + + if (strstr(buffer, "mono")) + strcpy(image_type, "mono"); + else if (strstr(buffer, "packet")) + strcpy(image_type, "packet"); + else if (strstr(buffer, "init")) { + /* + * If due to the user error the driver gets in a bad + * state where even though it is loaded , the + * /sys/class/firmware/dell_rbu entries are missing. + * to cover this situation the user can recreate entries + * by writing init to image_type. + */ + if (!rbu_data.entry_created) { + spin_unlock(&rbu_data.lock); + req_firm_rc = request_firmware_nowait(THIS_MODULE, + FW_ACTION_NOHOTPLUG, "dell_rbu", + &rbu_device->dev, &context, + callbackfn_rbu); + if (req_firm_rc) { + printk(KERN_ERR + "dell_rbu:%s request_firmware_nowait" + " failed %d\n", __FUNCTION__, rc); + rc = -EIO; + } else + rbu_data.entry_created = 1; + + spin_lock(&rbu_data.lock); + } + } else { + printk(KERN_WARNING "dell_rbu: image_type is invalid\n"); + spin_unlock(&rbu_data.lock); + return -EINVAL; + } + + /* we must free all previous allocations */ + packet_empty_list(); + img_update_free(); + spin_unlock(&rbu_data.lock); + + return rc; } +static struct bin_attribute rbu_data_attr = { + .attr = { + .name = "data", + .owner = THIS_MODULE, + .mode = 0444, + }, + .read = read_rbu_data, +}; + +static struct bin_attribute rbu_image_type_attr = { + .attr = { + .name = "image_type", + .owner = THIS_MODULE, + .mode = 0644, + }, + .read = read_rbu_image_type, + .write = write_rbu_image_type, +}; + static int __init dcdrbu_init(void) { int rc = 0; @@ -599,11 +647,11 @@ static int __init dcdrbu_init(void) init_packet_head(); rbu_device = - platform_device_register_simple("dell_rbu", -1, NULL, 0); + platform_device_register_simple("dell_rbu", -1, NULL, 0); if (!rbu_device) { printk(KERN_ERR - "dell_rbu:%s:platform_device_register_simple " - "failed\n", __FUNCTION__); + "dell_rbu:%s:platform_device_register_simple " + "failed\n", __FUNCTION__); return -EIO; } @@ -611,11 +659,12 @@ static int __init dcdrbu_init(void) sysfs_create_bin_file(&rbu_device->dev.kobj, &rbu_image_type_attr); rc = request_firmware_nowait(THIS_MODULE, FW_ACTION_NOHOTPLUG, - "dell_rbu", &rbu_device->dev, - &context, callbackfn_rbu); + "dell_rbu", &rbu_device->dev, &context, callbackfn_rbu); if (rc) printk(KERN_ERR "dell_rbu:%s:request_firmware_nowait" - " failed %d\n", __FUNCTION__, rc); + " failed %d\n", __FUNCTION__, rc); + else + rbu_data.entry_created = 1; return rc; diff --git a/drivers/hwmon/hdaps.c b/drivers/hwmon/hdaps.c index eaebfc1..4c56411 100644 --- a/drivers/hwmon/hdaps.c +++ b/drivers/hwmon/hdaps.c @@ -5,10 +5,10 @@ * Copyright (C) 2005 Jesper Juhl <jesper.juhl@gmail.com> * * The HardDisk Active Protection System (hdaps) is present in the IBM ThinkPad - * T41, T42, T43, R51, and X40, at least. It provides a basic two-axis - * accelerometer and other data, such as the device's temperature. + * T41, T42, T43, R50, R50p, R51, and X40, at least. It provides a basic + * two-axis accelerometer and other data, such as the device's temperature. * - * Based on the document by Mark A. Smith available at + * This driver is based on the document by Mark A. Smith available at * http://www.almaden.ibm.com/cs/people/marksmith/tpaps.html and a lot of trial * and error. * @@ -36,12 +36,7 @@ #include <asm/io.h> #define HDAPS_LOW_PORT 0x1600 /* first port used by hdaps */ -#define HDAPS_NR_PORTS 0x30 /* 0x1600 - 0x162f */ - -#define STATE_FRESH 0x50 /* accelerometer data is fresh */ - -#define REFRESH_ASYNC 0x00 /* do asynchronous refresh */ -#define REFRESH_SYNC 0x01 /* do synchronous refresh */ +#define HDAPS_NR_PORTS 0x30 /* number of ports: 0x1600 - 0x162f */ #define HDAPS_PORT_STATE 0x1611 /* device state */ #define HDAPS_PORT_YPOS 0x1612 /* y-axis position */ @@ -53,7 +48,7 @@ #define HDAPS_PORT_UNKNOWN 0x161c /* what is this? */ #define HDAPS_PORT_KMACT 0x161d /* keyboard or mouse activity */ -#define HDAPS_READ_MASK 0xff /* some reads have the low 8 bits set */ +#define STATE_FRESH 0x50 /* accelerometer data is fresh */ #define KEYBD_MASK 0x20 /* set if keyboard activity */ #define MOUSE_MASK 0x40 /* set if mouse activity */ @@ -63,12 +58,11 @@ #define INIT_TIMEOUT_MSECS 4000 /* wait up to 4s for device init ... */ #define INIT_WAIT_MSECS 200 /* ... in 200ms increments */ -static struct platform_device *pdev; -static struct input_dev hdaps_idev; +#define HDAPS_POLL_PERIOD (HZ/20) /* poll for input every 1/20s */ +#define HDAPS_INPUT_FUZZ 4 /* input event threshold */ + static struct timer_list hdaps_timer; -static unsigned int hdaps_mousedev_threshold = 4; -static unsigned long hdaps_poll_ms = 50; -static unsigned int hdaps_mousedev; +static struct platform_device *pdev; static unsigned int hdaps_invert; static u8 km_activity; static int rest_x; @@ -81,14 +75,14 @@ static DECLARE_MUTEX(hdaps_sem); */ static inline u8 __get_latch(u16 port) { - return inb(port) & HDAPS_READ_MASK; + return inb(port) & 0xff; } /* - * __check_latch - Check a port latch for a given value. Callers must hold - * hdaps_sem. Returns zero if the port contains the given value. + * __check_latch - Check a port latch for a given value. Returns zero if the + * port contains the given value. Callers must hold hdaps_sem. */ -static inline unsigned int __check_latch(u16 port, u8 val) +static inline int __check_latch(u16 port, u8 val) { if (__get_latch(port) == val) return 0; @@ -99,7 +93,7 @@ static inline unsigned int __check_latch(u16 port, u8 val) * __wait_latch - Wait up to 100us for a port latch to get a certain value, * returning zero if the value is obtained. Callers must hold hdaps_sem. */ -static unsigned int __wait_latch(u16 port, u8 val) +static int __wait_latch(u16 port, u8 val) { unsigned int i; @@ -109,59 +103,42 @@ static unsigned int __wait_latch(u16 port, u8 val) udelay(5); } - return -EINVAL; + return -EIO; } /* - * __device_refresh - Request a refresh from the accelerometer. - * - * If sync is REFRESH_SYNC, we perform a synchronous refresh and will wait. - * Returns zero if successful and nonzero on error. - * - * If sync is REFRESH_ASYNC, we merely kick off a new refresh if the device is - * not up-to-date. Always returns zero. - * - * Callers must hold hdaps_sem. + * __device_refresh - request a refresh from the accelerometer. Does not wait + * for refresh to complete. Callers must hold hdaps_sem. */ -static int __device_refresh(unsigned int sync) +static void __device_refresh(void) { - u8 state; - - udelay(100); - - state = inb(0x1604); - if (state == STATE_FRESH) - return 0; - - outb(0x11, 0x1610); - outb(0x01, 0x161f); - if (sync == REFRESH_ASYNC) - return 0; + udelay(200); + if (inb(0x1604) != STATE_FRESH) { + outb(0x11, 0x1610); + outb(0x01, 0x161f); + } +} +/* + * __device_refresh_sync - request a synchronous refresh from the + * accelerometer. We wait for the refresh to complete. Returns zero if + * successful and nonzero on error. Callers must hold hdaps_sem. + */ +static int __device_refresh_sync(void) +{ + __device_refresh(); return __wait_latch(0x1604, STATE_FRESH); } /* - * __device_complete - Indicate to the accelerometer that we are done reading + * __device_complete - indicate to the accelerometer that we are done reading * data, and then initiate an async refresh. Callers must hold hdaps_sem. */ static inline void __device_complete(void) { inb(0x161f); inb(0x1604); - __device_refresh(REFRESH_ASYNC); -} - -static int __hdaps_readb_one(unsigned int port, u8 *val) -{ - /* do a sync refresh -- we need to be sure that we read fresh data */ - if (__device_refresh(REFRESH_SYNC)) - return -EIO; - - *val = inb(port); - __device_complete(); - - return 0; + __device_refresh(); } /* @@ -174,17 +151,26 @@ static int hdaps_readb_one(unsigned int port, u8 *val) int ret; down(&hdaps_sem); - ret = __hdaps_readb_one(port, val); - up(&hdaps_sem); + /* do a sync refresh -- we need to be sure that we read fresh data */ + ret = __device_refresh_sync(); + if (ret) + goto out; + + *val = inb(port); + __device_complete(); + +out: + up(&hdaps_sem); return ret; } +/* __hdaps_read_pair - internal lockless helper for hdaps_read_pair(). */ static int __hdaps_read_pair(unsigned int port1, unsigned int port2, int *x, int *y) { /* do a sync refresh -- we need to be sure that we read fresh data */ - if (__device_refresh(REFRESH_SYNC)) + if (__device_refresh_sync()) return -EIO; *y = inw(port2); @@ -217,11 +203,13 @@ static int hdaps_read_pair(unsigned int port1, unsigned int port2, return ret; } -/* initialize the accelerometer */ +/* + * hdaps_device_init - initialize the accelerometer. Returns zero on success + * and negative error code on failure. Can sleep. + */ static int hdaps_device_init(void) { - unsigned int total_msecs = INIT_TIMEOUT_MSECS; - int ret = -ENXIO; + int total, ret = -ENXIO; down(&hdaps_sem); @@ -231,8 +219,10 @@ static int hdaps_device_init(void) goto out; /* - * The 0x03 value appears to only work on some thinkpads, such as the - * T42p. Others return 0x01. + * Most ThinkPads return 0x01. + * + * Others--namely the R50p, T41p, and T42p--return 0x03. These laptops + * have "inverted" axises. * * The 0x02 value occurs when the chip has been previously initialized. */ @@ -267,24 +257,23 @@ static int hdaps_device_init(void) outb(0x01, 0x161f); if (__wait_latch(0x161f, 0x00)) goto out; - if (__device_refresh(REFRESH_SYNC)) + if (__device_refresh_sync()) goto out; if (__wait_latch(0x1611, 0x00)) goto out; /* we have done our dance, now let's wait for the applause */ - while (total_msecs > 0) { - u8 ignored; + for (total = INIT_TIMEOUT_MSECS; total > 0; total -= INIT_WAIT_MSECS) { + int x, y; /* a read of the device helps push it into action */ - __hdaps_readb_one(HDAPS_PORT_UNKNOWN, &ignored); + __hdaps_read_pair(HDAPS_PORT_XPOS, HDAPS_PORT_YPOS, &x, &y); if (!__wait_latch(0x1611, 0x02)) { ret = 0; break; } msleep(INIT_WAIT_MSECS); - total_msecs -= INIT_WAIT_MSECS; } out: @@ -293,96 +282,6 @@ out: } -/* Input class stuff */ - -/* - * hdaps_calibrate - Zero out our "resting" values. Callers must hold hdaps_sem. - */ -static void hdaps_calibrate(void) -{ - int x, y; - - if (__hdaps_read_pair(HDAPS_PORT_XPOS, HDAPS_PORT_YPOS, &x, &y)) - return; - - rest_x = x; - rest_y = y; -} - -static void hdaps_mousedev_poll(unsigned long unused) -{ - int x, y; - - /* Cannot sleep. Try nonblockingly. If we fail, try again later. */ - if (down_trylock(&hdaps_sem)) { - mod_timer(&hdaps_timer,jiffies+msecs_to_jiffies(hdaps_poll_ms)); - return; - } - - if (__hdaps_read_pair(HDAPS_PORT_XPOS, HDAPS_PORT_YPOS, &x, &y)) - goto out; - - x -= rest_x; - y -= rest_y; - if (abs(x) > hdaps_mousedev_threshold) - input_report_rel(&hdaps_idev, REL_X, x); - if (abs(y) > hdaps_mousedev_threshold) - input_report_rel(&hdaps_idev, REL_Y, y); - input_sync(&hdaps_idev); - - mod_timer(&hdaps_timer, jiffies + msecs_to_jiffies(hdaps_poll_ms)); - -out: - up(&hdaps_sem); -} - -/* - * hdaps_mousedev_enable - enable the input class device. Can sleep. - */ -static void hdaps_mousedev_enable(void) -{ - down(&hdaps_sem); - - /* calibrate the device before enabling */ - hdaps_calibrate(); - - /* initialize the input class */ - init_input_dev(&hdaps_idev); - hdaps_idev.dev = &pdev->dev; - hdaps_idev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); - hdaps_idev.relbit[0] = BIT(REL_X) | BIT(REL_Y); - hdaps_idev.keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT); - input_register_device(&hdaps_idev); - - /* start up our timer */ - init_timer(&hdaps_timer); - hdaps_timer.function = hdaps_mousedev_poll; - hdaps_timer.expires = jiffies + msecs_to_jiffies(hdaps_poll_ms); - add_timer(&hdaps_timer); - - hdaps_mousedev = 1; - - up(&hdaps_sem); - - printk(KERN_INFO "hdaps: input device enabled.\n"); -} - -/* - * hdaps_mousedev_disable - disable the input class device. Caller must hold - * hdaps_sem. - */ -static void hdaps_mousedev_disable(void) -{ - down(&hdaps_sem); - if (hdaps_mousedev) { - hdaps_mousedev = 0; - del_timer_sync(&hdaps_timer); - input_unregister_device(&hdaps_idev); - } - up(&hdaps_sem); -} - - /* Device model stuff */ static int hdaps_probe(struct device *dev) @@ -412,6 +311,49 @@ static struct device_driver hdaps_driver = { .resume = hdaps_resume }; +/* Input class stuff */ + +static struct input_dev hdaps_idev = { + .name = "hdaps", + .evbit = { BIT(EV_ABS) }, + .absbit = { BIT(ABS_X) | BIT(ABS_Y) }, + .absmin = { [ABS_X] = -256, [ABS_Y] = -256 }, + .absmax = { [ABS_X] = 256, [ABS_Y] = 256 }, + .absfuzz = { [ABS_X] = HDAPS_INPUT_FUZZ, [ABS_Y] = HDAPS_INPUT_FUZZ }, + .absflat = { [ABS_X] = HDAPS_INPUT_FUZZ, [ABS_Y] = HDAPS_INPUT_FUZZ }, +}; + +/* + * hdaps_calibrate - Set our "resting" values. Callers must hold hdaps_sem. + */ +static void hdaps_calibrate(void) +{ + __hdaps_read_pair(HDAPS_PORT_XPOS, HDAPS_PORT_YPOS, &rest_x, &rest_y); +} + +static void hdaps_mousedev_poll(unsigned long unused) +{ + int x, y; + + /* Cannot sleep. Try nonblockingly. If we fail, try again later. */ + if (down_trylock(&hdaps_sem)) { + mod_timer(&hdaps_timer,jiffies + HDAPS_POLL_PERIOD); + return; + } + + if (__hdaps_read_pair(HDAPS_PORT_XPOS, HDAPS_PORT_YPOS, &x, &y)) + goto out; + + input_report_abs(&hdaps_idev, ABS_X, x - rest_x); + input_report_abs(&hdaps_idev, ABS_Y, y - rest_y); + input_sync(&hdaps_idev); + + mod_timer(&hdaps_timer, jiffies + HDAPS_POLL_PERIOD); + +out: + up(&hdaps_sem); +} + /* Sysfs Files */ @@ -517,69 +459,6 @@ static ssize_t hdaps_invert_store(struct device *dev, return count; } -static ssize_t hdaps_mousedev_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%d\n", hdaps_mousedev); -} - -static ssize_t hdaps_mousedev_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - int enable; - - if (sscanf(buf, "%d", &enable) != 1) - return -EINVAL; - - if (enable == 1) - hdaps_mousedev_enable(); - else if (enable == 0) - hdaps_mousedev_disable(); - else - return -EINVAL; - - return count; -} - -static ssize_t hdaps_poll_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%lu\n", hdaps_poll_ms); -} - -static ssize_t hdaps_poll_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - unsigned int poll; - - if (sscanf(buf, "%u", &poll) != 1 || poll == 0) - return -EINVAL; - hdaps_poll_ms = poll; - - return count; -} - -static ssize_t hdaps_threshold_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%u\n", hdaps_mousedev_threshold); -} - -static ssize_t hdaps_threshold_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - unsigned int threshold; - - if (sscanf(buf, "%u", &threshold) != 1 || threshold == 0) - return -EINVAL; - hdaps_mousedev_threshold = threshold; - - return count; -} - static DEVICE_ATTR(position, 0444, hdaps_position_show, NULL); static DEVICE_ATTR(variance, 0444, hdaps_variance_show, NULL); static DEVICE_ATTR(temp1, 0444, hdaps_temp1_show, NULL); @@ -588,10 +467,6 @@ static DEVICE_ATTR(keyboard_activity, 0444, hdaps_keyboard_activity_show, NULL); static DEVICE_ATTR(mouse_activity, 0444, hdaps_mouse_activity_show, NULL); static DEVICE_ATTR(calibrate, 0644, hdaps_calibrate_show,hdaps_calibrate_store); static DEVICE_ATTR(invert, 0644, hdaps_invert_show, hdaps_invert_store); -static DEVICE_ATTR(mousedev, 0644, hdaps_mousedev_show, hdaps_mousedev_store); -static DEVICE_ATTR(mousedev_poll_ms, 0644, hdaps_poll_show, hdaps_poll_store); -static DEVICE_ATTR(mousedev_threshold, 0644, hdaps_threshold_show, - hdaps_threshold_store); static struct attribute *hdaps_attributes[] = { &dev_attr_position.attr, @@ -601,9 +476,6 @@ static struct attribute *hdaps_attributes[] = { &dev_attr_keyboard_activity.attr, &dev_attr_mouse_activity.attr, &dev_attr_calibrate.attr, - &dev_attr_mousedev.attr, - &dev_attr_mousedev_threshold.attr, - &dev_attr_mousedev_poll_ms.attr, &dev_attr_invert.attr, NULL, }; @@ -619,7 +491,7 @@ static struct attribute_group hdaps_attribute_group = { * XXX: We should be able to return nonzero and halt the detection process. * But there is a bug in dmi_check_system() where a nonzero return from the * first match will result in a return of failure from dmi_check_system(). - * I fixed this; the patch is in 2.6-mm. Once in Linus's tree we can make + * I fixed this; the patch is 2.6-git. Once in a released tree, we can make * hdaps_dmi_match_invert() return hdaps_dmi_match(), which in turn returns 1. */ static int hdaps_dmi_match(struct dmi_system_id *id) @@ -668,6 +540,7 @@ static int __init hdaps_init(void) HDAPS_DMI_MATCH_NORMAL("ThinkPad T42"), HDAPS_DMI_MATCH_NORMAL("ThinkPad T43"), HDAPS_DMI_MATCH_NORMAL("ThinkPad X40"), + HDAPS_DMI_MATCH_NORMAL("ThinkPad X41 Tablet"), { .ident = NULL } }; @@ -696,8 +569,18 @@ static int __init hdaps_init(void) if (ret) goto out_device; - if (hdaps_mousedev) - hdaps_mousedev_enable(); + /* initial calibrate for the input device */ + hdaps_calibrate(); + + /* initialize the input class */ + hdaps_idev.dev = &pdev->dev; + input_register_device(&hdaps_idev); + + /* start up our timer for the input device */ + init_timer(&hdaps_timer); + hdaps_timer.function = hdaps_mousedev_poll; + hdaps_timer.expires = jiffies + HDAPS_POLL_PERIOD; + add_timer(&hdaps_timer); printk(KERN_INFO "hdaps: driver successfully loaded.\n"); return 0; @@ -715,8 +598,8 @@ out: static void __exit hdaps_exit(void) { - hdaps_mousedev_disable(); - + del_timer_sync(&hdaps_timer); + input_unregister_device(&hdaps_idev); sysfs_remove_group(&pdev->dev.kobj, &hdaps_attribute_group); platform_device_unregister(pdev); driver_unregister(&hdaps_driver); @@ -728,9 +611,6 @@ static void __exit hdaps_exit(void) module_init(hdaps_init); module_exit(hdaps_exit); -module_param_named(mousedev, hdaps_mousedev, bool, 0); -MODULE_PARM_DESC(mousedev, "enable the input class device"); - module_param_named(invert, hdaps_invert, bool, 0); MODULE_PARM_DESC(invert, "invert data along each axis"); 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/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index fdf53ce..44b595d 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -914,19 +914,23 @@ static int i2c_pxa_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num return ret; } +static u32 i2c_pxa_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + static struct i2c_algorithm i2c_pxa_algorithm = { - .name = "PXA-I2C-Algorithm", - .id = I2C_ALGO_PXA, .master_xfer = i2c_pxa_xfer, + .functionality = i2c_pxa_functionality, }; static struct pxa_i2c i2c_pxa = { .lock = SPIN_LOCK_UNLOCKED, .wait = __WAIT_QUEUE_HEAD_INITIALIZER(i2c_pxa.wait), .adap = { - .name = "pxa2xx-i2c", - .id = I2C_ALGO_PXA, + .owner = THIS_MODULE, .algo = &i2c_pxa_algorithm, + .name = "pxa2xx-i2c", .retries = 5, }, }; 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/ide-taskfile.c b/drivers/ide/ide-taskfile.c index d04f62a..ace8eda 100644 --- a/drivers/ide/ide-taskfile.c +++ b/drivers/ide/ide-taskfile.c @@ -500,6 +500,7 @@ static int ide_diag_taskfile(ide_drive_t *drive, ide_task_t *args, unsigned long } rq.special = args; + args->rq = &rq; return ide_do_drive_cmd(drive, &rq, ide_wait); } 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/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c index 8337b0f..4866fc3 100644 --- a/drivers/isdn/hisax/hfc_pci.c +++ b/drivers/isdn/hisax/hfc_pci.c @@ -61,6 +61,7 @@ static const PCI_ENTRY id_list[] = {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_E,"Digi International", "Digi DataFire Micro V (Europe)"}, {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_A,"Digi International", "Digi DataFire Micro V IOM2 (North America)"}, {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_A,"Digi International", "Digi DataFire Micro V (North America)"}, + {PCI_VENDOR_ID_SITECOM, PCI_DEVICE_ID_SITECOM_DC105V2, "Sitecom Europe", "DC-105 ISDN PCI"}, {0, 0, NULL, NULL}, }; diff --git a/drivers/isdn/hisax/sedlbauer_cs.c b/drivers/isdn/hisax/sedlbauer_cs.c index c6b5bf7..dc334aa 100644 --- a/drivers/isdn/hisax/sedlbauer_cs.c +++ b/drivers/isdn/hisax/sedlbauer_cs.c @@ -611,7 +611,7 @@ static int sedlbauer_event(event_t event, int priority, } /* sedlbauer_event */ static struct pcmcia_device_id sedlbauer_ids[] = { - PCMCIA_DEVICE_PROD_ID1234("SEDLBAUER", "speed star II", "V 3.1", "(c) 93 - 98 cb ", 0x81fb79f5, 0xf3612e1d, 0x6b95c78a, 0x50d4149c), + PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "speed star II", "V 3.1", 0x81fb79f5, 0xf3612e1d, 0x6b95c78a), PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", "4D67", 0x81fb79f5, 0xe4e9bc12, 0x397b7e90), PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", "4D98", 0x81fb79f5, 0xe4e9bc12, 0x2e5c7fce), PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", " (C) 93-94 VK", 0x81fb79f5, 0xe4e9bc12, 0x8db143fe), diff --git a/drivers/isdn/hisax/st5481.h b/drivers/isdn/hisax/st5481.h index 0fda5c8..9ffaae7 100644 --- a/drivers/isdn/hisax/st5481.h +++ b/drivers/isdn/hisax/st5481.h @@ -466,10 +466,10 @@ void st5481_stop(struct st5481_adapter *adapter); #define __debug_variable st5481_debug #include "hisax_debug.h" -#ifdef CONFIG_HISAX_DEBUG - extern int st5481_debug; +#ifdef CONFIG_HISAX_DEBUG + #define DBG_ISO_PACKET(level,urb) \ if (level & __debug_variable) dump_iso_packet(__FUNCTION__,urb) diff --git a/drivers/isdn/hisax/st5481_b.c b/drivers/isdn/hisax/st5481_b.c index 2fcd093..0a2536d 100644 --- a/drivers/isdn/hisax/st5481_b.c +++ b/drivers/isdn/hisax/st5481_b.c @@ -172,14 +172,18 @@ static void usb_b_out_complete(struct urb *urb, struct pt_regs *regs) test_and_clear_bit(buf_nr, &b_out->busy); if (unlikely(urb->status < 0)) { - if (urb->status != -ENOENT && urb->status != -ESHUTDOWN) { - WARN("urb status %d",urb->status); - if (b_out->busy == 0) { - st5481_usb_pipe_reset(adapter, (bcs->channel+1)*2 | USB_DIR_OUT, NULL, NULL); - } - } else { - DBG(1,"urb killed"); - return; // Give up + switch (urb->status) { + case -ENOENT: + case -ESHUTDOWN: + case -ECONNRESET: + DBG(4,"urb killed status %d", urb->status); + return; // Give up + default: + WARN("urb status %d",urb->status); + if (b_out->busy == 0) { + st5481_usb_pipe_reset(adapter, (bcs->channel+1)*2 | USB_DIR_OUT, NULL, NULL); + } + break; } } @@ -205,7 +209,9 @@ static void st5481B_mode(struct st5481_bcs *bcs, int mode) bcs->mode = mode; // Cancel all USB transfers on this B channel + b_out->urb[0]->transfer_flags |= URB_ASYNC_UNLINK; usb_unlink_urb(b_out->urb[0]); + b_out->urb[1]->transfer_flags |= URB_ASYNC_UNLINK; usb_unlink_urb(b_out->urb[1]); b_out->busy = 0; diff --git a/drivers/isdn/hisax/st5481_d.c b/drivers/isdn/hisax/st5481_d.c index 071b1d3..941f702 100644 --- a/drivers/isdn/hisax/st5481_d.c +++ b/drivers/isdn/hisax/st5481_d.c @@ -382,16 +382,20 @@ static void usb_d_out_complete(struct urb *urb, struct pt_regs *regs) test_and_clear_bit(buf_nr, &d_out->busy); if (unlikely(urb->status < 0)) { - if (urb->status != -ENOENT && urb->status != -ESHUTDOWN) { - WARN("urb status %d",urb->status); - if (d_out->busy == 0) { - st5481_usb_pipe_reset(adapter, EP_D_OUT | USB_DIR_OUT, fifo_reseted, adapter); - } - return; - } else { - DBG(1,"urb killed"); - return; // Give up + switch (urb->status) { + case -ENOENT: + case -ESHUTDOWN: + case -ECONNRESET: + DBG(1,"urb killed status %d", urb->status); + break; + default: + WARN("urb status %d",urb->status); + if (d_out->busy == 0) { + st5481_usb_pipe_reset(adapter, EP_D_OUT | USB_DIR_OUT, fifo_reseted, adapter); + } + break; } + return; // Give up } FsmEvent(&adapter->d_out.fsm, EV_DOUT_COMPLETE, (void *) buf_nr); @@ -709,14 +713,14 @@ int st5481_setup_d(struct st5481_adapter *adapter) adapter->l1m.fsm = &l1fsm; adapter->l1m.state = ST_L1_F3; - adapter->l1m.debug = 1; + adapter->l1m.debug = st5481_debug & 0x100; adapter->l1m.userdata = adapter; adapter->l1m.printdebug = l1m_debug; FsmInitTimer(&adapter->l1m, &adapter->timer); adapter->d_out.fsm.fsm = &dout_fsm; adapter->d_out.fsm.state = ST_DOUT_NONE; - adapter->d_out.fsm.debug = 1; + adapter->d_out.fsm.debug = st5481_debug & 0x100; adapter->d_out.fsm.userdata = adapter; adapter->d_out.fsm.printdebug = dout_debug; diff --git a/drivers/isdn/hisax/st5481_init.c b/drivers/isdn/hisax/st5481_init.c index 7aa810d..2cf5d1a 100644 --- a/drivers/isdn/hisax/st5481_init.c +++ b/drivers/isdn/hisax/st5481_init.c @@ -43,10 +43,10 @@ static int number_of_leds = 2; /* 2 LEDs on the adpater default */ module_param(number_of_leds, int, 0); #ifdef CONFIG_HISAX_DEBUG -static int debug = 0x1; +static int debug = 0; module_param(debug, int, 0); -int st5481_debug; #endif +int st5481_debug; static LIST_HEAD(adapter_list); diff --git a/drivers/isdn/hisax/st5481_usb.c b/drivers/isdn/hisax/st5481_usb.c index ab62223..ffd5b2d 100644 --- a/drivers/isdn/hisax/st5481_usb.c +++ b/drivers/isdn/hisax/st5481_usb.c @@ -132,11 +132,15 @@ static void usb_ctrl_complete(struct urb *urb, struct pt_regs *regs) struct ctrl_msg *ctrl_msg; if (unlikely(urb->status < 0)) { - if (urb->status != -ENOENT && urb->status != -ESHUTDOWN) { - WARN("urb status %d",urb->status); - } else { - DBG(1,"urb killed"); - return; // Give up + switch (urb->status) { + case -ENOENT: + case -ESHUTDOWN: + case -ECONNRESET: + DBG(1,"urb killed status %d", urb->status); + return; // Give up + default: + WARN("urb status %d",urb->status); + break; } } @@ -184,22 +188,22 @@ static void usb_int_complete(struct urb *urb, struct pt_regs *regs) int status; switch (urb->status) { - case 0: - /* success */ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* this urb is terminated, clean up */ - DBG(1, "urb shutting down with status: %d", urb->status); - return; - default: - WARN("nonzero urb status received: %d", urb->status); - goto exit; + case 0: + /* success */ + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + /* this urb is terminated, clean up */ + DBG(2, "urb shutting down with status: %d", urb->status); + return; + default: + WARN("nonzero urb status received: %d", urb->status); + goto exit; } - DBG_PACKET(1, data, INT_PKT_SIZE); + DBG_PACKET(2, data, INT_PKT_SIZE); if (urb->actual_length == 0) { goto exit; @@ -250,7 +254,7 @@ int st5481_setup_usb(struct st5481_adapter *adapter) struct urb *urb; u8 *buf; - DBG(1,""); + DBG(2,""); if ((status = usb_reset_configuration (dev)) < 0) { WARN("reset_configuration failed,status=%d",status); @@ -330,15 +334,17 @@ void st5481_release_usb(struct st5481_adapter *adapter) DBG(1,""); // Stop and free Control and Interrupt URBs - usb_unlink_urb(ctrl->urb); + usb_kill_urb(ctrl->urb); if (ctrl->urb->transfer_buffer) kfree(ctrl->urb->transfer_buffer); usb_free_urb(ctrl->urb); + ctrl->urb = NULL; - usb_unlink_urb(intr->urb); + usb_kill_urb(intr->urb); if (intr->urb->transfer_buffer) kfree(intr->urb->transfer_buffer); usb_free_urb(intr->urb); + ctrl->urb = NULL; } /* @@ -406,6 +412,7 @@ fill_isoc_urb(struct urb *urb, struct usb_device *dev, spin_lock_init(&urb->lock); urb->dev=dev; urb->pipe=pipe; + urb->interval = 1; urb->transfer_buffer=buf; urb->number_of_packets = num_packets; urb->transfer_buffer_length=num_packets*packet_size; @@ -452,7 +459,9 @@ st5481_setup_isocpipes(struct urb* urb[2], struct usb_device *dev, if (urb[j]) { if (urb[j]->transfer_buffer) kfree(urb[j]->transfer_buffer); + urb[j]->transfer_buffer = NULL; usb_free_urb(urb[j]); + urb[j] = NULL; } } return retval; @@ -463,10 +472,11 @@ void st5481_release_isocpipes(struct urb* urb[2]) int j; for (j = 0; j < 2; j++) { - usb_unlink_urb(urb[j]); + usb_kill_urb(urb[j]); if (urb[j]->transfer_buffer) kfree(urb[j]->transfer_buffer); usb_free_urb(urb[j]); + urb[j] = NULL; } } @@ -485,11 +495,15 @@ static void usb_in_complete(struct urb *urb, struct pt_regs *regs) int len, count, status; if (unlikely(urb->status < 0)) { - if (urb->status != -ENOENT && urb->status != -ESHUTDOWN) { - WARN("urb status %d",urb->status); - } else { - DBG(1,"urb killed"); - return; // Give up + switch (urb->status) { + case -ENOENT: + case -ESHUTDOWN: + case -ECONNRESET: + DBG(1,"urb killed status %d", urb->status); + return; // Give up + default: + WARN("urb status %d",urb->status); + break; } } @@ -631,7 +645,9 @@ void st5481_in_mode(struct st5481_in *in, int mode) in->mode = mode; + in->urb[0]->transfer_flags |= URB_ASYNC_UNLINK; usb_unlink_urb(in->urb[0]); + in->urb[1]->transfer_flags |= URB_ASYNC_UNLINK; usb_unlink_urb(in->urb[1]); if (in->mode != L1_MODE_NULL) { 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/md/raid6.h b/drivers/md/raid6.h index f80ee63..31cbee7 100644 --- a/drivers/md/raid6.h +++ b/drivers/md/raid6.h @@ -69,9 +69,13 @@ extern const char raid6_empty_zero_page[PAGE_SIZE]; #define __init #define __exit #define __attribute_const__ __attribute__((const)) +#define noinline __attribute__((noinline)) #define preempt_enable() #define preempt_disable() +#define cpu_has_feature(x) 1 +#define enable_kernel_altivec() +#define disable_kernel_altivec() #endif /* __KERNEL__ */ diff --git a/drivers/md/raid6algos.c b/drivers/md/raid6algos.c index acf386f..51c63c0 100644 --- a/drivers/md/raid6algos.c +++ b/drivers/md/raid6algos.c @@ -19,6 +19,7 @@ #include "raid6.h" #ifndef __KERNEL__ #include <sys/mman.h> +#include <stdio.h> #endif struct raid6_calls raid6_call; diff --git a/drivers/md/raid6altivec.uc b/drivers/md/raid6altivec.uc index 1de8f03..b9afd35 100644 --- a/drivers/md/raid6altivec.uc +++ b/drivers/md/raid6altivec.uc @@ -27,16 +27,20 @@ #ifdef CONFIG_ALTIVEC #include <altivec.h> -#include <asm/system.h> -#include <asm/cputable.h> +#ifdef __KERNEL__ +# include <asm/system.h> +# include <asm/cputable.h> +#endif /* - * This is the C data type to use + * This is the C data type to use. We use a vector of + * signed char so vec_cmpgt() will generate the right + * instruction. */ -typedef vector unsigned char unative_t; +typedef vector signed char unative_t; -#define NBYTES(x) ((vector unsigned char) {x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x}) +#define NBYTES(x) ((vector signed char) {x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x}) #define NSIZE sizeof(unative_t) /* @@ -108,7 +112,11 @@ int raid6_have_altivec(void); int raid6_have_altivec(void) { /* This assumes either all CPUs have Altivec or none does */ +# ifdef __KERNEL__ return cpu_has_feature(CPU_FTR_ALTIVEC); +# else + return 1; +# endif } #endif diff --git a/drivers/md/raid6test/Makefile b/drivers/md/raid6test/Makefile index 5578067..78e0396 100644 --- a/drivers/md/raid6test/Makefile +++ b/drivers/md/raid6test/Makefile @@ -8,6 +8,8 @@ OPTFLAGS = -O2 # Adjust as desired CFLAGS = -I.. -g $(OPTFLAGS) LD = ld PERL = perl +AR = ar +RANLIB = ranlib .c.o: $(CC) $(CFLAGS) -c -o $@ $< @@ -18,18 +20,33 @@ PERL = perl %.uc: ../%.uc cp -f $< $@ -all: raid6.o raid6test +all: raid6.a raid6test -raid6.o: raid6int1.o raid6int2.o raid6int4.o raid6int8.o raid6int16.o \ +raid6.a: raid6int1.o raid6int2.o raid6int4.o raid6int8.o raid6int16.o \ raid6int32.o \ raid6mmx.o raid6sse1.o raid6sse2.o \ + raid6altivec1.o raid6altivec2.o raid6altivec4.o raid6altivec8.o \ raid6recov.o raid6algos.o \ raid6tables.o - $(LD) -r -o $@ $^ + rm -f $@ + $(AR) cq $@ $^ + $(RANLIB) $@ -raid6test: raid6.o test.c +raid6test: test.c raid6.a $(CC) $(CFLAGS) -o raid6test $^ +raid6altivec1.c: raid6altivec.uc ../unroll.pl + $(PERL) ../unroll.pl 1 < raid6altivec.uc > $@ + +raid6altivec2.c: raid6altivec.uc ../unroll.pl + $(PERL) ../unroll.pl 2 < raid6altivec.uc > $@ + +raid6altivec4.c: raid6altivec.uc ../unroll.pl + $(PERL) ../unroll.pl 4 < raid6altivec.uc > $@ + +raid6altivec8.c: raid6altivec.uc ../unroll.pl + $(PERL) ../unroll.pl 8 < raid6altivec.uc > $@ + raid6int1.c: raid6int.uc ../unroll.pl $(PERL) ../unroll.pl 1 < raid6int.uc > $@ @@ -52,7 +69,7 @@ raid6tables.c: mktables ./mktables > raid6tables.c clean: - rm -f *.o mktables mktables.c raid6int.uc raid6*.c raid6test + rm -f *.o *.a mktables mktables.c raid6int.uc raid6*.c raid6test spotless: clean rm -f *~ 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/mtd/maps/sharpsl-flash.c b/drivers/mtd/maps/sharpsl-flash.c index d15da6f..b7f093f 100644 --- a/drivers/mtd/maps/sharpsl-flash.c +++ b/drivers/mtd/maps/sharpsl-flash.c @@ -82,7 +82,7 @@ int __init init_sharpsl(void) } else if (machine_is_tosa()) { sharpsl_partitions[0].size=0x006a0000; sharpsl_partitions[0].offset=0x00160000; - } else if (machine_is_spitz()) { + } else if (machine_is_spitz() || machine_is_akita() || machine_is_borzoi()) { sharpsl_partitions[0].size=0x006b0000; sharpsl_partitions[0].offset=0x00140000; } else { diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c index 9853b87..88b5b5b 100644 --- a/drivers/mtd/nand/sharpsl.c +++ b/drivers/mtd/nand/sharpsl.c @@ -221,10 +221,16 @@ sharpsl_nand_init(void) sharpsl_partition_info[1].size=25 * 1024 * 1024; } else if (machine_is_husky()) { sharpsl_partition_info[1].size=53 * 1024 * 1024; - } + } else if (machine_is_spitz()) { + sharpsl_partition_info[1].size=5 * 1024 * 1024; + } else if (machine_is_akita()) { + sharpsl_partition_info[1].size=58 * 1024 * 1024; + } else if (machine_is_borzoi()) { + sharpsl_partition_info[1].size=32 * 1024 * 1024; + } } - if (machine_is_husky()) { + if (machine_is_husky() || machine_is_borzoi()) { /* Need to use small eraseblock size for backward compatibility */ sharpsl_mtd->flags |= MTD_NO_VIRTBLOCKS; } diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index 34b80de..bc53744 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -353,8 +353,6 @@ struct cp_private { struct net_device_stats net_stats; struct cp_extra_stats cp_stats; - struct cp_dma_stats *nic_stats; - dma_addr_t nic_stats_dma; unsigned rx_tail ____cacheline_aligned; struct cp_desc *rx_ring; @@ -1143,10 +1141,6 @@ static int cp_alloc_rings (struct cp_private *cp) cp->rx_ring = mem; cp->tx_ring = &cp->rx_ring[CP_RX_RING_SIZE]; - mem += (CP_RING_BYTES - CP_STATS_SIZE); - cp->nic_stats = mem; - cp->nic_stats_dma = cp->ring_dma + (CP_RING_BYTES - CP_STATS_SIZE); - return cp_init_rings(cp); } @@ -1187,7 +1181,6 @@ static void cp_free_rings (struct cp_private *cp) pci_free_consistent(cp->pdev, CP_RING_BYTES, cp->rx_ring, cp->ring_dma); cp->rx_ring = NULL; cp->tx_ring = NULL; - cp->nic_stats = NULL; } static int cp_open (struct net_device *dev) @@ -1516,13 +1509,17 @@ static void cp_get_ethtool_stats (struct net_device *dev, struct ethtool_stats *estats, u64 *tmp_stats) { struct cp_private *cp = netdev_priv(dev); + struct cp_dma_stats *nic_stats; + dma_addr_t dma; int i; - memset(cp->nic_stats, 0, sizeof(struct cp_dma_stats)); + nic_stats = pci_alloc_consistent(cp->pdev, sizeof(*nic_stats), &dma); + if (!nic_stats) + return; /* begin NIC statistics dump */ - cpw32(StatsAddr + 4, (cp->nic_stats_dma >> 16) >> 16); - cpw32(StatsAddr, (cp->nic_stats_dma & 0xffffffff) | DumpStats); + cpw32(StatsAddr + 4, (u64)dma >> 32); + cpw32(StatsAddr, ((u64)dma & DMA_32BIT_MASK) | DumpStats); cpr32(StatsAddr); for (i = 0; i < 1000; i++) { @@ -1532,24 +1529,27 @@ static void cp_get_ethtool_stats (struct net_device *dev, } cpw32(StatsAddr, 0); cpw32(StatsAddr + 4, 0); + cpr32(StatsAddr); i = 0; - tmp_stats[i++] = le64_to_cpu(cp->nic_stats->tx_ok); - tmp_stats[i++] = le64_to_cpu(cp->nic_stats->rx_ok); - tmp_stats[i++] = le64_to_cpu(cp->nic_stats->tx_err); - tmp_stats[i++] = le32_to_cpu(cp->nic_stats->rx_err); - tmp_stats[i++] = le16_to_cpu(cp->nic_stats->rx_fifo); - tmp_stats[i++] = le16_to_cpu(cp->nic_stats->frame_align); - tmp_stats[i++] = le32_to_cpu(cp->nic_stats->tx_ok_1col); - tmp_stats[i++] = le32_to_cpu(cp->nic_stats->tx_ok_mcol); - tmp_stats[i++] = le64_to_cpu(cp->nic_stats->rx_ok_phys); - tmp_stats[i++] = le64_to_cpu(cp->nic_stats->rx_ok_bcast); - tmp_stats[i++] = le32_to_cpu(cp->nic_stats->rx_ok_mcast); - tmp_stats[i++] = le16_to_cpu(cp->nic_stats->tx_abort); - tmp_stats[i++] = le16_to_cpu(cp->nic_stats->tx_underrun); + tmp_stats[i++] = le64_to_cpu(nic_stats->tx_ok); + tmp_stats[i++] = le64_to_cpu(nic_stats->rx_ok); + tmp_stats[i++] = le64_to_cpu(nic_stats->tx_err); + tmp_stats[i++] = le32_to_cpu(nic_stats->rx_err); + tmp_stats[i++] = le16_to_cpu(nic_stats->rx_fifo); + tmp_stats[i++] = le16_to_cpu(nic_stats->frame_align); + tmp_stats[i++] = le32_to_cpu(nic_stats->tx_ok_1col); + tmp_stats[i++] = le32_to_cpu(nic_stats->tx_ok_mcol); + tmp_stats[i++] = le64_to_cpu(nic_stats->rx_ok_phys); + tmp_stats[i++] = le64_to_cpu(nic_stats->rx_ok_bcast); + tmp_stats[i++] = le32_to_cpu(nic_stats->rx_ok_mcast); + tmp_stats[i++] = le16_to_cpu(nic_stats->tx_abort); + tmp_stats[i++] = le16_to_cpu(nic_stats->tx_underrun); tmp_stats[i++] = cp->cp_stats.rx_frags; if (i != CP_NUM_STATS) BUG(); + + pci_free_consistent(cp->pdev, sizeof(*nic_stats), nic_stats, dma); } static struct ethtool_ops cp_ethtool_ops = { diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 54fff9c..96f14ab 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1951,7 +1951,7 @@ config SKGE ---help--- This driver support the Marvell Yukon or SysKonnect SK-98xx/SK-95xx and related Gigabit Ethernet adapters. It is a new smaller driver - driver with better performance and more complete ethtool support. + with better performance and more complete ethtool support. It does not support the link failover and network management features that "portable" vendor supplied sk98lin driver does. 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/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 94c9f68..90449a0 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -2879,6 +2879,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) * This target is not on a VLAN */ if (rt->u.dst.dev == bond->dev) { + ip_rt_put(rt); dprintk("basa: rtdev == bond->dev: arp_send\n"); bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i], bond->master_ip, 0); @@ -2898,6 +2899,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) } if (vlan_id) { + ip_rt_put(rt); bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i], vlan->vlan_ip, vlan_id); continue; @@ -2909,6 +2911,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) bond->dev->name, NIPQUAD(fl.fl4_dst), rt->u.dst.dev ? rt->u.dst.dev->name : "NULL"); } + ip_rt_put(rt); } } @@ -5036,6 +5039,14 @@ static int __init bonding_init(void) return 0; out_err: + /* + * rtnl_unlock() will run netdev_run_todo(), putting the + * thus-far-registered bonding devices into a state which + * unregigister_netdevice() will accept + */ + rtnl_unlock(); + rtnl_lock(); + /* free and unregister all bonds that were successfully added */ bond_free_all(); diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 25cc20e..fbf1c06 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -1387,13 +1387,13 @@ static void e100_update_stats(struct nic *nic) ns->collisions += nic->tx_collisions; ns->tx_errors += le32_to_cpu(s->tx_max_collisions) + le32_to_cpu(s->tx_lost_crs); - ns->rx_dropped += le32_to_cpu(s->rx_resource_errors); ns->rx_length_errors += le32_to_cpu(s->rx_short_frame_errors) + nic->rx_over_length_errors; ns->rx_crc_errors += le32_to_cpu(s->rx_crc_errors); ns->rx_frame_errors += le32_to_cpu(s->rx_alignment_errors); ns->rx_over_errors += le32_to_cpu(s->rx_overrun_errors); ns->rx_fifo_errors += le32_to_cpu(s->rx_overrun_errors); + ns->rx_missed_errors += le32_to_cpu(s->rx_resource_errors); ns->rx_errors += le32_to_cpu(s->rx_crc_errors) + le32_to_cpu(s->rx_alignment_errors) + le32_to_cpu(s->rx_short_frame_errors) + @@ -1727,12 +1727,10 @@ static inline int e100_rx_indicate(struct nic *nic, struct rx *rx, if(unlikely(!(rfd_status & cb_ok))) { /* Don't indicate if hardware indicates errors */ - nic->net_stats.rx_dropped++; dev_kfree_skb_any(skb); } else if(actual_size > ETH_DATA_LEN + VLAN_ETH_HLEN) { /* Don't indicate oversized frames */ nic->rx_over_length_errors++; - nic->net_stats.rx_dropped++; dev_kfree_skb_any(skb); } else { nic->net_stats.rx_packets++; diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 7c8a0a2..ee687c9 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -2544,7 +2544,6 @@ e1000_update_stats(struct e1000_adapter *adapter) adapter->stats.crcerrs + adapter->stats.algnerrc + adapter->stats.rlec + adapter->stats.mpc + adapter->stats.cexterr; - adapter->net_stats.rx_dropped = adapter->stats.mpc; adapter->net_stats.rx_length_errors = adapter->stats.rlec; adapter->net_stats.rx_crc_errors = adapter->stats.crcerrs; adapter->net_stats.rx_frame_errors = adapter->stats.algnerrc; diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index 5c55537..89d6d69 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -1616,8 +1616,6 @@ ixgb_update_stats(struct ixgb_adapter *adapter) adapter->stats.icbc + adapter->stats.ecbc + adapter->stats.mpc; - adapter->net_stats.rx_dropped = adapter->stats.mpc; - /* see above * adapter->net_stats.rx_length_errors = adapter->stats.rlec; */ diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index c829e6a..dd451e0 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -428,7 +428,7 @@ static int init_shared_mem(struct s2io_nic *nic) DBG_PRINT(INIT_DBG, "%s: Zero DMA address for TxDL. ", dev->name); DBG_PRINT(INIT_DBG, - "Virtual address %llx\n", (u64)tmp_v); + "Virtual address %p\n", tmp_v); tmp_v = pci_alloc_consistent(nic->pdev, PAGE_SIZE, &tmp_p); if (!tmp_v) { @@ -657,9 +657,10 @@ static void free_shared_mem(struct s2io_nic *nic) mac_control->zerodma_virt_addr, (dma_addr_t)0); DBG_PRINT(INIT_DBG, - "%s: Freeing TxDL with zero DMA addr. ", dev->name); - DBG_PRINT(INIT_DBG, "Virtual address %llx\n", - (u64)(mac_control->zerodma_virt_addr)); + "%s: Freeing TxDL with zero DMA addr. ", + dev->name); + DBG_PRINT(INIT_DBG, "Virtual address %p\n", + mac_control->zerodma_virt_addr); } kfree(mac_control->fifos[i].list_info); } diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c index 6ee4771..2e72d79 100644 --- a/drivers/net/sk98lin/skge.c +++ b/drivers/net/sk98lin/skge.c @@ -5216,17 +5216,15 @@ static struct pci_device_id skge_pci_tbl[] = { { PCI_VENDOR_ID_3COM, 0x80eb, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { PCI_VENDOR_ID_SYSKONNECT, 0x4300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { PCI_VENDOR_ID_SYSKONNECT, 0x4320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_DLINK, 0x4c00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, +/* DLink card does not have valid VPD so this driver gags + * { PCI_VENDOR_ID_DLINK, 0x4c00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + */ { PCI_VENDOR_ID_MARVELL, 0x4320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, -#if 0 /* don't handle Yukon2 cards at the moment -- mlindner@syskonnect.de */ - { PCI_VENDOR_ID_MARVELL, 0x4360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_MARVELL, 0x4361, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, -#endif { PCI_VENDOR_ID_MARVELL, 0x5005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { PCI_VENDOR_ID_CNET, 0x434e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_LINKSYS, 0x1032, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_LINKSYS, 0x1032, PCI_ANY_ID, 0x0015, }, { PCI_VENDOR_ID_LINKSYS, 0x1064, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { 0, } + { 0 } }; MODULE_DEVICE_TABLE(pci, skge_pci_tbl); diff --git a/drivers/net/skge.c b/drivers/net/skge.c index d7c9851..0208258 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -42,7 +42,7 @@ #include "skge.h" #define DRV_NAME "skge" -#define DRV_VERSION "0.9" +#define DRV_VERSION "1.0" #define PFX DRV_NAME " " #define DEFAULT_TX_RING_SIZE 128 @@ -669,7 +669,7 @@ static void skge_led(struct skge_port *skge, enum led_mode mode) PHY_M_LED_BLINK_RT(BLINK_84MS) | PHY_M_LEDC_TX_CTRL | PHY_M_LEDC_DP_CTRL); - + gm_phy_write(hw, port, PHY_MARV_LED_OVER, PHY_M_LED_MO_RX(MO_LED_OFF) | (skge->speed == SPEED_100 ? @@ -876,7 +876,7 @@ static int skge_rx_fill(struct skge_port *skge) static void skge_link_up(struct skge_port *skge) { - skge_write8(skge->hw, SK_REG(skge->port, LNK_LED_REG), + skge_write8(skge->hw, SK_REG(skge->port, LNK_LED_REG), LED_BLK_OFF|LED_SYNC_OFF|LED_ON); netif_carrier_on(skge->netdev); @@ -987,6 +987,8 @@ static void genesis_reset(struct skge_hw *hw, int port) { const u8 zero[8] = { 0 }; + skge_write8(hw, SK_REG(port, GMAC_IRQ_MSK), 0); + /* reset the statistics module */ xm_write32(hw, port, XM_GP_PORT, XM_GP_RES_STAT); xm_write16(hw, port, XM_IMSK, 0xffff); /* disable XMAC IRQs */ @@ -1021,8 +1023,6 @@ static void bcom_check_link(struct skge_hw *hw, int port) (void) xm_phy_read(hw, port, PHY_BCOM_STAT); status = xm_phy_read(hw, port, PHY_BCOM_STAT); - pr_debug("bcom_check_link status=0x%x\n", status); - if ((status & PHY_ST_LSYNC) == 0) { u16 cmd = xm_read16(hw, port, XM_MMU_CMD); cmd &= ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX); @@ -1106,8 +1106,6 @@ static void bcom_phy_init(struct skge_port *skge, int jumbo) { 0x17, 0x0013 }, { 0x15, 0x0A04 }, { 0x18, 0x0420 }, }; - pr_debug("bcom_phy_init\n"); - /* read Id from external PHY (all have the same address) */ id1 = xm_phy_read(hw, port, PHY_XMAC_ID1); @@ -1340,6 +1338,8 @@ static void genesis_stop(struct skge_port *skge) int port = skge->port; u32 reg; + genesis_reset(hw, port); + /* Clear Tx packet arbiter timeout IRQ */ skge_write16(hw, B3_PA_CTRL, port == 0 ? PA_CLR_TO_TX1 : PA_CLR_TO_TX2); @@ -1465,7 +1465,6 @@ static void genesis_link_up(struct skge_port *skge) u16 cmd; u32 mode, msk; - pr_debug("genesis_link_up\n"); cmd = xm_read16(hw, port, XM_MMU_CMD); /* @@ -1578,7 +1577,6 @@ static void yukon_init(struct skge_hw *hw, int port) struct skge_port *skge = netdev_priv(hw->dev[port]); u16 ctrl, ct1000, adv; - pr_debug("yukon_init\n"); if (skge->autoneg == AUTONEG_ENABLE) { u16 ectrl = gm_phy_read(hw, port, PHY_MARV_EXT_CTRL); @@ -1677,9 +1675,11 @@ static void yukon_mac_init(struct skge_hw *hw, int port) /* WA code for COMA mode -- set PHY reset */ if (hw->chip_id == CHIP_ID_YUKON_LITE && - hw->chip_rev >= CHIP_REV_YU_LITE_A3) - skge_write32(hw, B2_GP_IO, - (skge_read32(hw, B2_GP_IO) | GP_DIR_9 | GP_IO_9)); + hw->chip_rev >= CHIP_REV_YU_LITE_A3) { + reg = skge_read32(hw, B2_GP_IO); + reg |= GP_DIR_9 | GP_IO_9; + skge_write32(hw, B2_GP_IO, reg); + } /* hard reset */ skge_write32(hw, SK_REG(port, GPHY_CTRL), GPC_RST_SET); @@ -1687,10 +1687,12 @@ static void yukon_mac_init(struct skge_hw *hw, int port) /* WA code for COMA mode -- clear PHY reset */ if (hw->chip_id == CHIP_ID_YUKON_LITE && - hw->chip_rev >= CHIP_REV_YU_LITE_A3) - skge_write32(hw, B2_GP_IO, - (skge_read32(hw, B2_GP_IO) | GP_DIR_9) - & ~GP_IO_9); + hw->chip_rev >= CHIP_REV_YU_LITE_A3) { + reg = skge_read32(hw, B2_GP_IO); + reg |= GP_DIR_9; + reg &= ~GP_IO_9; + skge_write32(hw, B2_GP_IO, reg); + } /* Set hardware config mode */ reg = GPC_INT_POL_HI | GPC_DIS_FC | GPC_DIS_SLEEP | @@ -1729,7 +1731,7 @@ static void yukon_mac_init(struct skge_hw *hw, int port) } gma_write16(hw, port, GM_GP_CTRL, reg); - skge_read16(hw, GMAC_IRQ_SRC); + skge_read16(hw, SK_REG(port, GMAC_IRQ_SRC)); yukon_init(hw, port); @@ -1801,20 +1803,26 @@ static void yukon_stop(struct skge_port *skge) struct skge_hw *hw = skge->hw; int port = skge->port; - if (hw->chip_id == CHIP_ID_YUKON_LITE && - hw->chip_rev >= CHIP_REV_YU_LITE_A3) { - skge_write32(hw, B2_GP_IO, - skge_read32(hw, B2_GP_IO) | GP_DIR_9 | GP_IO_9); - } + skge_write8(hw, SK_REG(port, GMAC_IRQ_MSK), 0); + yukon_reset(hw, port); gma_write16(hw, port, GM_GP_CTRL, gma_read16(hw, port, GM_GP_CTRL) & ~(GM_GPCR_TX_ENA|GM_GPCR_RX_ENA)); gma_read16(hw, port, GM_GP_CTRL); + if (hw->chip_id == CHIP_ID_YUKON_LITE && + hw->chip_rev >= CHIP_REV_YU_LITE_A3) { + u32 io = skge_read32(hw, B2_GP_IO); + + io |= GP_DIR_9 | GP_IO_9; + skge_write32(hw, B2_GP_IO, io); + skge_read32(hw, B2_GP_IO); + } + /* set GPHY Control reset */ - skge_write32(hw, SK_REG(port, GPHY_CTRL), GPC_RST_SET); - skge_write32(hw, SK_REG(port, GMAC_CTRL), GMC_RST_SET); + skge_write8(hw, SK_REG(port, GPHY_CTRL), GPC_RST_SET); + skge_write8(hw, SK_REG(port, GMAC_CTRL), GMC_RST_SET); } static void yukon_get_stats(struct skge_port *skge, u64 *data) @@ -1873,10 +1881,8 @@ static void yukon_link_up(struct skge_port *skge) int port = skge->port; u16 reg; - pr_debug("yukon_link_up\n"); - /* Enable Transmit FIFO Underrun */ - skge_write8(hw, GMAC_IRQ_MSK, GMAC_DEF_MSK); + skge_write8(hw, SK_REG(port, GMAC_IRQ_MSK), GMAC_DEF_MSK); reg = gma_read16(hw, port, GM_GP_CTRL); if (skge->duplex == DUPLEX_FULL || skge->autoneg == AUTONEG_ENABLE) @@ -1896,7 +1902,6 @@ static void yukon_link_down(struct skge_port *skge) int port = skge->port; u16 ctrl; - pr_debug("yukon_link_down\n"); gm_phy_write(hw, port, PHY_MARV_INT_MASK, 0); ctrl = gma_read16(hw, port, GM_GP_CTRL); @@ -2112,7 +2117,6 @@ static int skge_up(struct net_device *dev) skge_write8(hw, Q_ADDR(rxqaddr[port], Q_CSR), CSR_START | CSR_IRQ_CL_F); skge_led(skge, LED_MODE_ON); - pr_debug("skge_up completed\n"); return 0; free_rx_ring: @@ -2135,15 +2139,20 @@ static int skge_down(struct net_device *dev) netif_stop_queue(dev); + skge_write8(skge->hw, SK_REG(skge->port, LNK_LED_REG), LED_OFF); + if (hw->chip_id == CHIP_ID_GENESIS) + genesis_stop(skge); + else + yukon_stop(skge); + + hw->intr_mask &= ~portirqmask[skge->port]; + skge_write32(hw, B0_IMSK, hw->intr_mask); + /* Stop transmitter */ skge_write8(hw, Q_ADDR(txqaddr[port], Q_CSR), CSR_STOP); skge_write32(hw, RB_ADDR(txqaddr[port], RB_CTRL), RB_RST_SET|RB_DIS_OP_MD); - if (hw->chip_id == CHIP_ID_GENESIS) - genesis_stop(skge); - else - yukon_stop(skge); /* Disable Force Sync bit and Enable Alloc bit */ skge_write8(hw, SK_REG(port, TXA_CTRL), @@ -2367,8 +2376,6 @@ static void genesis_set_multicast(struct net_device *dev) u32 mode; u8 filter[8]; - pr_debug("genesis_set_multicast flags=%x count=%d\n", dev->flags, dev->mc_count); - mode = xm_read32(hw, port, XM_MODE); mode |= XM_MD_ENA_HASH; if (dev->flags & IFF_PROMISC) @@ -2530,8 +2537,6 @@ static int skge_poll(struct net_device *dev, int *budget) unsigned int to_do = min(dev->quota, *budget); unsigned int work_done = 0; - pr_debug("skge_poll\n"); - for (e = ring->to_clean; work_done < to_do; e = e->next) { struct skge_rx_desc *rd = e->desc; struct sk_buff *skb; @@ -2672,9 +2677,9 @@ static void skge_error_irq(struct skge_hw *hw) if (hw->chip_id == CHIP_ID_GENESIS) { /* clear xmac errors */ if (hwstatus & (IS_NO_STAT_M1|IS_NO_TIST_M1)) - skge_write16(hw, SK_REG(0, RX_MFF_CTRL1), MFF_CLR_INSTAT); + skge_write16(hw, RX_MFF_CTRL1, MFF_CLR_INSTAT); if (hwstatus & (IS_NO_STAT_M2|IS_NO_TIST_M2)) - skge_write16(hw, SK_REG(0, RX_MFF_CTRL2), MFF_CLR_INSTAT); + skge_write16(hw, RX_MFF_CTRL2, MFF_CLR_INSTAT); } else { /* Timestamp (unused) overflow */ if (hwstatus & IS_IRQ_TIST_OV) @@ -3000,9 +3005,6 @@ static int skge_reset(struct skge_hw *hw) skge_write32(hw, B0_IMSK, hw->intr_mask); - if (hw->chip_id != CHIP_ID_GENESIS) - skge_write8(hw, GMAC_IRQ_MSK, 0); - spin_lock_bh(&hw->phy_lock); for (i = 0; i < hw->ports; i++) { if (hw->chip_id == CHIP_ID_GENESIS) @@ -3230,6 +3232,11 @@ static void __devexit skge_remove(struct pci_dev *pdev) dev0 = hw->dev[0]; unregister_netdev(dev0); + skge_write32(hw, B0_IMSK, 0); + skge_write16(hw, B0_LED, LED_STAT_OFF); + skge_pci_clear(hw); + skge_write8(hw, B0_CTST, CS_RST_SET); + tasklet_kill(&hw->ext_tasklet); free_irq(pdev->irq, hw); @@ -3238,7 +3245,7 @@ static void __devexit skge_remove(struct pci_dev *pdev) if (dev1) free_netdev(dev1); free_netdev(dev0); - skge_write16(hw, B0_LED, LED_STAT_OFF); + iounmap(hw->regs); kfree(hw); pci_set_drvdata(pdev, NULL); @@ -3257,7 +3264,10 @@ static int skge_suspend(struct pci_dev *pdev, pm_message_t state) struct skge_port *skge = netdev_priv(dev); if (netif_running(dev)) { netif_carrier_off(dev); - skge_down(dev); + if (skge->wol) + netif_stop_queue(dev); + else + skge_down(dev); } netif_device_detach(dev); wol |= skge->wol; diff --git a/drivers/net/skge.h b/drivers/net/skge.h index f1680be..efbf98c 100644 --- a/drivers/net/skge.h +++ b/drivers/net/skge.h @@ -2008,7 +2008,7 @@ enum { GM_IS_RX_FF_OR = 1<<1, /* Receive FIFO Overrun */ GM_IS_RX_COMPL = 1<<0, /* Frame Reception Complete */ -#define GMAC_DEF_MSK (GM_IS_TX_CO_OV | GM_IS_RX_CO_OV | GM_IS_TX_FF_UR) +#define GMAC_DEF_MSK (GM_IS_RX_FF_OR | GM_IS_TX_FF_UR) /* GMAC_LINK_CTRL 16 bit GMAC Link Control Reg (YUKON only) */ /* Bits 15.. 2: reserved */ diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 4e19220..c796f41 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -1817,6 +1817,10 @@ spider_net_setup_phy(struct spider_net_card *card) /* LEDs active in both modes, autosense prio = fiber */ spider_net_write_phy(card->netdev, 1, MII_NCONFIG, 0x945f); + /* switch off fibre autoneg */ + spider_net_write_phy(card->netdev, 1, MII_NCONFIG, 0xfc01); + spider_net_write_phy(card->netdev, 1, 0x0b, 0x0004); + phy->def->ops->read_link(phy); pr_info("Found %s with %i Mbps, %s-duplex.\n", phy->def->name, phy->speed, phy->duplex==1 ? "Full" : "Half"); diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 7599f52..81f4aed 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -67,8 +67,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.39" -#define DRV_MODULE_RELDATE "September 5, 2005" +#define DRV_MODULE_VERSION "3.40" +#define DRV_MODULE_RELDATE "September 15, 2005" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 @@ -3442,31 +3442,47 @@ static void tg3_tx_timeout(struct net_device *dev) schedule_work(&tp->reset_task); } +/* Test for DMA buffers crossing any 4GB boundaries: 4G, 8G, etc */ +static inline int tg3_4g_overflow_test(dma_addr_t mapping, int len) +{ + u32 base = (u32) mapping & 0xffffffff; + + return ((base > 0xffffdcc0) && + (base + len + 8 < base)); +} + static void tg3_set_txd(struct tg3 *, int, dma_addr_t, int, u32, u32); static int tigon3_4gb_hwbug_workaround(struct tg3 *tp, struct sk_buff *skb, - u32 guilty_entry, int guilty_len, - u32 last_plus_one, u32 *start, u32 mss) + u32 last_plus_one, u32 *start, + u32 base_flags, u32 mss) { struct sk_buff *new_skb = skb_copy(skb, GFP_ATOMIC); - dma_addr_t new_addr; + dma_addr_t new_addr = 0; u32 entry = *start; - int i; + int i, ret = 0; if (!new_skb) { - dev_kfree_skb(skb); - return -1; + ret = -1; + } else { + /* New SKB is guaranteed to be linear. */ + entry = *start; + new_addr = pci_map_single(tp->pdev, new_skb->data, new_skb->len, + PCI_DMA_TODEVICE); + /* Make sure new skb does not cross any 4G boundaries. + * Drop the packet if it does. + */ + if (tg3_4g_overflow_test(new_addr, new_skb->len)) { + ret = -1; + dev_kfree_skb(new_skb); + new_skb = NULL; + } else { + tg3_set_txd(tp, entry, new_addr, new_skb->len, + base_flags, 1 | (mss << 1)); + *start = NEXT_TX(entry); + } } - /* New SKB is guaranteed to be linear. */ - entry = *start; - new_addr = pci_map_single(tp->pdev, new_skb->data, new_skb->len, - PCI_DMA_TODEVICE); - tg3_set_txd(tp, entry, new_addr, new_skb->len, - (skb->ip_summed == CHECKSUM_HW) ? - TXD_FLAG_TCPUDP_CSUM : 0, 1 | (mss << 1)); - *start = NEXT_TX(entry); - /* Now clean up the sw ring entries. */ i = 0; while (entry != last_plus_one) { @@ -3491,7 +3507,7 @@ static int tigon3_4gb_hwbug_workaround(struct tg3 *tp, struct sk_buff *skb, dev_kfree_skb(skb); - return 0; + return ret; } static void tg3_set_txd(struct tg3 *tp, int entry, @@ -3517,19 +3533,10 @@ static void tg3_set_txd(struct tg3 *tp, int entry, txd->vlan_tag = vlan_tag << TXD_VLAN_TAG_SHIFT; } -static inline int tg3_4g_overflow_test(dma_addr_t mapping, int len) -{ - u32 base = (u32) mapping & 0xffffffff; - - return ((base > 0xffffdcc0) && - (base + len + 8 < base)); -} - static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct tg3 *tp = netdev_priv(dev); dma_addr_t mapping; - unsigned int i; u32 len, entry, base_flags, mss; int would_hit_hwbug; @@ -3624,7 +3631,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) would_hit_hwbug = 0; if (tg3_4g_overflow_test(mapping, len)) - would_hit_hwbug = entry + 1; + would_hit_hwbug = 1; tg3_set_txd(tp, entry, mapping, len, base_flags, (skb_shinfo(skb)->nr_frags == 0) | (mss << 1)); @@ -3648,12 +3655,8 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) tp->tx_buffers[entry].skb = NULL; pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping); - if (tg3_4g_overflow_test(mapping, len)) { - /* Only one should match. */ - if (would_hit_hwbug) - BUG(); - would_hit_hwbug = entry + 1; - } + if (tg3_4g_overflow_test(mapping, len)) + would_hit_hwbug = 1; if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) tg3_set_txd(tp, entry, mapping, len, @@ -3669,34 +3672,15 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) if (would_hit_hwbug) { u32 last_plus_one = entry; u32 start; - unsigned int len = 0; - - would_hit_hwbug -= 1; - entry = entry - 1 - skb_shinfo(skb)->nr_frags; - entry &= (TG3_TX_RING_SIZE - 1); - start = entry; - i = 0; - while (entry != last_plus_one) { - if (i == 0) - len = skb_headlen(skb); - else - len = skb_shinfo(skb)->frags[i-1].size; - if (entry == would_hit_hwbug) - break; - - i++; - entry = NEXT_TX(entry); - - } + start = entry - 1 - skb_shinfo(skb)->nr_frags; + start &= (TG3_TX_RING_SIZE - 1); /* If the workaround fails due to memory/mapping * failure, silently drop this packet. */ - if (tigon3_4gb_hwbug_workaround(tp, skb, - entry, len, - last_plus_one, - &start, mss)) + if (tigon3_4gb_hwbug_workaround(tp, skb, last_plus_one, + &start, base_flags, mss)) goto out_unlock; entry = start; @@ -9271,6 +9255,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) static struct pci_device_id write_reorder_chipsets[] = { { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_700C) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMD, + PCI_DEVICE_ID_AMD_K8_NB) }, { }, }; u32 misc_ctrl_reg; @@ -9285,7 +9271,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->tg3_flags2 |= TG3_FLG2_SUN_570X; #endif - /* If we have an AMD 762 chipset, write + /* If we have an AMD 762 or K8 chipset, write * reordering to the mailbox registers done by the host * controller can cause major troubles. We read back from * every mailbox register write to force the writes to be @@ -9532,7 +9518,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->write32_rx_mbox = tg3_write_indirect_mbox; iounmap(tp->regs); - tp->regs = 0; + tp->regs = NULL; pci_read_config_word(tp->pdev, PCI_COMMAND, &pci_cmd); pci_cmd &= ~PCI_COMMAND_MEMORY; @@ -10680,7 +10666,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, err_out_iounmap: if (tp->regs) { iounmap(tp->regs); - tp->regs = 0; + tp->regs = NULL; } err_out_free_dev: @@ -10705,7 +10691,7 @@ static void __devexit tg3_remove_one(struct pci_dev *pdev) unregister_netdev(dev); if (tp->regs) { iounmap(tp->regs); - tp->regs = 0; + tp->regs = NULL; } free_netdev(dev); pci_release_regions(pdev); diff --git a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c index 26cc4f6..60d1e05 100644 --- a/drivers/net/tulip/xircom_cb.c +++ b/drivers/net/tulip/xircom_cb.c @@ -117,7 +117,7 @@ static int xircom_open(struct net_device *dev); static int xircom_close(struct net_device *dev); static void xircom_up(struct xircom_private *card); static struct net_device_stats *xircom_get_stats(struct net_device *dev); -#if CONFIG_NET_POLL_CONTROLLER +#ifdef CONFIG_NET_POLL_CONTROLLER static void xircom_poll_controller(struct net_device *dev); #endif diff --git a/drivers/net/wan/hdlc_cisco.c b/drivers/net/wan/hdlc_cisco.c index 48c03c1..a01efa6 100644 --- a/drivers/net/wan/hdlc_cisco.c +++ b/drivers/net/wan/hdlc_cisco.c @@ -72,7 +72,7 @@ static void cisco_keepalive_send(struct net_device *dev, u32 type, } skb_reserve(skb, 4); cisco_hard_header(skb, dev, CISCO_KEEPALIVE, NULL, NULL, 0); - data = (cisco_packet*)skb->data; + data = (cisco_packet*)(skb->data + 4); data->type = htonl(type); data->par1 = htonl(par1); diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 2be65d3..06998c2 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -6852,7 +6852,10 @@ static inline char *airo_translate_scan(struct net_device *dev, /* Add frequency */ iwe.cmd = SIOCGIWFREQ; iwe.u.freq.m = le16_to_cpu(bss->dsChannel); - iwe.u.freq.m = frequency_list[iwe.u.freq.m] * 100000; + /* iwe.u.freq.m containt the channel (starting 1), our + * frequency_list array start at index 0... + */ + iwe.u.freq.m = frequency_list[iwe.u.freq.m - 1] * 100000; iwe.u.freq.e = 1; current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN); 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/pci/hotplug/ibmphp_pci.c b/drivers/pci/hotplug/ibmphp_pci.c index 8122fe7..b1ba429 100644 --- a/drivers/pci/hotplug/ibmphp_pci.c +++ b/drivers/pci/hotplug/ibmphp_pci.c @@ -558,7 +558,7 @@ static int configure_device (struct pci_func *func) pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_CACHE_LINE_SIZE, CACHE); pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_LATENCY_TIMER, LATENCY); - pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_ROM_ADDRESS, 0x00L); + pci_bus_write_config_dword (ibmphp_pci_bus, devfn, PCI_ROM_ADDRESS, 0x00L); pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_COMMAND, DEVICEENABLE); return 0; diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index 0e09476..898f6da 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c @@ -2526,7 +2526,6 @@ configure_new_function(struct controller *ctrl, struct pci_func *func, int cloop; u8 temp_byte; u8 class_code; - u16 temp_word; u32 rc; u32 temp_register; u32 base; @@ -2682,8 +2681,7 @@ configure_new_function(struct controller *ctrl, struct pci_func *func, } /* End of base register loop */ /* disable ROM base Address */ - temp_word = 0x00L; - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_ROM_ADDRESS, temp_word); + rc = pci_bus_write_config_dword (pci_bus, devfn, PCI_ROM_ADDRESS, 0x00); /* Set HP parameters (Cache Line Size, Latency Timer) */ rc = pciehprm_set_hpp(ctrl, func, PCI_HEADER_TYPE_NORMAL); diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c index 783b5ab..91c9903 100644 --- a/drivers/pci/hotplug/shpchp_ctrl.c +++ b/drivers/pci/hotplug/shpchp_ctrl.c @@ -2824,8 +2824,7 @@ static int configure_new_function (struct controller * ctrl, struct pci_func * f } #endif /* Disable ROM base Address */ - temp_word = 0x00L; - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_ROM_ADDRESS, temp_word); + rc = pci_bus_write_config_dword (pci_bus, devfn, PCI_ROM_ADDRESS, 0x00); /* Set HP parameters (Cache Line Size, Latency Timer) */ rc = shpchprm_set_hpp(ctrl, func, PCI_HEADER_TYPE_NORMAL); diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 992db89..259d247 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -309,17 +309,25 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state) pci_read_config_word(dev, pm + PCI_PM_CTRL, &pmcsr); - /* If we're in D3, force entire word to 0. + /* If we're (effectively) in D3, force entire word to 0. * This doesn't affect PME_Status, disables PME_En, and * sets PowerState to 0. */ - if (dev->current_state >= PCI_D3hot) { - if (!(pmcsr & PCI_PM_CTRL_NO_SOFT_RESET)) + switch (dev->current_state) { + case PCI_UNKNOWN: /* Boot-up */ + if ((pmcsr & PCI_PM_CTRL_STATE_MASK) == PCI_D3hot + && !(pmcsr & PCI_PM_CTRL_NO_SOFT_RESET)) need_restore = 1; + /* Fall-through: force to D0 */ + case PCI_D3hot: + case PCI_D3cold: + case PCI_POWER_ERROR: pmcsr = 0; - } else { + break; + default: pmcsr &= ~PCI_PM_CTRL_STATE_MASK; pmcsr |= state; + break; } /* enter specified state */ 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/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index f0997c3..ba4d78e 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c @@ -1045,7 +1045,18 @@ static int __devinit yenta_probe (struct pci_dev *dev, const struct pci_device_i { struct yenta_socket *socket; int ret; - + + /* + * If we failed to assign proper bus numbers for this cardbus + * controller during PCI probe, its subordinate pci_bus is NULL. + * Bail out if so. + */ + if (!dev->subordinate) { + printk(KERN_ERR "Yenta: no bus associated with %s! " + "(try 'pci=assign-busses')\n", pci_name(dev)); + return -ENODEV; + } + socket = kmalloc(sizeof(struct yenta_socket), GFP_KERNEL); if (!socket) return -ENOMEM; diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c index aac83ce..a1c52a6 100644 --- a/drivers/s390/cio/blacklist.c +++ b/drivers/s390/cio/blacklist.c @@ -1,7 +1,7 @@ /* * drivers/s390/cio/blacklist.c * S/390 common I/O routines -- blacklisting of specific devices - * $Revision: 1.34 $ + * $Revision: 1.35 $ * * Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH, * IBM Corporation @@ -35,7 +35,7 @@ */ /* 65536 bits to indicate if a devno is blacklisted or not */ -#define __BL_DEV_WORDS (__MAX_SUBCHANNELS + (8*sizeof(long) - 1) / \ +#define __BL_DEV_WORDS ((__MAX_SUBCHANNELS + (8*sizeof(long) - 1)) / \ (8*sizeof(long))) static unsigned long bl_dev[__BL_DEV_WORDS]; typedef enum {add, free} range_action; diff --git a/drivers/s390/crypto/z90main.c b/drivers/s390/crypto/z90main.c index 6aeef3b..0cb47ec 100644 --- a/drivers/s390/crypto/z90main.c +++ b/drivers/s390/crypto/z90main.c @@ -682,9 +682,6 @@ z90crypt_cleanup_module(void) del_timer(&config_timer); del_timer(&cleanup_timer); - if (z90_device_work) - destroy_workqueue(z90_device_work); - destroy_z90crypt(); PRINTKN("Unloaded.\n"); diff --git a/drivers/s390/net/ctcmain.c b/drivers/s390/net/ctcmain.c index 96ca863..0db4f57 100644 --- a/drivers/s390/net/ctcmain.c +++ b/drivers/s390/net/ctcmain.c @@ -1,5 +1,5 @@ /* - * $Id: ctcmain.c,v 1.74 2005/03/24 09:04:17 mschwide Exp $ + * $Id: ctcmain.c,v 1.78 2005/09/07 12:18:02 pavlic Exp $ * * CTC / ESCON network driver * @@ -37,10 +37,9 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * RELEASE-TAG: CTC/ESCON network driver $Revision: 1.74 $ + * RELEASE-TAG: CTC/ESCON network driver $Revision: 1.78 $ * */ - #undef DEBUG #include <linux/module.h> #include <linux/init.h> @@ -135,7 +134,7 @@ static const char *dev_event_names[] = { "TX down", "Restart", }; - + /** * Events of the channel statemachine */ @@ -249,7 +248,7 @@ static void print_banner(void) { static int printed = 0; - char vbuf[] = "$Revision: 1.74 $"; + char vbuf[] = "$Revision: 1.78 $"; char *version = vbuf; if (printed) @@ -334,7 +333,7 @@ static const char *ch_state_names[] = { "Restarting", "Not operational", }; - + #ifdef DEBUG /** * Dump header and first 16 bytes of an sk_buff for debugging purposes. @@ -671,7 +670,7 @@ static void fsm_action_nop(fsm_instance * fi, int event, void *arg) { } - + /** * Actions for channel - statemachines. *****************************************************************************/ @@ -1514,7 +1513,6 @@ ch_action_reinit(fsm_instance *fi, int event, void *arg) fsm_addtimer(&privptr->restart_timer, 1000, DEV_EVENT_RESTART, dev); } - /** * The statemachine for a channel. */ @@ -1625,7 +1623,7 @@ static const fsm_node ch_fsm[] = { }; static const int CH_FSM_LEN = sizeof (ch_fsm) / sizeof (fsm_node); - + /** * Functions related to setup and device detection. *****************************************************************************/ @@ -1976,7 +1974,7 @@ ctc_irq_handler(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) fsm_event(ch->fsm, CH_EVENT_IRQ, ch); } - + /** * Actions for interface - statemachine. *****************************************************************************/ @@ -2209,13 +2207,18 @@ transmit_skb(struct channel *ch, struct sk_buff *skb) int rc = 0; DBF_TEXT(trace, 5, __FUNCTION__); + /* we need to acquire the lock for testing the state + * otherwise we can have an IRQ changing the state to + * TXIDLE after the test but before acquiring the lock. + */ + spin_lock_irqsave(&ch->collect_lock, saveflags); if (fsm_getstate(ch->fsm) != CH_STATE_TXIDLE) { int l = skb->len + LL_HEADER_LENGTH; - spin_lock_irqsave(&ch->collect_lock, saveflags); - if (ch->collect_len + l > ch->max_bufsize - 2) - rc = -EBUSY; - else { + if (ch->collect_len + l > ch->max_bufsize - 2) { + spin_unlock_irqrestore(&ch->collect_lock, saveflags); + return -EBUSY; + } else { atomic_inc(&skb->users); header.length = l; header.type = skb->protocol; @@ -2231,7 +2234,7 @@ transmit_skb(struct channel *ch, struct sk_buff *skb) int ccw_idx; struct sk_buff *nskb; unsigned long hi; - + spin_unlock_irqrestore(&ch->collect_lock, saveflags); /** * Protect skb against beeing free'd by upper * layers. @@ -2256,6 +2259,7 @@ transmit_skb(struct channel *ch, struct sk_buff *skb) if (!nskb) { atomic_dec(&skb->users); skb_pull(skb, LL_HEADER_LENGTH + 2); + ctc_clear_busy(ch->netdev); return -ENOMEM; } else { memcpy(skb_put(nskb, skb->len), @@ -2281,6 +2285,7 @@ transmit_skb(struct channel *ch, struct sk_buff *skb) */ atomic_dec(&skb->users); skb_pull(skb, LL_HEADER_LENGTH + 2); + ctc_clear_busy(ch->netdev); return -EBUSY; } @@ -2327,9 +2332,10 @@ transmit_skb(struct channel *ch, struct sk_buff *skb) } } + ctc_clear_busy(ch->netdev); return rc; } - + /** * Interface API for upper network layers *****************************************************************************/ @@ -2421,7 +2427,6 @@ ctc_tx(struct sk_buff *skb, struct net_device * dev) dev->trans_start = jiffies; if (transmit_skb(privptr->channel[WRITE], skb) != 0) rc = 1; - ctc_clear_busy(dev); return rc; } @@ -2610,7 +2615,6 @@ stats_write(struct device *dev, struct device_attribute *attr, const char *buf, return count; } - static void ctc_netdev_unregister(struct net_device * dev) { @@ -2685,7 +2689,6 @@ ctc_proto_store(struct device *dev, struct device_attribute *attr, const char *b return count; } - static ssize_t ctc_type_show(struct device *dev, struct device_attribute *attr, char *buf) { diff --git a/drivers/s390/net/qeth.h b/drivers/s390/net/qeth.h index 3a02856..2ad4797 100644 --- a/drivers/s390/net/qeth.h +++ b/drivers/s390/net/qeth.h @@ -24,7 +24,7 @@ #include "qeth_mpc.h" -#define VERSION_QETH_H "$Revision: 1.139 $" +#define VERSION_QETH_H "$Revision: 1.142 $" #ifdef CONFIG_QETH_IPV6 #define QETH_VERSION_IPV6 ":IPv6" @@ -1172,7 +1172,7 @@ extern int qeth_realloc_buffer_pool(struct qeth_card *, int); extern int -qeth_set_large_send(struct qeth_card *); +qeth_set_large_send(struct qeth_card *, enum qeth_large_send_types); extern void qeth_fill_header(struct qeth_card *, struct qeth_hdr *, diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index 79c74f3..86582cf 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c @@ -1,6 +1,6 @@ /* * - * linux/drivers/s390/net/qeth_main.c ($Revision: 1.214 $) + * linux/drivers/s390/net/qeth_main.c ($Revision: 1.224 $) * * Linux on zSeries OSA Express and HiperSockets support * @@ -12,7 +12,7 @@ * Frank Pavlic (pavlic@de.ibm.com) and * Thomas Spatzier <tspat@de.ibm.com> * - * $Revision: 1.214 $ $Date: 2005/05/04 20:19:18 $ + * $Revision: 1.224 $ $Date: 2005/05/04 20:19:18 $ * * 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 @@ -29,14 +29,6 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/*** - * eye catcher; just for debugging purposes - */ -void volatile -qeth_eyecatcher(void) -{ - return; -} #include <linux/config.h> #include <linux/module.h> @@ -80,7 +72,7 @@ qeth_eyecatcher(void) #include "qeth_eddp.h" #include "qeth_tso.h" -#define VERSION_QETH_C "$Revision: 1.214 $" +#define VERSION_QETH_C "$Revision: 1.224 $" static const char *version = "qeth S/390 OSA-Express driver"; /** @@ -2759,11 +2751,9 @@ qeth_flush_buffers(struct qeth_qdio_out_q *queue, int under_int, queue->card->perf_stats.outbound_do_qdio_start_time; #endif if (rc){ - QETH_DBF_SPRINTF(trace, 0, "qeth_flush_buffers: do_QDIO " - "returned error (%i) on device %s.", - rc, CARD_DDEV_ID(queue->card)); QETH_DBF_TEXT(trace, 2, "flushbuf"); QETH_DBF_TEXT_(trace, 2, " err%d", rc); + QETH_DBF_TEXT_(trace, 2, "%s", CARD_DDEV_ID(queue->card)); queue->card->stats.tx_errors += count; /* this must not happen under normal circumstances. if it * happens something is really wrong -> recover */ @@ -2909,11 +2899,8 @@ qeth_qdio_output_handler(struct ccw_device * ccwdev, unsigned int status, QETH_DBF_TEXT(trace, 6, "qdouhdl"); if (status & QDIO_STATUS_LOOK_FOR_ERROR) { if (status & QDIO_STATUS_ACTIVATE_CHECK_CONDITION){ - QETH_DBF_SPRINTF(trace, 2, "On device %s: " - "received active check " - "condition (0x%08x).", - CARD_BUS_ID(card), status); - QETH_DBF_TEXT(trace, 2, "chkcond"); + QETH_DBF_TEXT(trace, 2, "achkcond"); + QETH_DBF_TEXT_(trace, 2, "%s", CARD_BUS_ID(card)); QETH_DBF_TEXT_(trace, 2, "%08x", status); netif_stop_queue(card->dev); qeth_schedule_recovery(card); @@ -3356,26 +3343,32 @@ qeth_halt_channel(struct qeth_channel *channel) static int qeth_halt_channels(struct qeth_card *card) { - int rc = 0; + int rc1 = 0, rc2=0, rc3 = 0; QETH_DBF_TEXT(trace,3,"haltchs"); - if ((rc = qeth_halt_channel(&card->read))) - return rc; - if ((rc = qeth_halt_channel(&card->write))) - return rc; - return qeth_halt_channel(&card->data); + rc1 = qeth_halt_channel(&card->read); + rc2 = qeth_halt_channel(&card->write); + rc3 = qeth_halt_channel(&card->data); + if (rc1) + return rc1; + if (rc2) + return rc2; + return rc3; } static int qeth_clear_channels(struct qeth_card *card) { - int rc = 0; + int rc1 = 0, rc2=0, rc3 = 0; QETH_DBF_TEXT(trace,3,"clearchs"); - if ((rc = qeth_clear_channel(&card->read))) - return rc; - if ((rc = qeth_clear_channel(&card->write))) - return rc; - return qeth_clear_channel(&card->data); + rc1 = qeth_clear_channel(&card->read); + rc2 = qeth_clear_channel(&card->write); + rc3 = qeth_clear_channel(&card->data); + if (rc1) + return rc1; + if (rc2) + return rc2; + return rc3; } static int @@ -3445,23 +3438,23 @@ qeth_mpc_initialize(struct qeth_card *card) } if ((rc = qeth_cm_enable(card))){ QETH_DBF_TEXT_(setup, 2, "2err%d", rc); - return rc; + goto out_qdio; } if ((rc = qeth_cm_setup(card))){ QETH_DBF_TEXT_(setup, 2, "3err%d", rc); - return rc; + goto out_qdio; } if ((rc = qeth_ulp_enable(card))){ QETH_DBF_TEXT_(setup, 2, "4err%d", rc); - return rc; + goto out_qdio; } if ((rc = qeth_ulp_setup(card))){ QETH_DBF_TEXT_(setup, 2, "5err%d", rc); - return rc; + goto out_qdio; } if ((rc = qeth_alloc_qdio_buffers(card))){ QETH_DBF_TEXT_(setup, 2, "5err%d", rc); - return rc; + goto out_qdio; } if ((rc = qeth_qdio_establish(card))){ QETH_DBF_TEXT_(setup, 2, "6err%d", rc); @@ -3795,12 +3788,16 @@ static inline int qeth_prepare_skb(struct qeth_card *card, struct sk_buff **skb, struct qeth_hdr **hdr, int ipv) { + int rc; #ifdef CONFIG_QETH_VLAN u16 *tag; #endif QETH_DBF_TEXT(trace, 6, "prepskb"); + rc = qeth_realloc_headroom(card, skb, sizeof(struct qeth_hdr)); + if (rc) + return rc; #ifdef CONFIG_QETH_VLAN if (card->vlangrp && vlan_tx_tag_present(*skb) && ((ipv == 6) || card->options.layer2) ) { @@ -4251,7 +4248,8 @@ out: } static inline int -qeth_get_elements_no(struct qeth_card *card, void *hdr, struct sk_buff *skb) +qeth_get_elements_no(struct qeth_card *card, void *hdr, + struct sk_buff *skb, int elems) { int elements_needed = 0; @@ -4261,9 +4259,10 @@ qeth_get_elements_no(struct qeth_card *card, void *hdr, struct sk_buff *skb) if (elements_needed == 0 ) elements_needed = 1 + (((((unsigned long) hdr) % PAGE_SIZE) + skb->len) >> PAGE_SHIFT); - if (elements_needed > QETH_MAX_BUFFER_ELEMENTS(card)){ + if ((elements_needed + elems) > QETH_MAX_BUFFER_ELEMENTS(card)){ PRINT_ERR("qeth_do_send_packet: invalid size of " - "IP packet. Discarded."); + "IP packet (Number=%d / Length=%d). Discarded.\n", + (elements_needed+elems), skb->len); return 0; } return elements_needed; @@ -4275,7 +4274,7 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb) int ipv = 0; int cast_type; struct qeth_qdio_out_q *queue; - struct qeth_hdr *hdr; + struct qeth_hdr *hdr = NULL; int elements_needed = 0; enum qeth_large_send_types large_send = QETH_LARGE_SEND_NO; struct qeth_eddp_context *ctx = NULL; @@ -4337,9 +4336,11 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb) return -EINVAL; } } else { - elements_needed += qeth_get_elements_no(card,(void*) hdr, skb); - if (!elements_needed) + int elems = qeth_get_elements_no(card,(void*) hdr, skb, + elements_needed); + if (!elems) return -EINVAL; + elements_needed += elems; } if (card->info.type != QETH_CARD_TYPE_IQD) @@ -4504,7 +4505,11 @@ qeth_arp_set_no_entries(struct qeth_card *card, int no_entries) QETH_DBF_TEXT(trace,3,"arpstnoe"); - /* TODO: really not supported by GuestLAN? */ + /* + * currently GuestLAN only supports the ARP assist function + * IPA_CMD_ASS_ARP_QUERY_INFO, but not IPA_CMD_ASS_ARP_SET_NO_ENTRIES; + * thus we say EOPNOTSUPP for this ARP function + */ if (card->info.guestlan) return -EOPNOTSUPP; if (!qeth_is_supported(card,IPA_ARP_PROCESSING)) { @@ -4681,14 +4686,6 @@ qeth_arp_query(struct qeth_card *card, char *udata) QETH_DBF_TEXT(trace,3,"arpquery"); - /* - * currently GuestLAN does only deliver all zeros on query arp, - * even though arp processing is supported (according to IPA supp. - * funcs flags); since all zeros is no valueable information, - * we say EOPNOTSUPP for all ARP functions - */ - /*if (card->info.guestlan) - return -EOPNOTSUPP; */ if (!qeth_is_supported(card,/*IPA_QUERY_ARP_ADDR_INFO*/ IPA_ARP_PROCESSING)) { PRINT_WARN("ARP processing not supported " @@ -4894,10 +4891,9 @@ qeth_arp_add_entry(struct qeth_card *card, struct qeth_arp_cache_entry *entry) QETH_DBF_TEXT(trace,3,"arpadent"); /* - * currently GuestLAN does only deliver all zeros on query arp, - * even though arp processing is supported (according to IPA supp. - * funcs flags); since all zeros is no valueable information, - * we say EOPNOTSUPP for all ARP functions + * currently GuestLAN only supports the ARP assist function + * IPA_CMD_ASS_ARP_QUERY_INFO, but not IPA_CMD_ASS_ARP_ADD_ENTRY; + * thus we say EOPNOTSUPP for this ARP function */ if (card->info.guestlan) return -EOPNOTSUPP; @@ -4937,10 +4933,9 @@ qeth_arp_remove_entry(struct qeth_card *card, struct qeth_arp_cache_entry *entry QETH_DBF_TEXT(trace,3,"arprment"); /* - * currently GuestLAN does only deliver all zeros on query arp, - * even though arp processing is supported (according to IPA supp. - * funcs flags); since all zeros is no valueable information, - * we say EOPNOTSUPP for all ARP functions + * currently GuestLAN only supports the ARP assist function + * IPA_CMD_ASS_ARP_QUERY_INFO, but not IPA_CMD_ASS_ARP_REMOVE_ENTRY; + * thus we say EOPNOTSUPP for this ARP function */ if (card->info.guestlan) return -EOPNOTSUPP; @@ -4978,11 +4973,10 @@ qeth_arp_flush_cache(struct qeth_card *card) QETH_DBF_TEXT(trace,3,"arpflush"); /* - * currently GuestLAN does only deliver all zeros on query arp, - * even though arp processing is supported (according to IPA supp. - * funcs flags); since all zeros is no valueable information, - * we say EOPNOTSUPP for all ARP functions - */ + * currently GuestLAN only supports the ARP assist function + * IPA_CMD_ASS_ARP_QUERY_INFO, but not IPA_CMD_ASS_ARP_FLUSH_CACHE; + * thus we say EOPNOTSUPP for this ARP function + */ if (card->info.guestlan || (card->info.type == QETH_CARD_TYPE_IQD)) return -EOPNOTSUPP; if (!qeth_is_supported(card,IPA_ARP_PROCESSING)) { @@ -7038,14 +7032,16 @@ qeth_setrouting_v6(struct qeth_card *card) } int -qeth_set_large_send(struct qeth_card *card) +qeth_set_large_send(struct qeth_card *card, enum qeth_large_send_types type) { int rc = 0; - if (card->dev == NULL) + if (card->dev == NULL) { + card->options.large_send = type; return 0; - + } netif_stop_queue(card->dev); + card->options.large_send = type; switch (card->options.large_send) { case QETH_LARGE_SEND_EDDP: card->dev->features |= NETIF_F_TSO | NETIF_F_SG; @@ -7066,7 +7062,6 @@ qeth_set_large_send(struct qeth_card *card) card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG); break; } - netif_wake_queue(card->dev); return rc; } @@ -8257,7 +8252,6 @@ qeth_init(void) { int rc=0; - qeth_eyecatcher(); PRINT_INFO("loading %s (%s/%s/%s/%s/%s/%s/%s %s %s)\n", version, VERSION_QETH_C, VERSION_QETH_H, VERSION_QETH_MPC_H, VERSION_QETH_MPC_C, @@ -8338,7 +8332,6 @@ again: printk("qeth: removed\n"); } -EXPORT_SYMBOL(qeth_eyecatcher); module_init(qeth_init); module_exit(qeth_exit); MODULE_AUTHOR("Frank Pavlic <pavlic@de.ibm.com>"); diff --git a/drivers/s390/net/qeth_sys.c b/drivers/s390/net/qeth_sys.c index 98bedb0..dda105b 100644 --- a/drivers/s390/net/qeth_sys.c +++ b/drivers/s390/net/qeth_sys.c @@ -1,6 +1,6 @@ /* * - * linux/drivers/s390/net/qeth_sys.c ($Revision: 1.51 $) + * linux/drivers/s390/net/qeth_sys.c ($Revision: 1.54 $) * * Linux on zSeries OSA Express and HiperSockets support * This file contains code related to sysfs. @@ -20,7 +20,7 @@ #include "qeth_mpc.h" #include "qeth_fs.h" -const char *VERSION_QETH_SYS_C = "$Revision: 1.51 $"; +const char *VERSION_QETH_SYS_C = "$Revision: 1.54 $"; /*****************************************************************************/ /* */ @@ -722,10 +722,13 @@ qeth_dev_layer2_store(struct device *dev, struct device_attribute *attr, const c if (!card) return -EINVAL; + if (card->info.type == QETH_CARD_TYPE_IQD) { + PRINT_WARN("Layer2 on Hipersockets is not supported! \n"); + return -EPERM; + } if (((card->state != CARD_STATE_DOWN) && - (card->state != CARD_STATE_RECOVER)) || - (card->info.type != QETH_CARD_TYPE_OSAE)) + (card->state != CARD_STATE_RECOVER))) return -EPERM; i = simple_strtoul(buf, &tmp, 16); @@ -771,9 +774,7 @@ qeth_dev_large_send_store(struct device *dev, struct device_attribute *attr, con if (!card) return -EINVAL; - tmp = strsep((char **) &buf, "\n"); - if (!strcmp(tmp, "no")){ type = QETH_LARGE_SEND_NO; } else if (!strcmp(tmp, "EDDP")) { @@ -786,10 +787,8 @@ qeth_dev_large_send_store(struct device *dev, struct device_attribute *attr, con } if (card->options.large_send == type) return count; - card->options.large_send = type; - if ((rc = qeth_set_large_send(card))) + if ((rc = qeth_set_large_send(card, type))) return rc; - return count; } 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/scsi/libata-core.c b/drivers/scsi/libata-core.c index 5cc53cd..d92273c 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -2465,9 +2465,12 @@ static unsigned long ata_pio_poll(struct ata_port *ap) * * LOCKING: * None. (executing in kernel thread context) + * + * RETURNS: + * Non-zero if qc completed, zero otherwise. */ -static void ata_pio_complete (struct ata_port *ap) +static int ata_pio_complete (struct ata_port *ap) { struct ata_queued_cmd *qc; u8 drv_stat; @@ -2486,14 +2489,14 @@ static void ata_pio_complete (struct ata_port *ap) if (drv_stat & (ATA_BUSY | ATA_DRQ)) { ap->pio_task_state = PIO_ST_LAST_POLL; ap->pio_task_timeout = jiffies + ATA_TMOUT_PIO; - return; + return 0; } } drv_stat = ata_wait_idle(ap); if (!ata_ok(drv_stat)) { ap->pio_task_state = PIO_ST_ERR; - return; + return 0; } qc = ata_qc_from_tag(ap, ap->active_tag); @@ -2502,6 +2505,10 @@ static void ata_pio_complete (struct ata_port *ap) ap->pio_task_state = PIO_ST_IDLE; ata_poll_qc_complete(qc, drv_stat); + + /* another command may start at this point */ + + return 1; } @@ -2709,7 +2716,7 @@ static void __atapi_pio_bytes(struct ata_queued_cmd *qc, unsigned int bytes) next_sg: if (unlikely(qc->cursg >= qc->n_elem)) { - /* + /* * The end of qc->sg is reached and the device expects * more data to transfer. In order not to overrun qc->sg * and fulfill length specified in the byte count register, @@ -2721,7 +2728,7 @@ next_sg: unsigned int i; if (words) /* warning if bytes > 1 */ - printk(KERN_WARNING "ata%u: %u bytes trailing data\n", + printk(KERN_WARNING "ata%u: %u bytes trailing data\n", ap->id, bytes); for (i = 0; i < words; i++) @@ -2849,9 +2856,7 @@ static void ata_pio_block(struct ata_port *ap) if (is_atapi_taskfile(&qc->tf)) { /* no more data to transfer or unsupported ATAPI command */ if ((status & ATA_DRQ) == 0) { - ap->pio_task_state = PIO_ST_IDLE; - - ata_poll_qc_complete(qc, status); + ap->pio_task_state = PIO_ST_LAST; return; } @@ -2887,7 +2892,12 @@ static void ata_pio_error(struct ata_port *ap) static void ata_pio_task(void *_data) { struct ata_port *ap = _data; - unsigned long timeout = 0; + unsigned long timeout; + int qc_completed; + +fsm_start: + timeout = 0; + qc_completed = 0; switch (ap->pio_task_state) { case PIO_ST_IDLE: @@ -2898,7 +2908,7 @@ static void ata_pio_task(void *_data) break; case PIO_ST_LAST: - ata_pio_complete(ap); + qc_completed = ata_pio_complete(ap); break; case PIO_ST_POLL: @@ -2913,10 +2923,9 @@ static void ata_pio_task(void *_data) } if (timeout) - queue_delayed_work(ata_wq, &ap->pio_task, - timeout); - else - queue_work(ata_wq, &ap->pio_task); + queue_delayed_work(ata_wq, &ap->pio_task, timeout); + else if (!qc_completed) + goto fsm_start; } static void atapi_request_sense(struct ata_port *ap, struct ata_device *dev, diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 3e9b641..23d095d 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -201,6 +201,7 @@ int qla2100_pci_config(scsi_qla_host_t *ha) { uint16_t w, mwi; + uint32_t d; unsigned long flags; struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; @@ -215,9 +216,9 @@ qla2100_pci_config(scsi_qla_host_t *ha) pci_write_config_word(ha->pdev, PCI_COMMAND, w); /* Reset expansion ROM address decode enable */ - pci_read_config_word(ha->pdev, PCI_ROM_ADDRESS, &w); - w &= ~PCI_ROM_ADDRESS_ENABLE; - pci_write_config_word(ha->pdev, PCI_ROM_ADDRESS, w); + pci_read_config_dword(ha->pdev, PCI_ROM_ADDRESS, &d); + d &= ~PCI_ROM_ADDRESS_ENABLE; + pci_write_config_dword(ha->pdev, PCI_ROM_ADDRESS, d); /* Get PCI bus information. */ spin_lock_irqsave(&ha->hardware_lock, flags); @@ -237,6 +238,7 @@ int qla2300_pci_config(scsi_qla_host_t *ha) { uint16_t w, mwi; + uint32_t d; unsigned long flags = 0; uint32_t cnt; struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; @@ -302,9 +304,9 @@ qla2300_pci_config(scsi_qla_host_t *ha) pci_write_config_byte(ha->pdev, PCI_LATENCY_TIMER, 0x80); /* Reset expansion ROM address decode enable */ - pci_read_config_word(ha->pdev, PCI_ROM_ADDRESS, &w); - w &= ~PCI_ROM_ADDRESS_ENABLE; - pci_write_config_word(ha->pdev, PCI_ROM_ADDRESS, w); + pci_read_config_dword(ha->pdev, PCI_ROM_ADDRESS, &d); + d &= ~PCI_ROM_ADDRESS_ENABLE; + pci_write_config_dword(ha->pdev, PCI_ROM_ADDRESS, d); /* Get PCI bus information. */ spin_lock_irqsave(&ha->hardware_lock, flags); @@ -324,6 +326,7 @@ int qla24xx_pci_config(scsi_qla_host_t *ha) { uint16_t w, mwi; + uint32_t d; unsigned long flags = 0; struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; int pcix_cmd_reg, pcie_dctl_reg; @@ -366,9 +369,9 @@ qla24xx_pci_config(scsi_qla_host_t *ha) } /* Reset expansion ROM address decode enable */ - pci_read_config_word(ha->pdev, PCI_ROM_ADDRESS, &w); - w &= ~PCI_ROM_ADDRESS_ENABLE; - pci_write_config_word(ha->pdev, PCI_ROM_ADDRESS, w); + pci_read_config_dword(ha->pdev, PCI_ROM_ADDRESS, &d); + d &= ~PCI_ROM_ADDRESS_ENABLE; + pci_write_config_dword(ha->pdev, PCI_ROM_ADDRESS, d); /* Get PCI bus information. */ spin_lock_irqsave(&ha->hardware_lock, flags); diff --git a/drivers/scsi/sata_sis.c b/drivers/scsi/sata_sis.c index a63f931..b227e51 100644 --- a/drivers/scsi/sata_sis.c +++ b/drivers/scsi/sata_sis.c @@ -161,7 +161,7 @@ static u32 sis_scr_cfg_read (struct ata_port *ap, unsigned int sc_reg) { struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); unsigned int cfg_addr = get_scr_cfg_addr(ap->port_no, sc_reg, pdev->device); - u32 val, val2; + u32 val, val2 = 0; u8 pmr; if (sc_reg == SCR_ERROR) /* doesn't exist in PCI cfg space */ @@ -289,7 +289,7 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) if (ent->device != 0x182) { if ((pmr & SIS_PMR_COMBINED) == 0) { printk(KERN_INFO "sata_sis: Detected SiS 180/181 chipset in SATA mode\n"); - port2_start=0x64; + port2_start = 64; } else { printk(KERN_INFO "sata_sis: Detected SiS 180/181 chipset in combined mode\n"); diff --git a/drivers/serial/21285.c b/drivers/serial/21285.c index aec39fb..b5cf394 100644 --- a/drivers/serial/21285.c +++ b/drivers/serial/21285.c @@ -463,7 +463,7 @@ static int __init serial21285_console_setup(struct console *co, char *options) return uart_set_options(port, co, baud, parity, bits, flow); } -extern struct uart_driver serial21285_reg; +static struct uart_driver serial21285_reg; static struct console serial21285_console = { diff --git a/drivers/serial/amba-pl010.c b/drivers/serial/amba-pl010.c index 978e124..679e678 100644 --- a/drivers/serial/amba-pl010.c +++ b/drivers/serial/amba-pl010.c @@ -689,7 +689,7 @@ static int __init pl010_console_setup(struct console *co, char *options) return uart_set_options(port, co, baud, parity, bits, flow); } -extern struct uart_driver amba_reg; +static struct uart_driver amba_reg; static struct console amba_console = { .name = "ttyAM", .write = pl010_console_write, diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c index 5607130..1ff629c 100644 --- a/drivers/serial/amba-pl011.c +++ b/drivers/serial/amba-pl011.c @@ -701,7 +701,7 @@ static int __init pl011_console_setup(struct console *co, char *options) return uart_set_options(&uap->port, co, baud, parity, bits, flow); } -extern struct uart_driver amba_reg; +static struct uart_driver amba_reg; static struct console amba_console = { .name = "ttyAMA", .write = pl011_console_write, diff --git a/drivers/serial/clps711x.c b/drivers/serial/clps711x.c index d822896..78c1f36 100644 --- a/drivers/serial/clps711x.c +++ b/drivers/serial/clps711x.c @@ -525,7 +525,7 @@ static int __init clps711xuart_console_setup(struct console *co, char *options) return uart_set_options(port, co, baud, parity, bits, flow); } -extern struct uart_driver clps711x_reg; +static struct uart_driver clps711x_reg; static struct console clps711x_console = { .name = "ttyCL", .write = clps711xuart_console_write, diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c index a3cd0ee..0585ab2 100644 --- a/drivers/serial/mpc52xx_uart.c +++ b/drivers/serial/mpc52xx_uart.c @@ -781,7 +781,7 @@ mpc52xx_uart_remove(struct device *dev) #ifdef CONFIG_PM static int -mpc52xx_uart_suspend(struct device *dev, u32 state, u32 level) +mpc52xx_uart_suspend(struct device *dev, pm_message_t state, u32 level) { struct uart_port *port = (struct uart_port *) dev_get_drvdata(dev); diff --git a/drivers/serial/pxa.c b/drivers/serial/pxa.c index eaa0af8..672b359 100644 --- a/drivers/serial/pxa.c +++ b/drivers/serial/pxa.c @@ -589,8 +589,8 @@ serial_pxa_type(struct uart_port *port) #ifdef CONFIG_SERIAL_PXA_CONSOLE -extern struct uart_pxa_port serial_pxa_ports[]; -extern struct uart_driver serial_pxa_reg; +static struct uart_pxa_port serial_pxa_ports[]; +static struct uart_driver serial_pxa_reg; #define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) diff --git a/drivers/serial/sa1100.c b/drivers/serial/sa1100.c index 1225b14..dd8aed2 100644 --- a/drivers/serial/sa1100.c +++ b/drivers/serial/sa1100.c @@ -799,7 +799,7 @@ sa1100_console_setup(struct console *co, char *options) return uart_set_options(&sport->port, co, baud, parity, bits, flow); } -extern struct uart_driver sa1100_reg; +static struct uart_driver sa1100_reg; static struct console sa1100_console = { .name = "ttySA", .write = sa1100_console_write, diff --git a/drivers/serial/serial_lh7a40x.c b/drivers/serial/serial_lh7a40x.c index 8302376..d01dbe5 100644 --- a/drivers/serial/serial_lh7a40x.c +++ b/drivers/serial/serial_lh7a40x.c @@ -632,7 +632,7 @@ static int __init lh7a40xuart_console_setup (struct console* co, char* options) return uart_set_options (port, co, baud, parity, bits, flow); } -extern struct uart_driver lh7a40x_reg; +static struct uart_driver lh7a40x_reg; static struct console lh7a40x_console = { .name = "ttyAM", .write = lh7a40xuart_console_write, 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..630f2df 100644 --- a/drivers/video/backlight/corgi_bl.c +++ b/drivers/video/backlight/corgi_bl.c @@ -19,17 +19,18 @@ #include <linux/fb.h> #include <linux/backlight.h> -#include <asm/arch-pxa/corgi.h> -#include <asm/hardware/scoop.h> +#include <asm/mach-types.h> +#include <asm/arch/sharpsl.h> -#define CORGI_MAX_INTENSITY 0x3e #define CORGI_DEFAULT_INTENSITY 0x1f -#define CORGI_LIMIT_MASK 0x0b +#define CORGI_LIMIT_MASK 0x0b static int corgibl_powermode = FB_BLANK_UNBLANK; static int current_intensity = 0; static int corgibl_limit = 0; +static void (*corgibl_mach_set_intensity)(int intensity); static spinlock_t bl_lock = SPIN_LOCK_UNLOCKED; +static struct backlight_properties corgibl_data; static void corgibl_send_intensity(int intensity) { @@ -43,18 +44,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 +106,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 +134,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 +142,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/console/vgacon.c b/drivers/video/console/vgacon.c index 0705cd7..6ef6f77 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -1020,7 +1020,9 @@ static int vgacon_font_get(struct vc_data *c, struct console_font *font) static int vgacon_resize(struct vc_data *c, unsigned int width, unsigned int height) { - if (width % 2 || width > ORIG_VIDEO_COLS || height > ORIG_VIDEO_LINES) + if (width % 2 || width > ORIG_VIDEO_COLS || + height > (ORIG_VIDEO_LINES * vga_default_font_height)/ + c->vc_font.height) return -EINVAL; if (CON_IS_VISIBLE(c) && !vga_is_gfx) /* who knows */ diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c index cabd53c..6c2244c 100644 --- a/drivers/video/imxfb.c +++ b/drivers/video/imxfb.c @@ -425,7 +425,7 @@ static void imxfb_setup_gpio(struct imxfb_info *fbi) * Power management hooks. Note that we won't be called from IRQ context, * unlike the blank functions above, so we may sleep. */ -static int imxfb_suspend(struct device *dev, u32 state, u32 level) +static int imxfb_suspend(struct device *dev, pm_message_t state, u32 level) { struct imxfb_info *fbi = dev_get_drvdata(dev); pr_debug("%s\n",__FUNCTION__); 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/nvidia/nv_i2c.c b/drivers/video/nvidia/nv_i2c.c index ace484f..12f2884 100644 --- a/drivers/video/nvidia/nv_i2c.c +++ b/drivers/video/nvidia/nv_i2c.c @@ -209,10 +209,13 @@ int nvidia_probe_i2c_connector(struct fb_info *info, int conn, u8 **out_edid) if (!edid && conn == 1) { /* try to get from firmware */ - edid = kmalloc(EDID_LENGTH, GFP_KERNEL); - if (edid) - memcpy(edid, fb_firmware_edid(info->device), - EDID_LENGTH); + const u8 *e = fb_firmware_edid(info->device); + + if (e != NULL) { + edid = kmalloc(EDID_LENGTH, GFP_KERNEL); + if (edid) + memcpy(edid, e, EDID_LENGTH); + } } if (out_edid) 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); } diff --git a/drivers/video/savage/savagefb-i2c.c b/drivers/video/savage/savagefb-i2c.c index 959404a..3c98457 100644 --- a/drivers/video/savage/savagefb-i2c.c +++ b/drivers/video/savage/savagefb-i2c.c @@ -274,10 +274,13 @@ int savagefb_probe_i2c_connector(struct fb_info *info, u8 **out_edid) if (!edid) { /* try to get from firmware */ - edid = kmalloc(EDID_LENGTH, GFP_KERNEL); - if (edid) - memcpy(edid, fb_firmware_edid(info->device), - EDID_LENGTH); + const u8 *e = fb_firmware_edid(info->device); + + if (e) { + edid = kmalloc(EDID_LENGTH, GFP_KERNEL); + if (edid) + memcpy(edid, e, EDID_LENGTH); + } } if (out_edid) diff --git a/drivers/video/savage/savagefb.h b/drivers/video/savage/savagefb.h index d6f9474..ea17f7e 100644 --- a/drivers/video/savage/savagefb.h +++ b/drivers/video/savage/savagefb.h @@ -60,8 +60,6 @@ #define S3_SAVAGE_SERIES(chip) ((chip>=S3_SAVAGE3D) && (chip<=S3_SAVAGE2000)) -#define S3_MOBILE_TWISTER_SERIES(chip) ((chip==S3_TWISTER) || (chip == S3_PROSAVAGEDDR)) - /* Chip tags. These are used to group the adapters into * related families. */ @@ -74,8 +72,6 @@ typedef enum { S3_PROSAVAGE, S3_SUPERSAVAGE, S3_SAVAGE2000, - S3_PROSAVAGEDDR, - S3_TWISTER, S3_LAST } savage_chipset; diff --git a/drivers/video/savage/savagefb_driver.c b/drivers/video/savage/savagefb_driver.c index b5ca3ef..7c28545 100644 --- a/drivers/video/savage/savagefb_driver.c +++ b/drivers/video/savage/savagefb_driver.c @@ -1773,8 +1773,7 @@ static int __devinit savage_init_hw (struct savagefb_par *par) } } - if (S3_SAVAGE_MOBILE_SERIES(par->chip) || - (S3_MOBILE_TWISTER_SERIES(par->chip) && !par->crtonly)) + if (S3_SAVAGE_MOBILE_SERIES(par->chip) && !par->crtonly) par->display_type = DISP_LCD; else if (dvi || (par->chip == S3_SAVAGE4 && par->dvi)) par->display_type = DISP_DFP; @@ -1783,7 +1782,7 @@ static int __devinit savage_init_hw (struct savagefb_par *par) /* Check LCD panel parrmation */ - if (par->chip == S3_SAVAGE_MX) { + if (par->display_type == DISP_LCD) { unsigned char cr6b = VGArCR( 0x6b ); int panelX = (VGArSEQ (0x61) + @@ -1922,15 +1921,15 @@ static int __devinit savage_init_fb_info (struct fb_info *info, snprintf (info->fix.id, 16, "ProSavageKM"); break; case FB_ACCEL_S3TWISTER_P: - par->chip = S3_TWISTER; + par->chip = S3_PROSAVAGE; snprintf (info->fix.id, 16, "TwisterP"); break; case FB_ACCEL_S3TWISTER_K: - par->chip = S3_TWISTER; + par->chip = S3_PROSAVAGE; snprintf (info->fix.id, 16, "TwisterK"); break; case FB_ACCEL_PROSAVAGE_DDR: - par->chip = S3_PROSAVAGEDDR; + par->chip = S3_PROSAVAGE; snprintf (info->fix.id, 16, "ProSavageDDR"); break; case FB_ACCEL_PROSAVAGE_DDRK: |