diff options
Diffstat (limited to 'drivers')
133 files changed, 5835 insertions, 6318 deletions
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 0ce0c279aabf..b73116ef9236 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c | |||
@@ -159,7 +159,7 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, | |||
159 | static int cciss_getgeo(struct block_device *bdev, struct hd_geometry *geo); | 159 | static int cciss_getgeo(struct block_device *bdev, struct hd_geometry *geo); |
160 | 160 | ||
161 | static int cciss_revalidate(struct gendisk *disk); | 161 | static int cciss_revalidate(struct gendisk *disk); |
162 | static int rebuild_lun_table(ctlr_info_t *h, struct gendisk *del_disk); | 162 | static int rebuild_lun_table(ctlr_info_t *h, int first_time); |
163 | static int deregister_disk(struct gendisk *disk, drive_info_struct *drv, | 163 | static int deregister_disk(struct gendisk *disk, drive_info_struct *drv, |
164 | int clear_all); | 164 | int clear_all); |
165 | 165 | ||
@@ -171,7 +171,6 @@ static void cciss_geometry_inquiry(int ctlr, int logvol, | |||
171 | int withirq, sector_t total_size, | 171 | int withirq, sector_t total_size, |
172 | unsigned int block_size, InquiryData_struct *inq_buff, | 172 | unsigned int block_size, InquiryData_struct *inq_buff, |
173 | drive_info_struct *drv); | 173 | drive_info_struct *drv); |
174 | static void cciss_getgeometry(int cntl_num); | ||
175 | static void __devinit cciss_interrupt_mode(ctlr_info_t *, struct pci_dev *, | 174 | static void __devinit cciss_interrupt_mode(ctlr_info_t *, struct pci_dev *, |
176 | __u32); | 175 | __u32); |
177 | static void start_io(ctlr_info_t *h); | 176 | static void start_io(ctlr_info_t *h); |
@@ -929,8 +928,10 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, | |||
929 | return 0; | 928 | return 0; |
930 | } | 929 | } |
931 | 930 | ||
931 | case CCISS_DEREGDISK: | ||
932 | case CCISS_REGNEWD: | ||
932 | case CCISS_REVALIDVOLS: | 933 | case CCISS_REVALIDVOLS: |
933 | return rebuild_lun_table(host, NULL); | 934 | return rebuild_lun_table(host, 0); |
934 | 935 | ||
935 | case CCISS_GETLUNINFO:{ | 936 | case CCISS_GETLUNINFO:{ |
936 | LogvolInfo_struct luninfo; | 937 | LogvolInfo_struct luninfo; |
@@ -943,12 +944,6 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, | |||
943 | return -EFAULT; | 944 | return -EFAULT; |
944 | return 0; | 945 | return 0; |
945 | } | 946 | } |
946 | case CCISS_DEREGDISK: | ||
947 | return rebuild_lun_table(host, disk); | ||
948 | |||
949 | case CCISS_REGNEWD: | ||
950 | return rebuild_lun_table(host, NULL); | ||
951 | |||
952 | case CCISS_PASSTHRU: | 947 | case CCISS_PASSTHRU: |
953 | { | 948 | { |
954 | IOCTL_Command_struct iocommand; | 949 | IOCTL_Command_struct iocommand; |
@@ -1134,7 +1129,7 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, | |||
1134 | if (ioc->Request.Type.Direction == XFER_WRITE) { | 1129 | if (ioc->Request.Type.Direction == XFER_WRITE) { |
1135 | if (copy_from_user | 1130 | if (copy_from_user |
1136 | (buff[sg_used], data_ptr, sz)) { | 1131 | (buff[sg_used], data_ptr, sz)) { |
1137 | status = -ENOMEM; | 1132 | status = -EFAULT; |
1138 | goto cleanup1; | 1133 | goto cleanup1; |
1139 | } | 1134 | } |
1140 | } else { | 1135 | } else { |
@@ -1330,15 +1325,84 @@ static void cciss_softirq_done(struct request *rq) | |||
1330 | spin_unlock_irqrestore(&h->lock, flags); | 1325 | spin_unlock_irqrestore(&h->lock, flags); |
1331 | } | 1326 | } |
1332 | 1327 | ||
1328 | /* This function gets the serial number of a logical drive via | ||
1329 | * inquiry page 0x83. Serial no. is 16 bytes. If the serial | ||
1330 | * number cannot be had, for whatever reason, 16 bytes of 0xff | ||
1331 | * are returned instead. | ||
1332 | */ | ||
1333 | static void cciss_get_serial_no(int ctlr, int logvol, int withirq, | ||
1334 | unsigned char *serial_no, int buflen) | ||
1335 | { | ||
1336 | #define PAGE_83_INQ_BYTES 64 | ||
1337 | int rc; | ||
1338 | unsigned char *buf; | ||
1339 | |||
1340 | if (buflen > 16) | ||
1341 | buflen = 16; | ||
1342 | memset(serial_no, 0xff, buflen); | ||
1343 | buf = kzalloc(PAGE_83_INQ_BYTES, GFP_KERNEL); | ||
1344 | if (!buf) | ||
1345 | return; | ||
1346 | memset(serial_no, 0, buflen); | ||
1347 | if (withirq) | ||
1348 | rc = sendcmd_withirq(CISS_INQUIRY, ctlr, buf, | ||
1349 | PAGE_83_INQ_BYTES, 1, logvol, 0x83, TYPE_CMD); | ||
1350 | else | ||
1351 | rc = sendcmd(CISS_INQUIRY, ctlr, buf, | ||
1352 | PAGE_83_INQ_BYTES, 1, logvol, 0x83, NULL, TYPE_CMD); | ||
1353 | if (rc == IO_OK) | ||
1354 | memcpy(serial_no, &buf[8], buflen); | ||
1355 | kfree(buf); | ||
1356 | return; | ||
1357 | } | ||
1358 | |||
1359 | static void cciss_add_disk(ctlr_info_t *h, struct gendisk *disk, | ||
1360 | int drv_index) | ||
1361 | { | ||
1362 | disk->queue = blk_init_queue(do_cciss_request, &h->lock); | ||
1363 | sprintf(disk->disk_name, "cciss/c%dd%d", h->ctlr, drv_index); | ||
1364 | disk->major = h->major; | ||
1365 | disk->first_minor = drv_index << NWD_SHIFT; | ||
1366 | disk->fops = &cciss_fops; | ||
1367 | disk->private_data = &h->drv[drv_index]; | ||
1368 | |||
1369 | /* Set up queue information */ | ||
1370 | blk_queue_bounce_limit(disk->queue, h->pdev->dma_mask); | ||
1371 | |||
1372 | /* This is a hardware imposed limit. */ | ||
1373 | blk_queue_max_hw_segments(disk->queue, MAXSGENTRIES); | ||
1374 | |||
1375 | /* This is a limit in the driver and could be eliminated. */ | ||
1376 | blk_queue_max_phys_segments(disk->queue, MAXSGENTRIES); | ||
1377 | |||
1378 | blk_queue_max_sectors(disk->queue, h->cciss_max_sectors); | ||
1379 | |||
1380 | blk_queue_softirq_done(disk->queue, cciss_softirq_done); | ||
1381 | |||
1382 | disk->queue->queuedata = h; | ||
1383 | |||
1384 | blk_queue_hardsect_size(disk->queue, | ||
1385 | h->drv[drv_index].block_size); | ||
1386 | |||
1387 | /* Make sure all queue data is written out before */ | ||
1388 | /* setting h->drv[drv_index].queue, as setting this */ | ||
1389 | /* allows the interrupt handler to start the queue */ | ||
1390 | wmb(); | ||
1391 | h->drv[drv_index].queue = disk->queue; | ||
1392 | add_disk(disk); | ||
1393 | } | ||
1394 | |||
1333 | /* This function will check the usage_count of the drive to be updated/added. | 1395 | /* This function will check the usage_count of the drive to be updated/added. |
1334 | * If the usage_count is zero then the drive information will be updated and | 1396 | * If the usage_count is zero and it is a heretofore unknown drive, or, |
1335 | * the disk will be re-registered with the kernel. If not then it will be | 1397 | * the drive's capacity, geometry, or serial number has changed, |
1336 | * left alone for the next reboot. The exception to this is disk 0 which | 1398 | * then the drive information will be updated and the disk will be |
1337 | * will always be left registered with the kernel since it is also the | 1399 | * re-registered with the kernel. If these conditions don't hold, |
1338 | * controller node. Any changes to disk 0 will show up on the next | 1400 | * then it will be left alone for the next reboot. The exception to this |
1339 | * reboot. | 1401 | * is disk 0 which will always be left registered with the kernel since it |
1402 | * is also the controller node. Any changes to disk 0 will show up on | ||
1403 | * the next reboot. | ||
1340 | */ | 1404 | */ |
1341 | static void cciss_update_drive_info(int ctlr, int drv_index) | 1405 | static void cciss_update_drive_info(int ctlr, int drv_index, int first_time) |
1342 | { | 1406 | { |
1343 | ctlr_info_t *h = hba[ctlr]; | 1407 | ctlr_info_t *h = hba[ctlr]; |
1344 | struct gendisk *disk; | 1408 | struct gendisk *disk; |
@@ -1347,16 +1411,81 @@ static void cciss_update_drive_info(int ctlr, int drv_index) | |||
1347 | sector_t total_size; | 1411 | sector_t total_size; |
1348 | unsigned long flags = 0; | 1412 | unsigned long flags = 0; |
1349 | int ret = 0; | 1413 | int ret = 0; |
1414 | drive_info_struct *drvinfo; | ||
1415 | int was_only_controller_node; | ||
1416 | |||
1417 | /* Get information about the disk and modify the driver structure */ | ||
1418 | inq_buff = kmalloc(sizeof(InquiryData_struct), GFP_KERNEL); | ||
1419 | drvinfo = kmalloc(sizeof(*drvinfo), GFP_KERNEL); | ||
1420 | if (inq_buff == NULL || drvinfo == NULL) | ||
1421 | goto mem_msg; | ||
1422 | |||
1423 | /* See if we're trying to update the "controller node" | ||
1424 | * this will happen the when the first logical drive gets | ||
1425 | * created by ACU. | ||
1426 | */ | ||
1427 | was_only_controller_node = (drv_index == 0 && | ||
1428 | h->drv[0].raid_level == -1); | ||
1350 | 1429 | ||
1351 | /* if the disk already exists then deregister it before proceeding */ | 1430 | /* testing to see if 16-byte CDBs are already being used */ |
1352 | if (h->drv[drv_index].raid_level != -1) { | 1431 | if (h->cciss_read == CCISS_READ_16) { |
1432 | cciss_read_capacity_16(h->ctlr, drv_index, 1, | ||
1433 | &total_size, &block_size); | ||
1434 | |||
1435 | } else { | ||
1436 | cciss_read_capacity(ctlr, drv_index, 1, | ||
1437 | &total_size, &block_size); | ||
1438 | |||
1439 | /* if read_capacity returns all F's this volume is >2TB */ | ||
1440 | /* in size so we switch to 16-byte CDB's for all */ | ||
1441 | /* read/write ops */ | ||
1442 | if (total_size == 0xFFFFFFFFULL) { | ||
1443 | cciss_read_capacity_16(ctlr, drv_index, 1, | ||
1444 | &total_size, &block_size); | ||
1445 | h->cciss_read = CCISS_READ_16; | ||
1446 | h->cciss_write = CCISS_WRITE_16; | ||
1447 | } else { | ||
1448 | h->cciss_read = CCISS_READ_10; | ||
1449 | h->cciss_write = CCISS_WRITE_10; | ||
1450 | } | ||
1451 | } | ||
1452 | |||
1453 | cciss_geometry_inquiry(ctlr, drv_index, 1, total_size, block_size, | ||
1454 | inq_buff, drvinfo); | ||
1455 | drvinfo->block_size = block_size; | ||
1456 | drvinfo->nr_blocks = total_size + 1; | ||
1457 | |||
1458 | cciss_get_serial_no(ctlr, drv_index, 1, drvinfo->serial_no, | ||
1459 | sizeof(drvinfo->serial_no)); | ||
1460 | |||
1461 | /* Is it the same disk we already know, and nothing's changed? */ | ||
1462 | if (h->drv[drv_index].raid_level != -1 && | ||
1463 | ((memcmp(drvinfo->serial_no, | ||
1464 | h->drv[drv_index].serial_no, 16) == 0) && | ||
1465 | drvinfo->block_size == h->drv[drv_index].block_size && | ||
1466 | drvinfo->nr_blocks == h->drv[drv_index].nr_blocks && | ||
1467 | drvinfo->heads == h->drv[drv_index].heads && | ||
1468 | drvinfo->sectors == h->drv[drv_index].sectors && | ||
1469 | drvinfo->cylinders == h->drv[drv_index].cylinders)) | ||
1470 | /* The disk is unchanged, nothing to update */ | ||
1471 | goto freeret; | ||
1472 | |||
1473 | /* If we get here it's not the same disk, or something's changed, | ||
1474 | * so we need to * deregister it, and re-register it, if it's not | ||
1475 | * in use. | ||
1476 | * If the disk already exists then deregister it before proceeding | ||
1477 | * (unless it's the first disk (for the controller node). | ||
1478 | */ | ||
1479 | if (h->drv[drv_index].raid_level != -1 && drv_index != 0) { | ||
1480 | printk(KERN_WARNING "disk %d has changed.\n", drv_index); | ||
1353 | spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags); | 1481 | spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags); |
1354 | h->drv[drv_index].busy_configuring = 1; | 1482 | h->drv[drv_index].busy_configuring = 1; |
1355 | spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); | 1483 | spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); |
1356 | 1484 | ||
1357 | /* deregister_disk sets h->drv[drv_index].queue = NULL */ | 1485 | /* deregister_disk sets h->drv[drv_index].queue = NULL |
1358 | /* which keeps the interrupt handler from starting */ | 1486 | * which keeps the interrupt handler from starting |
1359 | /* the queue. */ | 1487 | * the queue. |
1488 | */ | ||
1360 | ret = deregister_disk(h->gendisk[drv_index], | 1489 | ret = deregister_disk(h->gendisk[drv_index], |
1361 | &h->drv[drv_index], 0); | 1490 | &h->drv[drv_index], 0); |
1362 | h->drv[drv_index].busy_configuring = 0; | 1491 | h->drv[drv_index].busy_configuring = 0; |
@@ -1364,81 +1493,37 @@ static void cciss_update_drive_info(int ctlr, int drv_index) | |||
1364 | 1493 | ||
1365 | /* If the disk is in use return */ | 1494 | /* If the disk is in use return */ |
1366 | if (ret) | 1495 | if (ret) |
1367 | return; | 1496 | goto freeret; |
1368 | 1497 | ||
1369 | /* Get information about the disk and modify the driver structure */ | 1498 | /* Save the new information from cciss_geometry_inquiry |
1370 | inq_buff = kmalloc(sizeof(InquiryData_struct), GFP_KERNEL); | 1499 | * and serial number inquiry. |
1371 | if (inq_buff == NULL) | 1500 | */ |
1372 | goto mem_msg; | 1501 | h->drv[drv_index].block_size = drvinfo->block_size; |
1373 | 1502 | h->drv[drv_index].nr_blocks = drvinfo->nr_blocks; | |
1374 | /* testing to see if 16-byte CDBs are already being used */ | 1503 | h->drv[drv_index].heads = drvinfo->heads; |
1375 | if (h->cciss_read == CCISS_READ_16) { | 1504 | h->drv[drv_index].sectors = drvinfo->sectors; |
1376 | cciss_read_capacity_16(h->ctlr, drv_index, 1, | 1505 | h->drv[drv_index].cylinders = drvinfo->cylinders; |
1377 | &total_size, &block_size); | 1506 | h->drv[drv_index].raid_level = drvinfo->raid_level; |
1378 | goto geo_inq; | 1507 | memcpy(h->drv[drv_index].serial_no, drvinfo->serial_no, 16); |
1379 | } | ||
1380 | |||
1381 | cciss_read_capacity(ctlr, drv_index, 1, | ||
1382 | &total_size, &block_size); | ||
1383 | |||
1384 | /* if read_capacity returns all F's this volume is >2TB in size */ | ||
1385 | /* so we switch to 16-byte CDB's for all read/write ops */ | ||
1386 | if (total_size == 0xFFFFFFFFULL) { | ||
1387 | cciss_read_capacity_16(ctlr, drv_index, 1, | ||
1388 | &total_size, &block_size); | ||
1389 | h->cciss_read = CCISS_READ_16; | ||
1390 | h->cciss_write = CCISS_WRITE_16; | ||
1391 | } else { | ||
1392 | h->cciss_read = CCISS_READ_10; | ||
1393 | h->cciss_write = CCISS_WRITE_10; | ||
1394 | } | ||
1395 | geo_inq: | ||
1396 | cciss_geometry_inquiry(ctlr, drv_index, 1, total_size, block_size, | ||
1397 | inq_buff, &h->drv[drv_index]); | ||
1398 | 1508 | ||
1399 | ++h->num_luns; | 1509 | ++h->num_luns; |
1400 | disk = h->gendisk[drv_index]; | 1510 | disk = h->gendisk[drv_index]; |
1401 | set_capacity(disk, h->drv[drv_index].nr_blocks); | 1511 | set_capacity(disk, h->drv[drv_index].nr_blocks); |
1402 | 1512 | ||
1403 | /* if it's the controller it's already added */ | 1513 | /* If it's not disk 0 (drv_index != 0) |
1404 | if (drv_index) { | 1514 | * or if it was disk 0, but there was previously |
1405 | disk->queue = blk_init_queue(do_cciss_request, &h->lock); | 1515 | * no actual corresponding configured logical drive |
1406 | sprintf(disk->disk_name, "cciss/c%dd%d", ctlr, drv_index); | 1516 | * (raid_leve == -1) then we want to update the |
1407 | disk->major = h->major; | 1517 | * logical drive's information. |
1408 | disk->first_minor = drv_index << NWD_SHIFT; | 1518 | */ |
1409 | disk->fops = &cciss_fops; | 1519 | if (drv_index || first_time) |
1410 | disk->private_data = &h->drv[drv_index]; | 1520 | cciss_add_disk(h, disk, drv_index); |
1411 | |||
1412 | /* Set up queue information */ | ||
1413 | blk_queue_bounce_limit(disk->queue, hba[ctlr]->pdev->dma_mask); | ||
1414 | |||
1415 | /* This is a hardware imposed limit. */ | ||
1416 | blk_queue_max_hw_segments(disk->queue, MAXSGENTRIES); | ||
1417 | |||
1418 | /* This is a limit in the driver and could be eliminated. */ | ||
1419 | blk_queue_max_phys_segments(disk->queue, MAXSGENTRIES); | ||
1420 | |||
1421 | blk_queue_max_sectors(disk->queue, h->cciss_max_sectors); | ||
1422 | |||
1423 | blk_queue_softirq_done(disk->queue, cciss_softirq_done); | ||
1424 | |||
1425 | disk->queue->queuedata = hba[ctlr]; | ||
1426 | |||
1427 | blk_queue_hardsect_size(disk->queue, | ||
1428 | hba[ctlr]->drv[drv_index].block_size); | ||
1429 | |||
1430 | /* Make sure all queue data is written out before */ | ||
1431 | /* setting h->drv[drv_index].queue, as setting this */ | ||
1432 | /* allows the interrupt handler to start the queue */ | ||
1433 | wmb(); | ||
1434 | h->drv[drv_index].queue = disk->queue; | ||
1435 | add_disk(disk); | ||
1436 | } | ||
1437 | 1521 | ||
1438 | freeret: | 1522 | freeret: |
1439 | kfree(inq_buff); | 1523 | kfree(inq_buff); |
1524 | kfree(drvinfo); | ||
1440 | return; | 1525 | return; |
1441 | mem_msg: | 1526 | mem_msg: |
1442 | printk(KERN_ERR "cciss: out of memory\n"); | 1527 | printk(KERN_ERR "cciss: out of memory\n"); |
1443 | goto freeret; | 1528 | goto freeret; |
1444 | } | 1529 | } |
@@ -1448,21 +1533,91 @@ geo_inq: | |||
1448 | * where new drives will be added. If the index to be returned is greater | 1533 | * where new drives will be added. If the index to be returned is greater |
1449 | * than the highest_lun index for the controller then highest_lun is set | 1534 | * than the highest_lun index for the controller then highest_lun is set |
1450 | * to this new index. If there are no available indexes then -1 is returned. | 1535 | * to this new index. If there are no available indexes then -1 is returned. |
1536 | * "controller_node" is used to know if this is a real logical drive, or just | ||
1537 | * the controller node, which determines if this counts towards highest_lun. | ||
1451 | */ | 1538 | */ |
1452 | static int cciss_find_free_drive_index(int ctlr) | 1539 | static int cciss_find_free_drive_index(int ctlr, int controller_node) |
1453 | { | 1540 | { |
1454 | int i; | 1541 | int i; |
1455 | 1542 | ||
1456 | for (i = 0; i < CISS_MAX_LUN; i++) { | 1543 | for (i = 0; i < CISS_MAX_LUN; i++) { |
1457 | if (hba[ctlr]->drv[i].raid_level == -1) { | 1544 | if (hba[ctlr]->drv[i].raid_level == -1) { |
1458 | if (i > hba[ctlr]->highest_lun) | 1545 | if (i > hba[ctlr]->highest_lun) |
1459 | hba[ctlr]->highest_lun = i; | 1546 | if (!controller_node) |
1547 | hba[ctlr]->highest_lun = i; | ||
1460 | return i; | 1548 | return i; |
1461 | } | 1549 | } |
1462 | } | 1550 | } |
1463 | return -1; | 1551 | return -1; |
1464 | } | 1552 | } |
1465 | 1553 | ||
1554 | /* cciss_add_gendisk finds a free hba[]->drv structure | ||
1555 | * and allocates a gendisk if needed, and sets the lunid | ||
1556 | * in the drvinfo structure. It returns the index into | ||
1557 | * the ->drv[] array, or -1 if none are free. | ||
1558 | * is_controller_node indicates whether highest_lun should | ||
1559 | * count this disk, or if it's only being added to provide | ||
1560 | * a means to talk to the controller in case no logical | ||
1561 | * drives have yet been configured. | ||
1562 | */ | ||
1563 | static int cciss_add_gendisk(ctlr_info_t *h, __u32 lunid, int controller_node) | ||
1564 | { | ||
1565 | int drv_index; | ||
1566 | |||
1567 | drv_index = cciss_find_free_drive_index(h->ctlr, controller_node); | ||
1568 | if (drv_index == -1) | ||
1569 | return -1; | ||
1570 | /*Check if the gendisk needs to be allocated */ | ||
1571 | if (!h->gendisk[drv_index]) { | ||
1572 | h->gendisk[drv_index] = | ||
1573 | alloc_disk(1 << NWD_SHIFT); | ||
1574 | if (!h->gendisk[drv_index]) { | ||
1575 | printk(KERN_ERR "cciss%d: could not " | ||
1576 | "allocate a new disk %d\n", | ||
1577 | h->ctlr, drv_index); | ||
1578 | return -1; | ||
1579 | } | ||
1580 | } | ||
1581 | h->drv[drv_index].LunID = lunid; | ||
1582 | |||
1583 | /* Don't need to mark this busy because nobody */ | ||
1584 | /* else knows about this disk yet to contend */ | ||
1585 | /* for access to it. */ | ||
1586 | h->drv[drv_index].busy_configuring = 0; | ||
1587 | wmb(); | ||
1588 | return drv_index; | ||
1589 | } | ||
1590 | |||
1591 | /* This is for the special case of a controller which | ||
1592 | * has no logical drives. In this case, we still need | ||
1593 | * to register a disk so the controller can be accessed | ||
1594 | * by the Array Config Utility. | ||
1595 | */ | ||
1596 | static void cciss_add_controller_node(ctlr_info_t *h) | ||
1597 | { | ||
1598 | struct gendisk *disk; | ||
1599 | int drv_index; | ||
1600 | |||
1601 | if (h->gendisk[0] != NULL) /* already did this? Then bail. */ | ||
1602 | return; | ||
1603 | |||
1604 | drv_index = cciss_add_gendisk(h, 0, 1); | ||
1605 | if (drv_index == -1) { | ||
1606 | printk(KERN_WARNING "cciss%d: could not " | ||
1607 | "add disk 0.\n", h->ctlr); | ||
1608 | return; | ||
1609 | } | ||
1610 | h->drv[drv_index].block_size = 512; | ||
1611 | h->drv[drv_index].nr_blocks = 0; | ||
1612 | h->drv[drv_index].heads = 0; | ||
1613 | h->drv[drv_index].sectors = 0; | ||
1614 | h->drv[drv_index].cylinders = 0; | ||
1615 | h->drv[drv_index].raid_level = -1; | ||
1616 | memset(h->drv[drv_index].serial_no, 0, 16); | ||
1617 | disk = h->gendisk[drv_index]; | ||
1618 | cciss_add_disk(h, disk, drv_index); | ||
1619 | } | ||
1620 | |||
1466 | /* This function will add and remove logical drives from the Logical | 1621 | /* This function will add and remove logical drives from the Logical |
1467 | * drive array of the controller and maintain persistency of ordering | 1622 | * drive array of the controller and maintain persistency of ordering |
1468 | * so that mount points are preserved until the next reboot. This allows | 1623 | * so that mount points are preserved until the next reboot. This allows |
@@ -1470,15 +1625,12 @@ static int cciss_find_free_drive_index(int ctlr) | |||
1470 | * without a re-ordering of those drives. | 1625 | * without a re-ordering of those drives. |
1471 | * INPUT | 1626 | * INPUT |
1472 | * h = The controller to perform the operations on | 1627 | * h = The controller to perform the operations on |
1473 | * del_disk = The disk to remove if specified. If the value given | ||
1474 | * is NULL then no disk is removed. | ||
1475 | */ | 1628 | */ |
1476 | static int rebuild_lun_table(ctlr_info_t *h, struct gendisk *del_disk) | 1629 | static int rebuild_lun_table(ctlr_info_t *h, int first_time) |
1477 | { | 1630 | { |
1478 | int ctlr = h->ctlr; | 1631 | int ctlr = h->ctlr; |
1479 | int num_luns; | 1632 | int num_luns; |
1480 | ReportLunData_struct *ld_buff = NULL; | 1633 | ReportLunData_struct *ld_buff = NULL; |
1481 | drive_info_struct *drv = NULL; | ||
1482 | int return_code; | 1634 | int return_code; |
1483 | int listlength = 0; | 1635 | int listlength = 0; |
1484 | int i; | 1636 | int i; |
@@ -1487,6 +1639,9 @@ static int rebuild_lun_table(ctlr_info_t *h, struct gendisk *del_disk) | |||
1487 | __u32 lunid = 0; | 1639 | __u32 lunid = 0; |
1488 | unsigned long flags; | 1640 | unsigned long flags; |
1489 | 1641 | ||
1642 | if (!capable(CAP_SYS_RAWIO)) | ||
1643 | return -EPERM; | ||
1644 | |||
1490 | /* Set busy_configuring flag for this operation */ | 1645 | /* Set busy_configuring flag for this operation */ |
1491 | spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags); | 1646 | spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags); |
1492 | if (h->busy_configuring) { | 1647 | if (h->busy_configuring) { |
@@ -1494,100 +1649,100 @@ static int rebuild_lun_table(ctlr_info_t *h, struct gendisk *del_disk) | |||
1494 | return -EBUSY; | 1649 | return -EBUSY; |
1495 | } | 1650 | } |
1496 | h->busy_configuring = 1; | 1651 | h->busy_configuring = 1; |
1652 | spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); | ||
1497 | 1653 | ||
1498 | /* if del_disk is NULL then we are being called to add a new disk | 1654 | ld_buff = kzalloc(sizeof(ReportLunData_struct), GFP_KERNEL); |
1499 | * and update the logical drive table. If it is not NULL then | 1655 | if (ld_buff == NULL) |
1500 | * we will check if the disk is in use or not. | 1656 | goto mem_msg; |
1501 | */ | ||
1502 | if (del_disk != NULL) { | ||
1503 | drv = get_drv(del_disk); | ||
1504 | drv->busy_configuring = 1; | ||
1505 | spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); | ||
1506 | return_code = deregister_disk(del_disk, drv, 1); | ||
1507 | drv->busy_configuring = 0; | ||
1508 | h->busy_configuring = 0; | ||
1509 | return return_code; | ||
1510 | } else { | ||
1511 | spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); | ||
1512 | if (!capable(CAP_SYS_RAWIO)) | ||
1513 | return -EPERM; | ||
1514 | 1657 | ||
1515 | ld_buff = kzalloc(sizeof(ReportLunData_struct), GFP_KERNEL); | 1658 | return_code = sendcmd_withirq(CISS_REPORT_LOG, ctlr, ld_buff, |
1516 | if (ld_buff == NULL) | 1659 | sizeof(ReportLunData_struct), 0, |
1517 | goto mem_msg; | 1660 | 0, 0, TYPE_CMD); |
1518 | |||
1519 | return_code = sendcmd_withirq(CISS_REPORT_LOG, ctlr, ld_buff, | ||
1520 | sizeof(ReportLunData_struct), 0, | ||
1521 | 0, 0, TYPE_CMD); | ||
1522 | |||
1523 | if (return_code == IO_OK) { | ||
1524 | listlength = | ||
1525 | be32_to_cpu(*(__be32 *) ld_buff->LUNListLength); | ||
1526 | } else { /* reading number of logical volumes failed */ | ||
1527 | printk(KERN_WARNING "cciss: report logical volume" | ||
1528 | " command failed\n"); | ||
1529 | listlength = 0; | ||
1530 | goto freeret; | ||
1531 | } | ||
1532 | 1661 | ||
1533 | num_luns = listlength / 8; /* 8 bytes per entry */ | 1662 | if (return_code == IO_OK) |
1534 | if (num_luns > CISS_MAX_LUN) { | 1663 | listlength = be32_to_cpu(*(__be32 *) ld_buff->LUNListLength); |
1535 | num_luns = CISS_MAX_LUN; | 1664 | else { /* reading number of logical volumes failed */ |
1536 | printk(KERN_WARNING "cciss: more luns configured" | 1665 | printk(KERN_WARNING "cciss: report logical volume" |
1537 | " on controller than can be handled by" | 1666 | " command failed\n"); |
1538 | " this driver.\n"); | 1667 | listlength = 0; |
1668 | goto freeret; | ||
1669 | } | ||
1670 | |||
1671 | num_luns = listlength / 8; /* 8 bytes per entry */ | ||
1672 | if (num_luns > CISS_MAX_LUN) { | ||
1673 | num_luns = CISS_MAX_LUN; | ||
1674 | printk(KERN_WARNING "cciss: more luns configured" | ||
1675 | " on controller than can be handled by" | ||
1676 | " this driver.\n"); | ||
1677 | } | ||
1678 | |||
1679 | if (num_luns == 0) | ||
1680 | cciss_add_controller_node(h); | ||
1681 | |||
1682 | /* Compare controller drive array to driver's drive array | ||
1683 | * to see if any drives are missing on the controller due | ||
1684 | * to action of Array Config Utility (user deletes drive) | ||
1685 | * and deregister logical drives which have disappeared. | ||
1686 | */ | ||
1687 | for (i = 0; i <= h->highest_lun; i++) { | ||
1688 | int j; | ||
1689 | drv_found = 0; | ||
1690 | for (j = 0; j < num_luns; j++) { | ||
1691 | memcpy(&lunid, &ld_buff->LUN[j][0], 4); | ||
1692 | lunid = le32_to_cpu(lunid); | ||
1693 | if (h->drv[i].LunID == lunid) { | ||
1694 | drv_found = 1; | ||
1695 | break; | ||
1696 | } | ||
1539 | } | 1697 | } |
1698 | if (!drv_found) { | ||
1699 | /* Deregister it from the OS, it's gone. */ | ||
1700 | spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags); | ||
1701 | h->drv[i].busy_configuring = 1; | ||
1702 | spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); | ||
1703 | return_code = deregister_disk(h->gendisk[i], | ||
1704 | &h->drv[i], 1); | ||
1705 | h->drv[i].busy_configuring = 0; | ||
1706 | } | ||
1707 | } | ||
1708 | |||
1709 | /* Compare controller drive array to driver's drive array. | ||
1710 | * Check for updates in the drive information and any new drives | ||
1711 | * on the controller due to ACU adding logical drives, or changing | ||
1712 | * a logical drive's size, etc. Reregister any new/changed drives | ||
1713 | */ | ||
1714 | for (i = 0; i < num_luns; i++) { | ||
1715 | int j; | ||
1540 | 1716 | ||
1541 | /* Compare controller drive array to drivers drive array. | 1717 | drv_found = 0; |
1542 | * Check for updates in the drive information and any new drives | 1718 | |
1543 | * on the controller. | 1719 | memcpy(&lunid, &ld_buff->LUN[i][0], 4); |
1720 | lunid = le32_to_cpu(lunid); | ||
1721 | |||
1722 | /* Find if the LUN is already in the drive array | ||
1723 | * of the driver. If so then update its info | ||
1724 | * if not in use. If it does not exist then find | ||
1725 | * the first free index and add it. | ||
1544 | */ | 1726 | */ |
1545 | for (i = 0; i < num_luns; i++) { | 1727 | for (j = 0; j <= h->highest_lun; j++) { |
1546 | int j; | 1728 | if (h->drv[j].raid_level != -1 && |
1547 | 1729 | h->drv[j].LunID == lunid) { | |
1548 | drv_found = 0; | 1730 | drv_index = j; |
1549 | 1731 | drv_found = 1; | |
1550 | lunid = (0xff & | 1732 | break; |
1551 | (unsigned int)(ld_buff->LUN[i][3])) << 24; | ||
1552 | lunid |= (0xff & | ||
1553 | (unsigned int)(ld_buff->LUN[i][2])) << 16; | ||
1554 | lunid |= (0xff & | ||
1555 | (unsigned int)(ld_buff->LUN[i][1])) << 8; | ||
1556 | lunid |= 0xff & (unsigned int)(ld_buff->LUN[i][0]); | ||
1557 | |||
1558 | /* Find if the LUN is already in the drive array | ||
1559 | * of the controller. If so then update its info | ||
1560 | * if not is use. If it does not exist then find | ||
1561 | * the first free index and add it. | ||
1562 | */ | ||
1563 | for (j = 0; j <= h->highest_lun; j++) { | ||
1564 | if (h->drv[j].LunID == lunid) { | ||
1565 | drv_index = j; | ||
1566 | drv_found = 1; | ||
1567 | } | ||
1568 | } | 1733 | } |
1734 | } | ||
1569 | 1735 | ||
1570 | /* check if the drive was found already in the array */ | 1736 | /* check if the drive was found already in the array */ |
1571 | if (!drv_found) { | 1737 | if (!drv_found) { |
1572 | drv_index = cciss_find_free_drive_index(ctlr); | 1738 | drv_index = cciss_add_gendisk(h, lunid, 0); |
1573 | if (drv_index == -1) | 1739 | if (drv_index == -1) |
1574 | goto freeret; | 1740 | goto freeret; |
1575 | 1741 | } | |
1576 | /*Check if the gendisk needs to be allocated */ | 1742 | cciss_update_drive_info(ctlr, drv_index, first_time); |
1577 | if (!h->gendisk[drv_index]){ | 1743 | } /* end for */ |
1578 | h->gendisk[drv_index] = alloc_disk(1 << NWD_SHIFT); | ||
1579 | if (!h->gendisk[drv_index]){ | ||
1580 | printk(KERN_ERR "cciss: could not allocate new disk %d\n", drv_index); | ||
1581 | goto mem_msg; | ||
1582 | } | ||
1583 | } | ||
1584 | } | ||
1585 | h->drv[drv_index].LunID = lunid; | ||
1586 | cciss_update_drive_info(ctlr, drv_index); | ||
1587 | } /* end for */ | ||
1588 | } /* end else */ | ||
1589 | 1744 | ||
1590 | freeret: | 1745 | freeret: |
1591 | kfree(ld_buff); | 1746 | kfree(ld_buff); |
1592 | h->busy_configuring = 0; | 1747 | h->busy_configuring = 0; |
1593 | /* We return -1 here to tell the ACU that we have registered/updated | 1748 | /* We return -1 here to tell the ACU that we have registered/updated |
@@ -1595,8 +1750,9 @@ static int rebuild_lun_table(ctlr_info_t *h, struct gendisk *del_disk) | |||
1595 | * additional times. | 1750 | * additional times. |
1596 | */ | 1751 | */ |
1597 | return -1; | 1752 | return -1; |
1598 | mem_msg: | 1753 | mem_msg: |
1599 | printk(KERN_ERR "cciss: out of memory\n"); | 1754 | printk(KERN_ERR "cciss: out of memory\n"); |
1755 | h->busy_configuring = 0; | ||
1600 | goto freeret; | 1756 | goto freeret; |
1601 | } | 1757 | } |
1602 | 1758 | ||
@@ -1652,15 +1808,15 @@ static int deregister_disk(struct gendisk *disk, drive_info_struct *drv, | |||
1652 | * other than disk 0 we will call put_disk. We do not | 1808 | * other than disk 0 we will call put_disk. We do not |
1653 | * do this for disk 0 as we need it to be able to | 1809 | * do this for disk 0 as we need it to be able to |
1654 | * configure the controller. | 1810 | * configure the controller. |
1655 | */ | 1811 | */ |
1656 | if (clear_all){ | 1812 | if (clear_all){ |
1657 | /* This isn't pretty, but we need to find the | 1813 | /* This isn't pretty, but we need to find the |
1658 | * disk in our array and NULL our the pointer. | 1814 | * disk in our array and NULL our the pointer. |
1659 | * This is so that we will call alloc_disk if | 1815 | * This is so that we will call alloc_disk if |
1660 | * this index is used again later. | 1816 | * this index is used again later. |
1661 | */ | 1817 | */ |
1662 | for (i=0; i < CISS_MAX_LUN; i++){ | 1818 | for (i=0; i < CISS_MAX_LUN; i++){ |
1663 | if(h->gendisk[i] == disk){ | 1819 | if (h->gendisk[i] == disk) { |
1664 | h->gendisk[i] = NULL; | 1820 | h->gendisk[i] = NULL; |
1665 | break; | 1821 | break; |
1666 | } | 1822 | } |
@@ -1688,7 +1844,7 @@ static int deregister_disk(struct gendisk *disk, drive_info_struct *drv, | |||
1688 | if (drv == h->drv + h->highest_lun) { | 1844 | if (drv == h->drv + h->highest_lun) { |
1689 | /* if so, find the new hightest lun */ | 1845 | /* if so, find the new hightest lun */ |
1690 | int i, newhighest = -1; | 1846 | int i, newhighest = -1; |
1691 | for (i = 0; i < h->highest_lun; i++) { | 1847 | for (i = 0; i <= h->highest_lun; i++) { |
1692 | /* if the disk has size > 0, it is available */ | 1848 | /* if the disk has size > 0, it is available */ |
1693 | if (h->drv[i].heads) | 1849 | if (h->drv[i].heads) |
1694 | newhighest = i; | 1850 | newhighest = i; |
@@ -3199,136 +3355,9 @@ err_out_free_res: | |||
3199 | return err; | 3355 | return err; |
3200 | } | 3356 | } |
3201 | 3357 | ||
3202 | /* | 3358 | /* Function to find the first free pointer into our hba[] array |
3203 | * Gets information about the local volumes attached to the controller. | 3359 | * Returns -1 if no free entries are left. |
3204 | */ | 3360 | */ |
3205 | static void cciss_getgeometry(int cntl_num) | ||
3206 | { | ||
3207 | ReportLunData_struct *ld_buff; | ||
3208 | InquiryData_struct *inq_buff; | ||
3209 | int return_code; | ||
3210 | int i; | ||
3211 | int listlength = 0; | ||
3212 | __u32 lunid = 0; | ||
3213 | unsigned block_size; | ||
3214 | sector_t total_size; | ||
3215 | |||
3216 | ld_buff = kzalloc(sizeof(ReportLunData_struct), GFP_KERNEL); | ||
3217 | if (ld_buff == NULL) { | ||
3218 | printk(KERN_ERR "cciss: out of memory\n"); | ||
3219 | return; | ||
3220 | } | ||
3221 | inq_buff = kmalloc(sizeof(InquiryData_struct), GFP_KERNEL); | ||
3222 | if (inq_buff == NULL) { | ||
3223 | printk(KERN_ERR "cciss: out of memory\n"); | ||
3224 | kfree(ld_buff); | ||
3225 | return; | ||
3226 | } | ||
3227 | /* Get the firmware version */ | ||
3228 | return_code = sendcmd(CISS_INQUIRY, cntl_num, inq_buff, | ||
3229 | sizeof(InquiryData_struct), 0, 0, 0, NULL, | ||
3230 | TYPE_CMD); | ||
3231 | if (return_code == IO_OK) { | ||
3232 | hba[cntl_num]->firm_ver[0] = inq_buff->data_byte[32]; | ||
3233 | hba[cntl_num]->firm_ver[1] = inq_buff->data_byte[33]; | ||
3234 | hba[cntl_num]->firm_ver[2] = inq_buff->data_byte[34]; | ||
3235 | hba[cntl_num]->firm_ver[3] = inq_buff->data_byte[35]; | ||
3236 | } else { /* send command failed */ | ||
3237 | |||
3238 | printk(KERN_WARNING "cciss: unable to determine firmware" | ||
3239 | " version of controller\n"); | ||
3240 | } | ||
3241 | /* Get the number of logical volumes */ | ||
3242 | return_code = sendcmd(CISS_REPORT_LOG, cntl_num, ld_buff, | ||
3243 | sizeof(ReportLunData_struct), 0, 0, 0, NULL, | ||
3244 | TYPE_CMD); | ||
3245 | |||
3246 | if (return_code == IO_OK) { | ||
3247 | #ifdef CCISS_DEBUG | ||
3248 | printk("LUN Data\n--------------------------\n"); | ||
3249 | #endif /* CCISS_DEBUG */ | ||
3250 | |||
3251 | listlength |= | ||
3252 | (0xff & (unsigned int)(ld_buff->LUNListLength[0])) << 24; | ||
3253 | listlength |= | ||
3254 | (0xff & (unsigned int)(ld_buff->LUNListLength[1])) << 16; | ||
3255 | listlength |= | ||
3256 | (0xff & (unsigned int)(ld_buff->LUNListLength[2])) << 8; | ||
3257 | listlength |= 0xff & (unsigned int)(ld_buff->LUNListLength[3]); | ||
3258 | } else { /* reading number of logical volumes failed */ | ||
3259 | |||
3260 | printk(KERN_WARNING "cciss: report logical volume" | ||
3261 | " command failed\n"); | ||
3262 | listlength = 0; | ||
3263 | } | ||
3264 | hba[cntl_num]->num_luns = listlength / 8; // 8 bytes pre entry | ||
3265 | if (hba[cntl_num]->num_luns > CISS_MAX_LUN) { | ||
3266 | printk(KERN_ERR | ||
3267 | "ciss: only %d number of logical volumes supported\n", | ||
3268 | CISS_MAX_LUN); | ||
3269 | hba[cntl_num]->num_luns = CISS_MAX_LUN; | ||
3270 | } | ||
3271 | #ifdef CCISS_DEBUG | ||
3272 | printk(KERN_DEBUG "Length = %x %x %x %x = %d\n", | ||
3273 | ld_buff->LUNListLength[0], ld_buff->LUNListLength[1], | ||
3274 | ld_buff->LUNListLength[2], ld_buff->LUNListLength[3], | ||
3275 | hba[cntl_num]->num_luns); | ||
3276 | #endif /* CCISS_DEBUG */ | ||
3277 | |||
3278 | hba[cntl_num]->highest_lun = hba[cntl_num]->num_luns - 1; | ||
3279 | for (i = 0; i < CISS_MAX_LUN; i++) { | ||
3280 | if (i < hba[cntl_num]->num_luns) { | ||
3281 | lunid = (0xff & (unsigned int)(ld_buff->LUN[i][3])) | ||
3282 | << 24; | ||
3283 | lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][2])) | ||
3284 | << 16; | ||
3285 | lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][1])) | ||
3286 | << 8; | ||
3287 | lunid |= 0xff & (unsigned int)(ld_buff->LUN[i][0]); | ||
3288 | |||
3289 | hba[cntl_num]->drv[i].LunID = lunid; | ||
3290 | |||
3291 | #ifdef CCISS_DEBUG | ||
3292 | printk(KERN_DEBUG "LUN[%d]: %x %x %x %x = %x\n", i, | ||
3293 | ld_buff->LUN[i][0], ld_buff->LUN[i][1], | ||
3294 | ld_buff->LUN[i][2], ld_buff->LUN[i][3], | ||
3295 | hba[cntl_num]->drv[i].LunID); | ||
3296 | #endif /* CCISS_DEBUG */ | ||
3297 | |||
3298 | /* testing to see if 16-byte CDBs are already being used */ | ||
3299 | if(hba[cntl_num]->cciss_read == CCISS_READ_16) { | ||
3300 | cciss_read_capacity_16(cntl_num, i, 0, | ||
3301 | &total_size, &block_size); | ||
3302 | goto geo_inq; | ||
3303 | } | ||
3304 | cciss_read_capacity(cntl_num, i, 0, &total_size, &block_size); | ||
3305 | |||
3306 | /* If read_capacity returns all F's the logical is >2TB */ | ||
3307 | /* so we switch to 16-byte CDBs for all read/write ops */ | ||
3308 | if(total_size == 0xFFFFFFFFULL) { | ||
3309 | cciss_read_capacity_16(cntl_num, i, 0, | ||
3310 | &total_size, &block_size); | ||
3311 | hba[cntl_num]->cciss_read = CCISS_READ_16; | ||
3312 | hba[cntl_num]->cciss_write = CCISS_WRITE_16; | ||
3313 | } else { | ||
3314 | hba[cntl_num]->cciss_read = CCISS_READ_10; | ||
3315 | hba[cntl_num]->cciss_write = CCISS_WRITE_10; | ||
3316 | } | ||
3317 | geo_inq: | ||
3318 | cciss_geometry_inquiry(cntl_num, i, 0, total_size, | ||
3319 | block_size, inq_buff, | ||
3320 | &hba[cntl_num]->drv[i]); | ||
3321 | } else { | ||
3322 | /* initialize raid_level to indicate a free space */ | ||
3323 | hba[cntl_num]->drv[i].raid_level = -1; | ||
3324 | } | ||
3325 | } | ||
3326 | kfree(ld_buff); | ||
3327 | kfree(inq_buff); | ||
3328 | } | ||
3329 | |||
3330 | /* Function to find the first free pointer into our hba[] array */ | ||
3331 | /* Returns -1 if no free entries are left. */ | ||
3332 | static int alloc_cciss_hba(void) | 3361 | static int alloc_cciss_hba(void) |
3333 | { | 3362 | { |
3334 | int i; | 3363 | int i; |
@@ -3340,11 +3369,6 @@ static int alloc_cciss_hba(void) | |||
3340 | p = kzalloc(sizeof(ctlr_info_t), GFP_KERNEL); | 3369 | p = kzalloc(sizeof(ctlr_info_t), GFP_KERNEL); |
3341 | if (!p) | 3370 | if (!p) |
3342 | goto Enomem; | 3371 | goto Enomem; |
3343 | p->gendisk[0] = alloc_disk(1 << NWD_SHIFT); | ||
3344 | if (!p->gendisk[0]) { | ||
3345 | kfree(p); | ||
3346 | goto Enomem; | ||
3347 | } | ||
3348 | hba[i] = p; | 3372 | hba[i] = p; |
3349 | return i; | 3373 | return i; |
3350 | } | 3374 | } |
@@ -3472,11 +3496,13 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, | |||
3472 | ((hba[i]->nr_cmds + BITS_PER_LONG - | 3496 | ((hba[i]->nr_cmds + BITS_PER_LONG - |
3473 | 1) / BITS_PER_LONG) * sizeof(unsigned long)); | 3497 | 1) / BITS_PER_LONG) * sizeof(unsigned long)); |
3474 | 3498 | ||
3475 | #ifdef CCISS_DEBUG | 3499 | hba[i]->num_luns = 0; |
3476 | printk(KERN_DEBUG "Scanning for drives on controller cciss%d\n", i); | 3500 | hba[i]->highest_lun = -1; |
3477 | #endif /* CCISS_DEBUG */ | 3501 | for (j = 0; j < CISS_MAX_LUN; j++) { |
3478 | 3502 | hba[i]->drv[j].raid_level = -1; | |
3479 | cciss_getgeometry(i); | 3503 | hba[i]->drv[j].queue = NULL; |
3504 | hba[i]->gendisk[j] = NULL; | ||
3505 | } | ||
3480 | 3506 | ||
3481 | cciss_scsi_setup(i); | 3507 | cciss_scsi_setup(i); |
3482 | 3508 | ||
@@ -3489,76 +3515,10 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, | |||
3489 | 3515 | ||
3490 | hba[i]->busy_initializing = 0; | 3516 | hba[i]->busy_initializing = 0; |
3491 | 3517 | ||
3492 | do { | 3518 | rebuild_lun_table(hba[i], 1); |
3493 | drive_info_struct *drv = &(hba[i]->drv[j]); | ||
3494 | struct gendisk *disk = hba[i]->gendisk[j]; | ||
3495 | struct request_queue *q; | ||
3496 | |||
3497 | /* Check if the disk was allocated already */ | ||
3498 | if (!disk){ | ||
3499 | hba[i]->gendisk[j] = alloc_disk(1 << NWD_SHIFT); | ||
3500 | disk = hba[i]->gendisk[j]; | ||
3501 | } | ||
3502 | |||
3503 | /* Check that the disk was able to be allocated */ | ||
3504 | if (!disk) { | ||
3505 | printk(KERN_ERR "cciss: unable to allocate memory for disk %d\n", j); | ||
3506 | goto clean4; | ||
3507 | } | ||
3508 | |||
3509 | q = blk_init_queue(do_cciss_request, &hba[i]->lock); | ||
3510 | if (!q) { | ||
3511 | printk(KERN_ERR | ||
3512 | "cciss: unable to allocate queue for disk %d\n", | ||
3513 | j); | ||
3514 | goto clean4; | ||
3515 | } | ||
3516 | drv->queue = q; | ||
3517 | |||
3518 | blk_queue_bounce_limit(q, hba[i]->pdev->dma_mask); | ||
3519 | |||
3520 | /* This is a hardware imposed limit. */ | ||
3521 | blk_queue_max_hw_segments(q, MAXSGENTRIES); | ||
3522 | |||
3523 | /* This is a limit in the driver and could be eliminated. */ | ||
3524 | blk_queue_max_phys_segments(q, MAXSGENTRIES); | ||
3525 | |||
3526 | blk_queue_max_sectors(q, hba[i]->cciss_max_sectors); | ||
3527 | |||
3528 | blk_queue_softirq_done(q, cciss_softirq_done); | ||
3529 | |||
3530 | q->queuedata = hba[i]; | ||
3531 | sprintf(disk->disk_name, "cciss/c%dd%d", i, j); | ||
3532 | disk->major = hba[i]->major; | ||
3533 | disk->first_minor = j << NWD_SHIFT; | ||
3534 | disk->fops = &cciss_fops; | ||
3535 | disk->queue = q; | ||
3536 | disk->private_data = drv; | ||
3537 | disk->driverfs_dev = &pdev->dev; | ||
3538 | /* we must register the controller even if no disks exist */ | ||
3539 | /* this is for the online array utilities */ | ||
3540 | if (!drv->heads && j) | ||
3541 | continue; | ||
3542 | blk_queue_hardsect_size(q, drv->block_size); | ||
3543 | set_capacity(disk, drv->nr_blocks); | ||
3544 | j++; | ||
3545 | } while (j <= hba[i]->highest_lun); | ||
3546 | |||
3547 | /* Make sure all queue data is written out before */ | ||
3548 | /* interrupt handler, triggered by add_disk, */ | ||
3549 | /* is allowed to start them. */ | ||
3550 | wmb(); | ||
3551 | |||
3552 | for (j = 0; j <= hba[i]->highest_lun; j++) | ||
3553 | add_disk(hba[i]->gendisk[j]); | ||
3554 | |||
3555 | /* we must register the controller even if no disks exist */ | ||
3556 | if (hba[i]->highest_lun == -1) | ||
3557 | add_disk(hba[i]->gendisk[0]); | ||
3558 | |||
3559 | return 1; | 3519 | return 1; |
3560 | 3520 | ||
3561 | clean4: | 3521 | clean4: |
3562 | #ifdef CONFIG_CISS_SCSI_TAPE | 3522 | #ifdef CONFIG_CISS_SCSI_TAPE |
3563 | kfree(hba[i]->scsi_rejects.complete); | 3523 | kfree(hba[i]->scsi_rejects.complete); |
3564 | #endif | 3524 | #endif |
@@ -3573,9 +3533,9 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, | |||
3573 | hba[i]->errinfo_pool, | 3533 | hba[i]->errinfo_pool, |
3574 | hba[i]->errinfo_pool_dhandle); | 3534 | hba[i]->errinfo_pool_dhandle); |
3575 | free_irq(hba[i]->intr[SIMPLE_MODE_INT], hba[i]); | 3535 | free_irq(hba[i]->intr[SIMPLE_MODE_INT], hba[i]); |
3576 | clean2: | 3536 | clean2: |
3577 | unregister_blkdev(hba[i]->major, hba[i]->devname); | 3537 | unregister_blkdev(hba[i]->major, hba[i]->devname); |
3578 | clean1: | 3538 | clean1: |
3579 | hba[i]->busy_initializing = 0; | 3539 | hba[i]->busy_initializing = 0; |
3580 | /* cleanup any queues that may have been initialized */ | 3540 | /* cleanup any queues that may have been initialized */ |
3581 | for (j=0; j <= hba[i]->highest_lun; j++){ | 3541 | for (j=0; j <= hba[i]->highest_lun; j++){ |
@@ -3654,7 +3614,9 @@ static void __devexit cciss_remove_one(struct pci_dev *pdev) | |||
3654 | } | 3614 | } |
3655 | } | 3615 | } |
3656 | 3616 | ||
3617 | #ifdef CONFIG_CISS_SCSI_TAPE | ||
3657 | cciss_unregister_scsi(i); /* unhook from SCSI subsystem */ | 3618 | cciss_unregister_scsi(i); /* unhook from SCSI subsystem */ |
3619 | #endif | ||
3658 | 3620 | ||
3659 | cciss_shutdown(pdev); | 3621 | cciss_shutdown(pdev); |
3660 | 3622 | ||
diff --git a/drivers/block/cciss.h b/drivers/block/cciss.h index b70988dd33ec..24a7efa993ab 100644 --- a/drivers/block/cciss.h +++ b/drivers/block/cciss.h | |||
@@ -39,6 +39,8 @@ typedef struct _drive_info_struct | |||
39 | *to prevent it from being opened or it's queue | 39 | *to prevent it from being opened or it's queue |
40 | *from being started. | 40 | *from being started. |
41 | */ | 41 | */ |
42 | __u8 serial_no[16]; /* from inquiry page 0x83, */ | ||
43 | /* not necc. null terminated. */ | ||
42 | } drive_info_struct; | 44 | } drive_info_struct; |
43 | 45 | ||
44 | #ifdef CONFIG_CISS_SCSI_TAPE | 46 | #ifdef CONFIG_CISS_SCSI_TAPE |
diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c index e4bf9a11ca0d..e1233aabda77 100644 --- a/drivers/block/cciss_scsi.c +++ b/drivers/block/cciss_scsi.c | |||
@@ -358,23 +358,68 @@ find_bus_target_lun(int ctlr, int *bus, int *target, int *lun) | |||
358 | } | 358 | } |
359 | return (!found); | 359 | return (!found); |
360 | } | 360 | } |
361 | struct scsi2map { | ||
362 | char scsi3addr[8]; | ||
363 | int bus, target, lun; | ||
364 | }; | ||
361 | 365 | ||
362 | static int | 366 | static int |
363 | cciss_scsi_add_entry(int ctlr, int hostno, | 367 | cciss_scsi_add_entry(int ctlr, int hostno, |
364 | unsigned char *scsi3addr, int devtype) | 368 | unsigned char *scsi3addr, int devtype, |
369 | struct scsi2map *added, int *nadded) | ||
365 | { | 370 | { |
366 | /* assumes hba[ctlr]->scsi_ctlr->lock is held */ | 371 | /* assumes hba[ctlr]->scsi_ctlr->lock is held */ |
367 | int n = ccissscsi[ctlr].ndevices; | 372 | int n = ccissscsi[ctlr].ndevices; |
368 | struct cciss_scsi_dev_t *sd; | 373 | struct cciss_scsi_dev_t *sd; |
374 | int i, bus, target, lun; | ||
375 | unsigned char addr1[8], addr2[8]; | ||
369 | 376 | ||
370 | if (n >= CCISS_MAX_SCSI_DEVS_PER_HBA) { | 377 | if (n >= CCISS_MAX_SCSI_DEVS_PER_HBA) { |
371 | printk("cciss%d: Too many devices, " | 378 | printk("cciss%d: Too many devices, " |
372 | "some will be inaccessible.\n", ctlr); | 379 | "some will be inaccessible.\n", ctlr); |
373 | return -1; | 380 | return -1; |
374 | } | 381 | } |
382 | |||
383 | bus = target = -1; | ||
384 | lun = 0; | ||
385 | /* Is this device a non-zero lun of a multi-lun device */ | ||
386 | /* byte 4 of the 8-byte LUN addr will contain the logical unit no. */ | ||
387 | if (scsi3addr[4] != 0) { | ||
388 | /* Search through our list and find the device which */ | ||
389 | /* has the same 8 byte LUN address, excepting byte 4. */ | ||
390 | /* Assign the same bus and target for this new LUN. */ | ||
391 | /* Use the logical unit number from the firmware. */ | ||
392 | memcpy(addr1, scsi3addr, 8); | ||
393 | addr1[4] = 0; | ||
394 | for (i = 0; i < n; i++) { | ||
395 | sd = &ccissscsi[ctlr].dev[i]; | ||
396 | memcpy(addr2, sd->scsi3addr, 8); | ||
397 | addr2[4] = 0; | ||
398 | /* differ only in byte 4? */ | ||
399 | if (memcmp(addr1, addr2, 8) == 0) { | ||
400 | bus = sd->bus; | ||
401 | target = sd->target; | ||
402 | lun = scsi3addr[4]; | ||
403 | break; | ||
404 | } | ||
405 | } | ||
406 | } | ||
407 | |||
375 | sd = &ccissscsi[ctlr].dev[n]; | 408 | sd = &ccissscsi[ctlr].dev[n]; |
376 | if (find_bus_target_lun(ctlr, &sd->bus, &sd->target, &sd->lun) != 0) | 409 | if (lun == 0) { |
377 | return -1; | 410 | if (find_bus_target_lun(ctlr, |
411 | &sd->bus, &sd->target, &sd->lun) != 0) | ||
412 | return -1; | ||
413 | } else { | ||
414 | sd->bus = bus; | ||
415 | sd->target = target; | ||
416 | sd->lun = lun; | ||
417 | } | ||
418 | added[*nadded].bus = sd->bus; | ||
419 | added[*nadded].target = sd->target; | ||
420 | added[*nadded].lun = sd->lun; | ||
421 | (*nadded)++; | ||
422 | |||
378 | memcpy(&sd->scsi3addr[0], scsi3addr, 8); | 423 | memcpy(&sd->scsi3addr[0], scsi3addr, 8); |
379 | sd->devtype = devtype; | 424 | sd->devtype = devtype; |
380 | ccissscsi[ctlr].ndevices++; | 425 | ccissscsi[ctlr].ndevices++; |
@@ -390,7 +435,8 @@ cciss_scsi_add_entry(int ctlr, int hostno, | |||
390 | } | 435 | } |
391 | 436 | ||
392 | static void | 437 | static void |
393 | cciss_scsi_remove_entry(int ctlr, int hostno, int entry) | 438 | cciss_scsi_remove_entry(int ctlr, int hostno, int entry, |
439 | struct scsi2map *removed, int *nremoved) | ||
394 | { | 440 | { |
395 | /* assumes hba[ctlr]->scsi_ctlr->lock is held */ | 441 | /* assumes hba[ctlr]->scsi_ctlr->lock is held */ |
396 | int i; | 442 | int i; |
@@ -398,6 +444,10 @@ cciss_scsi_remove_entry(int ctlr, int hostno, int entry) | |||
398 | 444 | ||
399 | if (entry < 0 || entry >= CCISS_MAX_SCSI_DEVS_PER_HBA) return; | 445 | if (entry < 0 || entry >= CCISS_MAX_SCSI_DEVS_PER_HBA) return; |
400 | sd = ccissscsi[ctlr].dev[entry]; | 446 | sd = ccissscsi[ctlr].dev[entry]; |
447 | removed[*nremoved].bus = sd.bus; | ||
448 | removed[*nremoved].target = sd.target; | ||
449 | removed[*nremoved].lun = sd.lun; | ||
450 | (*nremoved)++; | ||
401 | for (i=entry;i<ccissscsi[ctlr].ndevices-1;i++) | 451 | for (i=entry;i<ccissscsi[ctlr].ndevices-1;i++) |
402 | ccissscsi[ctlr].dev[i] = ccissscsi[ctlr].dev[i+1]; | 452 | ccissscsi[ctlr].dev[i] = ccissscsi[ctlr].dev[i+1]; |
403 | ccissscsi[ctlr].ndevices--; | 453 | ccissscsi[ctlr].ndevices--; |
@@ -417,6 +467,26 @@ cciss_scsi_remove_entry(int ctlr, int hostno, int entry) | |||
417 | (a)[1] == (b)[1] && \ | 467 | (a)[1] == (b)[1] && \ |
418 | (a)[0] == (b)[0]) | 468 | (a)[0] == (b)[0]) |
419 | 469 | ||
470 | static void fixup_botched_add(int ctlr, char *scsi3addr) | ||
471 | { | ||
472 | /* called when scsi_add_device fails in order to re-adjust */ | ||
473 | /* ccissscsi[] to match the mid layer's view. */ | ||
474 | unsigned long flags; | ||
475 | int i, j; | ||
476 | CPQ_TAPE_LOCK(ctlr, flags); | ||
477 | for (i = 0; i < ccissscsi[ctlr].ndevices; i++) { | ||
478 | if (memcmp(scsi3addr, | ||
479 | ccissscsi[ctlr].dev[i].scsi3addr, 8) == 0) { | ||
480 | for (j = i; j < ccissscsi[ctlr].ndevices-1; j++) | ||
481 | ccissscsi[ctlr].dev[j] = | ||
482 | ccissscsi[ctlr].dev[j+1]; | ||
483 | ccissscsi[ctlr].ndevices--; | ||
484 | break; | ||
485 | } | ||
486 | } | ||
487 | CPQ_TAPE_UNLOCK(ctlr, flags); | ||
488 | } | ||
489 | |||
420 | static int | 490 | static int |
421 | adjust_cciss_scsi_table(int ctlr, int hostno, | 491 | adjust_cciss_scsi_table(int ctlr, int hostno, |
422 | struct cciss_scsi_dev_t sd[], int nsds) | 492 | struct cciss_scsi_dev_t sd[], int nsds) |
@@ -429,13 +499,33 @@ adjust_cciss_scsi_table(int ctlr, int hostno, | |||
429 | int i,j, found, changes=0; | 499 | int i,j, found, changes=0; |
430 | struct cciss_scsi_dev_t *csd; | 500 | struct cciss_scsi_dev_t *csd; |
431 | unsigned long flags; | 501 | unsigned long flags; |
502 | struct scsi2map *added, *removed; | ||
503 | int nadded, nremoved; | ||
504 | struct Scsi_Host *sh = NULL; | ||
505 | |||
506 | added = kzalloc(sizeof(*added) * CCISS_MAX_SCSI_DEVS_PER_HBA, | ||
507 | GFP_KERNEL); | ||
508 | removed = kzalloc(sizeof(*removed) * CCISS_MAX_SCSI_DEVS_PER_HBA, | ||
509 | GFP_KERNEL); | ||
510 | |||
511 | if (!added || !removed) { | ||
512 | printk(KERN_WARNING "cciss%d: Out of memory in " | ||
513 | "adjust_cciss_scsi_table\n", ctlr); | ||
514 | goto free_and_out; | ||
515 | } | ||
432 | 516 | ||
433 | CPQ_TAPE_LOCK(ctlr, flags); | 517 | CPQ_TAPE_LOCK(ctlr, flags); |
434 | 518 | ||
519 | if (hostno != -1) /* if it's not the first time... */ | ||
520 | sh = ((struct cciss_scsi_adapter_data_t *) | ||
521 | hba[ctlr]->scsi_ctlr)->scsi_host; | ||
522 | |||
435 | /* find any devices in ccissscsi[] that are not in | 523 | /* find any devices in ccissscsi[] that are not in |
436 | sd[] and remove them from ccissscsi[] */ | 524 | sd[] and remove them from ccissscsi[] */ |
437 | 525 | ||
438 | i = 0; | 526 | i = 0; |
527 | nremoved = 0; | ||
528 | nadded = 0; | ||
439 | while(i<ccissscsi[ctlr].ndevices) { | 529 | while(i<ccissscsi[ctlr].ndevices) { |
440 | csd = &ccissscsi[ctlr].dev[i]; | 530 | csd = &ccissscsi[ctlr].dev[i]; |
441 | found=0; | 531 | found=0; |
@@ -455,8 +545,9 @@ adjust_cciss_scsi_table(int ctlr, int hostno, | |||
455 | /* printk("cciss%d: %s device c%db%dt%dl%d removed.\n", | 545 | /* printk("cciss%d: %s device c%db%dt%dl%d removed.\n", |
456 | ctlr, scsi_device_type(csd->devtype), hostno, | 546 | ctlr, scsi_device_type(csd->devtype), hostno, |
457 | csd->bus, csd->target, csd->lun); */ | 547 | csd->bus, csd->target, csd->lun); */ |
458 | cciss_scsi_remove_entry(ctlr, hostno, i); | 548 | cciss_scsi_remove_entry(ctlr, hostno, i, |
459 | /* note, i not incremented */ | 549 | removed, &nremoved); |
550 | /* remove ^^^, hence i not incremented */ | ||
460 | } | 551 | } |
461 | else if (found == 1) { /* device is different kind */ | 552 | else if (found == 1) { /* device is different kind */ |
462 | changes++; | 553 | changes++; |
@@ -464,8 +555,15 @@ adjust_cciss_scsi_table(int ctlr, int hostno, | |||
464 | "(device type now %s).\n", | 555 | "(device type now %s).\n", |
465 | ctlr, hostno, csd->bus, csd->target, csd->lun, | 556 | ctlr, hostno, csd->bus, csd->target, csd->lun, |
466 | scsi_device_type(csd->devtype)); | 557 | scsi_device_type(csd->devtype)); |
558 | cciss_scsi_remove_entry(ctlr, hostno, i, | ||
559 | removed, &nremoved); | ||
560 | /* remove ^^^, hence i not incremented */ | ||
561 | if (cciss_scsi_add_entry(ctlr, hostno, | ||
562 | &sd[j].scsi3addr[0], sd[j].devtype, | ||
563 | added, &nadded) != 0) | ||
564 | /* we just removed one, so add can't fail. */ | ||
565 | BUG(); | ||
467 | csd->devtype = sd[j].devtype; | 566 | csd->devtype = sd[j].devtype; |
468 | i++; /* so just move along. */ | ||
469 | } else /* device is same as it ever was, */ | 567 | } else /* device is same as it ever was, */ |
470 | i++; /* so just move along. */ | 568 | i++; /* so just move along. */ |
471 | } | 569 | } |
@@ -489,7 +587,9 @@ adjust_cciss_scsi_table(int ctlr, int hostno, | |||
489 | if (!found) { | 587 | if (!found) { |
490 | changes++; | 588 | changes++; |
491 | if (cciss_scsi_add_entry(ctlr, hostno, | 589 | if (cciss_scsi_add_entry(ctlr, hostno, |
492 | &sd[i].scsi3addr[0], sd[i].devtype) != 0) | 590 | |
591 | &sd[i].scsi3addr[0], sd[i].devtype, | ||
592 | added, &nadded) != 0) | ||
493 | break; | 593 | break; |
494 | } else if (found == 1) { | 594 | } else if (found == 1) { |
495 | /* should never happen... */ | 595 | /* should never happen... */ |
@@ -501,9 +601,50 @@ adjust_cciss_scsi_table(int ctlr, int hostno, | |||
501 | } | 601 | } |
502 | CPQ_TAPE_UNLOCK(ctlr, flags); | 602 | CPQ_TAPE_UNLOCK(ctlr, flags); |
503 | 603 | ||
504 | if (!changes) | 604 | /* Don't notify scsi mid layer of any changes the first time through */ |
505 | printk("cciss%d: No device changes detected.\n", ctlr); | 605 | /* (or if there are no changes) scsi_scan_host will do it later the */ |
606 | /* first time through. */ | ||
607 | if (hostno == -1 || !changes) | ||
608 | goto free_and_out; | ||
609 | |||
610 | /* Notify scsi mid layer of any removed devices */ | ||
611 | for (i = 0; i < nremoved; i++) { | ||
612 | struct scsi_device *sdev = | ||
613 | scsi_device_lookup(sh, removed[i].bus, | ||
614 | removed[i].target, removed[i].lun); | ||
615 | if (sdev != NULL) { | ||
616 | scsi_remove_device(sdev); | ||
617 | scsi_device_put(sdev); | ||
618 | } else { | ||
619 | /* We don't expect to get here. */ | ||
620 | /* future cmds to this device will get selection */ | ||
621 | /* timeout as if the device was gone. */ | ||
622 | printk(KERN_WARNING "cciss%d: didn't find " | ||
623 | "c%db%dt%dl%d\n for removal.", | ||
624 | ctlr, hostno, removed[i].bus, | ||
625 | removed[i].target, removed[i].lun); | ||
626 | } | ||
627 | } | ||
628 | |||
629 | /* Notify scsi mid layer of any added devices */ | ||
630 | for (i = 0; i < nadded; i++) { | ||
631 | int rc; | ||
632 | rc = scsi_add_device(sh, added[i].bus, | ||
633 | added[i].target, added[i].lun); | ||
634 | if (rc == 0) | ||
635 | continue; | ||
636 | printk(KERN_WARNING "cciss%d: scsi_add_device " | ||
637 | "c%db%dt%dl%d failed, device not added.\n", | ||
638 | ctlr, hostno, | ||
639 | added[i].bus, added[i].target, added[i].lun); | ||
640 | /* now we have to remove it from ccissscsi, */ | ||
641 | /* since it didn't get added to scsi mid layer */ | ||
642 | fixup_botched_add(ctlr, added[i].scsi3addr); | ||
643 | } | ||
506 | 644 | ||
645 | free_and_out: | ||
646 | kfree(added); | ||
647 | kfree(removed); | ||
507 | return 0; | 648 | return 0; |
508 | } | 649 | } |
509 | 650 | ||
@@ -1355,32 +1496,6 @@ cciss_unregister_scsi(int ctlr) | |||
1355 | } | 1496 | } |
1356 | 1497 | ||
1357 | static int | 1498 | static int |
1358 | cciss_register_scsi(int ctlr) | ||
1359 | { | ||
1360 | unsigned long flags; | ||
1361 | |||
1362 | CPQ_TAPE_LOCK(ctlr, flags); | ||
1363 | |||
1364 | /* Since this is really a block driver, the SCSI core may not be | ||
1365 | initialized at init time, in which case, calling scsi_register_host | ||
1366 | would hang. Instead, we do it later, via /proc filesystem | ||
1367 | and rc scripts, when we know SCSI core is good to go. */ | ||
1368 | |||
1369 | /* Only register if SCSI devices are detected. */ | ||
1370 | if (ccissscsi[ctlr].ndevices != 0) { | ||
1371 | ((struct cciss_scsi_adapter_data_t *) | ||
1372 | hba[ctlr]->scsi_ctlr)->registered = 1; | ||
1373 | CPQ_TAPE_UNLOCK(ctlr, flags); | ||
1374 | return cciss_scsi_detect(ctlr); | ||
1375 | } | ||
1376 | CPQ_TAPE_UNLOCK(ctlr, flags); | ||
1377 | printk(KERN_INFO | ||
1378 | "cciss%d: No appropriate SCSI device detected, " | ||
1379 | "SCSI subsystem not engaged.\n", ctlr); | ||
1380 | return 0; | ||
1381 | } | ||
1382 | |||
1383 | static int | ||
1384 | cciss_engage_scsi(int ctlr) | 1499 | cciss_engage_scsi(int ctlr) |
1385 | { | 1500 | { |
1386 | struct cciss_scsi_adapter_data_t *sa; | 1501 | struct cciss_scsi_adapter_data_t *sa; |
@@ -1391,15 +1506,15 @@ cciss_engage_scsi(int ctlr) | |||
1391 | sa = (struct cciss_scsi_adapter_data_t *) hba[ctlr]->scsi_ctlr; | 1506 | sa = (struct cciss_scsi_adapter_data_t *) hba[ctlr]->scsi_ctlr; |
1392 | stk = &sa->cmd_stack; | 1507 | stk = &sa->cmd_stack; |
1393 | 1508 | ||
1394 | if (((struct cciss_scsi_adapter_data_t *) | 1509 | if (sa->registered) { |
1395 | hba[ctlr]->scsi_ctlr)->registered) { | ||
1396 | printk("cciss%d: SCSI subsystem already engaged.\n", ctlr); | 1510 | printk("cciss%d: SCSI subsystem already engaged.\n", ctlr); |
1397 | spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags); | 1511 | spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags); |
1398 | return ENXIO; | 1512 | return ENXIO; |
1399 | } | 1513 | } |
1514 | sa->registered = 1; | ||
1400 | spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags); | 1515 | spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags); |
1401 | cciss_update_non_disk_devices(ctlr, -1); | 1516 | cciss_update_non_disk_devices(ctlr, -1); |
1402 | cciss_register_scsi(ctlr); | 1517 | cciss_scsi_detect(ctlr); |
1403 | return 0; | 1518 | return 0; |
1404 | } | 1519 | } |
1405 | 1520 | ||
@@ -1493,7 +1608,5 @@ static int cciss_eh_abort_handler(struct scsi_cmnd *scsicmd) | |||
1493 | /* If no tape support, then these become defined out of existence */ | 1608 | /* If no tape support, then these become defined out of existence */ |
1494 | 1609 | ||
1495 | #define cciss_scsi_setup(cntl_num) | 1610 | #define cciss_scsi_setup(cntl_num) |
1496 | #define cciss_unregister_scsi(ctlr) | ||
1497 | #define cciss_register_scsi(ctlr) | ||
1498 | 1611 | ||
1499 | #endif /* CONFIG_CISS_SCSI_TAPE */ | 1612 | #endif /* CONFIG_CISS_SCSI_TAPE */ |
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 9ae05c584234..3ca643cafccd 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c | |||
@@ -154,8 +154,8 @@ static int blkif_getgeo(struct block_device *bd, struct hd_geometry *hg) | |||
154 | return 0; | 154 | return 0; |
155 | } | 155 | } |
156 | 156 | ||
157 | int blkif_ioctl(struct inode *inode, struct file *filep, | 157 | static int blkif_ioctl(struct inode *inode, struct file *filep, |
158 | unsigned command, unsigned long argument) | 158 | unsigned command, unsigned long argument) |
159 | { | 159 | { |
160 | struct blkfront_info *info = | 160 | struct blkfront_info *info = |
161 | inode->i_bdev->bd_disk->private_data; | 161 | inode->i_bdev->bd_disk->private_data; |
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index d0ac944e1696..caff85149b9d 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig | |||
@@ -8,7 +8,7 @@ config VT | |||
8 | bool "Virtual terminal" if EMBEDDED | 8 | bool "Virtual terminal" if EMBEDDED |
9 | depends on !S390 | 9 | depends on !S390 |
10 | select INPUT | 10 | select INPUT |
11 | default y if !VIOCONS | 11 | default y |
12 | ---help--- | 12 | ---help--- |
13 | If you say Y here, you will get support for terminal devices with | 13 | If you say Y here, you will get support for terminal devices with |
14 | display and keyboard devices. These are called "virtual" because you | 14 | display and keyboard devices. These are called "virtual" because you |
diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 8a161c30e1dc..6850f6da7576 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile | |||
@@ -55,7 +55,6 @@ obj-$(CONFIG_RAW_DRIVER) += raw.o | |||
55 | obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o | 55 | obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o |
56 | obj-$(CONFIG_MSPEC) += mspec.o | 56 | obj-$(CONFIG_MSPEC) += mspec.o |
57 | obj-$(CONFIG_MMTIMER) += mmtimer.o | 57 | obj-$(CONFIG_MMTIMER) += mmtimer.o |
58 | obj-$(CONFIG_VIOCONS) += viocons.o | ||
59 | obj-$(CONFIG_VIOTAPE) += viotape.o | 58 | obj-$(CONFIG_VIOTAPE) += viotape.o |
60 | obj-$(CONFIG_HVCS) += hvcs.o | 59 | obj-$(CONFIG_HVCS) += hvcs.o |
61 | obj-$(CONFIG_IBM_BSR) += bsr.o | 60 | obj-$(CONFIG_IBM_BSR) += bsr.o |
diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c index 3530ff417a51..6e763e3f5a81 100644 --- a/drivers/char/amiserial.c +++ b/drivers/char/amiserial.c | |||
@@ -1254,7 +1254,7 @@ static int rs_break(struct tty_struct *tty, int break_state) | |||
1254 | unsigned long flags; | 1254 | unsigned long flags; |
1255 | 1255 | ||
1256 | if (serial_paranoia_check(info, tty->name, "rs_break")) | 1256 | if (serial_paranoia_check(info, tty->name, "rs_break")) |
1257 | return; | 1257 | return -EINVAL; |
1258 | 1258 | ||
1259 | local_irq_save(flags); | 1259 | local_irq_save(flags); |
1260 | if (break_state == -1) | 1260 | if (break_state == -1) |
diff --git a/drivers/char/viocons.c b/drivers/char/viocons.c deleted file mode 100644 index 65fb848e1cce..000000000000 --- a/drivers/char/viocons.c +++ /dev/null | |||
@@ -1,1171 +0,0 @@ | |||
1 | /* -*- linux-c -*- | ||
2 | * | ||
3 | * drivers/char/viocons.c | ||
4 | * | ||
5 | * iSeries Virtual Terminal | ||
6 | * | ||
7 | * Authors: Dave Boutcher <boutcher@us.ibm.com> | ||
8 | * Ryan Arnold <ryanarn@us.ibm.com> | ||
9 | * Colin Devilbiss <devilbis@us.ibm.com> | ||
10 | * Stephen Rothwell | ||
11 | * | ||
12 | * (C) Copyright 2000, 2001, 2002, 2003, 2004 IBM Corporation | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License as | ||
16 | * published by the Free Software Foundation; either version 2 of the | ||
17 | * License, or (at your option) anyu later version. | ||
18 | * | ||
19 | * This program is distributed in the hope that it will be useful, but | ||
20 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
22 | * General Public License for more details. | ||
23 | * | ||
24 | * You should have received a copy of the GNU General Public License | ||
25 | * along with this program; if not, write to the Free Software Foundation, | ||
26 | * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
27 | */ | ||
28 | #include <linux/kernel.h> | ||
29 | #include <linux/proc_fs.h> | ||
30 | #include <linux/errno.h> | ||
31 | #include <linux/vmalloc.h> | ||
32 | #include <linux/mm.h> | ||
33 | #include <linux/console.h> | ||
34 | #include <linux/module.h> | ||
35 | #include <asm/uaccess.h> | ||
36 | #include <linux/init.h> | ||
37 | #include <linux/wait.h> | ||
38 | #include <linux/spinlock.h> | ||
39 | #include <asm/ioctls.h> | ||
40 | #include <linux/kd.h> | ||
41 | #include <linux/tty.h> | ||
42 | #include <linux/tty_flip.h> | ||
43 | #include <linux/sysrq.h> | ||
44 | |||
45 | #include <asm/firmware.h> | ||
46 | #include <asm/iseries/vio.h> | ||
47 | #include <asm/iseries/hv_lp_event.h> | ||
48 | #include <asm/iseries/hv_call_event.h> | ||
49 | #include <asm/iseries/hv_lp_config.h> | ||
50 | #include <asm/iseries/hv_call.h> | ||
51 | |||
52 | #ifdef CONFIG_VT | ||
53 | #error You must turn off CONFIG_VT to use CONFIG_VIOCONS | ||
54 | #endif | ||
55 | |||
56 | #define VIOTTY_MAGIC (0x0DCB) | ||
57 | #define VTTY_PORTS 10 | ||
58 | |||
59 | #define VIOCONS_KERN_WARN KERN_WARNING "viocons: " | ||
60 | #define VIOCONS_KERN_INFO KERN_INFO "viocons: " | ||
61 | |||
62 | static DEFINE_SPINLOCK(consolelock); | ||
63 | static DEFINE_SPINLOCK(consoleloglock); | ||
64 | |||
65 | static int vio_sysrq_pressed; | ||
66 | |||
67 | #define VIOCHAR_NUM_BUF 16 | ||
68 | |||
69 | /* | ||
70 | * Our port information. We store a pointer to one entry in the | ||
71 | * tty_driver_data | ||
72 | */ | ||
73 | static struct port_info { | ||
74 | int magic; | ||
75 | struct tty_struct *tty; | ||
76 | HvLpIndex lp; | ||
77 | u8 vcons; | ||
78 | u64 seq; /* sequence number of last HV send */ | ||
79 | u64 ack; /* last ack from HV */ | ||
80 | /* | ||
81 | * When we get writes faster than we can send it to the partition, | ||
82 | * buffer the data here. Note that used is a bit map of used buffers. | ||
83 | * It had better have enough bits to hold VIOCHAR_NUM_BUF the bitops assume | ||
84 | * it is a multiple of unsigned long | ||
85 | */ | ||
86 | unsigned long used; | ||
87 | u8 *buffer[VIOCHAR_NUM_BUF]; | ||
88 | int bufferBytes[VIOCHAR_NUM_BUF]; | ||
89 | int curbuf; | ||
90 | int bufferOverflow; | ||
91 | int overflowMessage; | ||
92 | } port_info[VTTY_PORTS]; | ||
93 | |||
94 | #define viochar_is_console(pi) ((pi) == &port_info[0]) | ||
95 | #define viochar_port(pi) ((pi) - &port_info[0]) | ||
96 | |||
97 | static void initDataEvent(struct viocharlpevent *viochar, HvLpIndex lp); | ||
98 | |||
99 | static struct tty_driver *viotty_driver; | ||
100 | |||
101 | static void hvlog(char *fmt, ...) | ||
102 | { | ||
103 | int i; | ||
104 | unsigned long flags; | ||
105 | va_list args; | ||
106 | static char buf[256]; | ||
107 | |||
108 | spin_lock_irqsave(&consoleloglock, flags); | ||
109 | va_start(args, fmt); | ||
110 | i = vscnprintf(buf, sizeof(buf) - 1, fmt, args); | ||
111 | va_end(args); | ||
112 | buf[i++] = '\r'; | ||
113 | HvCall_writeLogBuffer(buf, i); | ||
114 | spin_unlock_irqrestore(&consoleloglock, flags); | ||
115 | } | ||
116 | |||
117 | static void hvlogOutput(const char *buf, int count) | ||
118 | { | ||
119 | unsigned long flags; | ||
120 | int begin; | ||
121 | int index; | ||
122 | static const char cr = '\r'; | ||
123 | |||
124 | begin = 0; | ||
125 | spin_lock_irqsave(&consoleloglock, flags); | ||
126 | for (index = 0; index < count; index++) { | ||
127 | if (buf[index] == '\n') { | ||
128 | /* | ||
129 | * Start right after the last '\n' or at the zeroth | ||
130 | * array position and output the number of characters | ||
131 | * including the newline. | ||
132 | */ | ||
133 | HvCall_writeLogBuffer(&buf[begin], index - begin + 1); | ||
134 | begin = index + 1; | ||
135 | HvCall_writeLogBuffer(&cr, 1); | ||
136 | } | ||
137 | } | ||
138 | if ((index - begin) > 0) | ||
139 | HvCall_writeLogBuffer(&buf[begin], index - begin); | ||
140 | spin_unlock_irqrestore(&consoleloglock, flags); | ||
141 | } | ||
142 | |||
143 | /* | ||
144 | * Make sure we're pointing to a valid port_info structure. Shamelessly | ||
145 | * plagerized from serial.c | ||
146 | */ | ||
147 | static inline int viotty_paranoia_check(struct port_info *pi, | ||
148 | char *name, const char *routine) | ||
149 | { | ||
150 | static const char *bad_pi_addr = VIOCONS_KERN_WARN | ||
151 | "warning: bad address for port_info struct (%s) in %s\n"; | ||
152 | static const char *badmagic = VIOCONS_KERN_WARN | ||
153 | "warning: bad magic number for port_info struct (%s) in %s\n"; | ||
154 | |||
155 | if ((pi < &port_info[0]) || (viochar_port(pi) > VTTY_PORTS)) { | ||
156 | printk(bad_pi_addr, name, routine); | ||
157 | return 1; | ||
158 | } | ||
159 | if (pi->magic != VIOTTY_MAGIC) { | ||
160 | printk(badmagic, name, routine); | ||
161 | return 1; | ||
162 | } | ||
163 | return 0; | ||
164 | } | ||
165 | |||
166 | /* | ||
167 | * Add data to our pending-send buffers. | ||
168 | * | ||
169 | * NOTE: Don't use printk in here because it gets nastily recursive. | ||
170 | * hvlog can be used to log to the hypervisor buffer | ||
171 | */ | ||
172 | static int buffer_add(struct port_info *pi, const char *buf, size_t len) | ||
173 | { | ||
174 | size_t bleft; | ||
175 | size_t curlen; | ||
176 | const char *curbuf; | ||
177 | int nextbuf; | ||
178 | |||
179 | curbuf = buf; | ||
180 | bleft = len; | ||
181 | while (bleft > 0) { | ||
182 | /* | ||
183 | * If there is no space left in the current buffer, we have | ||
184 | * filled everything up, so return. If we filled the previous | ||
185 | * buffer we would already have moved to the next one. | ||
186 | */ | ||
187 | if (pi->bufferBytes[pi->curbuf] == VIOCHAR_MAX_DATA) { | ||
188 | hvlog ("\n\rviocons: No overflow buffer available for memcpy().\n"); | ||
189 | pi->bufferOverflow++; | ||
190 | pi->overflowMessage = 1; | ||
191 | break; | ||
192 | } | ||
193 | |||
194 | /* | ||
195 | * Turn on the "used" bit for this buffer. If it's already on, | ||
196 | * that's fine. | ||
197 | */ | ||
198 | set_bit(pi->curbuf, &pi->used); | ||
199 | |||
200 | /* | ||
201 | * See if this buffer has been allocated. If not, allocate it. | ||
202 | */ | ||
203 | if (pi->buffer[pi->curbuf] == NULL) { | ||
204 | pi->buffer[pi->curbuf] = | ||
205 | kmalloc(VIOCHAR_MAX_DATA, GFP_ATOMIC); | ||
206 | if (pi->buffer[pi->curbuf] == NULL) { | ||
207 | hvlog("\n\rviocons: kmalloc failed allocating spaces for buffer %d.", | ||
208 | pi->curbuf); | ||
209 | break; | ||
210 | } | ||
211 | } | ||
212 | |||
213 | /* Figure out how much we can copy into this buffer. */ | ||
214 | if (bleft < (VIOCHAR_MAX_DATA - pi->bufferBytes[pi->curbuf])) | ||
215 | curlen = bleft; | ||
216 | else | ||
217 | curlen = VIOCHAR_MAX_DATA - pi->bufferBytes[pi->curbuf]; | ||
218 | |||
219 | /* Copy the data into the buffer. */ | ||
220 | memcpy(pi->buffer[pi->curbuf] + pi->bufferBytes[pi->curbuf], | ||
221 | curbuf, curlen); | ||
222 | |||
223 | pi->bufferBytes[pi->curbuf] += curlen; | ||
224 | curbuf += curlen; | ||
225 | bleft -= curlen; | ||
226 | |||
227 | /* | ||
228 | * Now see if we've filled this buffer. If not then | ||
229 | * we'll try to use it again later. If we've filled it | ||
230 | * up then we'll advance the curbuf to the next in the | ||
231 | * circular queue. | ||
232 | */ | ||
233 | if (pi->bufferBytes[pi->curbuf] == VIOCHAR_MAX_DATA) { | ||
234 | nextbuf = (pi->curbuf + 1) % VIOCHAR_NUM_BUF; | ||
235 | /* | ||
236 | * Move to the next buffer if it hasn't been used yet | ||
237 | */ | ||
238 | if (test_bit(nextbuf, &pi->used) == 0) | ||
239 | pi->curbuf = nextbuf; | ||
240 | } | ||
241 | } | ||
242 | return len - bleft; | ||
243 | } | ||
244 | |||
245 | /* | ||
246 | * Send pending data | ||
247 | * | ||
248 | * NOTE: Don't use printk in here because it gets nastily recursive. | ||
249 | * hvlog can be used to log to the hypervisor buffer | ||
250 | */ | ||
251 | static void send_buffers(struct port_info *pi) | ||
252 | { | ||
253 | HvLpEvent_Rc hvrc; | ||
254 | int nextbuf; | ||
255 | struct viocharlpevent *viochar; | ||
256 | unsigned long flags; | ||
257 | |||
258 | spin_lock_irqsave(&consolelock, flags); | ||
259 | |||
260 | viochar = (struct viocharlpevent *) | ||
261 | vio_get_event_buffer(viomajorsubtype_chario); | ||
262 | |||
263 | /* Make sure we got a buffer */ | ||
264 | if (viochar == NULL) { | ||
265 | hvlog("\n\rviocons: Can't get viochar buffer in sendBuffers()."); | ||
266 | spin_unlock_irqrestore(&consolelock, flags); | ||
267 | return; | ||
268 | } | ||
269 | |||
270 | if (pi->used == 0) { | ||
271 | hvlog("\n\rviocons: in sendbuffers(), but no buffers used.\n"); | ||
272 | vio_free_event_buffer(viomajorsubtype_chario, viochar); | ||
273 | spin_unlock_irqrestore(&consolelock, flags); | ||
274 | return; | ||
275 | } | ||
276 | |||
277 | /* | ||
278 | * curbuf points to the buffer we're filling. We want to | ||
279 | * start sending AFTER this one. | ||
280 | */ | ||
281 | nextbuf = (pi->curbuf + 1) % VIOCHAR_NUM_BUF; | ||
282 | |||
283 | /* | ||
284 | * Loop until we find a buffer with the used bit on | ||
285 | */ | ||
286 | while (test_bit(nextbuf, &pi->used) == 0) | ||
287 | nextbuf = (nextbuf + 1) % VIOCHAR_NUM_BUF; | ||
288 | |||
289 | initDataEvent(viochar, pi->lp); | ||
290 | |||
291 | /* | ||
292 | * While we have buffers with data, and our send window | ||
293 | * is open, send them | ||
294 | */ | ||
295 | while ((test_bit(nextbuf, &pi->used)) && | ||
296 | ((pi->seq - pi->ack) < VIOCHAR_WINDOW)) { | ||
297 | viochar->len = pi->bufferBytes[nextbuf]; | ||
298 | viochar->event.xCorrelationToken = pi->seq++; | ||
299 | viochar->event.xSizeMinus1 = | ||
300 | offsetof(struct viocharlpevent, data) + viochar->len; | ||
301 | |||
302 | memcpy(viochar->data, pi->buffer[nextbuf], viochar->len); | ||
303 | |||
304 | hvrc = HvCallEvent_signalLpEvent(&viochar->event); | ||
305 | if (hvrc) { | ||
306 | /* | ||
307 | * MUST unlock the spinlock before doing a printk | ||
308 | */ | ||
309 | vio_free_event_buffer(viomajorsubtype_chario, viochar); | ||
310 | spin_unlock_irqrestore(&consolelock, flags); | ||
311 | |||
312 | printk(VIOCONS_KERN_WARN | ||
313 | "error sending event! return code %d\n", | ||
314 | (int)hvrc); | ||
315 | return; | ||
316 | } | ||
317 | |||
318 | /* | ||
319 | * clear the used bit, zero the number of bytes in | ||
320 | * this buffer, and move to the next buffer | ||
321 | */ | ||
322 | clear_bit(nextbuf, &pi->used); | ||
323 | pi->bufferBytes[nextbuf] = 0; | ||
324 | nextbuf = (nextbuf + 1) % VIOCHAR_NUM_BUF; | ||
325 | } | ||
326 | |||
327 | /* | ||
328 | * If we have emptied all the buffers, start at 0 again. | ||
329 | * this will re-use any allocated buffers | ||
330 | */ | ||
331 | if (pi->used == 0) { | ||
332 | pi->curbuf = 0; | ||
333 | |||
334 | if (pi->overflowMessage) | ||
335 | pi->overflowMessage = 0; | ||
336 | |||
337 | if (pi->tty) { | ||
338 | tty_wakeup(pi->tty); | ||
339 | } | ||
340 | } | ||
341 | |||
342 | vio_free_event_buffer(viomajorsubtype_chario, viochar); | ||
343 | spin_unlock_irqrestore(&consolelock, flags); | ||
344 | } | ||
345 | |||
346 | /* | ||
347 | * Our internal writer. Gets called both from the console device and | ||
348 | * the tty device. the tty pointer will be NULL if called from the console. | ||
349 | * Return total number of bytes "written". | ||
350 | * | ||
351 | * NOTE: Don't use printk in here because it gets nastily recursive. hvlog | ||
352 | * can be used to log to the hypervisor buffer | ||
353 | */ | ||
354 | static int internal_write(struct port_info *pi, const char *buf, size_t len) | ||
355 | { | ||
356 | HvLpEvent_Rc hvrc; | ||
357 | size_t bleft; | ||
358 | size_t curlen; | ||
359 | const char *curbuf; | ||
360 | unsigned long flags; | ||
361 | struct viocharlpevent *viochar; | ||
362 | |||
363 | /* | ||
364 | * Write to the hvlog of inbound data are now done prior to | ||
365 | * calling internal_write() since internal_write() is only called in | ||
366 | * the event that an lp event path is active, which isn't the case for | ||
367 | * logging attempts prior to console initialization. | ||
368 | * | ||
369 | * If there is already data queued for this port, send it prior to | ||
370 | * attempting to send any new data. | ||
371 | */ | ||
372 | if (pi->used) | ||
373 | send_buffers(pi); | ||
374 | |||
375 | spin_lock_irqsave(&consolelock, flags); | ||
376 | |||
377 | viochar = vio_get_event_buffer(viomajorsubtype_chario); | ||
378 | if (viochar == NULL) { | ||
379 | spin_unlock_irqrestore(&consolelock, flags); | ||
380 | hvlog("\n\rviocons: Can't get vio buffer in internal_write()."); | ||
381 | return -EAGAIN; | ||
382 | } | ||
383 | initDataEvent(viochar, pi->lp); | ||
384 | |||
385 | curbuf = buf; | ||
386 | bleft = len; | ||
387 | |||
388 | while ((bleft > 0) && (pi->used == 0) && | ||
389 | ((pi->seq - pi->ack) < VIOCHAR_WINDOW)) { | ||
390 | if (bleft > VIOCHAR_MAX_DATA) | ||
391 | curlen = VIOCHAR_MAX_DATA; | ||
392 | else | ||
393 | curlen = bleft; | ||
394 | |||
395 | viochar->event.xCorrelationToken = pi->seq++; | ||
396 | memcpy(viochar->data, curbuf, curlen); | ||
397 | viochar->len = curlen; | ||
398 | viochar->event.xSizeMinus1 = | ||
399 | offsetof(struct viocharlpevent, data) + curlen; | ||
400 | |||
401 | hvrc = HvCallEvent_signalLpEvent(&viochar->event); | ||
402 | if (hvrc) { | ||
403 | hvlog("viocons: error sending event! %d\n", (int)hvrc); | ||
404 | goto out; | ||
405 | } | ||
406 | curbuf += curlen; | ||
407 | bleft -= curlen; | ||
408 | } | ||
409 | |||
410 | /* If we didn't send it all, buffer as much of it as we can. */ | ||
411 | if (bleft > 0) | ||
412 | bleft -= buffer_add(pi, curbuf, bleft); | ||
413 | out: | ||
414 | vio_free_event_buffer(viomajorsubtype_chario, viochar); | ||
415 | spin_unlock_irqrestore(&consolelock, flags); | ||
416 | return len - bleft; | ||
417 | } | ||
418 | |||
419 | static struct port_info *get_port_data(struct tty_struct *tty) | ||
420 | { | ||
421 | unsigned long flags; | ||
422 | struct port_info *pi; | ||
423 | |||
424 | spin_lock_irqsave(&consolelock, flags); | ||
425 | if (tty) { | ||
426 | pi = (struct port_info *)tty->driver_data; | ||
427 | if (!pi || viotty_paranoia_check(pi, tty->name, | ||
428 | "get_port_data")) { | ||
429 | pi = NULL; | ||
430 | } | ||
431 | } else | ||
432 | /* | ||
433 | * If this is the console device, use the lp from | ||
434 | * the first port entry | ||
435 | */ | ||
436 | pi = &port_info[0]; | ||
437 | spin_unlock_irqrestore(&consolelock, flags); | ||
438 | return pi; | ||
439 | } | ||
440 | |||
441 | /* | ||
442 | * Initialize the common fields in a charLpEvent | ||
443 | */ | ||
444 | static void initDataEvent(struct viocharlpevent *viochar, HvLpIndex lp) | ||
445 | { | ||
446 | struct HvLpEvent *hev = &viochar->event; | ||
447 | |||
448 | memset(viochar, 0, sizeof(struct viocharlpevent)); | ||
449 | |||
450 | hev->flags = HV_LP_EVENT_VALID | HV_LP_EVENT_DEFERRED_ACK | | ||
451 | HV_LP_EVENT_INT; | ||
452 | hev->xType = HvLpEvent_Type_VirtualIo; | ||
453 | hev->xSubtype = viomajorsubtype_chario | viochardata; | ||
454 | hev->xSourceLp = HvLpConfig_getLpIndex(); | ||
455 | hev->xTargetLp = lp; | ||
456 | hev->xSizeMinus1 = sizeof(struct viocharlpevent); | ||
457 | hev->xSourceInstanceId = viopath_sourceinst(lp); | ||
458 | hev->xTargetInstanceId = viopath_targetinst(lp); | ||
459 | } | ||
460 | |||
461 | /* | ||
462 | * early console device write | ||
463 | */ | ||
464 | static void viocons_write_early(struct console *co, const char *s, unsigned count) | ||
465 | { | ||
466 | hvlogOutput(s, count); | ||
467 | } | ||
468 | |||
469 | /* | ||
470 | * console device write | ||
471 | */ | ||
472 | static void viocons_write(struct console *co, const char *s, unsigned count) | ||
473 | { | ||
474 | int index; | ||
475 | int begin; | ||
476 | struct port_info *pi; | ||
477 | |||
478 | static const char cr = '\r'; | ||
479 | |||
480 | /* | ||
481 | * Check port data first because the target LP might be valid but | ||
482 | * simply not active, in which case we want to hvlog the output. | ||
483 | */ | ||
484 | pi = get_port_data(NULL); | ||
485 | if (pi == NULL) { | ||
486 | hvlog("\n\rviocons_write: unable to get port data."); | ||
487 | return; | ||
488 | } | ||
489 | |||
490 | hvlogOutput(s, count); | ||
491 | |||
492 | if (!viopath_isactive(pi->lp)) | ||
493 | return; | ||
494 | |||
495 | /* | ||
496 | * Any newline character found will cause a | ||
497 | * carriage return character to be emitted as well. | ||
498 | */ | ||
499 | begin = 0; | ||
500 | for (index = 0; index < count; index++) { | ||
501 | if (s[index] == '\n') { | ||
502 | /* | ||
503 | * Newline found. Print everything up to and | ||
504 | * including the newline | ||
505 | */ | ||
506 | internal_write(pi, &s[begin], index - begin + 1); | ||
507 | begin = index + 1; | ||
508 | /* Emit a carriage return as well */ | ||
509 | internal_write(pi, &cr, 1); | ||
510 | } | ||
511 | } | ||
512 | |||
513 | /* If any characters left to write, write them now */ | ||
514 | if ((index - begin) > 0) | ||
515 | internal_write(pi, &s[begin], index - begin); | ||
516 | } | ||
517 | |||
518 | /* | ||
519 | * Work out the device associate with this console | ||
520 | */ | ||
521 | static struct tty_driver *viocons_device(struct console *c, int *index) | ||
522 | { | ||
523 | *index = c->index; | ||
524 | return viotty_driver; | ||
525 | } | ||
526 | |||
527 | /* | ||
528 | * console device I/O methods | ||
529 | */ | ||
530 | static struct console viocons_early = { | ||
531 | .name = "viocons", | ||
532 | .write = viocons_write_early, | ||
533 | .flags = CON_PRINTBUFFER, | ||
534 | .index = -1, | ||
535 | }; | ||
536 | |||
537 | static struct console viocons = { | ||
538 | .name = "viocons", | ||
539 | .write = viocons_write, | ||
540 | .device = viocons_device, | ||
541 | .flags = CON_PRINTBUFFER, | ||
542 | .index = -1, | ||
543 | }; | ||
544 | |||
545 | /* | ||
546 | * TTY Open method | ||
547 | */ | ||
548 | static int viotty_open(struct tty_struct *tty, struct file *filp) | ||
549 | { | ||
550 | int port; | ||
551 | unsigned long flags; | ||
552 | struct port_info *pi; | ||
553 | |||
554 | port = tty->index; | ||
555 | |||
556 | if ((port < 0) || (port >= VTTY_PORTS)) | ||
557 | return -ENODEV; | ||
558 | |||
559 | spin_lock_irqsave(&consolelock, flags); | ||
560 | |||
561 | pi = &port_info[port]; | ||
562 | /* If some other TTY is already connected here, reject the open */ | ||
563 | if ((pi->tty) && (pi->tty != tty)) { | ||
564 | spin_unlock_irqrestore(&consolelock, flags); | ||
565 | printk(VIOCONS_KERN_WARN | ||
566 | "attempt to open device twice from different ttys\n"); | ||
567 | return -EBUSY; | ||
568 | } | ||
569 | tty->driver_data = pi; | ||
570 | pi->tty = tty; | ||
571 | spin_unlock_irqrestore(&consolelock, flags); | ||
572 | |||
573 | return 0; | ||
574 | } | ||
575 | |||
576 | /* | ||
577 | * TTY Close method | ||
578 | */ | ||
579 | static void viotty_close(struct tty_struct *tty, struct file *filp) | ||
580 | { | ||
581 | unsigned long flags; | ||
582 | struct port_info *pi; | ||
583 | |||
584 | spin_lock_irqsave(&consolelock, flags); | ||
585 | pi = (struct port_info *)tty->driver_data; | ||
586 | |||
587 | if (!pi || viotty_paranoia_check(pi, tty->name, "viotty_close")) { | ||
588 | spin_unlock_irqrestore(&consolelock, flags); | ||
589 | return; | ||
590 | } | ||
591 | if (tty->count == 1) | ||
592 | pi->tty = NULL; | ||
593 | spin_unlock_irqrestore(&consolelock, flags); | ||
594 | } | ||
595 | |||
596 | /* | ||
597 | * TTY Write method | ||
598 | */ | ||
599 | static int viotty_write(struct tty_struct *tty, const unsigned char *buf, | ||
600 | int count) | ||
601 | { | ||
602 | struct port_info *pi; | ||
603 | |||
604 | pi = get_port_data(tty); | ||
605 | if (pi == NULL) { | ||
606 | hvlog("\n\rviotty_write: no port data."); | ||
607 | return -ENODEV; | ||
608 | } | ||
609 | |||
610 | if (viochar_is_console(pi)) | ||
611 | hvlogOutput(buf, count); | ||
612 | |||
613 | /* | ||
614 | * If the path to this LP is closed, don't bother doing anything more. | ||
615 | * just dump the data on the floor and return count. For some reason | ||
616 | * some user level programs will attempt to probe available tty's and | ||
617 | * they'll attempt a viotty_write on an invalid port which maps to an | ||
618 | * invalid target lp. If this is the case then ignore the | ||
619 | * viotty_write call and, since the viopath isn't active to this | ||
620 | * partition, return count. | ||
621 | */ | ||
622 | if (!viopath_isactive(pi->lp)) | ||
623 | return count; | ||
624 | |||
625 | return internal_write(pi, buf, count); | ||
626 | } | ||
627 | |||
628 | /* | ||
629 | * TTY put_char method | ||
630 | */ | ||
631 | static int viotty_put_char(struct tty_struct *tty, unsigned char ch) | ||
632 | { | ||
633 | struct port_info *pi; | ||
634 | |||
635 | pi = get_port_data(tty); | ||
636 | if (pi == NULL) | ||
637 | return 0; | ||
638 | |||
639 | /* This will append '\r' as well if the char is '\n' */ | ||
640 | if (viochar_is_console(pi)) | ||
641 | hvlogOutput(&ch, 1); | ||
642 | |||
643 | if (viopath_isactive(pi->lp)) | ||
644 | internal_write(pi, &ch, 1); | ||
645 | return 1; | ||
646 | } | ||
647 | |||
648 | /* | ||
649 | * TTY write_room method | ||
650 | */ | ||
651 | static int viotty_write_room(struct tty_struct *tty) | ||
652 | { | ||
653 | int i; | ||
654 | int room = 0; | ||
655 | struct port_info *pi; | ||
656 | unsigned long flags; | ||
657 | |||
658 | spin_lock_irqsave(&consolelock, flags); | ||
659 | pi = (struct port_info *)tty->driver_data; | ||
660 | if (!pi || viotty_paranoia_check(pi, tty->name, "viotty_write_room")) { | ||
661 | spin_unlock_irqrestore(&consolelock, flags); | ||
662 | return 0; | ||
663 | } | ||
664 | |||
665 | /* If no buffers are used, return the max size. */ | ||
666 | if (pi->used == 0) { | ||
667 | spin_unlock_irqrestore(&consolelock, flags); | ||
668 | return VIOCHAR_MAX_DATA * VIOCHAR_NUM_BUF; | ||
669 | } | ||
670 | |||
671 | /* | ||
672 | * We retain the spinlock because we want to get an accurate | ||
673 | * count and it can change on us between each operation if we | ||
674 | * don't hold the spinlock. | ||
675 | */ | ||
676 | for (i = 0; ((i < VIOCHAR_NUM_BUF) && (room < VIOCHAR_MAX_DATA)); i++) | ||
677 | room += (VIOCHAR_MAX_DATA - pi->bufferBytes[i]); | ||
678 | spin_unlock_irqrestore(&consolelock, flags); | ||
679 | |||
680 | if (room > VIOCHAR_MAX_DATA) | ||
681 | room = VIOCHAR_MAX_DATA; | ||
682 | return room; | ||
683 | } | ||
684 | |||
685 | /* | ||
686 | * TTY chars_in_buffer method | ||
687 | */ | ||
688 | static int viotty_chars_in_buffer(struct tty_struct *tty) | ||
689 | { | ||
690 | return 0; | ||
691 | } | ||
692 | |||
693 | static int viotty_ioctl(struct tty_struct *tty, struct file *file, | ||
694 | unsigned int cmd, unsigned long arg) | ||
695 | { | ||
696 | switch (cmd) { | ||
697 | /* | ||
698 | * the ioctls below read/set the flags usually shown in the leds | ||
699 | * don't use them - they will go away without warning | ||
700 | */ | ||
701 | case KDGETLED: | ||
702 | case KDGKBLED: | ||
703 | return put_user(0, (char *)arg); | ||
704 | |||
705 | case KDSKBLED: | ||
706 | return 0; | ||
707 | } | ||
708 | /* FIXME: WTF is this being called for ??? */ | ||
709 | lock_kernel(); | ||
710 | ret = n_tty_ioctl(tty, file, cmd, arg); | ||
711 | unlock_kernel(); | ||
712 | return ret; | ||
713 | } | ||
714 | |||
715 | /* | ||
716 | * Handle an open charLpEvent. Could be either interrupt or ack | ||
717 | */ | ||
718 | static void vioHandleOpenEvent(struct HvLpEvent *event) | ||
719 | { | ||
720 | unsigned long flags; | ||
721 | struct viocharlpevent *cevent = (struct viocharlpevent *)event; | ||
722 | u8 port = cevent->virtual_device; | ||
723 | struct port_info *pi; | ||
724 | int reject = 0; | ||
725 | |||
726 | if (hvlpevent_is_ack(event)) { | ||
727 | if (port >= VTTY_PORTS) | ||
728 | return; | ||
729 | |||
730 | spin_lock_irqsave(&consolelock, flags); | ||
731 | /* Got the lock, don't cause console output */ | ||
732 | |||
733 | pi = &port_info[port]; | ||
734 | if (event->xRc == HvLpEvent_Rc_Good) { | ||
735 | pi->seq = pi->ack = 0; | ||
736 | /* | ||
737 | * This line allows connections from the primary | ||
738 | * partition but once one is connected from the | ||
739 | * primary partition nothing short of a reboot | ||
740 | * of linux will allow access from the hosting | ||
741 | * partition again without a required iSeries fix. | ||
742 | */ | ||
743 | pi->lp = event->xTargetLp; | ||
744 | } | ||
745 | |||
746 | spin_unlock_irqrestore(&consolelock, flags); | ||
747 | if (event->xRc != HvLpEvent_Rc_Good) | ||
748 | printk(VIOCONS_KERN_WARN | ||
749 | "handle_open_event: event->xRc == (%d).\n", | ||
750 | event->xRc); | ||
751 | |||
752 | if (event->xCorrelationToken != 0) { | ||
753 | atomic_t *aptr= (atomic_t *)event->xCorrelationToken; | ||
754 | atomic_set(aptr, 1); | ||
755 | } else | ||
756 | printk(VIOCONS_KERN_WARN | ||
757 | "weird...got open ack without atomic\n"); | ||
758 | return; | ||
759 | } | ||
760 | |||
761 | /* This had better require an ack, otherwise complain */ | ||
762 | if (!hvlpevent_need_ack(event)) { | ||
763 | printk(VIOCONS_KERN_WARN "viocharopen without ack bit!\n"); | ||
764 | return; | ||
765 | } | ||
766 | |||
767 | spin_lock_irqsave(&consolelock, flags); | ||
768 | /* Got the lock, don't cause console output */ | ||
769 | |||
770 | /* Make sure this is a good virtual tty */ | ||
771 | if (port >= VTTY_PORTS) { | ||
772 | event->xRc = HvLpEvent_Rc_SubtypeError; | ||
773 | cevent->subtype_result_code = viorc_openRejected; | ||
774 | /* | ||
775 | * Flag state here since we can't printk while holding | ||
776 | * a spinlock. | ||
777 | */ | ||
778 | reject = 1; | ||
779 | } else { | ||
780 | pi = &port_info[port]; | ||
781 | if ((pi->lp != HvLpIndexInvalid) && | ||
782 | (pi->lp != event->xSourceLp)) { | ||
783 | /* | ||
784 | * If this is tty is already connected to a different | ||
785 | * partition, fail. | ||
786 | */ | ||
787 | event->xRc = HvLpEvent_Rc_SubtypeError; | ||
788 | cevent->subtype_result_code = viorc_openRejected; | ||
789 | reject = 2; | ||
790 | } else { | ||
791 | pi->lp = event->xSourceLp; | ||
792 | event->xRc = HvLpEvent_Rc_Good; | ||
793 | cevent->subtype_result_code = viorc_good; | ||
794 | pi->seq = pi->ack = 0; | ||
795 | reject = 0; | ||
796 | } | ||
797 | } | ||
798 | |||
799 | spin_unlock_irqrestore(&consolelock, flags); | ||
800 | |||
801 | if (reject == 1) | ||
802 | printk(VIOCONS_KERN_WARN "open rejected: bad virtual tty.\n"); | ||
803 | else if (reject == 2) | ||
804 | printk(VIOCONS_KERN_WARN | ||
805 | "open rejected: console in exclusive use by another partition.\n"); | ||
806 | |||
807 | /* Return the acknowledgement */ | ||
808 | HvCallEvent_ackLpEvent(event); | ||
809 | } | ||
810 | |||
811 | /* | ||
812 | * Handle a close charLpEvent. This should ONLY be an Interrupt because the | ||
813 | * virtual console should never actually issue a close event to the hypervisor | ||
814 | * because the virtual console never goes away. A close event coming from the | ||
815 | * hypervisor simply means that there are no client consoles connected to the | ||
816 | * virtual console. | ||
817 | * | ||
818 | * Regardless of the number of connections masqueraded on the other side of | ||
819 | * the hypervisor ONLY ONE close event should be called to accompany the ONE | ||
820 | * open event that is called. The close event should ONLY be called when NO | ||
821 | * MORE connections (masqueraded or not) exist on the other side of the | ||
822 | * hypervisor. | ||
823 | */ | ||
824 | static void vioHandleCloseEvent(struct HvLpEvent *event) | ||
825 | { | ||
826 | unsigned long flags; | ||
827 | struct viocharlpevent *cevent = (struct viocharlpevent *)event; | ||
828 | u8 port = cevent->virtual_device; | ||
829 | |||
830 | if (hvlpevent_is_int(event)) { | ||
831 | if (port >= VTTY_PORTS) { | ||
832 | printk(VIOCONS_KERN_WARN | ||
833 | "close message from invalid virtual device.\n"); | ||
834 | return; | ||
835 | } | ||
836 | |||
837 | /* For closes, just mark the console partition invalid */ | ||
838 | spin_lock_irqsave(&consolelock, flags); | ||
839 | /* Got the lock, don't cause console output */ | ||
840 | |||
841 | if (port_info[port].lp == event->xSourceLp) | ||
842 | port_info[port].lp = HvLpIndexInvalid; | ||
843 | |||
844 | spin_unlock_irqrestore(&consolelock, flags); | ||
845 | printk(VIOCONS_KERN_INFO "close from %d\n", event->xSourceLp); | ||
846 | } else | ||
847 | printk(VIOCONS_KERN_WARN | ||
848 | "got unexpected close acknowlegement\n"); | ||
849 | } | ||
850 | |||
851 | /* | ||
852 | * Handle a config charLpEvent. Could be either interrupt or ack | ||
853 | */ | ||
854 | static void vioHandleConfig(struct HvLpEvent *event) | ||
855 | { | ||
856 | struct viocharlpevent *cevent = (struct viocharlpevent *)event; | ||
857 | |||
858 | HvCall_writeLogBuffer(cevent->data, cevent->len); | ||
859 | |||
860 | if (cevent->data[0] == 0x01) | ||
861 | printk(VIOCONS_KERN_INFO "window resized to %d: %d: %d: %d\n", | ||
862 | cevent->data[1], cevent->data[2], | ||
863 | cevent->data[3], cevent->data[4]); | ||
864 | else | ||
865 | printk(VIOCONS_KERN_WARN "unknown config event\n"); | ||
866 | } | ||
867 | |||
868 | /* | ||
869 | * Handle a data charLpEvent. | ||
870 | */ | ||
871 | static void vioHandleData(struct HvLpEvent *event) | ||
872 | { | ||
873 | struct tty_struct *tty; | ||
874 | unsigned long flags; | ||
875 | struct viocharlpevent *cevent = (struct viocharlpevent *)event; | ||
876 | struct port_info *pi; | ||
877 | int index; | ||
878 | int num_pushed; | ||
879 | u8 port = cevent->virtual_device; | ||
880 | |||
881 | if (port >= VTTY_PORTS) { | ||
882 | printk(VIOCONS_KERN_WARN "data on invalid virtual device %d\n", | ||
883 | port); | ||
884 | return; | ||
885 | } | ||
886 | |||
887 | /* | ||
888 | * Hold the spinlock so that we don't take an interrupt that | ||
889 | * changes tty between the time we fetch the port_info | ||
890 | * pointer and the time we paranoia check. | ||
891 | */ | ||
892 | spin_lock_irqsave(&consolelock, flags); | ||
893 | pi = &port_info[port]; | ||
894 | |||
895 | /* | ||
896 | * Change 05/01/2003 - Ryan Arnold: If a partition other than | ||
897 | * the current exclusive partition tries to send us data | ||
898 | * events then just drop them on the floor because we don't | ||
899 | * want his stinking data. He isn't authorized to receive | ||
900 | * data because he wasn't the first one to get the console, | ||
901 | * therefore he shouldn't be allowed to send data either. | ||
902 | * This will work without an iSeries fix. | ||
903 | */ | ||
904 | if (pi->lp != event->xSourceLp) { | ||
905 | spin_unlock_irqrestore(&consolelock, flags); | ||
906 | return; | ||
907 | } | ||
908 | |||
909 | tty = pi->tty; | ||
910 | if (tty == NULL) { | ||
911 | spin_unlock_irqrestore(&consolelock, flags); | ||
912 | printk(VIOCONS_KERN_WARN "no tty for virtual device %d\n", | ||
913 | port); | ||
914 | return; | ||
915 | } | ||
916 | |||
917 | if (tty->magic != TTY_MAGIC) { | ||
918 | spin_unlock_irqrestore(&consolelock, flags); | ||
919 | printk(VIOCONS_KERN_WARN "tty bad magic\n"); | ||
920 | return; | ||
921 | } | ||
922 | |||
923 | /* | ||
924 | * Just to be paranoid, make sure the tty points back to this port | ||
925 | */ | ||
926 | pi = (struct port_info *)tty->driver_data; | ||
927 | if (!pi || viotty_paranoia_check(pi, tty->name, "vioHandleData")) { | ||
928 | spin_unlock_irqrestore(&consolelock, flags); | ||
929 | return; | ||
930 | } | ||
931 | spin_unlock_irqrestore(&consolelock, flags); | ||
932 | |||
933 | /* | ||
934 | * Change 07/21/2003 - Ryan Arnold: functionality added to | ||
935 | * support sysrq utilizing ^O as the sysrq key. The sysrq | ||
936 | * functionality will only work if built into the kernel and | ||
937 | * then only if sysrq is enabled through the proc filesystem. | ||
938 | */ | ||
939 | num_pushed = 0; | ||
940 | for (index = 0; index < cevent->len; index++) { | ||
941 | /* | ||
942 | * Will be optimized away if !CONFIG_MAGIC_SYSRQ: | ||
943 | */ | ||
944 | if (sysrq_on()) { | ||
945 | /* 0x0f is the ascii character for ^O */ | ||
946 | if (cevent->data[index] == '\x0f') { | ||
947 | vio_sysrq_pressed = 1; | ||
948 | /* | ||
949 | * continue because we don't want to add | ||
950 | * the sysrq key into the data string. | ||
951 | */ | ||
952 | continue; | ||
953 | } else if (vio_sysrq_pressed) { | ||
954 | handle_sysrq(cevent->data[index], tty); | ||
955 | vio_sysrq_pressed = 0; | ||
956 | /* | ||
957 | * continue because we don't want to add | ||
958 | * the sysrq sequence into the data string. | ||
959 | */ | ||
960 | continue; | ||
961 | } | ||
962 | } | ||
963 | /* | ||
964 | * The sysrq sequence isn't included in this check if | ||
965 | * sysrq is enabled and compiled into the kernel because | ||
966 | * the sequence will never get inserted into the buffer. | ||
967 | * Don't attempt to copy more data into the buffer than we | ||
968 | * have room for because it would fail without indication. | ||
969 | */ | ||
970 | if(tty_insert_flip_char(tty, cevent->data[index], TTY_NORMAL) == 0) { | ||
971 | printk(VIOCONS_KERN_WARN "input buffer overflow!\n"); | ||
972 | break; | ||
973 | } | ||
974 | num_pushed++; | ||
975 | } | ||
976 | |||
977 | if (num_pushed) | ||
978 | tty_flip_buffer_push(tty); | ||
979 | } | ||
980 | |||
981 | /* | ||
982 | * Handle an ack charLpEvent. | ||
983 | */ | ||
984 | static void vioHandleAck(struct HvLpEvent *event) | ||
985 | { | ||
986 | struct viocharlpevent *cevent = (struct viocharlpevent *)event; | ||
987 | unsigned long flags; | ||
988 | u8 port = cevent->virtual_device; | ||
989 | |||
990 | if (port >= VTTY_PORTS) { | ||
991 | printk(VIOCONS_KERN_WARN "data on invalid virtual device\n"); | ||
992 | return; | ||
993 | } | ||
994 | |||
995 | spin_lock_irqsave(&consolelock, flags); | ||
996 | port_info[port].ack = event->xCorrelationToken; | ||
997 | spin_unlock_irqrestore(&consolelock, flags); | ||
998 | |||
999 | if (port_info[port].used) | ||
1000 | send_buffers(&port_info[port]); | ||
1001 | } | ||
1002 | |||
1003 | /* | ||
1004 | * Handle charLpEvents and route to the appropriate routine | ||
1005 | */ | ||
1006 | static void vioHandleCharEvent(struct HvLpEvent *event) | ||
1007 | { | ||
1008 | int charminor; | ||
1009 | |||
1010 | if (event == NULL) | ||
1011 | return; | ||
1012 | |||
1013 | charminor = event->xSubtype & VIOMINOR_SUBTYPE_MASK; | ||
1014 | switch (charminor) { | ||
1015 | case viocharopen: | ||
1016 | vioHandleOpenEvent(event); | ||
1017 | break; | ||
1018 | case viocharclose: | ||
1019 | vioHandleCloseEvent(event); | ||
1020 | break; | ||
1021 | case viochardata: | ||
1022 | vioHandleData(event); | ||
1023 | break; | ||
1024 | case viocharack: | ||
1025 | vioHandleAck(event); | ||
1026 | break; | ||
1027 | case viocharconfig: | ||
1028 | vioHandleConfig(event); | ||
1029 | break; | ||
1030 | default: | ||
1031 | if (hvlpevent_is_int(event) && hvlpevent_need_ack(event)) { | ||
1032 | event->xRc = HvLpEvent_Rc_InvalidSubtype; | ||
1033 | HvCallEvent_ackLpEvent(event); | ||
1034 | } | ||
1035 | } | ||
1036 | } | ||
1037 | |||
1038 | /* | ||
1039 | * Send an open event | ||
1040 | */ | ||
1041 | static int send_open(HvLpIndex remoteLp, void *sem) | ||
1042 | { | ||
1043 | return HvCallEvent_signalLpEventFast(remoteLp, | ||
1044 | HvLpEvent_Type_VirtualIo, | ||
1045 | viomajorsubtype_chario | viocharopen, | ||
1046 | HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, | ||
1047 | viopath_sourceinst(remoteLp), | ||
1048 | viopath_targetinst(remoteLp), | ||
1049 | (u64)(unsigned long)sem, VIOVERSION << 16, | ||
1050 | 0, 0, 0, 0); | ||
1051 | } | ||
1052 | |||
1053 | static const struct tty_operations serial_ops = { | ||
1054 | .open = viotty_open, | ||
1055 | .close = viotty_close, | ||
1056 | .write = viotty_write, | ||
1057 | .put_char = viotty_put_char, | ||
1058 | .write_room = viotty_write_room, | ||
1059 | .chars_in_buffer = viotty_chars_in_buffer, | ||
1060 | .ioctl = viotty_ioctl, | ||
1061 | }; | ||
1062 | |||
1063 | static int __init viocons_init2(void) | ||
1064 | { | ||
1065 | atomic_t wait_flag; | ||
1066 | int rc; | ||
1067 | |||
1068 | if (!firmware_has_feature(FW_FEATURE_ISERIES)) | ||
1069 | return -ENODEV; | ||
1070 | |||
1071 | /* +2 for fudge */ | ||
1072 | rc = viopath_open(HvLpConfig_getPrimaryLpIndex(), | ||
1073 | viomajorsubtype_chario, VIOCHAR_WINDOW + 2); | ||
1074 | if (rc) | ||
1075 | printk(VIOCONS_KERN_WARN "error opening to primary %d\n", rc); | ||
1076 | |||
1077 | if (viopath_hostLp == HvLpIndexInvalid) | ||
1078 | vio_set_hostlp(); | ||
1079 | |||
1080 | /* | ||
1081 | * And if the primary is not the same as the hosting LP, open to the | ||
1082 | * hosting lp | ||
1083 | */ | ||
1084 | if ((viopath_hostLp != HvLpIndexInvalid) && | ||
1085 | (viopath_hostLp != HvLpConfig_getPrimaryLpIndex())) { | ||
1086 | printk(VIOCONS_KERN_INFO "open path to hosting (%d)\n", | ||
1087 | viopath_hostLp); | ||
1088 | rc = viopath_open(viopath_hostLp, viomajorsubtype_chario, | ||
1089 | VIOCHAR_WINDOW + 2); /* +2 for fudge */ | ||
1090 | if (rc) | ||
1091 | printk(VIOCONS_KERN_WARN | ||
1092 | "error opening to partition %d: %d\n", | ||
1093 | viopath_hostLp, rc); | ||
1094 | } | ||
1095 | |||
1096 | if (vio_setHandler(viomajorsubtype_chario, vioHandleCharEvent) < 0) | ||
1097 | printk(VIOCONS_KERN_WARN | ||
1098 | "error seting handler for console events!\n"); | ||
1099 | |||
1100 | /* | ||
1101 | * First, try to open the console to the hosting lp. | ||
1102 | * Wait on a semaphore for the response. | ||
1103 | */ | ||
1104 | atomic_set(&wait_flag, 0); | ||
1105 | if ((viopath_isactive(viopath_hostLp)) && | ||
1106 | (send_open(viopath_hostLp, (void *)&wait_flag) == 0)) { | ||
1107 | printk(VIOCONS_KERN_INFO "hosting partition %d\n", | ||
1108 | viopath_hostLp); | ||
1109 | while (atomic_read(&wait_flag) == 0) | ||
1110 | mb(); | ||
1111 | atomic_set(&wait_flag, 0); | ||
1112 | } | ||
1113 | |||
1114 | /* | ||
1115 | * If we don't have an active console, try the primary | ||
1116 | */ | ||
1117 | if ((!viopath_isactive(port_info[0].lp)) && | ||
1118 | (viopath_isactive(HvLpConfig_getPrimaryLpIndex())) && | ||
1119 | (send_open(HvLpConfig_getPrimaryLpIndex(), (void *)&wait_flag) | ||
1120 | == 0)) { | ||
1121 | printk(VIOCONS_KERN_INFO "opening console to primary partition\n"); | ||
1122 | while (atomic_read(&wait_flag) == 0) | ||
1123 | mb(); | ||
1124 | } | ||
1125 | |||
1126 | /* Initialize the tty_driver structure */ | ||
1127 | viotty_driver = alloc_tty_driver(VTTY_PORTS); | ||
1128 | viotty_driver->owner = THIS_MODULE; | ||
1129 | viotty_driver->driver_name = "vioconsole"; | ||
1130 | viotty_driver->name = "tty"; | ||
1131 | viotty_driver->name_base = 1; | ||
1132 | viotty_driver->major = TTY_MAJOR; | ||
1133 | viotty_driver->minor_start = 1; | ||
1134 | viotty_driver->type = TTY_DRIVER_TYPE_CONSOLE; | ||
1135 | viotty_driver->subtype = 1; | ||
1136 | viotty_driver->init_termios = tty_std_termios; | ||
1137 | viotty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS; | ||
1138 | tty_set_operations(viotty_driver, &serial_ops); | ||
1139 | |||
1140 | if (tty_register_driver(viotty_driver)) { | ||
1141 | printk(VIOCONS_KERN_WARN "couldn't register console driver\n"); | ||
1142 | put_tty_driver(viotty_driver); | ||
1143 | viotty_driver = NULL; | ||
1144 | } | ||
1145 | |||
1146 | unregister_console(&viocons_early); | ||
1147 | register_console(&viocons); | ||
1148 | |||
1149 | return 0; | ||
1150 | } | ||
1151 | |||
1152 | static int __init viocons_init(void) | ||
1153 | { | ||
1154 | int i; | ||
1155 | |||
1156 | if (!firmware_has_feature(FW_FEATURE_ISERIES)) | ||
1157 | return -ENODEV; | ||
1158 | |||
1159 | printk(VIOCONS_KERN_INFO "registering console\n"); | ||
1160 | for (i = 0; i < VTTY_PORTS; i++) { | ||
1161 | port_info[i].lp = HvLpIndexInvalid; | ||
1162 | port_info[i].magic = VIOTTY_MAGIC; | ||
1163 | } | ||
1164 | HvCall_setLogBufferFormatAndCodepage(HvCall_LogBuffer_ASCII, 437); | ||
1165 | add_preferred_console("viocons", 0, NULL); | ||
1166 | register_console(&viocons_early); | ||
1167 | return 0; | ||
1168 | } | ||
1169 | |||
1170 | console_initcall(viocons_init); | ||
1171 | module_init(viocons_init2); | ||
diff --git a/drivers/firewire/fw-cdev.c b/drivers/firewire/fw-cdev.c index bc81d6fcd2fd..2e6d5848d217 100644 --- a/drivers/firewire/fw-cdev.c +++ b/drivers/firewire/fw-cdev.c | |||
@@ -369,22 +369,33 @@ complete_transaction(struct fw_card *card, int rcode, | |||
369 | struct response *response = data; | 369 | struct response *response = data; |
370 | struct client *client = response->client; | 370 | struct client *client = response->client; |
371 | unsigned long flags; | 371 | unsigned long flags; |
372 | struct fw_cdev_event_response *r = &response->response; | ||
372 | 373 | ||
373 | if (length < response->response.length) | 374 | if (length < r->length) |
374 | response->response.length = length; | 375 | r->length = length; |
375 | if (rcode == RCODE_COMPLETE) | 376 | if (rcode == RCODE_COMPLETE) |
376 | memcpy(response->response.data, payload, | 377 | memcpy(r->data, payload, r->length); |
377 | response->response.length); | ||
378 | 378 | ||
379 | spin_lock_irqsave(&client->lock, flags); | 379 | spin_lock_irqsave(&client->lock, flags); |
380 | list_del(&response->resource.link); | 380 | list_del(&response->resource.link); |
381 | spin_unlock_irqrestore(&client->lock, flags); | 381 | spin_unlock_irqrestore(&client->lock, flags); |
382 | 382 | ||
383 | response->response.type = FW_CDEV_EVENT_RESPONSE; | 383 | r->type = FW_CDEV_EVENT_RESPONSE; |
384 | response->response.rcode = rcode; | 384 | r->rcode = rcode; |
385 | queue_event(client, &response->event, &response->response, | 385 | |
386 | sizeof(response->response) + response->response.length, | 386 | /* |
387 | NULL, 0); | 387 | * In the case that sizeof(*r) doesn't align with the position of the |
388 | * data, and the read is short, preserve an extra copy of the data | ||
389 | * to stay compatible with a pre-2.6.27 bug. Since the bug is harmless | ||
390 | * for short reads and some apps depended on it, this is both safe | ||
391 | * and prudent for compatibility. | ||
392 | */ | ||
393 | if (r->length <= sizeof(*r) - offsetof(typeof(*r), data)) | ||
394 | queue_event(client, &response->event, r, sizeof(*r), | ||
395 | r->data, r->length); | ||
396 | else | ||
397 | queue_event(client, &response->event, r, sizeof(*r) + r->length, | ||
398 | NULL, 0); | ||
388 | } | 399 | } |
389 | 400 | ||
390 | static int ioctl_send_request(struct client *client, void *buffer) | 401 | static int ioctl_send_request(struct client *client, void *buffer) |
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index c882fd05cf29..bf4ebfb86fa5 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig | |||
@@ -57,6 +57,16 @@ config SENSORS_ABITUGURU3 | |||
57 | This driver can also be built as a module. If so, the module | 57 | This driver can also be built as a module. If so, the module |
58 | will be called abituguru3. | 58 | will be called abituguru3. |
59 | 59 | ||
60 | config SENSORS_AD7414 | ||
61 | tristate "Analog Devices AD7414" | ||
62 | depends on I2C && EXPERIMENTAL | ||
63 | help | ||
64 | If you say yes here you get support for the Analog Devices | ||
65 | AD7414 temperature monitoring chip. | ||
66 | |||
67 | This driver can also be built as a module. If so, the module | ||
68 | will be called ad7414. | ||
69 | |||
60 | config SENSORS_AD7418 | 70 | config SENSORS_AD7418 |
61 | tristate "Analog Devices AD7416, AD7417 and AD7418" | 71 | tristate "Analog Devices AD7416, AD7417 and AD7418" |
62 | depends on I2C && EXPERIMENTAL | 72 | depends on I2C && EXPERIMENTAL |
@@ -124,7 +134,7 @@ config SENSORS_ADM1031 | |||
124 | 134 | ||
125 | config SENSORS_ADM9240 | 135 | config SENSORS_ADM9240 |
126 | tristate "Analog Devices ADM9240 and compatibles" | 136 | tristate "Analog Devices ADM9240 and compatibles" |
127 | depends on I2C && EXPERIMENTAL | 137 | depends on I2C |
128 | select HWMON_VID | 138 | select HWMON_VID |
129 | help | 139 | help |
130 | If you say yes here you get support for Analog Devices ADM9240, | 140 | If you say yes here you get support for Analog Devices ADM9240, |
@@ -575,8 +585,8 @@ config SENSORS_DME1737 | |||
575 | select HWMON_VID | 585 | select HWMON_VID |
576 | help | 586 | help |
577 | If you say yes here you get support for the hardware monitoring | 587 | If you say yes here you get support for the hardware monitoring |
578 | and fan control features of the SMSC DME1737 (and compatibles | 588 | and fan control features of the SMSC DME1737, SCH311x, SCH5027, and |
579 | like the Asus A8000) and SCH311x Super-I/O chips. | 589 | Asus A8000 Super-I/O chips. |
580 | 590 | ||
581 | This driver can also be built as a module. If so, the module | 591 | This driver can also be built as a module. If so, the module |
582 | will be called dme1737. | 592 | will be called dme1737. |
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index d098677e08de..7943e5cefb06 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile | |||
@@ -15,6 +15,7 @@ obj-$(CONFIG_SENSORS_W83791D) += w83791d.o | |||
15 | 15 | ||
16 | obj-$(CONFIG_SENSORS_ABITUGURU) += abituguru.o | 16 | obj-$(CONFIG_SENSORS_ABITUGURU) += abituguru.o |
17 | obj-$(CONFIG_SENSORS_ABITUGURU3)+= abituguru3.o | 17 | obj-$(CONFIG_SENSORS_ABITUGURU3)+= abituguru3.o |
18 | obj-$(CONFIG_SENSORS_AD7414) += ad7414.o | ||
18 | obj-$(CONFIG_SENSORS_AD7418) += ad7418.o | 19 | obj-$(CONFIG_SENSORS_AD7418) += ad7418.o |
19 | obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o | 20 | obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o |
20 | obj-$(CONFIG_SENSORS_ADM1025) += adm1025.o | 21 | obj-$(CONFIG_SENSORS_ADM1025) += adm1025.o |
diff --git a/drivers/hwmon/ad7414.c b/drivers/hwmon/ad7414.c new file mode 100644 index 000000000000..ce8d94fbfd7e --- /dev/null +++ b/drivers/hwmon/ad7414.c | |||
@@ -0,0 +1,268 @@ | |||
1 | /* | ||
2 | * An hwmon driver for the Analog Devices AD7414 | ||
3 | * | ||
4 | * Copyright 2006 Stefan Roese <sr at denx.de>, DENX Software Engineering | ||
5 | * | ||
6 | * Copyright (c) 2008 PIKA Technologies | ||
7 | * Sean MacLennan <smaclennan@pikatech.com> | ||
8 | * | ||
9 | * Copyright (c) 2008 Spansion Inc. | ||
10 | * Frank Edelhaeuser <frank.edelhaeuser at spansion.com> | ||
11 | * (converted to "new style" I2C driver model, removed checkpatch.pl warnings) | ||
12 | * | ||
13 | * Based on ad7418.c | ||
14 | * Copyright 2006 Tower Technologies, Alessandro Zummo <a.zummo at towertech.it> | ||
15 | * | ||
16 | * This program is free software; you can redistribute it and/or modify | ||
17 | * it under the terms of the GNU General Public License as published by | ||
18 | * the Free Software Foundation; either version 2 of the License, or | ||
19 | * (at your option) any later version. | ||
20 | */ | ||
21 | |||
22 | #include <linux/module.h> | ||
23 | #include <linux/jiffies.h> | ||
24 | #include <linux/i2c.h> | ||
25 | #include <linux/hwmon.h> | ||
26 | #include <linux/hwmon-sysfs.h> | ||
27 | #include <linux/err.h> | ||
28 | #include <linux/mutex.h> | ||
29 | #include <linux/sysfs.h> | ||
30 | |||
31 | |||
32 | /* AD7414 registers */ | ||
33 | #define AD7414_REG_TEMP 0x00 | ||
34 | #define AD7414_REG_CONF 0x01 | ||
35 | #define AD7414_REG_T_HIGH 0x02 | ||
36 | #define AD7414_REG_T_LOW 0x03 | ||
37 | |||
38 | static u8 AD7414_REG_LIMIT[] = { AD7414_REG_T_HIGH, AD7414_REG_T_LOW }; | ||
39 | |||
40 | struct ad7414_data { | ||
41 | struct device *hwmon_dev; | ||
42 | struct mutex lock; /* atomic read data updates */ | ||
43 | char valid; /* !=0 if following fields are valid */ | ||
44 | unsigned long next_update; /* In jiffies */ | ||
45 | s16 temp_input; /* Register values */ | ||
46 | s8 temps[ARRAY_SIZE(AD7414_REG_LIMIT)]; | ||
47 | }; | ||
48 | |||
49 | /* REG: (0.25C/bit, two's complement) << 6 */ | ||
50 | static inline int ad7414_temp_from_reg(s16 reg) | ||
51 | { | ||
52 | /* use integer division instead of equivalent right shift to | ||
53 | * guarantee arithmetic shift and preserve the sign | ||
54 | */ | ||
55 | return ((int)reg / 64) * 250; | ||
56 | } | ||
57 | |||
58 | static inline int ad7414_read(struct i2c_client *client, u8 reg) | ||
59 | { | ||
60 | if (reg == AD7414_REG_TEMP) { | ||
61 | int value = i2c_smbus_read_word_data(client, reg); | ||
62 | return (value < 0) ? value : swab16(value); | ||
63 | } else | ||
64 | return i2c_smbus_read_byte_data(client, reg); | ||
65 | } | ||
66 | |||
67 | static inline int ad7414_write(struct i2c_client *client, u8 reg, u8 value) | ||
68 | { | ||
69 | return i2c_smbus_write_byte_data(client, reg, value); | ||
70 | } | ||
71 | |||
72 | struct ad7414_data *ad7414_update_device(struct device *dev) | ||
73 | { | ||
74 | struct i2c_client *client = to_i2c_client(dev); | ||
75 | struct ad7414_data *data = i2c_get_clientdata(client); | ||
76 | |||
77 | mutex_lock(&data->lock); | ||
78 | |||
79 | if (time_after(jiffies, data->next_update) || !data->valid) { | ||
80 | int value, i; | ||
81 | |||
82 | dev_dbg(&client->dev, "starting ad7414 update\n"); | ||
83 | |||
84 | value = ad7414_read(client, AD7414_REG_TEMP); | ||
85 | if (value < 0) | ||
86 | dev_dbg(&client->dev, "AD7414_REG_TEMP err %d\n", | ||
87 | value); | ||
88 | else | ||
89 | data->temp_input = value; | ||
90 | |||
91 | for (i = 0; i < ARRAY_SIZE(AD7414_REG_LIMIT); ++i) { | ||
92 | value = ad7414_read(client, AD7414_REG_LIMIT[i]); | ||
93 | if (value < 0) | ||
94 | dev_dbg(&client->dev, "AD7414 reg %d err %d\n", | ||
95 | AD7414_REG_LIMIT[i], value); | ||
96 | else | ||
97 | data->temps[i] = value; | ||
98 | } | ||
99 | |||
100 | data->next_update = jiffies + HZ + HZ / 2; | ||
101 | data->valid = 1; | ||
102 | } | ||
103 | |||
104 | mutex_unlock(&data->lock); | ||
105 | |||
106 | return data; | ||
107 | } | ||
108 | |||
109 | static ssize_t show_temp_input(struct device *dev, | ||
110 | struct device_attribute *attr, char *buf) | ||
111 | { | ||
112 | struct ad7414_data *data = ad7414_update_device(dev); | ||
113 | return sprintf(buf, "%d\n", ad7414_temp_from_reg(data->temp_input)); | ||
114 | } | ||
115 | static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input, NULL, 0); | ||
116 | |||
117 | static ssize_t show_max_min(struct device *dev, struct device_attribute *attr, | ||
118 | char *buf) | ||
119 | { | ||
120 | int index = to_sensor_dev_attr(attr)->index; | ||
121 | struct ad7414_data *data = ad7414_update_device(dev); | ||
122 | return sprintf(buf, "%d\n", data->temps[index] * 1000); | ||
123 | } | ||
124 | |||
125 | static ssize_t set_max_min(struct device *dev, | ||
126 | struct device_attribute *attr, | ||
127 | const char *buf, size_t count) | ||
128 | { | ||
129 | struct i2c_client *client = to_i2c_client(dev); | ||
130 | struct ad7414_data *data = i2c_get_clientdata(client); | ||
131 | int index = to_sensor_dev_attr(attr)->index; | ||
132 | u8 reg = AD7414_REG_LIMIT[index]; | ||
133 | long temp = simple_strtol(buf, NULL, 10); | ||
134 | |||
135 | temp = SENSORS_LIMIT(temp, -40000, 85000); | ||
136 | temp = (temp + (temp < 0 ? -500 : 500)) / 1000; | ||
137 | |||
138 | mutex_lock(&data->lock); | ||
139 | data->temps[index] = temp; | ||
140 | ad7414_write(client, reg, temp); | ||
141 | mutex_unlock(&data->lock); | ||
142 | return count; | ||
143 | } | ||
144 | |||
145 | static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, | ||
146 | show_max_min, set_max_min, 0); | ||
147 | static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, | ||
148 | show_max_min, set_max_min, 1); | ||
149 | |||
150 | static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, | ||
151 | char *buf) | ||
152 | { | ||
153 | int bitnr = to_sensor_dev_attr(attr)->index; | ||
154 | struct ad7414_data *data = ad7414_update_device(dev); | ||
155 | int value = (data->temp_input >> bitnr) & 1; | ||
156 | return sprintf(buf, "%d\n", value); | ||
157 | } | ||
158 | |||
159 | static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 3); | ||
160 | static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 4); | ||
161 | |||
162 | static struct attribute *ad7414_attributes[] = { | ||
163 | &sensor_dev_attr_temp1_input.dev_attr.attr, | ||
164 | &sensor_dev_attr_temp1_max.dev_attr.attr, | ||
165 | &sensor_dev_attr_temp1_min.dev_attr.attr, | ||
166 | &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, | ||
167 | &sensor_dev_attr_temp1_min_alarm.dev_attr.attr, | ||
168 | NULL | ||
169 | }; | ||
170 | |||
171 | static const struct attribute_group ad7414_group = { | ||
172 | .attrs = ad7414_attributes, | ||
173 | }; | ||
174 | |||
175 | static int ad7414_probe(struct i2c_client *client, | ||
176 | const struct i2c_device_id *dev_id) | ||
177 | { | ||
178 | struct ad7414_data *data; | ||
179 | int conf; | ||
180 | int err = 0; | ||
181 | |||
182 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA | | ||
183 | I2C_FUNC_SMBUS_READ_WORD_DATA)) | ||
184 | goto exit; | ||
185 | |||
186 | data = kzalloc(sizeof(struct ad7414_data), GFP_KERNEL); | ||
187 | if (!data) { | ||
188 | err = -ENOMEM; | ||
189 | goto exit; | ||
190 | } | ||
191 | |||
192 | i2c_set_clientdata(client, data); | ||
193 | mutex_init(&data->lock); | ||
194 | |||
195 | dev_info(&client->dev, "chip found\n"); | ||
196 | |||
197 | /* Make sure the chip is powered up. */ | ||
198 | conf = i2c_smbus_read_byte_data(client, AD7414_REG_CONF); | ||
199 | if (conf < 0) | ||
200 | dev_warn(&client->dev, | ||
201 | "ad7414_probe unable to read config register.\n"); | ||
202 | else { | ||
203 | conf &= ~(1 << 7); | ||
204 | i2c_smbus_write_byte_data(client, AD7414_REG_CONF, conf); | ||
205 | } | ||
206 | |||
207 | /* Register sysfs hooks */ | ||
208 | err = sysfs_create_group(&client->dev.kobj, &ad7414_group); | ||
209 | if (err) | ||
210 | goto exit_free; | ||
211 | |||
212 | data->hwmon_dev = hwmon_device_register(&client->dev); | ||
213 | if (IS_ERR(data->hwmon_dev)) { | ||
214 | err = PTR_ERR(data->hwmon_dev); | ||
215 | goto exit_remove; | ||
216 | } | ||
217 | |||
218 | return 0; | ||
219 | |||
220 | exit_remove: | ||
221 | sysfs_remove_group(&client->dev.kobj, &ad7414_group); | ||
222 | exit_free: | ||
223 | kfree(data); | ||
224 | exit: | ||
225 | return err; | ||
226 | } | ||
227 | |||
228 | static int __devexit ad7414_remove(struct i2c_client *client) | ||
229 | { | ||
230 | struct ad7414_data *data = i2c_get_clientdata(client); | ||
231 | |||
232 | hwmon_device_unregister(data->hwmon_dev); | ||
233 | sysfs_remove_group(&client->dev.kobj, &ad7414_group); | ||
234 | kfree(data); | ||
235 | return 0; | ||
236 | } | ||
237 | |||
238 | static const struct i2c_device_id ad7414_id[] = { | ||
239 | { "ad7414", 0 }, | ||
240 | {} | ||
241 | }; | ||
242 | |||
243 | static struct i2c_driver ad7414_driver = { | ||
244 | .driver = { | ||
245 | .name = "ad7414", | ||
246 | }, | ||
247 | .probe = ad7414_probe, | ||
248 | .remove = __devexit_p(ad7414_remove), | ||
249 | .id_table = ad7414_id, | ||
250 | }; | ||
251 | |||
252 | static int __init ad7414_init(void) | ||
253 | { | ||
254 | return i2c_add_driver(&ad7414_driver); | ||
255 | } | ||
256 | module_init(ad7414_init); | ||
257 | |||
258 | static void __exit ad7414_exit(void) | ||
259 | { | ||
260 | i2c_del_driver(&ad7414_driver); | ||
261 | } | ||
262 | module_exit(ad7414_exit); | ||
263 | |||
264 | MODULE_AUTHOR("Stefan Roese <sr at denx.de>, " | ||
265 | "Frank Edelhaeuser <frank.edelhaeuser at spansion.com>"); | ||
266 | |||
267 | MODULE_DESCRIPTION("AD7414 driver"); | ||
268 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/hwmon/dme1737.c b/drivers/hwmon/dme1737.c index 5e2cf0aef480..cdb8311e4ef7 100644 --- a/drivers/hwmon/dme1737.c +++ b/drivers/hwmon/dme1737.c | |||
@@ -1,11 +1,11 @@ | |||
1 | /* | 1 | /* |
2 | * dme1737.c - Driver for the SMSC DME1737, Asus A8000, and SMSC SCH311x | 2 | * dme1737.c - Driver for the SMSC DME1737, Asus A8000, SMSC SCH311x and |
3 | * Super-I/O chips integrated hardware monitoring features. | 3 | * SCH5027 Super-I/O chips integrated hardware monitoring features. |
4 | * Copyright (c) 2007 Juerg Haefliger <juergh@gmail.com> | 4 | * Copyright (c) 2007, 2008 Juerg Haefliger <juergh@gmail.com> |
5 | * | 5 | * |
6 | * This driver is an I2C/ISA hybrid, meaning that it uses the I2C bus to access | 6 | * This driver is an I2C/ISA hybrid, meaning that it uses the I2C bus to access |
7 | * the chip registers if a DME1737 (or A8000) is found and the ISA bus if a | 7 | * the chip registers if a DME1737, A8000, or SCH5027 is found and the ISA bus |
8 | * SCH311x chip is found. Both types of chips have very similar hardware | 8 | * if a SCH311x chip is found. Both types of chips have very similar hardware |
9 | * monitoring capabilities but differ in the way they can be accessed. | 9 | * monitoring capabilities but differ in the way they can be accessed. |
10 | * | 10 | * |
11 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
@@ -57,7 +57,10 @@ MODULE_PARM_DESC(probe_all_addr, "Include probing of non-standard LPC " | |||
57 | static const unsigned short normal_i2c[] = {0x2c, 0x2d, 0x2e, I2C_CLIENT_END}; | 57 | static const unsigned short normal_i2c[] = {0x2c, 0x2d, 0x2e, I2C_CLIENT_END}; |
58 | 58 | ||
59 | /* Insmod parameters */ | 59 | /* Insmod parameters */ |
60 | I2C_CLIENT_INSMOD_1(dme1737); | 60 | I2C_CLIENT_INSMOD_2(dme1737, sch5027); |
61 | |||
62 | /* ISA chip types */ | ||
63 | enum isa_chips { sch311x = sch5027 + 1 }; | ||
61 | 64 | ||
62 | /* --------------------------------------------------------------------- | 65 | /* --------------------------------------------------------------------- |
63 | * Registers | 66 | * Registers |
@@ -163,6 +166,7 @@ static const u8 DME1737_BIT_ALARM_FAN[] = {10, 11, 12, 13, 22, 23}; | |||
163 | #define DME1737_VERSTEP 0x88 | 166 | #define DME1737_VERSTEP 0x88 |
164 | #define DME1737_VERSTEP_MASK 0xf8 | 167 | #define DME1737_VERSTEP_MASK 0xf8 |
165 | #define SCH311X_DEVICE 0x8c | 168 | #define SCH311X_DEVICE 0x8c |
169 | #define SCH5027_VERSTEP 0x69 | ||
166 | 170 | ||
167 | /* Length of ISA address segment */ | 171 | /* Length of ISA address segment */ |
168 | #define DME1737_EXTENT 2 | 172 | #define DME1737_EXTENT 2 |
@@ -182,6 +186,7 @@ struct dme1737_data { | |||
182 | unsigned long last_update; /* in jiffies */ | 186 | unsigned long last_update; /* in jiffies */ |
183 | unsigned long last_vbat; /* in jiffies */ | 187 | unsigned long last_vbat; /* in jiffies */ |
184 | enum chips type; | 188 | enum chips type; |
189 | const int *in_nominal; /* pointer to IN_NOMINAL array */ | ||
185 | 190 | ||
186 | u8 vid; | 191 | u8 vid; |
187 | u8 pwm_rr_en; | 192 | u8 pwm_rr_en; |
@@ -220,23 +225,23 @@ static const int IN_NOMINAL_DME1737[] = {5000, 2250, 3300, 5000, 12000, 3300, | |||
220 | 3300}; | 225 | 3300}; |
221 | static const int IN_NOMINAL_SCH311x[] = {2500, 1500, 3300, 5000, 12000, 3300, | 226 | static const int IN_NOMINAL_SCH311x[] = {2500, 1500, 3300, 5000, 12000, 3300, |
222 | 3300}; | 227 | 3300}; |
223 | #define IN_NOMINAL(ix, type) (((type) == dme1737) ? \ | 228 | static const int IN_NOMINAL_SCH5027[] = {5000, 2250, 3300, 1125, 1125, 3300, |
224 | IN_NOMINAL_DME1737[(ix)] : \ | 229 | 3300}; |
225 | IN_NOMINAL_SCH311x[(ix)]) | 230 | #define IN_NOMINAL(type) ((type) == sch311x ? IN_NOMINAL_SCH311x : \ |
231 | (type) == sch5027 ? IN_NOMINAL_SCH5027 : \ | ||
232 | IN_NOMINAL_DME1737) | ||
226 | 233 | ||
227 | /* Voltage input | 234 | /* Voltage input |
228 | * Voltage inputs have 16 bits resolution, limit values have 8 bits | 235 | * Voltage inputs have 16 bits resolution, limit values have 8 bits |
229 | * resolution. */ | 236 | * resolution. */ |
230 | static inline int IN_FROM_REG(int reg, int ix, int res, int type) | 237 | static inline int IN_FROM_REG(int reg, int nominal, int res) |
231 | { | 238 | { |
232 | return (reg * IN_NOMINAL(ix, type) + (3 << (res - 3))) / | 239 | return (reg * nominal + (3 << (res - 3))) / (3 << (res - 2)); |
233 | (3 << (res - 2)); | ||
234 | } | 240 | } |
235 | 241 | ||
236 | static inline int IN_TO_REG(int val, int ix, int type) | 242 | static inline int IN_TO_REG(int val, int nominal) |
237 | { | 243 | { |
238 | return SENSORS_LIMIT((val * 192 + IN_NOMINAL(ix, type) / 2) / | 244 | return SENSORS_LIMIT((val * 192 + nominal / 2) / nominal, 0, 255); |
239 | IN_NOMINAL(ix, type), 0, 255); | ||
240 | } | 245 | } |
241 | 246 | ||
242 | /* Temperature input | 247 | /* Temperature input |
@@ -565,7 +570,10 @@ static struct dme1737_data *dme1737_update_device(struct device *dev) | |||
565 | 570 | ||
566 | /* Sample register contents every 1 sec */ | 571 | /* Sample register contents every 1 sec */ |
567 | if (time_after(jiffies, data->last_update + HZ) || !data->valid) { | 572 | if (time_after(jiffies, data->last_update + HZ) || !data->valid) { |
568 | data->vid = dme1737_read(client, DME1737_REG_VID) & 0x3f; | 573 | if (data->type != sch5027) { |
574 | data->vid = dme1737_read(client, DME1737_REG_VID) & | ||
575 | 0x3f; | ||
576 | } | ||
569 | 577 | ||
570 | /* In (voltage) registers */ | 578 | /* In (voltage) registers */ |
571 | for (ix = 0; ix < ARRAY_SIZE(data->in); ix++) { | 579 | for (ix = 0; ix < ARRAY_SIZE(data->in); ix++) { |
@@ -593,8 +601,10 @@ static struct dme1737_data *dme1737_update_device(struct device *dev) | |||
593 | DME1737_REG_TEMP_MIN(ix)); | 601 | DME1737_REG_TEMP_MIN(ix)); |
594 | data->temp_max[ix] = dme1737_read(client, | 602 | data->temp_max[ix] = dme1737_read(client, |
595 | DME1737_REG_TEMP_MAX(ix)); | 603 | DME1737_REG_TEMP_MAX(ix)); |
596 | data->temp_offset[ix] = dme1737_read(client, | 604 | if (data->type != sch5027) { |
597 | DME1737_REG_TEMP_OFFSET(ix)); | 605 | data->temp_offset[ix] = dme1737_read(client, |
606 | DME1737_REG_TEMP_OFFSET(ix)); | ||
607 | } | ||
598 | } | 608 | } |
599 | 609 | ||
600 | /* In and temp LSB registers | 610 | /* In and temp LSB registers |
@@ -669,9 +679,11 @@ static struct dme1737_data *dme1737_update_device(struct device *dev) | |||
669 | data->zone_abs[ix] = dme1737_read(client, | 679 | data->zone_abs[ix] = dme1737_read(client, |
670 | DME1737_REG_ZONE_ABS(ix)); | 680 | DME1737_REG_ZONE_ABS(ix)); |
671 | } | 681 | } |
672 | for (ix = 0; ix < ARRAY_SIZE(data->zone_hyst); ix++) { | 682 | if (data->type != sch5027) { |
673 | data->zone_hyst[ix] = dme1737_read(client, | 683 | for (ix = 0; ix < ARRAY_SIZE(data->zone_hyst); ix++) { |
684 | data->zone_hyst[ix] = dme1737_read(client, | ||
674 | DME1737_REG_ZONE_HYST(ix)); | 685 | DME1737_REG_ZONE_HYST(ix)); |
686 | } | ||
675 | } | 687 | } |
676 | 688 | ||
677 | /* Alarm registers */ | 689 | /* Alarm registers */ |
@@ -735,13 +747,13 @@ static ssize_t show_in(struct device *dev, struct device_attribute *attr, | |||
735 | 747 | ||
736 | switch (fn) { | 748 | switch (fn) { |
737 | case SYS_IN_INPUT: | 749 | case SYS_IN_INPUT: |
738 | res = IN_FROM_REG(data->in[ix], ix, 16, data->type); | 750 | res = IN_FROM_REG(data->in[ix], data->in_nominal[ix], 16); |
739 | break; | 751 | break; |
740 | case SYS_IN_MIN: | 752 | case SYS_IN_MIN: |
741 | res = IN_FROM_REG(data->in_min[ix], ix, 8, data->type); | 753 | res = IN_FROM_REG(data->in_min[ix], data->in_nominal[ix], 8); |
742 | break; | 754 | break; |
743 | case SYS_IN_MAX: | 755 | case SYS_IN_MAX: |
744 | res = IN_FROM_REG(data->in_max[ix], ix, 8, data->type); | 756 | res = IN_FROM_REG(data->in_max[ix], data->in_nominal[ix], 8); |
745 | break; | 757 | break; |
746 | case SYS_IN_ALARM: | 758 | case SYS_IN_ALARM: |
747 | res = (data->alarms >> DME1737_BIT_ALARM_IN[ix]) & 0x01; | 759 | res = (data->alarms >> DME1737_BIT_ALARM_IN[ix]) & 0x01; |
@@ -768,12 +780,12 @@ static ssize_t set_in(struct device *dev, struct device_attribute *attr, | |||
768 | mutex_lock(&data->update_lock); | 780 | mutex_lock(&data->update_lock); |
769 | switch (fn) { | 781 | switch (fn) { |
770 | case SYS_IN_MIN: | 782 | case SYS_IN_MIN: |
771 | data->in_min[ix] = IN_TO_REG(val, ix, data->type); | 783 | data->in_min[ix] = IN_TO_REG(val, data->in_nominal[ix]); |
772 | dme1737_write(client, DME1737_REG_IN_MIN(ix), | 784 | dme1737_write(client, DME1737_REG_IN_MIN(ix), |
773 | data->in_min[ix]); | 785 | data->in_min[ix]); |
774 | break; | 786 | break; |
775 | case SYS_IN_MAX: | 787 | case SYS_IN_MAX: |
776 | data->in_max[ix] = IN_TO_REG(val, ix, data->type); | 788 | data->in_max[ix] = IN_TO_REG(val, data->in_nominal[ix]); |
777 | dme1737_write(client, DME1737_REG_IN_MAX(ix), | 789 | dme1737_write(client, DME1737_REG_IN_MAX(ix), |
778 | data->in_max[ix]); | 790 | data->in_max[ix]); |
779 | break; | 791 | break; |
@@ -1166,7 +1178,7 @@ static ssize_t show_pwm(struct device *dev, struct device_attribute *attr, | |||
1166 | return sprintf(buf, "%d\n", res); | 1178 | return sprintf(buf, "%d\n", res); |
1167 | } | 1179 | } |
1168 | 1180 | ||
1169 | static struct attribute *dme1737_attr_pwm[]; | 1181 | static struct attribute *dme1737_pwm_chmod_attr[]; |
1170 | static void dme1737_chmod_file(struct device*, struct attribute*, mode_t); | 1182 | static void dme1737_chmod_file(struct device*, struct attribute*, mode_t); |
1171 | 1183 | ||
1172 | static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, | 1184 | static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, |
@@ -1230,7 +1242,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, | |||
1230 | switch (val) { | 1242 | switch (val) { |
1231 | case 0: | 1243 | case 0: |
1232 | /* Change permissions of pwm[ix] to read-only */ | 1244 | /* Change permissions of pwm[ix] to read-only */ |
1233 | dme1737_chmod_file(dev, dme1737_attr_pwm[ix], | 1245 | dme1737_chmod_file(dev, dme1737_pwm_chmod_attr[ix], |
1234 | S_IRUGO); | 1246 | S_IRUGO); |
1235 | /* Turn fan fully on */ | 1247 | /* Turn fan fully on */ |
1236 | data->pwm_config[ix] = PWM_EN_TO_REG(0, | 1248 | data->pwm_config[ix] = PWM_EN_TO_REG(0, |
@@ -1245,12 +1257,12 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, | |||
1245 | dme1737_write(client, DME1737_REG_PWM_CONFIG(ix), | 1257 | dme1737_write(client, DME1737_REG_PWM_CONFIG(ix), |
1246 | data->pwm_config[ix]); | 1258 | data->pwm_config[ix]); |
1247 | /* Change permissions of pwm[ix] to read-writeable */ | 1259 | /* Change permissions of pwm[ix] to read-writeable */ |
1248 | dme1737_chmod_file(dev, dme1737_attr_pwm[ix], | 1260 | dme1737_chmod_file(dev, dme1737_pwm_chmod_attr[ix], |
1249 | S_IRUGO | S_IWUSR); | 1261 | S_IRUGO | S_IWUSR); |
1250 | break; | 1262 | break; |
1251 | case 2: | 1263 | case 2: |
1252 | /* Change permissions of pwm[ix] to read-only */ | 1264 | /* Change permissions of pwm[ix] to read-only */ |
1253 | dme1737_chmod_file(dev, dme1737_attr_pwm[ix], | 1265 | dme1737_chmod_file(dev, dme1737_pwm_chmod_attr[ix], |
1254 | S_IRUGO); | 1266 | S_IRUGO); |
1255 | /* Turn on auto mode using the saved zone channel | 1267 | /* Turn on auto mode using the saved zone channel |
1256 | * assignment */ | 1268 | * assignment */ |
@@ -1570,88 +1582,98 @@ static struct attribute *dme1737_attr[] ={ | |||
1570 | &sensor_dev_attr_temp1_max.dev_attr.attr, | 1582 | &sensor_dev_attr_temp1_max.dev_attr.attr, |
1571 | &sensor_dev_attr_temp1_alarm.dev_attr.attr, | 1583 | &sensor_dev_attr_temp1_alarm.dev_attr.attr, |
1572 | &sensor_dev_attr_temp1_fault.dev_attr.attr, | 1584 | &sensor_dev_attr_temp1_fault.dev_attr.attr, |
1573 | &sensor_dev_attr_temp1_offset.dev_attr.attr, | ||
1574 | &sensor_dev_attr_temp2_input.dev_attr.attr, | 1585 | &sensor_dev_attr_temp2_input.dev_attr.attr, |
1575 | &sensor_dev_attr_temp2_min.dev_attr.attr, | 1586 | &sensor_dev_attr_temp2_min.dev_attr.attr, |
1576 | &sensor_dev_attr_temp2_max.dev_attr.attr, | 1587 | &sensor_dev_attr_temp2_max.dev_attr.attr, |
1577 | &sensor_dev_attr_temp2_alarm.dev_attr.attr, | 1588 | &sensor_dev_attr_temp2_alarm.dev_attr.attr, |
1578 | &sensor_dev_attr_temp2_fault.dev_attr.attr, | 1589 | &sensor_dev_attr_temp2_fault.dev_attr.attr, |
1579 | &sensor_dev_attr_temp2_offset.dev_attr.attr, | ||
1580 | &sensor_dev_attr_temp3_input.dev_attr.attr, | 1590 | &sensor_dev_attr_temp3_input.dev_attr.attr, |
1581 | &sensor_dev_attr_temp3_min.dev_attr.attr, | 1591 | &sensor_dev_attr_temp3_min.dev_attr.attr, |
1582 | &sensor_dev_attr_temp3_max.dev_attr.attr, | 1592 | &sensor_dev_attr_temp3_max.dev_attr.attr, |
1583 | &sensor_dev_attr_temp3_alarm.dev_attr.attr, | 1593 | &sensor_dev_attr_temp3_alarm.dev_attr.attr, |
1584 | &sensor_dev_attr_temp3_fault.dev_attr.attr, | 1594 | &sensor_dev_attr_temp3_fault.dev_attr.attr, |
1585 | &sensor_dev_attr_temp3_offset.dev_attr.attr, | ||
1586 | /* Zones */ | 1595 | /* Zones */ |
1587 | &sensor_dev_attr_zone1_auto_point1_temp_hyst.dev_attr.attr, | ||
1588 | &sensor_dev_attr_zone1_auto_point1_temp.dev_attr.attr, | 1596 | &sensor_dev_attr_zone1_auto_point1_temp.dev_attr.attr, |
1589 | &sensor_dev_attr_zone1_auto_point2_temp.dev_attr.attr, | 1597 | &sensor_dev_attr_zone1_auto_point2_temp.dev_attr.attr, |
1590 | &sensor_dev_attr_zone1_auto_point3_temp.dev_attr.attr, | 1598 | &sensor_dev_attr_zone1_auto_point3_temp.dev_attr.attr, |
1591 | &sensor_dev_attr_zone1_auto_channels_temp.dev_attr.attr, | 1599 | &sensor_dev_attr_zone1_auto_channels_temp.dev_attr.attr, |
1592 | &sensor_dev_attr_zone2_auto_point1_temp_hyst.dev_attr.attr, | ||
1593 | &sensor_dev_attr_zone2_auto_point1_temp.dev_attr.attr, | 1600 | &sensor_dev_attr_zone2_auto_point1_temp.dev_attr.attr, |
1594 | &sensor_dev_attr_zone2_auto_point2_temp.dev_attr.attr, | 1601 | &sensor_dev_attr_zone2_auto_point2_temp.dev_attr.attr, |
1595 | &sensor_dev_attr_zone2_auto_point3_temp.dev_attr.attr, | 1602 | &sensor_dev_attr_zone2_auto_point3_temp.dev_attr.attr, |
1596 | &sensor_dev_attr_zone2_auto_channels_temp.dev_attr.attr, | 1603 | &sensor_dev_attr_zone2_auto_channels_temp.dev_attr.attr, |
1597 | &sensor_dev_attr_zone3_auto_point1_temp_hyst.dev_attr.attr, | ||
1598 | &sensor_dev_attr_zone3_auto_point1_temp.dev_attr.attr, | 1604 | &sensor_dev_attr_zone3_auto_point1_temp.dev_attr.attr, |
1599 | &sensor_dev_attr_zone3_auto_point2_temp.dev_attr.attr, | 1605 | &sensor_dev_attr_zone3_auto_point2_temp.dev_attr.attr, |
1600 | &sensor_dev_attr_zone3_auto_point3_temp.dev_attr.attr, | 1606 | &sensor_dev_attr_zone3_auto_point3_temp.dev_attr.attr, |
1601 | &sensor_dev_attr_zone3_auto_channels_temp.dev_attr.attr, | 1607 | &sensor_dev_attr_zone3_auto_channels_temp.dev_attr.attr, |
1608 | NULL | ||
1609 | }; | ||
1610 | |||
1611 | static const struct attribute_group dme1737_group = { | ||
1612 | .attrs = dme1737_attr, | ||
1613 | }; | ||
1614 | |||
1615 | /* The following struct holds misc attributes, which are not available in all | ||
1616 | * chips. Their creation depends on the chip type which is determined during | ||
1617 | * module load. */ | ||
1618 | static struct attribute *dme1737_misc_attr[] = { | ||
1619 | /* Temperatures */ | ||
1620 | &sensor_dev_attr_temp1_offset.dev_attr.attr, | ||
1621 | &sensor_dev_attr_temp2_offset.dev_attr.attr, | ||
1622 | &sensor_dev_attr_temp3_offset.dev_attr.attr, | ||
1623 | /* Zones */ | ||
1624 | &sensor_dev_attr_zone1_auto_point1_temp_hyst.dev_attr.attr, | ||
1625 | &sensor_dev_attr_zone2_auto_point1_temp_hyst.dev_attr.attr, | ||
1626 | &sensor_dev_attr_zone3_auto_point1_temp_hyst.dev_attr.attr, | ||
1602 | /* Misc */ | 1627 | /* Misc */ |
1603 | &dev_attr_vrm.attr, | 1628 | &dev_attr_vrm.attr, |
1604 | &dev_attr_cpu0_vid.attr, | 1629 | &dev_attr_cpu0_vid.attr, |
1605 | NULL | 1630 | NULL |
1606 | }; | 1631 | }; |
1607 | 1632 | ||
1608 | static const struct attribute_group dme1737_group = { | 1633 | static const struct attribute_group dme1737_misc_group = { |
1609 | .attrs = dme1737_attr, | 1634 | .attrs = dme1737_misc_attr, |
1610 | }; | 1635 | }; |
1611 | 1636 | ||
1612 | /* The following structs hold the PWM attributes, some of which are optional. | 1637 | /* The following structs hold the PWM attributes, some of which are optional. |
1613 | * Their creation depends on the chip configuration which is determined during | 1638 | * Their creation depends on the chip configuration which is determined during |
1614 | * module load. */ | 1639 | * module load. */ |
1615 | static struct attribute *dme1737_attr_pwm1[] = { | 1640 | static struct attribute *dme1737_pwm1_attr[] = { |
1616 | &sensor_dev_attr_pwm1.dev_attr.attr, | 1641 | &sensor_dev_attr_pwm1.dev_attr.attr, |
1617 | &sensor_dev_attr_pwm1_freq.dev_attr.attr, | 1642 | &sensor_dev_attr_pwm1_freq.dev_attr.attr, |
1618 | &sensor_dev_attr_pwm1_enable.dev_attr.attr, | 1643 | &sensor_dev_attr_pwm1_enable.dev_attr.attr, |
1619 | &sensor_dev_attr_pwm1_ramp_rate.dev_attr.attr, | 1644 | &sensor_dev_attr_pwm1_ramp_rate.dev_attr.attr, |
1620 | &sensor_dev_attr_pwm1_auto_channels_zone.dev_attr.attr, | 1645 | &sensor_dev_attr_pwm1_auto_channels_zone.dev_attr.attr, |
1621 | &sensor_dev_attr_pwm1_auto_pwm_min.dev_attr.attr, | ||
1622 | &sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr, | 1646 | &sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr, |
1623 | &sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr, | 1647 | &sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr, |
1624 | NULL | 1648 | NULL |
1625 | }; | 1649 | }; |
1626 | static struct attribute *dme1737_attr_pwm2[] = { | 1650 | static struct attribute *dme1737_pwm2_attr[] = { |
1627 | &sensor_dev_attr_pwm2.dev_attr.attr, | 1651 | &sensor_dev_attr_pwm2.dev_attr.attr, |
1628 | &sensor_dev_attr_pwm2_freq.dev_attr.attr, | 1652 | &sensor_dev_attr_pwm2_freq.dev_attr.attr, |
1629 | &sensor_dev_attr_pwm2_enable.dev_attr.attr, | 1653 | &sensor_dev_attr_pwm2_enable.dev_attr.attr, |
1630 | &sensor_dev_attr_pwm2_ramp_rate.dev_attr.attr, | 1654 | &sensor_dev_attr_pwm2_ramp_rate.dev_attr.attr, |
1631 | &sensor_dev_attr_pwm2_auto_channels_zone.dev_attr.attr, | 1655 | &sensor_dev_attr_pwm2_auto_channels_zone.dev_attr.attr, |
1632 | &sensor_dev_attr_pwm2_auto_pwm_min.dev_attr.attr, | ||
1633 | &sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr, | 1656 | &sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr, |
1634 | &sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr, | 1657 | &sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr, |
1635 | NULL | 1658 | NULL |
1636 | }; | 1659 | }; |
1637 | static struct attribute *dme1737_attr_pwm3[] = { | 1660 | static struct attribute *dme1737_pwm3_attr[] = { |
1638 | &sensor_dev_attr_pwm3.dev_attr.attr, | 1661 | &sensor_dev_attr_pwm3.dev_attr.attr, |
1639 | &sensor_dev_attr_pwm3_freq.dev_attr.attr, | 1662 | &sensor_dev_attr_pwm3_freq.dev_attr.attr, |
1640 | &sensor_dev_attr_pwm3_enable.dev_attr.attr, | 1663 | &sensor_dev_attr_pwm3_enable.dev_attr.attr, |
1641 | &sensor_dev_attr_pwm3_ramp_rate.dev_attr.attr, | 1664 | &sensor_dev_attr_pwm3_ramp_rate.dev_attr.attr, |
1642 | &sensor_dev_attr_pwm3_auto_channels_zone.dev_attr.attr, | 1665 | &sensor_dev_attr_pwm3_auto_channels_zone.dev_attr.attr, |
1643 | &sensor_dev_attr_pwm3_auto_pwm_min.dev_attr.attr, | ||
1644 | &sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr, | 1666 | &sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr, |
1645 | &sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr, | 1667 | &sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr, |
1646 | NULL | 1668 | NULL |
1647 | }; | 1669 | }; |
1648 | static struct attribute *dme1737_attr_pwm5[] = { | 1670 | static struct attribute *dme1737_pwm5_attr[] = { |
1649 | &sensor_dev_attr_pwm5.dev_attr.attr, | 1671 | &sensor_dev_attr_pwm5.dev_attr.attr, |
1650 | &sensor_dev_attr_pwm5_freq.dev_attr.attr, | 1672 | &sensor_dev_attr_pwm5_freq.dev_attr.attr, |
1651 | &sensor_dev_attr_pwm5_enable.dev_attr.attr, | 1673 | &sensor_dev_attr_pwm5_enable.dev_attr.attr, |
1652 | NULL | 1674 | NULL |
1653 | }; | 1675 | }; |
1654 | static struct attribute *dme1737_attr_pwm6[] = { | 1676 | static struct attribute *dme1737_pwm6_attr[] = { |
1655 | &sensor_dev_attr_pwm6.dev_attr.attr, | 1677 | &sensor_dev_attr_pwm6.dev_attr.attr, |
1656 | &sensor_dev_attr_pwm6_freq.dev_attr.attr, | 1678 | &sensor_dev_attr_pwm6_freq.dev_attr.attr, |
1657 | &sensor_dev_attr_pwm6_enable.dev_attr.attr, | 1679 | &sensor_dev_attr_pwm6_enable.dev_attr.attr, |
@@ -1659,53 +1681,62 @@ static struct attribute *dme1737_attr_pwm6[] = { | |||
1659 | }; | 1681 | }; |
1660 | 1682 | ||
1661 | static const struct attribute_group dme1737_pwm_group[] = { | 1683 | static const struct attribute_group dme1737_pwm_group[] = { |
1662 | { .attrs = dme1737_attr_pwm1 }, | 1684 | { .attrs = dme1737_pwm1_attr }, |
1663 | { .attrs = dme1737_attr_pwm2 }, | 1685 | { .attrs = dme1737_pwm2_attr }, |
1664 | { .attrs = dme1737_attr_pwm3 }, | 1686 | { .attrs = dme1737_pwm3_attr }, |
1665 | { .attrs = NULL }, | 1687 | { .attrs = NULL }, |
1666 | { .attrs = dme1737_attr_pwm5 }, | 1688 | { .attrs = dme1737_pwm5_attr }, |
1667 | { .attrs = dme1737_attr_pwm6 }, | 1689 | { .attrs = dme1737_pwm6_attr }, |
1690 | }; | ||
1691 | |||
1692 | /* The following struct holds misc PWM attributes, which are not available in | ||
1693 | * all chips. Their creation depends on the chip type which is determined | ||
1694 | * during module load. */ | ||
1695 | static struct attribute *dme1737_pwm_misc_attr[] = { | ||
1696 | &sensor_dev_attr_pwm1_auto_pwm_min.dev_attr.attr, | ||
1697 | &sensor_dev_attr_pwm2_auto_pwm_min.dev_attr.attr, | ||
1698 | &sensor_dev_attr_pwm3_auto_pwm_min.dev_attr.attr, | ||
1668 | }; | 1699 | }; |
1669 | 1700 | ||
1670 | /* The following structs hold the fan attributes, some of which are optional. | 1701 | /* The following structs hold the fan attributes, some of which are optional. |
1671 | * Their creation depends on the chip configuration which is determined during | 1702 | * Their creation depends on the chip configuration which is determined during |
1672 | * module load. */ | 1703 | * module load. */ |
1673 | static struct attribute *dme1737_attr_fan1[] = { | 1704 | static struct attribute *dme1737_fan1_attr[] = { |
1674 | &sensor_dev_attr_fan1_input.dev_attr.attr, | 1705 | &sensor_dev_attr_fan1_input.dev_attr.attr, |
1675 | &sensor_dev_attr_fan1_min.dev_attr.attr, | 1706 | &sensor_dev_attr_fan1_min.dev_attr.attr, |
1676 | &sensor_dev_attr_fan1_alarm.dev_attr.attr, | 1707 | &sensor_dev_attr_fan1_alarm.dev_attr.attr, |
1677 | &sensor_dev_attr_fan1_type.dev_attr.attr, | 1708 | &sensor_dev_attr_fan1_type.dev_attr.attr, |
1678 | NULL | 1709 | NULL |
1679 | }; | 1710 | }; |
1680 | static struct attribute *dme1737_attr_fan2[] = { | 1711 | static struct attribute *dme1737_fan2_attr[] = { |
1681 | &sensor_dev_attr_fan2_input.dev_attr.attr, | 1712 | &sensor_dev_attr_fan2_input.dev_attr.attr, |
1682 | &sensor_dev_attr_fan2_min.dev_attr.attr, | 1713 | &sensor_dev_attr_fan2_min.dev_attr.attr, |
1683 | &sensor_dev_attr_fan2_alarm.dev_attr.attr, | 1714 | &sensor_dev_attr_fan2_alarm.dev_attr.attr, |
1684 | &sensor_dev_attr_fan2_type.dev_attr.attr, | 1715 | &sensor_dev_attr_fan2_type.dev_attr.attr, |
1685 | NULL | 1716 | NULL |
1686 | }; | 1717 | }; |
1687 | static struct attribute *dme1737_attr_fan3[] = { | 1718 | static struct attribute *dme1737_fan3_attr[] = { |
1688 | &sensor_dev_attr_fan3_input.dev_attr.attr, | 1719 | &sensor_dev_attr_fan3_input.dev_attr.attr, |
1689 | &sensor_dev_attr_fan3_min.dev_attr.attr, | 1720 | &sensor_dev_attr_fan3_min.dev_attr.attr, |
1690 | &sensor_dev_attr_fan3_alarm.dev_attr.attr, | 1721 | &sensor_dev_attr_fan3_alarm.dev_attr.attr, |
1691 | &sensor_dev_attr_fan3_type.dev_attr.attr, | 1722 | &sensor_dev_attr_fan3_type.dev_attr.attr, |
1692 | NULL | 1723 | NULL |
1693 | }; | 1724 | }; |
1694 | static struct attribute *dme1737_attr_fan4[] = { | 1725 | static struct attribute *dme1737_fan4_attr[] = { |
1695 | &sensor_dev_attr_fan4_input.dev_attr.attr, | 1726 | &sensor_dev_attr_fan4_input.dev_attr.attr, |
1696 | &sensor_dev_attr_fan4_min.dev_attr.attr, | 1727 | &sensor_dev_attr_fan4_min.dev_attr.attr, |
1697 | &sensor_dev_attr_fan4_alarm.dev_attr.attr, | 1728 | &sensor_dev_attr_fan4_alarm.dev_attr.attr, |
1698 | &sensor_dev_attr_fan4_type.dev_attr.attr, | 1729 | &sensor_dev_attr_fan4_type.dev_attr.attr, |
1699 | NULL | 1730 | NULL |
1700 | }; | 1731 | }; |
1701 | static struct attribute *dme1737_attr_fan5[] = { | 1732 | static struct attribute *dme1737_fan5_attr[] = { |
1702 | &sensor_dev_attr_fan5_input.dev_attr.attr, | 1733 | &sensor_dev_attr_fan5_input.dev_attr.attr, |
1703 | &sensor_dev_attr_fan5_min.dev_attr.attr, | 1734 | &sensor_dev_attr_fan5_min.dev_attr.attr, |
1704 | &sensor_dev_attr_fan5_alarm.dev_attr.attr, | 1735 | &sensor_dev_attr_fan5_alarm.dev_attr.attr, |
1705 | &sensor_dev_attr_fan5_max.dev_attr.attr, | 1736 | &sensor_dev_attr_fan5_max.dev_attr.attr, |
1706 | NULL | 1737 | NULL |
1707 | }; | 1738 | }; |
1708 | static struct attribute *dme1737_attr_fan6[] = { | 1739 | static struct attribute *dme1737_fan6_attr[] = { |
1709 | &sensor_dev_attr_fan6_input.dev_attr.attr, | 1740 | &sensor_dev_attr_fan6_input.dev_attr.attr, |
1710 | &sensor_dev_attr_fan6_min.dev_attr.attr, | 1741 | &sensor_dev_attr_fan6_min.dev_attr.attr, |
1711 | &sensor_dev_attr_fan6_alarm.dev_attr.attr, | 1742 | &sensor_dev_attr_fan6_alarm.dev_attr.attr, |
@@ -1714,94 +1745,83 @@ static struct attribute *dme1737_attr_fan6[] = { | |||
1714 | }; | 1745 | }; |
1715 | 1746 | ||
1716 | static const struct attribute_group dme1737_fan_group[] = { | 1747 | static const struct attribute_group dme1737_fan_group[] = { |
1717 | { .attrs = dme1737_attr_fan1 }, | 1748 | { .attrs = dme1737_fan1_attr }, |
1718 | { .attrs = dme1737_attr_fan2 }, | 1749 | { .attrs = dme1737_fan2_attr }, |
1719 | { .attrs = dme1737_attr_fan3 }, | 1750 | { .attrs = dme1737_fan3_attr }, |
1720 | { .attrs = dme1737_attr_fan4 }, | 1751 | { .attrs = dme1737_fan4_attr }, |
1721 | { .attrs = dme1737_attr_fan5 }, | 1752 | { .attrs = dme1737_fan5_attr }, |
1722 | { .attrs = dme1737_attr_fan6 }, | 1753 | { .attrs = dme1737_fan6_attr }, |
1723 | }; | 1754 | }; |
1724 | 1755 | ||
1725 | /* The permissions of all of the following attributes are changed to read- | 1756 | /* The permissions of the following zone attributes are changed to read- |
1726 | * writeable if the chip is *not* locked. Otherwise they stay read-only. */ | 1757 | * writeable if the chip is *not* locked. Otherwise they stay read-only. */ |
1727 | static struct attribute *dme1737_attr_lock[] = { | 1758 | static struct attribute *dme1737_zone_chmod_attr[] = { |
1728 | /* Temperatures */ | ||
1729 | &sensor_dev_attr_temp1_offset.dev_attr.attr, | ||
1730 | &sensor_dev_attr_temp2_offset.dev_attr.attr, | ||
1731 | &sensor_dev_attr_temp3_offset.dev_attr.attr, | ||
1732 | /* Zones */ | ||
1733 | &sensor_dev_attr_zone1_auto_point1_temp_hyst.dev_attr.attr, | ||
1734 | &sensor_dev_attr_zone1_auto_point1_temp.dev_attr.attr, | 1759 | &sensor_dev_attr_zone1_auto_point1_temp.dev_attr.attr, |
1735 | &sensor_dev_attr_zone1_auto_point2_temp.dev_attr.attr, | 1760 | &sensor_dev_attr_zone1_auto_point2_temp.dev_attr.attr, |
1736 | &sensor_dev_attr_zone1_auto_point3_temp.dev_attr.attr, | 1761 | &sensor_dev_attr_zone1_auto_point3_temp.dev_attr.attr, |
1737 | &sensor_dev_attr_zone2_auto_point1_temp_hyst.dev_attr.attr, | ||
1738 | &sensor_dev_attr_zone2_auto_point1_temp.dev_attr.attr, | 1762 | &sensor_dev_attr_zone2_auto_point1_temp.dev_attr.attr, |
1739 | &sensor_dev_attr_zone2_auto_point2_temp.dev_attr.attr, | 1763 | &sensor_dev_attr_zone2_auto_point2_temp.dev_attr.attr, |
1740 | &sensor_dev_attr_zone2_auto_point3_temp.dev_attr.attr, | 1764 | &sensor_dev_attr_zone2_auto_point3_temp.dev_attr.attr, |
1741 | &sensor_dev_attr_zone3_auto_point1_temp_hyst.dev_attr.attr, | ||
1742 | &sensor_dev_attr_zone3_auto_point1_temp.dev_attr.attr, | 1765 | &sensor_dev_attr_zone3_auto_point1_temp.dev_attr.attr, |
1743 | &sensor_dev_attr_zone3_auto_point2_temp.dev_attr.attr, | 1766 | &sensor_dev_attr_zone3_auto_point2_temp.dev_attr.attr, |
1744 | &sensor_dev_attr_zone3_auto_point3_temp.dev_attr.attr, | 1767 | &sensor_dev_attr_zone3_auto_point3_temp.dev_attr.attr, |
1745 | NULL | 1768 | NULL |
1746 | }; | 1769 | }; |
1747 | 1770 | ||
1748 | static const struct attribute_group dme1737_lock_group = { | 1771 | static const struct attribute_group dme1737_zone_chmod_group = { |
1749 | .attrs = dme1737_attr_lock, | 1772 | .attrs = dme1737_zone_chmod_attr, |
1750 | }; | 1773 | }; |
1751 | 1774 | ||
1752 | /* The permissions of the following PWM attributes are changed to read- | 1775 | /* The permissions of the following PWM attributes are changed to read- |
1753 | * writeable if the chip is *not* locked and the respective PWM is available. | 1776 | * writeable if the chip is *not* locked and the respective PWM is available. |
1754 | * Otherwise they stay read-only. */ | 1777 | * Otherwise they stay read-only. */ |
1755 | static struct attribute *dme1737_attr_pwm1_lock[] = { | 1778 | static struct attribute *dme1737_pwm1_chmod_attr[] = { |
1756 | &sensor_dev_attr_pwm1_freq.dev_attr.attr, | 1779 | &sensor_dev_attr_pwm1_freq.dev_attr.attr, |
1757 | &sensor_dev_attr_pwm1_enable.dev_attr.attr, | 1780 | &sensor_dev_attr_pwm1_enable.dev_attr.attr, |
1758 | &sensor_dev_attr_pwm1_ramp_rate.dev_attr.attr, | 1781 | &sensor_dev_attr_pwm1_ramp_rate.dev_attr.attr, |
1759 | &sensor_dev_attr_pwm1_auto_channels_zone.dev_attr.attr, | 1782 | &sensor_dev_attr_pwm1_auto_channels_zone.dev_attr.attr, |
1760 | &sensor_dev_attr_pwm1_auto_pwm_min.dev_attr.attr, | ||
1761 | &sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr, | 1783 | &sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr, |
1762 | NULL | 1784 | NULL |
1763 | }; | 1785 | }; |
1764 | static struct attribute *dme1737_attr_pwm2_lock[] = { | 1786 | static struct attribute *dme1737_pwm2_chmod_attr[] = { |
1765 | &sensor_dev_attr_pwm2_freq.dev_attr.attr, | 1787 | &sensor_dev_attr_pwm2_freq.dev_attr.attr, |
1766 | &sensor_dev_attr_pwm2_enable.dev_attr.attr, | 1788 | &sensor_dev_attr_pwm2_enable.dev_attr.attr, |
1767 | &sensor_dev_attr_pwm2_ramp_rate.dev_attr.attr, | 1789 | &sensor_dev_attr_pwm2_ramp_rate.dev_attr.attr, |
1768 | &sensor_dev_attr_pwm2_auto_channels_zone.dev_attr.attr, | 1790 | &sensor_dev_attr_pwm2_auto_channels_zone.dev_attr.attr, |
1769 | &sensor_dev_attr_pwm2_auto_pwm_min.dev_attr.attr, | ||
1770 | &sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr, | 1791 | &sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr, |
1771 | NULL | 1792 | NULL |
1772 | }; | 1793 | }; |
1773 | static struct attribute *dme1737_attr_pwm3_lock[] = { | 1794 | static struct attribute *dme1737_pwm3_chmod_attr[] = { |
1774 | &sensor_dev_attr_pwm3_freq.dev_attr.attr, | 1795 | &sensor_dev_attr_pwm3_freq.dev_attr.attr, |
1775 | &sensor_dev_attr_pwm3_enable.dev_attr.attr, | 1796 | &sensor_dev_attr_pwm3_enable.dev_attr.attr, |
1776 | &sensor_dev_attr_pwm3_ramp_rate.dev_attr.attr, | 1797 | &sensor_dev_attr_pwm3_ramp_rate.dev_attr.attr, |
1777 | &sensor_dev_attr_pwm3_auto_channels_zone.dev_attr.attr, | 1798 | &sensor_dev_attr_pwm3_auto_channels_zone.dev_attr.attr, |
1778 | &sensor_dev_attr_pwm3_auto_pwm_min.dev_attr.attr, | ||
1779 | &sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr, | 1799 | &sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr, |
1780 | NULL | 1800 | NULL |
1781 | }; | 1801 | }; |
1782 | static struct attribute *dme1737_attr_pwm5_lock[] = { | 1802 | static struct attribute *dme1737_pwm5_chmod_attr[] = { |
1783 | &sensor_dev_attr_pwm5.dev_attr.attr, | 1803 | &sensor_dev_attr_pwm5.dev_attr.attr, |
1784 | &sensor_dev_attr_pwm5_freq.dev_attr.attr, | 1804 | &sensor_dev_attr_pwm5_freq.dev_attr.attr, |
1785 | NULL | 1805 | NULL |
1786 | }; | 1806 | }; |
1787 | static struct attribute *dme1737_attr_pwm6_lock[] = { | 1807 | static struct attribute *dme1737_pwm6_chmod_attr[] = { |
1788 | &sensor_dev_attr_pwm6.dev_attr.attr, | 1808 | &sensor_dev_attr_pwm6.dev_attr.attr, |
1789 | &sensor_dev_attr_pwm6_freq.dev_attr.attr, | 1809 | &sensor_dev_attr_pwm6_freq.dev_attr.attr, |
1790 | NULL | 1810 | NULL |
1791 | }; | 1811 | }; |
1792 | 1812 | ||
1793 | static const struct attribute_group dme1737_pwm_lock_group[] = { | 1813 | static const struct attribute_group dme1737_pwm_chmod_group[] = { |
1794 | { .attrs = dme1737_attr_pwm1_lock }, | 1814 | { .attrs = dme1737_pwm1_chmod_attr }, |
1795 | { .attrs = dme1737_attr_pwm2_lock }, | 1815 | { .attrs = dme1737_pwm2_chmod_attr }, |
1796 | { .attrs = dme1737_attr_pwm3_lock }, | 1816 | { .attrs = dme1737_pwm3_chmod_attr }, |
1797 | { .attrs = NULL }, | 1817 | { .attrs = NULL }, |
1798 | { .attrs = dme1737_attr_pwm5_lock }, | 1818 | { .attrs = dme1737_pwm5_chmod_attr }, |
1799 | { .attrs = dme1737_attr_pwm6_lock }, | 1819 | { .attrs = dme1737_pwm6_chmod_attr }, |
1800 | }; | 1820 | }; |
1801 | 1821 | ||
1802 | /* Pwm[1-3] are read-writeable if the associated pwm is in manual mode and the | 1822 | /* Pwm[1-3] are read-writeable if the associated pwm is in manual mode and the |
1803 | * chip is not locked. Otherwise they are read-only. */ | 1823 | * chip is not locked. Otherwise they are read-only. */ |
1804 | static struct attribute *dme1737_attr_pwm[] = { | 1824 | static struct attribute *dme1737_pwm_chmod_attr[] = { |
1805 | &sensor_dev_attr_pwm1.dev_attr.attr, | 1825 | &sensor_dev_attr_pwm1.dev_attr.attr, |
1806 | &sensor_dev_attr_pwm2.dev_attr.attr, | 1826 | &sensor_dev_attr_pwm2.dev_attr.attr, |
1807 | &sensor_dev_attr_pwm3.dev_attr.attr, | 1827 | &sensor_dev_attr_pwm3.dev_attr.attr, |
@@ -1875,9 +1895,17 @@ static void dme1737_remove_files(struct device *dev) | |||
1875 | if (data->has_pwm & (1 << ix)) { | 1895 | if (data->has_pwm & (1 << ix)) { |
1876 | sysfs_remove_group(&dev->kobj, | 1896 | sysfs_remove_group(&dev->kobj, |
1877 | &dme1737_pwm_group[ix]); | 1897 | &dme1737_pwm_group[ix]); |
1898 | if (data->type != sch5027 && ix < 3) { | ||
1899 | sysfs_remove_file(&dev->kobj, | ||
1900 | dme1737_pwm_misc_attr[ix]); | ||
1901 | } | ||
1878 | } | 1902 | } |
1879 | } | 1903 | } |
1880 | 1904 | ||
1905 | if (data->type != sch5027) { | ||
1906 | sysfs_remove_group(&dev->kobj, &dme1737_misc_group); | ||
1907 | } | ||
1908 | |||
1881 | sysfs_remove_group(&dev->kobj, &dme1737_group); | 1909 | sysfs_remove_group(&dev->kobj, &dme1737_group); |
1882 | 1910 | ||
1883 | if (!data->client.driver) { | 1911 | if (!data->client.driver) { |
@@ -1901,6 +1929,13 @@ static int dme1737_create_files(struct device *dev) | |||
1901 | goto exit_remove; | 1929 | goto exit_remove; |
1902 | } | 1930 | } |
1903 | 1931 | ||
1932 | /* Create misc sysfs attributes */ | ||
1933 | if ((data->type != sch5027) && | ||
1934 | (err = sysfs_create_group(&dev->kobj, | ||
1935 | &dme1737_misc_group))) { | ||
1936 | goto exit_remove; | ||
1937 | } | ||
1938 | |||
1904 | /* Create fan sysfs attributes */ | 1939 | /* Create fan sysfs attributes */ |
1905 | for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) { | 1940 | for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) { |
1906 | if (data->has_fan & (1 << ix)) { | 1941 | if (data->has_fan & (1 << ix)) { |
@@ -1918,6 +1953,11 @@ static int dme1737_create_files(struct device *dev) | |||
1918 | &dme1737_pwm_group[ix]))) { | 1953 | &dme1737_pwm_group[ix]))) { |
1919 | goto exit_remove; | 1954 | goto exit_remove; |
1920 | } | 1955 | } |
1956 | if (data->type != sch5027 && ix < 3 && | ||
1957 | (err = sysfs_create_file(&dev->kobj, | ||
1958 | dme1737_pwm_misc_attr[ix]))) { | ||
1959 | goto exit_remove; | ||
1960 | } | ||
1921 | } | 1961 | } |
1922 | } | 1962 | } |
1923 | 1963 | ||
@@ -1927,16 +1967,27 @@ static int dme1737_create_files(struct device *dev) | |||
1927 | dev_info(dev, "Device is locked. Some attributes " | 1967 | dev_info(dev, "Device is locked. Some attributes " |
1928 | "will be read-only.\n"); | 1968 | "will be read-only.\n"); |
1929 | } else { | 1969 | } else { |
1930 | /* Change permissions of standard attributes */ | 1970 | /* Change permissions of zone sysfs attributes */ |
1931 | dme1737_chmod_group(dev, &dme1737_lock_group, | 1971 | dme1737_chmod_group(dev, &dme1737_zone_chmod_group, |
1932 | S_IRUGO | S_IWUSR); | 1972 | S_IRUGO | S_IWUSR); |
1933 | 1973 | ||
1934 | /* Change permissions of PWM attributes */ | 1974 | /* Change permissions of misc sysfs attributes */ |
1935 | for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_lock_group); ix++) { | 1975 | if (data->type != sch5027) { |
1976 | dme1737_chmod_group(dev, &dme1737_misc_group, | ||
1977 | S_IRUGO | S_IWUSR); | ||
1978 | } | ||
1979 | |||
1980 | /* Change permissions of PWM sysfs attributes */ | ||
1981 | for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_chmod_group); ix++) { | ||
1936 | if (data->has_pwm & (1 << ix)) { | 1982 | if (data->has_pwm & (1 << ix)) { |
1937 | dme1737_chmod_group(dev, | 1983 | dme1737_chmod_group(dev, |
1938 | &dme1737_pwm_lock_group[ix], | 1984 | &dme1737_pwm_chmod_group[ix], |
1985 | S_IRUGO | S_IWUSR); | ||
1986 | if (data->type != sch5027 && ix < 3) { | ||
1987 | dme1737_chmod_file(dev, | ||
1988 | dme1737_pwm_misc_attr[ix], | ||
1939 | S_IRUGO | S_IWUSR); | 1989 | S_IRUGO | S_IWUSR); |
1990 | } | ||
1940 | } | 1991 | } |
1941 | } | 1992 | } |
1942 | 1993 | ||
@@ -1945,7 +1996,7 @@ static int dme1737_create_files(struct device *dev) | |||
1945 | if ((data->has_pwm & (1 << ix)) && | 1996 | if ((data->has_pwm & (1 << ix)) && |
1946 | (PWM_EN_FROM_REG(data->pwm_config[ix]) == 1)) { | 1997 | (PWM_EN_FROM_REG(data->pwm_config[ix]) == 1)) { |
1947 | dme1737_chmod_file(dev, | 1998 | dme1737_chmod_file(dev, |
1948 | dme1737_attr_pwm[ix], | 1999 | dme1737_pwm_chmod_attr[ix], |
1949 | S_IRUGO | S_IWUSR); | 2000 | S_IRUGO | S_IWUSR); |
1950 | } | 2001 | } |
1951 | } | 2002 | } |
@@ -1966,6 +2017,9 @@ static int dme1737_init_device(struct device *dev) | |||
1966 | int ix; | 2017 | int ix; |
1967 | u8 reg; | 2018 | u8 reg; |
1968 | 2019 | ||
2020 | /* Point to the right nominal voltages array */ | ||
2021 | data->in_nominal = IN_NOMINAL(data->type); | ||
2022 | |||
1969 | data->config = dme1737_read(client, DME1737_REG_CONFIG); | 2023 | data->config = dme1737_read(client, DME1737_REG_CONFIG); |
1970 | /* Inform if part is not monitoring/started */ | 2024 | /* Inform if part is not monitoring/started */ |
1971 | if (!(data->config & 0x01)) { | 2025 | if (!(data->config & 0x01)) { |
@@ -2076,7 +2130,9 @@ static int dme1737_init_device(struct device *dev) | |||
2076 | data->pwm_acz[2] = 4; /* pwm3 -> zone3 */ | 2130 | data->pwm_acz[2] = 4; /* pwm3 -> zone3 */ |
2077 | 2131 | ||
2078 | /* Set VRM */ | 2132 | /* Set VRM */ |
2079 | data->vrm = vid_which_vrm(); | 2133 | if (data->type != sch5027) { |
2134 | data->vrm = vid_which_vrm(); | ||
2135 | } | ||
2080 | 2136 | ||
2081 | return 0; | 2137 | return 0; |
2082 | } | 2138 | } |
@@ -2095,9 +2151,10 @@ static int dme1737_i2c_get_features(int sio_cip, struct dme1737_data *data) | |||
2095 | dme1737_sio_enter(sio_cip); | 2151 | dme1737_sio_enter(sio_cip); |
2096 | 2152 | ||
2097 | /* Check device ID | 2153 | /* Check device ID |
2098 | * The DME1737 can return either 0x78 or 0x77 as its device ID. */ | 2154 | * The DME1737 can return either 0x78 or 0x77 as its device ID. |
2155 | * The SCH5027 returns 0x89 as its device ID. */ | ||
2099 | reg = force_id ? force_id : dme1737_sio_inb(sio_cip, 0x20); | 2156 | reg = force_id ? force_id : dme1737_sio_inb(sio_cip, 0x20); |
2100 | if (!(reg == 0x77 || reg == 0x78)) { | 2157 | if (!(reg == 0x77 || reg == 0x78 || reg == 0x89)) { |
2101 | err = -ENODEV; | 2158 | err = -ENODEV; |
2102 | goto exit; | 2159 | goto exit; |
2103 | } | 2160 | } |
@@ -2166,15 +2223,24 @@ static int dme1737_i2c_detect(struct i2c_adapter *adapter, int address, | |||
2166 | company = dme1737_read(client, DME1737_REG_COMPANY); | 2223 | company = dme1737_read(client, DME1737_REG_COMPANY); |
2167 | verstep = dme1737_read(client, DME1737_REG_VERSTEP); | 2224 | verstep = dme1737_read(client, DME1737_REG_VERSTEP); |
2168 | 2225 | ||
2169 | if (!((company == DME1737_COMPANY_SMSC) && | 2226 | if (company == DME1737_COMPANY_SMSC && |
2170 | ((verstep & DME1737_VERSTEP_MASK) == DME1737_VERSTEP))) { | 2227 | (verstep & DME1737_VERSTEP_MASK) == DME1737_VERSTEP) { |
2228 | kind = dme1737; | ||
2229 | } else if (company == DME1737_COMPANY_SMSC && | ||
2230 | verstep == SCH5027_VERSTEP) { | ||
2231 | kind = sch5027; | ||
2232 | } else { | ||
2171 | err = -ENODEV; | 2233 | err = -ENODEV; |
2172 | goto exit_kfree; | 2234 | goto exit_kfree; |
2173 | } | 2235 | } |
2174 | } | 2236 | } |
2175 | 2237 | ||
2176 | kind = dme1737; | 2238 | if (kind == sch5027) { |
2177 | name = "dme1737"; | 2239 | name = "sch5027"; |
2240 | } else { | ||
2241 | kind = dme1737; | ||
2242 | name = "dme1737"; | ||
2243 | } | ||
2178 | data->type = kind; | 2244 | data->type = kind; |
2179 | 2245 | ||
2180 | /* Fill in the remaining client fields and put it into the global | 2246 | /* Fill in the remaining client fields and put it into the global |
@@ -2187,8 +2253,9 @@ static int dme1737_i2c_detect(struct i2c_adapter *adapter, int address, | |||
2187 | goto exit_kfree; | 2253 | goto exit_kfree; |
2188 | } | 2254 | } |
2189 | 2255 | ||
2190 | dev_info(dev, "Found a DME1737 chip at 0x%02x (rev 0x%02x).\n", | 2256 | dev_info(dev, "Found a %s chip at 0x%02x (rev 0x%02x).\n", |
2191 | client->addr, verstep); | 2257 | kind == sch5027 ? "SCH5027" : "DME1737", client->addr, |
2258 | verstep); | ||
2192 | 2259 | ||
2193 | /* Initialize the DME1737 chip */ | 2260 | /* Initialize the DME1737 chip */ |
2194 | if ((err = dme1737_init_device(dev))) { | 2261 | if ((err = dme1737_init_device(dev))) { |
@@ -2360,15 +2427,18 @@ static int __devinit dme1737_isa_probe(struct platform_device *pdev) | |||
2360 | client->addr = res->start; | 2427 | client->addr = res->start; |
2361 | platform_set_drvdata(pdev, data); | 2428 | platform_set_drvdata(pdev, data); |
2362 | 2429 | ||
2363 | company = dme1737_read(client, DME1737_REG_COMPANY); | 2430 | /* Skip chip detection if module is loaded with force_id parameter */ |
2364 | device = dme1737_read(client, DME1737_REG_DEVICE); | 2431 | if (!force_id) { |
2432 | company = dme1737_read(client, DME1737_REG_COMPANY); | ||
2433 | device = dme1737_read(client, DME1737_REG_DEVICE); | ||
2365 | 2434 | ||
2366 | if (!((company == DME1737_COMPANY_SMSC) && | 2435 | if (!((company == DME1737_COMPANY_SMSC) && |
2367 | (device == SCH311X_DEVICE))) { | 2436 | (device == SCH311X_DEVICE))) { |
2368 | err = -ENODEV; | 2437 | err = -ENODEV; |
2369 | goto exit_kfree; | 2438 | goto exit_kfree; |
2439 | } | ||
2370 | } | 2440 | } |
2371 | data->type = -1; | 2441 | data->type = sch311x; |
2372 | 2442 | ||
2373 | /* Fill in the remaining client fields and initialize the mutex */ | 2443 | /* Fill in the remaining client fields and initialize the mutex */ |
2374 | strlcpy(client->name, "sch311x", I2C_NAME_SIZE); | 2444 | strlcpy(client->name, "sch311x", I2C_NAME_SIZE); |
diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c index cbeb4984b5c7..67067e9a323e 100644 --- a/drivers/hwmon/f71882fg.c +++ b/drivers/hwmon/f71882fg.c | |||
@@ -87,8 +87,6 @@ static inline void superio_enter(int base); | |||
87 | static inline void superio_select(int base, int ld); | 87 | static inline void superio_select(int base, int ld); |
88 | static inline void superio_exit(int base); | 88 | static inline void superio_exit(int base); |
89 | 89 | ||
90 | static inline u16 fan_from_reg ( u16 reg ); | ||
91 | |||
92 | struct f71882fg_data { | 90 | struct f71882fg_data { |
93 | unsigned short addr; | 91 | unsigned short addr; |
94 | struct device *hwmon_dev; | 92 | struct device *hwmon_dev; |
@@ -116,10 +114,6 @@ struct f71882fg_data { | |||
116 | u8 temp_diode_open; | 114 | u8 temp_diode_open; |
117 | }; | 115 | }; |
118 | 116 | ||
119 | static u8 f71882fg_read8(struct f71882fg_data *data, u8 reg); | ||
120 | static u16 f71882fg_read16(struct f71882fg_data *data, u8 reg); | ||
121 | static void f71882fg_write8(struct f71882fg_data *data, u8 reg, u8 val); | ||
122 | |||
123 | /* Sysfs in*/ | 117 | /* Sysfs in*/ |
124 | static ssize_t show_in(struct device *dev, struct device_attribute *devattr, | 118 | static ssize_t show_in(struct device *dev, struct device_attribute *devattr, |
125 | char *buf); | 119 | char *buf); |
diff --git a/drivers/hwmon/hwmon-vid.c b/drivers/hwmon/hwmon-vid.c index 3330667280b9..7b0a32c4dcfb 100644 --- a/drivers/hwmon/hwmon-vid.c +++ b/drivers/hwmon/hwmon-vid.c | |||
@@ -1,76 +1,74 @@ | |||
1 | /* | 1 | /* |
2 | hwmon-vid.c - VID/VRM/VRD voltage conversions | 2 | * hwmon-vid.c - VID/VRM/VRD voltage conversions |
3 | 3 | * | |
4 | Copyright (c) 2004 Rudolf Marek <r.marek@assembler.cz> | 4 | * Copyright (c) 2004 Rudolf Marek <r.marek@assembler.cz> |
5 | 5 | * | |
6 | Partly imported from i2c-vid.h of the lm_sensors project | 6 | * Partly imported from i2c-vid.h of the lm_sensors project |
7 | Copyright (c) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com> | 7 | * Copyright (c) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com> |
8 | With assistance from Trent Piepho <xyzzy@speakeasy.org> | 8 | * With assistance from Trent Piepho <xyzzy@speakeasy.org> |
9 | 9 | * | |
10 | This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | it under the terms of the GNU General Public License as published by | 11 | * it under the terms of the GNU General Public License as published by |
12 | the Free Software Foundation; either version 2 of the License, or | 12 | * the Free Software Foundation; either version 2 of the License, or |
13 | (at your option) any later version. | 13 | * (at your option) any later version. |
14 | 14 | * | |
15 | This program is distributed in the hope that it will be useful, | 15 | * This program is distributed in the hope that it will be useful, |
16 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
18 | GNU General Public License for more details. | 18 | * GNU General Public License for more details. |
19 | 19 | * | |
20 | You should have received a copy of the GNU General Public License | 20 | * You should have received a copy of the GNU General Public License |
21 | along with this program; if not, write to the Free Software | 21 | * along with this program; if not, write to the Free Software |
22 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 22 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include <linux/module.h> | 25 | #include <linux/module.h> |
26 | #include <linux/kernel.h> | 26 | #include <linux/kernel.h> |
27 | #include <linux/hwmon-vid.h> | 27 | #include <linux/hwmon-vid.h> |
28 | 28 | ||
29 | /* | 29 | /* |
30 | Common code for decoding VID pins. | 30 | * Common code for decoding VID pins. |
31 | 31 | * | |
32 | References: | 32 | * References: |
33 | 33 | * | |
34 | For VRM 8.4 to 9.1, "VRM x.y DC-DC Converter Design Guidelines", | 34 | * For VRM 8.4 to 9.1, "VRM x.y DC-DC Converter Design Guidelines", |
35 | available at http://developer.intel.com/. | 35 | * available at http://developer.intel.com/. |
36 | 36 | * | |
37 | For VRD 10.0 and up, "VRD x.y Design Guide", | 37 | * For VRD 10.0 and up, "VRD x.y Design Guide", |
38 | available at http://developer.intel.com/. | 38 | * available at http://developer.intel.com/. |
39 | 39 | * | |
40 | AMD Opteron processors don't follow the Intel specifications. | 40 | * AMD NPT 0Fh (Athlon64 & Opteron), AMD Publication 32559, |
41 | I'm going to "make up" 2.4 as the spec number for the Opterons. | 41 | * http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/32559.pdf |
42 | No good reason just a mnemonic for the 24x Opteron processor | 42 | * Table 71. VID Code Voltages |
43 | series. | 43 | * AMD Opteron processors don't follow the Intel specifications. |
44 | 44 | * I'm going to "make up" 2.4 as the spec number for the Opterons. | |
45 | Opteron VID encoding is: | 45 | * No good reason just a mnemonic for the 24x Opteron processor |
46 | 00000 = 1.550 V | 46 | * series. |
47 | 00001 = 1.525 V | 47 | * |
48 | . . . . | 48 | * The 17 specification is in fact Intel Mobile Voltage Positioning - |
49 | 11110 = 0.800 V | 49 | * (IMVP-II). You can find more information in the datasheet of Max1718 |
50 | 11111 = 0.000 V (off) | 50 | * http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2452 |
51 | 51 | * | |
52 | The 17 specification is in fact Intel Mobile Voltage Positioning - | 52 | * The 13 specification corresponds to the Intel Pentium M series. There |
53 | (IMVP-II). You can find more information in the datasheet of Max1718 | 53 | * doesn't seem to be any named specification for these. The conversion |
54 | http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2452 | 54 | * tables are detailed directly in the various Pentium M datasheets: |
55 | 55 | * http://www.intel.com/design/intarch/pentiumm/docs_pentiumm.htm | |
56 | The 13 specification corresponds to the Intel Pentium M series. There | 56 | * |
57 | doesn't seem to be any named specification for these. The conversion | 57 | * The 14 specification corresponds to Intel Core series. There |
58 | tables are detailed directly in the various Pentium M datasheets: | 58 | * doesn't seem to be any named specification for these. The conversion |
59 | http://www.intel.com/design/intarch/pentiumm/docs_pentiumm.htm | 59 | * tables are detailed directly in the various Pentium Core datasheets: |
60 | 60 | * http://www.intel.com/design/mobile/datashts/309221.htm | |
61 | The 14 specification corresponds to Intel Core series. There | 61 | * |
62 | doesn't seem to be any named specification for these. The conversion | 62 | * The 110 (VRM 11) specification corresponds to Intel Conroe based series. |
63 | tables are detailed directly in the various Pentium Core datasheets: | 63 | * http://www.intel.com/design/processor/applnots/313214.htm |
64 | http://www.intel.com/design/mobile/datashts/309221.htm | 64 | */ |
65 | 65 | ||
66 | The 110 (VRM 11) specification corresponds to Intel Conroe based series. | 66 | /* |
67 | http://www.intel.com/design/processor/applnots/313214.htm | 67 | * vrm is the VRM/VRD document version multiplied by 10. |
68 | */ | 68 | * val is the 4-bit or more VID code. |
69 | 69 | * Returned value is in mV to avoid floating point in the kernel. | |
70 | /* vrm is the VRM/VRD document version multiplied by 10. | 70 | * Some VID have some bits in uV scale, this is rounded to mV. |
71 | val is the 4-bit or more VID code. | 71 | */ |
72 | Returned value is in mV to avoid floating point in the kernel. | ||
73 | Some VID have some bits in uV scale, this is rounded to mV */ | ||
74 | int vid_from_reg(int val, u8 vrm) | 72 | int vid_from_reg(int val, u8 vrm) |
75 | { | 73 | { |
76 | int vid; | 74 | int vid; |
@@ -96,9 +94,11 @@ int vid_from_reg(int val, u8 vrm) | |||
96 | if (val < 0x02 || val > 0xb2) | 94 | if (val < 0x02 || val > 0xb2) |
97 | return 0; | 95 | return 0; |
98 | return((1600000 - (val - 2) * 6250 + 500) / 1000); | 96 | return((1600000 - (val - 2) * 6250 + 500) / 1000); |
99 | case 24: /* Opteron processor */ | 97 | |
100 | val &= 0x1f; | 98 | case 24: /* AMD NPT 0Fh (Athlon64 & Opteron) */ |
101 | return(val == 0x1f ? 0 : 1550 - val * 25); | 99 | val &= 0x3f; |
100 | return (val < 32) ? 1550 - 25 * val | ||
101 | : 775 - (25 * (val - 31)) / 2; | ||
102 | 102 | ||
103 | case 91: /* VRM 9.1 */ | 103 | case 91: /* VRM 9.1 */ |
104 | case 90: /* VRM 9.0 */ | 104 | case 90: /* VRM 9.0 */ |
@@ -141,9 +141,9 @@ int vid_from_reg(int val, u8 vrm) | |||
141 | 141 | ||
142 | 142 | ||
143 | /* | 143 | /* |
144 | After this point is the code to automatically determine which | 144 | * After this point is the code to automatically determine which |
145 | VRM/VRD specification should be used depending on the CPU. | 145 | * VRM/VRD specification should be used depending on the CPU. |
146 | */ | 146 | */ |
147 | 147 | ||
148 | struct vrm_model { | 148 | struct vrm_model { |
149 | u8 vendor; | 149 | u8 vendor; |
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index e12c132ff83a..30cdb0956779 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c | |||
@@ -151,9 +151,9 @@ static int fix_pwm_polarity; | |||
151 | /* The IT8718F has the VID value in a different register, in Super-I/O | 151 | /* The IT8718F has the VID value in a different register, in Super-I/O |
152 | configuration space. */ | 152 | configuration space. */ |
153 | #define IT87_REG_VID 0x0a | 153 | #define IT87_REG_VID 0x0a |
154 | /* Warning: register 0x0b is used for something completely different in | 154 | /* The IT8705F and IT8712F earlier than revision 0x08 use register 0x0b |
155 | new chips/revisions. I suspect only 16-bit tachometer mode will work | 155 | for fan divisors. Later IT8712F revisions must use 16-bit tachometer |
156 | for these. */ | 156 | mode. */ |
157 | #define IT87_REG_FAN_DIV 0x0b | 157 | #define IT87_REG_FAN_DIV 0x0b |
158 | #define IT87_REG_FAN_16BIT 0x0c | 158 | #define IT87_REG_FAN_16BIT 0x0c |
159 | 159 | ||
@@ -234,6 +234,7 @@ static const unsigned int pwm_freq[8] = { | |||
234 | struct it87_sio_data { | 234 | struct it87_sio_data { |
235 | enum chips type; | 235 | enum chips type; |
236 | /* Values read from Super-I/O config space */ | 236 | /* Values read from Super-I/O config space */ |
237 | u8 revision; | ||
237 | u8 vid_value; | 238 | u8 vid_value; |
238 | }; | 239 | }; |
239 | 240 | ||
@@ -242,6 +243,7 @@ struct it87_sio_data { | |||
242 | struct it87_data { | 243 | struct it87_data { |
243 | struct device *hwmon_dev; | 244 | struct device *hwmon_dev; |
244 | enum chips type; | 245 | enum chips type; |
246 | u8 revision; | ||
245 | 247 | ||
246 | unsigned short addr; | 248 | unsigned short addr; |
247 | const char *name; | 249 | const char *name; |
@@ -268,6 +270,16 @@ struct it87_data { | |||
268 | u8 manual_pwm_ctl[3]; /* manual PWM value set by user */ | 270 | u8 manual_pwm_ctl[3]; /* manual PWM value set by user */ |
269 | }; | 271 | }; |
270 | 272 | ||
273 | static inline int has_16bit_fans(const struct it87_data *data) | ||
274 | { | ||
275 | /* IT8705F Datasheet 0.4.1, 3h == Version G. | ||
276 | IT8712F Datasheet 0.9.1, section 8.3.5 indicates 7h == Version I. | ||
277 | These are the first revisions with 16bit tachometer support. */ | ||
278 | return (data->type == it87 && data->revision >= 0x03) | ||
279 | || (data->type == it8712 && data->revision >= 0x07) | ||
280 | || data->type == it8716 | ||
281 | || data->type == it8718; | ||
282 | } | ||
271 | 283 | ||
272 | static int it87_probe(struct platform_device *pdev); | 284 | static int it87_probe(struct platform_device *pdev); |
273 | static int __devexit it87_remove(struct platform_device *pdev); | 285 | static int __devexit it87_remove(struct platform_device *pdev); |
@@ -991,8 +1003,9 @@ static int __init it87_find(unsigned short *address, | |||
991 | } | 1003 | } |
992 | 1004 | ||
993 | err = 0; | 1005 | err = 0; |
1006 | sio_data->revision = superio_inb(DEVREV) & 0x0f; | ||
994 | pr_info("it87: Found IT%04xF chip at 0x%x, revision %d\n", | 1007 | pr_info("it87: Found IT%04xF chip at 0x%x, revision %d\n", |
995 | chip_type, *address, superio_inb(DEVREV) & 0x0f); | 1008 | chip_type, *address, sio_data->revision); |
996 | 1009 | ||
997 | /* Read GPIO config and VID value from LDN 7 (GPIO) */ | 1010 | /* Read GPIO config and VID value from LDN 7 (GPIO) */ |
998 | if (chip_type != IT8705F_DEVID) { | 1011 | if (chip_type != IT8705F_DEVID) { |
@@ -1045,6 +1058,7 @@ static int __devinit it87_probe(struct platform_device *pdev) | |||
1045 | 1058 | ||
1046 | data->addr = res->start; | 1059 | data->addr = res->start; |
1047 | data->type = sio_data->type; | 1060 | data->type = sio_data->type; |
1061 | data->revision = sio_data->revision; | ||
1048 | data->name = names[sio_data->type]; | 1062 | data->name = names[sio_data->type]; |
1049 | 1063 | ||
1050 | /* Now, we do the remaining detection. */ | 1064 | /* Now, we do the remaining detection. */ |
@@ -1069,7 +1083,7 @@ static int __devinit it87_probe(struct platform_device *pdev) | |||
1069 | goto ERROR2; | 1083 | goto ERROR2; |
1070 | 1084 | ||
1071 | /* Do not create fan files for disabled fans */ | 1085 | /* Do not create fan files for disabled fans */ |
1072 | if (data->type == it8716 || data->type == it8718) { | 1086 | if (has_16bit_fans(data)) { |
1073 | /* 16-bit tachometers */ | 1087 | /* 16-bit tachometers */ |
1074 | if (data->has_fan & (1 << 0)) { | 1088 | if (data->has_fan & (1 << 0)) { |
1075 | if ((err = device_create_file(dev, | 1089 | if ((err = device_create_file(dev, |
@@ -1350,7 +1364,7 @@ static void __devinit it87_init_device(struct platform_device *pdev) | |||
1350 | data->has_fan = (data->fan_main_ctrl >> 4) & 0x07; | 1364 | data->has_fan = (data->fan_main_ctrl >> 4) & 0x07; |
1351 | 1365 | ||
1352 | /* Set tachometers to 16-bit mode if needed */ | 1366 | /* Set tachometers to 16-bit mode if needed */ |
1353 | if (data->type == it8716 || data->type == it8718) { | 1367 | if (has_16bit_fans(data)) { |
1354 | tmp = it87_read_value(data, IT87_REG_FAN_16BIT); | 1368 | tmp = it87_read_value(data, IT87_REG_FAN_16BIT); |
1355 | if (~tmp & 0x07 & data->has_fan) { | 1369 | if (~tmp & 0x07 & data->has_fan) { |
1356 | dev_dbg(&pdev->dev, | 1370 | dev_dbg(&pdev->dev, |
@@ -1358,10 +1372,13 @@ static void __devinit it87_init_device(struct platform_device *pdev) | |||
1358 | it87_write_value(data, IT87_REG_FAN_16BIT, | 1372 | it87_write_value(data, IT87_REG_FAN_16BIT, |
1359 | tmp | 0x07); | 1373 | tmp | 0x07); |
1360 | } | 1374 | } |
1361 | if (tmp & (1 << 4)) | 1375 | /* IT8705F only supports three fans. */ |
1362 | data->has_fan |= (1 << 3); /* fan4 enabled */ | 1376 | if (data->type != it87) { |
1363 | if (tmp & (1 << 5)) | 1377 | if (tmp & (1 << 4)) |
1364 | data->has_fan |= (1 << 4); /* fan5 enabled */ | 1378 | data->has_fan |= (1 << 3); /* fan4 enabled */ |
1379 | if (tmp & (1 << 5)) | ||
1380 | data->has_fan |= (1 << 4); /* fan5 enabled */ | ||
1381 | } | ||
1365 | } | 1382 | } |
1366 | 1383 | ||
1367 | /* Set current fan mode registers and the default settings for the | 1384 | /* Set current fan mode registers and the default settings for the |
@@ -1426,7 +1443,7 @@ static struct it87_data *it87_update_device(struct device *dev) | |||
1426 | data->fan[i] = it87_read_value(data, | 1443 | data->fan[i] = it87_read_value(data, |
1427 | IT87_REG_FAN[i]); | 1444 | IT87_REG_FAN[i]); |
1428 | /* Add high byte if in 16-bit mode */ | 1445 | /* Add high byte if in 16-bit mode */ |
1429 | if (data->type == it8716 || data->type == it8718) { | 1446 | if (has_16bit_fans(data)) { |
1430 | data->fan[i] |= it87_read_value(data, | 1447 | data->fan[i] |= it87_read_value(data, |
1431 | IT87_REG_FANX[i]) << 8; | 1448 | IT87_REG_FANX[i]) << 8; |
1432 | data->fan_min[i] |= it87_read_value(data, | 1449 | data->fan_min[i] |= it87_read_value(data, |
@@ -1443,8 +1460,7 @@ static struct it87_data *it87_update_device(struct device *dev) | |||
1443 | } | 1460 | } |
1444 | 1461 | ||
1445 | /* Newer chips don't have clock dividers */ | 1462 | /* Newer chips don't have clock dividers */ |
1446 | if ((data->has_fan & 0x07) && data->type != it8716 | 1463 | if ((data->has_fan & 0x07) && !has_16bit_fans(data)) { |
1447 | && data->type != it8718) { | ||
1448 | i = it87_read_value(data, IT87_REG_FAN_DIV); | 1464 | i = it87_read_value(data, IT87_REG_FAN_DIV); |
1449 | data->fan_div[0] = i & 0x07; | 1465 | data->fan_div[0] = i & 0x07; |
1450 | data->fan_div[1] = (i >> 3) & 0x07; | 1466 | data->fan_div[1] = (i >> 3) & 0x07; |
@@ -1460,7 +1476,8 @@ static struct it87_data *it87_update_device(struct device *dev) | |||
1460 | data->fan_ctl = it87_read_value(data, IT87_REG_FAN_CTL); | 1476 | data->fan_ctl = it87_read_value(data, IT87_REG_FAN_CTL); |
1461 | 1477 | ||
1462 | data->sensor = it87_read_value(data, IT87_REG_TEMP_ENABLE); | 1478 | data->sensor = it87_read_value(data, IT87_REG_TEMP_ENABLE); |
1463 | /* The 8705 does not have VID capability */ | 1479 | /* The 8705 does not have VID capability. |
1480 | The 8718 does not use IT87_REG_VID for the same purpose. */ | ||
1464 | if (data->type == it8712 || data->type == it8716) { | 1481 | if (data->type == it8712 || data->type == it8716) { |
1465 | data->vid = it87_read_value(data, IT87_REG_VID); | 1482 | data->vid = it87_read_value(data, IT87_REG_VID); |
1466 | /* The older IT8712F revisions had only 5 VID pins, | 1483 | /* The older IT8712F revisions had only 5 VID pins, |
diff --git a/drivers/hwmon/thmc50.c b/drivers/hwmon/thmc50.c index 3b01001108c1..7d97431e132f 100644 --- a/drivers/hwmon/thmc50.c +++ b/drivers/hwmon/thmc50.c | |||
@@ -55,8 +55,11 @@ I2C_CLIENT_MODULE_PARM(adm1022_temp3, "List of adapter,address pairs " | |||
55 | static const u8 THMC50_REG_TEMP[] = { 0x27, 0x26, 0x20 }; | 55 | static const u8 THMC50_REG_TEMP[] = { 0x27, 0x26, 0x20 }; |
56 | static const u8 THMC50_REG_TEMP_MIN[] = { 0x3A, 0x38, 0x2C }; | 56 | static const u8 THMC50_REG_TEMP_MIN[] = { 0x3A, 0x38, 0x2C }; |
57 | static const u8 THMC50_REG_TEMP_MAX[] = { 0x39, 0x37, 0x2B }; | 57 | static const u8 THMC50_REG_TEMP_MAX[] = { 0x39, 0x37, 0x2B }; |
58 | static const u8 THMC50_REG_TEMP_CRITICAL[] = { 0x13, 0x14, 0x14 }; | ||
59 | static const u8 THMC50_REG_TEMP_DEFAULT[] = { 0x17, 0x18, 0x18 }; | ||
58 | 60 | ||
59 | #define THMC50_REG_CONF_nFANOFF 0x20 | 61 | #define THMC50_REG_CONF_nFANOFF 0x20 |
62 | #define THMC50_REG_CONF_PROGRAMMED 0x08 | ||
60 | 63 | ||
61 | /* Each client has this additional data */ | 64 | /* Each client has this additional data */ |
62 | struct thmc50_data { | 65 | struct thmc50_data { |
@@ -72,6 +75,7 @@ struct thmc50_data { | |||
72 | s8 temp_input[3]; | 75 | s8 temp_input[3]; |
73 | s8 temp_max[3]; | 76 | s8 temp_max[3]; |
74 | s8 temp_min[3]; | 77 | s8 temp_min[3]; |
78 | s8 temp_critical[3]; | ||
75 | u8 analog_out; | 79 | u8 analog_out; |
76 | u8 alarms; | 80 | u8 alarms; |
77 | }; | 81 | }; |
@@ -199,6 +203,15 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, | |||
199 | return count; | 203 | return count; |
200 | } | 204 | } |
201 | 205 | ||
206 | static ssize_t show_temp_critical(struct device *dev, | ||
207 | struct device_attribute *attr, | ||
208 | char *buf) | ||
209 | { | ||
210 | int nr = to_sensor_dev_attr(attr)->index; | ||
211 | struct thmc50_data *data = thmc50_update_device(dev); | ||
212 | return sprintf(buf, "%d\n", data->temp_critical[nr] * 1000); | ||
213 | } | ||
214 | |||
202 | static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, | 215 | static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, |
203 | char *buf) | 216 | char *buf) |
204 | { | 217 | { |
@@ -214,7 +227,9 @@ static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp, \ | |||
214 | static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \ | 227 | static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \ |
215 | show_temp_min, set_temp_min, offset - 1); \ | 228 | show_temp_min, set_temp_min, offset - 1); \ |
216 | static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ | 229 | static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ |
217 | show_temp_max, set_temp_max, offset - 1); | 230 | show_temp_max, set_temp_max, offset - 1); \ |
231 | static SENSOR_DEVICE_ATTR(temp##offset##_crit, S_IRUGO, \ | ||
232 | show_temp_critical, NULL, offset - 1); | ||
218 | 233 | ||
219 | temp_reg(1); | 234 | temp_reg(1); |
220 | temp_reg(2); | 235 | temp_reg(2); |
@@ -234,10 +249,12 @@ static struct attribute *thmc50_attributes[] = { | |||
234 | &sensor_dev_attr_temp1_max.dev_attr.attr, | 249 | &sensor_dev_attr_temp1_max.dev_attr.attr, |
235 | &sensor_dev_attr_temp1_min.dev_attr.attr, | 250 | &sensor_dev_attr_temp1_min.dev_attr.attr, |
236 | &sensor_dev_attr_temp1_input.dev_attr.attr, | 251 | &sensor_dev_attr_temp1_input.dev_attr.attr, |
252 | &sensor_dev_attr_temp1_crit.dev_attr.attr, | ||
237 | &sensor_dev_attr_temp1_alarm.dev_attr.attr, | 253 | &sensor_dev_attr_temp1_alarm.dev_attr.attr, |
238 | &sensor_dev_attr_temp2_max.dev_attr.attr, | 254 | &sensor_dev_attr_temp2_max.dev_attr.attr, |
239 | &sensor_dev_attr_temp2_min.dev_attr.attr, | 255 | &sensor_dev_attr_temp2_min.dev_attr.attr, |
240 | &sensor_dev_attr_temp2_input.dev_attr.attr, | 256 | &sensor_dev_attr_temp2_input.dev_attr.attr, |
257 | &sensor_dev_attr_temp2_crit.dev_attr.attr, | ||
241 | &sensor_dev_attr_temp2_alarm.dev_attr.attr, | 258 | &sensor_dev_attr_temp2_alarm.dev_attr.attr, |
242 | &sensor_dev_attr_temp2_fault.dev_attr.attr, | 259 | &sensor_dev_attr_temp2_fault.dev_attr.attr, |
243 | &sensor_dev_attr_pwm1.dev_attr.attr, | 260 | &sensor_dev_attr_pwm1.dev_attr.attr, |
@@ -254,6 +271,7 @@ static struct attribute *temp3_attributes[] = { | |||
254 | &sensor_dev_attr_temp3_max.dev_attr.attr, | 271 | &sensor_dev_attr_temp3_max.dev_attr.attr, |
255 | &sensor_dev_attr_temp3_min.dev_attr.attr, | 272 | &sensor_dev_attr_temp3_min.dev_attr.attr, |
256 | &sensor_dev_attr_temp3_input.dev_attr.attr, | 273 | &sensor_dev_attr_temp3_input.dev_attr.attr, |
274 | &sensor_dev_attr_temp3_crit.dev_attr.attr, | ||
257 | &sensor_dev_attr_temp3_alarm.dev_attr.attr, | 275 | &sensor_dev_attr_temp3_alarm.dev_attr.attr, |
258 | &sensor_dev_attr_temp3_fault.dev_attr.attr, | 276 | &sensor_dev_attr_temp3_fault.dev_attr.attr, |
259 | NULL | 277 | NULL |
@@ -429,6 +447,10 @@ static struct thmc50_data *thmc50_update_device(struct device *dev) | |||
429 | 447 | ||
430 | int temps = data->has_temp3 ? 3 : 2; | 448 | int temps = data->has_temp3 ? 3 : 2; |
431 | int i; | 449 | int i; |
450 | int prog = i2c_smbus_read_byte_data(client, THMC50_REG_CONF); | ||
451 | |||
452 | prog &= THMC50_REG_CONF_PROGRAMMED; | ||
453 | |||
432 | for (i = 0; i < temps; i++) { | 454 | for (i = 0; i < temps; i++) { |
433 | data->temp_input[i] = i2c_smbus_read_byte_data(client, | 455 | data->temp_input[i] = i2c_smbus_read_byte_data(client, |
434 | THMC50_REG_TEMP[i]); | 456 | THMC50_REG_TEMP[i]); |
@@ -436,6 +458,10 @@ static struct thmc50_data *thmc50_update_device(struct device *dev) | |||
436 | THMC50_REG_TEMP_MAX[i]); | 458 | THMC50_REG_TEMP_MAX[i]); |
437 | data->temp_min[i] = i2c_smbus_read_byte_data(client, | 459 | data->temp_min[i] = i2c_smbus_read_byte_data(client, |
438 | THMC50_REG_TEMP_MIN[i]); | 460 | THMC50_REG_TEMP_MIN[i]); |
461 | data->temp_critical[i] = | ||
462 | i2c_smbus_read_byte_data(client, | ||
463 | prog ? THMC50_REG_TEMP_CRITICAL[i] | ||
464 | : THMC50_REG_TEMP_DEFAULT[i]); | ||
439 | } | 465 | } |
440 | data->analog_out = | 466 | data->analog_out = |
441 | i2c_smbus_read_byte_data(client, THMC50_REG_ANALOG_OUT); | 467 | i2c_smbus_read_byte_data(client, THMC50_REG_ANALOG_OUT); |
diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c index 9564fb069957..b30e5796cb26 100644 --- a/drivers/hwmon/w83627hf.c +++ b/drivers/hwmon/w83627hf.c | |||
@@ -67,10 +67,6 @@ module_param(force_i2c, byte, 0); | |||
67 | MODULE_PARM_DESC(force_i2c, | 67 | MODULE_PARM_DESC(force_i2c, |
68 | "Initialize the i2c address of the sensors"); | 68 | "Initialize the i2c address of the sensors"); |
69 | 69 | ||
70 | static int reset; | ||
71 | module_param(reset, bool, 0); | ||
72 | MODULE_PARM_DESC(reset, "Set to one to reset chip on load"); | ||
73 | |||
74 | static int init = 1; | 70 | static int init = 1; |
75 | module_param(init, bool, 0); | 71 | module_param(init, bool, 0); |
76 | MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization"); | 72 | MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization"); |
@@ -209,6 +205,13 @@ static const u16 w83627hf_reg_temp_over[] = { 0x39, 0x155, 0x255 }; | |||
209 | #define W83627HF_REG_PWM1 0x5A | 205 | #define W83627HF_REG_PWM1 0x5A |
210 | #define W83627HF_REG_PWM2 0x5B | 206 | #define W83627HF_REG_PWM2 0x5B |
211 | 207 | ||
208 | static const u8 W83627THF_REG_PWM_ENABLE[] = { | ||
209 | 0x04, /* FAN 1 mode */ | ||
210 | 0x04, /* FAN 2 mode */ | ||
211 | 0x12, /* FAN AUX mode */ | ||
212 | }; | ||
213 | static const u8 W83627THF_PWM_ENABLE_SHIFT[] = { 2, 4, 1 }; | ||
214 | |||
212 | #define W83627THF_REG_PWM1 0x01 /* 697HF/637HF/687THF too */ | 215 | #define W83627THF_REG_PWM1 0x01 /* 697HF/637HF/687THF too */ |
213 | #define W83627THF_REG_PWM2 0x03 /* 697HF/637HF/687THF too */ | 216 | #define W83627THF_REG_PWM2 0x03 /* 697HF/637HF/687THF too */ |
214 | #define W83627THF_REG_PWM3 0x11 /* 637HF/687THF too */ | 217 | #define W83627THF_REG_PWM3 0x11 /* 637HF/687THF too */ |
@@ -366,6 +369,9 @@ struct w83627hf_data { | |||
366 | u32 alarms; /* Register encoding, combined */ | 369 | u32 alarms; /* Register encoding, combined */ |
367 | u32 beep_mask; /* Register encoding, combined */ | 370 | u32 beep_mask; /* Register encoding, combined */ |
368 | u8 pwm[3]; /* Register value */ | 371 | u8 pwm[3]; /* Register value */ |
372 | u8 pwm_enable[3]; /* 1 = manual | ||
373 | 2 = thermal cruise (also called SmartFan I) | ||
374 | 3 = fan speed cruise */ | ||
369 | u8 pwm_freq[3]; /* Register value */ | 375 | u8 pwm_freq[3]; /* Register value */ |
370 | u16 sens[3]; /* 1 = pentium diode; 2 = 3904 diode; | 376 | u16 sens[3]; /* 1 = pentium diode; 2 = 3904 diode; |
371 | 4 = thermistor */ | 377 | 4 = thermistor */ |
@@ -957,6 +963,42 @@ static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 1); | |||
957 | static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 2); | 963 | static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 2); |
958 | 964 | ||
959 | static ssize_t | 965 | static ssize_t |
966 | show_pwm_enable(struct device *dev, struct device_attribute *devattr, char *buf) | ||
967 | { | ||
968 | int nr = to_sensor_dev_attr(devattr)->index; | ||
969 | struct w83627hf_data *data = w83627hf_update_device(dev); | ||
970 | return sprintf(buf, "%d\n", data->pwm_enable[nr]); | ||
971 | } | ||
972 | |||
973 | static ssize_t | ||
974 | store_pwm_enable(struct device *dev, struct device_attribute *devattr, | ||
975 | const char *buf, size_t count) | ||
976 | { | ||
977 | int nr = to_sensor_dev_attr(devattr)->index; | ||
978 | struct w83627hf_data *data = dev_get_drvdata(dev); | ||
979 | unsigned long val = simple_strtoul(buf, NULL, 10); | ||
980 | u8 reg; | ||
981 | |||
982 | if (!val || (val > 3)) /* modes 1, 2 and 3 are supported */ | ||
983 | return -EINVAL; | ||
984 | mutex_lock(&data->update_lock); | ||
985 | data->pwm_enable[nr] = val; | ||
986 | reg = w83627hf_read_value(data, W83627THF_REG_PWM_ENABLE[nr]); | ||
987 | reg &= ~(0x03 << W83627THF_PWM_ENABLE_SHIFT[nr]); | ||
988 | reg |= (val - 1) << W83627THF_PWM_ENABLE_SHIFT[nr]; | ||
989 | w83627hf_write_value(data, W83627THF_REG_PWM_ENABLE[nr], reg); | ||
990 | mutex_unlock(&data->update_lock); | ||
991 | return count; | ||
992 | } | ||
993 | |||
994 | static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO|S_IWUSR, show_pwm_enable, | ||
995 | store_pwm_enable, 0); | ||
996 | static SENSOR_DEVICE_ATTR(pwm2_enable, S_IRUGO|S_IWUSR, show_pwm_enable, | ||
997 | store_pwm_enable, 1); | ||
998 | static SENSOR_DEVICE_ATTR(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable, | ||
999 | store_pwm_enable, 2); | ||
1000 | |||
1001 | static ssize_t | ||
960 | show_pwm_freq(struct device *dev, struct device_attribute *devattr, char *buf) | 1002 | show_pwm_freq(struct device *dev, struct device_attribute *devattr, char *buf) |
961 | { | 1003 | { |
962 | int nr = to_sensor_dev_attr(devattr)->index; | 1004 | int nr = to_sensor_dev_attr(devattr)->index; |
@@ -1223,6 +1265,11 @@ static struct attribute *w83627hf_attributes_opt[] = { | |||
1223 | &sensor_dev_attr_pwm1_freq.dev_attr.attr, | 1265 | &sensor_dev_attr_pwm1_freq.dev_attr.attr, |
1224 | &sensor_dev_attr_pwm2_freq.dev_attr.attr, | 1266 | &sensor_dev_attr_pwm2_freq.dev_attr.attr, |
1225 | &sensor_dev_attr_pwm3_freq.dev_attr.attr, | 1267 | &sensor_dev_attr_pwm3_freq.dev_attr.attr, |
1268 | |||
1269 | &sensor_dev_attr_pwm1_enable.dev_attr.attr, | ||
1270 | &sensor_dev_attr_pwm2_enable.dev_attr.attr, | ||
1271 | &sensor_dev_attr_pwm3_enable.dev_attr.attr, | ||
1272 | |||
1226 | NULL | 1273 | NULL |
1227 | }; | 1274 | }; |
1228 | 1275 | ||
@@ -1366,6 +1413,19 @@ static int __devinit w83627hf_probe(struct platform_device *pdev) | |||
1366 | &sensor_dev_attr_pwm3_freq.dev_attr))) | 1413 | &sensor_dev_attr_pwm3_freq.dev_attr))) |
1367 | goto ERROR4; | 1414 | goto ERROR4; |
1368 | 1415 | ||
1416 | if (data->type != w83627hf) | ||
1417 | if ((err = device_create_file(dev, | ||
1418 | &sensor_dev_attr_pwm1_enable.dev_attr)) | ||
1419 | || (err = device_create_file(dev, | ||
1420 | &sensor_dev_attr_pwm2_enable.dev_attr))) | ||
1421 | goto ERROR4; | ||
1422 | |||
1423 | if (data->type == w83627thf || data->type == w83637hf | ||
1424 | || data->type == w83687thf) | ||
1425 | if ((err = device_create_file(dev, | ||
1426 | &sensor_dev_attr_pwm3_enable.dev_attr))) | ||
1427 | goto ERROR4; | ||
1428 | |||
1369 | data->hwmon_dev = hwmon_device_register(dev); | 1429 | data->hwmon_dev = hwmon_device_register(dev); |
1370 | if (IS_ERR(data->hwmon_dev)) { | 1430 | if (IS_ERR(data->hwmon_dev)) { |
1371 | err = PTR_ERR(data->hwmon_dev); | 1431 | err = PTR_ERR(data->hwmon_dev); |
@@ -1536,29 +1596,6 @@ static void __devinit w83627hf_init_device(struct platform_device *pdev) | |||
1536 | enum chips type = data->type; | 1596 | enum chips type = data->type; |
1537 | u8 tmp; | 1597 | u8 tmp; |
1538 | 1598 | ||
1539 | if (reset) { | ||
1540 | /* Resetting the chip has been the default for a long time, | ||
1541 | but repeatedly caused problems (fans going to full | ||
1542 | speed...) so it is now optional. It might even go away if | ||
1543 | nobody reports it as being useful, as I see very little | ||
1544 | reason why this would be needed at all. */ | ||
1545 | dev_info(&pdev->dev, "If reset=1 solved a problem you were " | ||
1546 | "having, please report!\n"); | ||
1547 | |||
1548 | /* save this register */ | ||
1549 | i = w83627hf_read_value(data, W83781D_REG_BEEP_CONFIG); | ||
1550 | /* Reset all except Watchdog values and last conversion values | ||
1551 | This sets fan-divs to 2, among others */ | ||
1552 | w83627hf_write_value(data, W83781D_REG_CONFIG, 0x80); | ||
1553 | /* Restore the register and disable power-on abnormal beep. | ||
1554 | This saves FAN 1/2/3 input/output values set by BIOS. */ | ||
1555 | w83627hf_write_value(data, W83781D_REG_BEEP_CONFIG, i | 0x80); | ||
1556 | /* Disable master beep-enable (reset turns it on). | ||
1557 | Individual beeps should be reset to off but for some reason | ||
1558 | disabling this bit helps some people not get beeped */ | ||
1559 | w83627hf_write_value(data, W83781D_REG_BEEP_INTS2, 0); | ||
1560 | } | ||
1561 | |||
1562 | /* Minimize conflicts with other winbond i2c-only clients... */ | 1599 | /* Minimize conflicts with other winbond i2c-only clients... */ |
1563 | /* disable i2c subclients... how to disable main i2c client?? */ | 1600 | /* disable i2c subclients... how to disable main i2c client?? */ |
1564 | /* force i2c address to relatively uncommon address */ | 1601 | /* force i2c address to relatively uncommon address */ |
@@ -1655,6 +1692,7 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev) | |||
1655 | { | 1692 | { |
1656 | struct w83627hf_data *data = dev_get_drvdata(dev); | 1693 | struct w83627hf_data *data = dev_get_drvdata(dev); |
1657 | int i, num_temps = (data->type == w83697hf) ? 2 : 3; | 1694 | int i, num_temps = (data->type == w83697hf) ? 2 : 3; |
1695 | int num_pwms = (data->type == w83697hf) ? 2 : 3; | ||
1658 | 1696 | ||
1659 | mutex_lock(&data->update_lock); | 1697 | mutex_lock(&data->update_lock); |
1660 | 1698 | ||
@@ -1707,6 +1745,15 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev) | |||
1707 | break; | 1745 | break; |
1708 | } | 1746 | } |
1709 | } | 1747 | } |
1748 | if (data->type != w83627hf) { | ||
1749 | for (i = 0; i < num_pwms; i++) { | ||
1750 | u8 tmp = w83627hf_read_value(data, | ||
1751 | W83627THF_REG_PWM_ENABLE[i]); | ||
1752 | data->pwm_enable[i] = | ||
1753 | ((tmp >> W83627THF_PWM_ENABLE_SHIFT[i]) | ||
1754 | & 0x03) + 1; | ||
1755 | } | ||
1756 | } | ||
1710 | for (i = 0; i < num_temps; i++) { | 1757 | for (i = 0; i < num_temps; i++) { |
1711 | data->temp[i] = w83627hf_read_value( | 1758 | data->temp[i] = w83627hf_read_value( |
1712 | data, w83627hf_reg_temp[i]); | 1759 | data, w83627hf_reg_temp[i]); |
diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c index e4e91c9d480a..daa7d121483b 100644 --- a/drivers/hwmon/w83791d.c +++ b/drivers/hwmon/w83791d.c | |||
@@ -233,11 +233,9 @@ static u8 fan_to_reg(long rpm, int div) | |||
233 | static u8 div_to_reg(int nr, long val) | 233 | static u8 div_to_reg(int nr, long val) |
234 | { | 234 | { |
235 | int i; | 235 | int i; |
236 | int max; | ||
237 | 236 | ||
238 | /* first three fan's divisor max out at 8, rest max out at 128 */ | 237 | /* fan divisors max out at 128 */ |
239 | max = (nr < 3) ? 8 : 128; | 238 | val = SENSORS_LIMIT(val, 1, 128) >> 1; |
240 | val = SENSORS_LIMIT(val, 1, max) >> 1; | ||
241 | for (i = 0; i < 7; i++) { | 239 | for (i = 0; i < 7; i++) { |
242 | if (val == 0) | 240 | if (val == 0) |
243 | break; | 241 | break; |
@@ -530,6 +528,7 @@ static ssize_t store_fan_div(struct device *dev, struct device_attribute *attr, | |||
530 | unsigned long min; | 528 | unsigned long min; |
531 | u8 tmp_fan_div; | 529 | u8 tmp_fan_div; |
532 | u8 fan_div_reg; | 530 | u8 fan_div_reg; |
531 | u8 vbat_reg; | ||
533 | int indx = 0; | 532 | int indx = 0; |
534 | u8 keep_mask = 0; | 533 | u8 keep_mask = 0; |
535 | u8 new_shift = 0; | 534 | u8 new_shift = 0; |
@@ -581,6 +580,16 @@ static ssize_t store_fan_div(struct device *dev, struct device_attribute *attr, | |||
581 | w83791d_write(client, W83791D_REG_FAN_DIV[indx], | 580 | w83791d_write(client, W83791D_REG_FAN_DIV[indx], |
582 | fan_div_reg | tmp_fan_div); | 581 | fan_div_reg | tmp_fan_div); |
583 | 582 | ||
583 | /* Bit 2 of fans 0-2 is stored in the vbat register (bits 5-7) */ | ||
584 | if (nr < 3) { | ||
585 | keep_mask = ~(1 << (nr + 5)); | ||
586 | vbat_reg = w83791d_read(client, W83791D_REG_VBAT) | ||
587 | & keep_mask; | ||
588 | tmp_fan_div = (data->fan_div[nr] << (3 + nr)) & ~keep_mask; | ||
589 | w83791d_write(client, W83791D_REG_VBAT, | ||
590 | vbat_reg | tmp_fan_div); | ||
591 | } | ||
592 | |||
584 | /* Restore fan_min */ | 593 | /* Restore fan_min */ |
585 | data->fan_min[nr] = fan_to_reg(min, DIV_FROM_REG(data->fan_div[nr])); | 594 | data->fan_min[nr] = fan_to_reg(min, DIV_FROM_REG(data->fan_div[nr])); |
586 | w83791d_write(client, W83791D_REG_FAN_MIN[nr], data->fan_min[nr]); | 595 | w83791d_write(client, W83791D_REG_FAN_MIN[nr], data->fan_min[nr]); |
@@ -1182,6 +1191,7 @@ static struct w83791d_data *w83791d_update_device(struct device *dev) | |||
1182 | struct w83791d_data *data = i2c_get_clientdata(client); | 1191 | struct w83791d_data *data = i2c_get_clientdata(client); |
1183 | int i, j; | 1192 | int i, j; |
1184 | u8 reg_array_tmp[3]; | 1193 | u8 reg_array_tmp[3]; |
1194 | u8 vbat_reg; | ||
1185 | 1195 | ||
1186 | mutex_lock(&data->update_lock); | 1196 | mutex_lock(&data->update_lock); |
1187 | 1197 | ||
@@ -1219,6 +1229,12 @@ static struct w83791d_data *w83791d_update_device(struct device *dev) | |||
1219 | data->fan_div[3] = reg_array_tmp[2] & 0x07; | 1229 | data->fan_div[3] = reg_array_tmp[2] & 0x07; |
1220 | data->fan_div[4] = (reg_array_tmp[2] >> 4) & 0x07; | 1230 | data->fan_div[4] = (reg_array_tmp[2] >> 4) & 0x07; |
1221 | 1231 | ||
1232 | /* The fan divisor for fans 0-2 get bit 2 from | ||
1233 | bits 5-7 respectively of vbat register */ | ||
1234 | vbat_reg = w83791d_read(client, W83791D_REG_VBAT); | ||
1235 | for (i = 0; i < 3; i++) | ||
1236 | data->fan_div[i] |= (vbat_reg >> (3 + i)) & 0x04; | ||
1237 | |||
1222 | /* Update the first temperature sensor */ | 1238 | /* Update the first temperature sensor */ |
1223 | for (i = 0; i < 3; i++) { | 1239 | for (i = 0; i < 3; i++) { |
1224 | data->temp1[i] = w83791d_read(client, | 1240 | data->temp1[i] = w83791d_read(client, |
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index e980ff3335db..d951896ff7fc 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c | |||
@@ -155,9 +155,7 @@ struct cma_multicast { | |||
155 | } multicast; | 155 | } multicast; |
156 | struct list_head list; | 156 | struct list_head list; |
157 | void *context; | 157 | void *context; |
158 | struct sockaddr addr; | 158 | struct sockaddr_storage addr; |
159 | u8 pad[sizeof(struct sockaddr_in6) - | ||
160 | sizeof(struct sockaddr)]; | ||
161 | }; | 159 | }; |
162 | 160 | ||
163 | struct cma_work { | 161 | struct cma_work { |
@@ -786,8 +784,8 @@ static void cma_cancel_operation(struct rdma_id_private *id_priv, | |||
786 | cma_cancel_route(id_priv); | 784 | cma_cancel_route(id_priv); |
787 | break; | 785 | break; |
788 | case CMA_LISTEN: | 786 | case CMA_LISTEN: |
789 | if (cma_any_addr(&id_priv->id.route.addr.src_addr) && | 787 | if (cma_any_addr((struct sockaddr *) &id_priv->id.route.addr.src_addr) |
790 | !id_priv->cma_dev) | 788 | && !id_priv->cma_dev) |
791 | cma_cancel_listens(id_priv); | 789 | cma_cancel_listens(id_priv); |
792 | break; | 790 | break; |
793 | default: | 791 | default: |
@@ -1026,7 +1024,7 @@ static struct rdma_id_private *cma_new_conn_id(struct rdma_cm_id *listen_id, | |||
1026 | rt->path_rec[1] = *ib_event->param.req_rcvd.alternate_path; | 1024 | rt->path_rec[1] = *ib_event->param.req_rcvd.alternate_path; |
1027 | 1025 | ||
1028 | ib_addr_set_dgid(&rt->addr.dev_addr, &rt->path_rec[0].dgid); | 1026 | ib_addr_set_dgid(&rt->addr.dev_addr, &rt->path_rec[0].dgid); |
1029 | ret = rdma_translate_ip(&id->route.addr.src_addr, | 1027 | ret = rdma_translate_ip((struct sockaddr *) &id->route.addr.src_addr, |
1030 | &id->route.addr.dev_addr); | 1028 | &id->route.addr.dev_addr); |
1031 | if (ret) | 1029 | if (ret) |
1032 | goto destroy_id; | 1030 | goto destroy_id; |
@@ -1064,7 +1062,7 @@ static struct rdma_id_private *cma_new_udp_id(struct rdma_cm_id *listen_id, | |||
1064 | cma_save_net_info(&id->route.addr, &listen_id->route.addr, | 1062 | cma_save_net_info(&id->route.addr, &listen_id->route.addr, |
1065 | ip_ver, port, src, dst); | 1063 | ip_ver, port, src, dst); |
1066 | 1064 | ||
1067 | ret = rdma_translate_ip(&id->route.addr.src_addr, | 1065 | ret = rdma_translate_ip((struct sockaddr *) &id->route.addr.src_addr, |
1068 | &id->route.addr.dev_addr); | 1066 | &id->route.addr.dev_addr); |
1069 | if (ret) | 1067 | if (ret) |
1070 | goto err; | 1068 | goto err; |
@@ -1377,7 +1375,7 @@ static int cma_ib_listen(struct rdma_id_private *id_priv) | |||
1377 | if (IS_ERR(id_priv->cm_id.ib)) | 1375 | if (IS_ERR(id_priv->cm_id.ib)) |
1378 | return PTR_ERR(id_priv->cm_id.ib); | 1376 | return PTR_ERR(id_priv->cm_id.ib); |
1379 | 1377 | ||
1380 | addr = &id_priv->id.route.addr.src_addr; | 1378 | addr = (struct sockaddr *) &id_priv->id.route.addr.src_addr; |
1381 | svc_id = cma_get_service_id(id_priv->id.ps, addr); | 1379 | svc_id = cma_get_service_id(id_priv->id.ps, addr); |
1382 | if (cma_any_addr(addr)) | 1380 | if (cma_any_addr(addr)) |
1383 | ret = ib_cm_listen(id_priv->cm_id.ib, svc_id, 0, NULL); | 1381 | ret = ib_cm_listen(id_priv->cm_id.ib, svc_id, 0, NULL); |
@@ -1443,7 +1441,7 @@ static void cma_listen_on_dev(struct rdma_id_private *id_priv, | |||
1443 | 1441 | ||
1444 | dev_id_priv->state = CMA_ADDR_BOUND; | 1442 | dev_id_priv->state = CMA_ADDR_BOUND; |
1445 | memcpy(&id->route.addr.src_addr, &id_priv->id.route.addr.src_addr, | 1443 | memcpy(&id->route.addr.src_addr, &id_priv->id.route.addr.src_addr, |
1446 | ip_addr_size(&id_priv->id.route.addr.src_addr)); | 1444 | ip_addr_size((struct sockaddr *) &id_priv->id.route.addr.src_addr)); |
1447 | 1445 | ||
1448 | cma_attach_to_dev(dev_id_priv, cma_dev); | 1446 | cma_attach_to_dev(dev_id_priv, cma_dev); |
1449 | list_add_tail(&dev_id_priv->listen_list, &id_priv->listen_list); | 1447 | list_add_tail(&dev_id_priv->listen_list, &id_priv->listen_list); |
@@ -1563,13 +1561,14 @@ static int cma_query_ib_route(struct rdma_id_private *id_priv, int timeout_ms, | |||
1563 | path_rec.pkey = cpu_to_be16(ib_addr_get_pkey(&addr->dev_addr)); | 1561 | path_rec.pkey = cpu_to_be16(ib_addr_get_pkey(&addr->dev_addr)); |
1564 | path_rec.numb_path = 1; | 1562 | path_rec.numb_path = 1; |
1565 | path_rec.reversible = 1; | 1563 | path_rec.reversible = 1; |
1566 | path_rec.service_id = cma_get_service_id(id_priv->id.ps, &addr->dst_addr); | 1564 | path_rec.service_id = cma_get_service_id(id_priv->id.ps, |
1565 | (struct sockaddr *) &addr->dst_addr); | ||
1567 | 1566 | ||
1568 | comp_mask = IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID | | 1567 | comp_mask = IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID | |
1569 | IB_SA_PATH_REC_PKEY | IB_SA_PATH_REC_NUMB_PATH | | 1568 | IB_SA_PATH_REC_PKEY | IB_SA_PATH_REC_NUMB_PATH | |
1570 | IB_SA_PATH_REC_REVERSIBLE | IB_SA_PATH_REC_SERVICE_ID; | 1569 | IB_SA_PATH_REC_REVERSIBLE | IB_SA_PATH_REC_SERVICE_ID; |
1571 | 1570 | ||
1572 | if (addr->src_addr.sa_family == AF_INET) { | 1571 | if (addr->src_addr.ss_family == AF_INET) { |
1573 | path_rec.qos_class = cpu_to_be16((u16) id_priv->tos); | 1572 | path_rec.qos_class = cpu_to_be16((u16) id_priv->tos); |
1574 | comp_mask |= IB_SA_PATH_REC_QOS_CLASS; | 1573 | comp_mask |= IB_SA_PATH_REC_QOS_CLASS; |
1575 | } else { | 1574 | } else { |
@@ -1848,7 +1847,7 @@ static int cma_resolve_loopback(struct rdma_id_private *id_priv) | |||
1848 | ib_addr_get_sgid(&id_priv->id.route.addr.dev_addr, &gid); | 1847 | ib_addr_get_sgid(&id_priv->id.route.addr.dev_addr, &gid); |
1849 | ib_addr_set_dgid(&id_priv->id.route.addr.dev_addr, &gid); | 1848 | ib_addr_set_dgid(&id_priv->id.route.addr.dev_addr, &gid); |
1850 | 1849 | ||
1851 | if (cma_zero_addr(&id_priv->id.route.addr.src_addr)) { | 1850 | if (cma_zero_addr((struct sockaddr *) &id_priv->id.route.addr.src_addr)) { |
1852 | src_in = (struct sockaddr_in *)&id_priv->id.route.addr.src_addr; | 1851 | src_in = (struct sockaddr_in *)&id_priv->id.route.addr.src_addr; |
1853 | dst_in = (struct sockaddr_in *)&id_priv->id.route.addr.dst_addr; | 1852 | dst_in = (struct sockaddr_in *)&id_priv->id.route.addr.dst_addr; |
1854 | src_in->sin_family = dst_in->sin_family; | 1853 | src_in->sin_family = dst_in->sin_family; |
@@ -1897,7 +1896,7 @@ int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, | |||
1897 | if (cma_any_addr(dst_addr)) | 1896 | if (cma_any_addr(dst_addr)) |
1898 | ret = cma_resolve_loopback(id_priv); | 1897 | ret = cma_resolve_loopback(id_priv); |
1899 | else | 1898 | else |
1900 | ret = rdma_resolve_ip(&addr_client, &id->route.addr.src_addr, | 1899 | ret = rdma_resolve_ip(&addr_client, (struct sockaddr *) &id->route.addr.src_addr, |
1901 | dst_addr, &id->route.addr.dev_addr, | 1900 | dst_addr, &id->route.addr.dev_addr, |
1902 | timeout_ms, addr_handler, id_priv); | 1901 | timeout_ms, addr_handler, id_priv); |
1903 | if (ret) | 1902 | if (ret) |
@@ -2021,11 +2020,11 @@ static int cma_use_port(struct idr *ps, struct rdma_id_private *id_priv) | |||
2021 | * We don't support binding to any address if anyone is bound to | 2020 | * We don't support binding to any address if anyone is bound to |
2022 | * a specific address on the same port. | 2021 | * a specific address on the same port. |
2023 | */ | 2022 | */ |
2024 | if (cma_any_addr(&id_priv->id.route.addr.src_addr)) | 2023 | if (cma_any_addr((struct sockaddr *) &id_priv->id.route.addr.src_addr)) |
2025 | return -EADDRNOTAVAIL; | 2024 | return -EADDRNOTAVAIL; |
2026 | 2025 | ||
2027 | hlist_for_each_entry(cur_id, node, &bind_list->owners, node) { | 2026 | hlist_for_each_entry(cur_id, node, &bind_list->owners, node) { |
2028 | if (cma_any_addr(&cur_id->id.route.addr.src_addr)) | 2027 | if (cma_any_addr((struct sockaddr *) &cur_id->id.route.addr.src_addr)) |
2029 | return -EADDRNOTAVAIL; | 2028 | return -EADDRNOTAVAIL; |
2030 | 2029 | ||
2031 | cur_sin = (struct sockaddr_in *) &cur_id->id.route.addr.src_addr; | 2030 | cur_sin = (struct sockaddr_in *) &cur_id->id.route.addr.src_addr; |
@@ -2060,7 +2059,7 @@ static int cma_get_port(struct rdma_id_private *id_priv) | |||
2060 | } | 2059 | } |
2061 | 2060 | ||
2062 | mutex_lock(&lock); | 2061 | mutex_lock(&lock); |
2063 | if (cma_any_port(&id_priv->id.route.addr.src_addr)) | 2062 | if (cma_any_port((struct sockaddr *) &id_priv->id.route.addr.src_addr)) |
2064 | ret = cma_alloc_any_port(ps, id_priv); | 2063 | ret = cma_alloc_any_port(ps, id_priv); |
2065 | else | 2064 | else |
2066 | ret = cma_use_port(ps, id_priv); | 2065 | ret = cma_use_port(ps, id_priv); |
@@ -2232,7 +2231,7 @@ static int cma_resolve_ib_udp(struct rdma_id_private *id_priv, | |||
2232 | 2231 | ||
2233 | req.path = route->path_rec; | 2232 | req.path = route->path_rec; |
2234 | req.service_id = cma_get_service_id(id_priv->id.ps, | 2233 | req.service_id = cma_get_service_id(id_priv->id.ps, |
2235 | &route->addr.dst_addr); | 2234 | (struct sockaddr *) &route->addr.dst_addr); |
2236 | req.timeout_ms = 1 << (CMA_CM_RESPONSE_TIMEOUT - 8); | 2235 | req.timeout_ms = 1 << (CMA_CM_RESPONSE_TIMEOUT - 8); |
2237 | req.max_cm_retries = CMA_MAX_CM_RETRIES; | 2236 | req.max_cm_retries = CMA_MAX_CM_RETRIES; |
2238 | 2237 | ||
@@ -2283,7 +2282,7 @@ static int cma_connect_ib(struct rdma_id_private *id_priv, | |||
2283 | req.alternate_path = &route->path_rec[1]; | 2282 | req.alternate_path = &route->path_rec[1]; |
2284 | 2283 | ||
2285 | req.service_id = cma_get_service_id(id_priv->id.ps, | 2284 | req.service_id = cma_get_service_id(id_priv->id.ps, |
2286 | &route->addr.dst_addr); | 2285 | (struct sockaddr *) &route->addr.dst_addr); |
2287 | req.qp_num = id_priv->qp_num; | 2286 | req.qp_num = id_priv->qp_num; |
2288 | req.qp_type = IB_QPT_RC; | 2287 | req.qp_type = IB_QPT_RC; |
2289 | req.starting_psn = id_priv->seq_num; | 2288 | req.starting_psn = id_priv->seq_num; |
@@ -2667,7 +2666,7 @@ static int cma_join_ib_multicast(struct rdma_id_private *id_priv, | |||
2667 | if (ret) | 2666 | if (ret) |
2668 | return ret; | 2667 | return ret; |
2669 | 2668 | ||
2670 | cma_set_mgid(id_priv, &mc->addr, &rec.mgid); | 2669 | cma_set_mgid(id_priv, (struct sockaddr *) &mc->addr, &rec.mgid); |
2671 | if (id_priv->id.ps == RDMA_PS_UDP) | 2670 | if (id_priv->id.ps == RDMA_PS_UDP) |
2672 | rec.qkey = cpu_to_be32(RDMA_UDP_QKEY); | 2671 | rec.qkey = cpu_to_be32(RDMA_UDP_QKEY); |
2673 | ib_addr_get_sgid(dev_addr, &rec.port_gid); | 2672 | ib_addr_get_sgid(dev_addr, &rec.port_gid); |
diff --git a/drivers/infiniband/core/mad_rmpp.c b/drivers/infiniband/core/mad_rmpp.c index d0ef7d61c037..3af2b84cd838 100644 --- a/drivers/infiniband/core/mad_rmpp.c +++ b/drivers/infiniband/core/mad_rmpp.c | |||
@@ -133,7 +133,7 @@ static void ack_recv(struct mad_rmpp_recv *rmpp_recv, | |||
133 | msg = ib_create_send_mad(&rmpp_recv->agent->agent, recv_wc->wc->src_qp, | 133 | msg = ib_create_send_mad(&rmpp_recv->agent->agent, recv_wc->wc->src_qp, |
134 | recv_wc->wc->pkey_index, 1, hdr_len, | 134 | recv_wc->wc->pkey_index, 1, hdr_len, |
135 | 0, GFP_KERNEL); | 135 | 0, GFP_KERNEL); |
136 | if (!msg) | 136 | if (IS_ERR(msg)) |
137 | return; | 137 | return; |
138 | 138 | ||
139 | format_ack(msg, (struct ib_rmpp_mad *) recv_wc->recv_buf.mad, rmpp_recv); | 139 | format_ack(msg, (struct ib_rmpp_mad *) recv_wc->recv_buf.mad, rmpp_recv); |
diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index b41dd26bbfa1..3ddacf39b7ba 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c | |||
@@ -81,9 +81,7 @@ struct ucma_multicast { | |||
81 | 81 | ||
82 | u64 uid; | 82 | u64 uid; |
83 | struct list_head list; | 83 | struct list_head list; |
84 | struct sockaddr addr; | 84 | struct sockaddr_storage addr; |
85 | u8 pad[sizeof(struct sockaddr_in6) - | ||
86 | sizeof(struct sockaddr)]; | ||
87 | }; | 85 | }; |
88 | 86 | ||
89 | struct ucma_event { | 87 | struct ucma_event { |
@@ -603,11 +601,11 @@ static ssize_t ucma_query_route(struct ucma_file *file, | |||
603 | return PTR_ERR(ctx); | 601 | return PTR_ERR(ctx); |
604 | 602 | ||
605 | memset(&resp, 0, sizeof resp); | 603 | memset(&resp, 0, sizeof resp); |
606 | addr = &ctx->cm_id->route.addr.src_addr; | 604 | addr = (struct sockaddr *) &ctx->cm_id->route.addr.src_addr; |
607 | memcpy(&resp.src_addr, addr, addr->sa_family == AF_INET ? | 605 | memcpy(&resp.src_addr, addr, addr->sa_family == AF_INET ? |
608 | sizeof(struct sockaddr_in) : | 606 | sizeof(struct sockaddr_in) : |
609 | sizeof(struct sockaddr_in6)); | 607 | sizeof(struct sockaddr_in6)); |
610 | addr = &ctx->cm_id->route.addr.dst_addr; | 608 | addr = (struct sockaddr *) &ctx->cm_id->route.addr.dst_addr; |
611 | memcpy(&resp.dst_addr, addr, addr->sa_family == AF_INET ? | 609 | memcpy(&resp.dst_addr, addr, addr->sa_family == AF_INET ? |
612 | sizeof(struct sockaddr_in) : | 610 | sizeof(struct sockaddr_in) : |
613 | sizeof(struct sockaddr_in6)); | 611 | sizeof(struct sockaddr_in6)); |
@@ -913,7 +911,7 @@ static ssize_t ucma_join_multicast(struct ucma_file *file, | |||
913 | 911 | ||
914 | mc->uid = cmd.uid; | 912 | mc->uid = cmd.uid; |
915 | memcpy(&mc->addr, &cmd.addr, sizeof cmd.addr); | 913 | memcpy(&mc->addr, &cmd.addr, sizeof cmd.addr); |
916 | ret = rdma_join_multicast(ctx->cm_id, &mc->addr, mc); | 914 | ret = rdma_join_multicast(ctx->cm_id, (struct sockaddr *) &mc->addr, mc); |
917 | if (ret) | 915 | if (ret) |
918 | goto err2; | 916 | goto err2; |
919 | 917 | ||
@@ -929,7 +927,7 @@ static ssize_t ucma_join_multicast(struct ucma_file *file, | |||
929 | return 0; | 927 | return 0; |
930 | 928 | ||
931 | err3: | 929 | err3: |
932 | rdma_leave_multicast(ctx->cm_id, &mc->addr); | 930 | rdma_leave_multicast(ctx->cm_id, (struct sockaddr *) &mc->addr); |
933 | ucma_cleanup_mc_events(mc); | 931 | ucma_cleanup_mc_events(mc); |
934 | err2: | 932 | err2: |
935 | mutex_lock(&mut); | 933 | mutex_lock(&mut); |
@@ -975,7 +973,7 @@ static ssize_t ucma_leave_multicast(struct ucma_file *file, | |||
975 | goto out; | 973 | goto out; |
976 | } | 974 | } |
977 | 975 | ||
978 | rdma_leave_multicast(mc->ctx->cm_id, &mc->addr); | 976 | rdma_leave_multicast(mc->ctx->cm_id, (struct sockaddr *) &mc->addr); |
979 | mutex_lock(&mc->ctx->file->mut); | 977 | mutex_lock(&mc->ctx->file->mut); |
980 | ucma_cleanup_mc_events(mc); | 978 | ucma_cleanup_mc_events(mc); |
981 | list_del(&mc->list); | 979 | list_del(&mc->list); |
diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.c b/drivers/infiniband/hw/cxgb3/cxio_hal.c index f6d5747153a5..4dcf08b3fd83 100644 --- a/drivers/infiniband/hw/cxgb3/cxio_hal.c +++ b/drivers/infiniband/hw/cxgb3/cxio_hal.c | |||
@@ -725,9 +725,9 @@ static int __cxio_tpt_op(struct cxio_rdev *rdev_p, u32 reset_tpt_entry, | |||
725 | V_TPT_STAG_TYPE(type) | V_TPT_PDID(pdid)); | 725 | V_TPT_STAG_TYPE(type) | V_TPT_PDID(pdid)); |
726 | BUG_ON(page_size >= 28); | 726 | BUG_ON(page_size >= 28); |
727 | tpt.flags_pagesize_qpid = cpu_to_be32(V_TPT_PERM(perm) | | 727 | tpt.flags_pagesize_qpid = cpu_to_be32(V_TPT_PERM(perm) | |
728 | F_TPT_MW_BIND_ENABLE | | 728 | ((perm & TPT_MW_BIND) ? F_TPT_MW_BIND_ENABLE : 0) | |
729 | V_TPT_ADDR_TYPE((zbva ? TPT_ZBTO : TPT_VATO)) | | 729 | V_TPT_ADDR_TYPE((zbva ? TPT_ZBTO : TPT_VATO)) | |
730 | V_TPT_PAGE_SIZE(page_size)); | 730 | V_TPT_PAGE_SIZE(page_size)); |
731 | tpt.rsvd_pbl_addr = reset_tpt_entry ? 0 : | 731 | tpt.rsvd_pbl_addr = reset_tpt_entry ? 0 : |
732 | cpu_to_be32(V_TPT_PBL_ADDR(PBL_OFF(rdev_p, pbl_addr)>>3)); | 732 | cpu_to_be32(V_TPT_PBL_ADDR(PBL_OFF(rdev_p, pbl_addr)>>3)); |
733 | tpt.len = cpu_to_be32(len); | 733 | tpt.len = cpu_to_be32(len); |
diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c index b89640aa6e10..eb778bfd6f66 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_provider.c +++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c | |||
@@ -1187,28 +1187,6 @@ static ssize_t show_rev(struct device *dev, struct device_attribute *attr, | |||
1187 | return sprintf(buf, "%d\n", iwch_dev->rdev.t3cdev_p->type); | 1187 | return sprintf(buf, "%d\n", iwch_dev->rdev.t3cdev_p->type); |
1188 | } | 1188 | } |
1189 | 1189 | ||
1190 | static int fw_supports_fastreg(struct iwch_dev *iwch_dev) | ||
1191 | { | ||
1192 | struct ethtool_drvinfo info; | ||
1193 | struct net_device *lldev = iwch_dev->rdev.t3cdev_p->lldev; | ||
1194 | char *cp, *next; | ||
1195 | unsigned fw_maj, fw_min; | ||
1196 | |||
1197 | rtnl_lock(); | ||
1198 | lldev->ethtool_ops->get_drvinfo(lldev, &info); | ||
1199 | rtnl_unlock(); | ||
1200 | |||
1201 | next = info.fw_version+1; | ||
1202 | cp = strsep(&next, "."); | ||
1203 | sscanf(cp, "%i", &fw_maj); | ||
1204 | cp = strsep(&next, "."); | ||
1205 | sscanf(cp, "%i", &fw_min); | ||
1206 | |||
1207 | PDBG("%s maj %u min %u\n", __func__, fw_maj, fw_min); | ||
1208 | |||
1209 | return fw_maj > 6 || (fw_maj == 6 && fw_min > 0); | ||
1210 | } | ||
1211 | |||
1212 | static ssize_t show_fw_ver(struct device *dev, struct device_attribute *attr, char *buf) | 1190 | static ssize_t show_fw_ver(struct device *dev, struct device_attribute *attr, char *buf) |
1213 | { | 1191 | { |
1214 | struct iwch_dev *iwch_dev = container_of(dev, struct iwch_dev, | 1192 | struct iwch_dev *iwch_dev = container_of(dev, struct iwch_dev, |
@@ -1325,12 +1303,12 @@ int iwch_register_device(struct iwch_dev *dev) | |||
1325 | memset(&dev->ibdev.node_guid, 0, sizeof(dev->ibdev.node_guid)); | 1303 | memset(&dev->ibdev.node_guid, 0, sizeof(dev->ibdev.node_guid)); |
1326 | memcpy(&dev->ibdev.node_guid, dev->rdev.t3cdev_p->lldev->dev_addr, 6); | 1304 | memcpy(&dev->ibdev.node_guid, dev->rdev.t3cdev_p->lldev->dev_addr, 6); |
1327 | dev->ibdev.owner = THIS_MODULE; | 1305 | dev->ibdev.owner = THIS_MODULE; |
1328 | dev->device_cap_flags = IB_DEVICE_LOCAL_DMA_LKEY | IB_DEVICE_MEM_WINDOW; | 1306 | dev->device_cap_flags = IB_DEVICE_LOCAL_DMA_LKEY | |
1307 | IB_DEVICE_MEM_WINDOW | | ||
1308 | IB_DEVICE_MEM_MGT_EXTENSIONS; | ||
1329 | 1309 | ||
1330 | /* cxgb3 supports STag 0. */ | 1310 | /* cxgb3 supports STag 0. */ |
1331 | dev->ibdev.local_dma_lkey = 0; | 1311 | dev->ibdev.local_dma_lkey = 0; |
1332 | if (fw_supports_fastreg(dev)) | ||
1333 | dev->device_cap_flags |= IB_DEVICE_MEM_MGT_EXTENSIONS; | ||
1334 | 1312 | ||
1335 | dev->ibdev.uverbs_cmd_mask = | 1313 | dev->ibdev.uverbs_cmd_mask = |
1336 | (1ull << IB_USER_VERBS_CMD_GET_CONTEXT) | | 1314 | (1ull << IB_USER_VERBS_CMD_GET_CONTEXT) | |
diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.h b/drivers/infiniband/hw/cxgb3/iwch_provider.h index f5ceca05c435..a237d49bdcc9 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_provider.h +++ b/drivers/infiniband/hw/cxgb3/iwch_provider.h | |||
@@ -293,9 +293,16 @@ static inline u32 iwch_ib_to_tpt_access(int acc) | |||
293 | return (acc & IB_ACCESS_REMOTE_WRITE ? TPT_REMOTE_WRITE : 0) | | 293 | return (acc & IB_ACCESS_REMOTE_WRITE ? TPT_REMOTE_WRITE : 0) | |
294 | (acc & IB_ACCESS_REMOTE_READ ? TPT_REMOTE_READ : 0) | | 294 | (acc & IB_ACCESS_REMOTE_READ ? TPT_REMOTE_READ : 0) | |
295 | (acc & IB_ACCESS_LOCAL_WRITE ? TPT_LOCAL_WRITE : 0) | | 295 | (acc & IB_ACCESS_LOCAL_WRITE ? TPT_LOCAL_WRITE : 0) | |
296 | (acc & IB_ACCESS_MW_BIND ? TPT_MW_BIND : 0) | | ||
296 | TPT_LOCAL_READ; | 297 | TPT_LOCAL_READ; |
297 | } | 298 | } |
298 | 299 | ||
300 | static inline u32 iwch_ib_to_tpt_bind_access(int acc) | ||
301 | { | ||
302 | return (acc & IB_ACCESS_REMOTE_WRITE ? TPT_REMOTE_WRITE : 0) | | ||
303 | (acc & IB_ACCESS_REMOTE_READ ? TPT_REMOTE_READ : 0); | ||
304 | } | ||
305 | |||
299 | enum iwch_mmid_state { | 306 | enum iwch_mmid_state { |
300 | IWCH_STAG_STATE_VALID, | 307 | IWCH_STAG_STATE_VALID, |
301 | IWCH_STAG_STATE_INVALID | 308 | IWCH_STAG_STATE_INVALID |
diff --git a/drivers/infiniband/hw/cxgb3/iwch_qp.c b/drivers/infiniband/hw/cxgb3/iwch_qp.c index 9a3be3a9d5dc..3e4585c2318a 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_qp.c +++ b/drivers/infiniband/hw/cxgb3/iwch_qp.c | |||
@@ -565,7 +565,7 @@ int iwch_bind_mw(struct ib_qp *qp, | |||
565 | wqe->bind.type = TPT_VATO; | 565 | wqe->bind.type = TPT_VATO; |
566 | 566 | ||
567 | /* TBD: check perms */ | 567 | /* TBD: check perms */ |
568 | wqe->bind.perms = iwch_ib_to_tpt_access(mw_bind->mw_access_flags); | 568 | wqe->bind.perms = iwch_ib_to_tpt_bind_access(mw_bind->mw_access_flags); |
569 | wqe->bind.mr_stag = cpu_to_be32(mw_bind->mr->lkey); | 569 | wqe->bind.mr_stag = cpu_to_be32(mw_bind->mr->lkey); |
570 | wqe->bind.mw_stag = cpu_to_be32(mw->rkey); | 570 | wqe->bind.mw_stag = cpu_to_be32(mw->rkey); |
571 | wqe->bind.mw_len = cpu_to_be32(mw_bind->length); | 571 | wqe->bind.mw_len = cpu_to_be32(mw_bind->length); |
@@ -879,20 +879,13 @@ static int rdma_init(struct iwch_dev *rhp, struct iwch_qp *qhp, | |||
879 | (qhp->attr.mpa_attr.xmit_marker_enabled << 1) | | 879 | (qhp->attr.mpa_attr.xmit_marker_enabled << 1) | |
880 | (qhp->attr.mpa_attr.crc_enabled << 2); | 880 | (qhp->attr.mpa_attr.crc_enabled << 2); |
881 | 881 | ||
882 | /* | 882 | init_attr.qpcaps = uP_RI_QP_RDMA_READ_ENABLE | |
883 | * XXX - The IWCM doesn't quite handle getting these | 883 | uP_RI_QP_RDMA_WRITE_ENABLE | |
884 | * attrs set before going into RTS. For now, just turn | 884 | uP_RI_QP_BIND_ENABLE; |
885 | * them on always... | 885 | if (!qhp->ibqp.uobject) |
886 | */ | 886 | init_attr.qpcaps |= uP_RI_QP_STAG0_ENABLE | |
887 | #if 0 | 887 | uP_RI_QP_FAST_REGISTER_ENABLE; |
888 | init_attr.qpcaps = qhp->attr.enableRdmaRead | | 888 | |
889 | (qhp->attr.enableRdmaWrite << 1) | | ||
890 | (qhp->attr.enableBind << 2) | | ||
891 | (qhp->attr.enable_stag0_fastreg << 3) | | ||
892 | (qhp->attr.enable_stag0_fastreg << 4); | ||
893 | #else | ||
894 | init_attr.qpcaps = 0x1f; | ||
895 | #endif | ||
896 | init_attr.tcp_emss = qhp->ep->emss; | 889 | init_attr.tcp_emss = qhp->ep->emss; |
897 | init_attr.ord = qhp->attr.max_ord; | 890 | init_attr.ord = qhp->attr.max_ord; |
898 | init_attr.ird = qhp->attr.max_ird; | 891 | init_attr.ird = qhp->attr.max_ird; |
@@ -900,8 +893,6 @@ static int rdma_init(struct iwch_dev *rhp, struct iwch_qp *qhp, | |||
900 | init_attr.qp_dma_size = (1UL << qhp->wq.size_log2); | 893 | init_attr.qp_dma_size = (1UL << qhp->wq.size_log2); |
901 | init_attr.rqe_count = iwch_rqes_posted(qhp); | 894 | init_attr.rqe_count = iwch_rqes_posted(qhp); |
902 | init_attr.flags = qhp->attr.mpa_attr.initiator ? MPA_INITIATOR : 0; | 895 | init_attr.flags = qhp->attr.mpa_attr.initiator ? MPA_INITIATOR : 0; |
903 | if (!qhp->ibqp.uobject) | ||
904 | init_attr.flags |= PRIV_QP; | ||
905 | if (peer2peer) { | 896 | if (peer2peer) { |
906 | init_attr.rtr_type = RTR_READ; | 897 | init_attr.rtr_type = RTR_READ; |
907 | if (init_attr.ord == 0 && qhp->attr.mpa_attr.initiator) | 898 | if (init_attr.ord == 0 && qhp->attr.mpa_attr.initiator) |
diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c index daad09a45910..ad0aab60b051 100644 --- a/drivers/infiniband/hw/ipath/ipath_driver.c +++ b/drivers/infiniband/hw/ipath/ipath_driver.c | |||
@@ -1259,7 +1259,7 @@ reloop: | |||
1259 | */ | 1259 | */ |
1260 | ipath_cdbg(ERRPKT, "Error Pkt, but no eflags! egrbuf" | 1260 | ipath_cdbg(ERRPKT, "Error Pkt, but no eflags! egrbuf" |
1261 | " %x, len %x hdrq+%x rhf: %Lx\n", | 1261 | " %x, len %x hdrq+%x rhf: %Lx\n", |
1262 | etail, tlen, l, | 1262 | etail, tlen, l, (unsigned long long) |
1263 | le64_to_cpu(*(__le64 *) rhf_addr)); | 1263 | le64_to_cpu(*(__le64 *) rhf_addr)); |
1264 | if (ipath_debug & __IPATH_ERRPKTDBG) { | 1264 | if (ipath_debug & __IPATH_ERRPKTDBG) { |
1265 | u32 j, *d, dw = rsize-2; | 1265 | u32 j, *d, dw = rsize-2; |
@@ -1457,7 +1457,8 @@ static void ipath_reset_availshadow(struct ipath_devdata *dd) | |||
1457 | 0xaaaaaaaaaaaaaaaaULL); /* All BUSY bits in qword */ | 1457 | 0xaaaaaaaaaaaaaaaaULL); /* All BUSY bits in qword */ |
1458 | if (oldval != dd->ipath_pioavailshadow[i]) | 1458 | if (oldval != dd->ipath_pioavailshadow[i]) |
1459 | ipath_dbg("shadow[%d] was %Lx, now %lx\n", | 1459 | ipath_dbg("shadow[%d] was %Lx, now %lx\n", |
1460 | i, oldval, dd->ipath_pioavailshadow[i]); | 1460 | i, (unsigned long long) oldval, |
1461 | dd->ipath_pioavailshadow[i]); | ||
1461 | } | 1462 | } |
1462 | spin_unlock_irqrestore(&ipath_pioavail_lock, flags); | 1463 | spin_unlock_irqrestore(&ipath_pioavail_lock, flags); |
1463 | } | 1464 | } |
diff --git a/drivers/infiniband/hw/ipath/ipath_iba7220.c b/drivers/infiniband/hw/ipath/ipath_iba7220.c index fadbfbf55a6a..d90f5e9a54fa 100644 --- a/drivers/infiniband/hw/ipath/ipath_iba7220.c +++ b/drivers/infiniband/hw/ipath/ipath_iba7220.c | |||
@@ -1032,7 +1032,7 @@ static int ipath_7220_bringup_serdes(struct ipath_devdata *dd) | |||
1032 | ipath_cdbg(VERBOSE, "done: xgxs=%llx from %llx\n", | 1032 | ipath_cdbg(VERBOSE, "done: xgxs=%llx from %llx\n", |
1033 | (unsigned long long) | 1033 | (unsigned long long) |
1034 | ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig), | 1034 | ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig), |
1035 | prev_val); | 1035 | (unsigned long long) prev_val); |
1036 | 1036 | ||
1037 | guid = be64_to_cpu(dd->ipath_guid); | 1037 | guid = be64_to_cpu(dd->ipath_guid); |
1038 | 1038 | ||
@@ -1042,7 +1042,8 @@ static int ipath_7220_bringup_serdes(struct ipath_devdata *dd) | |||
1042 | ipath_dbg("No GUID for heartbeat, faking %llx\n", | 1042 | ipath_dbg("No GUID for heartbeat, faking %llx\n", |
1043 | (unsigned long long)guid); | 1043 | (unsigned long long)guid); |
1044 | } else | 1044 | } else |
1045 | ipath_cdbg(VERBOSE, "Wrote %llX to HRTBT_GUID\n", guid); | 1045 | ipath_cdbg(VERBOSE, "Wrote %llX to HRTBT_GUID\n", |
1046 | (unsigned long long) guid); | ||
1046 | ipath_write_kreg(dd, dd->ipath_kregs->kr_hrtbt_guid, guid); | 1047 | ipath_write_kreg(dd, dd->ipath_kregs->kr_hrtbt_guid, guid); |
1047 | return ret; | 1048 | return ret; |
1048 | } | 1049 | } |
@@ -2505,7 +2506,7 @@ done: | |||
2505 | if (dd->ipath_flags & IPATH_IB_AUTONEG_INPROG) { | 2506 | if (dd->ipath_flags & IPATH_IB_AUTONEG_INPROG) { |
2506 | ipath_dbg("Did not get to DDR INIT (%x) after %Lu msecs\n", | 2507 | ipath_dbg("Did not get to DDR INIT (%x) after %Lu msecs\n", |
2507 | ipath_ib_state(dd, dd->ipath_lastibcstat), | 2508 | ipath_ib_state(dd, dd->ipath_lastibcstat), |
2508 | jiffies_to_msecs(jiffies)-startms); | 2509 | (unsigned long long) jiffies_to_msecs(jiffies)-startms); |
2509 | dd->ipath_flags &= ~IPATH_IB_AUTONEG_INPROG; | 2510 | dd->ipath_flags &= ~IPATH_IB_AUTONEG_INPROG; |
2510 | if (dd->ipath_autoneg_tries == IPATH_AUTONEG_TRIES) { | 2511 | if (dd->ipath_autoneg_tries == IPATH_AUTONEG_TRIES) { |
2511 | dd->ipath_flags |= IPATH_IB_AUTONEG_FAILED; | 2512 | dd->ipath_flags |= IPATH_IB_AUTONEG_FAILED; |
diff --git a/drivers/infiniband/hw/ipath/ipath_intr.c b/drivers/infiniband/hw/ipath/ipath_intr.c index 26900b3b7a4e..6c21b4b5ec71 100644 --- a/drivers/infiniband/hw/ipath/ipath_intr.c +++ b/drivers/infiniband/hw/ipath/ipath_intr.c | |||
@@ -356,9 +356,10 @@ static void handle_e_ibstatuschanged(struct ipath_devdata *dd, | |||
356 | dd->ipath_cregs->cr_iblinkerrrecovcnt); | 356 | dd->ipath_cregs->cr_iblinkerrrecovcnt); |
357 | if (linkrecov != dd->ipath_lastlinkrecov) { | 357 | if (linkrecov != dd->ipath_lastlinkrecov) { |
358 | ipath_dbg("IB linkrecov up %Lx (%s %s) recov %Lu\n", | 358 | ipath_dbg("IB linkrecov up %Lx (%s %s) recov %Lu\n", |
359 | ibcs, ib_linkstate(dd, ibcs), | 359 | (unsigned long long) ibcs, |
360 | ib_linkstate(dd, ibcs), | ||
360 | ipath_ibcstatus_str[ltstate], | 361 | ipath_ibcstatus_str[ltstate], |
361 | linkrecov); | 362 | (unsigned long long) linkrecov); |
362 | /* and no more until active again */ | 363 | /* and no more until active again */ |
363 | dd->ipath_lastlinkrecov = 0; | 364 | dd->ipath_lastlinkrecov = 0; |
364 | ipath_set_linkstate(dd, IPATH_IB_LINKDOWN); | 365 | ipath_set_linkstate(dd, IPATH_IB_LINKDOWN); |
@@ -1118,9 +1119,11 @@ irqreturn_t ipath_intr(int irq, void *data) | |||
1118 | if (unlikely(istat & ~dd->ipath_i_bitsextant)) | 1119 | if (unlikely(istat & ~dd->ipath_i_bitsextant)) |
1119 | ipath_dev_err(dd, | 1120 | ipath_dev_err(dd, |
1120 | "interrupt with unknown interrupts %Lx set\n", | 1121 | "interrupt with unknown interrupts %Lx set\n", |
1122 | (unsigned long long) | ||
1121 | istat & ~dd->ipath_i_bitsextant); | 1123 | istat & ~dd->ipath_i_bitsextant); |
1122 | else if (istat & ~INFINIPATH_I_ERROR) /* errors do own printing */ | 1124 | else if (istat & ~INFINIPATH_I_ERROR) /* errors do own printing */ |
1123 | ipath_cdbg(VERBOSE, "intr stat=0x%Lx\n", istat); | 1125 | ipath_cdbg(VERBOSE, "intr stat=0x%Lx\n", |
1126 | (unsigned long long) istat); | ||
1124 | 1127 | ||
1125 | if (istat & INFINIPATH_I_ERROR) { | 1128 | if (istat & INFINIPATH_I_ERROR) { |
1126 | ipath_stats.sps_errints++; | 1129 | ipath_stats.sps_errints++; |
@@ -1128,7 +1131,8 @@ irqreturn_t ipath_intr(int irq, void *data) | |||
1128 | dd->ipath_kregs->kr_errorstatus); | 1131 | dd->ipath_kregs->kr_errorstatus); |
1129 | if (!estat) | 1132 | if (!estat) |
1130 | dev_info(&dd->pcidev->dev, "error interrupt (%Lx), " | 1133 | dev_info(&dd->pcidev->dev, "error interrupt (%Lx), " |
1131 | "but no error bits set!\n", istat); | 1134 | "but no error bits set!\n", |
1135 | (unsigned long long) istat); | ||
1132 | else if (estat == -1LL) | 1136 | else if (estat == -1LL) |
1133 | /* | 1137 | /* |
1134 | * should we try clearing all, or hope next read | 1138 | * should we try clearing all, or hope next read |
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.c b/drivers/infiniband/hw/ipath/ipath_verbs.c index 55c718828826..b766e40e9ebf 100644 --- a/drivers/infiniband/hw/ipath/ipath_verbs.c +++ b/drivers/infiniband/hw/ipath/ipath_verbs.c | |||
@@ -1021,7 +1021,7 @@ static void sdma_complete(void *cookie, int status) | |||
1021 | struct ipath_verbs_txreq *tx = cookie; | 1021 | struct ipath_verbs_txreq *tx = cookie; |
1022 | struct ipath_qp *qp = tx->qp; | 1022 | struct ipath_qp *qp = tx->qp; |
1023 | struct ipath_ibdev *dev = to_idev(qp->ibqp.device); | 1023 | struct ipath_ibdev *dev = to_idev(qp->ibqp.device); |
1024 | unsigned int flags; | 1024 | unsigned long flags; |
1025 | enum ib_wc_status ibs = status == IPATH_SDMA_TXREQ_S_OK ? | 1025 | enum ib_wc_status ibs = status == IPATH_SDMA_TXREQ_S_OK ? |
1026 | IB_WC_SUCCESS : IB_WC_WR_FLUSH_ERR; | 1026 | IB_WC_SUCCESS : IB_WC_WR_FLUSH_ERR; |
1027 | 1027 | ||
@@ -1051,7 +1051,7 @@ static void sdma_complete(void *cookie, int status) | |||
1051 | 1051 | ||
1052 | static void decrement_dma_busy(struct ipath_qp *qp) | 1052 | static void decrement_dma_busy(struct ipath_qp *qp) |
1053 | { | 1053 | { |
1054 | unsigned int flags; | 1054 | unsigned long flags; |
1055 | 1055 | ||
1056 | if (atomic_dec_and_test(&qp->s_dma_busy)) { | 1056 | if (atomic_dec_and_test(&qp->s_dma_busy)) { |
1057 | spin_lock_irqsave(&qp->s_lock, flags); | 1057 | spin_lock_irqsave(&qp->s_lock, flags); |
@@ -1221,7 +1221,7 @@ static int ipath_verbs_send_pio(struct ipath_qp *qp, | |||
1221 | unsigned flush_wc; | 1221 | unsigned flush_wc; |
1222 | u32 control; | 1222 | u32 control; |
1223 | int ret; | 1223 | int ret; |
1224 | unsigned int flags; | 1224 | unsigned long flags; |
1225 | 1225 | ||
1226 | piobuf = ipath_getpiobuf(dd, plen, NULL); | 1226 | piobuf = ipath_getpiobuf(dd, plen, NULL); |
1227 | if (unlikely(piobuf == NULL)) { | 1227 | if (unlikely(piobuf == NULL)) { |
diff --git a/drivers/infiniband/hw/mlx4/cq.c b/drivers/infiniband/hw/mlx4/cq.c index a1464574bfdd..d0866a3636e2 100644 --- a/drivers/infiniband/hw/mlx4/cq.c +++ b/drivers/infiniband/hw/mlx4/cq.c | |||
@@ -515,17 +515,17 @@ static void mlx4_ib_handle_error_cqe(struct mlx4_err_cqe *cqe, | |||
515 | wc->vendor_err = cqe->vendor_err_syndrome; | 515 | wc->vendor_err = cqe->vendor_err_syndrome; |
516 | } | 516 | } |
517 | 517 | ||
518 | static int mlx4_ib_ipoib_csum_ok(__be32 status, __be16 checksum) | 518 | static int mlx4_ib_ipoib_csum_ok(__be16 status, __be16 checksum) |
519 | { | 519 | { |
520 | return ((status & cpu_to_be32(MLX4_CQE_IPOIB_STATUS_IPV4 | | 520 | return ((status & cpu_to_be16(MLX4_CQE_STATUS_IPV4 | |
521 | MLX4_CQE_IPOIB_STATUS_IPV4F | | 521 | MLX4_CQE_STATUS_IPV4F | |
522 | MLX4_CQE_IPOIB_STATUS_IPV4OPT | | 522 | MLX4_CQE_STATUS_IPV4OPT | |
523 | MLX4_CQE_IPOIB_STATUS_IPV6 | | 523 | MLX4_CQE_STATUS_IPV6 | |
524 | MLX4_CQE_IPOIB_STATUS_IPOK)) == | 524 | MLX4_CQE_STATUS_IPOK)) == |
525 | cpu_to_be32(MLX4_CQE_IPOIB_STATUS_IPV4 | | 525 | cpu_to_be16(MLX4_CQE_STATUS_IPV4 | |
526 | MLX4_CQE_IPOIB_STATUS_IPOK)) && | 526 | MLX4_CQE_STATUS_IPOK)) && |
527 | (status & cpu_to_be32(MLX4_CQE_IPOIB_STATUS_UDP | | 527 | (status & cpu_to_be16(MLX4_CQE_STATUS_UDP | |
528 | MLX4_CQE_IPOIB_STATUS_TCP)) && | 528 | MLX4_CQE_STATUS_TCP)) && |
529 | checksum == cpu_to_be16(0xffff); | 529 | checksum == cpu_to_be16(0xffff); |
530 | } | 530 | } |
531 | 531 | ||
@@ -582,17 +582,17 @@ repoll: | |||
582 | } | 582 | } |
583 | 583 | ||
584 | if (!*cur_qp || | 584 | if (!*cur_qp || |
585 | (be32_to_cpu(cqe->my_qpn) & 0xffffff) != (*cur_qp)->mqp.qpn) { | 585 | (be32_to_cpu(cqe->vlan_my_qpn) & MLX4_CQE_QPN_MASK) != (*cur_qp)->mqp.qpn) { |
586 | /* | 586 | /* |
587 | * We do not have to take the QP table lock here, | 587 | * We do not have to take the QP table lock here, |
588 | * because CQs will be locked while QPs are removed | 588 | * because CQs will be locked while QPs are removed |
589 | * from the table. | 589 | * from the table. |
590 | */ | 590 | */ |
591 | mqp = __mlx4_qp_lookup(to_mdev(cq->ibcq.device)->dev, | 591 | mqp = __mlx4_qp_lookup(to_mdev(cq->ibcq.device)->dev, |
592 | be32_to_cpu(cqe->my_qpn)); | 592 | be32_to_cpu(cqe->vlan_my_qpn)); |
593 | if (unlikely(!mqp)) { | 593 | if (unlikely(!mqp)) { |
594 | printk(KERN_WARNING "CQ %06x with entry for unknown QPN %06x\n", | 594 | printk(KERN_WARNING "CQ %06x with entry for unknown QPN %06x\n", |
595 | cq->mcq.cqn, be32_to_cpu(cqe->my_qpn) & 0xffffff); | 595 | cq->mcq.cqn, be32_to_cpu(cqe->vlan_my_qpn) & MLX4_CQE_QPN_MASK); |
596 | return -EINVAL; | 596 | return -EINVAL; |
597 | } | 597 | } |
598 | 598 | ||
@@ -692,14 +692,13 @@ repoll: | |||
692 | } | 692 | } |
693 | 693 | ||
694 | wc->slid = be16_to_cpu(cqe->rlid); | 694 | wc->slid = be16_to_cpu(cqe->rlid); |
695 | wc->sl = cqe->sl >> 4; | 695 | wc->sl = be16_to_cpu(cqe->sl_vid >> 12); |
696 | g_mlpath_rqpn = be32_to_cpu(cqe->g_mlpath_rqpn); | 696 | g_mlpath_rqpn = be32_to_cpu(cqe->g_mlpath_rqpn); |
697 | wc->src_qp = g_mlpath_rqpn & 0xffffff; | 697 | wc->src_qp = g_mlpath_rqpn & 0xffffff; |
698 | wc->dlid_path_bits = (g_mlpath_rqpn >> 24) & 0x7f; | 698 | wc->dlid_path_bits = (g_mlpath_rqpn >> 24) & 0x7f; |
699 | wc->wc_flags |= g_mlpath_rqpn & 0x80000000 ? IB_WC_GRH : 0; | 699 | wc->wc_flags |= g_mlpath_rqpn & 0x80000000 ? IB_WC_GRH : 0; |
700 | wc->pkey_index = be32_to_cpu(cqe->immed_rss_invalid) & 0x7f; | 700 | wc->pkey_index = be32_to_cpu(cqe->immed_rss_invalid) & 0x7f; |
701 | wc->csum_ok = mlx4_ib_ipoib_csum_ok(cqe->ipoib_status, | 701 | wc->csum_ok = mlx4_ib_ipoib_csum_ok(cqe->status, cqe->checksum); |
702 | cqe->checksum); | ||
703 | } | 702 | } |
704 | 703 | ||
705 | return 0; | 704 | return 0; |
@@ -767,7 +766,7 @@ void __mlx4_ib_cq_clean(struct mlx4_ib_cq *cq, u32 qpn, struct mlx4_ib_srq *srq) | |||
767 | */ | 766 | */ |
768 | while ((int) --prod_index - (int) cq->mcq.cons_index >= 0) { | 767 | while ((int) --prod_index - (int) cq->mcq.cons_index >= 0) { |
769 | cqe = get_cqe(cq, prod_index & cq->ibcq.cqe); | 768 | cqe = get_cqe(cq, prod_index & cq->ibcq.cqe); |
770 | if ((be32_to_cpu(cqe->my_qpn) & 0xffffff) == qpn) { | 769 | if ((be32_to_cpu(cqe->vlan_my_qpn) & MLX4_CQE_QPN_MASK) == qpn) { |
771 | if (srq && !(cqe->owner_sr_opcode & MLX4_CQE_IS_SEND_MASK)) | 770 | if (srq && !(cqe->owner_sr_opcode & MLX4_CQE_IS_SEND_MASK)) |
772 | mlx4_ib_free_srq_wqe(srq, be16_to_cpu(cqe->wqe_index)); | 771 | mlx4_ib_free_srq_wqe(srq, be16_to_cpu(cqe->wqe_index)); |
773 | ++nfreed; | 772 | ++nfreed; |
diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c index f7bc7dd8578a..f29dbb767e87 100644 --- a/drivers/infiniband/hw/mlx4/qp.c +++ b/drivers/infiniband/hw/mlx4/qp.c | |||
@@ -902,7 +902,7 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp, | |||
902 | context->mtu_msgmax = (IB_MTU_4096 << 5) | | 902 | context->mtu_msgmax = (IB_MTU_4096 << 5) | |
903 | ilog2(dev->dev->caps.max_gso_sz); | 903 | ilog2(dev->dev->caps.max_gso_sz); |
904 | else | 904 | else |
905 | context->mtu_msgmax = (IB_MTU_4096 << 5) | 11; | 905 | context->mtu_msgmax = (IB_MTU_4096 << 5) | 12; |
906 | } else if (attr_mask & IB_QP_PATH_MTU) { | 906 | } else if (attr_mask & IB_QP_PATH_MTU) { |
907 | if (attr->path_mtu < IB_MTU_256 || attr->path_mtu > IB_MTU_4096) { | 907 | if (attr->path_mtu < IB_MTU_256 || attr->path_mtu > IB_MTU_4096) { |
908 | printk(KERN_ERR "path MTU (%u) is invalid\n", | 908 | printk(KERN_ERR "path MTU (%u) is invalid\n", |
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index 0f2d3045061a..7ebc400a4b3d 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c | |||
@@ -337,7 +337,7 @@ static void ipoib_cm_init_rx_wr(struct net_device *dev, | |||
337 | sge[i].length = PAGE_SIZE; | 337 | sge[i].length = PAGE_SIZE; |
338 | 338 | ||
339 | wr->next = NULL; | 339 | wr->next = NULL; |
340 | wr->sg_list = priv->cm.rx_sge; | 340 | wr->sg_list = sge; |
341 | wr->num_sge = priv->cm.num_frags; | 341 | wr->num_sge = priv->cm.num_frags; |
342 | } | 342 | } |
343 | 343 | ||
diff --git a/drivers/input/serio/i8042-sparcio.h b/drivers/input/serio/i8042-sparcio.h index d9ca55891cd7..66bafe308b0c 100644 --- a/drivers/input/serio/i8042-sparcio.h +++ b/drivers/input/serio/i8042-sparcio.h | |||
@@ -41,6 +41,8 @@ static inline void i8042_write_command(int val) | |||
41 | writeb(val, kbd_iobase + 0x64UL); | 41 | writeb(val, kbd_iobase + 0x64UL); |
42 | } | 42 | } |
43 | 43 | ||
44 | #ifdef CONFIG_PCI | ||
45 | |||
44 | #define OBP_PS2KBD_NAME1 "kb_ps2" | 46 | #define OBP_PS2KBD_NAME1 "kb_ps2" |
45 | #define OBP_PS2KBD_NAME2 "keyboard" | 47 | #define OBP_PS2KBD_NAME2 "keyboard" |
46 | #define OBP_PS2MS_NAME1 "kdmouse" | 48 | #define OBP_PS2MS_NAME1 "kdmouse" |
@@ -101,9 +103,6 @@ static struct of_platform_driver sparc_i8042_driver = { | |||
101 | 103 | ||
102 | static int __init i8042_platform_init(void) | 104 | static int __init i8042_platform_init(void) |
103 | { | 105 | { |
104 | #ifndef CONFIG_PCI | ||
105 | return -ENODEV; | ||
106 | #else | ||
107 | struct device_node *root = of_find_node_by_path("/"); | 106 | struct device_node *root = of_find_node_by_path("/"); |
108 | 107 | ||
109 | if (!strcmp(root->name, "SUNW,JavaStation-1")) { | 108 | if (!strcmp(root->name, "SUNW,JavaStation-1")) { |
@@ -131,17 +130,25 @@ static int __init i8042_platform_init(void) | |||
131 | i8042_reset = 1; | 130 | i8042_reset = 1; |
132 | 131 | ||
133 | return 0; | 132 | return 0; |
134 | #endif /* CONFIG_PCI */ | ||
135 | } | 133 | } |
136 | 134 | ||
137 | static inline void i8042_platform_exit(void) | 135 | static inline void i8042_platform_exit(void) |
138 | { | 136 | { |
139 | #ifdef CONFIG_PCI | ||
140 | struct device_node *root = of_find_node_by_path("/"); | 137 | struct device_node *root = of_find_node_by_path("/"); |
141 | 138 | ||
142 | if (strcmp(root->name, "SUNW,JavaStation-1")) | 139 | if (strcmp(root->name, "SUNW,JavaStation-1")) |
143 | of_unregister_driver(&sparc_i8042_driver); | 140 | of_unregister_driver(&sparc_i8042_driver); |
144 | #endif | ||
145 | } | 141 | } |
146 | 142 | ||
143 | #else /* !CONFIG_PCI */ | ||
144 | static int __init i8042_platform_init(void) | ||
145 | { | ||
146 | return -ENODEV; | ||
147 | } | ||
148 | |||
149 | static inline void i8042_platform_exit(void) | ||
150 | { | ||
151 | } | ||
152 | #endif /* !CONFIG_PCI */ | ||
153 | |||
147 | #endif /* _I8042_SPARCIO_H */ | 154 | #endif /* _I8042_SPARCIO_H */ |
diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c index 578afce6884c..aaa0b6f0b521 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.c +++ b/drivers/media/dvb/dvb-usb/cxusb.c | |||
@@ -565,7 +565,8 @@ static int cxusb_lgh064f_tuner_attach(struct dvb_usb_adapter *adap) | |||
565 | 565 | ||
566 | static int dvico_bluebird_xc2028_callback(void *ptr, int command, int arg) | 566 | static int dvico_bluebird_xc2028_callback(void *ptr, int command, int arg) |
567 | { | 567 | { |
568 | struct dvb_usb_device *d = ptr; | 568 | struct dvb_usb_adapter *adap = ptr; |
569 | struct dvb_usb_device *d = adap->dev; | ||
569 | 570 | ||
570 | switch (command) { | 571 | switch (command) { |
571 | case XC2028_TUNER_RESET: | 572 | case XC2028_TUNER_RESET: |
@@ -593,9 +594,9 @@ static int cxusb_dvico_xc3028_tuner_attach(struct dvb_usb_adapter *adap) | |||
593 | .callback = dvico_bluebird_xc2028_callback, | 594 | .callback = dvico_bluebird_xc2028_callback, |
594 | }; | 595 | }; |
595 | static struct xc2028_ctrl ctl = { | 596 | static struct xc2028_ctrl ctl = { |
596 | .fname = "xc3028-dvico-au-01.fw", | 597 | .fname = "xc3028-v27.fw", |
597 | .max_len = 64, | 598 | .max_len = 64, |
598 | .scode_table = XC3028_FE_ZARLINK456, | 599 | .demod = XC3028_FE_ZARLINK456, |
599 | }; | 600 | }; |
600 | 601 | ||
601 | fe = dvb_attach(xc2028_attach, adap->fe, &cfg); | 602 | fe = dvb_attach(xc2028_attach, adap->fe, &cfg); |
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index 574dffe91b68..7dbb4a223c99 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig | |||
@@ -135,9 +135,8 @@ config DVB_CX22702 | |||
135 | 135 | ||
136 | config DVB_DRX397XD | 136 | config DVB_DRX397XD |
137 | tristate "Micronas DRX3975D/DRX3977D based" | 137 | tristate "Micronas DRX3975D/DRX3977D based" |
138 | depends on DVB_CORE && I2C && HOTPLUG | 138 | depends on DVB_CORE && I2C |
139 | default m if DVB_FE_CUSTOMISE | 139 | default m if DVB_FE_CUSTOMISE |
140 | select FW_LOADER | ||
141 | help | 140 | help |
142 | A DVB-T tuner module. Say Y when you want to support this frontend. | 141 | A DVB-T tuner module. Say Y when you want to support this frontend. |
143 | 142 | ||
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index d4a6e56a7135..ecbfa1b39b70 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig | |||
@@ -630,7 +630,7 @@ config VIDEO_ZORAN_ZR36060 | |||
630 | depends on VIDEO_ZORAN | 630 | depends on VIDEO_ZORAN |
631 | help | 631 | help |
632 | Say Y to support Zoran boards based on 36060 chips. | 632 | Say Y to support Zoran boards based on 36060 chips. |
633 | This includes Iomega Bus, Pinnacle DC10, Linux media Labs 33 | 633 | This includes Iomega Buz, Pinnacle DC10, Linux media Labs 33 |
634 | and 33 R10 and AverMedia 6 boards. | 634 | and 33 R10 and AverMedia 6 boards. |
635 | 635 | ||
636 | config VIDEO_ZORAN_BUZ | 636 | config VIDEO_ZORAN_BUZ |
diff --git a/drivers/media/video/arv.c b/drivers/media/video/arv.c index 56ebfd5ef6fa..9e436ad3d34b 100644 --- a/drivers/media/video/arv.c +++ b/drivers/media/video/arv.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/sched.h> | 29 | #include <linux/sched.h> |
30 | #include <linux/videodev.h> | 30 | #include <linux/videodev.h> |
31 | #include <media/v4l2-common.h> | 31 | #include <media/v4l2-common.h> |
32 | #include <media/v4l2-ioctl.h> | ||
32 | #include <linux/mutex.h> | 33 | #include <linux/mutex.h> |
33 | 34 | ||
34 | #include <asm/uaccess.h> | 35 | #include <asm/uaccess.h> |
@@ -755,7 +756,6 @@ static const struct file_operations ar_fops = { | |||
755 | 756 | ||
756 | static struct video_device ar_template = { | 757 | static struct video_device ar_template = { |
757 | .name = "Colour AR VGA", | 758 | .name = "Colour AR VGA", |
758 | .type = VID_TYPE_CAPTURE, | ||
759 | .fops = &ar_fops, | 759 | .fops = &ar_fops, |
760 | .release = ar_release, | 760 | .release = ar_release, |
761 | .minor = -1, | 761 | .minor = -1, |
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 476ae44a62d2..452da70e719f 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c | |||
@@ -1015,6 +1015,7 @@ struct em28xx_board em28xx_boards[] = { | |||
1015 | .valid = EM28XX_BOARD_NOT_VALIDATED, | 1015 | .valid = EM28XX_BOARD_NOT_VALIDATED, |
1016 | .vchannels = 3, | 1016 | .vchannels = 3, |
1017 | .tuner_type = TUNER_XC2028, | 1017 | .tuner_type = TUNER_XC2028, |
1018 | .mts_firmware = 1, | ||
1018 | .decoder = EM28XX_TVP5150, | 1019 | .decoder = EM28XX_TVP5150, |
1019 | .input = { { | 1020 | .input = { { |
1020 | .type = EM28XX_VMUX_TELEVISION, | 1021 | .type = EM28XX_VMUX_TELEVISION, |
diff --git a/drivers/media/video/gspca/conex.c b/drivers/media/video/gspca/conex.c index 44b0bffeb20e..cd3a3f5829b2 100644 --- a/drivers/media/video/gspca/conex.c +++ b/drivers/media/video/gspca/conex.c | |||
@@ -123,7 +123,7 @@ static void reg_r(struct gspca_dev *gspca_dev, | |||
123 | { | 123 | { |
124 | struct usb_device *dev = gspca_dev->dev; | 124 | struct usb_device *dev = gspca_dev->dev; |
125 | 125 | ||
126 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 126 | #ifdef GSPCA_DEBUG |
127 | if (len > sizeof gspca_dev->usb_buf) { | 127 | if (len > sizeof gspca_dev->usb_buf) { |
128 | err("reg_r: buffer overflow"); | 128 | err("reg_r: buffer overflow"); |
129 | return; | 129 | return; |
@@ -163,7 +163,7 @@ static void reg_w(struct gspca_dev *gspca_dev, | |||
163 | { | 163 | { |
164 | struct usb_device *dev = gspca_dev->dev; | 164 | struct usb_device *dev = gspca_dev->dev; |
165 | 165 | ||
166 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 166 | #ifdef GSPCA_DEBUG |
167 | if (len > sizeof gspca_dev->usb_buf) { | 167 | if (len > sizeof gspca_dev->usb_buf) { |
168 | err("reg_w: buffer overflow"); | 168 | err("reg_w: buffer overflow"); |
169 | return; | 169 | return; |
diff --git a/drivers/media/video/gspca/etoms.c b/drivers/media/video/gspca/etoms.c index c8c2f02fcf00..1dbe92d01e6a 100644 --- a/drivers/media/video/gspca/etoms.c +++ b/drivers/media/video/gspca/etoms.c | |||
@@ -233,7 +233,7 @@ static void reg_r(struct gspca_dev *gspca_dev, | |||
233 | { | 233 | { |
234 | struct usb_device *dev = gspca_dev->dev; | 234 | struct usb_device *dev = gspca_dev->dev; |
235 | 235 | ||
236 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 236 | #ifdef GSPCA_DEBUG |
237 | if (len > sizeof gspca_dev->usb_buf) { | 237 | if (len > sizeof gspca_dev->usb_buf) { |
238 | err("reg_r: buffer overflow"); | 238 | err("reg_r: buffer overflow"); |
239 | return; | 239 | return; |
@@ -271,7 +271,7 @@ static void reg_w(struct gspca_dev *gspca_dev, | |||
271 | { | 271 | { |
272 | struct usb_device *dev = gspca_dev->dev; | 272 | struct usb_device *dev = gspca_dev->dev; |
273 | 273 | ||
274 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 274 | #ifdef GSPCA_DEBUG |
275 | if (len > sizeof gspca_dev->usb_buf) { | 275 | if (len > sizeof gspca_dev->usb_buf) { |
276 | err("reg_w: buffer overflow"); | 276 | err("reg_w: buffer overflow"); |
277 | return; | 277 | return; |
@@ -461,6 +461,52 @@ static void Et_init2(struct gspca_dev *gspca_dev) | |||
461 | reg_w_val(gspca_dev, 0x80, 0x20); /* 0x20; */ | 461 | reg_w_val(gspca_dev, 0x80, 0x20); /* 0x20; */ |
462 | } | 462 | } |
463 | 463 | ||
464 | static void setbrightness(struct gspca_dev *gspca_dev) | ||
465 | { | ||
466 | struct sd *sd = (struct sd *) gspca_dev; | ||
467 | int i; | ||
468 | __u8 brightness = sd->brightness; | ||
469 | |||
470 | for (i = 0; i < 4; i++) | ||
471 | reg_w_val(gspca_dev, ET_O_RED + i, brightness); | ||
472 | } | ||
473 | |||
474 | static void getbrightness(struct gspca_dev *gspca_dev) | ||
475 | { | ||
476 | struct sd *sd = (struct sd *) gspca_dev; | ||
477 | int i; | ||
478 | int brightness = 0; | ||
479 | |||
480 | for (i = 0; i < 4; i++) { | ||
481 | reg_r(gspca_dev, ET_O_RED + i, 1); | ||
482 | brightness += gspca_dev->usb_buf[0]; | ||
483 | } | ||
484 | sd->brightness = brightness >> 3; | ||
485 | } | ||
486 | |||
487 | static void setcontrast(struct gspca_dev *gspca_dev) | ||
488 | { | ||
489 | struct sd *sd = (struct sd *) gspca_dev; | ||
490 | __u8 RGBG[] = { 0x80, 0x80, 0x80, 0x80, 0x00, 0x00 }; | ||
491 | __u8 contrast = sd->contrast; | ||
492 | |||
493 | memset(RGBG, contrast, sizeof(RGBG) - 2); | ||
494 | reg_w(gspca_dev, ET_G_RED, RGBG, 6); | ||
495 | } | ||
496 | |||
497 | static void getcontrast(struct gspca_dev *gspca_dev) | ||
498 | { | ||
499 | struct sd *sd = (struct sd *) gspca_dev; | ||
500 | int i; | ||
501 | int contrast = 0; | ||
502 | |||
503 | for (i = 0; i < 4; i++) { | ||
504 | reg_r(gspca_dev, ET_G_RED + i, 1); | ||
505 | contrast += gspca_dev->usb_buf[0]; | ||
506 | } | ||
507 | sd->contrast = contrast >> 2; | ||
508 | } | ||
509 | |||
464 | static void setcolors(struct gspca_dev *gspca_dev) | 510 | static void setcolors(struct gspca_dev *gspca_dev) |
465 | { | 511 | { |
466 | struct sd *sd = (struct sd *) gspca_dev; | 512 | struct sd *sd = (struct sd *) gspca_dev; |
@@ -492,6 +538,16 @@ static void getcolors(struct gspca_dev *gspca_dev) | |||
492 | } | 538 | } |
493 | } | 539 | } |
494 | 540 | ||
541 | static void setautogain(struct gspca_dev *gspca_dev) | ||
542 | { | ||
543 | struct sd *sd = (struct sd *) gspca_dev; | ||
544 | |||
545 | if (sd->autogain) | ||
546 | sd->ag_cnt = AG_CNT_START; | ||
547 | else | ||
548 | sd->ag_cnt = -1; | ||
549 | } | ||
550 | |||
495 | static void Et_init1(struct gspca_dev *gspca_dev) | 551 | static void Et_init1(struct gspca_dev *gspca_dev) |
496 | { | 552 | { |
497 | __u8 value; | 553 | __u8 value; |
@@ -614,6 +670,7 @@ static int sd_config(struct gspca_dev *gspca_dev, | |||
614 | sd->contrast = CONTRAST_DEF; | 670 | sd->contrast = CONTRAST_DEF; |
615 | sd->colors = COLOR_DEF; | 671 | sd->colors = COLOR_DEF; |
616 | sd->autogain = AUTOGAIN_DEF; | 672 | sd->autogain = AUTOGAIN_DEF; |
673 | sd->ag_cnt = -1; | ||
617 | return 0; | 674 | return 0; |
618 | } | 675 | } |
619 | 676 | ||
@@ -641,6 +698,8 @@ static void sd_start(struct gspca_dev *gspca_dev) | |||
641 | else | 698 | else |
642 | Et_init2(gspca_dev); | 699 | Et_init2(gspca_dev); |
643 | 700 | ||
701 | setautogain(gspca_dev); | ||
702 | |||
644 | reg_w_val(gspca_dev, ET_RESET_ALL, 0x08); | 703 | reg_w_val(gspca_dev, ET_RESET_ALL, 0x08); |
645 | et_video(gspca_dev, 1); /* video on */ | 704 | et_video(gspca_dev, 1); /* video on */ |
646 | } | 705 | } |
@@ -658,52 +717,6 @@ static void sd_close(struct gspca_dev *gspca_dev) | |||
658 | { | 717 | { |
659 | } | 718 | } |
660 | 719 | ||
661 | static void setbrightness(struct gspca_dev *gspca_dev) | ||
662 | { | ||
663 | struct sd *sd = (struct sd *) gspca_dev; | ||
664 | int i; | ||
665 | __u8 brightness = sd->brightness; | ||
666 | |||
667 | for (i = 0; i < 4; i++) | ||
668 | reg_w_val(gspca_dev, ET_O_RED + i, brightness); | ||
669 | } | ||
670 | |||
671 | static void getbrightness(struct gspca_dev *gspca_dev) | ||
672 | { | ||
673 | struct sd *sd = (struct sd *) gspca_dev; | ||
674 | int i; | ||
675 | int brightness = 0; | ||
676 | |||
677 | for (i = 0; i < 4; i++) { | ||
678 | reg_r(gspca_dev, ET_O_RED + i, 1); | ||
679 | brightness += gspca_dev->usb_buf[0]; | ||
680 | } | ||
681 | sd->brightness = brightness >> 3; | ||
682 | } | ||
683 | |||
684 | static void setcontrast(struct gspca_dev *gspca_dev) | ||
685 | { | ||
686 | struct sd *sd = (struct sd *) gspca_dev; | ||
687 | __u8 RGBG[] = { 0x80, 0x80, 0x80, 0x80, 0x00, 0x00 }; | ||
688 | __u8 contrast = sd->contrast; | ||
689 | |||
690 | memset(RGBG, contrast, sizeof(RGBG) - 2); | ||
691 | reg_w(gspca_dev, ET_G_RED, RGBG, 6); | ||
692 | } | ||
693 | |||
694 | static void getcontrast(struct gspca_dev *gspca_dev) | ||
695 | { | ||
696 | struct sd *sd = (struct sd *) gspca_dev; | ||
697 | int i; | ||
698 | int contrast = 0; | ||
699 | |||
700 | for (i = 0; i < 4; i++) { | ||
701 | reg_r(gspca_dev, ET_G_RED + i, 1); | ||
702 | contrast += gspca_dev->usb_buf[0]; | ||
703 | } | ||
704 | sd->contrast = contrast >> 2; | ||
705 | } | ||
706 | |||
707 | static __u8 Et_getgainG(struct gspca_dev *gspca_dev) | 720 | static __u8 Et_getgainG(struct gspca_dev *gspca_dev) |
708 | { | 721 | { |
709 | struct sd *sd = (struct sd *) gspca_dev; | 722 | struct sd *sd = (struct sd *) gspca_dev; |
@@ -733,15 +746,22 @@ static void Et_setgainG(struct gspca_dev *gspca_dev, __u8 gain) | |||
733 | #define LIMIT(color) \ | 746 | #define LIMIT(color) \ |
734 | (unsigned char)((color > 0xff)?0xff:((color < 0)?0:color)) | 747 | (unsigned char)((color > 0xff)?0xff:((color < 0)?0:color)) |
735 | 748 | ||
736 | static void setautogain(struct gspca_dev *gspca_dev) | 749 | static void do_autogain(struct gspca_dev *gspca_dev) |
737 | { | 750 | { |
738 | __u8 luma = 0; | 751 | struct sd *sd = (struct sd *) gspca_dev; |
752 | __u8 luma; | ||
739 | __u8 luma_mean = 128; | 753 | __u8 luma_mean = 128; |
740 | __u8 luma_delta = 20; | 754 | __u8 luma_delta = 20; |
741 | __u8 spring = 4; | 755 | __u8 spring = 4; |
742 | int Gbright = 0; | 756 | int Gbright; |
743 | __u8 r, g, b; | 757 | __u8 r, g, b; |
744 | 758 | ||
759 | if (sd->ag_cnt < 0) | ||
760 | return; | ||
761 | if (--sd->ag_cnt >= 0) | ||
762 | return; | ||
763 | sd->ag_cnt = AG_CNT_START; | ||
764 | |||
745 | Gbright = Et_getgainG(gspca_dev); | 765 | Gbright = Et_getgainG(gspca_dev); |
746 | reg_r(gspca_dev, ET_LUMA_CENTER, 4); | 766 | reg_r(gspca_dev, ET_LUMA_CENTER, 4); |
747 | g = (gspca_dev->usb_buf[0] + gspca_dev->usb_buf[3]) >> 1; | 767 | g = (gspca_dev->usb_buf[0] + gspca_dev->usb_buf[3]) >> 1; |
@@ -768,7 +788,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, | |||
768 | __u8 *data, /* isoc packet */ | 788 | __u8 *data, /* isoc packet */ |
769 | int len) /* iso packet length */ | 789 | int len) /* iso packet length */ |
770 | { | 790 | { |
771 | struct sd *sd; | ||
772 | int seqframe; | 791 | int seqframe; |
773 | 792 | ||
774 | seqframe = data[0] & 0x3f; | 793 | seqframe = data[0] & 0x3f; |
@@ -783,13 +802,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, | |||
783 | frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame, | 802 | frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame, |
784 | data, 0); | 803 | data, 0); |
785 | gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, len); | 804 | gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, len); |
786 | sd = (struct sd *) gspca_dev; | ||
787 | if (sd->ag_cnt >= 0) { | ||
788 | if (--sd->ag_cnt < 0) { | ||
789 | sd->ag_cnt = AG_CNT_START; | ||
790 | setautogain(gspca_dev); | ||
791 | } | ||
792 | } | ||
793 | return; | 805 | return; |
794 | } | 806 | } |
795 | if (len) { | 807 | if (len) { |
@@ -862,10 +874,8 @@ static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) | |||
862 | struct sd *sd = (struct sd *) gspca_dev; | 874 | struct sd *sd = (struct sd *) gspca_dev; |
863 | 875 | ||
864 | sd->autogain = val; | 876 | sd->autogain = val; |
865 | if (val) | 877 | if (gspca_dev->streaming) |
866 | sd->ag_cnt = AG_CNT_START; | 878 | setautogain(gspca_dev); |
867 | else | ||
868 | sd->ag_cnt = -1; | ||
869 | return 0; | 879 | return 0; |
870 | } | 880 | } |
871 | 881 | ||
@@ -889,6 +899,7 @@ static struct sd_desc sd_desc = { | |||
889 | .stop0 = sd_stop0, | 899 | .stop0 = sd_stop0, |
890 | .close = sd_close, | 900 | .close = sd_close, |
891 | .pkt_scan = sd_pkt_scan, | 901 | .pkt_scan = sd_pkt_scan, |
902 | .dq_callback = do_autogain, | ||
892 | }; | 903 | }; |
893 | 904 | ||
894 | /* -- module initialisation -- */ | 905 | /* -- module initialisation -- */ |
diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index 3a051c925ff6..15d302b28b79 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c | |||
@@ -47,7 +47,7 @@ MODULE_LICENSE("GPL"); | |||
47 | 47 | ||
48 | static int video_nr = -1; | 48 | static int video_nr = -1; |
49 | 49 | ||
50 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 50 | #ifdef GSPCA_DEBUG |
51 | int gspca_debug = D_ERR | D_PROBE; | 51 | int gspca_debug = D_ERR | D_PROBE; |
52 | EXPORT_SYMBOL(gspca_debug); | 52 | EXPORT_SYMBOL(gspca_debug); |
53 | 53 | ||
@@ -677,7 +677,7 @@ static int try_fmt_vid_cap(struct gspca_dev *gspca_dev, | |||
677 | w = fmt->fmt.pix.width; | 677 | w = fmt->fmt.pix.width; |
678 | h = fmt->fmt.pix.height; | 678 | h = fmt->fmt.pix.height; |
679 | 679 | ||
680 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 680 | #ifdef GSPCA_DEBUG |
681 | if (gspca_debug & D_CONF) | 681 | if (gspca_debug & D_CONF) |
682 | PDEBUG_MODE("try fmt cap", fmt->fmt.pix.pixelformat, w, h); | 682 | PDEBUG_MODE("try fmt cap", fmt->fmt.pix.pixelformat, w, h); |
683 | #endif | 683 | #endif |
@@ -785,7 +785,7 @@ static int dev_open(struct inode *inode, struct file *file) | |||
785 | } | 785 | } |
786 | gspca_dev->users++; | 786 | gspca_dev->users++; |
787 | file->private_data = gspca_dev; | 787 | file->private_data = gspca_dev; |
788 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 788 | #ifdef GSPCA_DEBUG |
789 | /* activate the v4l2 debug */ | 789 | /* activate the v4l2 debug */ |
790 | if (gspca_debug & D_V4L2) | 790 | if (gspca_debug & D_V4L2) |
791 | gspca_dev->vdev.debug |= 3; | 791 | gspca_dev->vdev.debug |= 3; |
@@ -904,7 +904,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv, | |||
904 | if (ctrl->id != ctrls->qctrl.id) | 904 | if (ctrl->id != ctrls->qctrl.id) |
905 | continue; | 905 | continue; |
906 | if (ctrl->value < ctrls->qctrl.minimum | 906 | if (ctrl->value < ctrls->qctrl.minimum |
907 | && ctrl->value > ctrls->qctrl.maximum) | 907 | || ctrl->value > ctrls->qctrl.maximum) |
908 | return -ERANGE; | 908 | return -ERANGE; |
909 | PDEBUG(D_CONF, "set ctrl [%08x] = %d", ctrl->id, ctrl->value); | 909 | PDEBUG(D_CONF, "set ctrl [%08x] = %d", ctrl->id, ctrl->value); |
910 | if (mutex_lock_interruptible(&gspca_dev->usb_lock)) | 910 | if (mutex_lock_interruptible(&gspca_dev->usb_lock)) |
@@ -1080,7 +1080,7 @@ static int vidioc_streamon(struct file *file, void *priv, | |||
1080 | if (ret < 0) | 1080 | if (ret < 0) |
1081 | goto out; | 1081 | goto out; |
1082 | } | 1082 | } |
1083 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 1083 | #ifdef GSPCA_DEBUG |
1084 | if (gspca_debug & D_STREAM) { | 1084 | if (gspca_debug & D_STREAM) { |
1085 | PDEBUG_MODE("stream on OK", | 1085 | PDEBUG_MODE("stream on OK", |
1086 | gspca_dev->pixfmt, | 1086 | gspca_dev->pixfmt, |
@@ -1913,7 +1913,7 @@ static void __exit gspca_exit(void) | |||
1913 | module_init(gspca_init); | 1913 | module_init(gspca_init); |
1914 | module_exit(gspca_exit); | 1914 | module_exit(gspca_exit); |
1915 | 1915 | ||
1916 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 1916 | #ifdef GSPCA_DEBUG |
1917 | module_param_named(debug, gspca_debug, int, 0644); | 1917 | module_param_named(debug, gspca_debug, int, 0644); |
1918 | MODULE_PARM_DESC(debug, | 1918 | MODULE_PARM_DESC(debug, |
1919 | "Debug (bit) 0x01:error 0x02:probe 0x04:config" | 1919 | "Debug (bit) 0x01:error 0x02:probe 0x04:config" |
diff --git a/drivers/media/video/gspca/gspca.h b/drivers/media/video/gspca/gspca.h index 3fd2c4eee204..67e448940eaa 100644 --- a/drivers/media/video/gspca/gspca.h +++ b/drivers/media/video/gspca/gspca.h | |||
@@ -9,7 +9,10 @@ | |||
9 | #include <media/v4l2-common.h> | 9 | #include <media/v4l2-common.h> |
10 | #include <linux/mutex.h> | 10 | #include <linux/mutex.h> |
11 | 11 | ||
12 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 12 | /* compilation option */ |
13 | #define GSPCA_DEBUG 1 | ||
14 | |||
15 | #ifdef GSPCA_DEBUG | ||
13 | /* GSPCA our debug messages */ | 16 | /* GSPCA our debug messages */ |
14 | extern int gspca_debug; | 17 | extern int gspca_debug; |
15 | #define PDEBUG(level, fmt, args...) \ | 18 | #define PDEBUG(level, fmt, args...) \ |
diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/video/gspca/ov519.c index 83139efc4629..b4f00ec0885c 100644 --- a/drivers/media/video/gspca/ov519.c +++ b/drivers/media/video/gspca/ov519.c | |||
@@ -40,14 +40,15 @@ struct sd { | |||
40 | struct gspca_dev gspca_dev; /* !! must be the first item */ | 40 | struct gspca_dev gspca_dev; /* !! must be the first item */ |
41 | 41 | ||
42 | /* Determined by sensor type */ | 42 | /* Determined by sensor type */ |
43 | short maxwidth; | 43 | char sif; |
44 | short maxheight; | ||
45 | 44 | ||
46 | unsigned char primary_i2c_slave; /* I2C write id of sensor */ | 45 | unsigned char primary_i2c_slave; /* I2C write id of sensor */ |
47 | 46 | ||
48 | unsigned char brightness; | 47 | unsigned char brightness; |
49 | unsigned char contrast; | 48 | unsigned char contrast; |
50 | unsigned char colors; | 49 | unsigned char colors; |
50 | __u8 hflip; | ||
51 | __u8 vflip; | ||
51 | 52 | ||
52 | char compress; /* Should the next frame be compressed? */ | 53 | char compress; /* Should the next frame be compressed? */ |
53 | char compress_inited; /* Are compression params uploaded? */ | 54 | char compress_inited; /* Are compression params uploaded? */ |
@@ -77,9 +78,12 @@ static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); | |||
77 | static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); | 78 | static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); |
78 | static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val); | 79 | static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val); |
79 | static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val); | 80 | static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val); |
81 | static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val); | ||
82 | static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val); | ||
83 | static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val); | ||
84 | static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val); | ||
80 | 85 | ||
81 | static struct ctrl sd_ctrls[] = { | 86 | static struct ctrl sd_ctrls[] = { |
82 | #define SD_BRIGHTNESS 0 | ||
83 | { | 87 | { |
84 | { | 88 | { |
85 | .id = V4L2_CID_BRIGHTNESS, | 89 | .id = V4L2_CID_BRIGHTNESS, |
@@ -88,12 +92,12 @@ static struct ctrl sd_ctrls[] = { | |||
88 | .minimum = 0, | 92 | .minimum = 0, |
89 | .maximum = 255, | 93 | .maximum = 255, |
90 | .step = 1, | 94 | .step = 1, |
91 | .default_value = 127, | 95 | #define BRIGHTNESS_DEF 127 |
96 | .default_value = BRIGHTNESS_DEF, | ||
92 | }, | 97 | }, |
93 | .set = sd_setbrightness, | 98 | .set = sd_setbrightness, |
94 | .get = sd_getbrightness, | 99 | .get = sd_getbrightness, |
95 | }, | 100 | }, |
96 | #define SD_CONTRAST 1 | ||
97 | { | 101 | { |
98 | { | 102 | { |
99 | .id = V4L2_CID_CONTRAST, | 103 | .id = V4L2_CID_CONTRAST, |
@@ -102,31 +106,61 @@ static struct ctrl sd_ctrls[] = { | |||
102 | .minimum = 0, | 106 | .minimum = 0, |
103 | .maximum = 255, | 107 | .maximum = 255, |
104 | .step = 1, | 108 | .step = 1, |
105 | .default_value = 127, | 109 | #define CONTRAST_DEF 127 |
110 | .default_value = CONTRAST_DEF, | ||
106 | }, | 111 | }, |
107 | .set = sd_setcontrast, | 112 | .set = sd_setcontrast, |
108 | .get = sd_getcontrast, | 113 | .get = sd_getcontrast, |
109 | }, | 114 | }, |
110 | #define SD_COLOR 2 | ||
111 | { | 115 | { |
112 | { | 116 | { |
113 | .id = V4L2_CID_SATURATION, | 117 | .id = V4L2_CID_SATURATION, |
114 | .type = V4L2_CTRL_TYPE_INTEGER, | 118 | .type = V4L2_CTRL_TYPE_INTEGER, |
115 | .name = "Saturation", | 119 | .name = "Color", |
116 | .minimum = 0, | 120 | .minimum = 0, |
117 | .maximum = 255, | 121 | .maximum = 255, |
118 | .step = 1, | 122 | .step = 1, |
119 | .default_value = 127, | 123 | #define COLOR_DEF 127 |
124 | .default_value = COLOR_DEF, | ||
120 | }, | 125 | }, |
121 | .set = sd_setcolors, | 126 | .set = sd_setcolors, |
122 | .get = sd_getcolors, | 127 | .get = sd_getcolors, |
123 | }, | 128 | }, |
129 | /* next controls work with ov7670 only */ | ||
130 | { | ||
131 | { | ||
132 | .id = V4L2_CID_HFLIP, | ||
133 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
134 | .name = "Mirror", | ||
135 | .minimum = 0, | ||
136 | .maximum = 1, | ||
137 | .step = 1, | ||
138 | #define HFLIP_DEF 0 | ||
139 | .default_value = HFLIP_DEF, | ||
140 | }, | ||
141 | .set = sd_sethflip, | ||
142 | .get = sd_gethflip, | ||
143 | }, | ||
144 | { | ||
145 | { | ||
146 | .id = V4L2_CID_VFLIP, | ||
147 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
148 | .name = "Vflip", | ||
149 | .minimum = 0, | ||
150 | .maximum = 1, | ||
151 | .step = 1, | ||
152 | #define VFLIP_DEF 0 | ||
153 | .default_value = VFLIP_DEF, | ||
154 | }, | ||
155 | .set = sd_setvflip, | ||
156 | .get = sd_getvflip, | ||
157 | }, | ||
124 | }; | 158 | }; |
125 | 159 | ||
126 | static struct v4l2_pix_format vga_mode[] = { | 160 | static struct v4l2_pix_format vga_mode[] = { |
127 | {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, | 161 | {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, |
128 | .bytesperline = 320, | 162 | .bytesperline = 320, |
129 | .sizeimage = 320 * 240 * 3 / 8 + 589, | 163 | .sizeimage = 320 * 240 * 3 / 8 + 590, |
130 | .colorspace = V4L2_COLORSPACE_JPEG, | 164 | .colorspace = V4L2_COLORSPACE_JPEG, |
131 | .priv = 1}, | 165 | .priv = 1}, |
132 | {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, | 166 | {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, |
@@ -138,12 +172,12 @@ static struct v4l2_pix_format vga_mode[] = { | |||
138 | static struct v4l2_pix_format sif_mode[] = { | 172 | static struct v4l2_pix_format sif_mode[] = { |
139 | {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, | 173 | {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, |
140 | .bytesperline = 176, | 174 | .bytesperline = 176, |
141 | .sizeimage = 176 * 144 * 3 / 8 + 589, | 175 | .sizeimage = 176 * 144 * 3 / 8 + 590, |
142 | .colorspace = V4L2_COLORSPACE_JPEG, | 176 | .colorspace = V4L2_COLORSPACE_JPEG, |
143 | .priv = 1}, | 177 | .priv = 1}, |
144 | {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, | 178 | {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, |
145 | .bytesperline = 352, | 179 | .bytesperline = 352, |
146 | .sizeimage = 352 * 288 * 3 / 8 + 589, | 180 | .sizeimage = 352 * 288 * 3 / 8 + 590, |
147 | .colorspace = V4L2_COLORSPACE_JPEG, | 181 | .colorspace = V4L2_COLORSPACE_JPEG, |
148 | .priv = 0}, | 182 | .priv = 0}, |
149 | }; | 183 | }; |
@@ -225,6 +259,7 @@ static struct v4l2_pix_format sif_mode[] = { | |||
225 | #define OV7670_REG_VSTART 0x19 /* Vert start high bits */ | 259 | #define OV7670_REG_VSTART 0x19 /* Vert start high bits */ |
226 | #define OV7670_REG_VSTOP 0x1a /* Vert stop high bits */ | 260 | #define OV7670_REG_VSTOP 0x1a /* Vert stop high bits */ |
227 | #define OV7670_REG_MVFP 0x1e /* Mirror / vflip */ | 261 | #define OV7670_REG_MVFP 0x1e /* Mirror / vflip */ |
262 | #define OV7670_MVFP_VFLIP 0x10 /* vertical flip */ | ||
228 | #define OV7670_MVFP_MIRROR 0x20 /* Mirror image */ | 263 | #define OV7670_MVFP_MIRROR 0x20 /* Mirror image */ |
229 | #define OV7670_REG_AEW 0x24 /* AGC upper limit */ | 264 | #define OV7670_REG_AEW 0x24 /* AGC upper limit */ |
230 | #define OV7670_REG_AEB 0x25 /* AGC lower limit */ | 265 | #define OV7670_REG_AEB 0x25 /* AGC lower limit */ |
@@ -258,16 +293,6 @@ static struct v4l2_pix_format sif_mode[] = { | |||
258 | #define OV7670_REG_HAECC7 0xaa /* Hist AEC/AGC control 7 */ | 293 | #define OV7670_REG_HAECC7 0xaa /* Hist AEC/AGC control 7 */ |
259 | #define OV7670_REG_BD60MAX 0xab /* 60hz banding step limit */ | 294 | #define OV7670_REG_BD60MAX 0xab /* 60hz banding step limit */ |
260 | 295 | ||
261 | struct ovsensor_window { | ||
262 | short x; | ||
263 | short y; | ||
264 | short width; | ||
265 | short height; | ||
266 | /* int format; */ | ||
267 | short quarter; /* Scale width and height down 2x */ | ||
268 | short clockdiv; /* Clock divisor setting */ | ||
269 | }; | ||
270 | |||
271 | static unsigned char ov7670_abs_to_sm(unsigned char v) | 296 | static unsigned char ov7670_abs_to_sm(unsigned char v) |
272 | { | 297 | { |
273 | if (v > 127) | 298 | if (v > 127) |
@@ -499,19 +524,6 @@ static int init_ov_sensor(struct sd *sd) | |||
499 | return 0; | 524 | return 0; |
500 | } | 525 | } |
501 | 526 | ||
502 | /* Switch on standard JPEG compression. Returns 0 for success. */ | ||
503 | static int ov519_init_compression(struct sd *sd) | ||
504 | { | ||
505 | if (!sd->compress_inited) { | ||
506 | if (reg_w_mask(sd, OV519_SYS_EN_CLK1, 1 << 2, 1 << 2) < 0) { | ||
507 | PDEBUG(D_ERR, "Error switching to compressed mode"); | ||
508 | return -EIO; | ||
509 | } | ||
510 | sd->compress_inited = 1; | ||
511 | } | ||
512 | return 0; | ||
513 | } | ||
514 | |||
515 | /* Set the read and write slave IDs. The "slave" argument is the write slave, | 527 | /* Set the read and write slave IDs. The "slave" argument is the write slave, |
516 | * and the read slave will be set to (slave + 1). | 528 | * and the read slave will be set to (slave + 1). |
517 | * This should not be called from outside the i2c I/O functions. | 529 | * This should not be called from outside the i2c I/O functions. |
@@ -681,21 +693,17 @@ static int ov8xx0_configure(struct sd *sd) | |||
681 | return -1; | 693 | return -1; |
682 | } | 694 | } |
683 | if ((rc & 3) == 1) { | 695 | if ((rc & 3) == 1) { |
684 | PDEBUG(D_PROBE, "Sensor is an OV8610"); | ||
685 | sd->sensor = SEN_OV8610; | 696 | sd->sensor = SEN_OV8610; |
686 | } else { | 697 | } else { |
687 | PDEBUG(D_ERR, "Unknown image sensor version: %d", rc & 3); | 698 | PDEBUG(D_ERR, "Unknown image sensor version: %d", rc & 3); |
688 | return -1; | 699 | return -1; |
689 | } | 700 | } |
690 | PDEBUG(D_PROBE, "Writing 8610 registers"); | 701 | PDEBUG(D_PROBE, "Writing 8610 registers"); |
691 | if (write_i2c_regvals(sd, | 702 | if (write_i2c_regvals(sd, norm_8610, ARRAY_SIZE(norm_8610))) |
692 | norm_8610, | ||
693 | sizeof norm_8610 / sizeof norm_8610[0])) | ||
694 | return -1; | 703 | return -1; |
695 | 704 | ||
696 | /* Set sensor-specific vars */ | 705 | /* Set sensor-specific vars */ |
697 | sd->maxwidth = 640; | 706 | /* sd->sif = 0; already done */ |
698 | sd->maxheight = 480; | ||
699 | return 0; | 707 | return 0; |
700 | } | 708 | } |
701 | 709 | ||
@@ -825,7 +833,7 @@ static int ov7xx0_configure(struct sd *sd) | |||
825 | { OV7670_REG_COM7, OV7670_COM7_RESET }, | 833 | { OV7670_REG_COM7, OV7670_COM7_RESET }, |
826 | { OV7670_REG_TSLB, 0x04 }, /* OV */ | 834 | { OV7670_REG_TSLB, 0x04 }, /* OV */ |
827 | { OV7670_REG_COM7, OV7670_COM7_FMT_VGA }, /* VGA */ | 835 | { OV7670_REG_COM7, OV7670_COM7_FMT_VGA }, /* VGA */ |
828 | { OV7670_REG_CLKRC, 0x1 }, | 836 | { OV7670_REG_CLKRC, 0x01 }, |
829 | /* | 837 | /* |
830 | * Set the hardware window. These values from OV don't entirely | 838 | * Set the hardware window. These values from OV don't entirely |
831 | * make sense - hstop is less than hstart. But they work... | 839 | * make sense - hstop is less than hstart. But they work... |
@@ -839,16 +847,12 @@ static int ov7xx0_configure(struct sd *sd) | |||
839 | { 0x70, 0x3a }, { 0x71, 0x35 }, | 847 | { 0x70, 0x3a }, { 0x71, 0x35 }, |
840 | { 0x72, 0x11 }, { 0x73, 0xf0 }, | 848 | { 0x72, 0x11 }, { 0x73, 0xf0 }, |
841 | { 0xa2, 0x02 }, | 849 | { 0xa2, 0x02 }, |
842 | /* jfm */ | 850 | /* { OV7670_REG_COM10, 0x0 }, */ |
843 | /* { OV7670_REG_COM10, 0x0 }, */ | ||
844 | 851 | ||
845 | /* Gamma curve values */ | 852 | /* Gamma curve values */ |
846 | { 0x7a, 0x20 }, | 853 | { 0x7a, 0x20 }, |
847 | /* jfm:win 7b=1c */ | ||
848 | { 0x7b, 0x10 }, | 854 | { 0x7b, 0x10 }, |
849 | /* jfm:win 7c=28 */ | ||
850 | { 0x7c, 0x1e }, | 855 | { 0x7c, 0x1e }, |
851 | /* jfm:win 7d=3c */ | ||
852 | { 0x7d, 0x35 }, | 856 | { 0x7d, 0x35 }, |
853 | { 0x7e, 0x5a }, { 0x7f, 0x69 }, | 857 | { 0x7e, 0x5a }, { 0x7f, 0x69 }, |
854 | { 0x80, 0x76 }, { 0x81, 0x80 }, | 858 | { 0x80, 0x76 }, { 0x81, 0x80 }, |
@@ -864,13 +868,11 @@ static int ov7xx0_configure(struct sd *sd) | |||
864 | | OV7670_COM8_BFILT }, | 868 | | OV7670_COM8_BFILT }, |
865 | { OV7670_REG_GAIN, 0 }, { OV7670_REG_AECH, 0 }, | 869 | { OV7670_REG_GAIN, 0 }, { OV7670_REG_AECH, 0 }, |
866 | { OV7670_REG_COM4, 0x40 }, /* magic reserved bit */ | 870 | { OV7670_REG_COM4, 0x40 }, /* magic reserved bit */ |
867 | /* jfm:win 14=38 */ | ||
868 | { OV7670_REG_COM9, 0x18 }, /* 4x gain + magic rsvd bit */ | 871 | { OV7670_REG_COM9, 0x18 }, /* 4x gain + magic rsvd bit */ |
869 | { OV7670_REG_BD50MAX, 0x05 }, { OV7670_REG_BD60MAX, 0x07 }, | 872 | { OV7670_REG_BD50MAX, 0x05 }, { OV7670_REG_BD60MAX, 0x07 }, |
870 | { OV7670_REG_AEW, 0x95 }, { OV7670_REG_AEB, 0x33 }, | 873 | { OV7670_REG_AEW, 0x95 }, { OV7670_REG_AEB, 0x33 }, |
871 | { OV7670_REG_VPT, 0xe3 }, { OV7670_REG_HAECC1, 0x78 }, | 874 | { OV7670_REG_VPT, 0xe3 }, { OV7670_REG_HAECC1, 0x78 }, |
872 | { OV7670_REG_HAECC2, 0x68 }, | 875 | { OV7670_REG_HAECC2, 0x68 }, |
873 | /* jfm:win a1=0b */ | ||
874 | { 0xa1, 0x03 }, /* magic */ | 876 | { 0xa1, 0x03 }, /* magic */ |
875 | { OV7670_REG_HAECC3, 0xd8 }, { OV7670_REG_HAECC4, 0xd8 }, | 877 | { OV7670_REG_HAECC3, 0xd8 }, { OV7670_REG_HAECC4, 0xd8 }, |
876 | { OV7670_REG_HAECC5, 0xf0 }, { OV7670_REG_HAECC6, 0x90 }, | 878 | { OV7670_REG_HAECC5, 0xf0 }, { OV7670_REG_HAECC6, 0x90 }, |
@@ -884,8 +886,6 @@ static int ov7xx0_configure(struct sd *sd) | |||
884 | /* Almost all of these are magic "reserved" values. */ | 886 | /* Almost all of these are magic "reserved" values. */ |
885 | { OV7670_REG_COM5, 0x61 }, { OV7670_REG_COM6, 0x4b }, | 887 | { OV7670_REG_COM5, 0x61 }, { OV7670_REG_COM6, 0x4b }, |
886 | { 0x16, 0x02 }, | 888 | { 0x16, 0x02 }, |
887 | /* jfm */ | ||
888 | /* { OV7670_REG_MVFP, 0x07|OV7670_MVFP_MIRROR }, */ | ||
889 | { OV7670_REG_MVFP, 0x07 }, | 889 | { OV7670_REG_MVFP, 0x07 }, |
890 | { 0x21, 0x02 }, { 0x22, 0x91 }, | 890 | { 0x21, 0x02 }, { 0x22, 0x91 }, |
891 | { 0x29, 0x07 }, { 0x33, 0x0b }, | 891 | { 0x29, 0x07 }, { 0x33, 0x0b }, |
@@ -930,7 +930,10 @@ static int ov7xx0_configure(struct sd *sd) | |||
930 | { OV7670_REG_EDGE, 0 }, | 930 | { OV7670_REG_EDGE, 0 }, |
931 | { 0x75, 0x05 }, { 0x76, 0xe1 }, | 931 | { 0x75, 0x05 }, { 0x76, 0xe1 }, |
932 | { 0x4c, 0 }, { 0x77, 0x01 }, | 932 | { 0x4c, 0 }, { 0x77, 0x01 }, |
933 | { OV7670_REG_COM13, 0xc3 }, { 0x4b, 0x09 }, | 933 | { OV7670_REG_COM13, OV7670_COM13_GAMMA |
934 | | OV7670_COM13_UVSAT | ||
935 | | 2}, /* was 3 */ | ||
936 | { 0x4b, 0x09 }, | ||
934 | { 0xc9, 0x60 }, { OV7670_REG_COM16, 0x38 }, | 937 | { 0xc9, 0x60 }, { OV7670_REG_COM16, 0x38 }, |
935 | { 0x56, 0x40 }, | 938 | { 0x56, 0x40 }, |
936 | 939 | ||
@@ -956,30 +959,10 @@ static int ov7xx0_configure(struct sd *sd) | |||
956 | { 0x79, 0x03 }, { 0xc8, 0x40 }, | 959 | { 0x79, 0x03 }, { 0xc8, 0x40 }, |
957 | { 0x79, 0x05 }, { 0xc8, 0x30 }, | 960 | { 0x79, 0x05 }, { 0xc8, 0x30 }, |
958 | { 0x79, 0x26 }, | 961 | { 0x79, 0x26 }, |
959 | 962 | }; | |
960 | /* Format YUV422 */ | ||
961 | { OV7670_REG_COM7, OV7670_COM7_YUV }, /* Selects YUV mode */ | ||
962 | { OV7670_REG_RGB444, 0 }, /* No RGB444 please */ | ||
963 | { OV7670_REG_COM1, 0 }, | ||
964 | { OV7670_REG_COM15, OV7670_COM15_R00FF }, | ||
965 | { OV7670_REG_COM9, 0x18 }, | ||
966 | /* 4x gain ceiling; 0x8 is reserved bit */ | ||
967 | { 0x4f, 0x80 }, /* "matrix coefficient 1" */ | ||
968 | { 0x50, 0x80 }, /* "matrix coefficient 2" */ | ||
969 | { 0x52, 0x22 }, /* "matrix coefficient 4" */ | ||
970 | { 0x53, 0x5e }, /* "matrix coefficient 5" */ | ||
971 | { 0x54, 0x80 }, /* "matrix coefficient 6" */ | ||
972 | { OV7670_REG_COM13, OV7670_COM13_GAMMA|OV7670_COM13_UVSAT }, | ||
973 | }; | ||
974 | 963 | ||
975 | PDEBUG(D_PROBE, "starting OV7xx0 configuration"); | 964 | PDEBUG(D_PROBE, "starting OV7xx0 configuration"); |
976 | 965 | ||
977 | /* jfm:already done? */ | ||
978 | if (init_ov_sensor(sd) < 0) | ||
979 | PDEBUG(D_ERR, "Failed to read sensor ID"); | ||
980 | else | ||
981 | PDEBUG(D_PROBE, "OV7xx0 initialized"); | ||
982 | |||
983 | /* Detect sensor (sub)type */ | 966 | /* Detect sensor (sub)type */ |
984 | rc = i2c_r(sd, OV7610_REG_COM_I); | 967 | rc = i2c_r(sd, OV7610_REG_COM_I); |
985 | 968 | ||
@@ -1025,20 +1008,25 @@ static int ov7xx0_configure(struct sd *sd) | |||
1025 | return low; | 1008 | return low; |
1026 | } | 1009 | } |
1027 | if (high == 0x76) { | 1010 | if (high == 0x76) { |
1028 | if (low == 0x30) { | 1011 | switch (low) { |
1012 | case 0x30: | ||
1029 | PDEBUG(D_PROBE, "Sensor is an OV7630/OV7635"); | 1013 | PDEBUG(D_PROBE, "Sensor is an OV7630/OV7635"); |
1030 | sd->sensor = SEN_OV7630; | 1014 | sd->sensor = SEN_OV7630; |
1031 | } else if (low == 0x40) { | 1015 | break; |
1016 | case 0x40: | ||
1032 | PDEBUG(D_PROBE, "Sensor is an OV7645"); | 1017 | PDEBUG(D_PROBE, "Sensor is an OV7645"); |
1033 | sd->sensor = SEN_OV7640; /* FIXME */ | 1018 | sd->sensor = SEN_OV7640; /* FIXME */ |
1034 | } else if (low == 0x45) { | 1019 | break; |
1020 | case 0x45: | ||
1035 | PDEBUG(D_PROBE, "Sensor is an OV7645B"); | 1021 | PDEBUG(D_PROBE, "Sensor is an OV7645B"); |
1036 | sd->sensor = SEN_OV7640; /* FIXME */ | 1022 | sd->sensor = SEN_OV7640; /* FIXME */ |
1037 | } else if (low == 0x48) { | 1023 | break; |
1024 | case 0x48: | ||
1038 | PDEBUG(D_PROBE, "Sensor is an OV7648"); | 1025 | PDEBUG(D_PROBE, "Sensor is an OV7648"); |
1039 | sd->sensor = SEN_OV7640; /* FIXME */ | 1026 | sd->sensor = SEN_OV7640; /* FIXME */ |
1040 | } else { | 1027 | break; |
1041 | PDEBUG(D_PROBE, "Unknown sensor: 0x76%X", low); | 1028 | default: |
1029 | PDEBUG(D_PROBE, "Unknown sensor: 0x76%x", low); | ||
1042 | return -1; | 1030 | return -1; |
1043 | } | 1031 | } |
1044 | } else { | 1032 | } else { |
@@ -1050,34 +1038,34 @@ static int ov7xx0_configure(struct sd *sd) | |||
1050 | return -1; | 1038 | return -1; |
1051 | } | 1039 | } |
1052 | 1040 | ||
1053 | if (sd->sensor == SEN_OV7620) { | 1041 | switch (sd->sensor) { |
1042 | case SEN_OV7620: | ||
1054 | PDEBUG(D_PROBE, "Writing 7620 registers"); | 1043 | PDEBUG(D_PROBE, "Writing 7620 registers"); |
1055 | if (write_i2c_regvals(sd, norm_7620, | 1044 | if (write_i2c_regvals(sd, norm_7620, ARRAY_SIZE(norm_7620))) |
1056 | sizeof norm_7620 / sizeof norm_7620[0])) | ||
1057 | return -1; | 1045 | return -1; |
1058 | } else if (sd->sensor == SEN_OV7630) { | 1046 | break; |
1047 | case SEN_OV7630: | ||
1059 | PDEBUG(D_ERR, "7630 is not supported by this driver version"); | 1048 | PDEBUG(D_ERR, "7630 is not supported by this driver version"); |
1060 | return -1; | 1049 | return -1; |
1061 | } else if (sd->sensor == SEN_OV7640) { | 1050 | case SEN_OV7640: |
1062 | PDEBUG(D_PROBE, "Writing 7640 registers"); | 1051 | PDEBUG(D_PROBE, "Writing 7640 registers"); |
1063 | if (write_i2c_regvals(sd, norm_7640, | 1052 | if (write_i2c_regvals(sd, norm_7640, ARRAY_SIZE(norm_7640))) |
1064 | sizeof norm_7640 / sizeof norm_7640[0])) | ||
1065 | return -1; | 1053 | return -1; |
1066 | } else if (sd->sensor == SEN_OV7670) { | 1054 | break; |
1055 | case SEN_OV7670: | ||
1067 | PDEBUG(D_PROBE, "Writing 7670 registers"); | 1056 | PDEBUG(D_PROBE, "Writing 7670 registers"); |
1068 | if (write_i2c_regvals(sd, norm_7670, | 1057 | if (write_i2c_regvals(sd, norm_7670, ARRAY_SIZE(norm_7670))) |
1069 | sizeof norm_7670 / sizeof norm_7670[0])) | ||
1070 | return -1; | 1058 | return -1; |
1071 | } else { | 1059 | break; |
1060 | default: | ||
1072 | PDEBUG(D_PROBE, "Writing 7610 registers"); | 1061 | PDEBUG(D_PROBE, "Writing 7610 registers"); |
1073 | if (write_i2c_regvals(sd, norm_7610, | 1062 | if (write_i2c_regvals(sd, norm_7610, ARRAY_SIZE(norm_7610))) |
1074 | sizeof norm_7610 / sizeof norm_7610[0])) | ||
1075 | return -1; | 1063 | return -1; |
1064 | break; | ||
1076 | } | 1065 | } |
1077 | 1066 | ||
1078 | /* Set sensor-specific vars */ | 1067 | /* Set sensor-specific vars */ |
1079 | sd->maxwidth = 640; | 1068 | /* sd->sif = 0; already done */ |
1080 | sd->maxheight = 480; | ||
1081 | return 0; | 1069 | return 0; |
1082 | } | 1070 | } |
1083 | 1071 | ||
@@ -1231,43 +1219,45 @@ static int ov6xx0_configure(struct sd *sd) | |||
1231 | /* Ugh. The first two bits are the version bits, but | 1219 | /* Ugh. The first two bits are the version bits, but |
1232 | * the entire register value must be used. I guess OVT | 1220 | * the entire register value must be used. I guess OVT |
1233 | * underestimated how many variants they would make. */ | 1221 | * underestimated how many variants they would make. */ |
1234 | if (rc == 0x00) { | 1222 | switch (rc) { |
1223 | case 0x00: | ||
1235 | sd->sensor = SEN_OV6630; | 1224 | sd->sensor = SEN_OV6630; |
1236 | PDEBUG(D_ERR, | 1225 | PDEBUG(D_ERR, |
1237 | "WARNING: Sensor is an OV66308. Your camera may have"); | 1226 | "WARNING: Sensor is an OV66308. Your camera may have"); |
1238 | PDEBUG(D_ERR, "been misdetected in previous driver versions."); | 1227 | PDEBUG(D_ERR, "been misdetected in previous driver versions."); |
1239 | } else if (rc == 0x01) { | 1228 | break; |
1229 | case 0x01: | ||
1240 | sd->sensor = SEN_OV6620; | 1230 | sd->sensor = SEN_OV6620; |
1241 | PDEBUG(D_PROBE, "Sensor is an OV6620"); | 1231 | break; |
1242 | } else if (rc == 0x02) { | 1232 | case 0x02: |
1243 | sd->sensor = SEN_OV6630; | 1233 | sd->sensor = SEN_OV6630; |
1244 | PDEBUG(D_PROBE, "Sensor is an OV66308AE"); | 1234 | PDEBUG(D_PROBE, "Sensor is an OV66308AE"); |
1245 | } else if (rc == 0x03) { | 1235 | break; |
1236 | case 0x03: | ||
1246 | sd->sensor = SEN_OV6630; | 1237 | sd->sensor = SEN_OV6630; |
1247 | PDEBUG(D_PROBE, "Sensor is an OV66308AF"); | 1238 | PDEBUG(D_PROBE, "Sensor is an OV66308AF"); |
1248 | } else if (rc == 0x90) { | 1239 | break; |
1240 | case 0x90: | ||
1249 | sd->sensor = SEN_OV6630; | 1241 | sd->sensor = SEN_OV6630; |
1250 | PDEBUG(D_ERR, | 1242 | PDEBUG(D_ERR, |
1251 | "WARNING: Sensor is an OV66307. Your camera may have"); | 1243 | "WARNING: Sensor is an OV66307. Your camera may have"); |
1252 | PDEBUG(D_ERR, "been misdetected in previous driver versions."); | 1244 | PDEBUG(D_ERR, "been misdetected in previous driver versions."); |
1253 | } else { | 1245 | break; |
1246 | default: | ||
1254 | PDEBUG(D_ERR, "FATAL: Unknown sensor version: 0x%02x", rc); | 1247 | PDEBUG(D_ERR, "FATAL: Unknown sensor version: 0x%02x", rc); |
1255 | return -1; | 1248 | return -1; |
1256 | } | 1249 | } |
1257 | 1250 | ||
1258 | /* Set sensor-specific vars */ | 1251 | /* Set sensor-specific vars */ |
1259 | sd->maxwidth = 352; | 1252 | sd->sif = 1; |
1260 | sd->maxheight = 288; | ||
1261 | 1253 | ||
1262 | if (sd->sensor == SEN_OV6620) { | 1254 | if (sd->sensor == SEN_OV6620) { |
1263 | PDEBUG(D_PROBE, "Writing 6x20 registers"); | 1255 | PDEBUG(D_PROBE, "Writing 6x20 registers"); |
1264 | if (write_i2c_regvals(sd, norm_6x20, | 1256 | if (write_i2c_regvals(sd, norm_6x20, ARRAY_SIZE(norm_6x20))) |
1265 | sizeof norm_6x20 / sizeof norm_6x20[0])) | ||
1266 | return -1; | 1257 | return -1; |
1267 | } else { | 1258 | } else { |
1268 | PDEBUG(D_PROBE, "Writing 6x30 registers"); | 1259 | PDEBUG(D_PROBE, "Writing 6x30 registers"); |
1269 | if (write_i2c_regvals(sd, norm_6x30, | 1260 | if (write_i2c_regvals(sd, norm_6x30, ARRAY_SIZE(norm_6x30))) |
1270 | sizeof norm_6x30 / sizeof norm_6x30[0])) | ||
1271 | return -1; | 1261 | return -1; |
1272 | } | 1262 | } |
1273 | return 0; | 1263 | return 0; |
@@ -1276,14 +1266,8 @@ static int ov6xx0_configure(struct sd *sd) | |||
1276 | /* Turns on or off the LED. Only has an effect with OV511+/OV518(+)/OV519 */ | 1266 | /* Turns on or off the LED. Only has an effect with OV511+/OV518(+)/OV519 */ |
1277 | static void ov51x_led_control(struct sd *sd, int on) | 1267 | static void ov51x_led_control(struct sd *sd, int on) |
1278 | { | 1268 | { |
1279 | PDEBUG(D_STREAM, "LED (%s)", on ? "on" : "off"); | 1269 | /* PDEBUG(D_STREAM, "LED (%s)", on ? "on" : "off"); */ |
1280 | 1270 | reg_w_mask(sd, OV519_GPIO_DATA_OUT0, !on, 1); /* 0 / 1 */ | |
1281 | /* if (sd->bridge == BRG_OV511PLUS) */ | ||
1282 | /* reg_w(sd, R511_SYS_LED_CTL, on ? 1 : 0); */ | ||
1283 | /* else if (sd->bridge == BRG_OV519) */ | ||
1284 | reg_w_mask(sd, OV519_GPIO_DATA_OUT0, !on, 1); /* 0 / 1 */ | ||
1285 | /* else if (sd->bclass == BCL_OV518) */ | ||
1286 | /* reg_w_mask(sd, R518_GPIO_OUT, on ? 0x02 : 0x00, 0x02); */ | ||
1287 | } | 1271 | } |
1288 | 1272 | ||
1289 | /* this function is called at probe time */ | 1273 | /* this function is called at probe time */ |
@@ -1293,11 +1277,8 @@ static int sd_config(struct gspca_dev *gspca_dev, | |||
1293 | struct sd *sd = (struct sd *) gspca_dev; | 1277 | struct sd *sd = (struct sd *) gspca_dev; |
1294 | struct cam *cam; | 1278 | struct cam *cam; |
1295 | 1279 | ||
1296 | /* (from ov519_configure) */ | ||
1297 | static const struct ov_regvals init_519[] = { | 1280 | static const struct ov_regvals init_519[] = { |
1298 | { 0x5a, 0x6d }, /* EnableSystem */ | 1281 | { 0x5a, 0x6d }, /* EnableSystem */ |
1299 | /* jfm trace usbsnoop3-1.txt */ | ||
1300 | /* jfm 53 = fb */ | ||
1301 | { 0x53, 0x9b }, | 1282 | { 0x53, 0x9b }, |
1302 | { 0x54, 0xff }, /* set bit2 to enable jpeg */ | 1283 | { 0x54, 0xff }, /* set bit2 to enable jpeg */ |
1303 | { 0x5d, 0x03 }, | 1284 | { 0x5d, 0x03 }, |
@@ -1314,9 +1295,6 @@ static int sd_config(struct gspca_dev *gspca_dev, | |||
1314 | 1295 | ||
1315 | if (write_regvals(sd, init_519, ARRAY_SIZE(init_519))) | 1296 | if (write_regvals(sd, init_519, ARRAY_SIZE(init_519))) |
1316 | goto error; | 1297 | goto error; |
1317 | /* jfm: not seen in windows trace */ | ||
1318 | if (ov519_init_compression(sd)) | ||
1319 | goto error; | ||
1320 | ov51x_led_control(sd, 0); /* turn LED off */ | 1298 | ov51x_led_control(sd, 0); /* turn LED off */ |
1321 | 1299 | ||
1322 | /* Test for 76xx */ | 1300 | /* Test for 76xx */ |
@@ -1365,16 +1343,18 @@ static int sd_config(struct gspca_dev *gspca_dev, | |||
1365 | 1343 | ||
1366 | cam = &gspca_dev->cam; | 1344 | cam = &gspca_dev->cam; |
1367 | cam->epaddr = OV511_ENDPOINT_ADDRESS; | 1345 | cam->epaddr = OV511_ENDPOINT_ADDRESS; |
1368 | if (sd->maxwidth == 640) { | 1346 | if (!sd->sif) { |
1369 | cam->cam_mode = vga_mode; | 1347 | cam->cam_mode = vga_mode; |
1370 | cam->nmodes = sizeof vga_mode / sizeof vga_mode[0]; | 1348 | cam->nmodes = ARRAY_SIZE(vga_mode); |
1371 | } else { | 1349 | } else { |
1372 | cam->cam_mode = sif_mode; | 1350 | cam->cam_mode = sif_mode; |
1373 | cam->nmodes = sizeof sif_mode / sizeof sif_mode[0]; | 1351 | cam->nmodes = ARRAY_SIZE(sif_mode); |
1374 | } | 1352 | } |
1375 | sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value; | 1353 | sd->brightness = BRIGHTNESS_DEF; |
1376 | sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value; | 1354 | sd->contrast = CONTRAST_DEF; |
1377 | sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value; | 1355 | sd->colors = COLOR_DEF; |
1356 | sd->hflip = HFLIP_DEF; | ||
1357 | sd->vflip = VFLIP_DEF; | ||
1378 | return 0; | 1358 | return 0; |
1379 | error: | 1359 | error: |
1380 | PDEBUG(D_ERR, "OV519 Config failed"); | 1360 | PDEBUG(D_ERR, "OV519 Config failed"); |
@@ -1394,8 +1374,7 @@ static int sd_open(struct gspca_dev *gspca_dev) | |||
1394 | * | 1374 | * |
1395 | * Do not put any sensor-specific code in here (including I2C I/O functions) | 1375 | * Do not put any sensor-specific code in here (including I2C I/O functions) |
1396 | */ | 1376 | */ |
1397 | static int ov519_mode_init_regs(struct sd *sd, | 1377 | static int ov519_mode_init_regs(struct sd *sd) |
1398 | int width, int height) | ||
1399 | { | 1378 | { |
1400 | static const struct ov_regvals mode_init_519_ov7670[] = { | 1379 | static const struct ov_regvals mode_init_519_ov7670[] = { |
1401 | { 0x5d, 0x03 }, /* Turn off suspend mode */ | 1380 | { 0x5d, 0x03 }, /* Turn off suspend mode */ |
@@ -1441,36 +1420,23 @@ static int ov519_mode_init_regs(struct sd *sd, | |||
1441 | /* windows reads 0x55 at this point, why? */ | 1420 | /* windows reads 0x55 at this point, why? */ |
1442 | }; | 1421 | }; |
1443 | 1422 | ||
1444 | /* int hi_res; */ | ||
1445 | |||
1446 | PDEBUG(D_CONF, "mode init %dx%d", width, height); | ||
1447 | |||
1448 | /* if (width >= 800 && height >= 600) | ||
1449 | hi_res = 1; | ||
1450 | else | ||
1451 | hi_res = 0; */ | ||
1452 | |||
1453 | /* if (ov51x_stop(sd) < 0) | ||
1454 | return -EIO; */ | ||
1455 | |||
1456 | /******** Set the mode ********/ | 1423 | /******** Set the mode ********/ |
1457 | if (sd->sensor != SEN_OV7670) { | 1424 | if (sd->sensor != SEN_OV7670) { |
1458 | if (write_regvals(sd, mode_init_519, | 1425 | if (write_regvals(sd, mode_init_519, |
1459 | ARRAY_SIZE(mode_init_519))) | 1426 | ARRAY_SIZE(mode_init_519))) |
1460 | return -EIO; | 1427 | return -EIO; |
1428 | if (sd->sensor == SEN_OV7640) { | ||
1429 | /* Select 8-bit input mode */ | ||
1430 | reg_w_mask(sd, OV519_CAM_DFR, 0x10, 0x10); | ||
1431 | } | ||
1461 | } else { | 1432 | } else { |
1462 | if (write_regvals(sd, mode_init_519_ov7670, | 1433 | if (write_regvals(sd, mode_init_519_ov7670, |
1463 | ARRAY_SIZE(mode_init_519_ov7670))) | 1434 | ARRAY_SIZE(mode_init_519_ov7670))) |
1464 | return -EIO; | 1435 | return -EIO; |
1465 | } | 1436 | } |
1466 | 1437 | ||
1467 | if (sd->sensor == SEN_OV7640) { | 1438 | reg_w(sd, OV519_CAM_H_SIZE, sd->gspca_dev.width >> 4); |
1468 | /* Select 8-bit input mode */ | 1439 | reg_w(sd, OV519_CAM_V_SIZE, sd->gspca_dev.height >> 3); |
1469 | reg_w_mask(sd, OV519_CAM_DFR, 0x10, 0x10); | ||
1470 | } | ||
1471 | |||
1472 | reg_w(sd, OV519_CAM_H_SIZE, width >> 4); | ||
1473 | reg_w(sd, OV519_CAM_V_SIZE, height >> 3); | ||
1474 | reg_w(sd, OV519_CAM_X_OFFSETL, 0x00); | 1440 | reg_w(sd, OV519_CAM_X_OFFSETL, 0x00); |
1475 | reg_w(sd, OV519_CAM_X_OFFSETH, 0x00); | 1441 | reg_w(sd, OV519_CAM_X_OFFSETH, 0x00); |
1476 | reg_w(sd, OV519_CAM_Y_OFFSETL, 0x00); | 1442 | reg_w(sd, OV519_CAM_Y_OFFSETL, 0x00); |
@@ -1485,9 +1451,10 @@ static int ov519_mode_init_regs(struct sd *sd, | |||
1485 | 1451 | ||
1486 | /* FIXME: These are only valid at the max resolution. */ | 1452 | /* FIXME: These are only valid at the max resolution. */ |
1487 | sd->clockdiv = 0; | 1453 | sd->clockdiv = 0; |
1488 | if (sd->sensor == SEN_OV7640) { | 1454 | switch (sd->sensor) { |
1455 | case SEN_OV7640: | ||
1489 | switch (sd->frame_rate) { | 1456 | switch (sd->frame_rate) { |
1490 | /*jfm: default was 30 fps */ | 1457 | /*fixme: default was 30 fps */ |
1491 | case 30: | 1458 | case 30: |
1492 | reg_w(sd, 0xa4, 0x0c); | 1459 | reg_w(sd, 0xa4, 0x0c); |
1493 | reg_w(sd, 0x23, 0xff); | 1460 | reg_w(sd, 0x23, 0xff); |
@@ -1517,7 +1484,8 @@ static int ov519_mode_init_regs(struct sd *sd, | |||
1517 | sd->clockdiv = 1; | 1484 | sd->clockdiv = 1; |
1518 | break; | 1485 | break; |
1519 | } | 1486 | } |
1520 | } else if (sd->sensor == SEN_OV8610) { | 1487 | break; |
1488 | case SEN_OV8610: | ||
1521 | switch (sd->frame_rate) { | 1489 | switch (sd->frame_rate) { |
1522 | default: /* 15 fps */ | 1490 | default: /* 15 fps */ |
1523 | /* case 15: */ | 1491 | /* case 15: */ |
@@ -1533,41 +1501,37 @@ static int ov519_mode_init_regs(struct sd *sd, | |||
1533 | reg_w(sd, 0x23, 0x1b); | 1501 | reg_w(sd, 0x23, 0x1b); |
1534 | break; | 1502 | break; |
1535 | } | 1503 | } |
1536 | sd->clockdiv = 0; | 1504 | break; |
1537 | } else if (sd->sensor == SEN_OV7670) { /* guesses, based on 7640 */ | 1505 | case SEN_OV7670: /* guesses, based on 7640 */ |
1538 | PDEBUG(D_STREAM, "Setting framerate to %d fps", | 1506 | PDEBUG(D_STREAM, "Setting framerate to %d fps", |
1539 | (sd->frame_rate == 0) ? 15 : sd->frame_rate); | 1507 | (sd->frame_rate == 0) ? 15 : sd->frame_rate); |
1508 | reg_w(sd, 0xa4, 0x10); | ||
1540 | switch (sd->frame_rate) { | 1509 | switch (sd->frame_rate) { |
1541 | case 30: | 1510 | case 30: |
1542 | reg_w(sd, 0xa4, 0x10); | ||
1543 | reg_w(sd, 0x23, 0xff); | 1511 | reg_w(sd, 0x23, 0xff); |
1544 | break; | 1512 | break; |
1545 | case 20: | 1513 | case 20: |
1546 | reg_w(sd, 0xa4, 0x10); | ||
1547 | reg_w(sd, 0x23, 0x1b); | 1514 | reg_w(sd, 0x23, 0x1b); |
1548 | break; | 1515 | break; |
1549 | default: /* 15 fps */ | 1516 | default: |
1550 | /* case 15: */ | 1517 | /* case 15: */ |
1551 | reg_w(sd, 0xa4, 0x10); | ||
1552 | reg_w(sd, 0x23, 0xff); | 1518 | reg_w(sd, 0x23, 0xff); |
1553 | sd->clockdiv = 1; | 1519 | sd->clockdiv = 1; |
1554 | break; | 1520 | break; |
1555 | } | 1521 | } |
1522 | break; | ||
1556 | } | 1523 | } |
1557 | 1524 | ||
1558 | /* if (ov51x_restart(sd) < 0) | ||
1559 | return -EIO; */ | ||
1560 | |||
1561 | /* Reset it just for good measure */ | ||
1562 | /* if (ov51x_reset(sd, OV511_RESET_NOREGS) < 0) | ||
1563 | return -EIO; */ | ||
1564 | return 0; | 1525 | return 0; |
1565 | } | 1526 | } |
1566 | 1527 | ||
1567 | static int mode_init_ov_sensor_regs(struct sd *sd, | 1528 | static int mode_init_ov_sensor_regs(struct sd *sd) |
1568 | struct ovsensor_window *win) | ||
1569 | { | 1529 | { |
1570 | int qvga = win->quarter; | 1530 | struct gspca_dev *gspca_dev; |
1531 | int qvga; | ||
1532 | |||
1533 | gspca_dev = &sd->gspca_dev; | ||
1534 | qvga = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; | ||
1571 | 1535 | ||
1572 | /******** Mode (VGA/QVGA) and sensor specific regs ********/ | 1536 | /******** Mode (VGA/QVGA) and sensor specific regs ********/ |
1573 | switch (sd->sensor) { | 1537 | switch (sd->sensor) { |
@@ -1611,8 +1575,6 @@ static int mode_init_ov_sensor_regs(struct sd *sd, | |||
1611 | OV7670_COM7_FMT_MASK); | 1575 | OV7670_COM7_FMT_MASK); |
1612 | break; | 1576 | break; |
1613 | case SEN_OV6620: | 1577 | case SEN_OV6620: |
1614 | i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20); | ||
1615 | break; | ||
1616 | case SEN_OV6630: | 1578 | case SEN_OV6630: |
1617 | i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20); | 1579 | i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20); |
1618 | break; | 1580 | break; |
@@ -1621,24 +1583,21 @@ static int mode_init_ov_sensor_regs(struct sd *sd, | |||
1621 | } | 1583 | } |
1622 | 1584 | ||
1623 | /******** Palette-specific regs ********/ | 1585 | /******** Palette-specific regs ********/ |
1624 | /* Need to do work here for the OV7670 */ | 1586 | if (sd->sensor == SEN_OV7610 || sd->sensor == SEN_OV76BE) { |
1625 | 1587 | /* not valid on the OV6620/OV7620/6630? */ | |
1626 | if (sd->sensor == SEN_OV7610 || sd->sensor == SEN_OV76BE) { | 1588 | i2c_w_mask(sd, 0x0e, 0x00, 0x40); |
1627 | /* not valid on the OV6620/OV7620/6630? */ | 1589 | } |
1628 | i2c_w_mask(sd, 0x0e, 0x00, 0x40); | ||
1629 | } | ||
1630 | 1590 | ||
1631 | /* The OV518 needs special treatment. Although both the OV518 | 1591 | /* The OV518 needs special treatment. Although both the OV518 |
1632 | * and the OV6630 support a 16-bit video bus, only the 8 bit Y | 1592 | * and the OV6630 support a 16-bit video bus, only the 8 bit Y |
1633 | * bus is actually used. The UV bus is tied to ground. | 1593 | * bus is actually used. The UV bus is tied to ground. |
1634 | * Therefore, the OV6630 needs to be in 8-bit multiplexed | 1594 | * Therefore, the OV6630 needs to be in 8-bit multiplexed |
1635 | * output mode */ | 1595 | * output mode */ |
1636 | 1596 | ||
1637 | /* OV7640 is 8-bit only */ | 1597 | /* OV7640 is 8-bit only */ |
1638 | 1598 | ||
1639 | if (sd->sensor != SEN_OV6630 && sd->sensor != SEN_OV7640) | 1599 | if (sd->sensor != SEN_OV6630 && sd->sensor != SEN_OV7640) |
1640 | i2c_w_mask(sd, 0x13, 0x00, 0x20); | 1600 | i2c_w_mask(sd, 0x13, 0x00, 0x20); |
1641 | /* } */ | ||
1642 | 1601 | ||
1643 | /******** Clock programming ********/ | 1602 | /******** Clock programming ********/ |
1644 | /* The OV6620 needs special handling. This prevents the | 1603 | /* The OV6620 needs special handling. This prevents the |
@@ -1647,14 +1606,14 @@ static int mode_init_ov_sensor_regs(struct sd *sd, | |||
1647 | 1606 | ||
1648 | /* Clock down */ | 1607 | /* Clock down */ |
1649 | i2c_w(sd, 0x2a, 0x04); | 1608 | i2c_w(sd, 0x2a, 0x04); |
1650 | i2c_w(sd, 0x11, win->clockdiv); | 1609 | i2c_w(sd, 0x11, sd->clockdiv); |
1651 | i2c_w(sd, 0x2a, 0x84); | 1610 | i2c_w(sd, 0x2a, 0x84); |
1652 | /* This next setting is critical. It seems to improve | 1611 | /* This next setting is critical. It seems to improve |
1653 | * the gain or the contrast. The "reserved" bits seem | 1612 | * the gain or the contrast. The "reserved" bits seem |
1654 | * to have some effect in this case. */ | 1613 | * to have some effect in this case. */ |
1655 | i2c_w(sd, 0x2d, 0x85); | 1614 | i2c_w(sd, 0x2d, 0x85); |
1656 | } else if (win->clockdiv >= 0) { | 1615 | } else if (sd->clockdiv >= 0) { |
1657 | i2c_w(sd, 0x11, win->clockdiv); | 1616 | i2c_w(sd, 0x11, sd->clockdiv); |
1658 | } | 1617 | } |
1659 | 1618 | ||
1660 | /******** Special Features ********/ | 1619 | /******** Special Features ********/ |
@@ -1674,7 +1633,7 @@ static int mode_init_ov_sensor_regs(struct sd *sd, | |||
1674 | /* is fully tested. */ | 1633 | /* is fully tested. */ |
1675 | /* 7620/6620/6630? don't have register 0x35, so play it safe */ | 1634 | /* 7620/6620/6630? don't have register 0x35, so play it safe */ |
1676 | if (sd->sensor == SEN_OV7610 || sd->sensor == SEN_OV76BE) { | 1635 | if (sd->sensor == SEN_OV7610 || sd->sensor == SEN_OV76BE) { |
1677 | if (win->width == 640 /*&& win->height == 480*/) | 1636 | if (!qvga) |
1678 | i2c_w(sd, 0x35, 0x9e); | 1637 | i2c_w(sd, 0x35, 0x9e); |
1679 | else | 1638 | else |
1680 | i2c_w(sd, 0x35, 0x1e); | 1639 | i2c_w(sd, 0x35, 0x1e); |
@@ -1682,13 +1641,31 @@ static int mode_init_ov_sensor_regs(struct sd *sd, | |||
1682 | return 0; | 1641 | return 0; |
1683 | } | 1642 | } |
1684 | 1643 | ||
1685 | static int set_ov_sensor_window(struct sd *sd, | 1644 | static void sethvflip(struct sd *sd) |
1686 | struct ovsensor_window *win) | ||
1687 | { | 1645 | { |
1646 | if (sd->sensor != SEN_OV7670) | ||
1647 | return; | ||
1648 | if (sd->gspca_dev.streaming) | ||
1649 | ov51x_stop(sd); | ||
1650 | i2c_w_mask(sd, OV7670_REG_MVFP, | ||
1651 | OV7670_MVFP_MIRROR * sd->hflip | ||
1652 | | OV7670_MVFP_VFLIP * sd->vflip, | ||
1653 | OV7670_MVFP_MIRROR | OV7670_MVFP_VFLIP); | ||
1654 | if (sd->gspca_dev.streaming) | ||
1655 | ov51x_restart(sd); | ||
1656 | } | ||
1657 | |||
1658 | static int set_ov_sensor_window(struct sd *sd) | ||
1659 | { | ||
1660 | struct gspca_dev *gspca_dev; | ||
1661 | int qvga; | ||
1688 | int hwsbase, hwebase, vwsbase, vwebase, hwscale, vwscale; | 1662 | int hwsbase, hwebase, vwsbase, vwebase, hwscale, vwscale; |
1689 | int ret, hstart, hstop, vstop, vstart; | 1663 | int ret, hstart, hstop, vstop, vstart; |
1690 | __u8 v; | 1664 | __u8 v; |
1691 | 1665 | ||
1666 | gspca_dev = &sd->gspca_dev; | ||
1667 | qvga = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; | ||
1668 | |||
1692 | /* The different sensor ICs handle setting up of window differently. | 1669 | /* The different sensor ICs handle setting up of window differently. |
1693 | * IF YOU SET IT WRONG, YOU WILL GET ALL ZERO ISOC DATA FROM OV51x!! */ | 1670 | * IF YOU SET IT WRONG, YOU WILL GET ALL ZERO ISOC DATA FROM OV51x!! */ |
1694 | switch (sd->sensor) { | 1671 | switch (sd->sensor) { |
@@ -1733,7 +1710,7 @@ static int set_ov_sensor_window(struct sd *sd, | |||
1733 | switch (sd->sensor) { | 1710 | switch (sd->sensor) { |
1734 | case SEN_OV6620: | 1711 | case SEN_OV6620: |
1735 | case SEN_OV6630: | 1712 | case SEN_OV6630: |
1736 | if (win->quarter) { /* QCIF */ | 1713 | if (qvga) { /* QCIF */ |
1737 | hwscale = 0; | 1714 | hwscale = 0; |
1738 | vwscale = 0; | 1715 | vwscale = 0; |
1739 | } else { /* CIF */ | 1716 | } else { /* CIF */ |
@@ -1743,7 +1720,7 @@ static int set_ov_sensor_window(struct sd *sd, | |||
1743 | } | 1720 | } |
1744 | break; | 1721 | break; |
1745 | case SEN_OV8610: | 1722 | case SEN_OV8610: |
1746 | if (win->quarter) { /* QSVGA */ | 1723 | if (qvga) { /* QSVGA */ |
1747 | hwscale = 1; | 1724 | hwscale = 1; |
1748 | vwscale = 1; | 1725 | vwscale = 1; |
1749 | } else { /* SVGA */ | 1726 | } else { /* SVGA */ |
@@ -1752,7 +1729,7 @@ static int set_ov_sensor_window(struct sd *sd, | |||
1752 | } | 1729 | } |
1753 | break; | 1730 | break; |
1754 | default: /* SEN_OV7xx0 */ | 1731 | default: /* SEN_OV7xx0 */ |
1755 | if (win->quarter) { /* QVGA */ | 1732 | if (qvga) { /* QVGA */ |
1756 | hwscale = 1; | 1733 | hwscale = 1; |
1757 | vwscale = 0; | 1734 | vwscale = 0; |
1758 | } else { /* VGA */ | 1735 | } else { /* VGA */ |
@@ -1761,7 +1738,7 @@ static int set_ov_sensor_window(struct sd *sd, | |||
1761 | } | 1738 | } |
1762 | } | 1739 | } |
1763 | 1740 | ||
1764 | ret = mode_init_ov_sensor_regs(sd, win); | 1741 | ret = mode_init_ov_sensor_regs(sd); |
1765 | if (ret < 0) | 1742 | if (ret < 0) |
1766 | return ret; | 1743 | return ret; |
1767 | 1744 | ||
@@ -1782,7 +1759,7 @@ static int set_ov_sensor_window(struct sd *sd, | |||
1782 | /* I can hard code this for OV7670s */ | 1759 | /* I can hard code this for OV7670s */ |
1783 | /* Yes, these numbers do look odd, but they're tested and work! */ | 1760 | /* Yes, these numbers do look odd, but they're tested and work! */ |
1784 | if (sd->sensor == SEN_OV7670) { | 1761 | if (sd->sensor == SEN_OV7670) { |
1785 | if (win->quarter) { /* QVGA from ov7670.c by | 1762 | if (qvga) { /* QVGA from ov7670.c by |
1786 | * Jonathan Corbet */ | 1763 | * Jonathan Corbet */ |
1787 | hstart = 164; | 1764 | hstart = 164; |
1788 | hstop = 20; | 1765 | hstop = 20; |
@@ -1796,75 +1773,45 @@ static int set_ov_sensor_window(struct sd *sd, | |||
1796 | } | 1773 | } |
1797 | /* OV7670 hardware window registers are split across | 1774 | /* OV7670 hardware window registers are split across |
1798 | * multiple locations */ | 1775 | * multiple locations */ |
1799 | i2c_w(sd, OV7670_REG_HSTART, (hstart >> 3) & 0xff); | 1776 | i2c_w(sd, OV7670_REG_HSTART, hstart >> 3); |
1800 | i2c_w(sd, OV7670_REG_HSTOP, (hstop >> 3) & 0xff); | 1777 | i2c_w(sd, OV7670_REG_HSTOP, hstop >> 3); |
1801 | v = i2c_r(sd, OV7670_REG_HREF); | 1778 | v = i2c_r(sd, OV7670_REG_HREF); |
1802 | v = (v & 0xc0) | ((hstop & 0x7) << 3) | (hstart & 0x07); | 1779 | v = (v & 0xc0) | ((hstop & 0x7) << 3) | (hstart & 0x07); |
1803 | msleep(10); /* need to sleep between read and write to | 1780 | msleep(10); /* need to sleep between read and write to |
1804 | * same reg! */ | 1781 | * same reg! */ |
1805 | i2c_w(sd, OV7670_REG_HREF, v); | 1782 | i2c_w(sd, OV7670_REG_HREF, v); |
1806 | 1783 | ||
1807 | i2c_w(sd, OV7670_REG_VSTART, (vstart >> 2) & 0xff); | 1784 | i2c_w(sd, OV7670_REG_VSTART, vstart >> 2); |
1808 | i2c_w(sd, OV7670_REG_VSTOP, (vstop >> 2) & 0xff); | 1785 | i2c_w(sd, OV7670_REG_VSTOP, vstop >> 2); |
1809 | v = i2c_r(sd, OV7670_REG_VREF); | 1786 | v = i2c_r(sd, OV7670_REG_VREF); |
1810 | v = (v & 0xc0) | ((vstop & 0x3) << 2) | (vstart & 0x03); | 1787 | v = (v & 0xc0) | ((vstop & 0x3) << 2) | (vstart & 0x03); |
1811 | msleep(10); /* need to sleep between read and write to | 1788 | msleep(10); /* need to sleep between read and write to |
1812 | * same reg! */ | 1789 | * same reg! */ |
1813 | i2c_w(sd, OV7670_REG_VREF, v); | 1790 | i2c_w(sd, OV7670_REG_VREF, v); |
1814 | 1791 | sethvflip(sd); | |
1815 | } else { | 1792 | } else { |
1816 | i2c_w(sd, 0x17, hwsbase + (win->x >> hwscale)); | 1793 | i2c_w(sd, 0x17, hwsbase); |
1817 | i2c_w(sd, 0x18, hwebase + ((win->x + win->width) >> hwscale)); | 1794 | i2c_w(sd, 0x18, hwebase + (sd->gspca_dev.width >> hwscale)); |
1818 | i2c_w(sd, 0x19, vwsbase + (win->y >> vwscale)); | 1795 | i2c_w(sd, 0x19, vwsbase); |
1819 | i2c_w(sd, 0x1a, vwebase + ((win->y + win->height) >> vwscale)); | 1796 | i2c_w(sd, 0x1a, vwebase + (sd->gspca_dev.height >> vwscale)); |
1820 | } | 1797 | } |
1821 | return 0; | 1798 | return 0; |
1822 | } | 1799 | } |
1823 | 1800 | ||
1824 | static int ov_sensor_mode_setup(struct sd *sd, | ||
1825 | int width, int height) | ||
1826 | { | ||
1827 | struct ovsensor_window win; | ||
1828 | |||
1829 | /* win.format = mode; */ | ||
1830 | |||
1831 | /* Unless subcapture is enabled, | ||
1832 | * center the image window and downsample | ||
1833 | * if possible to increase the field of view */ | ||
1834 | /* NOTE: OV518(+) and OV519 does downsampling on its own */ | ||
1835 | win.width = width; | ||
1836 | win.height = height; | ||
1837 | if (width == sd->maxwidth) | ||
1838 | win.quarter = 0; | ||
1839 | else | ||
1840 | win.quarter = 1; | ||
1841 | |||
1842 | /* Center it */ | ||
1843 | win.x = (win.width - width) / 2; | ||
1844 | win.y = (win.height - height) / 2; | ||
1845 | |||
1846 | /* Clock is determined by OV519 frame rate code */ | ||
1847 | win.clockdiv = sd->clockdiv; | ||
1848 | |||
1849 | PDEBUG(D_CONF, "Setting clock divider to %d", win.clockdiv); | ||
1850 | return set_ov_sensor_window(sd, &win); | ||
1851 | } | ||
1852 | |||
1853 | /* -- start the camera -- */ | 1801 | /* -- start the camera -- */ |
1854 | static void sd_start(struct gspca_dev *gspca_dev) | 1802 | static void sd_start(struct gspca_dev *gspca_dev) |
1855 | { | 1803 | { |
1856 | struct sd *sd = (struct sd *) gspca_dev; | 1804 | struct sd *sd = (struct sd *) gspca_dev; |
1857 | int ret; | 1805 | int ret; |
1858 | 1806 | ||
1859 | 1807 | ret = ov519_mode_init_regs(sd); | |
1860 | ret = ov519_mode_init_regs(sd, gspca_dev->width, gspca_dev->height); | ||
1861 | if (ret < 0) | 1808 | if (ret < 0) |
1862 | goto out; | 1809 | goto out; |
1863 | ret = ov_sensor_mode_setup(sd, gspca_dev->width, gspca_dev->height); | 1810 | ret = set_ov_sensor_window(sd); |
1864 | if (ret < 0) | 1811 | if (ret < 0) |
1865 | goto out; | 1812 | goto out; |
1866 | 1813 | ||
1867 | ret = ov51x_restart((struct sd *) gspca_dev); | 1814 | ret = ov51x_restart(sd); |
1868 | if (ret < 0) | 1815 | if (ret < 0) |
1869 | goto out; | 1816 | goto out; |
1870 | PDEBUG(D_STREAM, "camera started alt: 0x%02x", gspca_dev->alt); | 1817 | PDEBUG(D_STREAM, "camera started alt: 0x%02x", gspca_dev->alt); |
@@ -1938,12 +1885,10 @@ static void setbrightness(struct gspca_dev *gspca_dev) | |||
1938 | { | 1885 | { |
1939 | struct sd *sd = (struct sd *) gspca_dev; | 1886 | struct sd *sd = (struct sd *) gspca_dev; |
1940 | int val; | 1887 | int val; |
1941 | /* int was_streaming; */ | ||
1942 | 1888 | ||
1943 | val = sd->brightness; | 1889 | val = sd->brightness; |
1944 | PDEBUG(D_CONF, "brightness:%d", val); | 1890 | PDEBUG(D_CONF, "brightness:%d", val); |
1945 | /* was_streaming = gspca_dev->streaming; | 1891 | /* if (gspca_dev->streaming) |
1946 | * if (was_streaming) | ||
1947 | * ov51x_stop(sd); */ | 1892 | * ov51x_stop(sd); */ |
1948 | switch (sd->sensor) { | 1893 | switch (sd->sensor) { |
1949 | case SEN_OV8610: | 1894 | case SEN_OV8610: |
@@ -1961,12 +1906,12 @@ static void setbrightness(struct gspca_dev *gspca_dev) | |||
1961 | i2c_w(sd, OV7610_REG_BRT, val); | 1906 | i2c_w(sd, OV7610_REG_BRT, val); |
1962 | break; | 1907 | break; |
1963 | case SEN_OV7670: | 1908 | case SEN_OV7670: |
1964 | /*jfm - from windblows | 1909 | /*win trace |
1965 | * i2c_w_mask(sd, OV7670_REG_COM8, 0, OV7670_COM8_AEC); */ | 1910 | * i2c_w_mask(sd, OV7670_REG_COM8, 0, OV7670_COM8_AEC); */ |
1966 | i2c_w(sd, OV7670_REG_BRIGHT, ov7670_abs_to_sm(val)); | 1911 | i2c_w(sd, OV7670_REG_BRIGHT, ov7670_abs_to_sm(val)); |
1967 | break; | 1912 | break; |
1968 | } | 1913 | } |
1969 | /* if (was_streaming) | 1914 | /* if (gspca_dev->streaming) |
1970 | * ov51x_restart(sd); */ | 1915 | * ov51x_restart(sd); */ |
1971 | } | 1916 | } |
1972 | 1917 | ||
@@ -1974,12 +1919,10 @@ static void setcontrast(struct gspca_dev *gspca_dev) | |||
1974 | { | 1919 | { |
1975 | struct sd *sd = (struct sd *) gspca_dev; | 1920 | struct sd *sd = (struct sd *) gspca_dev; |
1976 | int val; | 1921 | int val; |
1977 | /* int was_streaming; */ | ||
1978 | 1922 | ||
1979 | val = sd->contrast; | 1923 | val = sd->contrast; |
1980 | PDEBUG(D_CONF, "contrast:%d", val); | 1924 | PDEBUG(D_CONF, "contrast:%d", val); |
1981 | /* was_streaming = gspca_dev->streaming; | 1925 | /* if (gspca_dev->streaming) |
1982 | if (was_streaming) | ||
1983 | ov51x_stop(sd); */ | 1926 | ov51x_stop(sd); */ |
1984 | switch (sd->sensor) { | 1927 | switch (sd->sensor) { |
1985 | case SEN_OV7610: | 1928 | case SEN_OV7610: |
@@ -2016,7 +1959,7 @@ static void setcontrast(struct gspca_dev *gspca_dev) | |||
2016 | i2c_w(sd, OV7670_REG_CONTRAS, val >> 1); | 1959 | i2c_w(sd, OV7670_REG_CONTRAS, val >> 1); |
2017 | break; | 1960 | break; |
2018 | } | 1961 | } |
2019 | /* if (was_streaming) | 1962 | /* if (gspca_dev->streaming) |
2020 | ov51x_restart(sd); */ | 1963 | ov51x_restart(sd); */ |
2021 | } | 1964 | } |
2022 | 1965 | ||
@@ -2024,12 +1967,10 @@ static void setcolors(struct gspca_dev *gspca_dev) | |||
2024 | { | 1967 | { |
2025 | struct sd *sd = (struct sd *) gspca_dev; | 1968 | struct sd *sd = (struct sd *) gspca_dev; |
2026 | int val; | 1969 | int val; |
2027 | /* int was_streaming; */ | ||
2028 | 1970 | ||
2029 | val = sd->colors; | 1971 | val = sd->colors; |
2030 | PDEBUG(D_CONF, "saturation:%d", val); | 1972 | PDEBUG(D_CONF, "saturation:%d", val); |
2031 | /* was_streaming = gspca_dev->streaming; | 1973 | /* if (gspca_dev->streaming) |
2032 | if (was_streaming) | ||
2033 | ov51x_stop(sd); */ | 1974 | ov51x_stop(sd); */ |
2034 | switch (sd->sensor) { | 1975 | switch (sd->sensor) { |
2035 | case SEN_OV8610: | 1976 | case SEN_OV8610: |
@@ -2055,7 +1996,7 @@ static void setcolors(struct gspca_dev *gspca_dev) | |||
2055 | /* set REG_COM13 values for UV sat auto mode */ | 1996 | /* set REG_COM13 values for UV sat auto mode */ |
2056 | break; | 1997 | break; |
2057 | } | 1998 | } |
2058 | /* if (was_streaming) | 1999 | /* if (gspca_dev->streaming) |
2059 | ov51x_restart(sd); */ | 2000 | ov51x_restart(sd); */ |
2060 | } | 2001 | } |
2061 | 2002 | ||
@@ -2110,6 +2051,40 @@ static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) | |||
2110 | return 0; | 2051 | return 0; |
2111 | } | 2052 | } |
2112 | 2053 | ||
2054 | static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val) | ||
2055 | { | ||
2056 | struct sd *sd = (struct sd *) gspca_dev; | ||
2057 | |||
2058 | sd->hflip = val; | ||
2059 | sethvflip(sd); | ||
2060 | return 0; | ||
2061 | } | ||
2062 | |||
2063 | static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val) | ||
2064 | { | ||
2065 | struct sd *sd = (struct sd *) gspca_dev; | ||
2066 | |||
2067 | *val = sd->hflip; | ||
2068 | return 0; | ||
2069 | } | ||
2070 | |||
2071 | static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val) | ||
2072 | { | ||
2073 | struct sd *sd = (struct sd *) gspca_dev; | ||
2074 | |||
2075 | sd->vflip = val; | ||
2076 | sethvflip(sd); | ||
2077 | return 0; | ||
2078 | } | ||
2079 | |||
2080 | static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val) | ||
2081 | { | ||
2082 | struct sd *sd = (struct sd *) gspca_dev; | ||
2083 | |||
2084 | *val = sd->vflip; | ||
2085 | return 0; | ||
2086 | } | ||
2087 | |||
2113 | /* sub-driver description */ | 2088 | /* sub-driver description */ |
2114 | static const struct sd_desc sd_desc = { | 2089 | static const struct sd_desc sd_desc = { |
2115 | .name = MODULE_NAME, | 2090 | .name = MODULE_NAME, |
@@ -2178,4 +2153,3 @@ module_exit(sd_mod_exit); | |||
2178 | 2153 | ||
2179 | module_param(frame_rate, int, 0644); | 2154 | module_param(frame_rate, int, 0644); |
2180 | MODULE_PARM_DESC(frame_rate, "Frame rate (5, 10, 15, 20 or 30 fps)"); | 2155 | MODULE_PARM_DESC(frame_rate, "Frame rate (5, 10, 15, 20 or 30 fps)"); |
2181 | |||
diff --git a/drivers/media/video/gspca/pac7311.c b/drivers/media/video/gspca/pac7311.c index ea3d7021f401..815bea6edc44 100644 --- a/drivers/media/video/gspca/pac7311.c +++ b/drivers/media/video/gspca/pac7311.c | |||
@@ -31,7 +31,9 @@ MODULE_LICENSE("GPL"); | |||
31 | struct sd { | 31 | struct sd { |
32 | struct gspca_dev gspca_dev; /* !! must be the first item */ | 32 | struct gspca_dev gspca_dev; /* !! must be the first item */ |
33 | 33 | ||
34 | int avg_lum; | 34 | int lum_sum; |
35 | atomic_t avg_lum; | ||
36 | atomic_t do_gain; | ||
35 | 37 | ||
36 | unsigned char brightness; | 38 | unsigned char brightness; |
37 | unsigned char contrast; | 39 | unsigned char contrast; |
@@ -271,6 +273,7 @@ static int sd_config(struct gspca_dev *gspca_dev, | |||
271 | sd->contrast = CONTRAST_DEF; | 273 | sd->contrast = CONTRAST_DEF; |
272 | sd->colors = COLOR_DEF; | 274 | sd->colors = COLOR_DEF; |
273 | sd->autogain = AUTOGAIN_DEF; | 275 | sd->autogain = AUTOGAIN_DEF; |
276 | sd->ag_cnt = -1; | ||
274 | return 0; | 277 | return 0; |
275 | } | 278 | } |
276 | 279 | ||
@@ -311,6 +314,18 @@ static void setcolors(struct gspca_dev *gspca_dev) | |||
311 | PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors); | 314 | PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors); |
312 | } | 315 | } |
313 | 316 | ||
317 | static void setautogain(struct gspca_dev *gspca_dev) | ||
318 | { | ||
319 | struct sd *sd = (struct sd *) gspca_dev; | ||
320 | |||
321 | if (sd->autogain) { | ||
322 | sd->lum_sum = 0; | ||
323 | sd->ag_cnt = AG_CNT_START; | ||
324 | } else { | ||
325 | sd->ag_cnt = -1; | ||
326 | } | ||
327 | } | ||
328 | |||
314 | /* this function is called at open time */ | 329 | /* this function is called at open time */ |
315 | static int sd_open(struct gspca_dev *gspca_dev) | 330 | static int sd_open(struct gspca_dev *gspca_dev) |
316 | { | 331 | { |
@@ -320,8 +335,6 @@ static int sd_open(struct gspca_dev *gspca_dev) | |||
320 | 335 | ||
321 | static void sd_start(struct gspca_dev *gspca_dev) | 336 | static void sd_start(struct gspca_dev *gspca_dev) |
322 | { | 337 | { |
323 | struct sd *sd = (struct sd *) gspca_dev; | ||
324 | |||
325 | reg_w(gspca_dev, 0xff, 0x01); | 338 | reg_w(gspca_dev, 0xff, 0x01); |
326 | reg_w_buf(gspca_dev, 0x0002, "\x48\x0a\x40\x08\x00\x00\x08\x00", 8); | 339 | reg_w_buf(gspca_dev, 0x0002, "\x48\x0a\x40\x08\x00\x00\x08\x00", 8); |
327 | reg_w_buf(gspca_dev, 0x000a, "\x06\xff\x11\xff\x5a\x30\x90\x4c", 8); | 340 | reg_w_buf(gspca_dev, 0x000a, "\x06\xff\x11\xff\x5a\x30\x90\x4c", 8); |
@@ -394,6 +407,7 @@ static void sd_start(struct gspca_dev *gspca_dev) | |||
394 | setcontrast(gspca_dev); | 407 | setcontrast(gspca_dev); |
395 | setbrightness(gspca_dev); | 408 | setbrightness(gspca_dev); |
396 | setcolors(gspca_dev); | 409 | setcolors(gspca_dev); |
410 | setautogain(gspca_dev); | ||
397 | 411 | ||
398 | /* set correct resolution */ | 412 | /* set correct resolution */ |
399 | switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) { | 413 | switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) { |
@@ -431,13 +445,6 @@ static void sd_start(struct gspca_dev *gspca_dev) | |||
431 | reg_w(gspca_dev, 0xff, 0x01); | 445 | reg_w(gspca_dev, 0xff, 0x01); |
432 | reg_w(gspca_dev, 0x78, 0x04); | 446 | reg_w(gspca_dev, 0x78, 0x04); |
433 | reg_w(gspca_dev, 0x78, 0x05); | 447 | reg_w(gspca_dev, 0x78, 0x05); |
434 | |||
435 | if (sd->autogain) { | ||
436 | sd->ag_cnt = AG_CNT_START; | ||
437 | sd->avg_lum = 0; | ||
438 | } else { | ||
439 | sd->ag_cnt = -1; | ||
440 | } | ||
441 | } | 448 | } |
442 | 449 | ||
443 | static void sd_stopN(struct gspca_dev *gspca_dev) | 450 | static void sd_stopN(struct gspca_dev *gspca_dev) |
@@ -473,13 +480,20 @@ static void sd_close(struct gspca_dev *gspca_dev) | |||
473 | reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */ | 480 | reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */ |
474 | } | 481 | } |
475 | 482 | ||
476 | static void setautogain(struct gspca_dev *gspca_dev, int luma) | 483 | static void do_autogain(struct gspca_dev *gspca_dev) |
477 | { | 484 | { |
485 | struct sd *sd = (struct sd *) gspca_dev; | ||
486 | int luma; | ||
478 | int luma_mean = 128; | 487 | int luma_mean = 128; |
479 | int luma_delta = 20; | 488 | int luma_delta = 20; |
480 | __u8 spring = 5; | 489 | __u8 spring = 5; |
481 | int Gbright; | 490 | int Gbright; |
482 | 491 | ||
492 | if (!atomic_read(&sd->do_gain)) | ||
493 | return; | ||
494 | atomic_set(&sd->do_gain, 0); | ||
495 | |||
496 | luma = atomic_read(&sd->avg_lum); | ||
483 | Gbright = reg_r(gspca_dev, 0x02); | 497 | Gbright = reg_r(gspca_dev, 0x02); |
484 | PDEBUG(D_FRAM, "luma mean %d", luma); | 498 | PDEBUG(D_FRAM, "luma mean %d", luma); |
485 | if (luma < luma_mean - luma_delta || | 499 | if (luma < luma_mean - luma_delta || |
@@ -523,12 +537,13 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, | |||
523 | 537 | ||
524 | /* start of frame */ | 538 | /* start of frame */ |
525 | if (sd->ag_cnt >= 0 && p > 28) { | 539 | if (sd->ag_cnt >= 0 && p > 28) { |
526 | sd->avg_lum += data[p - 23]; | 540 | sd->lum_sum += data[p - 23]; |
527 | if (--sd->ag_cnt < 0) { | 541 | if (--sd->ag_cnt < 0) { |
528 | sd->ag_cnt = AG_CNT_START; | 542 | sd->ag_cnt = AG_CNT_START; |
529 | setautogain(gspca_dev, | 543 | atomic_set(&sd->avg_lum, |
530 | sd->avg_lum / AG_CNT_START); | 544 | sd->lum_sum / AG_CNT_START); |
531 | sd->avg_lum = 0; | 545 | sd->lum_sum = 0; |
546 | atomic_set(&sd->do_gain, 1); | ||
532 | } | 547 | } |
533 | } | 548 | } |
534 | 549 | ||
@@ -677,12 +692,8 @@ static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) | |||
677 | struct sd *sd = (struct sd *) gspca_dev; | 692 | struct sd *sd = (struct sd *) gspca_dev; |
678 | 693 | ||
679 | sd->autogain = val; | 694 | sd->autogain = val; |
680 | if (val) { | 695 | if (gspca_dev->streaming) |
681 | sd->ag_cnt = AG_CNT_START; | 696 | setautogain(gspca_dev); |
682 | sd->avg_lum = 0; | ||
683 | } else { | ||
684 | sd->ag_cnt = -1; | ||
685 | } | ||
686 | return 0; | 697 | return 0; |
687 | } | 698 | } |
688 | 699 | ||
@@ -706,6 +717,7 @@ static struct sd_desc sd_desc = { | |||
706 | .stop0 = sd_stop0, | 717 | .stop0 = sd_stop0, |
707 | .close = sd_close, | 718 | .close = sd_close, |
708 | .pkt_scan = sd_pkt_scan, | 719 | .pkt_scan = sd_pkt_scan, |
720 | .dq_callback = do_autogain, | ||
709 | }; | 721 | }; |
710 | 722 | ||
711 | /* -- module initialisation -- */ | 723 | /* -- module initialisation -- */ |
diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c index e18748c5a14d..11210c71f66c 100644 --- a/drivers/media/video/gspca/sonixb.c +++ b/drivers/media/video/gspca/sonixb.c | |||
@@ -408,7 +408,7 @@ static void reg_w(struct gspca_dev *gspca_dev, | |||
408 | const __u8 *buffer, | 408 | const __u8 *buffer, |
409 | int len) | 409 | int len) |
410 | { | 410 | { |
411 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 411 | #ifdef GSPCA_DEBUG |
412 | if (len > sizeof gspca_dev->usb_buf) { | 412 | if (len > sizeof gspca_dev->usb_buf) { |
413 | PDEBUG(D_ERR|D_PACK, "reg_w: buffer overflow"); | 413 | PDEBUG(D_ERR|D_PACK, "reg_w: buffer overflow"); |
414 | return; | 414 | return; |
diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c index 33a3df1f6915..245a30ec5fb1 100644 --- a/drivers/media/video/gspca/sonixj.c +++ b/drivers/media/video/gspca/sonixj.c | |||
@@ -32,7 +32,7 @@ MODULE_LICENSE("GPL"); | |||
32 | struct sd { | 32 | struct sd { |
33 | struct gspca_dev gspca_dev; /* !! must be the first item */ | 33 | struct gspca_dev gspca_dev; /* !! must be the first item */ |
34 | 34 | ||
35 | int avg_lum; | 35 | atomic_t avg_lum; |
36 | unsigned int exposure; | 36 | unsigned int exposure; |
37 | 37 | ||
38 | unsigned short brightness; | 38 | unsigned short brightness; |
@@ -148,55 +148,58 @@ static struct v4l2_pix_format vga_mode[] = { | |||
148 | 148 | ||
149 | /*Data from sn9c102p+hv71331r */ | 149 | /*Data from sn9c102p+hv71331r */ |
150 | static const __u8 sn_hv7131[] = { | 150 | static const __u8 sn_hv7131[] = { |
151 | /* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 reg9 */ | 151 | /* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ |
152 | 0x00, 0x03, 0x64, 0x00, 0x1A, 0x20, 0x20, 0x20, 0xA1, 0x11, | 152 | 0x00, 0x03, 0x64, 0x00, 0x1a, 0x20, 0x20, 0x20, |
153 | /* rega regb regc regd rege regf reg10 reg11 */ | 153 | /* reg8 reg9 rega regb regc regd rege regf */ |
154 | 0x02, 0x09, 0x00, 0x00, 0x00, 0x10, 0x03, 0x00, /* 00 */ | 154 | 0xa1, 0x11, 0x02, 0x09, 0x00, 0x00, 0x00, 0x10, |
155 | /* reg12 reg13 reg14 reg15 reg16 reg17 reg18 reg19 reg1a reg1b */ | 155 | /* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ |
156 | 0x00, 0x01, 0x03, 0x28, 0x1e, 0x41, 0x0a, 0x00, 0x00, 0x00, | 156 | 0x03, 0x00, 0x00, 0x01, 0x03, 0x28, 0x1e, 0x41, |
157 | /* reg1c reg1d reg1e reg1f reg20 reg21 reg22 reg23 */ | 157 | /* reg18 reg19 reg1a reg1b reg1c reg1d reg1e reg1f */ |
158 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 | 158 | 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 |
159 | }; | 159 | }; |
160 | 160 | ||
161 | static const __u8 sn_mi0360[] = { | 161 | static const __u8 sn_mi0360[] = { |
162 | /* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 reg9 */ | 162 | /* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ |
163 | 0x00, 0x61, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20, 0xb1, 0x5d, | 163 | 0x00, 0x61, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20, |
164 | /* rega regb regc regd rege regf reg10 reg11 */ | 164 | /* reg8 reg9 rega regb regc regd rege regf */ |
165 | 0x07, 0x00, 0x00, 0x00, 0x00, 0x10, 0x03, 0x00, | 165 | 0xb1, 0x5d, 0x07, 0x00, 0x00, 0x00, 0x00, 0x10, |
166 | /* reg12 reg13 reg14 reg15 reg16 reg17 reg18 reg19 reg1a reg1b */ | 166 | /* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ |
167 | 0x00, 0x02, 0x0a, 0x28, 0x1e, 0x61, 0x06, 0x00, 0x00, 0x00, | 167 | 0x03, 0x00, 0x00, 0x02, 0x0a, 0x28, 0x1e, 0x61, |
168 | /* reg1c reg1d reg1e reg1f reg20 reg21 reg22 reg23 */ | 168 | /* reg18 reg19 reg1a reg1b reg1c reg1d reg1e reg1f */ |
169 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 | 169 | 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 |
170 | }; | 170 | }; |
171 | 171 | ||
172 | static const __u8 sn_mo4000[] = { | 172 | static const __u8 sn_mo4000[] = { |
173 | /* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 */ | 173 | /* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ |
174 | 0x12, 0x23, 0x60, 0x00, 0x1A, 0x00, 0x20, 0x18, 0x81, | 174 | 0x12, 0x23, 0x60, 0x00, 0x1a, 0x00, 0x20, 0x18, |
175 | /* reg9 rega regb regc regd rege regf reg10 reg11*/ | 175 | /* reg8 reg9 rega regb regc regd rege regf */ |
176 | 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, | 176 | 0x81, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
177 | /* reg12 reg13 reg14 reg15 reg16 reg17 reg18 reg19 reg1a*/ | 177 | /* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ |
178 | 0x0b, 0x0f, 0x14, 0x28, 0x1e, 0x40, 0x08, 0x00, 0x00, | 178 | 0x03, 0x00, 0x0b, 0x0f, 0x14, 0x28, 0x1e, 0x40, |
179 | /* reg1b reg1c reg1d reg1e reg1f reg20 reg21 reg22 reg23*/ | 179 | /* reg18 reg19 reg1a reg1b reg1c reg1d reg1e reg1f */ |
180 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x25, 0x39, 0x4b, | 180 | 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 |
181 | 0x5c, 0x6b, 0x79, 0x87, 0x95, 0xa2, 0xaf, 0xbb, 0xc7, | ||
182 | 0xd3, 0xdf, 0xea, 0xf5 | ||
183 | }; | 181 | }; |
184 | 182 | ||
185 | static const __u8 sn_ov7648[] = { | 183 | static const __u8 sn_ov7648[] = { |
186 | 0x00, 0x21, 0x62, 0x00, 0x1a, 0x20, 0x20, 0x20, 0xA1, 0x6E, 0x18, 0x65, | 184 | /* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ |
187 | 0x00, 0x00, 0x00, 0x10, 0x03, 0x00, 0x00, 0x06, 0x06, 0x28, 0x1E, 0x82, | 185 | 0x00, 0x21, 0x62, 0x00, 0x1a, 0x20, 0x20, 0x20, |
188 | 0x07, 0x00, 0x00, 0x00, 0x00, 0x00 | 186 | /* reg8 reg9 rega regb regc regd rege regf */ |
187 | 0xa1, 0x6e, 0x18, 0x65, 0x00, 0x00, 0x00, 0x10, | ||
188 | /* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ | ||
189 | 0x03, 0x00, 0x00, 0x06, 0x06, 0x28, 0x1e, 0x82, | ||
190 | /* reg18 reg19 reg1a reg1b reg1c reg1d reg1e reg1f */ | ||
191 | 0x07, 0x00, 0x00, 0x00, 0x00, 0x00 | ||
189 | }; | 192 | }; |
190 | 193 | ||
191 | static const __u8 sn_ov7660[] = { | 194 | static const __u8 sn_ov7660[] = { |
192 | /* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 */ | 195 | /* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ |
193 | 0x00, 0x61, 0x40, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x81, | 196 | 0x00, 0x61, 0x40, 0x00, 0x1a, 0x20, 0x20, 0x20, |
194 | /* reg9 rega regb regc regd rege regf reg10 reg11*/ | 197 | /* reg8 reg9 rega regb regc regd rege regf */ |
195 | 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, | 198 | 0x81, 0x21, 0x07, 0x00, 0x00, 0x00, 0x00, 0x10, |
196 | /* reg12 reg13 reg14 reg15 reg16 reg17 reg18 reg19 reg1a*/ | 199 | /* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ |
197 | 0x01, 0x01, 0x14, 0x28, 0x1e, 0x00, 0x07, 0x00, 0x00, | 200 | 0x03, 0x00, 0x01, 0x01, 0x08, 0x28, 0x1e, 0x20, |
198 | /* reg1b reg1c reg1d reg1e reg1f reg20 reg21 reg22 reg23*/ | 201 | /* reg18 reg19 reg1a reg1b reg1c reg1d reg1e reg1f */ |
199 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 | 202 | 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
200 | }; | 203 | }; |
201 | 204 | ||
202 | /* sequence specific to the sensors - !! index = SENSOR_xxx */ | 205 | /* sequence specific to the sensors - !! index = SENSOR_xxx */ |
@@ -212,10 +215,6 @@ static const __u8 regsn20[] = { | |||
212 | 0x00, 0x2d, 0x46, 0x5a, 0x6c, 0x7c, 0x8b, 0x99, | 215 | 0x00, 0x2d, 0x46, 0x5a, 0x6c, 0x7c, 0x8b, 0x99, |
213 | 0xa6, 0xb2, 0xbf, 0xca, 0xd5, 0xe0, 0xeb, 0xf5, 0xff | 216 | 0xa6, 0xb2, 0xbf, 0xca, 0xd5, 0xe0, 0xeb, 0xf5, 0xff |
214 | }; | 217 | }; |
215 | static const __u8 regsn20_sn9c120[] = { | ||
216 | 0x00, 0x25, 0x3c, 0x50, 0x62, 0x72, 0x81, 0x90, | ||
217 | 0x9e, 0xab, 0xb8, 0xc5, 0xd1, 0xdd, 0xe9, 0xf4, 0xff | ||
218 | }; | ||
219 | static const __u8 regsn20_sn9c325[] = { | 218 | static const __u8 regsn20_sn9c325[] = { |
220 | 0x0a, 0x3a, 0x56, 0x6c, 0x7e, 0x8d, 0x9a, 0xa4, | 219 | 0x0a, 0x3a, 0x56, 0x6c, 0x7e, 0x8d, 0x9a, 0xa4, |
221 | 0xaf, 0xbb, 0xc5, 0xcd, 0xd5, 0xde, 0xe8, 0xed, 0xf5 | 220 | 0xaf, 0xbb, 0xc5, 0xcd, 0xd5, 0xde, 0xe8, 0xed, 0xf5 |
@@ -227,21 +226,6 @@ static const __u8 reg84[] = { | |||
227 | /* 0x00, 0x00, 0x00, 0x00, 0x00 */ | 226 | /* 0x00, 0x00, 0x00, 0x00, 0x00 */ |
228 | 0xf7, 0x0f, 0x0a, 0x00, 0x00 | 227 | 0xf7, 0x0f, 0x0a, 0x00, 0x00 |
229 | }; | 228 | }; |
230 | static const __u8 reg84_sn9c120_1[] = { | ||
231 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
232 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
233 | 0x00, 0x00, 0x0c, 0x00, 0x00 | ||
234 | }; | ||
235 | static const __u8 reg84_sn9c120_2[] = { | ||
236 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
237 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
238 | 0x00, 0x00, 0x0c, 0x02, 0x3b | ||
239 | }; | ||
240 | static const __u8 reg84_sn9c120_3[] = { | ||
241 | 0x14, 0x00, 0x27, 0x00, 0x08, 0x00, 0xeb, 0x0f, | ||
242 | 0xd5, 0x0f, 0x42, 0x00, 0x41, 0x00, 0xca, 0x0f, | ||
243 | 0xf5, 0x0f, 0x0c, 0x02, 0x3b | ||
244 | }; | ||
245 | static const __u8 reg84_sn9c325[] = { | 229 | static const __u8 reg84_sn9c325[] = { |
246 | 0x14, 0x00, 0x27, 0x00, 0x07, 0x00, 0xe4, 0x0f, | 230 | 0x14, 0x00, 0x27, 0x00, 0x07, 0x00, 0xe4, 0x0f, |
247 | 0xd3, 0x0f, 0x4b, 0x00, 0x48, 0x00, 0xc0, 0x0f, | 231 | 0xd3, 0x0f, 0x4b, 0x00, 0x48, 0x00, 0xc0, 0x0f, |
@@ -360,17 +344,15 @@ static const __u8 ov7660_sensor_init[][8] = { | |||
360 | {0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, /* reset SCCB */ | 344 | {0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, /* reset SCCB */ |
361 | /* (delay 20ms) */ | 345 | /* (delay 20ms) */ |
362 | {0xa1, 0x21, 0x12, 0x05, 0x00, 0x00, 0x00, 0x10}, | 346 | {0xa1, 0x21, 0x12, 0x05, 0x00, 0x00, 0x00, 0x10}, |
363 | /* Outformat ?? rawRGB */ | 347 | /* Outformat = rawRGB */ |
364 | {0xa1, 0x21, 0x13, 0xb8, 0x00, 0x00, 0x00, 0x10}, /* init COM8 */ | 348 | {0xa1, 0x21, 0x13, 0xb8, 0x00, 0x00, 0x00, 0x10}, /* init COM8 */ |
365 | {0xd1, 0x21, 0x00, 0x01, 0x74, 0x92, 0x00, 0x10}, | 349 | {0xd1, 0x21, 0x00, 0x01, 0x74, 0x74, 0x00, 0x10}, |
366 | /* {0xd1, 0x21, 0x00, 0x01, 0x74, 0x74, 0x00, 0x10}, */ | ||
367 | /* GAIN BLUE RED VREF */ | 350 | /* GAIN BLUE RED VREF */ |
368 | {0xd1, 0x21, 0x04, 0x00, 0x7d, 0x62, 0x00, 0x10}, | 351 | {0xd1, 0x21, 0x04, 0x00, 0x7d, 0x62, 0x00, 0x10}, |
369 | /* COM 1 BAVE GEAVE AECHH */ | 352 | /* COM 1 BAVE GEAVE AECHH */ |
370 | {0xb1, 0x21, 0x08, 0x83, 0x01, 0x00, 0x00, 0x10}, /* RAVE COM2 */ | 353 | {0xb1, 0x21, 0x08, 0x83, 0x01, 0x00, 0x00, 0x10}, /* RAVE COM2 */ |
371 | {0xd1, 0x21, 0x0c, 0x00, 0x08, 0x04, 0x4f, 0x10}, /* COM 3 4 5 6 */ | 354 | {0xd1, 0x21, 0x0c, 0x00, 0x08, 0x04, 0x4f, 0x10}, /* COM 3 4 5 6 */ |
372 | {0xd1, 0x21, 0x10, 0x7f, 0x40, 0x05, 0xf8, 0x10}, | 355 | {0xd1, 0x21, 0x10, 0x7f, 0x40, 0x05, 0xff, 0x10}, |
373 | /* {0xd1, 0x21, 0x10, 0x7f, 0x40, 0x05, 0xff, 0x10}, */ | ||
374 | /* AECH CLKRC COM7 COM8 */ | 356 | /* AECH CLKRC COM7 COM8 */ |
375 | {0xc1, 0x21, 0x14, 0x2c, 0x00, 0x02, 0x00, 0x10}, /* COM9 COM10 */ | 357 | {0xc1, 0x21, 0x14, 0x2c, 0x00, 0x02, 0x00, 0x10}, /* COM9 COM10 */ |
376 | {0xd1, 0x21, 0x17, 0x10, 0x60, 0x02, 0x7b, 0x10}, | 358 | {0xd1, 0x21, 0x17, 0x10, 0x60, 0x02, 0x7b, 0x10}, |
@@ -379,8 +361,8 @@ static const __u8 ov7660_sensor_init[][8] = { | |||
379 | {0xb1, 0x21, 0x1e, 0x01, 0x0e, 0x00, 0x00, 0x10}, /* MVFP LAEC */ | 361 | {0xb1, 0x21, 0x1e, 0x01, 0x0e, 0x00, 0x00, 0x10}, /* MVFP LAEC */ |
380 | {0xd1, 0x21, 0x20, 0x07, 0x07, 0x07, 0x07, 0x10}, | 362 | {0xd1, 0x21, 0x20, 0x07, 0x07, 0x07, 0x07, 0x10}, |
381 | /* BOS GBOS GROS ROS (BGGR offset) */ | 363 | /* BOS GBOS GROS ROS (BGGR offset) */ |
382 | {0xd1, 0x21, 0x24, 0x68, 0x58, 0xd4, 0x80, 0x10}, | 364 | /* {0xd1, 0x21, 0x24, 0x68, 0x58, 0xd4, 0x80, 0x10}, */ |
383 | /* {0xd1, 0x21, 0x24, 0x78, 0x68, 0xd4, 0x80, 0x10}, */ | 365 | {0xd1, 0x21, 0x24, 0x78, 0x68, 0xd4, 0x80, 0x10}, |
384 | /* AEW AEB VPT BBIAS */ | 366 | /* AEW AEB VPT BBIAS */ |
385 | {0xd1, 0x21, 0x28, 0x80, 0x30, 0x00, 0x00, 0x10}, | 367 | {0xd1, 0x21, 0x28, 0x80, 0x30, 0x00, 0x00, 0x10}, |
386 | /* GbBIAS RSVD EXHCH EXHCL */ | 368 | /* GbBIAS RSVD EXHCH EXHCL */ |
@@ -407,9 +389,9 @@ static const __u8 ov7660_sensor_init[][8] = { | |||
407 | {0xd1, 0x21, 0x62, 0x00, 0x00, 0x50, 0x30, 0x10}, | 389 | {0xd1, 0x21, 0x62, 0x00, 0x00, 0x50, 0x30, 0x10}, |
408 | /* LCC1 LCC2 LCC3 LCC4 */ | 390 | /* LCC1 LCC2 LCC3 LCC4 */ |
409 | {0xa1, 0x21, 0x66, 0x00, 0x00, 0x00, 0x00, 0x10}, /* LCC5 */ | 391 | {0xa1, 0x21, 0x66, 0x00, 0x00, 0x00, 0x00, 0x10}, /* LCC5 */ |
410 | {0xd1, 0x21, 0x67, 0x80, 0x7a, 0x90, 0x80, 0x10}, | 392 | {0xd1, 0x21, 0x67, 0x80, 0x7a, 0x90, 0x80, 0x10}, /* MANU */ |
411 | {0xa1, 0x21, 0x6b, 0x0a, 0x00, 0x00, 0x00, 0x10}, | 393 | {0xa1, 0x21, 0x6b, 0x0a, 0x00, 0x00, 0x00, 0x10}, |
412 | /* band gap reference [0..3] DBLV */ | 394 | /* band gap reference [0:3] DBLV */ |
413 | {0xd1, 0x21, 0x6c, 0x30, 0x48, 0x80, 0x74, 0x10}, /* gamma curve */ | 395 | {0xd1, 0x21, 0x6c, 0x30, 0x48, 0x80, 0x74, 0x10}, /* gamma curve */ |
414 | {0xd1, 0x21, 0x70, 0x64, 0x60, 0x5c, 0x58, 0x10}, /* gamma curve */ | 396 | {0xd1, 0x21, 0x70, 0x64, 0x60, 0x5c, 0x58, 0x10}, /* gamma curve */ |
415 | {0xd1, 0x21, 0x74, 0x54, 0x4c, 0x40, 0x38, 0x10}, /* gamma curve */ | 397 | {0xd1, 0x21, 0x74, 0x54, 0x4c, 0x40, 0x38, 0x10}, /* gamma curve */ |
@@ -419,37 +401,35 @@ static const __u8 ov7660_sensor_init[][8] = { | |||
419 | {0xd1, 0x21, 0x84, 0x6e, 0x77, 0x87, 0x95, 0x10}, /* gamma curve */ | 401 | {0xd1, 0x21, 0x84, 0x6e, 0x77, 0x87, 0x95, 0x10}, /* gamma curve */ |
420 | {0xc1, 0x21, 0x88, 0xaf, 0xc7, 0xdf, 0x00, 0x10}, /* gamma curve */ | 402 | {0xc1, 0x21, 0x88, 0xaf, 0xc7, 0xdf, 0x00, 0x10}, /* gamma curve */ |
421 | {0xc1, 0x21, 0x8b, 0x99, 0x99, 0xcf, 0x00, 0x10}, /* reserved */ | 403 | {0xc1, 0x21, 0x8b, 0x99, 0x99, 0xcf, 0x00, 0x10}, /* reserved */ |
422 | {0xb1, 0x21, 0x92, 0x00, 0x00, 0x00, 0x00, 0x10}, | 404 | {0xb1, 0x21, 0x92, 0x00, 0x00, 0x00, 0x00, 0x10}, /* DM_LNL/H */ |
423 | /****** (some exchanges in the win trace) ******/ | 405 | /****** (some exchanges in the win trace) ******/ |
424 | {0xa1, 0x21, 0x1e, 0x01, 0x00, 0x00, 0x00, 0x10}, | 406 | {0xa1, 0x21, 0x1e, 0x01, 0x00, 0x00, 0x00, 0x10}, /* MVFP */ |
425 | /* bits[3..0]reserved */ | 407 | /* bits[3..0]reserved */ |
426 | {0xa1, 0x21, 0x1e, 0x01, 0x00, 0x00, 0x00, 0x10}, | 408 | {0xa1, 0x21, 0x1e, 0x01, 0x00, 0x00, 0x00, 0x10}, |
427 | {0xa1, 0x21, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10}, | 409 | {0xa1, 0x21, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10}, |
428 | /* VREF vertical frame ctrl */ | 410 | /* VREF vertical frame ctrl */ |
429 | {0xa1, 0x21, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10}, | 411 | {0xa1, 0x21, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10}, |
430 | {0xa1, 0x21, 0x10, 0x20, 0x00, 0x00, 0x00, 0x10}, /* 0x20 */ | 412 | {0xa1, 0x21, 0x10, 0x20, 0x00, 0x00, 0x00, 0x10}, /* AECH 0x20 */ |
431 | {0xa1, 0x21, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x10}, | 413 | {0xa1, 0x21, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x10}, /* ADVFL */ |
432 | {0xa1, 0x21, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x10}, | 414 | {0xa1, 0x21, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x10}, /* ADVFH */ |
433 | /* {0xa1, 0x21, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x10}, */ | 415 | {0xa1, 0x21, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x10}, /* GAIN */ |
434 | {0xa1, 0x21, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x10}, | 416 | /* {0xb1, 0x21, 0x01, 0x78, 0x78, 0x00, 0x00, 0x10}, * BLUE */ |
435 | {0xb1, 0x21, 0x01, 0x78, 0x78, 0x00, 0x00, 0x10}, | ||
436 | /****** (some exchanges in the win trace) ******/ | 417 | /****** (some exchanges in the win trace) ******/ |
437 | {0xa1, 0x21, 0x93, 0x00, 0x00, 0x00, 0x00, 0x10},/* dummy line hight */ | 418 | {0xa1, 0x21, 0x93, 0x00, 0x00, 0x00, 0x00, 0x10},/* dummy line hight */ |
438 | {0xa1, 0x21, 0x92, 0x25, 0x00, 0x00, 0x00, 0x10},/* dummy line low */ | 419 | {0xa1, 0x21, 0x92, 0x25, 0x00, 0x00, 0x00, 0x10}, /* dummy line low */ |
439 | {0xa1, 0x21, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x10}, | 420 | {0xa1, 0x21, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x10}, /* EXHCH */ |
440 | {0xa1, 0x21, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10}, | 421 | {0xa1, 0x21, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10}, /* EXHCL */ |
441 | {0xa1, 0x21, 0x02, 0x90, 0x00, 0x00, 0x00, 0x10}, | 422 | /* {0xa1, 0x21, 0x02, 0x90, 0x00, 0x00, 0x00, 0x10}, * RED */ |
442 | /****** (some exchanges in the win trace) ******/ | 423 | /****** (some exchanges in the win trace) ******/ |
443 | /**********startsensor KO if changed !!****/ | 424 | /******!! startsensor KO if changed !!****/ |
444 | {0xa1, 0x21, 0x93, 0x01, 0x00, 0x00, 0x00, 0x10}, | 425 | {0xa1, 0x21, 0x93, 0x01, 0x00, 0x00, 0x00, 0x10}, |
445 | {0xa1, 0x21, 0x92, 0xff, 0x00, 0x00, 0x00, 0x10}, | 426 | {0xa1, 0x21, 0x92, 0xff, 0x00, 0x00, 0x00, 0x10}, |
446 | {0xa1, 0x21, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x10}, | 427 | {0xa1, 0x21, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x10}, |
447 | {0xa1, 0x21, 0x2b, 0xc3, 0x00, 0x00, 0x00, 0x10}, | 428 | {0xa1, 0x21, 0x2b, 0xc3, 0x00, 0x00, 0x00, 0x10}, |
448 | /* here may start the isoc exchanges */ | ||
449 | {} | 429 | {} |
450 | }; | 430 | }; |
451 | /* reg0x04 reg0x07 reg 0x10 */ | 431 | /* reg 0x04 reg 0x07 reg 0x10 */ |
452 | /* expo = (COM1 & 0x02) | (AECHH & 0x2f <<10) [ (AECh << 2) */ | 432 | /* expo = (COM1 & 0x02) | ((AECHH & 0x2f) << 10) | (AECh << 2) */ |
453 | 433 | ||
454 | static const __u8 ov7648_sensor_init[][8] = { | 434 | static const __u8 ov7648_sensor_init[][8] = { |
455 | {0xC1, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00}, | 435 | {0xC1, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00}, |
@@ -680,13 +660,12 @@ static int configure_gpio(struct gspca_dev *gspca_dev, | |||
680 | const __u8 *reg9a; | 660 | const __u8 *reg9a; |
681 | static const __u8 reg9a_def[] = | 661 | static const __u8 reg9a_def[] = |
682 | {0x08, 0x40, 0x20, 0x10, 0x00, 0x04}; | 662 | {0x08, 0x40, 0x20, 0x10, 0x00, 0x04}; |
683 | static const __u8 reg9a_sn9c120[] = /* from win trace */ | ||
684 | {0x00, 0x40, 0x38, 0x30, 0x00, 0x20}; | ||
685 | static const __u8 reg9a_sn9c325[] = | 663 | static const __u8 reg9a_sn9c325[] = |
686 | {0x0a, 0x40, 0x38, 0x30, 0x00, 0x20}; | 664 | {0x0a, 0x40, 0x38, 0x30, 0x00, 0x20}; |
665 | static const __u8 regd4[] = {0x60, 0x00, 0x00}; | ||
687 | 666 | ||
688 | reg_w1(gspca_dev, 0xf1, 0x00); | 667 | reg_w1(gspca_dev, 0xf1, 0x00); |
689 | reg_w1(gspca_dev, 0x01, sn9c1xx[0]); /*fixme:jfm was [1] en v1*/ | 668 | reg_w1(gspca_dev, 0x01, 0x00); /*jfm was sn9c1xx[1] in v1*/ |
690 | 669 | ||
691 | /* configure gpio */ | 670 | /* configure gpio */ |
692 | reg_w(gspca_dev, 0x01, &sn9c1xx[1], 2); | 671 | reg_w(gspca_dev, 0x01, &sn9c1xx[1], 2); |
@@ -696,25 +675,17 @@ static int configure_gpio(struct gspca_dev *gspca_dev, | |||
696 | case BRIDGE_SN9C325: | 675 | case BRIDGE_SN9C325: |
697 | reg9a = reg9a_sn9c325; | 676 | reg9a = reg9a_sn9c325; |
698 | break; | 677 | break; |
699 | case BRIDGE_SN9C120: | ||
700 | reg9a = reg9a_sn9c120; | ||
701 | break; | ||
702 | default: | 678 | default: |
703 | reg9a = reg9a_def; | 679 | reg9a = reg9a_def; |
704 | break; | 680 | break; |
705 | } | 681 | } |
706 | reg_w(gspca_dev, 0x9a, reg9a, 6); | 682 | reg_w(gspca_dev, 0x9a, reg9a, 6); |
707 | 683 | ||
708 | reg_w1(gspca_dev, 0xd4, 0x60); /*fixme:jfm 60 00 00 (3) ? */ | 684 | reg_w(gspca_dev, 0xd4, regd4, sizeof regd4); /*fixme:jfm was 60 only*/ |
709 | 685 | ||
710 | reg_w(gspca_dev, 0x03, &sn9c1xx[3], 0x0f); | 686 | reg_w(gspca_dev, 0x03, &sn9c1xx[3], 0x0f); |
711 | 687 | ||
712 | switch (sd->bridge) { | 688 | switch (sd->bridge) { |
713 | case BRIDGE_SN9C120: /* from win trace */ | ||
714 | reg_w1(gspca_dev, 0x01, 0x61); | ||
715 | reg_w1(gspca_dev, 0x17, 0x20); | ||
716 | reg_w1(gspca_dev, 0x01, 0x60); | ||
717 | break; | ||
718 | case BRIDGE_SN9C325: | 689 | case BRIDGE_SN9C325: |
719 | reg_w1(gspca_dev, 0x01, 0x43); | 690 | reg_w1(gspca_dev, 0x01, 0x43); |
720 | reg_w1(gspca_dev, 0x17, 0xae); | 691 | reg_w1(gspca_dev, 0x17, 0xae); |
@@ -810,6 +781,8 @@ static int sd_config(struct gspca_dev *gspca_dev, | |||
810 | sd->contrast = CONTRAST_DEF; | 781 | sd->contrast = CONTRAST_DEF; |
811 | sd->colors = COLOR_DEF; | 782 | sd->colors = COLOR_DEF; |
812 | sd->autogain = AUTOGAIN_DEF; | 783 | sd->autogain = AUTOGAIN_DEF; |
784 | sd->ag_cnt = -1; | ||
785 | |||
813 | return 0; | 786 | return 0; |
814 | } | 787 | } |
815 | 788 | ||
@@ -823,10 +796,11 @@ static int sd_open(struct gspca_dev *gspca_dev) | |||
823 | 796 | ||
824 | /* setup a selector by bridge */ | 797 | /* setup a selector by bridge */ |
825 | reg_w1(gspca_dev, 0xf1, 0x01); | 798 | reg_w1(gspca_dev, 0xf1, 0x01); |
826 | reg_r(gspca_dev, 0x00, 1); /* -> regF1 = 0x00 */ | ||
827 | reg_w1(gspca_dev, 0xf1, gspca_dev->usb_buf[0]); | ||
828 | reg_r(gspca_dev, 0x00, 1); | 799 | reg_r(gspca_dev, 0x00, 1); |
800 | reg_w1(gspca_dev, 0xf1, gspca_dev->usb_buf[0]); | ||
801 | reg_r(gspca_dev, 0x00, 1); /* get sonix chip id */ | ||
829 | regF1 = gspca_dev->usb_buf[0]; | 802 | regF1 = gspca_dev->usb_buf[0]; |
803 | PDEBUG(D_PROBE, "Sonix chip id: %02x", regF1); | ||
830 | switch (sd->bridge) { | 804 | switch (sd->bridge) { |
831 | case BRIDGE_SN9C102P: | 805 | case BRIDGE_SN9C102P: |
832 | if (regF1 != 0x11) | 806 | if (regF1 != 0x11) |
@@ -937,15 +911,10 @@ static void setbrightness(struct gspca_dev *gspca_dev) | |||
937 | sd->exposure = setexposure(gspca_dev, expo); | 911 | sd->exposure = setexposure(gspca_dev, expo); |
938 | break; | 912 | break; |
939 | case SENSOR_MI0360: | 913 | case SENSOR_MI0360: |
940 | expo = sd->brightness >> 4; | ||
941 | sd->exposure = setexposure(gspca_dev, expo); | ||
942 | break; | ||
943 | case SENSOR_MO4000: | 914 | case SENSOR_MO4000: |
944 | expo = sd->brightness >> 4; | 915 | expo = sd->brightness >> 4; |
945 | sd->exposure = setexposure(gspca_dev, expo); | 916 | sd->exposure = setexposure(gspca_dev, expo); |
946 | break; | 917 | break; |
947 | case SENSOR_OV7660: | ||
948 | return; /*jfm??*/ | ||
949 | } | 918 | } |
950 | 919 | ||
951 | k2 = sd->brightness >> 10; | 920 | k2 = sd->brightness >> 10; |
@@ -958,8 +927,6 @@ static void setcontrast(struct gspca_dev *gspca_dev) | |||
958 | __u8 k2; | 927 | __u8 k2; |
959 | __u8 contrast[] = { 0x00, 0x00, 0x28, 0x00, 0x07, 0x00 }; | 928 | __u8 contrast[] = { 0x00, 0x00, 0x28, 0x00, 0x07, 0x00 }; |
960 | 929 | ||
961 | if (sd->sensor == SENSOR_OV7660) | ||
962 | return; /*jfm??*/ | ||
963 | k2 = sd->contrast; | 930 | k2 = sd->contrast; |
964 | contrast[2] = k2; | 931 | contrast[2] = k2; |
965 | contrast[0] = (k2 + 1) >> 1; | 932 | contrast[0] = (k2 + 1) >> 1; |
@@ -981,20 +948,32 @@ static void setcolors(struct gspca_dev *gspca_dev) | |||
981 | reg_w1(gspca_dev, 0x05, data); | 948 | reg_w1(gspca_dev, 0x05, data); |
982 | } | 949 | } |
983 | 950 | ||
951 | static void setautogain(struct gspca_dev *gspca_dev) | ||
952 | { | ||
953 | struct sd *sd = (struct sd *) gspca_dev; | ||
954 | |||
955 | switch (sd->sensor) { | ||
956 | case SENSOR_HV7131R: | ||
957 | case SENSOR_MO4000: | ||
958 | case SENSOR_MI0360: | ||
959 | if (sd->autogain) | ||
960 | sd->ag_cnt = AG_CNT_START; | ||
961 | else | ||
962 | sd->ag_cnt = -1; | ||
963 | break; | ||
964 | } | ||
965 | } | ||
966 | |||
984 | /* -- start the camera -- */ | 967 | /* -- start the camera -- */ |
985 | static void sd_start(struct gspca_dev *gspca_dev) | 968 | static void sd_start(struct gspca_dev *gspca_dev) |
986 | { | 969 | { |
987 | struct sd *sd = (struct sd *) gspca_dev; | 970 | struct sd *sd = (struct sd *) gspca_dev; |
988 | int i; | 971 | int i; |
989 | __u8 data; | 972 | __u8 reg1, reg17, reg18; |
990 | __u8 reg1; | ||
991 | __u8 reg17; | ||
992 | const __u8 *sn9c1xx; | 973 | const __u8 *sn9c1xx; |
993 | int mode; | 974 | int mode; |
994 | static const __u8 C0[] = { 0x2d, 0x2d, 0x3a, 0x05, 0x04, 0x3f }; | 975 | static const __u8 C0[] = { 0x2d, 0x2d, 0x3a, 0x05, 0x04, 0x3f }; |
995 | static const __u8 CA[] = { 0x28, 0xd8, 0x14, 0xec }; | 976 | static const __u8 CA[] = { 0x28, 0xd8, 0x14, 0xec }; |
996 | static const __u8 CA_sn9c120[] = | ||
997 | { 0x14, 0xec, 0x0a, 0xf6 }; /* SN9C120 */ | ||
998 | static const __u8 CE[] = { 0x32, 0xdd, 0x2d, 0xdd }; /* MI0360 */ | 977 | static const __u8 CE[] = { 0x32, 0xdd, 0x2d, 0xdd }; /* MI0360 */ |
999 | static const __u8 CE_sn9c325[] = | 978 | static const __u8 CE_sn9c325[] = |
1000 | { 0x32, 0xdd, 0x32, 0xdd }; /* OV7648 - SN9C325 */ | 979 | { 0x32, 0xdd, 0x32, 0xdd }; /* OV7648 - SN9C325 */ |
@@ -1002,9 +981,7 @@ static void sd_start(struct gspca_dev *gspca_dev) | |||
1002 | sn9c1xx = sn_tb[(int) sd->sensor]; | 981 | sn9c1xx = sn_tb[(int) sd->sensor]; |
1003 | configure_gpio(gspca_dev, sn9c1xx); | 982 | configure_gpio(gspca_dev, sn9c1xx); |
1004 | 983 | ||
1005 | /*fixme:jfm this sequence should appear at end of sd_start */ | 984 | /* reg_w1(gspca_dev, 0x01, 0x44); jfm from win trace*/ |
1006 | /* with | ||
1007 | reg_w1(gspca_dev, 0x01, 0x44); */ | ||
1008 | reg_w1(gspca_dev, 0x15, sn9c1xx[0x15]); | 985 | reg_w1(gspca_dev, 0x15, sn9c1xx[0x15]); |
1009 | reg_w1(gspca_dev, 0x16, sn9c1xx[0x16]); | 986 | reg_w1(gspca_dev, 0x16, sn9c1xx[0x16]); |
1010 | reg_w1(gspca_dev, 0x12, sn9c1xx[0x12]); | 987 | reg_w1(gspca_dev, 0x12, sn9c1xx[0x12]); |
@@ -1016,20 +993,16 @@ static void sd_start(struct gspca_dev *gspca_dev) | |||
1016 | reg_w1(gspca_dev, 0xc7, 0x00); | 993 | reg_w1(gspca_dev, 0xc7, 0x00); |
1017 | reg_w1(gspca_dev, 0xc8, 0x50); | 994 | reg_w1(gspca_dev, 0xc8, 0x50); |
1018 | reg_w1(gspca_dev, 0xc9, 0x3c); | 995 | reg_w1(gspca_dev, 0xc9, 0x3c); |
1019 | /*fixme:jfm end of ending sequence */ | ||
1020 | reg_w1(gspca_dev, 0x18, sn9c1xx[0x18]); | 996 | reg_w1(gspca_dev, 0x18, sn9c1xx[0x18]); |
1021 | switch (sd->bridge) { | 997 | switch (sd->bridge) { |
1022 | case BRIDGE_SN9C325: | 998 | case BRIDGE_SN9C325: |
1023 | data = 0xae; | 999 | reg17 = 0xae; |
1024 | break; | ||
1025 | case BRIDGE_SN9C120: | ||
1026 | data = 0xa0; | ||
1027 | break; | 1000 | break; |
1028 | default: | 1001 | default: |
1029 | data = 0x60; | 1002 | reg17 = 0x60; |
1030 | break; | 1003 | break; |
1031 | } | 1004 | } |
1032 | reg_w1(gspca_dev, 0x17, data); | 1005 | reg_w1(gspca_dev, 0x17, reg17); |
1033 | reg_w1(gspca_dev, 0x05, sn9c1xx[5]); | 1006 | reg_w1(gspca_dev, 0x05, sn9c1xx[5]); |
1034 | reg_w1(gspca_dev, 0x07, sn9c1xx[7]); | 1007 | reg_w1(gspca_dev, 0x07, sn9c1xx[7]); |
1035 | reg_w1(gspca_dev, 0x06, sn9c1xx[6]); | 1008 | reg_w1(gspca_dev, 0x06, sn9c1xx[6]); |
@@ -1044,20 +1017,6 @@ static void sd_start(struct gspca_dev *gspca_dev) | |||
1044 | reg_w1(gspca_dev, 0x9a, 0x0a); | 1017 | reg_w1(gspca_dev, 0x9a, 0x0a); |
1045 | reg_w1(gspca_dev, 0x99, 0x60); | 1018 | reg_w1(gspca_dev, 0x99, 0x60); |
1046 | break; | 1019 | break; |
1047 | case BRIDGE_SN9C120: | ||
1048 | reg_w(gspca_dev, 0x20, regsn20_sn9c120, | ||
1049 | sizeof regsn20_sn9c120); | ||
1050 | for (i = 0; i < 2; i++) | ||
1051 | reg_w(gspca_dev, 0x84, reg84_sn9c120_1, | ||
1052 | sizeof reg84_sn9c120_1); | ||
1053 | for (i = 0; i < 6; i++) | ||
1054 | reg_w(gspca_dev, 0x84, reg84_sn9c120_2, | ||
1055 | sizeof reg84_sn9c120_2); | ||
1056 | reg_w(gspca_dev, 0x84, reg84_sn9c120_3, | ||
1057 | sizeof reg84_sn9c120_3); | ||
1058 | reg_w1(gspca_dev, 0x9a, 0x05); | ||
1059 | reg_w1(gspca_dev, 0x99, 0x5b); | ||
1060 | break; | ||
1061 | default: | 1020 | default: |
1062 | reg_w(gspca_dev, 0x20, regsn20, sizeof regsn20); | 1021 | reg_w(gspca_dev, 0x20, regsn20, sizeof regsn20); |
1063 | for (i = 0; i < 8; i++) | 1022 | for (i = 0; i < 8; i++) |
@@ -1107,22 +1066,14 @@ static void sd_start(struct gspca_dev *gspca_dev) | |||
1107 | /* reg1 = 0x44; */ | 1066 | /* reg1 = 0x44; */ |
1108 | /* reg1 = 0x46; (done) */ | 1067 | /* reg1 = 0x46; (done) */ |
1109 | } else { | 1068 | } else { |
1110 | reg17 = 0xa2; /* 640 */ | 1069 | reg17 = 0x22; /* 640 MCKSIZE */ |
1111 | reg1 = 0x40; | 1070 | reg1 = 0x06; |
1112 | } | 1071 | } |
1113 | break; | 1072 | break; |
1114 | } | 1073 | } |
1115 | reg_w(gspca_dev, 0xc0, C0, 6); | 1074 | reg_w(gspca_dev, 0xc0, C0, 6); |
1075 | reg_w(gspca_dev, 0xca, CA, 4); | ||
1116 | switch (sd->bridge) { | 1076 | switch (sd->bridge) { |
1117 | case BRIDGE_SN9C120: /*jfm ?? */ | ||
1118 | reg_w(gspca_dev, 0xca, CA_sn9c120, 4); | ||
1119 | break; | ||
1120 | default: | ||
1121 | reg_w(gspca_dev, 0xca, CA, 4); | ||
1122 | break; | ||
1123 | } | ||
1124 | switch (sd->bridge) { | ||
1125 | case BRIDGE_SN9C120: /*jfm ?? */ | ||
1126 | case BRIDGE_SN9C325: | 1077 | case BRIDGE_SN9C325: |
1127 | reg_w(gspca_dev, 0xce, CE_sn9c325, 4); | 1078 | reg_w(gspca_dev, 0xce, CE_sn9c325, 4); |
1128 | break; | 1079 | break; |
@@ -1133,19 +1084,19 @@ static void sd_start(struct gspca_dev *gspca_dev) | |||
1133 | } | 1084 | } |
1134 | 1085 | ||
1135 | /* here change size mode 0 -> VGA; 1 -> CIF */ | 1086 | /* here change size mode 0 -> VGA; 1 -> CIF */ |
1136 | data = 0x40 | sn9c1xx[0x18] | (mode << 4); | 1087 | reg18 = sn9c1xx[0x18] | (mode << 4); |
1137 | reg_w1(gspca_dev, 0x18, data); | 1088 | reg_w1(gspca_dev, 0x18, reg18 | 0x40); |
1138 | 1089 | ||
1139 | reg_w(gspca_dev, 0x100, qtable4, 0x40); | 1090 | reg_w(gspca_dev, 0x100, qtable4, 0x40); |
1140 | reg_w(gspca_dev, 0x140, qtable4 + 0x40, 0x40); | 1091 | reg_w(gspca_dev, 0x140, qtable4 + 0x40, 0x40); |
1141 | 1092 | ||
1142 | data = sn9c1xx[0x18] | (mode << 4); | 1093 | reg_w1(gspca_dev, 0x18, reg18); |
1143 | reg_w1(gspca_dev, 0x18, data); | ||
1144 | 1094 | ||
1145 | reg_w1(gspca_dev, 0x17, reg17); | 1095 | reg_w1(gspca_dev, 0x17, reg17); |
1146 | reg_w1(gspca_dev, 0x01, reg1); | 1096 | reg_w1(gspca_dev, 0x01, reg1); |
1147 | setbrightness(gspca_dev); | 1097 | setbrightness(gspca_dev); |
1148 | setcontrast(gspca_dev); | 1098 | setcontrast(gspca_dev); |
1099 | setautogain(gspca_dev); | ||
1149 | } | 1100 | } |
1150 | 1101 | ||
1151 | static void sd_stopN(struct gspca_dev *gspca_dev) | 1102 | static void sd_stopN(struct gspca_dev *gspca_dev) |
@@ -1168,12 +1119,11 @@ static void sd_stopN(struct gspca_dev *gspca_dev) | |||
1168 | i2c_w8(gspca_dev, stopmi0360); | 1119 | i2c_w8(gspca_dev, stopmi0360); |
1169 | data = 0x29; | 1120 | data = 0x29; |
1170 | break; | 1121 | break; |
1171 | case SENSOR_MO4000: | ||
1172 | break; | ||
1173 | case SENSOR_OV7648: | 1122 | case SENSOR_OV7648: |
1174 | data = 0x29; | 1123 | data = 0x29; |
1175 | break; | 1124 | break; |
1176 | default: | 1125 | default: |
1126 | /* case SENSOR_MO4000: */ | ||
1177 | /* case SENSOR_OV7660: */ | 1127 | /* case SENSOR_OV7660: */ |
1178 | break; | 1128 | break; |
1179 | } | 1129 | } |
@@ -1193,16 +1143,23 @@ static void sd_close(struct gspca_dev *gspca_dev) | |||
1193 | { | 1143 | { |
1194 | } | 1144 | } |
1195 | 1145 | ||
1196 | static void setautogain(struct gspca_dev *gspca_dev) | 1146 | static void do_autogain(struct gspca_dev *gspca_dev) |
1197 | { | 1147 | { |
1198 | struct sd *sd = (struct sd *) gspca_dev; | 1148 | struct sd *sd = (struct sd *) gspca_dev; |
1199 | /* Thanks S., without your advice, autobright should not work :) */ | ||
1200 | int delta; | 1149 | int delta; |
1201 | int expotimes = 0; | 1150 | int expotimes; |
1202 | __u8 luma_mean = 130; | 1151 | __u8 luma_mean = 130; |
1203 | __u8 luma_delta = 20; | 1152 | __u8 luma_delta = 20; |
1204 | 1153 | ||
1205 | delta = sd->avg_lum; | 1154 | /* Thanks S., without your advice, autobright should not work :) */ |
1155 | if (sd->ag_cnt < 0) | ||
1156 | return; | ||
1157 | if (--sd->ag_cnt >= 0) | ||
1158 | return; | ||
1159 | sd->ag_cnt = AG_CNT_START; | ||
1160 | |||
1161 | delta = atomic_read(&sd->avg_lum); | ||
1162 | PDEBUG(D_FRAM, "mean lum %d", delta); | ||
1206 | if (delta < luma_mean - luma_delta || | 1163 | if (delta < luma_mean - luma_delta || |
1207 | delta > luma_mean + luma_delta) { | 1164 | delta > luma_mean + luma_delta) { |
1208 | switch (sd->sensor) { | 1165 | switch (sd->sensor) { |
@@ -1214,8 +1171,9 @@ static void setautogain(struct gspca_dev *gspca_dev) | |||
1214 | sd->exposure = setexposure(gspca_dev, | 1171 | sd->exposure = setexposure(gspca_dev, |
1215 | (unsigned int) (expotimes << 8)); | 1172 | (unsigned int) (expotimes << 8)); |
1216 | break; | 1173 | break; |
1217 | case SENSOR_MO4000: | 1174 | default: |
1218 | case SENSOR_MI0360: | 1175 | /* case SENSOR_MO4000: */ |
1176 | /* case SENSOR_MI0360: */ | ||
1219 | expotimes = sd->exposure; | 1177 | expotimes = sd->exposure; |
1220 | expotimes += (luma_mean - delta) >> 6; | 1178 | expotimes += (luma_mean - delta) >> 6; |
1221 | if (expotimes < 0) | 1179 | if (expotimes < 0) |
@@ -1228,6 +1186,8 @@ static void setautogain(struct gspca_dev *gspca_dev) | |||
1228 | } | 1186 | } |
1229 | } | 1187 | } |
1230 | 1188 | ||
1189 | /* scan the URB packets */ | ||
1190 | /* This function is run at interrupt level. */ | ||
1231 | static void sd_pkt_scan(struct gspca_dev *gspca_dev, | 1191 | static void sd_pkt_scan(struct gspca_dev *gspca_dev, |
1232 | struct gspca_frame *frame, /* target */ | 1192 | struct gspca_frame *frame, /* target */ |
1233 | __u8 *data, /* isoc packet */ | 1193 | __u8 *data, /* isoc packet */ |
@@ -1244,9 +1204,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, | |||
1244 | frame, data, sof + 2); | 1204 | frame, data, sof + 2); |
1245 | if (sd->ag_cnt < 0) | 1205 | if (sd->ag_cnt < 0) |
1246 | return; | 1206 | return; |
1247 | if (--sd->ag_cnt >= 0) | ||
1248 | return; | ||
1249 | sd->ag_cnt = AG_CNT_START; | ||
1250 | /* w1 w2 w3 */ | 1207 | /* w1 w2 w3 */ |
1251 | /* w4 w5 w6 */ | 1208 | /* w4 w5 w6 */ |
1252 | /* w7 w8 */ | 1209 | /* w7 w8 */ |
@@ -1261,9 +1218,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, | |||
1261 | /* w5 */ | 1218 | /* w5 */ |
1262 | avg_lum += ((data[sof + 31] << 8) | data[sof + 32]) >> 4; | 1219 | avg_lum += ((data[sof + 31] << 8) | data[sof + 32]) >> 4; |
1263 | avg_lum >>= 4; | 1220 | avg_lum >>= 4; |
1264 | sd->avg_lum = avg_lum; | 1221 | atomic_set(&sd->avg_lum, avg_lum); |
1265 | PDEBUG(D_PACK, "mean lum %d", avg_lum); | ||
1266 | setautogain(gspca_dev); | ||
1267 | return; | 1222 | return; |
1268 | } | 1223 | } |
1269 | if (gspca_dev->last_packet_type == LAST_PACKET) { | 1224 | if (gspca_dev->last_packet_type == LAST_PACKET) { |
@@ -1300,6 +1255,7 @@ static unsigned int getexposure(struct gspca_dev *gspca_dev) | |||
1300 | (hexpo << 10) | (mexpo << 2) | lexpo); | 1255 | (hexpo << 10) | (mexpo << 2) | lexpo); |
1301 | return (hexpo << 10) | (mexpo << 2) | lexpo; | 1256 | return (hexpo << 10) | (mexpo << 2) | lexpo; |
1302 | default: | 1257 | default: |
1258 | /* case SENSOR_OV7648: * jfm: is it ok for 7648? */ | ||
1303 | /* case SENSOR_OV7660: */ | 1259 | /* case SENSOR_OV7660: */ |
1304 | /* read sensor exposure */ | 1260 | /* read sensor exposure */ |
1305 | i2c_r5(gspca_dev, 0x04); | 1261 | i2c_r5(gspca_dev, 0x04); |
@@ -1318,14 +1274,12 @@ static void getbrightness(struct gspca_dev *gspca_dev) | |||
1318 | /* hardcoded registers seem not readable */ | 1274 | /* hardcoded registers seem not readable */ |
1319 | switch (sd->sensor) { | 1275 | switch (sd->sensor) { |
1320 | case SENSOR_HV7131R: | 1276 | case SENSOR_HV7131R: |
1321 | /* sd->brightness = 0x7fff; */ | ||
1322 | sd->brightness = getexposure(gspca_dev) >> 4; | 1277 | sd->brightness = getexposure(gspca_dev) >> 4; |
1323 | break; | 1278 | break; |
1324 | case SENSOR_MI0360: | 1279 | case SENSOR_MI0360: |
1325 | sd->brightness = getexposure(gspca_dev) << 4; | 1280 | sd->brightness = getexposure(gspca_dev) << 4; |
1326 | break; | 1281 | break; |
1327 | case SENSOR_MO4000: | 1282 | case SENSOR_MO4000: |
1328 | /* sd->brightness = 0x1fff; */ | ||
1329 | sd->brightness = getexposure(gspca_dev) << 4; | 1283 | sd->brightness = getexposure(gspca_dev) << 4; |
1330 | break; | 1284 | break; |
1331 | } | 1285 | } |
@@ -1391,10 +1345,8 @@ static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) | |||
1391 | struct sd *sd = (struct sd *) gspca_dev; | 1345 | struct sd *sd = (struct sd *) gspca_dev; |
1392 | 1346 | ||
1393 | sd->autogain = val; | 1347 | sd->autogain = val; |
1394 | if (val) | 1348 | if (gspca_dev->streaming) |
1395 | sd->ag_cnt = AG_CNT_START; | 1349 | setautogain(gspca_dev); |
1396 | else | ||
1397 | sd->ag_cnt = -1; | ||
1398 | return 0; | 1350 | return 0; |
1399 | } | 1351 | } |
1400 | 1352 | ||
@@ -1418,6 +1370,7 @@ static const struct sd_desc sd_desc = { | |||
1418 | .stop0 = sd_stop0, | 1370 | .stop0 = sd_stop0, |
1419 | .close = sd_close, | 1371 | .close = sd_close, |
1420 | .pkt_scan = sd_pkt_scan, | 1372 | .pkt_scan = sd_pkt_scan, |
1373 | .dq_callback = do_autogain, | ||
1421 | }; | 1374 | }; |
1422 | 1375 | ||
1423 | /* -- module initialisation -- */ | 1376 | /* -- module initialisation -- */ |
diff --git a/drivers/media/video/gspca/spca505.c b/drivers/media/video/gspca/spca505.c index 3c2be80cbd65..eda29d609359 100644 --- a/drivers/media/video/gspca/spca505.c +++ b/drivers/media/video/gspca/spca505.c | |||
@@ -61,27 +61,27 @@ static struct ctrl sd_ctrls[] = { | |||
61 | 61 | ||
62 | static struct v4l2_pix_format vga_mode[] = { | 62 | static struct v4l2_pix_format vga_mode[] = { |
63 | {160, 120, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, | 63 | {160, 120, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, |
64 | .bytesperline = 160 * 3, | 64 | .bytesperline = 160, |
65 | .sizeimage = 160 * 120 * 3 / 2, | 65 | .sizeimage = 160 * 120 * 3 / 2, |
66 | .colorspace = V4L2_COLORSPACE_SRGB, | 66 | .colorspace = V4L2_COLORSPACE_SRGB, |
67 | .priv = 5}, | 67 | .priv = 5}, |
68 | {176, 144, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, | 68 | {176, 144, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, |
69 | .bytesperline = 176 * 3, | 69 | .bytesperline = 176, |
70 | .sizeimage = 176 * 144 * 3 / 2, | 70 | .sizeimage = 176 * 144 * 3 / 2, |
71 | .colorspace = V4L2_COLORSPACE_SRGB, | 71 | .colorspace = V4L2_COLORSPACE_SRGB, |
72 | .priv = 4}, | 72 | .priv = 4}, |
73 | {320, 240, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, | 73 | {320, 240, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, |
74 | .bytesperline = 320 * 3, | 74 | .bytesperline = 320, |
75 | .sizeimage = 320 * 240 * 3 / 2, | 75 | .sizeimage = 320 * 240 * 3 / 2, |
76 | .colorspace = V4L2_COLORSPACE_SRGB, | 76 | .colorspace = V4L2_COLORSPACE_SRGB, |
77 | .priv = 2}, | 77 | .priv = 2}, |
78 | {352, 288, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, | 78 | {352, 288, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, |
79 | .bytesperline = 352 * 3, | 79 | .bytesperline = 352, |
80 | .sizeimage = 352 * 288 * 3 / 2, | 80 | .sizeimage = 352 * 288 * 3 / 2, |
81 | .colorspace = V4L2_COLORSPACE_SRGB, | 81 | .colorspace = V4L2_COLORSPACE_SRGB, |
82 | .priv = 1}, | 82 | .priv = 1}, |
83 | {640, 480, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, | 83 | {640, 480, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, |
84 | .bytesperline = 640 * 3, | 84 | .bytesperline = 640, |
85 | .sizeimage = 640 * 480 * 3 / 2, | 85 | .sizeimage = 640 * 480 * 3 / 2, |
86 | .colorspace = V4L2_COLORSPACE_SRGB, | 86 | .colorspace = V4L2_COLORSPACE_SRGB, |
87 | .priv = 0}, | 87 | .priv = 0}, |
@@ -776,7 +776,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, | |||
776 | default: | 776 | default: |
777 | data += 1; | 777 | data += 1; |
778 | len -= 1; | 778 | len -= 1; |
779 | gspca_frame_add(gspca_dev, FIRST_PACKET, frame, | 779 | gspca_frame_add(gspca_dev, INTER_PACKET, frame, |
780 | data, len); | 780 | data, len); |
781 | break; | 781 | break; |
782 | } | 782 | } |
diff --git a/drivers/media/video/gspca/spca506.c b/drivers/media/video/gspca/spca506.c index 6fe715c80ad2..f622fa75766d 100644 --- a/drivers/media/video/gspca/spca506.c +++ b/drivers/media/video/gspca/spca506.c | |||
@@ -112,27 +112,27 @@ static struct ctrl sd_ctrls[] = { | |||
112 | 112 | ||
113 | static struct v4l2_pix_format vga_mode[] = { | 113 | static struct v4l2_pix_format vga_mode[] = { |
114 | {160, 120, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, | 114 | {160, 120, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, |
115 | .bytesperline = 160 * 3, | 115 | .bytesperline = 160, |
116 | .sizeimage = 160 * 120 * 3 / 2, | 116 | .sizeimage = 160 * 120 * 3 / 2, |
117 | .colorspace = V4L2_COLORSPACE_SRGB, | 117 | .colorspace = V4L2_COLORSPACE_SRGB, |
118 | .priv = 5}, | 118 | .priv = 5}, |
119 | {176, 144, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, | 119 | {176, 144, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, |
120 | .bytesperline = 176 * 3, | 120 | .bytesperline = 176, |
121 | .sizeimage = 176 * 144 * 3 / 2, | 121 | .sizeimage = 176 * 144 * 3 / 2, |
122 | .colorspace = V4L2_COLORSPACE_SRGB, | 122 | .colorspace = V4L2_COLORSPACE_SRGB, |
123 | .priv = 4}, | 123 | .priv = 4}, |
124 | {320, 240, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, | 124 | {320, 240, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, |
125 | .bytesperline = 320 * 3, | 125 | .bytesperline = 320, |
126 | .sizeimage = 320 * 240 * 3 / 2, | 126 | .sizeimage = 320 * 240 * 3 / 2, |
127 | .colorspace = V4L2_COLORSPACE_SRGB, | 127 | .colorspace = V4L2_COLORSPACE_SRGB, |
128 | .priv = 2}, | 128 | .priv = 2}, |
129 | {352, 288, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, | 129 | {352, 288, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, |
130 | .bytesperline = 352 * 3, | 130 | .bytesperline = 352, |
131 | .sizeimage = 352 * 288 * 3 / 2, | 131 | .sizeimage = 352 * 288 * 3 / 2, |
132 | .colorspace = V4L2_COLORSPACE_SRGB, | 132 | .colorspace = V4L2_COLORSPACE_SRGB, |
133 | .priv = 1}, | 133 | .priv = 1}, |
134 | {640, 480, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, | 134 | {640, 480, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, |
135 | .bytesperline = 640 * 3, | 135 | .bytesperline = 640, |
136 | .sizeimage = 640 * 480 * 3 / 2, | 136 | .sizeimage = 640 * 480 * 3 / 2, |
137 | .colorspace = V4L2_COLORSPACE_SRGB, | 137 | .colorspace = V4L2_COLORSPACE_SRGB, |
138 | .priv = 0}, | 138 | .priv = 0}, |
@@ -588,7 +588,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, | |||
588 | default: | 588 | default: |
589 | data += 1; | 589 | data += 1; |
590 | len -= 1; | 590 | len -= 1; |
591 | gspca_frame_add(gspca_dev, FIRST_PACKET, frame, | 591 | gspca_frame_add(gspca_dev, INTER_PACKET, frame, |
592 | data, len); | 592 | data, len); |
593 | break; | 593 | break; |
594 | } | 594 | } |
diff --git a/drivers/media/video/gspca/spca508.c b/drivers/media/video/gspca/spca508.c index b608a27ad115..699340c17dea 100644 --- a/drivers/media/video/gspca/spca508.c +++ b/drivers/media/video/gspca/spca508.c | |||
@@ -63,23 +63,23 @@ static struct ctrl sd_ctrls[] = { | |||
63 | }; | 63 | }; |
64 | 64 | ||
65 | static struct v4l2_pix_format sif_mode[] = { | 65 | static struct v4l2_pix_format sif_mode[] = { |
66 | {160, 120, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, | 66 | {160, 120, V4L2_PIX_FMT_SPCA508, V4L2_FIELD_NONE, |
67 | .bytesperline = 160 * 3, | 67 | .bytesperline = 160, |
68 | .sizeimage = 160 * 120 * 3 / 2, | 68 | .sizeimage = 160 * 120 * 3 / 2, |
69 | .colorspace = V4L2_COLORSPACE_SRGB, | 69 | .colorspace = V4L2_COLORSPACE_SRGB, |
70 | .priv = 3}, | 70 | .priv = 3}, |
71 | {176, 144, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, | 71 | {176, 144, V4L2_PIX_FMT_SPCA508, V4L2_FIELD_NONE, |
72 | .bytesperline = 176 * 3, | 72 | .bytesperline = 176, |
73 | .sizeimage = 176 * 144 * 3 / 2, | 73 | .sizeimage = 176 * 144 * 3 / 2, |
74 | .colorspace = V4L2_COLORSPACE_SRGB, | 74 | .colorspace = V4L2_COLORSPACE_SRGB, |
75 | .priv = 2}, | 75 | .priv = 2}, |
76 | {320, 240, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, | 76 | {320, 240, V4L2_PIX_FMT_SPCA508, V4L2_FIELD_NONE, |
77 | .bytesperline = 320 * 3, | 77 | .bytesperline = 320, |
78 | .sizeimage = 320 * 240 * 3 / 2, | 78 | .sizeimage = 320 * 240 * 3 / 2, |
79 | .colorspace = V4L2_COLORSPACE_SRGB, | 79 | .colorspace = V4L2_COLORSPACE_SRGB, |
80 | .priv = 1}, | 80 | .priv = 1}, |
81 | {352, 288, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, | 81 | {352, 288, V4L2_PIX_FMT_SPCA508, V4L2_FIELD_NONE, |
82 | .bytesperline = 352 * 3, | 82 | .bytesperline = 352, |
83 | .sizeimage = 352 * 288 * 3 / 2, | 83 | .sizeimage = 352 * 288 * 3 / 2, |
84 | .colorspace = V4L2_COLORSPACE_SRGB, | 84 | .colorspace = V4L2_COLORSPACE_SRGB, |
85 | .priv = 0}, | 85 | .priv = 0}, |
@@ -1583,7 +1583,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, | |||
1583 | default: | 1583 | default: |
1584 | data += 1; | 1584 | data += 1; |
1585 | len -= 1; | 1585 | len -= 1; |
1586 | gspca_frame_add(gspca_dev, FIRST_PACKET, frame, | 1586 | gspca_frame_add(gspca_dev, INTER_PACKET, frame, |
1587 | data, len); | 1587 | data, len); |
1588 | break; | 1588 | break; |
1589 | } | 1589 | } |
diff --git a/drivers/media/video/gspca/spca561.c b/drivers/media/video/gspca/spca561.c index a26174508cb9..1073ac3d2ec6 100644 --- a/drivers/media/video/gspca/spca561.c +++ b/drivers/media/video/gspca/spca561.c | |||
@@ -644,6 +644,18 @@ static void setcontrast(struct gspca_dev *gspca_dev) | |||
644 | } | 644 | } |
645 | } | 645 | } |
646 | 646 | ||
647 | static void setautogain(struct gspca_dev *gspca_dev) | ||
648 | { | ||
649 | struct sd *sd = (struct sd *) gspca_dev; | ||
650 | |||
651 | if (sd->chip_revision == Rev072A) { | ||
652 | if (sd->autogain) | ||
653 | sd->ag_cnt = AG_CNT_START; | ||
654 | else | ||
655 | sd->ag_cnt = -1; | ||
656 | } | ||
657 | } | ||
658 | |||
647 | static void sd_start(struct gspca_dev *gspca_dev) | 659 | static void sd_start(struct gspca_dev *gspca_dev) |
648 | { | 660 | { |
649 | struct sd *sd = (struct sd *) gspca_dev; | 661 | struct sd *sd = (struct sd *) gspca_dev; |
@@ -671,6 +683,7 @@ static void sd_start(struct gspca_dev *gspca_dev) | |||
671 | reg_w_val(dev, 0x8500, mode); /* mode */ | 683 | reg_w_val(dev, 0x8500, mode); /* mode */ |
672 | reg_w_val(dev, 0x8700, Clck); /* 0x27 clock */ | 684 | reg_w_val(dev, 0x8700, Clck); /* 0x27 clock */ |
673 | reg_w_val(dev, 0x8112, 0x10 | 0x20); | 685 | reg_w_val(dev, 0x8112, 0x10 | 0x20); |
686 | setautogain(gspca_dev); | ||
674 | break; | 687 | break; |
675 | default: | 688 | default: |
676 | /* case Rev012A: */ | 689 | /* case Rev012A: */ |
@@ -720,18 +733,24 @@ static void sd_close(struct gspca_dev *gspca_dev) | |||
720 | reg_w_val(gspca_dev->dev, 0x8114, 0); | 733 | reg_w_val(gspca_dev->dev, 0x8114, 0); |
721 | } | 734 | } |
722 | 735 | ||
723 | static void setautogain(struct gspca_dev *gspca_dev) | 736 | static void do_autogain(struct gspca_dev *gspca_dev) |
724 | { | 737 | { |
725 | struct sd *sd = (struct sd *) gspca_dev; | 738 | struct sd *sd = (struct sd *) gspca_dev; |
726 | int expotimes = 0; | 739 | int expotimes; |
727 | int pixelclk = 0; | 740 | int pixelclk; |
728 | int gainG = 0; | 741 | int gainG; |
729 | __u8 R, Gr, Gb, B; | 742 | __u8 R, Gr, Gb, B; |
730 | int y; | 743 | int y; |
731 | __u8 luma_mean = 110; | 744 | __u8 luma_mean = 110; |
732 | __u8 luma_delta = 20; | 745 | __u8 luma_delta = 20; |
733 | __u8 spring = 4; | 746 | __u8 spring = 4; |
734 | 747 | ||
748 | if (sd->ag_cnt < 0) | ||
749 | return; | ||
750 | if (--sd->ag_cnt >= 0) | ||
751 | return; | ||
752 | sd->ag_cnt = AG_CNT_START; | ||
753 | |||
735 | switch (sd->chip_revision) { | 754 | switch (sd->chip_revision) { |
736 | case Rev072A: | 755 | case Rev072A: |
737 | reg_r(gspca_dev, 0x8621, 1); | 756 | reg_r(gspca_dev, 0x8621, 1); |
@@ -795,18 +814,10 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, | |||
795 | __u8 *data, /* isoc packet */ | 814 | __u8 *data, /* isoc packet */ |
796 | int len) /* iso packet length */ | 815 | int len) /* iso packet length */ |
797 | { | 816 | { |
798 | struct sd *sd = (struct sd *) gspca_dev; | ||
799 | |||
800 | switch (data[0]) { | 817 | switch (data[0]) { |
801 | case 0: /* start of frame */ | 818 | case 0: /* start of frame */ |
802 | frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame, | 819 | frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame, |
803 | data, 0); | 820 | data, 0); |
804 | if (sd->ag_cnt >= 0) { | ||
805 | if (--sd->ag_cnt < 0) { | ||
806 | sd->ag_cnt = AG_CNT_START; | ||
807 | setautogain(gspca_dev); | ||
808 | } | ||
809 | } | ||
810 | data += SPCA561_OFFSET_DATA; | 821 | data += SPCA561_OFFSET_DATA; |
811 | len -= SPCA561_OFFSET_DATA; | 822 | len -= SPCA561_OFFSET_DATA; |
812 | if (data[1] & 0x10) { | 823 | if (data[1] & 0x10) { |
@@ -944,10 +955,8 @@ static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) | |||
944 | struct sd *sd = (struct sd *) gspca_dev; | 955 | struct sd *sd = (struct sd *) gspca_dev; |
945 | 956 | ||
946 | sd->autogain = val; | 957 | sd->autogain = val; |
947 | if (val) | 958 | if (gspca_dev->streaming) |
948 | sd->ag_cnt = AG_CNT_START; | 959 | setautogain(gspca_dev); |
949 | else | ||
950 | sd->ag_cnt = -1; | ||
951 | return 0; | 960 | return 0; |
952 | } | 961 | } |
953 | 962 | ||
@@ -971,6 +980,7 @@ static const struct sd_desc sd_desc = { | |||
971 | .stop0 = sd_stop0, | 980 | .stop0 = sd_stop0, |
972 | .close = sd_close, | 981 | .close = sd_close, |
973 | .pkt_scan = sd_pkt_scan, | 982 | .pkt_scan = sd_pkt_scan, |
983 | .dq_callback = do_autogain, | ||
974 | }; | 984 | }; |
975 | 985 | ||
976 | /* -- module initialisation -- */ | 986 | /* -- module initialisation -- */ |
diff --git a/drivers/media/video/gspca/vc032x.c b/drivers/media/video/gspca/vc032x.c index a4221753e1bf..f4a52956e0d9 100644 --- a/drivers/media/video/gspca/vc032x.c +++ b/drivers/media/video/gspca/vc032x.c | |||
@@ -88,12 +88,12 @@ static struct ctrl sd_ctrls[] = { | |||
88 | 88 | ||
89 | static struct v4l2_pix_format vc0321_mode[] = { | 89 | static struct v4l2_pix_format vc0321_mode[] = { |
90 | {320, 240, V4L2_PIX_FMT_YUV420, V4L2_FIELD_NONE, | 90 | {320, 240, V4L2_PIX_FMT_YUV420, V4L2_FIELD_NONE, |
91 | .bytesperline = 320 * 2, | 91 | .bytesperline = 320, |
92 | .sizeimage = 320 * 240 * 2, | 92 | .sizeimage = 320 * 240 * 2, |
93 | .colorspace = V4L2_COLORSPACE_SRGB, | 93 | .colorspace = V4L2_COLORSPACE_SRGB, |
94 | .priv = 1}, | 94 | .priv = 1}, |
95 | {640, 480, V4L2_PIX_FMT_YUV420, V4L2_FIELD_NONE, | 95 | {640, 480, V4L2_PIX_FMT_YUV420, V4L2_FIELD_NONE, |
96 | .bytesperline = 640 * 2, | 96 | .bytesperline = 640, |
97 | .sizeimage = 640 * 480 * 2, | 97 | .sizeimage = 640 * 480 * 2, |
98 | .colorspace = V4L2_COLORSPACE_SRGB, | 98 | .colorspace = V4L2_COLORSPACE_SRGB, |
99 | .priv = 0}, | 99 | .priv = 0}, |
diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c index 22a994ccb1d5..bc7d0eedcd81 100644 --- a/drivers/media/video/gspca/zc3xx.c +++ b/drivers/media/video/gspca/zc3xx.c | |||
@@ -6469,7 +6469,7 @@ static void setcontrast(struct gspca_dev *gspca_dev) | |||
6469 | NULL, Tgradient_1, Tgradient_2, | 6469 | NULL, Tgradient_1, Tgradient_2, |
6470 | Tgradient_3, Tgradient_4, Tgradient_5, Tgradient_6 | 6470 | Tgradient_3, Tgradient_4, Tgradient_5, Tgradient_6 |
6471 | }; | 6471 | }; |
6472 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 6472 | #ifdef GSPCA_DEBUG |
6473 | __u8 v[16]; | 6473 | __u8 v[16]; |
6474 | #endif | 6474 | #endif |
6475 | 6475 | ||
@@ -6487,7 +6487,7 @@ static void setcontrast(struct gspca_dev *gspca_dev) | |||
6487 | else if (g <= 0) | 6487 | else if (g <= 0) |
6488 | g = 1; | 6488 | g = 1; |
6489 | reg_w(dev, g, 0x0120 + i); /* gamma */ | 6489 | reg_w(dev, g, 0x0120 + i); /* gamma */ |
6490 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 6490 | #ifdef GSPCA_DEBUG |
6491 | if (gspca_debug & D_CONF) | 6491 | if (gspca_debug & D_CONF) |
6492 | v[i] = g; | 6492 | v[i] = g; |
6493 | #endif | 6493 | #endif |
@@ -6507,7 +6507,7 @@ static void setcontrast(struct gspca_dev *gspca_dev) | |||
6507 | g = 1; | 6507 | g = 1; |
6508 | } | 6508 | } |
6509 | reg_w(dev, g, 0x0130 + i); /* gradient */ | 6509 | reg_w(dev, g, 0x0130 + i); /* gradient */ |
6510 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 6510 | #ifdef GSPCA_DEBUG |
6511 | if (gspca_debug & D_CONF) | 6511 | if (gspca_debug & D_CONF) |
6512 | v[i] = g; | 6512 | v[i] = g; |
6513 | #endif | 6513 | #endif |
diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c index b15f82c49766..ead87ddaf7fb 100644 --- a/drivers/media/video/pxa_camera.c +++ b/drivers/media/video/pxa_camera.c | |||
@@ -128,6 +128,8 @@ struct pxa_camera_dev { | |||
128 | 128 | ||
129 | struct pxa_buffer *active; | 129 | struct pxa_buffer *active; |
130 | struct pxa_dma_desc *sg_tail[3]; | 130 | struct pxa_dma_desc *sg_tail[3]; |
131 | |||
132 | u32 save_cicr[5]; | ||
131 | }; | 133 | }; |
132 | 134 | ||
133 | static const char *pxa_cam_driver_description = "PXA_Camera"; | 135 | static const char *pxa_cam_driver_description = "PXA_Camera"; |
@@ -997,10 +999,64 @@ static int pxa_camera_querycap(struct soc_camera_host *ici, | |||
997 | return 0; | 999 | return 0; |
998 | } | 1000 | } |
999 | 1001 | ||
1002 | static int pxa_camera_suspend(struct soc_camera_device *icd, pm_message_t state) | ||
1003 | { | ||
1004 | struct soc_camera_host *ici = | ||
1005 | to_soc_camera_host(icd->dev.parent); | ||
1006 | struct pxa_camera_dev *pcdev = ici->priv; | ||
1007 | int i = 0, ret = 0; | ||
1008 | |||
1009 | pcdev->save_cicr[i++] = CICR0; | ||
1010 | pcdev->save_cicr[i++] = CICR1; | ||
1011 | pcdev->save_cicr[i++] = CICR2; | ||
1012 | pcdev->save_cicr[i++] = CICR3; | ||
1013 | pcdev->save_cicr[i++] = CICR4; | ||
1014 | |||
1015 | if ((pcdev->icd) && (pcdev->icd->ops->suspend)) | ||
1016 | ret = pcdev->icd->ops->suspend(pcdev->icd, state); | ||
1017 | |||
1018 | return ret; | ||
1019 | } | ||
1020 | |||
1021 | static int pxa_camera_resume(struct soc_camera_device *icd) | ||
1022 | { | ||
1023 | struct soc_camera_host *ici = | ||
1024 | to_soc_camera_host(icd->dev.parent); | ||
1025 | struct pxa_camera_dev *pcdev = ici->priv; | ||
1026 | int i = 0, ret = 0; | ||
1027 | |||
1028 | DRCMR68 = pcdev->dma_chans[0] | DRCMR_MAPVLD; | ||
1029 | DRCMR69 = pcdev->dma_chans[1] | DRCMR_MAPVLD; | ||
1030 | DRCMR70 = pcdev->dma_chans[2] | DRCMR_MAPVLD; | ||
1031 | |||
1032 | CICR0 = pcdev->save_cicr[i++] & ~CICR0_ENB; | ||
1033 | CICR1 = pcdev->save_cicr[i++]; | ||
1034 | CICR2 = pcdev->save_cicr[i++]; | ||
1035 | CICR3 = pcdev->save_cicr[i++]; | ||
1036 | CICR4 = pcdev->save_cicr[i++]; | ||
1037 | |||
1038 | if ((pcdev->icd) && (pcdev->icd->ops->resume)) | ||
1039 | ret = pcdev->icd->ops->resume(pcdev->icd); | ||
1040 | |||
1041 | /* Restart frame capture if active buffer exists */ | ||
1042 | if (!ret && pcdev->active) { | ||
1043 | /* Reset the FIFOs */ | ||
1044 | CIFR |= CIFR_RESET_F; | ||
1045 | /* Enable End-Of-Frame Interrupt */ | ||
1046 | CICR0 &= ~CICR0_EOFM; | ||
1047 | /* Restart the Capture Interface */ | ||
1048 | CICR0 |= CICR0_ENB; | ||
1049 | } | ||
1050 | |||
1051 | return ret; | ||
1052 | } | ||
1053 | |||
1000 | static struct soc_camera_host_ops pxa_soc_camera_host_ops = { | 1054 | static struct soc_camera_host_ops pxa_soc_camera_host_ops = { |
1001 | .owner = THIS_MODULE, | 1055 | .owner = THIS_MODULE, |
1002 | .add = pxa_camera_add_device, | 1056 | .add = pxa_camera_add_device, |
1003 | .remove = pxa_camera_remove_device, | 1057 | .remove = pxa_camera_remove_device, |
1058 | .suspend = pxa_camera_suspend, | ||
1059 | .resume = pxa_camera_resume, | ||
1004 | .set_fmt_cap = pxa_camera_set_fmt_cap, | 1060 | .set_fmt_cap = pxa_camera_set_fmt_cap, |
1005 | .try_fmt_cap = pxa_camera_try_fmt_cap, | 1061 | .try_fmt_cap = pxa_camera_try_fmt_cap, |
1006 | .init_videobuf = pxa_camera_init_videobuf, | 1062 | .init_videobuf = pxa_camera_init_videobuf, |
@@ -1198,7 +1254,7 @@ static int __devinit pxa_camera_init(void) | |||
1198 | 1254 | ||
1199 | static void __exit pxa_camera_exit(void) | 1255 | static void __exit pxa_camera_exit(void) |
1200 | { | 1256 | { |
1201 | return platform_driver_unregister(&pxa_camera_driver); | 1257 | platform_driver_unregister(&pxa_camera_driver); |
1202 | } | 1258 | } |
1203 | 1259 | ||
1204 | module_init(pxa_camera_init); | 1260 | module_init(pxa_camera_init); |
diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index f7ca3cb9340a..318754e73132 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c | |||
@@ -647,7 +647,7 @@ static int __init sh_mobile_ceu_init(void) | |||
647 | 647 | ||
648 | static void __exit sh_mobile_ceu_exit(void) | 648 | static void __exit sh_mobile_ceu_exit(void) |
649 | { | 649 | { |
650 | return platform_driver_unregister(&sh_mobile_ceu_driver); | 650 | platform_driver_unregister(&sh_mobile_ceu_driver); |
651 | } | 651 | } |
652 | 652 | ||
653 | module_init(sh_mobile_ceu_init); | 653 | module_init(sh_mobile_ceu_init); |
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index b6be5ee678b6..66ebe5956a87 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c | |||
@@ -732,10 +732,36 @@ static int soc_camera_remove(struct device *dev) | |||
732 | return 0; | 732 | return 0; |
733 | } | 733 | } |
734 | 734 | ||
735 | static int soc_camera_suspend(struct device *dev, pm_message_t state) | ||
736 | { | ||
737 | struct soc_camera_device *icd = to_soc_camera_dev(dev); | ||
738 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | ||
739 | int ret = 0; | ||
740 | |||
741 | if (ici->ops->suspend) | ||
742 | ret = ici->ops->suspend(icd, state); | ||
743 | |||
744 | return ret; | ||
745 | } | ||
746 | |||
747 | static int soc_camera_resume(struct device *dev) | ||
748 | { | ||
749 | struct soc_camera_device *icd = to_soc_camera_dev(dev); | ||
750 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | ||
751 | int ret = 0; | ||
752 | |||
753 | if (ici->ops->resume) | ||
754 | ret = ici->ops->resume(icd); | ||
755 | |||
756 | return ret; | ||
757 | } | ||
758 | |||
735 | static struct bus_type soc_camera_bus_type = { | 759 | static struct bus_type soc_camera_bus_type = { |
736 | .name = "soc-camera", | 760 | .name = "soc-camera", |
737 | .probe = soc_camera_probe, | 761 | .probe = soc_camera_probe, |
738 | .remove = soc_camera_remove, | 762 | .remove = soc_camera_remove, |
763 | .suspend = soc_camera_suspend, | ||
764 | .resume = soc_camera_resume, | ||
739 | }; | 765 | }; |
740 | 766 | ||
741 | static struct device_driver ic_drv = { | 767 | static struct device_driver ic_drv = { |
diff --git a/drivers/media/video/soc_camera_platform.c b/drivers/media/video/soc_camera_platform.c index eefb0327ebb6..1adc257ebdb9 100644 --- a/drivers/media/video/soc_camera_platform.c +++ b/drivers/media/video/soc_camera_platform.c | |||
@@ -187,7 +187,7 @@ static int __init soc_camera_platform_module_init(void) | |||
187 | 187 | ||
188 | static void __exit soc_camera_platform_module_exit(void) | 188 | static void __exit soc_camera_platform_module_exit(void) |
189 | { | 189 | { |
190 | return platform_driver_unregister(&soc_camera_platform_driver); | 190 | platform_driver_unregister(&soc_camera_platform_driver); |
191 | } | 191 | } |
192 | 192 | ||
193 | module_init(soc_camera_platform_module_init); | 193 | module_init(soc_camera_platform_module_init); |
diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c index 626f4ad7e876..6ef3e5297de8 100644 --- a/drivers/media/video/uvc/uvc_ctrl.c +++ b/drivers/media/video/uvc/uvc_ctrl.c | |||
@@ -585,13 +585,17 @@ int uvc_query_v4l2_ctrl(struct uvc_video_device *video, | |||
585 | struct uvc_control_mapping *mapping; | 585 | struct uvc_control_mapping *mapping; |
586 | struct uvc_menu_info *menu; | 586 | struct uvc_menu_info *menu; |
587 | unsigned int i; | 587 | unsigned int i; |
588 | __u8 data[8]; | 588 | __u8 *data; |
589 | int ret; | 589 | int ret; |
590 | 590 | ||
591 | ctrl = uvc_find_control(video, v4l2_ctrl->id, &mapping); | 591 | ctrl = uvc_find_control(video, v4l2_ctrl->id, &mapping); |
592 | if (ctrl == NULL) | 592 | if (ctrl == NULL) |
593 | return -EINVAL; | 593 | return -EINVAL; |
594 | 594 | ||
595 | data = kmalloc(8, GFP_KERNEL); | ||
596 | if (data == NULL) | ||
597 | return -ENOMEM; | ||
598 | |||
595 | memset(v4l2_ctrl, 0, sizeof *v4l2_ctrl); | 599 | memset(v4l2_ctrl, 0, sizeof *v4l2_ctrl); |
596 | v4l2_ctrl->id = mapping->id; | 600 | v4l2_ctrl->id = mapping->id; |
597 | v4l2_ctrl->type = mapping->v4l2_type; | 601 | v4l2_ctrl->type = mapping->v4l2_type; |
@@ -604,8 +608,8 @@ int uvc_query_v4l2_ctrl(struct uvc_video_device *video, | |||
604 | if (ctrl->info->flags & UVC_CONTROL_GET_DEF) { | 608 | if (ctrl->info->flags & UVC_CONTROL_GET_DEF) { |
605 | if ((ret = uvc_query_ctrl(video->dev, GET_DEF, ctrl->entity->id, | 609 | if ((ret = uvc_query_ctrl(video->dev, GET_DEF, ctrl->entity->id, |
606 | video->dev->intfnum, ctrl->info->selector, | 610 | video->dev->intfnum, ctrl->info->selector, |
607 | &data, ctrl->info->size)) < 0) | 611 | data, ctrl->info->size)) < 0) |
608 | return ret; | 612 | goto out; |
609 | v4l2_ctrl->default_value = uvc_get_le_value(data, mapping); | 613 | v4l2_ctrl->default_value = uvc_get_le_value(data, mapping); |
610 | } | 614 | } |
611 | 615 | ||
@@ -623,13 +627,15 @@ int uvc_query_v4l2_ctrl(struct uvc_video_device *video, | |||
623 | } | 627 | } |
624 | } | 628 | } |
625 | 629 | ||
626 | return 0; | 630 | ret = 0; |
631 | goto out; | ||
627 | 632 | ||
628 | case V4L2_CTRL_TYPE_BOOLEAN: | 633 | case V4L2_CTRL_TYPE_BOOLEAN: |
629 | v4l2_ctrl->minimum = 0; | 634 | v4l2_ctrl->minimum = 0; |
630 | v4l2_ctrl->maximum = 1; | 635 | v4l2_ctrl->maximum = 1; |
631 | v4l2_ctrl->step = 1; | 636 | v4l2_ctrl->step = 1; |
632 | return 0; | 637 | ret = 0; |
638 | goto out; | ||
633 | 639 | ||
634 | default: | 640 | default: |
635 | break; | 641 | break; |
@@ -638,26 +644,29 @@ int uvc_query_v4l2_ctrl(struct uvc_video_device *video, | |||
638 | if (ctrl->info->flags & UVC_CONTROL_GET_MIN) { | 644 | if (ctrl->info->flags & UVC_CONTROL_GET_MIN) { |
639 | if ((ret = uvc_query_ctrl(video->dev, GET_MIN, ctrl->entity->id, | 645 | if ((ret = uvc_query_ctrl(video->dev, GET_MIN, ctrl->entity->id, |
640 | video->dev->intfnum, ctrl->info->selector, | 646 | video->dev->intfnum, ctrl->info->selector, |
641 | &data, ctrl->info->size)) < 0) | 647 | data, ctrl->info->size)) < 0) |
642 | return ret; | 648 | goto out; |
643 | v4l2_ctrl->minimum = uvc_get_le_value(data, mapping); | 649 | v4l2_ctrl->minimum = uvc_get_le_value(data, mapping); |
644 | } | 650 | } |
645 | if (ctrl->info->flags & UVC_CONTROL_GET_MAX) { | 651 | if (ctrl->info->flags & UVC_CONTROL_GET_MAX) { |
646 | if ((ret = uvc_query_ctrl(video->dev, GET_MAX, ctrl->entity->id, | 652 | if ((ret = uvc_query_ctrl(video->dev, GET_MAX, ctrl->entity->id, |
647 | video->dev->intfnum, ctrl->info->selector, | 653 | video->dev->intfnum, ctrl->info->selector, |
648 | &data, ctrl->info->size)) < 0) | 654 | data, ctrl->info->size)) < 0) |
649 | return ret; | 655 | goto out; |
650 | v4l2_ctrl->maximum = uvc_get_le_value(data, mapping); | 656 | v4l2_ctrl->maximum = uvc_get_le_value(data, mapping); |
651 | } | 657 | } |
652 | if (ctrl->info->flags & UVC_CONTROL_GET_RES) { | 658 | if (ctrl->info->flags & UVC_CONTROL_GET_RES) { |
653 | if ((ret = uvc_query_ctrl(video->dev, GET_RES, ctrl->entity->id, | 659 | if ((ret = uvc_query_ctrl(video->dev, GET_RES, ctrl->entity->id, |
654 | video->dev->intfnum, ctrl->info->selector, | 660 | video->dev->intfnum, ctrl->info->selector, |
655 | &data, ctrl->info->size)) < 0) | 661 | data, ctrl->info->size)) < 0) |
656 | return ret; | 662 | goto out; |
657 | v4l2_ctrl->step = uvc_get_le_value(data, mapping); | 663 | v4l2_ctrl->step = uvc_get_le_value(data, mapping); |
658 | } | 664 | } |
659 | 665 | ||
660 | return 0; | 666 | ret = 0; |
667 | out: | ||
668 | kfree(data); | ||
669 | return ret; | ||
661 | } | 670 | } |
662 | 671 | ||
663 | 672 | ||
diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c index b3c4d75e8490..7e102034d38d 100644 --- a/drivers/media/video/uvc/uvc_driver.c +++ b/drivers/media/video/uvc/uvc_driver.c | |||
@@ -1884,7 +1884,7 @@ static struct usb_device_id uvc_ids[] = { | |||
1884 | .bInterfaceSubClass = 1, | 1884 | .bInterfaceSubClass = 1, |
1885 | .bInterfaceProtocol = 0, | 1885 | .bInterfaceProtocol = 0, |
1886 | .driver_info = UVC_QUIRK_PROBE_MINMAX }, | 1886 | .driver_info = UVC_QUIRK_PROBE_MINMAX }, |
1887 | /* Packard Bell OEM Webcam */ | 1887 | /* Packard Bell OEM Webcam - Bison Electronics */ |
1888 | { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | 1888 | { .match_flags = USB_DEVICE_ID_MATCH_DEVICE |
1889 | | USB_DEVICE_ID_MATCH_INT_INFO, | 1889 | | USB_DEVICE_ID_MATCH_INT_INFO, |
1890 | .idVendor = 0x5986, | 1890 | .idVendor = 0x5986, |
@@ -1893,7 +1893,7 @@ static struct usb_device_id uvc_ids[] = { | |||
1893 | .bInterfaceSubClass = 1, | 1893 | .bInterfaceSubClass = 1, |
1894 | .bInterfaceProtocol = 0, | 1894 | .bInterfaceProtocol = 0, |
1895 | .driver_info = UVC_QUIRK_PROBE_MINMAX }, | 1895 | .driver_info = UVC_QUIRK_PROBE_MINMAX }, |
1896 | /* Acer Crystal Eye webcam */ | 1896 | /* Acer Crystal Eye webcam - Bison Electronics */ |
1897 | { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | 1897 | { .match_flags = USB_DEVICE_ID_MATCH_DEVICE |
1898 | | USB_DEVICE_ID_MATCH_INT_INFO, | 1898 | | USB_DEVICE_ID_MATCH_INT_INFO, |
1899 | .idVendor = 0x5986, | 1899 | .idVendor = 0x5986, |
@@ -1902,7 +1902,7 @@ static struct usb_device_id uvc_ids[] = { | |||
1902 | .bInterfaceSubClass = 1, | 1902 | .bInterfaceSubClass = 1, |
1903 | .bInterfaceProtocol = 0, | 1903 | .bInterfaceProtocol = 0, |
1904 | .driver_info = UVC_QUIRK_PROBE_MINMAX }, | 1904 | .driver_info = UVC_QUIRK_PROBE_MINMAX }, |
1905 | /* Medion Akoya Mini E1210 */ | 1905 | /* Medion Akoya Mini E1210 - Bison Electronics */ |
1906 | { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | 1906 | { .match_flags = USB_DEVICE_ID_MATCH_DEVICE |
1907 | | USB_DEVICE_ID_MATCH_INT_INFO, | 1907 | | USB_DEVICE_ID_MATCH_INT_INFO, |
1908 | .idVendor = 0x5986, | 1908 | .idVendor = 0x5986, |
@@ -1911,7 +1911,7 @@ static struct usb_device_id uvc_ids[] = { | |||
1911 | .bInterfaceSubClass = 1, | 1911 | .bInterfaceSubClass = 1, |
1912 | .bInterfaceProtocol = 0, | 1912 | .bInterfaceProtocol = 0, |
1913 | .driver_info = UVC_QUIRK_PROBE_MINMAX }, | 1913 | .driver_info = UVC_QUIRK_PROBE_MINMAX }, |
1914 | /* Acer OrbiCam - Unknown vendor */ | 1914 | /* Acer OrbiCam - Bison Electronics */ |
1915 | { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | 1915 | { .match_flags = USB_DEVICE_ID_MATCH_DEVICE |
1916 | | USB_DEVICE_ID_MATCH_INT_INFO, | 1916 | | USB_DEVICE_ID_MATCH_INT_INFO, |
1917 | .idVendor = 0x5986, | 1917 | .idVendor = 0x5986, |
@@ -1920,6 +1920,24 @@ static struct usb_device_id uvc_ids[] = { | |||
1920 | .bInterfaceSubClass = 1, | 1920 | .bInterfaceSubClass = 1, |
1921 | .bInterfaceProtocol = 0, | 1921 | .bInterfaceProtocol = 0, |
1922 | .driver_info = UVC_QUIRK_PROBE_MINMAX }, | 1922 | .driver_info = UVC_QUIRK_PROBE_MINMAX }, |
1923 | /* Bison Electronics */ | ||
1924 | { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | ||
1925 | | USB_DEVICE_ID_MATCH_INT_INFO, | ||
1926 | .idVendor = 0x5986, | ||
1927 | .idProduct = 0x0300, | ||
1928 | .bInterfaceClass = USB_CLASS_VIDEO, | ||
1929 | .bInterfaceSubClass = 1, | ||
1930 | .bInterfaceProtocol = 0, | ||
1931 | .driver_info = UVC_QUIRK_PROBE_MINMAX }, | ||
1932 | /* Clevo M570TU - Bison Electronics */ | ||
1933 | { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | ||
1934 | | USB_DEVICE_ID_MATCH_INT_INFO, | ||
1935 | .idVendor = 0x5986, | ||
1936 | .idProduct = 0x0303, | ||
1937 | .bInterfaceClass = USB_CLASS_VIDEO, | ||
1938 | .bInterfaceSubClass = 1, | ||
1939 | .bInterfaceProtocol = 0, | ||
1940 | .driver_info = UVC_QUIRK_PROBE_MINMAX }, | ||
1923 | /* Generic USB Video Class */ | 1941 | /* Generic USB Video Class */ |
1924 | { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) }, | 1942 | { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) }, |
1925 | {} | 1943 | {} |
diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c index ad63794fda77..6854ac78a161 100644 --- a/drivers/media/video/uvc/uvc_video.c +++ b/drivers/media/video/uvc/uvc_video.c | |||
@@ -90,17 +90,20 @@ static void uvc_fixup_buffer_size(struct uvc_video_device *video, | |||
90 | static int uvc_get_video_ctrl(struct uvc_video_device *video, | 90 | static int uvc_get_video_ctrl(struct uvc_video_device *video, |
91 | struct uvc_streaming_control *ctrl, int probe, __u8 query) | 91 | struct uvc_streaming_control *ctrl, int probe, __u8 query) |
92 | { | 92 | { |
93 | __u8 data[34]; | 93 | __u8 *data; |
94 | __u8 size; | 94 | __u16 size; |
95 | int ret; | 95 | int ret; |
96 | 96 | ||
97 | size = video->dev->uvc_version >= 0x0110 ? 34 : 26; | 97 | size = video->dev->uvc_version >= 0x0110 ? 34 : 26; |
98 | data = kmalloc(size, GFP_KERNEL); | ||
99 | if (data == NULL) | ||
100 | return -ENOMEM; | ||
101 | |||
98 | ret = __uvc_query_ctrl(video->dev, query, 0, video->streaming->intfnum, | 102 | ret = __uvc_query_ctrl(video->dev, query, 0, video->streaming->intfnum, |
99 | probe ? VS_PROBE_CONTROL : VS_COMMIT_CONTROL, &data, size, | 103 | probe ? VS_PROBE_CONTROL : VS_COMMIT_CONTROL, data, size, |
100 | UVC_CTRL_STREAMING_TIMEOUT); | 104 | UVC_CTRL_STREAMING_TIMEOUT); |
101 | |||
102 | if (ret < 0) | 105 | if (ret < 0) |
103 | return ret; | 106 | goto out; |
104 | 107 | ||
105 | ctrl->bmHint = le16_to_cpup((__le16 *)&data[0]); | 108 | ctrl->bmHint = le16_to_cpup((__le16 *)&data[0]); |
106 | ctrl->bFormatIndex = data[2]; | 109 | ctrl->bFormatIndex = data[2]; |
@@ -136,17 +139,22 @@ static int uvc_get_video_ctrl(struct uvc_video_device *video, | |||
136 | */ | 139 | */ |
137 | uvc_fixup_buffer_size(video, ctrl); | 140 | uvc_fixup_buffer_size(video, ctrl); |
138 | 141 | ||
139 | return 0; | 142 | out: |
143 | kfree(data); | ||
144 | return ret; | ||
140 | } | 145 | } |
141 | 146 | ||
142 | int uvc_set_video_ctrl(struct uvc_video_device *video, | 147 | int uvc_set_video_ctrl(struct uvc_video_device *video, |
143 | struct uvc_streaming_control *ctrl, int probe) | 148 | struct uvc_streaming_control *ctrl, int probe) |
144 | { | 149 | { |
145 | __u8 data[34]; | 150 | __u8 *data; |
146 | __u8 size; | 151 | __u16 size; |
152 | int ret; | ||
147 | 153 | ||
148 | size = video->dev->uvc_version >= 0x0110 ? 34 : 26; | 154 | size = video->dev->uvc_version >= 0x0110 ? 34 : 26; |
149 | memset(data, 0, sizeof data); | 155 | data = kzalloc(size, GFP_KERNEL); |
156 | if (data == NULL) | ||
157 | return -ENOMEM; | ||
150 | 158 | ||
151 | *(__le16 *)&data[0] = cpu_to_le16(ctrl->bmHint); | 159 | *(__le16 *)&data[0] = cpu_to_le16(ctrl->bmHint); |
152 | data[2] = ctrl->bFormatIndex; | 160 | data[2] = ctrl->bFormatIndex; |
@@ -174,10 +182,13 @@ int uvc_set_video_ctrl(struct uvc_video_device *video, | |||
174 | data[33] = ctrl->bMaxVersion; | 182 | data[33] = ctrl->bMaxVersion; |
175 | } | 183 | } |
176 | 184 | ||
177 | return __uvc_query_ctrl(video->dev, SET_CUR, 0, | 185 | ret = __uvc_query_ctrl(video->dev, SET_CUR, 0, |
178 | video->streaming->intfnum, | 186 | video->streaming->intfnum, |
179 | probe ? VS_PROBE_CONTROL : VS_COMMIT_CONTROL, &data, size, | 187 | probe ? VS_PROBE_CONTROL : VS_COMMIT_CONTROL, data, size, |
180 | UVC_CTRL_STREAMING_TIMEOUT); | 188 | UVC_CTRL_STREAMING_TIMEOUT); |
189 | |||
190 | kfree(data); | ||
191 | return ret; | ||
181 | } | 192 | } |
182 | 193 | ||
183 | int uvc_probe_video(struct uvc_video_device *video, | 194 | int uvc_probe_video(struct uvc_video_device *video, |
diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c index 556615fe93de..6f36006aecda 100644 --- a/drivers/media/video/v4l2-dev.c +++ b/drivers/media/video/v4l2-dev.c | |||
@@ -222,11 +222,13 @@ int video_register_device(struct video_device *vfd, int type, int nr) | |||
222 | EXPORT_SYMBOL(video_register_device); | 222 | EXPORT_SYMBOL(video_register_device); |
223 | 223 | ||
224 | /** | 224 | /** |
225 | * video_register_device - register video4linux devices | 225 | * video_register_device_index - register video4linux devices |
226 | * @vfd: video device structure we want to register | 226 | * @vfd: video device structure we want to register |
227 | * @type: type of device to register | 227 | * @type: type of device to register |
228 | * @nr: which device number (0 == /dev/video0, 1 == /dev/video1, ... | 228 | * @nr: which device number (0 == /dev/video0, 1 == /dev/video1, ... |
229 | * -1 == first free) | 229 | * -1 == first free) |
230 | * @index: stream number based on parent device; | ||
231 | * -1 if auto assign, requested number otherwise | ||
230 | * | 232 | * |
231 | * The registration code assigns minor numbers based on the type | 233 | * The registration code assigns minor numbers based on the type |
232 | * requested. -ENFILE is returned in all the device slots for this | 234 | * requested. -ENFILE is returned in all the device slots for this |
diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c index ef7572cbc4ab..1edda456fc64 100644 --- a/drivers/media/video/vino.c +++ b/drivers/media/video/vino.c | |||
@@ -41,6 +41,7 @@ | |||
41 | #include <linux/videodev2.h> | 41 | #include <linux/videodev2.h> |
42 | #include <media/v4l2-ioctl.h> | 42 | #include <media/v4l2-ioctl.h> |
43 | #include <media/v4l2-common.h> | 43 | #include <media/v4l2-common.h> |
44 | #include <media/v4l2-ioctl.h> | ||
44 | #include <linux/video_decoder.h> | 45 | #include <linux/video_decoder.h> |
45 | #include <linux/mutex.h> | 46 | #include <linux/mutex.h> |
46 | 47 | ||
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 82af385460e4..a726f3b01a6b 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig | |||
@@ -427,10 +427,10 @@ config ENCLOSURE_SERVICES | |||
427 | config SGI_XP | 427 | config SGI_XP |
428 | tristate "Support communication between SGI SSIs" | 428 | tristate "Support communication between SGI SSIs" |
429 | depends on NET | 429 | depends on NET |
430 | depends on IA64_GENERIC || IA64_SGI_SN2 || IA64_SGI_UV || (X86_64 && SMP) | 430 | depends on (IA64_GENERIC || IA64_SGI_SN2 || IA64_SGI_UV || X86_64) && SMP |
431 | select IA64_UNCACHED_ALLOCATOR if IA64_GENERIC || IA64_SGI_SN2 | 431 | select IA64_UNCACHED_ALLOCATOR if IA64_GENERIC || IA64_SGI_SN2 |
432 | select GENERIC_ALLOCATOR if IA64_GENERIC || IA64_SGI_SN2 | 432 | select GENERIC_ALLOCATOR if IA64_GENERIC || IA64_SGI_SN2 |
433 | select SGI_GRU if IA64_GENERIC || IA64_SGI_UV || (X86_64 && SMP) | 433 | select SGI_GRU if (IA64_GENERIC || IA64_SGI_UV || X86_64) && SMP |
434 | ---help--- | 434 | ---help--- |
435 | An SGI machine can be divided into multiple Single System | 435 | An SGI machine can be divided into multiple Single System |
436 | Images which act independently of each other and have | 436 | Images which act independently of each other and have |
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 48399e134c0d..32b9fe153641 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig | |||
@@ -463,7 +463,7 @@ config PC87413_WDT | |||
463 | module will be called pc87413_wdt. | 463 | module will be called pc87413_wdt. |
464 | 464 | ||
465 | Most people will say N. | 465 | Most people will say N. |
466 | 466 | ||
467 | config 60XX_WDT | 467 | config 60XX_WDT |
468 | tristate "SBC-60XX Watchdog Timer" | 468 | tristate "SBC-60XX Watchdog Timer" |
469 | depends on X86 | 469 | depends on X86 |
@@ -695,9 +695,17 @@ config 8xx_WDT | |||
695 | tristate "MPC8xx Watchdog Timer" | 695 | tristate "MPC8xx Watchdog Timer" |
696 | depends on 8xx | 696 | depends on 8xx |
697 | 697 | ||
698 | config 83xx_WDT | 698 | config 8xxx_WDT |
699 | tristate "MPC83xx Watchdog Timer" | 699 | tristate "MPC8xxx Platform Watchdog Timer" |
700 | depends on PPC_83xx | 700 | depends on PPC_8xx || PPC_83xx || PPC_86xx |
701 | help | ||
702 | This driver is for a SoC level watchdog that exists on some | ||
703 | Freescale PowerPC processors. So far this driver supports: | ||
704 | - MPC8xx watchdogs | ||
705 | - MPC83xx watchdogs | ||
706 | - MPC86xx watchdogs | ||
707 | |||
708 | For BookE processors (MPC85xx) use the BOOKE_WDT driver instead. | ||
701 | 709 | ||
702 | config MV64X60_WDT | 710 | config MV64X60_WDT |
703 | tristate "MV64X60 (Marvell Discovery) Watchdog Timer" | 711 | tristate "MV64X60 (Marvell Discovery) Watchdog Timer" |
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index edd305a64e63..049c91895699 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile | |||
@@ -92,7 +92,7 @@ obj-$(CONFIG_SBC_EPX_C3_WATCHDOG) += sbc_epx_c3.o | |||
92 | 92 | ||
93 | # MIPS Architecture | 93 | # MIPS Architecture |
94 | obj-$(CONFIG_INDYDOG) += indydog.o | 94 | obj-$(CONFIG_INDYDOG) += indydog.o |
95 | obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o | 95 | obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o |
96 | obj-$(CONFIG_WDT_RM9K_GPI) += rm9k_wdt.o | 96 | obj-$(CONFIG_WDT_RM9K_GPI) += rm9k_wdt.o |
97 | obj-$(CONFIG_SIBYTE_WDOG) += sb_wdog.o | 97 | obj-$(CONFIG_SIBYTE_WDOG) += sb_wdog.o |
98 | obj-$(CONFIG_AR7_WDT) += ar7_wdt.o | 98 | obj-$(CONFIG_AR7_WDT) += ar7_wdt.o |
@@ -103,7 +103,7 @@ obj-$(CONFIG_TXX9_WDT) += txx9wdt.o | |||
103 | # POWERPC Architecture | 103 | # POWERPC Architecture |
104 | obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o | 104 | obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o |
105 | obj-$(CONFIG_MPC5200_WDT) += mpc5200_wdt.o | 105 | obj-$(CONFIG_MPC5200_WDT) += mpc5200_wdt.o |
106 | obj-$(CONFIG_83xx_WDT) += mpc83xx_wdt.o | 106 | obj-$(CONFIG_8xxx_WDT) += mpc8xxx_wdt.o |
107 | obj-$(CONFIG_MV64X60_WDT) += mv64x60_wdt.o | 107 | obj-$(CONFIG_MV64X60_WDT) += mv64x60_wdt.o |
108 | obj-$(CONFIG_BOOKE_WDT) += booke_wdt.o | 108 | obj-$(CONFIG_BOOKE_WDT) += booke_wdt.o |
109 | 109 | ||
diff --git a/drivers/watchdog/acquirewdt.c b/drivers/watchdog/acquirewdt.c index 85269c365a10..6e46a551395c 100644 --- a/drivers/watchdog/acquirewdt.c +++ b/drivers/watchdog/acquirewdt.c | |||
@@ -58,39 +58,45 @@ | |||
58 | #include <linux/types.h> /* For standard types (like size_t) */ | 58 | #include <linux/types.h> /* For standard types (like size_t) */ |
59 | #include <linux/errno.h> /* For the -ENODEV/... values */ | 59 | #include <linux/errno.h> /* For the -ENODEV/... values */ |
60 | #include <linux/kernel.h> /* For printk/panic/... */ | 60 | #include <linux/kernel.h> /* For printk/panic/... */ |
61 | #include <linux/miscdevice.h> /* For MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR) */ | 61 | #include <linux/miscdevice.h> /* For MODULE_ALIAS_MISCDEV |
62 | (WATCHDOG_MINOR) */ | ||
62 | #include <linux/watchdog.h> /* For the watchdog specific items */ | 63 | #include <linux/watchdog.h> /* For the watchdog specific items */ |
63 | #include <linux/fs.h> /* For file operations */ | 64 | #include <linux/fs.h> /* For file operations */ |
64 | #include <linux/ioport.h> /* For io-port access */ | 65 | #include <linux/ioport.h> /* For io-port access */ |
65 | #include <linux/platform_device.h> /* For platform_driver framework */ | 66 | #include <linux/platform_device.h> /* For platform_driver framework */ |
66 | #include <linux/init.h> /* For __init/__exit/... */ | 67 | #include <linux/init.h> /* For __init/__exit/... */ |
67 | 68 | #include <linux/uaccess.h> /* For copy_to_user/put_user/... */ | |
68 | #include <asm/uaccess.h> /* For copy_to_user/put_user/... */ | 69 | #include <linux/io.h> /* For inb/outb/... */ |
69 | #include <asm/io.h> /* For inb/outb/... */ | ||
70 | 70 | ||
71 | /* Module information */ | 71 | /* Module information */ |
72 | #define DRV_NAME "acquirewdt" | 72 | #define DRV_NAME "acquirewdt" |
73 | #define PFX DRV_NAME ": " | 73 | #define PFX DRV_NAME ": " |
74 | #define WATCHDOG_NAME "Acquire WDT" | 74 | #define WATCHDOG_NAME "Acquire WDT" |
75 | #define WATCHDOG_HEARTBEAT 0 /* There is no way to see what the correct time-out period is */ | 75 | /* There is no way to see what the correct time-out period is */ |
76 | #define WATCHDOG_HEARTBEAT 0 | ||
76 | 77 | ||
77 | /* internal variables */ | 78 | /* internal variables */ |
78 | static struct platform_device *acq_platform_device; /* the watchdog platform device */ | 79 | /* the watchdog platform device */ |
80 | static struct platform_device *acq_platform_device; | ||
79 | static unsigned long acq_is_open; | 81 | static unsigned long acq_is_open; |
80 | static char expect_close; | 82 | static char expect_close; |
81 | 83 | ||
82 | /* module parameters */ | 84 | /* module parameters */ |
83 | static int wdt_stop = 0x43; /* You must set this - there is no sane way to probe for this board. */ | 85 | /* You must set this - there is no sane way to probe for this board. */ |
86 | static int wdt_stop = 0x43; | ||
84 | module_param(wdt_stop, int, 0); | 87 | module_param(wdt_stop, int, 0); |
85 | MODULE_PARM_DESC(wdt_stop, "Acquire WDT 'stop' io port (default 0x43)"); | 88 | MODULE_PARM_DESC(wdt_stop, "Acquire WDT 'stop' io port (default 0x43)"); |
86 | 89 | ||
87 | static int wdt_start = 0x443; /* You must set this - there is no sane way to probe for this board. */ | 90 | /* You must set this - there is no sane way to probe for this board. */ |
91 | static int wdt_start = 0x443; | ||
88 | module_param(wdt_start, int, 0); | 92 | module_param(wdt_start, int, 0); |
89 | MODULE_PARM_DESC(wdt_start, "Acquire WDT 'start' io port (default 0x443)"); | 93 | MODULE_PARM_DESC(wdt_start, "Acquire WDT 'start' io port (default 0x443)"); |
90 | 94 | ||
91 | static int nowayout = WATCHDOG_NOWAYOUT; | 95 | static int nowayout = WATCHDOG_NOWAYOUT; |
92 | module_param(nowayout, int, 0); | 96 | module_param(nowayout, int, 0); |
93 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 97 | MODULE_PARM_DESC(nowayout, |
98 | "Watchdog cannot be stopped once started (default=" | ||
99 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
94 | 100 | ||
95 | /* | 101 | /* |
96 | * Watchdog Operations | 102 | * Watchdog Operations |
@@ -112,18 +118,18 @@ static void acq_stop(void) | |||
112 | * /dev/watchdog handling | 118 | * /dev/watchdog handling |
113 | */ | 119 | */ |
114 | 120 | ||
115 | static ssize_t acq_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) | 121 | static ssize_t acq_write(struct file *file, const char __user *buf, |
122 | size_t count, loff_t *ppos) | ||
116 | { | 123 | { |
117 | /* See if we got the magic character 'V' and reload the timer */ | 124 | /* See if we got the magic character 'V' and reload the timer */ |
118 | if(count) { | 125 | if (count) { |
119 | if (!nowayout) { | 126 | if (!nowayout) { |
120 | size_t i; | 127 | size_t i; |
121 | |||
122 | /* note: just in case someone wrote the magic character | 128 | /* note: just in case someone wrote the magic character |
123 | * five months ago... */ | 129 | five months ago... */ |
124 | expect_close = 0; | 130 | expect_close = 0; |
125 | 131 | /* scan to see whether or not we got the | |
126 | /* scan to see whether or not we got the magic character */ | 132 | magic character */ |
127 | for (i = 0; i != count; i++) { | 133 | for (i = 0; i != count; i++) { |
128 | char c; | 134 | char c; |
129 | if (get_user(c, buf + i)) | 135 | if (get_user(c, buf + i)) |
@@ -132,64 +138,55 @@ static ssize_t acq_write(struct file *file, const char __user *buf, size_t count | |||
132 | expect_close = 42; | 138 | expect_close = 42; |
133 | } | 139 | } |
134 | } | 140 | } |
135 | 141 | /* Well, anyhow someone wrote to us, we should | |
136 | /* Well, anyhow someone wrote to us, we should return that favour */ | 142 | return that favour */ |
137 | acq_keepalive(); | 143 | acq_keepalive(); |
138 | } | 144 | } |
139 | return count; | 145 | return count; |
140 | } | 146 | } |
141 | 147 | ||
142 | static int acq_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | 148 | static long acq_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
143 | unsigned long arg) | ||
144 | { | 149 | { |
145 | int options, retval = -EINVAL; | 150 | int options, retval = -EINVAL; |
146 | void __user *argp = (void __user *)arg; | 151 | void __user *argp = (void __user *)arg; |
147 | int __user *p = argp; | 152 | int __user *p = argp; |
148 | static struct watchdog_info ident = | 153 | static struct watchdog_info ident = { |
149 | { | ||
150 | .options = WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, | 154 | .options = WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, |
151 | .firmware_version = 1, | 155 | .firmware_version = 1, |
152 | .identity = WATCHDOG_NAME, | 156 | .identity = WATCHDOG_NAME, |
153 | }; | 157 | }; |
154 | 158 | ||
155 | switch(cmd) | 159 | switch (cmd) { |
156 | { | ||
157 | case WDIOC_GETSUPPORT: | 160 | case WDIOC_GETSUPPORT: |
158 | return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; | 161 | return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; |
159 | 162 | ||
160 | case WDIOC_GETSTATUS: | 163 | case WDIOC_GETSTATUS: |
161 | case WDIOC_GETBOOTSTATUS: | 164 | case WDIOC_GETBOOTSTATUS: |
162 | return put_user(0, p); | 165 | return put_user(0, p); |
163 | |||
164 | case WDIOC_KEEPALIVE: | ||
165 | acq_keepalive(); | ||
166 | return 0; | ||
167 | |||
168 | case WDIOC_GETTIMEOUT: | ||
169 | return put_user(WATCHDOG_HEARTBEAT, p); | ||
170 | 166 | ||
171 | case WDIOC_SETOPTIONS: | 167 | case WDIOC_SETOPTIONS: |
172 | { | 168 | { |
173 | if (get_user(options, p)) | 169 | if (get_user(options, p)) |
174 | return -EFAULT; | 170 | return -EFAULT; |
175 | 171 | if (options & WDIOS_DISABLECARD) { | |
176 | if (options & WDIOS_DISABLECARD) | 172 | acq_stop(); |
177 | { | 173 | retval = 0; |
178 | acq_stop(); | 174 | } |
179 | retval = 0; | 175 | if (options & WDIOS_ENABLECARD) { |
180 | } | 176 | acq_keepalive(); |
181 | 177 | retval = 0; | |
182 | if (options & WDIOS_ENABLECARD) | 178 | } |
183 | { | 179 | return retval; |
184 | acq_keepalive(); | ||
185 | retval = 0; | ||
186 | } | ||
187 | |||
188 | return retval; | ||
189 | } | 180 | } |
181 | case WDIOC_KEEPALIVE: | ||
182 | acq_keepalive(); | ||
183 | return 0; | ||
184 | |||
185 | case WDIOC_GETTIMEOUT: | ||
186 | return put_user(WATCHDOG_HEARTBEAT, p); | ||
190 | 187 | ||
191 | default: | 188 | default: |
192 | return -ENOTTY; | 189 | return -ENOTTY; |
193 | } | 190 | } |
194 | } | 191 | } |
195 | 192 | ||
@@ -211,7 +208,8 @@ static int acq_close(struct inode *inode, struct file *file) | |||
211 | if (expect_close == 42) { | 208 | if (expect_close == 42) { |
212 | acq_stop(); | 209 | acq_stop(); |
213 | } else { | 210 | } else { |
214 | printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); | 211 | printk(KERN_CRIT PFX |
212 | "Unexpected close, not stopping watchdog!\n"); | ||
215 | acq_keepalive(); | 213 | acq_keepalive(); |
216 | } | 214 | } |
217 | clear_bit(0, &acq_is_open); | 215 | clear_bit(0, &acq_is_open); |
@@ -227,7 +225,7 @@ static const struct file_operations acq_fops = { | |||
227 | .owner = THIS_MODULE, | 225 | .owner = THIS_MODULE, |
228 | .llseek = no_llseek, | 226 | .llseek = no_llseek, |
229 | .write = acq_write, | 227 | .write = acq_write, |
230 | .ioctl = acq_ioctl, | 228 | .unlocked_ioctl = acq_ioctl, |
231 | .open = acq_open, | 229 | .open = acq_open, |
232 | .release = acq_close, | 230 | .release = acq_close, |
233 | }; | 231 | }; |
@@ -248,32 +246,29 @@ static int __devinit acq_probe(struct platform_device *dev) | |||
248 | 246 | ||
249 | if (wdt_stop != wdt_start) { | 247 | if (wdt_stop != wdt_start) { |
250 | if (!request_region(wdt_stop, 1, WATCHDOG_NAME)) { | 248 | if (!request_region(wdt_stop, 1, WATCHDOG_NAME)) { |
251 | printk (KERN_ERR PFX "I/O address 0x%04x already in use\n", | 249 | printk(KERN_ERR PFX |
252 | wdt_stop); | 250 | "I/O address 0x%04x already in use\n", wdt_stop); |
253 | ret = -EIO; | 251 | ret = -EIO; |
254 | goto out; | 252 | goto out; |
255 | } | 253 | } |
256 | } | 254 | } |
257 | 255 | ||
258 | if (!request_region(wdt_start, 1, WATCHDOG_NAME)) { | 256 | if (!request_region(wdt_start, 1, WATCHDOG_NAME)) { |
259 | printk (KERN_ERR PFX "I/O address 0x%04x already in use\n", | 257 | printk(KERN_ERR PFX "I/O address 0x%04x already in use\n", |
260 | wdt_start); | 258 | wdt_start); |
261 | ret = -EIO; | 259 | ret = -EIO; |
262 | goto unreg_stop; | 260 | goto unreg_stop; |
263 | } | 261 | } |
264 | |||
265 | ret = misc_register(&acq_miscdev); | 262 | ret = misc_register(&acq_miscdev); |
266 | if (ret != 0) { | 263 | if (ret != 0) { |
267 | printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", | 264 | printk(KERN_ERR PFX |
268 | WATCHDOG_MINOR, ret); | 265 | "cannot register miscdev on minor=%d (err=%d)\n", |
266 | WATCHDOG_MINOR, ret); | ||
269 | goto unreg_regions; | 267 | goto unreg_regions; |
270 | } | 268 | } |
271 | 269 | printk(KERN_INFO PFX "initialized. (nowayout=%d)\n", nowayout); | |
272 | printk (KERN_INFO PFX "initialized. (nowayout=%d)\n", | ||
273 | nowayout); | ||
274 | 270 | ||
275 | return 0; | 271 | return 0; |
276 | |||
277 | unreg_regions: | 272 | unreg_regions: |
278 | release_region(wdt_start, 1); | 273 | release_region(wdt_start, 1); |
279 | unreg_stop: | 274 | unreg_stop: |
@@ -286,9 +281,9 @@ out: | |||
286 | static int __devexit acq_remove(struct platform_device *dev) | 281 | static int __devexit acq_remove(struct platform_device *dev) |
287 | { | 282 | { |
288 | misc_deregister(&acq_miscdev); | 283 | misc_deregister(&acq_miscdev); |
289 | release_region(wdt_start,1); | 284 | release_region(wdt_start, 1); |
290 | if(wdt_stop != wdt_start) | 285 | if (wdt_stop != wdt_start) |
291 | release_region(wdt_stop,1); | 286 | release_region(wdt_stop, 1); |
292 | 287 | ||
293 | return 0; | 288 | return 0; |
294 | } | 289 | } |
@@ -313,18 +308,19 @@ static int __init acq_init(void) | |||
313 | { | 308 | { |
314 | int err; | 309 | int err; |
315 | 310 | ||
316 | printk(KERN_INFO "WDT driver for Acquire single board computer initialising.\n"); | 311 | printk(KERN_INFO |
312 | "WDT driver for Acquire single board computer initialising.\n"); | ||
317 | 313 | ||
318 | err = platform_driver_register(&acquirewdt_driver); | 314 | err = platform_driver_register(&acquirewdt_driver); |
319 | if (err) | 315 | if (err) |
320 | return err; | 316 | return err; |
321 | 317 | ||
322 | acq_platform_device = platform_device_register_simple(DRV_NAME, -1, NULL, 0); | 318 | acq_platform_device = platform_device_register_simple(DRV_NAME, |
319 | -1, NULL, 0); | ||
323 | if (IS_ERR(acq_platform_device)) { | 320 | if (IS_ERR(acq_platform_device)) { |
324 | err = PTR_ERR(acq_platform_device); | 321 | err = PTR_ERR(acq_platform_device); |
325 | goto unreg_platform_driver; | 322 | goto unreg_platform_driver; |
326 | } | 323 | } |
327 | |||
328 | return 0; | 324 | return 0; |
329 | 325 | ||
330 | unreg_platform_driver: | 326 | unreg_platform_driver: |
diff --git a/drivers/watchdog/advantechwdt.c b/drivers/watchdog/advantechwdt.c index 8121cc247343..a5110f93a755 100644 --- a/drivers/watchdog/advantechwdt.c +++ b/drivers/watchdog/advantechwdt.c | |||
@@ -37,9 +37,9 @@ | |||
37 | #include <linux/ioport.h> | 37 | #include <linux/ioport.h> |
38 | #include <linux/platform_device.h> | 38 | #include <linux/platform_device.h> |
39 | #include <linux/init.h> | 39 | #include <linux/init.h> |
40 | #include <linux/io.h> | ||
41 | #include <linux/uaccess.h> | ||
40 | 42 | ||
41 | #include <asm/io.h> | ||
42 | #include <asm/uaccess.h> | ||
43 | #include <asm/system.h> | 43 | #include <asm/system.h> |
44 | 44 | ||
45 | #define DRV_NAME "advantechwdt" | 45 | #define DRV_NAME "advantechwdt" |
@@ -47,7 +47,8 @@ | |||
47 | #define WATCHDOG_NAME "Advantech WDT" | 47 | #define WATCHDOG_NAME "Advantech WDT" |
48 | #define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */ | 48 | #define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */ |
49 | 49 | ||
50 | static struct platform_device *advwdt_platform_device; /* the watchdog platform device */ | 50 | /* the watchdog platform device */ |
51 | static struct platform_device *advwdt_platform_device; | ||
51 | static unsigned long advwdt_is_open; | 52 | static unsigned long advwdt_is_open; |
52 | static char adv_expect_close; | 53 | static char adv_expect_close; |
53 | 54 | ||
@@ -72,35 +73,35 @@ MODULE_PARM_DESC(wdt_start, "Advantech WDT 'start' io port (default 0x443)"); | |||
72 | 73 | ||
73 | static int timeout = WATCHDOG_TIMEOUT; /* in seconds */ | 74 | static int timeout = WATCHDOG_TIMEOUT; /* in seconds */ |
74 | module_param(timeout, int, 0); | 75 | module_param(timeout, int, 0); |
75 | MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=63, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) "."); | 76 | MODULE_PARM_DESC(timeout, |
77 | "Watchdog timeout in seconds. 1<= timeout <=63, default=" | ||
78 | __MODULE_STRING(WATCHDOG_TIMEOUT) "."); | ||
76 | 79 | ||
77 | static int nowayout = WATCHDOG_NOWAYOUT; | 80 | static int nowayout = WATCHDOG_NOWAYOUT; |
78 | module_param(nowayout, int, 0); | 81 | module_param(nowayout, int, 0); |
79 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 82 | MODULE_PARM_DESC(nowayout, |
83 | "Watchdog cannot be stopped once started (default=" | ||
84 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
80 | 85 | ||
81 | /* | 86 | /* |
82 | * Watchdog Operations | 87 | * Watchdog Operations |
83 | */ | 88 | */ |
84 | 89 | ||
85 | static void | 90 | static void advwdt_ping(void) |
86 | advwdt_ping(void) | ||
87 | { | 91 | { |
88 | /* Write a watchdog value */ | 92 | /* Write a watchdog value */ |
89 | outb_p(timeout, wdt_start); | 93 | outb_p(timeout, wdt_start); |
90 | } | 94 | } |
91 | 95 | ||
92 | static void | 96 | static void advwdt_disable(void) |
93 | advwdt_disable(void) | ||
94 | { | 97 | { |
95 | inb_p(wdt_stop); | 98 | inb_p(wdt_stop); |
96 | } | 99 | } |
97 | 100 | ||
98 | static int | 101 | static int advwdt_set_heartbeat(int t) |
99 | advwdt_set_heartbeat(int t) | ||
100 | { | 102 | { |
101 | if ((t < 1) || (t > 63)) | 103 | if (t < 1 || t > 63) |
102 | return -EINVAL; | 104 | return -EINVAL; |
103 | |||
104 | timeout = t; | 105 | timeout = t; |
105 | return 0; | 106 | return 0; |
106 | } | 107 | } |
@@ -109,8 +110,8 @@ advwdt_set_heartbeat(int t) | |||
109 | * /dev/watchdog handling | 110 | * /dev/watchdog handling |
110 | */ | 111 | */ |
111 | 112 | ||
112 | static ssize_t | 113 | static ssize_t advwdt_write(struct file *file, const char __user *buf, |
113 | advwdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) | 114 | size_t count, loff_t *ppos) |
114 | { | 115 | { |
115 | if (count) { | 116 | if (count) { |
116 | if (!nowayout) { | 117 | if (!nowayout) { |
@@ -120,7 +121,7 @@ advwdt_write(struct file *file, const char __user *buf, size_t count, loff_t *pp | |||
120 | 121 | ||
121 | for (i = 0; i != count; i++) { | 122 | for (i = 0; i != count; i++) { |
122 | char c; | 123 | char c; |
123 | if (get_user(c, buf+i)) | 124 | if (get_user(c, buf + i)) |
124 | return -EFAULT; | 125 | return -EFAULT; |
125 | if (c == 'V') | 126 | if (c == 'V') |
126 | adv_expect_close = 42; | 127 | adv_expect_close = 42; |
@@ -131,9 +132,7 @@ advwdt_write(struct file *file, const char __user *buf, size_t count, loff_t *pp | |||
131 | return count; | 132 | return count; |
132 | } | 133 | } |
133 | 134 | ||
134 | static int | 135 | static long advwdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
135 | advwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | ||
136 | unsigned long arg) | ||
137 | { | 136 | { |
138 | int new_timeout; | 137 | int new_timeout; |
139 | void __user *argp = (void __user *)arg; | 138 | void __user *argp = (void __user *)arg; |
@@ -146,57 +145,50 @@ advwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | |||
146 | 145 | ||
147 | switch (cmd) { | 146 | switch (cmd) { |
148 | case WDIOC_GETSUPPORT: | 147 | case WDIOC_GETSUPPORT: |
149 | if (copy_to_user(argp, &ident, sizeof(ident))) | 148 | if (copy_to_user(argp, &ident, sizeof(ident))) |
150 | return -EFAULT; | 149 | return -EFAULT; |
151 | break; | 150 | break; |
152 | 151 | ||
153 | case WDIOC_GETSTATUS: | 152 | case WDIOC_GETSTATUS: |
154 | case WDIOC_GETBOOTSTATUS: | 153 | case WDIOC_GETBOOTSTATUS: |
155 | return put_user(0, p); | 154 | return put_user(0, p); |
156 | |||
157 | case WDIOC_KEEPALIVE: | ||
158 | advwdt_ping(); | ||
159 | break; | ||
160 | |||
161 | case WDIOC_SETTIMEOUT: | ||
162 | if (get_user(new_timeout, p)) | ||
163 | return -EFAULT; | ||
164 | if (advwdt_set_heartbeat(new_timeout)) | ||
165 | return -EINVAL; | ||
166 | advwdt_ping(); | ||
167 | /* Fall */ | ||
168 | |||
169 | case WDIOC_GETTIMEOUT: | ||
170 | return put_user(timeout, p); | ||
171 | 155 | ||
172 | case WDIOC_SETOPTIONS: | 156 | case WDIOC_SETOPTIONS: |
173 | { | 157 | { |
174 | int options, retval = -EINVAL; | 158 | int options, retval = -EINVAL; |
175 | |||
176 | if (get_user(options, p)) | ||
177 | return -EFAULT; | ||
178 | |||
179 | if (options & WDIOS_DISABLECARD) { | ||
180 | advwdt_disable(); | ||
181 | retval = 0; | ||
182 | } | ||
183 | 159 | ||
184 | if (options & WDIOS_ENABLECARD) { | 160 | if (get_user(options, p)) |
185 | advwdt_ping(); | 161 | return -EFAULT; |
186 | retval = 0; | 162 | if (options & WDIOS_DISABLECARD) { |
187 | } | 163 | advwdt_disable(); |
188 | 164 | retval = 0; | |
189 | return retval; | 165 | } |
166 | if (options & WDIOS_ENABLECARD) { | ||
167 | advwdt_ping(); | ||
168 | retval = 0; | ||
169 | } | ||
170 | return retval; | ||
190 | } | 171 | } |
172 | case WDIOC_KEEPALIVE: | ||
173 | advwdt_ping(); | ||
174 | break; | ||
191 | 175 | ||
176 | case WDIOC_SETTIMEOUT: | ||
177 | if (get_user(new_timeout, p)) | ||
178 | return -EFAULT; | ||
179 | if (advwdt_set_heartbeat(new_timeout)) | ||
180 | return -EINVAL; | ||
181 | advwdt_ping(); | ||
182 | /* Fall */ | ||
183 | case WDIOC_GETTIMEOUT: | ||
184 | return put_user(timeout, p); | ||
192 | default: | 185 | default: |
193 | return -ENOTTY; | 186 | return -ENOTTY; |
194 | } | 187 | } |
195 | return 0; | 188 | return 0; |
196 | } | 189 | } |
197 | 190 | ||
198 | static int | 191 | static int advwdt_open(struct inode *inode, struct file *file) |
199 | advwdt_open(struct inode *inode, struct file *file) | ||
200 | { | 192 | { |
201 | if (test_and_set_bit(0, &advwdt_is_open)) | 193 | if (test_and_set_bit(0, &advwdt_is_open)) |
202 | return -EBUSY; | 194 | return -EBUSY; |
@@ -208,13 +200,13 @@ advwdt_open(struct inode *inode, struct file *file) | |||
208 | return nonseekable_open(inode, file); | 200 | return nonseekable_open(inode, file); |
209 | } | 201 | } |
210 | 202 | ||
211 | static int | 203 | static int advwdt_close(struct inode *inode, struct file *file) |
212 | advwdt_close(struct inode *inode, struct file *file) | ||
213 | { | 204 | { |
214 | if (adv_expect_close == 42) { | 205 | if (adv_expect_close == 42) { |
215 | advwdt_disable(); | 206 | advwdt_disable(); |
216 | } else { | 207 | } else { |
217 | printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); | 208 | printk(KERN_CRIT PFX |
209 | "Unexpected close, not stopping watchdog!\n"); | ||
218 | advwdt_ping(); | 210 | advwdt_ping(); |
219 | } | 211 | } |
220 | clear_bit(0, &advwdt_is_open); | 212 | clear_bit(0, &advwdt_is_open); |
@@ -230,7 +222,7 @@ static const struct file_operations advwdt_fops = { | |||
230 | .owner = THIS_MODULE, | 222 | .owner = THIS_MODULE, |
231 | .llseek = no_llseek, | 223 | .llseek = no_llseek, |
232 | .write = advwdt_write, | 224 | .write = advwdt_write, |
233 | .ioctl = advwdt_ioctl, | 225 | .unlocked_ioctl = advwdt_ioctl, |
234 | .open = advwdt_open, | 226 | .open = advwdt_open, |
235 | .release = advwdt_close, | 227 | .release = advwdt_close, |
236 | }; | 228 | }; |
@@ -245,23 +237,24 @@ static struct miscdevice advwdt_miscdev = { | |||
245 | * Init & exit routines | 237 | * Init & exit routines |
246 | */ | 238 | */ |
247 | 239 | ||
248 | static int __devinit | 240 | static int __devinit advwdt_probe(struct platform_device *dev) |
249 | advwdt_probe(struct platform_device *dev) | ||
250 | { | 241 | { |
251 | int ret; | 242 | int ret; |
252 | 243 | ||
253 | if (wdt_stop != wdt_start) { | 244 | if (wdt_stop != wdt_start) { |
254 | if (!request_region(wdt_stop, 1, WATCHDOG_NAME)) { | 245 | if (!request_region(wdt_stop, 1, WATCHDOG_NAME)) { |
255 | printk (KERN_ERR PFX "I/O address 0x%04x already in use\n", | 246 | printk(KERN_ERR PFX |
256 | wdt_stop); | 247 | "I/O address 0x%04x already in use\n", |
248 | wdt_stop); | ||
257 | ret = -EIO; | 249 | ret = -EIO; |
258 | goto out; | 250 | goto out; |
259 | } | 251 | } |
260 | } | 252 | } |
261 | 253 | ||
262 | if (!request_region(wdt_start, 1, WATCHDOG_NAME)) { | 254 | if (!request_region(wdt_start, 1, WATCHDOG_NAME)) { |
263 | printk (KERN_ERR PFX "I/O address 0x%04x already in use\n", | 255 | printk(KERN_ERR PFX |
264 | wdt_start); | 256 | "I/O address 0x%04x already in use\n", |
257 | wdt_start); | ||
265 | ret = -EIO; | 258 | ret = -EIO; |
266 | goto unreg_stop; | 259 | goto unreg_stop; |
267 | } | 260 | } |
@@ -269,20 +262,19 @@ advwdt_probe(struct platform_device *dev) | |||
269 | /* Check that the heartbeat value is within it's range ; if not reset to the default */ | 262 | /* Check that the heartbeat value is within it's range ; if not reset to the default */ |
270 | if (advwdt_set_heartbeat(timeout)) { | 263 | if (advwdt_set_heartbeat(timeout)) { |
271 | advwdt_set_heartbeat(WATCHDOG_TIMEOUT); | 264 | advwdt_set_heartbeat(WATCHDOG_TIMEOUT); |
272 | printk (KERN_INFO PFX "timeout value must be 1<=x<=63, using %d\n", | 265 | printk(KERN_INFO PFX |
273 | timeout); | 266 | "timeout value must be 1<=x<=63, using %d\n", timeout); |
274 | } | 267 | } |
275 | 268 | ||
276 | ret = misc_register(&advwdt_miscdev); | 269 | ret = misc_register(&advwdt_miscdev); |
277 | if (ret != 0) { | 270 | if (ret != 0) { |
278 | printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", | 271 | printk(KERN_ERR PFX |
279 | WATCHDOG_MINOR, ret); | 272 | "cannot register miscdev on minor=%d (err=%d)\n", |
273 | WATCHDOG_MINOR, ret); | ||
280 | goto unreg_regions; | 274 | goto unreg_regions; |
281 | } | 275 | } |
282 | 276 | printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n", | |
283 | printk (KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n", | ||
284 | timeout, nowayout); | 277 | timeout, nowayout); |
285 | |||
286 | out: | 278 | out: |
287 | return ret; | 279 | return ret; |
288 | unreg_regions: | 280 | unreg_regions: |
@@ -293,19 +285,17 @@ unreg_stop: | |||
293 | goto out; | 285 | goto out; |
294 | } | 286 | } |
295 | 287 | ||
296 | static int __devexit | 288 | static int __devexit advwdt_remove(struct platform_device *dev) |
297 | advwdt_remove(struct platform_device *dev) | ||
298 | { | 289 | { |
299 | misc_deregister(&advwdt_miscdev); | 290 | misc_deregister(&advwdt_miscdev); |
300 | release_region(wdt_start,1); | 291 | release_region(wdt_start, 1); |
301 | if(wdt_stop != wdt_start) | 292 | if (wdt_stop != wdt_start) |
302 | release_region(wdt_stop,1); | 293 | release_region(wdt_stop, 1); |
303 | 294 | ||
304 | return 0; | 295 | return 0; |
305 | } | 296 | } |
306 | 297 | ||
307 | static void | 298 | static void advwdt_shutdown(struct platform_device *dev) |
308 | advwdt_shutdown(struct platform_device *dev) | ||
309 | { | 299 | { |
310 | /* Turn the WDT off if we have a soft shutdown */ | 300 | /* Turn the WDT off if we have a soft shutdown */ |
311 | advwdt_disable(); | 301 | advwdt_disable(); |
@@ -321,18 +311,19 @@ static struct platform_driver advwdt_driver = { | |||
321 | }, | 311 | }, |
322 | }; | 312 | }; |
323 | 313 | ||
324 | static int __init | 314 | static int __init advwdt_init(void) |
325 | advwdt_init(void) | ||
326 | { | 315 | { |
327 | int err; | 316 | int err; |
328 | 317 | ||
329 | printk(KERN_INFO "WDT driver for Advantech single board computer initialising.\n"); | 318 | printk(KERN_INFO |
319 | "WDT driver for Advantech single board computer initialising.\n"); | ||
330 | 320 | ||
331 | err = platform_driver_register(&advwdt_driver); | 321 | err = platform_driver_register(&advwdt_driver); |
332 | if (err) | 322 | if (err) |
333 | return err; | 323 | return err; |
334 | 324 | ||
335 | advwdt_platform_device = platform_device_register_simple(DRV_NAME, -1, NULL, 0); | 325 | advwdt_platform_device = platform_device_register_simple(DRV_NAME, |
326 | -1, NULL, 0); | ||
336 | if (IS_ERR(advwdt_platform_device)) { | 327 | if (IS_ERR(advwdt_platform_device)) { |
337 | err = PTR_ERR(advwdt_platform_device); | 328 | err = PTR_ERR(advwdt_platform_device); |
338 | goto unreg_platform_driver; | 329 | goto unreg_platform_driver; |
@@ -345,8 +336,7 @@ unreg_platform_driver: | |||
345 | return err; | 336 | return err; |
346 | } | 337 | } |
347 | 338 | ||
348 | static void __exit | 339 | static void __exit advwdt_exit(void) |
349 | advwdt_exit(void) | ||
350 | { | 340 | { |
351 | platform_device_unregister(advwdt_platform_device); | 341 | platform_device_unregister(advwdt_platform_device); |
352 | platform_driver_unregister(&advwdt_driver); | 342 | platform_driver_unregister(&advwdt_driver); |
diff --git a/drivers/watchdog/alim1535_wdt.c b/drivers/watchdog/alim1535_wdt.c index 2b1fbdb2fcf7..2a7690ecf97d 100644 --- a/drivers/watchdog/alim1535_wdt.c +++ b/drivers/watchdog/alim1535_wdt.c | |||
@@ -18,9 +18,8 @@ | |||
18 | #include <linux/init.h> | 18 | #include <linux/init.h> |
19 | #include <linux/fs.h> | 19 | #include <linux/fs.h> |
20 | #include <linux/pci.h> | 20 | #include <linux/pci.h> |
21 | 21 | #include <linux/uaccess.h> | |
22 | #include <asm/uaccess.h> | 22 | #include <linux/io.h> |
23 | #include <asm/io.h> | ||
24 | 23 | ||
25 | #define WATCHDOG_NAME "ALi_M1535" | 24 | #define WATCHDOG_NAME "ALi_M1535" |
26 | #define PFX WATCHDOG_NAME ": " | 25 | #define PFX WATCHDOG_NAME ": " |
@@ -30,17 +29,21 @@ | |||
30 | static unsigned long ali_is_open; | 29 | static unsigned long ali_is_open; |
31 | static char ali_expect_release; | 30 | static char ali_expect_release; |
32 | static struct pci_dev *ali_pci; | 31 | static struct pci_dev *ali_pci; |
33 | static u32 ali_timeout_bits; /* stores the computed timeout */ | 32 | static u32 ali_timeout_bits; /* stores the computed timeout */ |
34 | static DEFINE_SPINLOCK(ali_lock); /* Guards the hardware */ | 33 | static DEFINE_SPINLOCK(ali_lock); /* Guards the hardware */ |
35 | 34 | ||
36 | /* module parameters */ | 35 | /* module parameters */ |
37 | static int timeout = WATCHDOG_TIMEOUT; | 36 | static int timeout = WATCHDOG_TIMEOUT; |
38 | module_param(timeout, int, 0); | 37 | module_param(timeout, int, 0); |
39 | MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (0<timeout<18000, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")"); | 38 | MODULE_PARM_DESC(timeout, |
39 | "Watchdog timeout in seconds. (0 < timeout < 18000, default=" | ||
40 | __MODULE_STRING(WATCHDOG_TIMEOUT) ")"); | ||
40 | 41 | ||
41 | static int nowayout = WATCHDOG_NOWAYOUT; | 42 | static int nowayout = WATCHDOG_NOWAYOUT; |
42 | module_param(nowayout, int, 0); | 43 | module_param(nowayout, int, 0); |
43 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 44 | MODULE_PARM_DESC(nowayout, |
45 | "Watchdog cannot be stopped once started (default=" | ||
46 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
44 | 47 | ||
45 | /* | 48 | /* |
46 | * ali_start - start watchdog countdown | 49 | * ali_start - start watchdog countdown |
@@ -103,15 +106,16 @@ static void ali_keepalive(void) | |||
103 | 106 | ||
104 | static int ali_settimer(int t) | 107 | static int ali_settimer(int t) |
105 | { | 108 | { |
106 | if(t < 0) | 109 | if (t < 0) |
107 | return -EINVAL; | 110 | return -EINVAL; |
108 | else if(t < 60) | 111 | else if (t < 60) |
109 | ali_timeout_bits = t|(1<<6); | 112 | ali_timeout_bits = t|(1<<6); |
110 | else if(t < 3600) | 113 | else if (t < 3600) |
111 | ali_timeout_bits = (t/60)|(1<<7); | 114 | ali_timeout_bits = (t/60)|(1<<7); |
112 | else if(t < 18000) | 115 | else if (t < 18000) |
113 | ali_timeout_bits = (t/300)|(1<<6)|(1<<7); | 116 | ali_timeout_bits = (t/300)|(1<<6)|(1<<7); |
114 | else return -EINVAL; | 117 | else |
118 | return -EINVAL; | ||
115 | 119 | ||
116 | timeout = t; | 120 | timeout = t; |
117 | return 0; | 121 | return 0; |
@@ -134,21 +138,22 @@ static int ali_settimer(int t) | |||
134 | */ | 138 | */ |
135 | 139 | ||
136 | static ssize_t ali_write(struct file *file, const char __user *data, | 140 | static ssize_t ali_write(struct file *file, const char __user *data, |
137 | size_t len, loff_t * ppos) | 141 | size_t len, loff_t *ppos) |
138 | { | 142 | { |
139 | /* See if we got the magic character 'V' and reload the timer */ | 143 | /* See if we got the magic character 'V' and reload the timer */ |
140 | if (len) { | 144 | if (len) { |
141 | if (!nowayout) { | 145 | if (!nowayout) { |
142 | size_t i; | 146 | size_t i; |
143 | 147 | ||
144 | /* note: just in case someone wrote the magic character | 148 | /* note: just in case someone wrote the |
145 | * five months ago... */ | 149 | magic character five months ago... */ |
146 | ali_expect_release = 0; | 150 | ali_expect_release = 0; |
147 | 151 | ||
148 | /* scan to see whether or not we got the magic character */ | 152 | /* scan to see whether or not we got |
153 | the magic character */ | ||
149 | for (i = 0; i != len; i++) { | 154 | for (i = 0; i != len; i++) { |
150 | char c; | 155 | char c; |
151 | if(get_user(c, data+i)) | 156 | if (get_user(c, data + i)) |
152 | return -EFAULT; | 157 | return -EFAULT; |
153 | if (c == 'V') | 158 | if (c == 'V') |
154 | ali_expect_release = 42; | 159 | ali_expect_release = 42; |
@@ -163,7 +168,6 @@ static ssize_t ali_write(struct file *file, const char __user *data, | |||
163 | 168 | ||
164 | /* | 169 | /* |
165 | * ali_ioctl - handle watchdog ioctls | 170 | * ali_ioctl - handle watchdog ioctls |
166 | * @inode: VFS inode | ||
167 | * @file: VFS file pointer | 171 | * @file: VFS file pointer |
168 | * @cmd: ioctl number | 172 | * @cmd: ioctl number |
169 | * @arg: arguments to the ioctl | 173 | * @arg: arguments to the ioctl |
@@ -172,8 +176,7 @@ static ssize_t ali_write(struct file *file, const char __user *data, | |||
172 | * we want an extension to enable irq ack monitoring and the like | 176 | * we want an extension to enable irq ack monitoring and the like |
173 | */ | 177 | */ |
174 | 178 | ||
175 | static int ali_ioctl(struct inode *inode, struct file *file, | 179 | static long ali_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
176 | unsigned int cmd, unsigned long arg) | ||
177 | { | 180 | { |
178 | void __user *argp = (void __user *)arg; | 181 | void __user *argp = (void __user *)arg; |
179 | int __user *p = argp; | 182 | int __user *p = argp; |
@@ -186,57 +189,45 @@ static int ali_ioctl(struct inode *inode, struct file *file, | |||
186 | }; | 189 | }; |
187 | 190 | ||
188 | switch (cmd) { | 191 | switch (cmd) { |
189 | case WDIOC_GETSUPPORT: | 192 | case WDIOC_GETSUPPORT: |
190 | return copy_to_user(argp, &ident, | 193 | return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; |
191 | sizeof (ident)) ? -EFAULT : 0; | 194 | |
192 | 195 | case WDIOC_GETSTATUS: | |
193 | case WDIOC_GETSTATUS: | 196 | case WDIOC_GETBOOTSTATUS: |
194 | case WDIOC_GETBOOTSTATUS: | 197 | return put_user(0, p); |
195 | return put_user(0, p); | 198 | case WDIOC_SETOPTIONS: |
196 | 199 | { | |
197 | case WDIOC_KEEPALIVE: | 200 | int new_options, retval = -EINVAL; |
198 | ali_keepalive(); | 201 | |
199 | return 0; | 202 | if (get_user(new_options, p)) |
200 | 203 | return -EFAULT; | |
201 | case WDIOC_SETOPTIONS: | 204 | if (new_options & WDIOS_DISABLECARD) { |
202 | { | 205 | ali_stop(); |
203 | int new_options, retval = -EINVAL; | 206 | retval = 0; |
204 | |||
205 | if (get_user (new_options, p)) | ||
206 | return -EFAULT; | ||
207 | |||
208 | if (new_options & WDIOS_DISABLECARD) { | ||
209 | ali_stop(); | ||
210 | retval = 0; | ||
211 | } | ||
212 | |||
213 | if (new_options & WDIOS_ENABLECARD) { | ||
214 | ali_start(); | ||
215 | retval = 0; | ||
216 | } | ||
217 | |||
218 | return retval; | ||
219 | } | 207 | } |
220 | 208 | if (new_options & WDIOS_ENABLECARD) { | |
221 | case WDIOC_SETTIMEOUT: | 209 | ali_start(); |
222 | { | 210 | retval = 0; |
223 | int new_timeout; | ||
224 | |||
225 | if (get_user(new_timeout, p)) | ||
226 | return -EFAULT; | ||
227 | |||
228 | if (ali_settimer(new_timeout)) | ||
229 | return -EINVAL; | ||
230 | |||
231 | ali_keepalive(); | ||
232 | /* Fall */ | ||
233 | } | 211 | } |
234 | 212 | return retval; | |
235 | case WDIOC_GETTIMEOUT: | 213 | } |
236 | return put_user(timeout, p); | 214 | case WDIOC_KEEPALIVE: |
237 | 215 | ali_keepalive(); | |
238 | default: | 216 | return 0; |
239 | return -ENOTTY; | 217 | case WDIOC_SETTIMEOUT: |
218 | { | ||
219 | int new_timeout; | ||
220 | if (get_user(new_timeout, p)) | ||
221 | return -EFAULT; | ||
222 | if (ali_settimer(new_timeout)) | ||
223 | return -EINVAL; | ||
224 | ali_keepalive(); | ||
225 | /* Fall */ | ||
226 | } | ||
227 | case WDIOC_GETTIMEOUT: | ||
228 | return put_user(timeout, p); | ||
229 | default: | ||
230 | return -ENOTTY; | ||
240 | } | 231 | } |
241 | } | 232 | } |
242 | 233 | ||
@@ -274,10 +265,11 @@ static int ali_release(struct inode *inode, struct file *file) | |||
274 | /* | 265 | /* |
275 | * Shut off the timer. | 266 | * Shut off the timer. |
276 | */ | 267 | */ |
277 | if (ali_expect_release == 42) { | 268 | if (ali_expect_release == 42) |
278 | ali_stop(); | 269 | ali_stop(); |
279 | } else { | 270 | else { |
280 | printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); | 271 | printk(KERN_CRIT PFX |
272 | "Unexpected close, not stopping watchdog!\n"); | ||
281 | ali_keepalive(); | 273 | ali_keepalive(); |
282 | } | 274 | } |
283 | clear_bit(0, &ali_is_open); | 275 | clear_bit(0, &ali_is_open); |
@@ -292,13 +284,11 @@ static int ali_release(struct inode *inode, struct file *file) | |||
292 | */ | 284 | */ |
293 | 285 | ||
294 | 286 | ||
295 | static int ali_notify_sys(struct notifier_block *this, unsigned long code, void *unused) | 287 | static int ali_notify_sys(struct notifier_block *this, |
288 | unsigned long code, void *unused) | ||
296 | { | 289 | { |
297 | if (code==SYS_DOWN || code==SYS_HALT) { | 290 | if (code == SYS_DOWN || code == SYS_HALT) |
298 | /* Turn the WDT off */ | 291 | ali_stop(); /* Turn the WDT off */ |
299 | ali_stop(); | ||
300 | } | ||
301 | |||
302 | return NOTIFY_DONE; | 292 | return NOTIFY_DONE; |
303 | } | 293 | } |
304 | 294 | ||
@@ -340,10 +330,10 @@ static int __init ali_find_watchdog(void) | |||
340 | 330 | ||
341 | /* Check for the a 7101 PMU */ | 331 | /* Check for the a 7101 PMU */ |
342 | pdev = pci_get_device(PCI_VENDOR_ID_AL, 0x7101, NULL); | 332 | pdev = pci_get_device(PCI_VENDOR_ID_AL, 0x7101, NULL); |
343 | if(pdev == NULL) | 333 | if (pdev == NULL) |
344 | return -ENODEV; | 334 | return -ENODEV; |
345 | 335 | ||
346 | if(pci_enable_device(pdev)) { | 336 | if (pci_enable_device(pdev)) { |
347 | pci_dev_put(pdev); | 337 | pci_dev_put(pdev); |
348 | return -EIO; | 338 | return -EIO; |
349 | } | 339 | } |
@@ -355,9 +345,12 @@ static int __init ali_find_watchdog(void) | |||
355 | */ | 345 | */ |
356 | pci_read_config_dword(pdev, 0xCC, &wdog); | 346 | pci_read_config_dword(pdev, 0xCC, &wdog); |
357 | 347 | ||
358 | wdog &= ~0x3F; /* Timer bits */ | 348 | /* Timer bits */ |
359 | wdog &= ~((1<<27)|(1<<26)|(1<<25)|(1<<24)); /* Issued events */ | 349 | wdog &= ~0x3F; |
360 | wdog &= ~((1<<16)|(1<<13)|(1<<12)|(1<<11)|(1<<10)|(1<<9)); /* No monitor bits */ | 350 | /* Issued events */ |
351 | wdog &= ~((1<<27)|(1<<26)|(1<<25)|(1<<24)); | ||
352 | /* No monitor bits */ | ||
353 | wdog &= ~((1<<16)|(1<<13)|(1<<12)|(1<<11)|(1<<10)|(1<<9)); | ||
361 | 354 | ||
362 | pci_write_config_dword(pdev, 0xCC, wdog); | 355 | pci_write_config_dword(pdev, 0xCC, wdog); |
363 | 356 | ||
@@ -369,12 +362,12 @@ static int __init ali_find_watchdog(void) | |||
369 | */ | 362 | */ |
370 | 363 | ||
371 | static const struct file_operations ali_fops = { | 364 | static const struct file_operations ali_fops = { |
372 | .owner = THIS_MODULE, | 365 | .owner = THIS_MODULE, |
373 | .llseek = no_llseek, | 366 | .llseek = no_llseek, |
374 | .write = ali_write, | 367 | .write = ali_write, |
375 | .ioctl = ali_ioctl, | 368 | .unlocked_ioctl = ali_ioctl, |
376 | .open = ali_open, | 369 | .open = ali_open, |
377 | .release = ali_release, | 370 | .release = ali_release, |
378 | }; | 371 | }; |
379 | 372 | ||
380 | static struct miscdevice ali_miscdev = { | 373 | static struct miscdevice ali_miscdev = { |
@@ -399,15 +392,16 @@ static int __init watchdog_init(void) | |||
399 | int ret; | 392 | int ret; |
400 | 393 | ||
401 | /* Check whether or not the hardware watchdog is there */ | 394 | /* Check whether or not the hardware watchdog is there */ |
402 | if (ali_find_watchdog() != 0) { | 395 | if (ali_find_watchdog() != 0) |
403 | return -ENODEV; | 396 | return -ENODEV; |
404 | } | ||
405 | 397 | ||
406 | /* Check that the timeout value is within it's range ; if not reset to the default */ | 398 | /* Check that the timeout value is within it's range; |
399 | if not reset to the default */ | ||
407 | if (timeout < 1 || timeout >= 18000) { | 400 | if (timeout < 1 || timeout >= 18000) { |
408 | timeout = WATCHDOG_TIMEOUT; | 401 | timeout = WATCHDOG_TIMEOUT; |
409 | printk(KERN_INFO PFX "timeout value must be 0<timeout<18000, using %d\n", | 402 | printk(KERN_INFO PFX |
410 | timeout); | 403 | "timeout value must be 0 < timeout < 18000, using %d\n", |
404 | timeout); | ||
411 | } | 405 | } |
412 | 406 | ||
413 | /* Calculate the watchdog's timeout */ | 407 | /* Calculate the watchdog's timeout */ |
@@ -415,15 +409,16 @@ static int __init watchdog_init(void) | |||
415 | 409 | ||
416 | ret = register_reboot_notifier(&ali_notifier); | 410 | ret = register_reboot_notifier(&ali_notifier); |
417 | if (ret != 0) { | 411 | if (ret != 0) { |
418 | printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", | 412 | printk(KERN_ERR PFX |
419 | ret); | 413 | "cannot register reboot notifier (err=%d)\n", ret); |
420 | goto out; | 414 | goto out; |
421 | } | 415 | } |
422 | 416 | ||
423 | ret = misc_register(&ali_miscdev); | 417 | ret = misc_register(&ali_miscdev); |
424 | if (ret != 0) { | 418 | if (ret != 0) { |
425 | printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", | 419 | printk(KERN_ERR PFX |
426 | WATCHDOG_MINOR, ret); | 420 | "cannot register miscdev on minor=%d (err=%d)\n", |
421 | WATCHDOG_MINOR, ret); | ||
427 | goto unreg_reboot; | 422 | goto unreg_reboot; |
428 | } | 423 | } |
429 | 424 | ||
diff --git a/drivers/watchdog/alim7101_wdt.c b/drivers/watchdog/alim7101_wdt.c index 238273c98656..a045ef869439 100644 --- a/drivers/watchdog/alim7101_wdt.c +++ b/drivers/watchdog/alim7101_wdt.c | |||
@@ -31,9 +31,9 @@ | |||
31 | #include <linux/init.h> | 31 | #include <linux/init.h> |
32 | #include <linux/fs.h> | 32 | #include <linux/fs.h> |
33 | #include <linux/pci.h> | 33 | #include <linux/pci.h> |
34 | #include <linux/io.h> | ||
35 | #include <linux/uaccess.h> | ||
34 | 36 | ||
35 | #include <asm/io.h> | ||
36 | #include <asm/uaccess.h> | ||
37 | #include <asm/system.h> | 37 | #include <asm/system.h> |
38 | 38 | ||
39 | #define OUR_NAME "alim7101_wdt" | 39 | #define OUR_NAME "alim7101_wdt" |
@@ -60,13 +60,17 @@ | |||
60 | */ | 60 | */ |
61 | 61 | ||
62 | #define WATCHDOG_TIMEOUT 30 /* 30 sec default timeout */ | 62 | #define WATCHDOG_TIMEOUT 30 /* 30 sec default timeout */ |
63 | static int timeout = WATCHDOG_TIMEOUT; /* in seconds, will be multiplied by HZ to get seconds to wait for a ping */ | 63 | /* in seconds, will be multiplied by HZ to get seconds to wait for a ping */ |
64 | static int timeout = WATCHDOG_TIMEOUT; | ||
64 | module_param(timeout, int, 0); | 65 | module_param(timeout, int, 0); |
65 | MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (1<=timeout<=3600, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")"); | 66 | MODULE_PARM_DESC(timeout, |
67 | "Watchdog timeout in seconds. (1<=timeout<=3600, default=" | ||
68 | __MODULE_STRING(WATCHDOG_TIMEOUT) ")"); | ||
66 | 69 | ||
67 | static int use_gpio = 0; /* Use the pic (for a1d revision alim7101) */ | 70 | static int use_gpio; /* Use the pic (for a1d revision alim7101) */ |
68 | module_param(use_gpio, int, 0); | 71 | module_param(use_gpio, int, 0); |
69 | MODULE_PARM_DESC(use_gpio, "Use the gpio watchdog. (required by old cobalt boards)"); | 72 | MODULE_PARM_DESC(use_gpio, |
73 | "Use the gpio watchdog (required by old cobalt boards)."); | ||
70 | 74 | ||
71 | static void wdt_timer_ping(unsigned long); | 75 | static void wdt_timer_ping(unsigned long); |
72 | static DEFINE_TIMER(timer, wdt_timer_ping, 0, 1); | 76 | static DEFINE_TIMER(timer, wdt_timer_ping, 0, 1); |
@@ -77,8 +81,9 @@ static struct pci_dev *alim7101_pmu; | |||
77 | 81 | ||
78 | static int nowayout = WATCHDOG_NOWAYOUT; | 82 | static int nowayout = WATCHDOG_NOWAYOUT; |
79 | module_param(nowayout, int, 0); | 83 | module_param(nowayout, int, 0); |
80 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" | 84 | MODULE_PARM_DESC(nowayout, |
81 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 85 | "Watchdog cannot be stopped once started (default=" |
86 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
82 | 87 | ||
83 | /* | 88 | /* |
84 | * Whack the dog | 89 | * Whack the dog |
@@ -89,23 +94,26 @@ static void wdt_timer_ping(unsigned long data) | |||
89 | /* If we got a heartbeat pulse within the WDT_US_INTERVAL | 94 | /* If we got a heartbeat pulse within the WDT_US_INTERVAL |
90 | * we agree to ping the WDT | 95 | * we agree to ping the WDT |
91 | */ | 96 | */ |
92 | char tmp; | 97 | char tmp; |
93 | 98 | ||
94 | if(time_before(jiffies, next_heartbeat)) | 99 | if (time_before(jiffies, next_heartbeat)) { |
95 | { | ||
96 | /* Ping the WDT (this is actually a disarm/arm sequence) */ | 100 | /* Ping the WDT (this is actually a disarm/arm sequence) */ |
97 | pci_read_config_byte(alim7101_pmu, 0x92, &tmp); | 101 | pci_read_config_byte(alim7101_pmu, 0x92, &tmp); |
98 | pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, (tmp & ~ALI_WDT_ARM)); | 102 | pci_write_config_byte(alim7101_pmu, |
99 | pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, (tmp | ALI_WDT_ARM)); | 103 | ALI_7101_WDT, (tmp & ~ALI_WDT_ARM)); |
104 | pci_write_config_byte(alim7101_pmu, | ||
105 | ALI_7101_WDT, (tmp | ALI_WDT_ARM)); | ||
100 | if (use_gpio) { | 106 | if (use_gpio) { |
101 | pci_read_config_byte(alim7101_pmu, ALI_7101_GPIO_O, &tmp); | 107 | pci_read_config_byte(alim7101_pmu, |
102 | pci_write_config_byte(alim7101_pmu, ALI_7101_GPIO_O, tmp | 108 | ALI_7101_GPIO_O, &tmp); |
103 | | 0x20); | 109 | pci_write_config_byte(alim7101_pmu, |
104 | pci_write_config_byte(alim7101_pmu, ALI_7101_GPIO_O, tmp | 110 | ALI_7101_GPIO_O, tmp | 0x20); |
105 | & ~0x20); | 111 | pci_write_config_byte(alim7101_pmu, |
112 | ALI_7101_GPIO_O, tmp & ~0x20); | ||
106 | } | 113 | } |
107 | } else { | 114 | } else { |
108 | printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n"); | 115 | printk(KERN_WARNING PFX |
116 | "Heartbeat lost! Will not ping the watchdog\n"); | ||
109 | } | 117 | } |
110 | /* Re-set the timer interval */ | 118 | /* Re-set the timer interval */ |
111 | mod_timer(&timer, jiffies + WDT_INTERVAL); | 119 | mod_timer(&timer, jiffies + WDT_INTERVAL); |
@@ -117,21 +125,27 @@ static void wdt_timer_ping(unsigned long data) | |||
117 | 125 | ||
118 | static void wdt_change(int writeval) | 126 | static void wdt_change(int writeval) |
119 | { | 127 | { |
120 | char tmp; | 128 | char tmp; |
121 | 129 | ||
122 | pci_read_config_byte(alim7101_pmu, ALI_7101_WDT, &tmp); | 130 | pci_read_config_byte(alim7101_pmu, ALI_7101_WDT, &tmp); |
123 | if (writeval == WDT_ENABLE) { | 131 | if (writeval == WDT_ENABLE) { |
124 | pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, (tmp | ALI_WDT_ARM)); | 132 | pci_write_config_byte(alim7101_pmu, |
133 | ALI_7101_WDT, (tmp | ALI_WDT_ARM)); | ||
125 | if (use_gpio) { | 134 | if (use_gpio) { |
126 | pci_read_config_byte(alim7101_pmu, ALI_7101_GPIO_O, &tmp); | 135 | pci_read_config_byte(alim7101_pmu, |
127 | pci_write_config_byte(alim7101_pmu, ALI_7101_GPIO_O, tmp & ~0x20); | 136 | ALI_7101_GPIO_O, &tmp); |
137 | pci_write_config_byte(alim7101_pmu, | ||
138 | ALI_7101_GPIO_O, tmp & ~0x20); | ||
128 | } | 139 | } |
129 | 140 | ||
130 | } else { | 141 | } else { |
131 | pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, (tmp & ~ALI_WDT_ARM)); | 142 | pci_write_config_byte(alim7101_pmu, |
143 | ALI_7101_WDT, (tmp & ~ALI_WDT_ARM)); | ||
132 | if (use_gpio) { | 144 | if (use_gpio) { |
133 | pci_read_config_byte(alim7101_pmu, ALI_7101_GPIO_O, &tmp); | 145 | pci_read_config_byte(alim7101_pmu, |
134 | pci_write_config_byte(alim7101_pmu, ALI_7101_GPIO_O, tmp | 0x20); | 146 | ALI_7101_GPIO_O, &tmp); |
147 | pci_write_config_byte(alim7101_pmu, | ||
148 | ALI_7101_GPIO_O, tmp | 0x20); | ||
135 | } | 149 | } |
136 | } | 150 | } |
137 | } | 151 | } |
@@ -169,10 +183,11 @@ static void wdt_keepalive(void) | |||
169 | * /dev/watchdog handling | 183 | * /dev/watchdog handling |
170 | */ | 184 | */ |
171 | 185 | ||
172 | static ssize_t fop_write(struct file * file, const char __user * buf, size_t count, loff_t * ppos) | 186 | static ssize_t fop_write(struct file *file, const char __user *buf, |
187 | size_t count, loff_t *ppos) | ||
173 | { | 188 | { |
174 | /* See if we got the magic character 'V' and reload the timer */ | 189 | /* See if we got the magic character 'V' and reload the timer */ |
175 | if(count) { | 190 | if (count) { |
176 | if (!nowayout) { | 191 | if (!nowayout) { |
177 | size_t ofs; | 192 | size_t ofs; |
178 | 193 | ||
@@ -183,7 +198,7 @@ static ssize_t fop_write(struct file * file, const char __user * buf, size_t cou | |||
183 | /* now scan */ | 198 | /* now scan */ |
184 | for (ofs = 0; ofs != count; ofs++) { | 199 | for (ofs = 0; ofs != count; ofs++) { |
185 | char c; | 200 | char c; |
186 | if (get_user(c, buf+ofs)) | 201 | if (get_user(c, buf + ofs)) |
187 | return -EFAULT; | 202 | return -EFAULT; |
188 | if (c == 'V') | 203 | if (c == 'V') |
189 | wdt_expect_close = 42; | 204 | wdt_expect_close = 42; |
@@ -195,119 +210,116 @@ static ssize_t fop_write(struct file * file, const char __user * buf, size_t cou | |||
195 | return count; | 210 | return count; |
196 | } | 211 | } |
197 | 212 | ||
198 | static int fop_open(struct inode * inode, struct file * file) | 213 | static int fop_open(struct inode *inode, struct file *file) |
199 | { | 214 | { |
200 | /* Just in case we're already talking to someone... */ | 215 | /* Just in case we're already talking to someone... */ |
201 | if(test_and_set_bit(0, &wdt_is_open)) | 216 | if (test_and_set_bit(0, &wdt_is_open)) |
202 | return -EBUSY; | 217 | return -EBUSY; |
203 | /* Good, fire up the show */ | 218 | /* Good, fire up the show */ |
204 | wdt_startup(); | 219 | wdt_startup(); |
205 | return nonseekable_open(inode, file); | 220 | return nonseekable_open(inode, file); |
206 | } | 221 | } |
207 | 222 | ||
208 | static int fop_close(struct inode * inode, struct file * file) | 223 | static int fop_close(struct inode *inode, struct file *file) |
209 | { | 224 | { |
210 | if(wdt_expect_close == 42) | 225 | if (wdt_expect_close == 42) |
211 | wdt_turnoff(); | 226 | wdt_turnoff(); |
212 | else { | 227 | else { |
213 | /* wim: shouldn't there be a: del_timer(&timer); */ | 228 | /* wim: shouldn't there be a: del_timer(&timer); */ |
214 | printk(KERN_CRIT PFX "device file closed unexpectedly. Will not stop the WDT!\n"); | 229 | printk(KERN_CRIT PFX |
230 | "device file closed unexpectedly. Will not stop the WDT!\n"); | ||
215 | } | 231 | } |
216 | clear_bit(0, &wdt_is_open); | 232 | clear_bit(0, &wdt_is_open); |
217 | wdt_expect_close = 0; | 233 | wdt_expect_close = 0; |
218 | return 0; | 234 | return 0; |
219 | } | 235 | } |
220 | 236 | ||
221 | static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) | 237 | static long fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
222 | { | 238 | { |
223 | void __user *argp = (void __user *)arg; | 239 | void __user *argp = (void __user *)arg; |
224 | int __user *p = argp; | 240 | int __user *p = argp; |
225 | static struct watchdog_info ident = | 241 | static struct watchdog_info ident = { |
226 | { | 242 | .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
227 | .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, | 243 | | WDIOF_MAGICCLOSE, |
228 | .firmware_version = 1, | 244 | .firmware_version = 1, |
229 | .identity = "ALiM7101", | 245 | .identity = "ALiM7101", |
230 | }; | 246 | }; |
231 | 247 | ||
232 | switch(cmd) | 248 | switch (cmd) { |
249 | case WDIOC_GETSUPPORT: | ||
250 | return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; | ||
251 | case WDIOC_GETSTATUS: | ||
252 | case WDIOC_GETBOOTSTATUS: | ||
253 | return put_user(0, p); | ||
254 | case WDIOC_SETOPTIONS: | ||
233 | { | 255 | { |
234 | case WDIOC_GETSUPPORT: | 256 | int new_options, retval = -EINVAL; |
235 | return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0; | ||
236 | case WDIOC_GETSTATUS: | ||
237 | case WDIOC_GETBOOTSTATUS: | ||
238 | return put_user(0, p); | ||
239 | case WDIOC_KEEPALIVE: | ||
240 | wdt_keepalive(); | ||
241 | return 0; | ||
242 | case WDIOC_SETOPTIONS: | ||
243 | { | ||
244 | int new_options, retval = -EINVAL; | ||
245 | |||
246 | if(get_user(new_options, p)) | ||
247 | return -EFAULT; | ||
248 | |||
249 | if(new_options & WDIOS_DISABLECARD) { | ||
250 | wdt_turnoff(); | ||
251 | retval = 0; | ||
252 | } | ||
253 | 257 | ||
254 | if(new_options & WDIOS_ENABLECARD) { | 258 | if (get_user(new_options, p)) |
255 | wdt_startup(); | 259 | return -EFAULT; |
256 | retval = 0; | 260 | if (new_options & WDIOS_DISABLECARD) { |
257 | } | 261 | wdt_turnoff(); |
258 | 262 | retval = 0; | |
259 | return retval; | ||
260 | } | 263 | } |
261 | case WDIOC_SETTIMEOUT: | 264 | if (new_options & WDIOS_ENABLECARD) { |
262 | { | 265 | wdt_startup(); |
263 | int new_timeout; | 266 | retval = 0; |
264 | |||
265 | if(get_user(new_timeout, p)) | ||
266 | return -EFAULT; | ||
267 | |||
268 | if(new_timeout < 1 || new_timeout > 3600) /* arbitrary upper limit */ | ||
269 | return -EINVAL; | ||
270 | |||
271 | timeout = new_timeout; | ||
272 | wdt_keepalive(); | ||
273 | /* Fall through */ | ||
274 | } | 267 | } |
275 | case WDIOC_GETTIMEOUT: | 268 | return retval; |
276 | return put_user(timeout, p); | 269 | } |
277 | default: | 270 | case WDIOC_KEEPALIVE: |
278 | return -ENOTTY; | 271 | wdt_keepalive(); |
272 | return 0; | ||
273 | case WDIOC_SETTIMEOUT: | ||
274 | { | ||
275 | int new_timeout; | ||
276 | |||
277 | if (get_user(new_timeout, p)) | ||
278 | return -EFAULT; | ||
279 | /* arbitrary upper limit */ | ||
280 | if (new_timeout < 1 || new_timeout > 3600) | ||
281 | return -EINVAL; | ||
282 | timeout = new_timeout; | ||
283 | wdt_keepalive(); | ||
284 | /* Fall through */ | ||
285 | } | ||
286 | case WDIOC_GETTIMEOUT: | ||
287 | return put_user(timeout, p); | ||
288 | default: | ||
289 | return -ENOTTY; | ||
279 | } | 290 | } |
280 | } | 291 | } |
281 | 292 | ||
282 | static const struct file_operations wdt_fops = { | 293 | static const struct file_operations wdt_fops = { |
283 | .owner= THIS_MODULE, | 294 | .owner = THIS_MODULE, |
284 | .llseek= no_llseek, | 295 | .llseek = no_llseek, |
285 | .write= fop_write, | 296 | .write = fop_write, |
286 | .open= fop_open, | 297 | .open = fop_open, |
287 | .release= fop_close, | 298 | .release = fop_close, |
288 | .ioctl= fop_ioctl, | 299 | .unlocked_ioctl = fop_ioctl, |
289 | }; | 300 | }; |
290 | 301 | ||
291 | static struct miscdevice wdt_miscdev = { | 302 | static struct miscdevice wdt_miscdev = { |
292 | .minor=WATCHDOG_MINOR, | 303 | .minor = WATCHDOG_MINOR, |
293 | .name="watchdog", | 304 | .name = "watchdog", |
294 | .fops=&wdt_fops, | 305 | .fops = &wdt_fops, |
295 | }; | 306 | }; |
296 | 307 | ||
297 | /* | 308 | /* |
298 | * Notifier for system down | 309 | * Notifier for system down |
299 | */ | 310 | */ |
300 | 311 | ||
301 | static int wdt_notify_sys(struct notifier_block *this, unsigned long code, void *unused) | 312 | static int wdt_notify_sys(struct notifier_block *this, |
313 | unsigned long code, void *unused) | ||
302 | { | 314 | { |
303 | if (code==SYS_DOWN || code==SYS_HALT) | 315 | if (code == SYS_DOWN || code == SYS_HALT) |
304 | wdt_turnoff(); | 316 | wdt_turnoff(); |
305 | 317 | ||
306 | if (code==SYS_RESTART) { | 318 | if (code == SYS_RESTART) { |
307 | /* | 319 | /* |
308 | * Cobalt devices have no way of rebooting themselves other than | 320 | * Cobalt devices have no way of rebooting themselves other |
309 | * getting the watchdog to pull reset, so we restart the watchdog on | 321 | * than getting the watchdog to pull reset, so we restart the |
310 | * reboot with no heartbeat | 322 | * watchdog on reboot with no heartbeat |
311 | */ | 323 | */ |
312 | wdt_change(WDT_ENABLE); | 324 | wdt_change(WDT_ENABLE); |
313 | printk(KERN_INFO PFX "Watchdog timer is now enabled with no heartbeat - should reboot in ~1 second.\n"); | 325 | printk(KERN_INFO PFX "Watchdog timer is now enabled with no heartbeat - should reboot in ~1 second.\n"); |
@@ -320,8 +332,7 @@ static int wdt_notify_sys(struct notifier_block *this, unsigned long code, void | |||
320 | * turn the timebomb registers off. | 332 | * turn the timebomb registers off. |
321 | */ | 333 | */ |
322 | 334 | ||
323 | static struct notifier_block wdt_notifier= | 335 | static struct notifier_block wdt_notifier = { |
324 | { | ||
325 | .notifier_call = wdt_notify_sys, | 336 | .notifier_call = wdt_notify_sys, |
326 | }; | 337 | }; |
327 | 338 | ||
@@ -354,7 +365,8 @@ static int __init alim7101_wdt_init(void) | |||
354 | ali1543_south = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, | 365 | ali1543_south = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, |
355 | NULL); | 366 | NULL); |
356 | if (!ali1543_south) { | 367 | if (!ali1543_south) { |
357 | printk(KERN_INFO PFX "ALi 1543 South-Bridge not present - WDT not set\n"); | 368 | printk(KERN_INFO PFX |
369 | "ALi 1543 South-Bridge not present - WDT not set\n"); | ||
358 | goto err_out; | 370 | goto err_out; |
359 | } | 371 | } |
360 | pci_read_config_byte(ali1543_south, 0x5e, &tmp); | 372 | pci_read_config_byte(ali1543_south, 0x5e, &tmp); |
@@ -363,24 +375,25 @@ static int __init alim7101_wdt_init(void) | |||
363 | if (!use_gpio) { | 375 | if (!use_gpio) { |
364 | printk(KERN_INFO PFX "Detected old alim7101 revision 'a1d'. If this is a cobalt board, set the 'use_gpio' module parameter.\n"); | 376 | printk(KERN_INFO PFX "Detected old alim7101 revision 'a1d'. If this is a cobalt board, set the 'use_gpio' module parameter.\n"); |
365 | goto err_out; | 377 | goto err_out; |
366 | } | 378 | } |
367 | nowayout = 1; | 379 | nowayout = 1; |
368 | } else if ((tmp & 0x1e) != 0x12 && (tmp & 0x1e) != 0x00) { | 380 | } else if ((tmp & 0x1e) != 0x12 && (tmp & 0x1e) != 0x00) { |
369 | printk(KERN_INFO PFX "ALi 1543 South-Bridge does not have the correct revision number (???1001?) - WDT not set\n"); | 381 | printk(KERN_INFO PFX "ALi 1543 South-Bridge does not have the correct revision number (???1001?) - WDT not set\n"); |
370 | goto err_out; | 382 | goto err_out; |
371 | } | 383 | } |
372 | 384 | ||
373 | if(timeout < 1 || timeout > 3600) /* arbitrary upper limit */ | 385 | if (timeout < 1 || timeout > 3600) { |
374 | { | 386 | /* arbitrary upper limit */ |
375 | timeout = WATCHDOG_TIMEOUT; | 387 | timeout = WATCHDOG_TIMEOUT; |
376 | printk(KERN_INFO PFX "timeout value must be 1<=x<=3600, using %d\n", | 388 | printk(KERN_INFO PFX |
377 | timeout); | 389 | "timeout value must be 1 <= x <= 3600, using %d\n", |
390 | timeout); | ||
378 | } | 391 | } |
379 | 392 | ||
380 | rc = register_reboot_notifier(&wdt_notifier); | 393 | rc = register_reboot_notifier(&wdt_notifier); |
381 | if (rc) { | 394 | if (rc) { |
382 | printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", | 395 | printk(KERN_ERR PFX |
383 | rc); | 396 | "cannot register reboot notifier (err=%d)\n", rc); |
384 | goto err_out; | 397 | goto err_out; |
385 | } | 398 | } |
386 | 399 | ||
@@ -391,9 +404,8 @@ static int __init alim7101_wdt_init(void) | |||
391 | goto err_out_reboot; | 404 | goto err_out_reboot; |
392 | } | 405 | } |
393 | 406 | ||
394 | if (nowayout) { | 407 | if (nowayout) |
395 | __module_get(THIS_MODULE); | 408 | __module_get(THIS_MODULE); |
396 | } | ||
397 | 409 | ||
398 | printk(KERN_INFO PFX "WDT driver for ALi M7101 initialised. timeout=%d sec (nowayout=%d)\n", | 410 | printk(KERN_INFO PFX "WDT driver for ALi M7101 initialised. timeout=%d sec (nowayout=%d)\n", |
399 | timeout, nowayout); | 411 | timeout, nowayout); |
diff --git a/drivers/watchdog/ar7_wdt.c b/drivers/watchdog/ar7_wdt.c index ef7b0d67095e..55dcbfe2bb72 100644 --- a/drivers/watchdog/ar7_wdt.c +++ b/drivers/watchdog/ar7_wdt.c | |||
@@ -213,7 +213,7 @@ static int ar7_wdt_notify_sys(struct notifier_block *this, | |||
213 | } | 213 | } |
214 | 214 | ||
215 | static struct notifier_block ar7_wdt_notifier = { | 215 | static struct notifier_block ar7_wdt_notifier = { |
216 | .notifier_call = ar7_wdt_notify_sys | 216 | .notifier_call = ar7_wdt_notify_sys, |
217 | }; | 217 | }; |
218 | 218 | ||
219 | static ssize_t ar7_wdt_write(struct file *file, const char *data, | 219 | static ssize_t ar7_wdt_write(struct file *file, const char *data, |
@@ -230,7 +230,7 @@ static ssize_t ar7_wdt_write(struct file *file, const char *data, | |||
230 | expect_close = 0; | 230 | expect_close = 0; |
231 | for (i = 0; i < len; ++i) { | 231 | for (i = 0; i < len; ++i) { |
232 | char c; | 232 | char c; |
233 | if (get_user(c, data+i)) | 233 | if (get_user(c, data + i)) |
234 | return -EFAULT; | 234 | return -EFAULT; |
235 | if (c == 'V') | 235 | if (c == 'V') |
236 | expect_close = 1; | 236 | expect_close = 1; |
@@ -251,8 +251,6 @@ static long ar7_wdt_ioctl(struct file *file, | |||
251 | int new_margin; | 251 | int new_margin; |
252 | 252 | ||
253 | switch (cmd) { | 253 | switch (cmd) { |
254 | default: | ||
255 | return -ENOTTY; | ||
256 | case WDIOC_GETSUPPORT: | 254 | case WDIOC_GETSUPPORT: |
257 | if (copy_to_user((struct watchdog_info *)arg, &ident, | 255 | if (copy_to_user((struct watchdog_info *)arg, &ident, |
258 | sizeof(ident))) | 256 | sizeof(ident))) |
@@ -281,6 +279,8 @@ static long ar7_wdt_ioctl(struct file *file, | |||
281 | if (put_user(margin, (int *)arg)) | 279 | if (put_user(margin, (int *)arg)) |
282 | return -EFAULT; | 280 | return -EFAULT; |
283 | return 0; | 281 | return 0; |
282 | default: | ||
283 | return -ENOTTY; | ||
284 | } | 284 | } |
285 | } | 285 | } |
286 | 286 | ||
diff --git a/drivers/watchdog/at32ap700x_wdt.c b/drivers/watchdog/at32ap700x_wdt.c index ae0fca5e8749..e8ae638e5804 100644 --- a/drivers/watchdog/at32ap700x_wdt.c +++ b/drivers/watchdog/at32ap700x_wdt.c | |||
@@ -212,8 +212,8 @@ static struct watchdog_info at32_wdt_info = { | |||
212 | /* | 212 | /* |
213 | * Handle commands from user-space. | 213 | * Handle commands from user-space. |
214 | */ | 214 | */ |
215 | static int at32_wdt_ioctl(struct inode *inode, struct file *file, | 215 | static long at32_wdt_ioctl(struct file *file, |
216 | unsigned int cmd, unsigned long arg) | 216 | unsigned int cmd, unsigned long arg) |
217 | { | 217 | { |
218 | int ret = -ENOTTY; | 218 | int ret = -ENOTTY; |
219 | int time; | 219 | int time; |
@@ -221,27 +221,10 @@ static int at32_wdt_ioctl(struct inode *inode, struct file *file, | |||
221 | int __user *p = argp; | 221 | int __user *p = argp; |
222 | 222 | ||
223 | switch (cmd) { | 223 | switch (cmd) { |
224 | case WDIOC_KEEPALIVE: | ||
225 | at32_wdt_pat(); | ||
226 | ret = 0; | ||
227 | break; | ||
228 | case WDIOC_GETSUPPORT: | 224 | case WDIOC_GETSUPPORT: |
229 | ret = copy_to_user(argp, &at32_wdt_info, | 225 | ret = copy_to_user(argp, &at32_wdt_info, |
230 | sizeof(at32_wdt_info)) ? -EFAULT : 0; | 226 | sizeof(at32_wdt_info)) ? -EFAULT : 0; |
231 | break; | 227 | break; |
232 | case WDIOC_SETTIMEOUT: | ||
233 | ret = get_user(time, p); | ||
234 | if (ret) | ||
235 | break; | ||
236 | ret = at32_wdt_settimeout(time); | ||
237 | if (ret) | ||
238 | break; | ||
239 | /* Enable new time value */ | ||
240 | at32_wdt_start(); | ||
241 | /* fall through */ | ||
242 | case WDIOC_GETTIMEOUT: | ||
243 | ret = put_user(wdt->timeout, p); | ||
244 | break; | ||
245 | case WDIOC_GETSTATUS: | 228 | case WDIOC_GETSTATUS: |
246 | ret = put_user(0, p); | 229 | ret = put_user(0, p); |
247 | break; | 230 | break; |
@@ -258,6 +241,23 @@ static int at32_wdt_ioctl(struct inode *inode, struct file *file, | |||
258 | at32_wdt_start(); | 241 | at32_wdt_start(); |
259 | ret = 0; | 242 | ret = 0; |
260 | break; | 243 | break; |
244 | case WDIOC_KEEPALIVE: | ||
245 | at32_wdt_pat(); | ||
246 | ret = 0; | ||
247 | break; | ||
248 | case WDIOC_SETTIMEOUT: | ||
249 | ret = get_user(time, p); | ||
250 | if (ret) | ||
251 | break; | ||
252 | ret = at32_wdt_settimeout(time); | ||
253 | if (ret) | ||
254 | break; | ||
255 | /* Enable new time value */ | ||
256 | at32_wdt_start(); | ||
257 | /* fall through */ | ||
258 | case WDIOC_GETTIMEOUT: | ||
259 | ret = put_user(wdt->timeout, p); | ||
260 | break; | ||
261 | } | 261 | } |
262 | 262 | ||
263 | return ret; | 263 | return ret; |
@@ -283,7 +283,7 @@ static ssize_t at32_wdt_write(struct file *file, const char __user *data, | |||
283 | */ | 283 | */ |
284 | for (i = 0; i != len; i++) { | 284 | for (i = 0; i != len; i++) { |
285 | char c; | 285 | char c; |
286 | if (get_user(c, data+i)) | 286 | if (get_user(c, data + i)) |
287 | return -EFAULT; | 287 | return -EFAULT; |
288 | if (c == 'V') | 288 | if (c == 'V') |
289 | expect_release = 42; | 289 | expect_release = 42; |
@@ -298,7 +298,7 @@ static ssize_t at32_wdt_write(struct file *file, const char __user *data, | |||
298 | static const struct file_operations at32_wdt_fops = { | 298 | static const struct file_operations at32_wdt_fops = { |
299 | .owner = THIS_MODULE, | 299 | .owner = THIS_MODULE, |
300 | .llseek = no_llseek, | 300 | .llseek = no_llseek, |
301 | .ioctl = at32_wdt_ioctl, | 301 | .unlocked_ioctl = at32_wdt_ioctl, |
302 | .open = at32_wdt_open, | 302 | .open = at32_wdt_open, |
303 | .release = at32_wdt_close, | 303 | .release = at32_wdt_close, |
304 | .write = at32_wdt_write, | 304 | .write = at32_wdt_write, |
@@ -391,7 +391,6 @@ static int __exit at32_wdt_remove(struct platform_device *pdev) | |||
391 | wdt = NULL; | 391 | wdt = NULL; |
392 | platform_set_drvdata(pdev, NULL); | 392 | platform_set_drvdata(pdev, NULL); |
393 | } | 393 | } |
394 | |||
395 | return 0; | 394 | return 0; |
396 | } | 395 | } |
397 | 396 | ||
diff --git a/drivers/watchdog/at91rm9200_wdt.c b/drivers/watchdog/at91rm9200_wdt.c index 9ff9a9565320..2313f44144f8 100644 --- a/drivers/watchdog/at91rm9200_wdt.c +++ b/drivers/watchdog/at91rm9200_wdt.c | |||
@@ -20,7 +20,7 @@ | |||
20 | #include <linux/platform_device.h> | 20 | #include <linux/platform_device.h> |
21 | #include <linux/types.h> | 21 | #include <linux/types.h> |
22 | #include <linux/watchdog.h> | 22 | #include <linux/watchdog.h> |
23 | #include <asm/uaccess.h> | 23 | #include <linux/uaccess.h> |
24 | #include <asm/arch/at91_st.h> | 24 | #include <asm/arch/at91_st.h> |
25 | 25 | ||
26 | 26 | ||
@@ -31,11 +31,14 @@ static int wdt_time = WDT_DEFAULT_TIME; | |||
31 | static int nowayout = WATCHDOG_NOWAYOUT; | 31 | static int nowayout = WATCHDOG_NOWAYOUT; |
32 | 32 | ||
33 | module_param(wdt_time, int, 0); | 33 | module_param(wdt_time, int, 0); |
34 | MODULE_PARM_DESC(wdt_time, "Watchdog time in seconds. (default="__MODULE_STRING(WDT_DEFAULT_TIME) ")"); | 34 | MODULE_PARM_DESC(wdt_time, "Watchdog time in seconds. (default=" |
35 | __MODULE_STRING(WDT_DEFAULT_TIME) ")"); | ||
35 | 36 | ||
36 | #ifdef CONFIG_WATCHDOG_NOWAYOUT | 37 | #ifdef CONFIG_WATCHDOG_NOWAYOUT |
37 | module_param(nowayout, int, 0); | 38 | module_param(nowayout, int, 0); |
38 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 39 | MODULE_PARM_DESC(nowayout, |
40 | "Watchdog cannot be stopped once started (default=" | ||
41 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
39 | #endif | 42 | #endif |
40 | 43 | ||
41 | 44 | ||
@@ -46,7 +49,7 @@ static unsigned long at91wdt_busy; | |||
46 | /* | 49 | /* |
47 | * Disable the watchdog. | 50 | * Disable the watchdog. |
48 | */ | 51 | */ |
49 | static void inline at91_wdt_stop(void) | 52 | static inline void at91_wdt_stop(void) |
50 | { | 53 | { |
51 | at91_sys_write(AT91_ST_WDMR, AT91_ST_EXTEN); | 54 | at91_sys_write(AT91_ST_WDMR, AT91_ST_EXTEN); |
52 | } | 55 | } |
@@ -54,16 +57,17 @@ static void inline at91_wdt_stop(void) | |||
54 | /* | 57 | /* |
55 | * Enable and reset the watchdog. | 58 | * Enable and reset the watchdog. |
56 | */ | 59 | */ |
57 | static void inline at91_wdt_start(void) | 60 | static inline void at91_wdt_start(void) |
58 | { | 61 | { |
59 | at91_sys_write(AT91_ST_WDMR, AT91_ST_EXTEN | AT91_ST_RSTEN | (((65536 * wdt_time) >> 8) & AT91_ST_WDV)); | 62 | at91_sys_write(AT91_ST_WDMR, AT91_ST_EXTEN | AT91_ST_RSTEN | |
63 | (((65536 * wdt_time) >> 8) & AT91_ST_WDV)); | ||
60 | at91_sys_write(AT91_ST_CR, AT91_ST_WDRST); | 64 | at91_sys_write(AT91_ST_CR, AT91_ST_WDRST); |
61 | } | 65 | } |
62 | 66 | ||
63 | /* | 67 | /* |
64 | * Reload the watchdog timer. (ie, pat the watchdog) | 68 | * Reload the watchdog timer. (ie, pat the watchdog) |
65 | */ | 69 | */ |
66 | static void inline at91_wdt_reload(void) | 70 | static inline void at91_wdt_reload(void) |
67 | { | 71 | { |
68 | at91_sys_write(AT91_ST_CR, AT91_ST_WDRST); | 72 | at91_sys_write(AT91_ST_CR, AT91_ST_WDRST); |
69 | } | 73 | } |
@@ -89,8 +93,9 @@ static int at91_wdt_open(struct inode *inode, struct file *file) | |||
89 | */ | 93 | */ |
90 | static int at91_wdt_close(struct inode *inode, struct file *file) | 94 | static int at91_wdt_close(struct inode *inode, struct file *file) |
91 | { | 95 | { |
96 | /* Disable the watchdog when file is closed */ | ||
92 | if (!nowayout) | 97 | if (!nowayout) |
93 | at91_wdt_stop(); /* Disable the watchdog when file is closed */ | 98 | at91_wdt_stop(); |
94 | 99 | ||
95 | clear_bit(0, &at91wdt_busy); | 100 | clear_bit(0, &at91wdt_busy); |
96 | return 0; | 101 | return 0; |
@@ -110,7 +115,8 @@ static int at91_wdt_settimeout(int new_time) | |||
110 | if ((new_time <= 0) || (new_time > WDT_MAX_TIME)) | 115 | if ((new_time <= 0) || (new_time > WDT_MAX_TIME)) |
111 | return -EINVAL; | 116 | return -EINVAL; |
112 | 117 | ||
113 | /* Set new watchdog time. It will be used when at91_wdt_start() is called. */ | 118 | /* Set new watchdog time. It will be used when |
119 | at91_wdt_start() is called. */ | ||
114 | wdt_time = new_time; | 120 | wdt_time = new_time; |
115 | return 0; | 121 | return 0; |
116 | } | 122 | } |
@@ -123,60 +129,52 @@ static struct watchdog_info at91_wdt_info = { | |||
123 | /* | 129 | /* |
124 | * Handle commands from user-space. | 130 | * Handle commands from user-space. |
125 | */ | 131 | */ |
126 | static int at91_wdt_ioctl(struct inode *inode, struct file *file, | 132 | static long at91_wdt_ioct(struct file *file, |
127 | unsigned int cmd, unsigned long arg) | 133 | unsigned int cmd, unsigned long arg) |
128 | { | 134 | { |
129 | void __user *argp = (void __user *)arg; | 135 | void __user *argp = (void __user *)arg; |
130 | int __user *p = argp; | 136 | int __user *p = argp; |
131 | int new_value; | 137 | int new_value; |
132 | 138 | ||
133 | switch(cmd) { | 139 | switch (cmd) { |
134 | case WDIOC_KEEPALIVE: | 140 | case WDIOC_GETSUPPORT: |
135 | at91_wdt_reload(); /* pat the watchdog */ | 141 | return copy_to_user(argp, &at91_wdt_info, |
136 | return 0; | 142 | sizeof(at91_wdt_info)) ? -EFAULT : 0; |
137 | 143 | case WDIOC_GETSTATUS: | |
138 | case WDIOC_GETSUPPORT: | 144 | case WDIOC_GETBOOTSTATUS: |
139 | return copy_to_user(argp, &at91_wdt_info, sizeof(at91_wdt_info)) ? -EFAULT : 0; | 145 | return put_user(0, p); |
140 | 146 | case WDIOC_SETOPTIONS: | |
141 | case WDIOC_SETTIMEOUT: | 147 | if (get_user(new_value, p)) |
142 | if (get_user(new_value, p)) | 148 | return -EFAULT; |
143 | return -EFAULT; | 149 | if (new_value & WDIOS_DISABLECARD) |
144 | 150 | at91_wdt_stop(); | |
145 | if (at91_wdt_settimeout(new_value)) | 151 | if (new_value & WDIOS_ENABLECARD) |
146 | return -EINVAL; | ||
147 | |||
148 | /* Enable new time value */ | ||
149 | at91_wdt_start(); | 152 | at91_wdt_start(); |
150 | 153 | return 0; | |
151 | /* Return current value */ | 154 | case WDIOC_KEEPALIVE: |
152 | return put_user(wdt_time, p); | 155 | at91_wdt_reload(); /* pat the watchdog */ |
153 | 156 | return 0; | |
154 | case WDIOC_GETTIMEOUT: | 157 | case WDIOC_SETTIMEOUT: |
155 | return put_user(wdt_time, p); | 158 | if (get_user(new_value, p)) |
156 | 159 | return -EFAULT; | |
157 | case WDIOC_GETSTATUS: | 160 | if (at91_wdt_settimeout(new_value)) |
158 | case WDIOC_GETBOOTSTATUS: | 161 | return -EINVAL; |
159 | return put_user(0, p); | 162 | /* Enable new time value */ |
160 | 163 | at91_wdt_start(); | |
161 | case WDIOC_SETOPTIONS: | 164 | /* Return current value */ |
162 | if (get_user(new_value, p)) | 165 | return put_user(wdt_time, p); |
163 | return -EFAULT; | 166 | case WDIOC_GETTIMEOUT: |
164 | 167 | return put_user(wdt_time, p); | |
165 | if (new_value & WDIOS_DISABLECARD) | 168 | default: |
166 | at91_wdt_stop(); | 169 | return -ENOTTY; |
167 | if (new_value & WDIOS_ENABLECARD) | ||
168 | at91_wdt_start(); | ||
169 | return 0; | ||
170 | |||
171 | default: | ||
172 | return -ENOTTY; | ||
173 | } | 170 | } |
174 | } | 171 | } |
175 | 172 | ||
176 | /* | 173 | /* |
177 | * Pat the watchdog whenever device is written to. | 174 | * Pat the watchdog whenever device is written to. |
178 | */ | 175 | */ |
179 | static ssize_t at91_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos) | 176 | static ssize_t at91_wdt_write(struct file *file, const char *data, |
177 | size_t len, loff_t *ppos) | ||
180 | { | 178 | { |
181 | at91_wdt_reload(); /* pat the watchdog */ | 179 | at91_wdt_reload(); /* pat the watchdog */ |
182 | return len; | 180 | return len; |
@@ -187,7 +185,7 @@ static ssize_t at91_wdt_write(struct file *file, const char *data, size_t len, l | |||
187 | static const struct file_operations at91wdt_fops = { | 185 | static const struct file_operations at91wdt_fops = { |
188 | .owner = THIS_MODULE, | 186 | .owner = THIS_MODULE, |
189 | .llseek = no_llseek, | 187 | .llseek = no_llseek, |
190 | .ioctl = at91_wdt_ioctl, | 188 | .unlocked_ioctl = at91_wdt_ioctl, |
191 | .open = at91_wdt_open, | 189 | .open = at91_wdt_open, |
192 | .release = at91_wdt_close, | 190 | .release = at91_wdt_close, |
193 | .write = at91_wdt_write, | 191 | .write = at91_wdt_write, |
@@ -211,7 +209,8 @@ static int __init at91wdt_probe(struct platform_device *pdev) | |||
211 | if (res) | 209 | if (res) |
212 | return res; | 210 | return res; |
213 | 211 | ||
214 | printk("AT91 Watchdog Timer enabled (%d seconds%s)\n", wdt_time, nowayout ? ", nowayout" : ""); | 212 | printk(KERN_INFO "AT91 Watchdog Timer enabled (%d seconds%s)\n", |
213 | wdt_time, nowayout ? ", nowayout" : ""); | ||
215 | return 0; | 214 | return 0; |
216 | } | 215 | } |
217 | 216 | ||
@@ -265,7 +264,8 @@ static struct platform_driver at91wdt_driver = { | |||
265 | 264 | ||
266 | static int __init at91_wdt_init(void) | 265 | static int __init at91_wdt_init(void) |
267 | { | 266 | { |
268 | /* Check that the heartbeat value is within range; if not reset to the default */ | 267 | /* Check that the heartbeat value is within range; |
268 | if not reset to the default */ | ||
269 | if (at91_wdt_settimeout(wdt_time)) { | 269 | if (at91_wdt_settimeout(wdt_time)) { |
270 | at91_wdt_settimeout(WDT_DEFAULT_TIME); | 270 | at91_wdt_settimeout(WDT_DEFAULT_TIME); |
271 | pr_info("at91_wdt: wdt_time value must be 1 <= wdt_time <= 256, using %d\n", wdt_time); | 271 | pr_info("at91_wdt: wdt_time value must be 1 <= wdt_time <= 256, using %d\n", wdt_time); |
diff --git a/drivers/watchdog/bfin_wdt.c b/drivers/watchdog/bfin_wdt.c index 03b3e3d91e7c..31b42253054e 100644 --- a/drivers/watchdog/bfin_wdt.c +++ b/drivers/watchdog/bfin_wdt.c | |||
@@ -24,8 +24,8 @@ | |||
24 | #include <linux/reboot.h> | 24 | #include <linux/reboot.h> |
25 | #include <linux/init.h> | 25 | #include <linux/init.h> |
26 | #include <linux/interrupt.h> | 26 | #include <linux/interrupt.h> |
27 | #include <linux/uaccess.h> | ||
27 | #include <asm/blackfin.h> | 28 | #include <asm/blackfin.h> |
28 | #include <asm/uaccess.h> | ||
29 | 29 | ||
30 | #define stamp(fmt, args...) pr_debug("%s:%i: " fmt "\n", __func__, __LINE__, ## args) | 30 | #define stamp(fmt, args...) pr_debug("%s:%i: " fmt "\n", __func__, __LINE__, ## args) |
31 | #define stampit() stamp("here i am") | 31 | #define stampit() stamp("here i am") |
@@ -148,7 +148,8 @@ static int bfin_wdt_set_timeout(unsigned long t) | |||
148 | int run = bfin_wdt_running(); | 148 | int run = bfin_wdt_running(); |
149 | bfin_wdt_stop(); | 149 | bfin_wdt_stop(); |
150 | bfin_write_WDOG_CNT(cnt); | 150 | bfin_write_WDOG_CNT(cnt); |
151 | if (run) bfin_wdt_start(); | 151 | if (run) |
152 | bfin_wdt_start(); | ||
152 | } | 153 | } |
153 | spin_unlock_irqrestore(&bfin_wdt_spinlock, flags); | 154 | spin_unlock_irqrestore(&bfin_wdt_spinlock, flags); |
154 | 155 | ||
@@ -191,16 +192,15 @@ static int bfin_wdt_release(struct inode *inode, struct file *file) | |||
191 | { | 192 | { |
192 | stampit(); | 193 | stampit(); |
193 | 194 | ||
194 | if (expect_close == 42) { | 195 | if (expect_close == 42) |
195 | bfin_wdt_stop(); | 196 | bfin_wdt_stop(); |
196 | } else { | 197 | else { |
197 | printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); | 198 | printk(KERN_CRIT PFX |
199 | "Unexpected close, not stopping watchdog!\n"); | ||
198 | bfin_wdt_keepalive(); | 200 | bfin_wdt_keepalive(); |
199 | } | 201 | } |
200 | |||
201 | expect_close = 0; | 202 | expect_close = 0; |
202 | clear_bit(0, &open_check); | 203 | clear_bit(0, &open_check); |
203 | |||
204 | return 0; | 204 | return 0; |
205 | } | 205 | } |
206 | 206 | ||
@@ -214,7 +214,7 @@ static int bfin_wdt_release(struct inode *inode, struct file *file) | |||
214 | * Pings the watchdog on write. | 214 | * Pings the watchdog on write. |
215 | */ | 215 | */ |
216 | static ssize_t bfin_wdt_write(struct file *file, const char __user *data, | 216 | static ssize_t bfin_wdt_write(struct file *file, const char __user *data, |
217 | size_t len, loff_t *ppos) | 217 | size_t len, loff_t *ppos) |
218 | { | 218 | { |
219 | stampit(); | 219 | stampit(); |
220 | 220 | ||
@@ -241,7 +241,6 @@ static ssize_t bfin_wdt_write(struct file *file, const char __user *data, | |||
241 | 241 | ||
242 | /** | 242 | /** |
243 | * bfin_wdt_ioctl - Query Device | 243 | * bfin_wdt_ioctl - Query Device |
244 | * @inode: inode of device | ||
245 | * @file: file handle of device | 244 | * @file: file handle of device |
246 | * @cmd: watchdog command | 245 | * @cmd: watchdog command |
247 | * @arg: argument | 246 | * @arg: argument |
@@ -249,8 +248,8 @@ static ssize_t bfin_wdt_write(struct file *file, const char __user *data, | |||
249 | * Query basic information from the device or ping it, as outlined by the | 248 | * Query basic information from the device or ping it, as outlined by the |
250 | * watchdog API. | 249 | * watchdog API. |
251 | */ | 250 | */ |
252 | static int bfin_wdt_ioctl(struct inode *inode, struct file *file, | 251 | static long bfin_wdt_ioctl(struct file *file, |
253 | unsigned int cmd, unsigned long arg) | 252 | unsigned int cmd, unsigned long arg) |
254 | { | 253 | { |
255 | void __user *argp = (void __user *)arg; | 254 | void __user *argp = (void __user *)arg; |
256 | int __user *p = argp; | 255 | int __user *p = argp; |
@@ -258,59 +257,49 @@ static int bfin_wdt_ioctl(struct inode *inode, struct file *file, | |||
258 | stampit(); | 257 | stampit(); |
259 | 258 | ||
260 | switch (cmd) { | 259 | switch (cmd) { |
261 | default: | 260 | case WDIOC_GETSUPPORT: |
262 | return -ENOTTY; | 261 | if (copy_to_user(argp, &bfin_wdt_info, sizeof(bfin_wdt_info))) |
263 | 262 | return -EFAULT; | |
264 | case WDIOC_GETSUPPORT: | 263 | else |
265 | if (copy_to_user(argp, &bfin_wdt_info, sizeof(bfin_wdt_info))) | ||
266 | return -EFAULT; | ||
267 | else | ||
268 | return 0; | ||
269 | |||
270 | case WDIOC_GETSTATUS: | ||
271 | case WDIOC_GETBOOTSTATUS: | ||
272 | return put_user(!!(_bfin_swrst & SWRST_RESET_WDOG), p); | ||
273 | |||
274 | case WDIOC_KEEPALIVE: | ||
275 | bfin_wdt_keepalive(); | ||
276 | return 0; | 264 | return 0; |
277 | 265 | case WDIOC_GETSTATUS: | |
278 | case WDIOC_SETTIMEOUT: { | 266 | case WDIOC_GETBOOTSTATUS: |
279 | int new_timeout; | 267 | return put_user(!!(_bfin_swrst & SWRST_RESET_WDOG), p); |
280 | 268 | case WDIOC_SETOPTIONS: { | |
281 | if (get_user(new_timeout, p)) | 269 | unsigned long flags; |
282 | return -EFAULT; | 270 | int options, ret = -EINVAL; |
283 | 271 | ||
284 | if (bfin_wdt_set_timeout(new_timeout)) | 272 | if (get_user(options, p)) |
285 | return -EINVAL; | 273 | return -EFAULT; |
274 | |||
275 | spin_lock_irqsave(&bfin_wdt_spinlock, flags); | ||
276 | if (options & WDIOS_DISABLECARD) { | ||
277 | bfin_wdt_stop(); | ||
278 | ret = 0; | ||
286 | } | 279 | } |
287 | /* Fall */ | 280 | if (options & WDIOS_ENABLECARD) { |
288 | case WDIOC_GETTIMEOUT: | 281 | bfin_wdt_start(); |
289 | return put_user(timeout, p); | 282 | ret = 0; |
290 | |||
291 | case WDIOC_SETOPTIONS: { | ||
292 | unsigned long flags; | ||
293 | int options, ret = -EINVAL; | ||
294 | |||
295 | if (get_user(options, p)) | ||
296 | return -EFAULT; | ||
297 | |||
298 | spin_lock_irqsave(&bfin_wdt_spinlock, flags); | ||
299 | |||
300 | if (options & WDIOS_DISABLECARD) { | ||
301 | bfin_wdt_stop(); | ||
302 | ret = 0; | ||
303 | } | ||
304 | |||
305 | if (options & WDIOS_ENABLECARD) { | ||
306 | bfin_wdt_start(); | ||
307 | ret = 0; | ||
308 | } | ||
309 | |||
310 | spin_unlock_irqrestore(&bfin_wdt_spinlock, flags); | ||
311 | |||
312 | return ret; | ||
313 | } | 283 | } |
284 | spin_unlock_irqrestore(&bfin_wdt_spinlock, flags); | ||
285 | return ret; | ||
286 | } | ||
287 | case WDIOC_KEEPALIVE: | ||
288 | bfin_wdt_keepalive(); | ||
289 | return 0; | ||
290 | case WDIOC_SETTIMEOUT: { | ||
291 | int new_timeout; | ||
292 | |||
293 | if (get_user(new_timeout, p)) | ||
294 | return -EFAULT; | ||
295 | if (bfin_wdt_set_timeout(new_timeout)) | ||
296 | return -EINVAL; | ||
297 | } | ||
298 | /* Fall */ | ||
299 | case WDIOC_GETTIMEOUT: | ||
300 | return put_user(timeout, p); | ||
301 | default: | ||
302 | return -ENOTTY; | ||
314 | } | 303 | } |
315 | } | 304 | } |
316 | 305 | ||
@@ -323,8 +312,8 @@ static int bfin_wdt_ioctl(struct inode *inode, struct file *file, | |||
323 | * Handles specific events, such as turning off the watchdog during a | 312 | * Handles specific events, such as turning off the watchdog during a |
324 | * shutdown event. | 313 | * shutdown event. |
325 | */ | 314 | */ |
326 | static int bfin_wdt_notify_sys(struct notifier_block *this, unsigned long code, | 315 | static int bfin_wdt_notify_sys(struct notifier_block *this, |
327 | void *unused) | 316 | unsigned long code, void *unused) |
328 | { | 317 | { |
329 | stampit(); | 318 | stampit(); |
330 | 319 | ||
@@ -379,12 +368,12 @@ static int bfin_wdt_resume(struct platform_device *pdev) | |||
379 | #endif | 368 | #endif |
380 | 369 | ||
381 | static const struct file_operations bfin_wdt_fops = { | 370 | static const struct file_operations bfin_wdt_fops = { |
382 | .owner = THIS_MODULE, | 371 | .owner = THIS_MODULE, |
383 | .llseek = no_llseek, | 372 | .llseek = no_llseek, |
384 | .write = bfin_wdt_write, | 373 | .write = bfin_wdt_write, |
385 | .ioctl = bfin_wdt_ioctl, | 374 | .unlocked_ioctl = bfin_wdt_ioctl, |
386 | .open = bfin_wdt_open, | 375 | .open = bfin_wdt_open, |
387 | .release = bfin_wdt_release, | 376 | .release = bfin_wdt_release, |
388 | }; | 377 | }; |
389 | 378 | ||
390 | static struct miscdevice bfin_wdt_miscdev = { | 379 | static struct miscdevice bfin_wdt_miscdev = { |
@@ -396,8 +385,8 @@ static struct miscdevice bfin_wdt_miscdev = { | |||
396 | static struct watchdog_info bfin_wdt_info = { | 385 | static struct watchdog_info bfin_wdt_info = { |
397 | .identity = "Blackfin Watchdog", | 386 | .identity = "Blackfin Watchdog", |
398 | .options = WDIOF_SETTIMEOUT | | 387 | .options = WDIOF_SETTIMEOUT | |
399 | WDIOF_KEEPALIVEPING | | 388 | WDIOF_KEEPALIVEPING | |
400 | WDIOF_MAGICCLOSE, | 389 | WDIOF_MAGICCLOSE, |
401 | }; | 390 | }; |
402 | 391 | ||
403 | static struct notifier_block bfin_wdt_notifier = { | 392 | static struct notifier_block bfin_wdt_notifier = { |
@@ -416,14 +405,16 @@ static int __devinit bfin_wdt_probe(struct platform_device *pdev) | |||
416 | 405 | ||
417 | ret = register_reboot_notifier(&bfin_wdt_notifier); | 406 | ret = register_reboot_notifier(&bfin_wdt_notifier); |
418 | if (ret) { | 407 | if (ret) { |
419 | pr_devinit(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", ret); | 408 | pr_devinit(KERN_ERR PFX |
409 | "cannot register reboot notifier (err=%d)\n", ret); | ||
420 | return ret; | 410 | return ret; |
421 | } | 411 | } |
422 | 412 | ||
423 | ret = misc_register(&bfin_wdt_miscdev); | 413 | ret = misc_register(&bfin_wdt_miscdev); |
424 | if (ret) { | 414 | if (ret) { |
425 | pr_devinit(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", | 415 | pr_devinit(KERN_ERR PFX |
426 | WATCHDOG_MINOR, ret); | 416 | "cannot register miscdev on minor=%d (err=%d)\n", |
417 | WATCHDOG_MINOR, ret); | ||
427 | unregister_reboot_notifier(&bfin_wdt_notifier); | 418 | unregister_reboot_notifier(&bfin_wdt_notifier); |
428 | return ret; | 419 | return ret; |
429 | } | 420 | } |
@@ -516,7 +507,11 @@ MODULE_LICENSE("GPL"); | |||
516 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); | 507 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); |
517 | 508 | ||
518 | module_param(timeout, uint, 0); | 509 | module_param(timeout, uint, 0); |
519 | MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (1<=timeout<=((2^32)/SCLK), default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")"); | 510 | MODULE_PARM_DESC(timeout, |
511 | "Watchdog timeout in seconds. (1<=timeout<=((2^32)/SCLK), default=" | ||
512 | __MODULE_STRING(WATCHDOG_TIMEOUT) ")"); | ||
520 | 513 | ||
521 | module_param(nowayout, int, 0); | 514 | module_param(nowayout, int, 0); |
522 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 515 | MODULE_PARM_DESC(nowayout, |
516 | "Watchdog cannot be stopped once started (default=" | ||
517 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
diff --git a/drivers/watchdog/booke_wdt.c b/drivers/watchdog/booke_wdt.c index 770824458d45..c3b78a76f173 100644 --- a/drivers/watchdog/booke_wdt.c +++ b/drivers/watchdog/booke_wdt.c | |||
@@ -18,9 +18,9 @@ | |||
18 | #include <linux/miscdevice.h> | 18 | #include <linux/miscdevice.h> |
19 | #include <linux/notifier.h> | 19 | #include <linux/notifier.h> |
20 | #include <linux/watchdog.h> | 20 | #include <linux/watchdog.h> |
21 | #include <linux/uaccess.h> | ||
21 | 22 | ||
22 | #include <asm/reg_booke.h> | 23 | #include <asm/reg_booke.h> |
23 | #include <asm/uaccess.h> | ||
24 | #include <asm/system.h> | 24 | #include <asm/system.h> |
25 | 25 | ||
26 | /* If the kernel parameter wdt=1, the watchdog will be enabled at boot. | 26 | /* If the kernel parameter wdt=1, the watchdog will be enabled at boot. |
@@ -32,7 +32,7 @@ | |||
32 | */ | 32 | */ |
33 | 33 | ||
34 | #ifdef CONFIG_FSL_BOOKE | 34 | #ifdef CONFIG_FSL_BOOKE |
35 | #define WDT_PERIOD_DEFAULT 63 /* Ex. wdt_period=28 bus=333Mhz , reset=~40sec */ | 35 | #define WDT_PERIOD_DEFAULT 63 /* Ex. wdt_period=28 bus=333Mhz,reset=~40sec */ |
36 | #else | 36 | #else |
37 | #define WDT_PERIOD_DEFAULT 3 /* Refer to the PPC40x and PPC4xx manuals */ | 37 | #define WDT_PERIOD_DEFAULT 3 /* Refer to the PPC40x and PPC4xx manuals */ |
38 | #endif /* for timing information */ | 38 | #endif /* for timing information */ |
@@ -82,16 +82,15 @@ static struct watchdog_info ident = { | |||
82 | .identity = "PowerPC Book-E Watchdog", | 82 | .identity = "PowerPC Book-E Watchdog", |
83 | }; | 83 | }; |
84 | 84 | ||
85 | static int booke_wdt_ioctl(struct inode *inode, struct file *file, | 85 | static long booke_wdt_ioctl(struct file *file, |
86 | unsigned int cmd, unsigned long arg) | 86 | unsigned int cmd, unsigned long arg) |
87 | { | 87 | { |
88 | u32 tmp = 0; | 88 | u32 tmp = 0; |
89 | u32 __user *p = (u32 __user *)arg; | 89 | u32 __user *p = (u32 __user *)arg; |
90 | 90 | ||
91 | switch (cmd) { | 91 | switch (cmd) { |
92 | case WDIOC_GETSUPPORT: | 92 | case WDIOC_GETSUPPORT: |
93 | if (copy_to_user((struct watchdog_info __user *)arg, &ident, | 93 | if (copy_to_user(arg, &ident, sizeof(struct watchdog_info))) |
94 | sizeof(struct watchdog_info))) | ||
95 | return -EFAULT; | 94 | return -EFAULT; |
96 | case WDIOC_GETSTATUS: | 95 | case WDIOC_GETSTATUS: |
97 | return put_user(ident.options, p); | 96 | return put_user(ident.options, p); |
@@ -100,16 +99,6 @@ static int booke_wdt_ioctl(struct inode *inode, struct file *file, | |||
100 | tmp = mfspr(SPRN_TSR) & TSR_WRS(3); | 99 | tmp = mfspr(SPRN_TSR) & TSR_WRS(3); |
101 | /* returns 1 if last reset was caused by the WDT */ | 100 | /* returns 1 if last reset was caused by the WDT */ |
102 | return (tmp ? 1 : 0); | 101 | return (tmp ? 1 : 0); |
103 | case WDIOC_KEEPALIVE: | ||
104 | booke_wdt_ping(); | ||
105 | return 0; | ||
106 | case WDIOC_SETTIMEOUT: | ||
107 | if (get_user(booke_wdt_period, p)) | ||
108 | return -EFAULT; | ||
109 | mtspr(SPRN_TCR, (mfspr(SPRN_TCR)&~WDTP(0))|WDTP(booke_wdt_period)); | ||
110 | return 0; | ||
111 | case WDIOC_GETTIMEOUT: | ||
112 | return put_user(booke_wdt_period, p); | ||
113 | case WDIOC_SETOPTIONS: | 102 | case WDIOC_SETOPTIONS: |
114 | if (get_user(tmp, p)) | 103 | if (get_user(tmp, p)) |
115 | return -EINVAL; | 104 | return -EINVAL; |
@@ -119,6 +108,17 @@ static int booke_wdt_ioctl(struct inode *inode, struct file *file, | |||
119 | } else | 108 | } else |
120 | return -EINVAL; | 109 | return -EINVAL; |
121 | return 0; | 110 | return 0; |
111 | case WDIOC_KEEPALIVE: | ||
112 | booke_wdt_ping(); | ||
113 | return 0; | ||
114 | case WDIOC_SETTIMEOUT: | ||
115 | if (get_user(booke_wdt_period, p)) | ||
116 | return -EFAULT; | ||
117 | mtspr(SPRN_TCR, (mfspr(SPRN_TCR) & ~WDTP(0)) | | ||
118 | WDTP(booke_wdt_period)); | ||
119 | return 0; | ||
120 | case WDIOC_GETTIMEOUT: | ||
121 | return put_user(booke_wdt_period, p); | ||
122 | default: | 122 | default: |
123 | return -ENOTTY; | 123 | return -ENOTTY; |
124 | } | 124 | } |
@@ -132,8 +132,9 @@ static int booke_wdt_open(struct inode *inode, struct file *file) | |||
132 | if (booke_wdt_enabled == 0) { | 132 | if (booke_wdt_enabled == 0) { |
133 | booke_wdt_enabled = 1; | 133 | booke_wdt_enabled = 1; |
134 | on_each_cpu(__booke_wdt_enable, NULL, 0); | 134 | on_each_cpu(__booke_wdt_enable, NULL, 0); |
135 | printk(KERN_INFO "PowerPC Book-E Watchdog Timer Enabled " | 135 | printk(KERN_INFO |
136 | "(wdt_period=%d)\n", booke_wdt_period); | 136 | "PowerPC Book-E Watchdog Timer Enabled (wdt_period=%d)\n", |
137 | booke_wdt_period); | ||
137 | } | 138 | } |
138 | spin_unlock(&booke_wdt_lock); | 139 | spin_unlock(&booke_wdt_lock); |
139 | 140 | ||
@@ -144,7 +145,7 @@ static const struct file_operations booke_wdt_fops = { | |||
144 | .owner = THIS_MODULE, | 145 | .owner = THIS_MODULE, |
145 | .llseek = no_llseek, | 146 | .llseek = no_llseek, |
146 | .write = booke_wdt_write, | 147 | .write = booke_wdt_write, |
147 | .ioctl = booke_wdt_ioctl, | 148 | .unlocked_ioctl = booke_wdt_ioctl, |
148 | .open = booke_wdt_open, | 149 | .open = booke_wdt_open, |
149 | }; | 150 | }; |
150 | 151 | ||
@@ -175,8 +176,9 @@ static int __init booke_wdt_init(void) | |||
175 | 176 | ||
176 | spin_lock(&booke_wdt_lock); | 177 | spin_lock(&booke_wdt_lock); |
177 | if (booke_wdt_enabled == 1) { | 178 | if (booke_wdt_enabled == 1) { |
178 | printk(KERN_INFO "PowerPC Book-E Watchdog Timer Enabled " | 179 | printk(KERN_INFO |
179 | "(wdt_period=%d)\n", booke_wdt_period); | 180 | "PowerPC Book-E Watchdog Timer Enabled (wdt_period=%d)\n", |
181 | booke_wdt_period); | ||
180 | on_each_cpu(__booke_wdt_enable, NULL, 0); | 182 | on_each_cpu(__booke_wdt_enable, NULL, 0); |
181 | } | 183 | } |
182 | spin_unlock(&booke_wdt_lock); | 184 | spin_unlock(&booke_wdt_lock); |
diff --git a/drivers/watchdog/cpu5wdt.c b/drivers/watchdog/cpu5wdt.c index df72f90123df..71f6d7eec9a8 100644 --- a/drivers/watchdog/cpu5wdt.c +++ b/drivers/watchdog/cpu5wdt.c | |||
@@ -30,16 +30,16 @@ | |||
30 | #include <linux/timer.h> | 30 | #include <linux/timer.h> |
31 | #include <linux/completion.h> | 31 | #include <linux/completion.h> |
32 | #include <linux/jiffies.h> | 32 | #include <linux/jiffies.h> |
33 | #include <asm/io.h> | 33 | #include <linux/io.h> |
34 | #include <asm/uaccess.h> | 34 | #include <linux/uaccess.h> |
35 | |||
36 | #include <linux/watchdog.h> | 35 | #include <linux/watchdog.h> |
37 | 36 | ||
38 | /* adjustable parameters */ | 37 | /* adjustable parameters */ |
39 | 38 | ||
40 | static int verbose = 0; | 39 | static int verbose; |
41 | static int port = 0x91; | 40 | static int port = 0x91; |
42 | static int ticks = 10000; | 41 | static int ticks = 10000; |
42 | static spinlock_t cpu5wdt_lock; | ||
43 | 43 | ||
44 | #define PFX "cpu5wdt: " | 44 | #define PFX "cpu5wdt: " |
45 | 45 | ||
@@ -70,12 +70,13 @@ static struct { | |||
70 | 70 | ||
71 | static void cpu5wdt_trigger(unsigned long unused) | 71 | static void cpu5wdt_trigger(unsigned long unused) |
72 | { | 72 | { |
73 | if ( verbose > 2 ) | 73 | if (verbose > 2) |
74 | printk(KERN_DEBUG PFX "trigger at %i ticks\n", ticks); | 74 | printk(KERN_DEBUG PFX "trigger at %i ticks\n", ticks); |
75 | 75 | ||
76 | if( cpu5wdt_device.running ) | 76 | if (cpu5wdt_device.running) |
77 | ticks--; | 77 | ticks--; |
78 | 78 | ||
79 | spin_lock(&cpu5wdt_lock); | ||
79 | /* keep watchdog alive */ | 80 | /* keep watchdog alive */ |
80 | outb(1, port + CPU5WDT_TRIGGER_REG); | 81 | outb(1, port + CPU5WDT_TRIGGER_REG); |
81 | 82 | ||
@@ -86,6 +87,7 @@ static void cpu5wdt_trigger(unsigned long unused) | |||
86 | /* ticks doesn't matter anyway */ | 87 | /* ticks doesn't matter anyway */ |
87 | complete(&cpu5wdt_device.stop); | 88 | complete(&cpu5wdt_device.stop); |
88 | } | 89 | } |
90 | spin_unlock(&cpu5wdt_lock); | ||
89 | 91 | ||
90 | } | 92 | } |
91 | 93 | ||
@@ -93,14 +95,17 @@ static void cpu5wdt_reset(void) | |||
93 | { | 95 | { |
94 | ticks = cpu5wdt_device.default_ticks; | 96 | ticks = cpu5wdt_device.default_ticks; |
95 | 97 | ||
96 | if ( verbose ) | 98 | if (verbose) |
97 | printk(KERN_DEBUG PFX "reset (%i ticks)\n", (int) ticks); | 99 | printk(KERN_DEBUG PFX "reset (%i ticks)\n", (int) ticks); |
98 | 100 | ||
99 | } | 101 | } |
100 | 102 | ||
101 | static void cpu5wdt_start(void) | 103 | static void cpu5wdt_start(void) |
102 | { | 104 | { |
103 | if ( !cpu5wdt_device.queue ) { | 105 | unsigned long flags; |
106 | |||
107 | spin_lock_irqsave(&cpu5wdt_lock, flags); | ||
108 | if (!cpu5wdt_device.queue) { | ||
104 | cpu5wdt_device.queue = 1; | 109 | cpu5wdt_device.queue = 1; |
105 | outb(0, port + CPU5WDT_TIME_A_REG); | 110 | outb(0, port + CPU5WDT_TIME_A_REG); |
106 | outb(0, port + CPU5WDT_TIME_B_REG); | 111 | outb(0, port + CPU5WDT_TIME_B_REG); |
@@ -111,18 +116,20 @@ static void cpu5wdt_start(void) | |||
111 | } | 116 | } |
112 | /* if process dies, counter is not decremented */ | 117 | /* if process dies, counter is not decremented */ |
113 | cpu5wdt_device.running++; | 118 | cpu5wdt_device.running++; |
119 | spin_unlock_irqrestore(&cpu5wdt_lock, flags); | ||
114 | } | 120 | } |
115 | 121 | ||
116 | static int cpu5wdt_stop(void) | 122 | static int cpu5wdt_stop(void) |
117 | { | 123 | { |
118 | if ( cpu5wdt_device.running ) | 124 | unsigned long flags; |
119 | cpu5wdt_device.running = 0; | ||
120 | 125 | ||
126 | spin_lock_irqsave(&cpu5wdt_lock, flags); | ||
127 | if (cpu5wdt_device.running) | ||
128 | cpu5wdt_device.running = 0; | ||
121 | ticks = cpu5wdt_device.default_ticks; | 129 | ticks = cpu5wdt_device.default_ticks; |
122 | 130 | spin_unlock_irqrestore(&cpu5wdt_lock, flags); | |
123 | if ( verbose ) | 131 | if (verbose) |
124 | printk(KERN_CRIT PFX "stop not possible\n"); | 132 | printk(KERN_CRIT PFX "stop not possible\n"); |
125 | |||
126 | return -EIO; | 133 | return -EIO; |
127 | } | 134 | } |
128 | 135 | ||
@@ -130,9 +137,8 @@ static int cpu5wdt_stop(void) | |||
130 | 137 | ||
131 | static int cpu5wdt_open(struct inode *inode, struct file *file) | 138 | static int cpu5wdt_open(struct inode *inode, struct file *file) |
132 | { | 139 | { |
133 | if ( test_and_set_bit(0, &cpu5wdt_device.inuse) ) | 140 | if (test_and_set_bit(0, &cpu5wdt_device.inuse)) |
134 | return -EBUSY; | 141 | return -EBUSY; |
135 | |||
136 | return nonseekable_open(inode, file); | 142 | return nonseekable_open(inode, file); |
137 | } | 143 | } |
138 | 144 | ||
@@ -142,67 +148,58 @@ static int cpu5wdt_release(struct inode *inode, struct file *file) | |||
142 | return 0; | 148 | return 0; |
143 | } | 149 | } |
144 | 150 | ||
145 | static int cpu5wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) | 151 | static long cpu5wdt_ioctl(struct file *file, unsigned int cmd, |
152 | unsigned long arg) | ||
146 | { | 153 | { |
147 | void __user *argp = (void __user *)arg; | 154 | void __user *argp = (void __user *)arg; |
155 | int __user *p = argp; | ||
148 | unsigned int value; | 156 | unsigned int value; |
149 | static struct watchdog_info ident = | 157 | static struct watchdog_info ident = { |
150 | { | ||
151 | .options = WDIOF_CARDRESET, | 158 | .options = WDIOF_CARDRESET, |
152 | .identity = "CPU5 WDT", | 159 | .identity = "CPU5 WDT", |
153 | }; | 160 | }; |
154 | 161 | ||
155 | switch(cmd) { | 162 | switch (cmd) { |
156 | case WDIOC_KEEPALIVE: | 163 | case WDIOC_GETSUPPORT: |
157 | cpu5wdt_reset(); | 164 | if (copy_to_user(argp, &ident, sizeof(ident))) |
158 | break; | 165 | return -EFAULT; |
159 | case WDIOC_GETSTATUS: | 166 | break; |
160 | value = inb(port + CPU5WDT_STATUS_REG); | 167 | case WDIOC_GETSTATUS: |
161 | value = (value >> 2) & 1; | 168 | value = inb(port + CPU5WDT_STATUS_REG); |
162 | if ( copy_to_user(argp, &value, sizeof(int)) ) | 169 | value = (value >> 2) & 1; |
163 | return -EFAULT; | 170 | return put_user(value, p); |
164 | break; | 171 | case WDIOC_GETBOOTSTATUS: |
165 | case WDIOC_GETBOOTSTATUS: | 172 | return put_user(0, p); |
166 | if ( copy_to_user(argp, &value, sizeof(int)) ) | 173 | case WDIOC_SETOPTIONS: |
167 | return -EFAULT; | 174 | if (get_user(value, p)) |
168 | break; | 175 | return -EFAULT; |
169 | case WDIOC_GETSUPPORT: | 176 | if (value & WDIOS_ENABLECARD) |
170 | if ( copy_to_user(argp, &ident, sizeof(ident)) ) | 177 | cpu5wdt_start(); |
171 | return -EFAULT; | 178 | if (value & WDIOS_DISABLECARD) |
172 | break; | 179 | cpu5wdt_stop(); |
173 | case WDIOC_SETOPTIONS: | 180 | break; |
174 | if ( copy_from_user(&value, argp, sizeof(int)) ) | 181 | case WDIOC_KEEPALIVE: |
175 | return -EFAULT; | 182 | cpu5wdt_reset(); |
176 | switch(value) { | 183 | break; |
177 | case WDIOS_ENABLECARD: | 184 | default: |
178 | cpu5wdt_start(); | 185 | return -ENOTTY; |
179 | break; | ||
180 | case WDIOS_DISABLECARD: | ||
181 | return cpu5wdt_stop(); | ||
182 | default: | ||
183 | return -EINVAL; | ||
184 | } | ||
185 | break; | ||
186 | default: | ||
187 | return -ENOTTY; | ||
188 | } | 186 | } |
189 | return 0; | 187 | return 0; |
190 | } | 188 | } |
191 | 189 | ||
192 | static ssize_t cpu5wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) | 190 | static ssize_t cpu5wdt_write(struct file *file, const char __user *buf, |
191 | size_t count, loff_t *ppos) | ||
193 | { | 192 | { |
194 | if ( !count ) | 193 | if (!count) |
195 | return -EIO; | 194 | return -EIO; |
196 | |||
197 | cpu5wdt_reset(); | 195 | cpu5wdt_reset(); |
198 | |||
199 | return count; | 196 | return count; |
200 | } | 197 | } |
201 | 198 | ||
202 | static const struct file_operations cpu5wdt_fops = { | 199 | static const struct file_operations cpu5wdt_fops = { |
203 | .owner = THIS_MODULE, | 200 | .owner = THIS_MODULE, |
204 | .llseek = no_llseek, | 201 | .llseek = no_llseek, |
205 | .ioctl = cpu5wdt_ioctl, | 202 | .unlocked_ioctl = cpu5wdt_ioctl, |
206 | .open = cpu5wdt_open, | 203 | .open = cpu5wdt_open, |
207 | .write = cpu5wdt_write, | 204 | .write = cpu5wdt_write, |
208 | .release = cpu5wdt_release, | 205 | .release = cpu5wdt_release, |
@@ -221,37 +218,36 @@ static int __devinit cpu5wdt_init(void) | |||
221 | unsigned int val; | 218 | unsigned int val; |
222 | int err; | 219 | int err; |
223 | 220 | ||
224 | if ( verbose ) | 221 | if (verbose) |
225 | printk(KERN_DEBUG PFX "port=0x%x, verbose=%i\n", port, verbose); | 222 | printk(KERN_DEBUG PFX |
223 | "port=0x%x, verbose=%i\n", port, verbose); | ||
226 | 224 | ||
227 | if ( !request_region(port, CPU5WDT_EXTENT, PFX) ) { | 225 | init_completion(&cpu5wdt_device.stop); |
226 | spin_lock_init(&cpu5wdt_lock); | ||
227 | cpu5wdt_device.queue = 0; | ||
228 | setup_timer(&cpu5wdt_device.timer, cpu5wdt_trigger, 0); | ||
229 | cpu5wdt_device.default_ticks = ticks; | ||
230 | |||
231 | if (!request_region(port, CPU5WDT_EXTENT, PFX)) { | ||
228 | printk(KERN_ERR PFX "request_region failed\n"); | 232 | printk(KERN_ERR PFX "request_region failed\n"); |
229 | err = -EBUSY; | 233 | err = -EBUSY; |
230 | goto no_port; | 234 | goto no_port; |
231 | } | 235 | } |
232 | 236 | ||
233 | if ( (err = misc_register(&cpu5wdt_misc)) < 0 ) { | ||
234 | printk(KERN_ERR PFX "misc_register failed\n"); | ||
235 | goto no_misc; | ||
236 | } | ||
237 | |||
238 | /* watchdog reboot? */ | 237 | /* watchdog reboot? */ |
239 | val = inb(port + CPU5WDT_STATUS_REG); | 238 | val = inb(port + CPU5WDT_STATUS_REG); |
240 | val = (val >> 2) & 1; | 239 | val = (val >> 2) & 1; |
241 | if ( !val ) | 240 | if (!val) |
242 | printk(KERN_INFO PFX "sorry, was my fault\n"); | 241 | printk(KERN_INFO PFX "sorry, was my fault\n"); |
243 | 242 | ||
244 | init_completion(&cpu5wdt_device.stop); | 243 | err = misc_register(&cpu5wdt_misc); |
245 | cpu5wdt_device.queue = 0; | 244 | if (err < 0) { |
246 | 245 | printk(KERN_ERR PFX "misc_register failed\n"); | |
247 | clear_bit(0, &cpu5wdt_device.inuse); | 246 | goto no_misc; |
248 | 247 | } | |
249 | setup_timer(&cpu5wdt_device.timer, cpu5wdt_trigger, 0); | ||
250 | 248 | ||
251 | cpu5wdt_device.default_ticks = ticks; | ||
252 | 249 | ||
253 | printk(KERN_INFO PFX "init success\n"); | 250 | printk(KERN_INFO PFX "init success\n"); |
254 | |||
255 | return 0; | 251 | return 0; |
256 | 252 | ||
257 | no_misc: | 253 | no_misc: |
@@ -267,7 +263,7 @@ static int __devinit cpu5wdt_init_module(void) | |||
267 | 263 | ||
268 | static void __devexit cpu5wdt_exit(void) | 264 | static void __devexit cpu5wdt_exit(void) |
269 | { | 265 | { |
270 | if ( cpu5wdt_device.queue ) { | 266 | if (cpu5wdt_device.queue) { |
271 | cpu5wdt_device.queue = 0; | 267 | cpu5wdt_device.queue = 0; |
272 | wait_for_completion(&cpu5wdt_device.stop); | 268 | wait_for_completion(&cpu5wdt_device.stop); |
273 | } | 269 | } |
diff --git a/drivers/watchdog/davinci_wdt.c b/drivers/watchdog/davinci_wdt.c index 1782c79eff06..802aeba347a0 100644 --- a/drivers/watchdog/davinci_wdt.c +++ b/drivers/watchdog/davinci_wdt.c | |||
@@ -22,10 +22,10 @@ | |||
22 | #include <linux/bitops.h> | 22 | #include <linux/bitops.h> |
23 | #include <linux/platform_device.h> | 23 | #include <linux/platform_device.h> |
24 | #include <linux/spinlock.h> | 24 | #include <linux/spinlock.h> |
25 | #include <linux/uaccess.h> | ||
26 | #include <linux/io.h> | ||
25 | 27 | ||
26 | #include <asm/hardware.h> | 28 | #include <asm/hardware.h> |
27 | #include <asm/uaccess.h> | ||
28 | #include <asm/io.h> | ||
29 | 29 | ||
30 | #define MODULE_NAME "DAVINCI-WDT: " | 30 | #define MODULE_NAME "DAVINCI-WDT: " |
31 | 31 | ||
@@ -143,9 +143,8 @@ static struct watchdog_info ident = { | |||
143 | .identity = "DaVinci Watchdog", | 143 | .identity = "DaVinci Watchdog", |
144 | }; | 144 | }; |
145 | 145 | ||
146 | static int | 146 | static long davinci_wdt_ioctl(struct file *file, |
147 | davinci_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | 147 | unsigned int cmd, unsigned long arg) |
148 | unsigned long arg) | ||
149 | { | 148 | { |
150 | int ret = -ENOTTY; | 149 | int ret = -ENOTTY; |
151 | 150 | ||
@@ -160,14 +159,14 @@ davinci_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | |||
160 | ret = put_user(0, (int *)arg); | 159 | ret = put_user(0, (int *)arg); |
161 | break; | 160 | break; |
162 | 161 | ||
163 | case WDIOC_GETTIMEOUT: | ||
164 | ret = put_user(heartbeat, (int *)arg); | ||
165 | break; | ||
166 | |||
167 | case WDIOC_KEEPALIVE: | 162 | case WDIOC_KEEPALIVE: |
168 | wdt_service(); | 163 | wdt_service(); |
169 | ret = 0; | 164 | ret = 0; |
170 | break; | 165 | break; |
166 | |||
167 | case WDIOC_GETTIMEOUT: | ||
168 | ret = put_user(heartbeat, (int *)arg); | ||
169 | break; | ||
171 | } | 170 | } |
172 | return ret; | 171 | return ret; |
173 | } | 172 | } |
@@ -184,7 +183,7 @@ static const struct file_operations davinci_wdt_fops = { | |||
184 | .owner = THIS_MODULE, | 183 | .owner = THIS_MODULE, |
185 | .llseek = no_llseek, | 184 | .llseek = no_llseek, |
186 | .write = davinci_wdt_write, | 185 | .write = davinci_wdt_write, |
187 | .ioctl = davinci_wdt_ioctl, | 186 | .unlocked_ioctl = davinci_wdt_ioctl, |
188 | .open = davinci_wdt_open, | 187 | .open = davinci_wdt_open, |
189 | .release = davinci_wdt_release, | 188 | .release = davinci_wdt_release, |
190 | }; | 189 | }; |
diff --git a/drivers/watchdog/ep93xx_wdt.c b/drivers/watchdog/ep93xx_wdt.c index 0e4787a0bb87..07b74a768922 100644 --- a/drivers/watchdog/ep93xx_wdt.c +++ b/drivers/watchdog/ep93xx_wdt.c | |||
@@ -28,9 +28,9 @@ | |||
28 | #include <linux/miscdevice.h> | 28 | #include <linux/miscdevice.h> |
29 | #include <linux/watchdog.h> | 29 | #include <linux/watchdog.h> |
30 | #include <linux/timer.h> | 30 | #include <linux/timer.h> |
31 | #include <linux/uaccess.h> | ||
31 | 32 | ||
32 | #include <asm/hardware.h> | 33 | #include <asm/hardware.h> |
33 | #include <asm/uaccess.h> | ||
34 | 34 | ||
35 | #define WDT_VERSION "0.3" | 35 | #define WDT_VERSION "0.3" |
36 | #define PFX "ep93xx_wdt: " | 36 | #define PFX "ep93xx_wdt: " |
@@ -136,9 +136,8 @@ static struct watchdog_info ident = { | |||
136 | .identity = "EP93xx Watchdog", | 136 | .identity = "EP93xx Watchdog", |
137 | }; | 137 | }; |
138 | 138 | ||
139 | static int | 139 | static long ep93xx_wdt_ioctl(struct file *file, |
140 | ep93xx_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | 140 | unsigned int cmd, unsigned long arg) |
141 | unsigned long arg) | ||
142 | { | 141 | { |
143 | int ret = -ENOTTY; | 142 | int ret = -ENOTTY; |
144 | 143 | ||
@@ -156,15 +155,15 @@ ep93xx_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | |||
156 | ret = put_user(boot_status, (int __user *)arg); | 155 | ret = put_user(boot_status, (int __user *)arg); |
157 | break; | 156 | break; |
158 | 157 | ||
159 | case WDIOC_GETTIMEOUT: | ||
160 | /* actually, it is 0.250 seconds.... */ | ||
161 | ret = put_user(1, (int __user *)arg); | ||
162 | break; | ||
163 | |||
164 | case WDIOC_KEEPALIVE: | 158 | case WDIOC_KEEPALIVE: |
165 | wdt_keepalive(); | 159 | wdt_keepalive(); |
166 | ret = 0; | 160 | ret = 0; |
167 | break; | 161 | break; |
162 | |||
163 | case WDIOC_GETTIMEOUT: | ||
164 | /* actually, it is 0.250 seconds.... */ | ||
165 | ret = put_user(1, (int __user *)arg); | ||
166 | break; | ||
168 | } | 167 | } |
169 | return ret; | 168 | return ret; |
170 | } | 169 | } |
@@ -174,8 +173,8 @@ static int ep93xx_wdt_release(struct inode *inode, struct file *file) | |||
174 | if (test_bit(WDT_OK_TO_CLOSE, &wdt_status)) | 173 | if (test_bit(WDT_OK_TO_CLOSE, &wdt_status)) |
175 | wdt_shutdown(); | 174 | wdt_shutdown(); |
176 | else | 175 | else |
177 | printk(KERN_CRIT PFX "Device closed unexpectedly - " | 176 | printk(KERN_CRIT PFX |
178 | "timer will not stop\n"); | 177 | "Device closed unexpectedly - timer will not stop\n"); |
179 | 178 | ||
180 | clear_bit(WDT_IN_USE, &wdt_status); | 179 | clear_bit(WDT_IN_USE, &wdt_status); |
181 | clear_bit(WDT_OK_TO_CLOSE, &wdt_status); | 180 | clear_bit(WDT_OK_TO_CLOSE, &wdt_status); |
@@ -186,7 +185,7 @@ static int ep93xx_wdt_release(struct inode *inode, struct file *file) | |||
186 | static const struct file_operations ep93xx_wdt_fops = { | 185 | static const struct file_operations ep93xx_wdt_fops = { |
187 | .owner = THIS_MODULE, | 186 | .owner = THIS_MODULE, |
188 | .write = ep93xx_wdt_write, | 187 | .write = ep93xx_wdt_write, |
189 | .ioctl = ep93xx_wdt_ioctl, | 188 | .unlocked_ioctl = ep93xx_wdt_ioctl, |
190 | .open = ep93xx_wdt_open, | 189 | .open = ep93xx_wdt_open, |
191 | .release = ep93xx_wdt_release, | 190 | .release = ep93xx_wdt_release, |
192 | }; | 191 | }; |
@@ -243,7 +242,9 @@ module_param(nowayout, int, 0); | |||
243 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started"); | 242 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started"); |
244 | 243 | ||
245 | module_param(timeout, int, 0); | 244 | module_param(timeout, int, 0); |
246 | MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (1<=timeout<=3600, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")"); | 245 | MODULE_PARM_DESC(timeout, |
246 | "Watchdog timeout in seconds. (1<=timeout<=3600, default=" | ||
247 | __MODULE_STRING(WATCHDOG_TIMEOUT) ")"); | ||
247 | 248 | ||
248 | MODULE_AUTHOR("Ray Lehtiniemi <rayl@mail.com>," | 249 | MODULE_AUTHOR("Ray Lehtiniemi <rayl@mail.com>," |
249 | "Alessandro Zummo <a.zummo@towertech.it>"); | 250 | "Alessandro Zummo <a.zummo@towertech.it>"); |
diff --git a/drivers/watchdog/eurotechwdt.c b/drivers/watchdog/eurotechwdt.c index b14e9d1f164d..bbd14e34319f 100644 --- a/drivers/watchdog/eurotechwdt.c +++ b/drivers/watchdog/eurotechwdt.c | |||
@@ -56,14 +56,15 @@ | |||
56 | #include <linux/notifier.h> | 56 | #include <linux/notifier.h> |
57 | #include <linux/reboot.h> | 57 | #include <linux/reboot.h> |
58 | #include <linux/init.h> | 58 | #include <linux/init.h> |
59 | #include <linux/io.h> | ||
60 | #include <linux/uaccess.h> | ||
59 | 61 | ||
60 | #include <asm/io.h> | ||
61 | #include <asm/uaccess.h> | ||
62 | #include <asm/system.h> | 62 | #include <asm/system.h> |
63 | 63 | ||
64 | static unsigned long eurwdt_is_open; | 64 | static unsigned long eurwdt_is_open; |
65 | static int eurwdt_timeout; | 65 | static int eurwdt_timeout; |
66 | static char eur_expect_close; | 66 | static char eur_expect_close; |
67 | static spinlock_t eurwdt_lock; | ||
67 | 68 | ||
68 | /* | 69 | /* |
69 | * You must set these - there is no sane way to probe for this board. | 70 | * You must set these - there is no sane way to probe for this board. |
@@ -78,7 +79,9 @@ static char *ev = "int"; | |||
78 | 79 | ||
79 | static int nowayout = WATCHDOG_NOWAYOUT; | 80 | static int nowayout = WATCHDOG_NOWAYOUT; |
80 | module_param(nowayout, int, 0); | 81 | module_param(nowayout, int, 0); |
81 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 82 | MODULE_PARM_DESC(nowayout, |
83 | "Watchdog cannot be stopped once started (default=" | ||
84 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
82 | 85 | ||
83 | /* | 86 | /* |
84 | * Some symbolic names | 87 | * Some symbolic names |
@@ -137,7 +140,8 @@ static void eurwdt_activate_timer(void) | |||
137 | { | 140 | { |
138 | eurwdt_disable_timer(); | 141 | eurwdt_disable_timer(); |
139 | eurwdt_write_reg(WDT_CTRL_REG, 0x01); /* activate the WDT */ | 142 | eurwdt_write_reg(WDT_CTRL_REG, 0x01); /* activate the WDT */ |
140 | eurwdt_write_reg(WDT_OUTPIN_CFG, !strcmp("int", ev) ? WDT_EVENT_INT : WDT_EVENT_REBOOT); | 143 | eurwdt_write_reg(WDT_OUTPIN_CFG, |
144 | !strcmp("int", ev) ? WDT_EVENT_INT : WDT_EVENT_REBOOT); | ||
141 | 145 | ||
142 | /* Setting interrupt line */ | 146 | /* Setting interrupt line */ |
143 | if (irq == 2 || irq > 15 || irq < 0) { | 147 | if (irq == 2 || irq > 15 || irq < 0) { |
@@ -206,21 +210,21 @@ size_t count, loff_t *ppos) | |||
206 | 210 | ||
207 | for (i = 0; i != count; i++) { | 211 | for (i = 0; i != count; i++) { |
208 | char c; | 212 | char c; |
209 | if(get_user(c, buf+i)) | 213 | if (get_user(c, buf + i)) |
210 | return -EFAULT; | 214 | return -EFAULT; |
211 | if (c == 'V') | 215 | if (c == 'V') |
212 | eur_expect_close = 42; | 216 | eur_expect_close = 42; |
213 | } | 217 | } |
214 | } | 218 | } |
219 | spin_lock(&eurwdt_lock); | ||
215 | eurwdt_ping(); /* the default timeout */ | 220 | eurwdt_ping(); /* the default timeout */ |
221 | spin_unlock(&eurwdt_lock); | ||
216 | } | 222 | } |
217 | |||
218 | return count; | 223 | return count; |
219 | } | 224 | } |
220 | 225 | ||
221 | /** | 226 | /** |
222 | * eurwdt_ioctl: | 227 | * eurwdt_ioctl: |
223 | * @inode: inode of the device | ||
224 | * @file: file handle to the device | 228 | * @file: file handle to the device |
225 | * @cmd: watchdog command | 229 | * @cmd: watchdog command |
226 | * @arg: argument pointer | 230 | * @arg: argument pointer |
@@ -229,13 +233,14 @@ size_t count, loff_t *ppos) | |||
229 | * according to their available features. | 233 | * according to their available features. |
230 | */ | 234 | */ |
231 | 235 | ||
232 | static int eurwdt_ioctl(struct inode *inode, struct file *file, | 236 | static long eurwdt_ioctl(struct file *file, |
233 | unsigned int cmd, unsigned long arg) | 237 | unsigned int cmd, unsigned long arg) |
234 | { | 238 | { |
235 | void __user *argp = (void __user *)arg; | 239 | void __user *argp = (void __user *)arg; |
236 | int __user *p = argp; | 240 | int __user *p = argp; |
237 | static struct watchdog_info ident = { | 241 | static struct watchdog_info ident = { |
238 | .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, | 242 | .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
243 | | WDIOF_MAGICCLOSE, | ||
239 | .firmware_version = 1, | 244 | .firmware_version = 1, |
240 | .identity = "WDT Eurotech CPU-1220/1410", | 245 | .identity = "WDT Eurotech CPU-1220/1410", |
241 | }; | 246 | }; |
@@ -243,10 +248,7 @@ static int eurwdt_ioctl(struct inode *inode, struct file *file, | |||
243 | int time; | 248 | int time; |
244 | int options, retval = -EINVAL; | 249 | int options, retval = -EINVAL; |
245 | 250 | ||
246 | switch(cmd) { | 251 | switch (cmd) { |
247 | default: | ||
248 | return -ENOTTY; | ||
249 | |||
250 | case WDIOC_GETSUPPORT: | 252 | case WDIOC_GETSUPPORT: |
251 | return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; | 253 | return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; |
252 | 254 | ||
@@ -254,8 +256,26 @@ static int eurwdt_ioctl(struct inode *inode, struct file *file, | |||
254 | case WDIOC_GETBOOTSTATUS: | 256 | case WDIOC_GETBOOTSTATUS: |
255 | return put_user(0, p); | 257 | return put_user(0, p); |
256 | 258 | ||
259 | case WDIOC_SETOPTIONS: | ||
260 | if (get_user(options, p)) | ||
261 | return -EFAULT; | ||
262 | spin_lock(&eurwdt_lock); | ||
263 | if (options & WDIOS_DISABLECARD) { | ||
264 | eurwdt_disable_timer(); | ||
265 | retval = 0; | ||
266 | } | ||
267 | if (options & WDIOS_ENABLECARD) { | ||
268 | eurwdt_activate_timer(); | ||
269 | eurwdt_ping(); | ||
270 | retval = 0; | ||
271 | } | ||
272 | spin_unlock(&eurwdt_lock); | ||
273 | return retval; | ||
274 | |||
257 | case WDIOC_KEEPALIVE: | 275 | case WDIOC_KEEPALIVE: |
276 | spin_lock(&eurwdt_lock); | ||
258 | eurwdt_ping(); | 277 | eurwdt_ping(); |
278 | spin_unlock(&eurwdt_lock); | ||
259 | return 0; | 279 | return 0; |
260 | 280 | ||
261 | case WDIOC_SETTIMEOUT: | 281 | case WDIOC_SETTIMEOUT: |
@@ -266,26 +286,17 @@ static int eurwdt_ioctl(struct inode *inode, struct file *file, | |||
266 | if (time < 0 || time > 255) | 286 | if (time < 0 || time > 255) |
267 | return -EINVAL; | 287 | return -EINVAL; |
268 | 288 | ||
289 | spin_lock(&eurwdt_lock); | ||
269 | eurwdt_timeout = time; | 290 | eurwdt_timeout = time; |
270 | eurwdt_set_timeout(time); | 291 | eurwdt_set_timeout(time); |
292 | spin_unlock(&eurwdt_lock); | ||
271 | /* Fall */ | 293 | /* Fall */ |
272 | 294 | ||
273 | case WDIOC_GETTIMEOUT: | 295 | case WDIOC_GETTIMEOUT: |
274 | return put_user(eurwdt_timeout, p); | 296 | return put_user(eurwdt_timeout, p); |
275 | 297 | ||
276 | case WDIOC_SETOPTIONS: | 298 | default: |
277 | if (get_user(options, p)) | 299 | return -ENOTTY; |
278 | return -EFAULT; | ||
279 | if (options & WDIOS_DISABLECARD) { | ||
280 | eurwdt_disable_timer(); | ||
281 | retval = 0; | ||
282 | } | ||
283 | if (options & WDIOS_ENABLECARD) { | ||
284 | eurwdt_activate_timer(); | ||
285 | eurwdt_ping(); | ||
286 | retval = 0; | ||
287 | } | ||
288 | return retval; | ||
289 | } | 300 | } |
290 | } | 301 | } |
291 | 302 | ||
@@ -322,10 +333,11 @@ static int eurwdt_open(struct inode *inode, struct file *file) | |||
322 | 333 | ||
323 | static int eurwdt_release(struct inode *inode, struct file *file) | 334 | static int eurwdt_release(struct inode *inode, struct file *file) |
324 | { | 335 | { |
325 | if (eur_expect_close == 42) { | 336 | if (eur_expect_close == 42) |
326 | eurwdt_disable_timer(); | 337 | eurwdt_disable_timer(); |
327 | } else { | 338 | else { |
328 | printk(KERN_CRIT "eurwdt: Unexpected close, not stopping watchdog!\n"); | 339 | printk(KERN_CRIT |
340 | "eurwdt: Unexpected close, not stopping watchdog!\n"); | ||
329 | eurwdt_ping(); | 341 | eurwdt_ping(); |
330 | } | 342 | } |
331 | clear_bit(0, &eurwdt_is_open); | 343 | clear_bit(0, &eurwdt_is_open); |
@@ -348,10 +360,8 @@ static int eurwdt_release(struct inode *inode, struct file *file) | |||
348 | static int eurwdt_notify_sys(struct notifier_block *this, unsigned long code, | 360 | static int eurwdt_notify_sys(struct notifier_block *this, unsigned long code, |
349 | void *unused) | 361 | void *unused) |
350 | { | 362 | { |
351 | if (code == SYS_DOWN || code == SYS_HALT) { | 363 | if (code == SYS_DOWN || code == SYS_HALT) |
352 | /* Turn the card off */ | 364 | eurwdt_disable_timer(); /* Turn the card off */ |
353 | eurwdt_disable_timer(); | ||
354 | } | ||
355 | 365 | ||
356 | return NOTIFY_DONE; | 366 | return NOTIFY_DONE; |
357 | } | 367 | } |
@@ -362,11 +372,11 @@ static int eurwdt_notify_sys(struct notifier_block *this, unsigned long code, | |||
362 | 372 | ||
363 | 373 | ||
364 | static const struct file_operations eurwdt_fops = { | 374 | static const struct file_operations eurwdt_fops = { |
365 | .owner = THIS_MODULE, | 375 | .owner = THIS_MODULE, |
366 | .llseek = no_llseek, | 376 | .llseek = no_llseek, |
367 | .write = eurwdt_write, | 377 | .write = eurwdt_write, |
368 | .ioctl = eurwdt_ioctl, | 378 | .unlocked_ioctl = eurwdt_ioctl, |
369 | .open = eurwdt_open, | 379 | .open = eurwdt_open, |
370 | .release = eurwdt_release, | 380 | .release = eurwdt_release, |
371 | }; | 381 | }; |
372 | 382 | ||
@@ -419,7 +429,7 @@ static int __init eurwdt_init(void) | |||
419 | int ret; | 429 | int ret; |
420 | 430 | ||
421 | ret = request_irq(irq, eurwdt_interrupt, IRQF_DISABLED, "eurwdt", NULL); | 431 | ret = request_irq(irq, eurwdt_interrupt, IRQF_DISABLED, "eurwdt", NULL); |
422 | if(ret) { | 432 | if (ret) { |
423 | printk(KERN_ERR "eurwdt: IRQ %d is not free.\n", irq); | 433 | printk(KERN_ERR "eurwdt: IRQ %d is not free.\n", irq); |
424 | goto out; | 434 | goto out; |
425 | } | 435 | } |
@@ -432,10 +442,13 @@ static int __init eurwdt_init(void) | |||
432 | 442 | ||
433 | ret = register_reboot_notifier(&eurwdt_notifier); | 443 | ret = register_reboot_notifier(&eurwdt_notifier); |
434 | if (ret) { | 444 | if (ret) { |
435 | printk(KERN_ERR "eurwdt: can't register reboot notifier (err=%d)\n", ret); | 445 | printk(KERN_ERR |
446 | "eurwdt: can't register reboot notifier (err=%d)\n", ret); | ||
436 | goto outreg; | 447 | goto outreg; |
437 | } | 448 | } |
438 | 449 | ||
450 | spin_lock_init(&eurwdt_lock); | ||
451 | |||
439 | ret = misc_register(&eurwdt_miscdev); | 452 | ret = misc_register(&eurwdt_miscdev); |
440 | if (ret) { | 453 | if (ret) { |
441 | printk(KERN_ERR "eurwdt: can't misc_register on minor=%d\n", | 454 | printk(KERN_ERR "eurwdt: can't misc_register on minor=%d\n", |
diff --git a/drivers/watchdog/geodewdt.c b/drivers/watchdog/geodewdt.c index 30d09cbbad94..614a5c7017b6 100644 --- a/drivers/watchdog/geodewdt.c +++ b/drivers/watchdog/geodewdt.c | |||
@@ -17,8 +17,8 @@ | |||
17 | #include <linux/fs.h> | 17 | #include <linux/fs.h> |
18 | #include <linux/platform_device.h> | 18 | #include <linux/platform_device.h> |
19 | #include <linux/reboot.h> | 19 | #include <linux/reboot.h> |
20 | #include <linux/uaccess.h> | ||
20 | 21 | ||
21 | #include <asm/uaccess.h> | ||
22 | #include <asm/geode.h> | 22 | #include <asm/geode.h> |
23 | 23 | ||
24 | #define GEODEWDT_HZ 500 | 24 | #define GEODEWDT_HZ 500 |
@@ -77,27 +77,24 @@ static int geodewdt_set_heartbeat(int val) | |||
77 | return 0; | 77 | return 0; |
78 | } | 78 | } |
79 | 79 | ||
80 | static int | 80 | static int geodewdt_open(struct inode *inode, struct file *file) |
81 | geodewdt_open(struct inode *inode, struct file *file) | ||
82 | { | 81 | { |
83 | if (test_and_set_bit(WDT_FLAGS_OPEN, &wdt_flags)) | 82 | if (test_and_set_bit(WDT_FLAGS_OPEN, &wdt_flags)) |
84 | return -EBUSY; | 83 | return -EBUSY; |
85 | 84 | ||
86 | if (!test_and_clear_bit(WDT_FLAGS_ORPHAN, &wdt_flags)) | 85 | if (!test_and_clear_bit(WDT_FLAGS_ORPHAN, &wdt_flags)) |
87 | __module_get(THIS_MODULE); | 86 | __module_get(THIS_MODULE); |
88 | 87 | ||
89 | geodewdt_ping(); | 88 | geodewdt_ping(); |
90 | return nonseekable_open(inode, file); | 89 | return nonseekable_open(inode, file); |
91 | } | 90 | } |
92 | 91 | ||
93 | static int | 92 | static int geodewdt_release(struct inode *inode, struct file *file) |
94 | geodewdt_release(struct inode *inode, struct file *file) | ||
95 | { | 93 | { |
96 | if (safe_close) { | 94 | if (safe_close) { |
97 | geodewdt_disable(); | 95 | geodewdt_disable(); |
98 | module_put(THIS_MODULE); | 96 | module_put(THIS_MODULE); |
99 | } | 97 | } else { |
100 | else { | ||
101 | printk(KERN_CRIT "Unexpected close - watchdog is not stopping.\n"); | 98 | printk(KERN_CRIT "Unexpected close - watchdog is not stopping.\n"); |
102 | geodewdt_ping(); | 99 | geodewdt_ping(); |
103 | 100 | ||
@@ -109,11 +106,10 @@ geodewdt_release(struct inode *inode, struct file *file) | |||
109 | return 0; | 106 | return 0; |
110 | } | 107 | } |
111 | 108 | ||
112 | static ssize_t | 109 | static ssize_t geodewdt_write(struct file *file, const char __user *data, |
113 | geodewdt_write(struct file *file, const char __user *data, size_t len, | 110 | size_t len, loff_t *ppos) |
114 | loff_t *ppos) | ||
115 | { | 111 | { |
116 | if(len) { | 112 | if (len) { |
117 | if (!nowayout) { | 113 | if (!nowayout) { |
118 | size_t i; | 114 | size_t i; |
119 | safe_close = 0; | 115 | safe_close = 0; |
@@ -134,9 +130,8 @@ geodewdt_write(struct file *file, const char __user *data, size_t len, | |||
134 | return len; | 130 | return len; |
135 | } | 131 | } |
136 | 132 | ||
137 | static int | 133 | static int geodewdt_ioctl(struct inode *inode, struct file *file, |
138 | geodewdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | 134 | unsigned int cmd, unsigned long arg) |
139 | unsigned long arg) | ||
140 | { | 135 | { |
141 | void __user *argp = (void __user *)arg; | 136 | void __user *argp = (void __user *)arg; |
142 | int __user *p = argp; | 137 | int __user *p = argp; |
@@ -147,9 +142,9 @@ geodewdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | |||
147 | | WDIOF_MAGICCLOSE, | 142 | | WDIOF_MAGICCLOSE, |
148 | .firmware_version = 1, | 143 | .firmware_version = 1, |
149 | .identity = WATCHDOG_NAME, | 144 | .identity = WATCHDOG_NAME, |
150 | }; | 145 | }; |
151 | 146 | ||
152 | switch(cmd) { | 147 | switch (cmd) { |
153 | case WDIOC_GETSUPPORT: | 148 | case WDIOC_GETSUPPORT: |
154 | return copy_to_user(argp, &ident, | 149 | return copy_to_user(argp, &ident, |
155 | sizeof(ident)) ? -EFAULT : 0; | 150 | sizeof(ident)) ? -EFAULT : 0; |
@@ -159,22 +154,6 @@ geodewdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | |||
159 | case WDIOC_GETBOOTSTATUS: | 154 | case WDIOC_GETBOOTSTATUS: |
160 | return put_user(0, p); | 155 | return put_user(0, p); |
161 | 156 | ||
162 | case WDIOC_KEEPALIVE: | ||
163 | geodewdt_ping(); | ||
164 | return 0; | ||
165 | |||
166 | case WDIOC_SETTIMEOUT: | ||
167 | if (get_user(interval, p)) | ||
168 | return -EFAULT; | ||
169 | |||
170 | if (geodewdt_set_heartbeat(interval)) | ||
171 | return -EINVAL; | ||
172 | |||
173 | /* Fall through */ | ||
174 | |||
175 | case WDIOC_GETTIMEOUT: | ||
176 | return put_user(timeout, p); | ||
177 | |||
178 | case WDIOC_SETOPTIONS: | 157 | case WDIOC_SETOPTIONS: |
179 | { | 158 | { |
180 | int options, ret = -EINVAL; | 159 | int options, ret = -EINVAL; |
@@ -194,6 +173,20 @@ geodewdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | |||
194 | 173 | ||
195 | return ret; | 174 | return ret; |
196 | } | 175 | } |
176 | case WDIOC_KEEPALIVE: | ||
177 | geodewdt_ping(); | ||
178 | return 0; | ||
179 | |||
180 | case WDIOC_SETTIMEOUT: | ||
181 | if (get_user(interval, p)) | ||
182 | return -EFAULT; | ||
183 | |||
184 | if (geodewdt_set_heartbeat(interval)) | ||
185 | return -EINVAL; | ||
186 | /* Fall through */ | ||
187 | case WDIOC_GETTIMEOUT: | ||
188 | return put_user(timeout, p); | ||
189 | |||
197 | default: | 190 | default: |
198 | return -ENOTTY; | 191 | return -ENOTTY; |
199 | } | 192 | } |
@@ -202,22 +195,21 @@ geodewdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | |||
202 | } | 195 | } |
203 | 196 | ||
204 | static const struct file_operations geodewdt_fops = { | 197 | static const struct file_operations geodewdt_fops = { |
205 | .owner = THIS_MODULE, | 198 | .owner = THIS_MODULE, |
206 | .llseek = no_llseek, | 199 | .llseek = no_llseek, |
207 | .write = geodewdt_write, | 200 | .write = geodewdt_write, |
208 | .ioctl = geodewdt_ioctl, | 201 | .ioctl = geodewdt_ioctl, |
209 | .open = geodewdt_open, | 202 | .open = geodewdt_open, |
210 | .release = geodewdt_release, | 203 | .release = geodewdt_release, |
211 | }; | 204 | }; |
212 | 205 | ||
213 | static struct miscdevice geodewdt_miscdev = { | 206 | static struct miscdevice geodewdt_miscdev = { |
214 | .minor = WATCHDOG_MINOR, | 207 | .minor = WATCHDOG_MINOR, |
215 | .name = "watchdog", | 208 | .name = "watchdog", |
216 | .fops = &geodewdt_fops | 209 | .fops = &geodewdt_fops, |
217 | }; | 210 | }; |
218 | 211 | ||
219 | static int __devinit | 212 | static int __devinit geodewdt_probe(struct platform_device *dev) |
220 | geodewdt_probe(struct platform_device *dev) | ||
221 | { | 213 | { |
222 | int ret, timer; | 214 | int ret, timer; |
223 | 215 | ||
@@ -248,15 +240,13 @@ geodewdt_probe(struct platform_device *dev) | |||
248 | return ret; | 240 | return ret; |
249 | } | 241 | } |
250 | 242 | ||
251 | static int __devexit | 243 | static int __devexit geodewdt_remove(struct platform_device *dev) |
252 | geodewdt_remove(struct platform_device *dev) | ||
253 | { | 244 | { |
254 | misc_deregister(&geodewdt_miscdev); | 245 | misc_deregister(&geodewdt_miscdev); |
255 | return 0; | 246 | return 0; |
256 | } | 247 | } |
257 | 248 | ||
258 | static void | 249 | static void geodewdt_shutdown(struct platform_device *dev) |
259 | geodewdt_shutdown(struct platform_device *dev) | ||
260 | { | 250 | { |
261 | geodewdt_disable(); | 251 | geodewdt_disable(); |
262 | } | 252 | } |
@@ -271,8 +261,7 @@ static struct platform_driver geodewdt_driver = { | |||
271 | }, | 261 | }, |
272 | }; | 262 | }; |
273 | 263 | ||
274 | static int __init | 264 | static int __init geodewdt_init(void) |
275 | geodewdt_init(void) | ||
276 | { | 265 | { |
277 | int ret; | 266 | int ret; |
278 | 267 | ||
@@ -292,8 +281,7 @@ err: | |||
292 | return ret; | 281 | return ret; |
293 | } | 282 | } |
294 | 283 | ||
295 | static void __exit | 284 | static void __exit geodewdt_exit(void) |
296 | geodewdt_exit(void) | ||
297 | { | 285 | { |
298 | platform_device_unregister(geodewdt_platform_device); | 286 | platform_device_unregister(geodewdt_platform_device); |
299 | platform_driver_unregister(&geodewdt_driver); | 287 | platform_driver_unregister(&geodewdt_driver); |
diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index ccd6c530782d..d039d5f2fd1c 100644 --- a/drivers/watchdog/hpwdt.c +++ b/drivers/watchdog/hpwdt.c | |||
@@ -39,9 +39,7 @@ | |||
39 | #include <linux/string.h> | 39 | #include <linux/string.h> |
40 | #include <linux/bootmem.h> | 40 | #include <linux/bootmem.h> |
41 | #include <linux/slab.h> | 41 | #include <linux/slab.h> |
42 | #include <asm/dmi.h> | ||
43 | #include <asm/desc.h> | 42 | #include <asm/desc.h> |
44 | #include <asm/kdebug.h> | ||
45 | 43 | ||
46 | #define PCI_BIOS32_SD_VALUE 0x5F32335F /* "_32_" */ | 44 | #define PCI_BIOS32_SD_VALUE 0x5F32335F /* "_32_" */ |
47 | #define CRU_BIOS_SIGNATURE_VALUE 0x55524324 | 45 | #define CRU_BIOS_SIGNATURE_VALUE 0x55524324 |
@@ -407,7 +405,7 @@ static int __devinit detect_cru_service(void) | |||
407 | dmi_walk(dmi_find_cru); | 405 | dmi_walk(dmi_find_cru); |
408 | 406 | ||
409 | /* if cru_rom_addr has been set then we found a CRU service */ | 407 | /* if cru_rom_addr has been set then we found a CRU service */ |
410 | return ((cru_rom_addr != NULL)? 0: -ENODEV); | 408 | return ((cru_rom_addr != NULL) ? 0: -ENODEV); |
411 | } | 409 | } |
412 | 410 | ||
413 | /* ------------------------------------------------------------------------- */ | 411 | /* ------------------------------------------------------------------------- */ |
@@ -535,7 +533,7 @@ static ssize_t hpwdt_write(struct file *file, const char __user *data, | |||
535 | /* scan to see whether or not we got the magic char. */ | 533 | /* scan to see whether or not we got the magic char. */ |
536 | for (i = 0; i != len; i++) { | 534 | for (i = 0; i != len; i++) { |
537 | char c; | 535 | char c; |
538 | if (get_user(c, data+i)) | 536 | if (get_user(c, data + i)) |
539 | return -EFAULT; | 537 | return -EFAULT; |
540 | if (c == 'V') | 538 | if (c == 'V') |
541 | expect_release = 42; | 539 | expect_release = 42; |
diff --git a/drivers/watchdog/i6300esb.c b/drivers/watchdog/i6300esb.c index ca44fd9b19bb..c13383f7fcb9 100644 --- a/drivers/watchdog/i6300esb.c +++ b/drivers/watchdog/i6300esb.c | |||
@@ -9,18 +9,18 @@ | |||
9 | * as published by the Free Software Foundation; either version | 9 | * as published by the Free Software Foundation; either version |
10 | * 2 of the License, or (at your option) any later version. | 10 | * 2 of the License, or (at your option) any later version. |
11 | * | 11 | * |
12 | * based on i810-tco.c which is in turn based on softdog.c | 12 | * based on i810-tco.c which is in turn based on softdog.c |
13 | * | 13 | * |
14 | * The timer is implemented in the following I/O controller hubs: | 14 | * The timer is implemented in the following I/O controller hubs: |
15 | * (See the intel documentation on http://developer.intel.com.) | 15 | * (See the intel documentation on http://developer.intel.com.) |
16 | * 6300ESB chip : document number 300641-003 | 16 | * 6300ESB chip : document number 300641-003 |
17 | * | 17 | * |
18 | * 2004YYZZ Ross Biro | 18 | * 2004YYZZ Ross Biro |
19 | * Initial version 0.01 | 19 | * Initial version 0.01 |
20 | * 2004YYZZ Ross Biro | 20 | * 2004YYZZ Ross Biro |
21 | * Version 0.02 | 21 | * Version 0.02 |
22 | * 20050210 David Härdeman <david@2gen.com> | 22 | * 20050210 David Härdeman <david@2gen.com> |
23 | * Ported driver to kernel 2.6 | 23 | * Ported driver to kernel 2.6 |
24 | */ | 24 | */ |
25 | 25 | ||
26 | /* | 26 | /* |
@@ -38,9 +38,8 @@ | |||
38 | #include <linux/init.h> | 38 | #include <linux/init.h> |
39 | #include <linux/pci.h> | 39 | #include <linux/pci.h> |
40 | #include <linux/ioport.h> | 40 | #include <linux/ioport.h> |
41 | 41 | #include <linux/uaccess.h> | |
42 | #include <asm/uaccess.h> | 42 | #include <linux/io.h> |
43 | #include <asm/io.h> | ||
44 | 43 | ||
45 | /* Module and version information */ | 44 | /* Module and version information */ |
46 | #define ESB_VERSION "0.03" | 45 | #define ESB_VERSION "0.03" |
@@ -59,17 +58,17 @@ | |||
59 | #define ESB_RELOAD_REG BASEADDR + 0x0c /* Reload register */ | 58 | #define ESB_RELOAD_REG BASEADDR + 0x0c /* Reload register */ |
60 | 59 | ||
61 | /* Lock register bits */ | 60 | /* Lock register bits */ |
62 | #define ESB_WDT_FUNC ( 0x01 << 2 ) /* Watchdog functionality */ | 61 | #define ESB_WDT_FUNC (0x01 << 2) /* Watchdog functionality */ |
63 | #define ESB_WDT_ENABLE ( 0x01 << 1 ) /* Enable WDT */ | 62 | #define ESB_WDT_ENABLE (0x01 << 1) /* Enable WDT */ |
64 | #define ESB_WDT_LOCK ( 0x01 << 0 ) /* Lock (nowayout) */ | 63 | #define ESB_WDT_LOCK (0x01 << 0) /* Lock (nowayout) */ |
65 | 64 | ||
66 | /* Config register bits */ | 65 | /* Config register bits */ |
67 | #define ESB_WDT_REBOOT ( 0x01 << 5 ) /* Enable reboot on timeout */ | 66 | #define ESB_WDT_REBOOT (0x01 << 5) /* Enable reboot on timeout */ |
68 | #define ESB_WDT_FREQ ( 0x01 << 2 ) /* Decrement frequency */ | 67 | #define ESB_WDT_FREQ (0x01 << 2) /* Decrement frequency */ |
69 | #define ESB_WDT_INTTYPE ( 0x11 << 0 ) /* Interrupt type on timer1 timeout */ | 68 | #define ESB_WDT_INTTYPE (0x11 << 0) /* Interrupt type on timer1 timeout */ |
70 | 69 | ||
71 | /* Reload register bits */ | 70 | /* Reload register bits */ |
72 | #define ESB_WDT_RELOAD ( 0x01 << 8 ) /* prevent timeout */ | 71 | #define ESB_WDT_RELOAD (0x01 << 8) /* prevent timeout */ |
73 | 72 | ||
74 | /* Magic constants */ | 73 | /* Magic constants */ |
75 | #define ESB_UNLOCK1 0x80 /* Step 1 to unlock reset registers */ | 74 | #define ESB_UNLOCK1 0x80 /* Step 1 to unlock reset registers */ |
@@ -84,14 +83,20 @@ static unsigned short triggered; /* The status of the watchdog upon boot */ | |||
84 | static char esb_expect_close; | 83 | static char esb_expect_close; |
85 | 84 | ||
86 | /* module parameters */ | 85 | /* module parameters */ |
87 | #define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat (1<heartbeat<2*1023) */ | 86 | /* 30 sec default heartbeat (1 < heartbeat < 2*1023) */ |
87 | #define WATCHDOG_HEARTBEAT 30 | ||
88 | static int heartbeat = WATCHDOG_HEARTBEAT; /* in seconds */ | 88 | static int heartbeat = WATCHDOG_HEARTBEAT; /* in seconds */ |
89 | |||
89 | module_param(heartbeat, int, 0); | 90 | module_param(heartbeat, int, 0); |
90 | MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (1<heartbeat<2046, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")"); | 91 | MODULE_PARM_DESC(heartbeat, |
92 | "Watchdog heartbeat in seconds. (1<heartbeat<2046, default=" | ||
93 | __MODULE_STRING(WATCHDOG_HEARTBEAT) ")"); | ||
91 | 94 | ||
92 | static int nowayout = WATCHDOG_NOWAYOUT; | 95 | static int nowayout = WATCHDOG_NOWAYOUT; |
93 | module_param(nowayout, int, 0); | 96 | module_param(nowayout, int, 0); |
94 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 97 | MODULE_PARM_DESC(nowayout, |
98 | "Watchdog cannot be stopped once started (default=" | ||
99 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
95 | 100 | ||
96 | /* | 101 | /* |
97 | * Some i6300ESB specific functions | 102 | * Some i6300ESB specific functions |
@@ -103,9 +108,10 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" _ | |||
103 | * reload register. After this the appropriate registers can be written | 108 | * reload register. After this the appropriate registers can be written |
104 | * to once before they need to be unlocked again. | 109 | * to once before they need to be unlocked again. |
105 | */ | 110 | */ |
106 | static inline void esb_unlock_registers(void) { | 111 | static inline void esb_unlock_registers(void) |
107 | writeb(ESB_UNLOCK1, ESB_RELOAD_REG); | 112 | { |
108 | writeb(ESB_UNLOCK2, ESB_RELOAD_REG); | 113 | writeb(ESB_UNLOCK1, ESB_RELOAD_REG); |
114 | writeb(ESB_UNLOCK2, ESB_RELOAD_REG); | ||
109 | } | 115 | } |
110 | 116 | ||
111 | static void esb_timer_start(void) | 117 | static void esb_timer_start(void) |
@@ -114,8 +120,7 @@ static void esb_timer_start(void) | |||
114 | 120 | ||
115 | /* Enable or Enable + Lock? */ | 121 | /* Enable or Enable + Lock? */ |
116 | val = 0x02 | (nowayout ? 0x01 : 0x00); | 122 | val = 0x02 | (nowayout ? 0x01 : 0x00); |
117 | 123 | pci_write_config_byte(esb_pci, ESB_LOCK_REG, val); | |
118 | pci_write_config_byte(esb_pci, ESB_LOCK_REG, val); | ||
119 | } | 124 | } |
120 | 125 | ||
121 | static int esb_timer_stop(void) | 126 | static int esb_timer_stop(void) |
@@ -140,7 +145,7 @@ static void esb_timer_keepalive(void) | |||
140 | spin_lock(&esb_lock); | 145 | spin_lock(&esb_lock); |
141 | esb_unlock_registers(); | 146 | esb_unlock_registers(); |
142 | writew(ESB_WDT_RELOAD, ESB_RELOAD_REG); | 147 | writew(ESB_WDT_RELOAD, ESB_RELOAD_REG); |
143 | /* FIXME: Do we need to flush anything here? */ | 148 | /* FIXME: Do we need to flush anything here? */ |
144 | spin_unlock(&esb_lock); | 149 | spin_unlock(&esb_lock); |
145 | } | 150 | } |
146 | 151 | ||
@@ -165,9 +170,9 @@ static int esb_timer_set_heartbeat(int time) | |||
165 | 170 | ||
166 | /* Write timer 2 */ | 171 | /* Write timer 2 */ |
167 | esb_unlock_registers(); | 172 | esb_unlock_registers(); |
168 | writel(val, ESB_TIMER2_REG); | 173 | writel(val, ESB_TIMER2_REG); |
169 | 174 | ||
170 | /* Reload */ | 175 | /* Reload */ |
171 | esb_unlock_registers(); | 176 | esb_unlock_registers(); |
172 | writew(ESB_WDT_RELOAD, ESB_RELOAD_REG); | 177 | writew(ESB_WDT_RELOAD, ESB_RELOAD_REG); |
173 | 178 | ||
@@ -179,54 +184,55 @@ static int esb_timer_set_heartbeat(int time) | |||
179 | return 0; | 184 | return 0; |
180 | } | 185 | } |
181 | 186 | ||
182 | static int esb_timer_read (void) | 187 | static int esb_timer_read(void) |
183 | { | 188 | { |
184 | u32 count; | 189 | u32 count; |
185 | 190 | ||
186 | /* This isn't documented, and doesn't take into | 191 | /* This isn't documented, and doesn't take into |
187 | * acount which stage is running, but it looks | 192 | * acount which stage is running, but it looks |
188 | * like a 20 bit count down, so we might as well report it. | 193 | * like a 20 bit count down, so we might as well report it. |
189 | */ | 194 | */ |
190 | pci_read_config_dword(esb_pci, 0x64, &count); | 195 | pci_read_config_dword(esb_pci, 0x64, &count); |
191 | return (int)count; | 196 | return (int)count; |
192 | } | 197 | } |
193 | 198 | ||
194 | /* | 199 | /* |
195 | * /dev/watchdog handling | 200 | * /dev/watchdog handling |
196 | */ | 201 | */ |
197 | 202 | ||
198 | static int esb_open (struct inode *inode, struct file *file) | 203 | static int esb_open(struct inode *inode, struct file *file) |
199 | { | 204 | { |
200 | /* /dev/watchdog can only be opened once */ | 205 | /* /dev/watchdog can only be opened once */ |
201 | if (test_and_set_bit(0, &timer_alive)) | 206 | if (test_and_set_bit(0, &timer_alive)) |
202 | return -EBUSY; | 207 | return -EBUSY; |
203 | 208 | ||
204 | /* Reload and activate timer */ | 209 | /* Reload and activate timer */ |
205 | esb_timer_keepalive (); | 210 | esb_timer_keepalive(); |
206 | esb_timer_start (); | 211 | esb_timer_start(); |
207 | 212 | ||
208 | return nonseekable_open(inode, file); | 213 | return nonseekable_open(inode, file); |
209 | } | 214 | } |
210 | 215 | ||
211 | static int esb_release (struct inode *inode, struct file *file) | 216 | static int esb_release(struct inode *inode, struct file *file) |
212 | { | 217 | { |
213 | /* Shut off the timer. */ | 218 | /* Shut off the timer. */ |
214 | if (esb_expect_close == 42) { | 219 | if (esb_expect_close == 42) |
215 | esb_timer_stop (); | 220 | esb_timer_stop(); |
216 | } else { | 221 | else { |
217 | printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); | 222 | printk(KERN_CRIT PFX |
218 | esb_timer_keepalive (); | 223 | "Unexpected close, not stopping watchdog!\n"); |
219 | } | 224 | esb_timer_keepalive(); |
220 | clear_bit(0, &timer_alive); | 225 | } |
221 | esb_expect_close = 0; | 226 | clear_bit(0, &timer_alive); |
222 | return 0; | 227 | esb_expect_close = 0; |
228 | return 0; | ||
223 | } | 229 | } |
224 | 230 | ||
225 | static ssize_t esb_write (struct file *file, const char __user *data, | 231 | static ssize_t esb_write(struct file *file, const char __user *data, |
226 | size_t len, loff_t * ppos) | 232 | size_t len, loff_t *ppos) |
227 | { | 233 | { |
228 | /* See if we got the magic character 'V' and reload the timer */ | 234 | /* See if we got the magic character 'V' and reload the timer */ |
229 | if (len) { | 235 | if (len) { |
230 | if (!nowayout) { | 236 | if (!nowayout) { |
231 | size_t i; | 237 | size_t i; |
232 | 238 | ||
@@ -237,7 +243,7 @@ static ssize_t esb_write (struct file *file, const char __user *data, | |||
237 | /* scan to see whether or not we got the magic character */ | 243 | /* scan to see whether or not we got the magic character */ |
238 | for (i = 0; i != len; i++) { | 244 | for (i = 0; i != len; i++) { |
239 | char c; | 245 | char c; |
240 | if(get_user(c, data+i)) | 246 | if (get_user(c, data + i)) |
241 | return -EFAULT; | 247 | return -EFAULT; |
242 | if (c == 'V') | 248 | if (c == 'V') |
243 | esb_expect_close = 42; | 249 | esb_expect_close = 42; |
@@ -245,92 +251,84 @@ static ssize_t esb_write (struct file *file, const char __user *data, | |||
245 | } | 251 | } |
246 | 252 | ||
247 | /* someone wrote to us, we should reload the timer */ | 253 | /* someone wrote to us, we should reload the timer */ |
248 | esb_timer_keepalive (); | 254 | esb_timer_keepalive(); |
249 | } | 255 | } |
250 | return len; | 256 | return len; |
251 | } | 257 | } |
252 | 258 | ||
253 | static int esb_ioctl (struct inode *inode, struct file *file, | 259 | static long esb_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
254 | unsigned int cmd, unsigned long arg) | ||
255 | { | 260 | { |
256 | int new_options, retval = -EINVAL; | 261 | int new_options, retval = -EINVAL; |
257 | int new_heartbeat; | 262 | int new_heartbeat; |
258 | void __user *argp = (void __user *)arg; | 263 | void __user *argp = (void __user *)arg; |
259 | int __user *p = argp; | 264 | int __user *p = argp; |
260 | static struct watchdog_info ident = { | 265 | static struct watchdog_info ident = { |
261 | .options = WDIOF_SETTIMEOUT | | 266 | .options = WDIOF_SETTIMEOUT | |
262 | WDIOF_KEEPALIVEPING | | 267 | WDIOF_KEEPALIVEPING | |
263 | WDIOF_MAGICCLOSE, | 268 | WDIOF_MAGICCLOSE, |
264 | .firmware_version = 0, | 269 | .firmware_version = 0, |
265 | .identity = ESB_MODULE_NAME, | 270 | .identity = ESB_MODULE_NAME, |
266 | }; | 271 | }; |
267 | 272 | ||
268 | switch (cmd) { | 273 | switch (cmd) { |
269 | case WDIOC_GETSUPPORT: | 274 | case WDIOC_GETSUPPORT: |
270 | return copy_to_user(argp, &ident, | 275 | return copy_to_user(argp, &ident, |
271 | sizeof (ident)) ? -EFAULT : 0; | 276 | sizeof(ident)) ? -EFAULT : 0; |
272 | |||
273 | case WDIOC_GETSTATUS: | ||
274 | return put_user (esb_timer_read(), p); | ||
275 | |||
276 | case WDIOC_GETBOOTSTATUS: | ||
277 | return put_user (triggered, p); | ||
278 | 277 | ||
279 | case WDIOC_KEEPALIVE: | 278 | case WDIOC_GETSTATUS: |
280 | esb_timer_keepalive (); | 279 | return put_user(esb_timer_read(), p); |
281 | return 0; | ||
282 | 280 | ||
283 | case WDIOC_SETOPTIONS: | 281 | case WDIOC_GETBOOTSTATUS: |
284 | { | 282 | return put_user(triggered, p); |
285 | if (get_user (new_options, p)) | ||
286 | return -EFAULT; | ||
287 | 283 | ||
288 | if (new_options & WDIOS_DISABLECARD) { | 284 | case WDIOC_SETOPTIONS: |
289 | esb_timer_stop (); | 285 | { |
290 | retval = 0; | 286 | if (get_user(new_options, p)) |
291 | } | 287 | return -EFAULT; |
292 | 288 | ||
293 | if (new_options & WDIOS_ENABLECARD) { | 289 | if (new_options & WDIOS_DISABLECARD) { |
294 | esb_timer_keepalive (); | 290 | esb_timer_stop(); |
295 | esb_timer_start (); | 291 | retval = 0; |
296 | retval = 0; | 292 | } |
297 | } | ||
298 | |||
299 | return retval; | ||
300 | } | ||
301 | |||
302 | case WDIOC_SETTIMEOUT: | ||
303 | { | ||
304 | if (get_user(new_heartbeat, p)) | ||
305 | return -EFAULT; | ||
306 | |||
307 | if (esb_timer_set_heartbeat(new_heartbeat)) | ||
308 | return -EINVAL; | ||
309 | |||
310 | esb_timer_keepalive (); | ||
311 | /* Fall */ | ||
312 | } | ||
313 | |||
314 | case WDIOC_GETTIMEOUT: | ||
315 | return put_user(heartbeat, p); | ||
316 | 293 | ||
317 | default: | 294 | if (new_options & WDIOS_ENABLECARD) { |
318 | return -ENOTTY; | 295 | esb_timer_keepalive(); |
319 | } | 296 | esb_timer_start(); |
297 | retval = 0; | ||
298 | } | ||
299 | return retval; | ||
300 | } | ||
301 | case WDIOC_KEEPALIVE: | ||
302 | esb_timer_keepalive(); | ||
303 | return 0; | ||
304 | |||
305 | case WDIOC_SETTIMEOUT: | ||
306 | { | ||
307 | if (get_user(new_heartbeat, p)) | ||
308 | return -EFAULT; | ||
309 | if (esb_timer_set_heartbeat(new_heartbeat)) | ||
310 | return -EINVAL; | ||
311 | esb_timer_keepalive(); | ||
312 | /* Fall */ | ||
313 | } | ||
314 | case WDIOC_GETTIMEOUT: | ||
315 | return put_user(heartbeat, p); | ||
316 | default: | ||
317 | return -ENOTTY; | ||
318 | } | ||
320 | } | 319 | } |
321 | 320 | ||
322 | /* | 321 | /* |
323 | * Notify system | 322 | * Notify system |
324 | */ | 323 | */ |
325 | 324 | ||
326 | static int esb_notify_sys (struct notifier_block *this, unsigned long code, void *unused) | 325 | static int esb_notify_sys(struct notifier_block *this, |
326 | unsigned long code, void *unused) | ||
327 | { | 327 | { |
328 | if (code==SYS_DOWN || code==SYS_HALT) { | 328 | if (code == SYS_DOWN || code == SYS_HALT) |
329 | /* Turn the WDT off */ | 329 | esb_timer_stop(); /* Turn the WDT off */ |
330 | esb_timer_stop (); | ||
331 | } | ||
332 | 330 | ||
333 | return NOTIFY_DONE; | 331 | return NOTIFY_DONE; |
334 | } | 332 | } |
335 | 333 | ||
336 | /* | 334 | /* |
@@ -338,22 +336,22 @@ static int esb_notify_sys (struct notifier_block *this, unsigned long code, void | |||
338 | */ | 336 | */ |
339 | 337 | ||
340 | static const struct file_operations esb_fops = { | 338 | static const struct file_operations esb_fops = { |
341 | .owner = THIS_MODULE, | 339 | .owner = THIS_MODULE, |
342 | .llseek = no_llseek, | 340 | .llseek = no_llseek, |
343 | .write = esb_write, | 341 | .write = esb_write, |
344 | .ioctl = esb_ioctl, | 342 | .unlocked_ioctl = esb_ioctl, |
345 | .open = esb_open, | 343 | .open = esb_open, |
346 | .release = esb_release, | 344 | .release = esb_release, |
347 | }; | 345 | }; |
348 | 346 | ||
349 | static struct miscdevice esb_miscdev = { | 347 | static struct miscdevice esb_miscdev = { |
350 | .minor = WATCHDOG_MINOR, | 348 | .minor = WATCHDOG_MINOR, |
351 | .name = "watchdog", | 349 | .name = "watchdog", |
352 | .fops = &esb_fops, | 350 | .fops = &esb_fops, |
353 | }; | 351 | }; |
354 | 352 | ||
355 | static struct notifier_block esb_notifier = { | 353 | static struct notifier_block esb_notifier = { |
356 | .notifier_call = esb_notify_sys, | 354 | .notifier_call = esb_notify_sys, |
357 | }; | 355 | }; |
358 | 356 | ||
359 | /* | 357 | /* |
@@ -365,50 +363,44 @@ static struct notifier_block esb_notifier = { | |||
365 | * want to register another driver on the same PCI id. | 363 | * want to register another driver on the same PCI id. |
366 | */ | 364 | */ |
367 | static struct pci_device_id esb_pci_tbl[] = { | 365 | static struct pci_device_id esb_pci_tbl[] = { |
368 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_9), }, | 366 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_9), }, |
369 | { 0, }, /* End of list */ | 367 | { 0, }, /* End of list */ |
370 | }; | 368 | }; |
371 | MODULE_DEVICE_TABLE (pci, esb_pci_tbl); | 369 | MODULE_DEVICE_TABLE(pci, esb_pci_tbl); |
372 | 370 | ||
373 | /* | 371 | /* |
374 | * Init & exit routines | 372 | * Init & exit routines |
375 | */ | 373 | */ |
376 | 374 | ||
377 | static unsigned char __init esb_getdevice (void) | 375 | static unsigned char __init esb_getdevice(void) |
378 | { | 376 | { |
379 | u8 val1; | 377 | u8 val1; |
380 | unsigned short val2; | 378 | unsigned short val2; |
379 | /* | ||
380 | * Find the PCI device | ||
381 | */ | ||
381 | 382 | ||
382 | struct pci_dev *dev = NULL; | 383 | esb_pci = pci_get_device(PCI_VENDOR_ID_INTEL, |
383 | /* | 384 | PCI_DEVICE_ID_INTEL_ESB_9, NULL); |
384 | * Find the PCI device | ||
385 | */ | ||
386 | |||
387 | for_each_pci_dev(dev) { | ||
388 | if (pci_match_id(esb_pci_tbl, dev)) { | ||
389 | esb_pci = dev; | ||
390 | break; | ||
391 | } | ||
392 | } | ||
393 | 385 | ||
394 | if (esb_pci) { | 386 | if (esb_pci) { |
395 | if (pci_enable_device(esb_pci)) { | 387 | if (pci_enable_device(esb_pci)) { |
396 | printk (KERN_ERR PFX "failed to enable device\n"); | 388 | printk(KERN_ERR PFX "failed to enable device\n"); |
397 | goto err_devput; | 389 | goto err_devput; |
398 | } | 390 | } |
399 | 391 | ||
400 | if (pci_request_region(esb_pci, 0, ESB_MODULE_NAME)) { | 392 | if (pci_request_region(esb_pci, 0, ESB_MODULE_NAME)) { |
401 | printk (KERN_ERR PFX "failed to request region\n"); | 393 | printk(KERN_ERR PFX "failed to request region\n"); |
402 | goto err_disable; | 394 | goto err_disable; |
403 | } | 395 | } |
404 | 396 | ||
405 | BASEADDR = ioremap(pci_resource_start(esb_pci, 0), | 397 | BASEADDR = ioremap(pci_resource_start(esb_pci, 0), |
406 | pci_resource_len(esb_pci, 0)); | 398 | pci_resource_len(esb_pci, 0)); |
407 | if (BASEADDR == NULL) { | 399 | if (BASEADDR == NULL) { |
408 | /* Something's wrong here, BASEADDR has to be set */ | 400 | /* Something's wrong here, BASEADDR has to be set */ |
409 | printk (KERN_ERR PFX "failed to get BASEADDR\n"); | 401 | printk(KERN_ERR PFX "failed to get BASEADDR\n"); |
410 | goto err_release; | 402 | goto err_release; |
411 | } | 403 | } |
412 | 404 | ||
413 | /* | 405 | /* |
414 | * The watchdog has two timers, it can be setup so that the | 406 | * The watchdog has two timers, it can be setup so that the |
@@ -425,7 +417,7 @@ static unsigned char __init esb_getdevice (void) | |||
425 | /* Check that the WDT isn't already locked */ | 417 | /* Check that the WDT isn't already locked */ |
426 | pci_read_config_byte(esb_pci, ESB_LOCK_REG, &val1); | 418 | pci_read_config_byte(esb_pci, ESB_LOCK_REG, &val1); |
427 | if (val1 & ESB_WDT_LOCK) | 419 | if (val1 & ESB_WDT_LOCK) |
428 | printk (KERN_WARNING PFX "nowayout already set\n"); | 420 | printk(KERN_WARNING PFX "nowayout already set\n"); |
429 | 421 | ||
430 | /* Set the timer to watchdog mode and disable it for now */ | 422 | /* Set the timer to watchdog mode and disable it for now */ |
431 | pci_write_config_byte(esb_pci, ESB_LOCK_REG, 0x00); | 423 | pci_write_config_byte(esb_pci, ESB_LOCK_REG, 0x00); |
@@ -452,44 +444,44 @@ err_devput: | |||
452 | return 0; | 444 | return 0; |
453 | } | 445 | } |
454 | 446 | ||
455 | static int __init watchdog_init (void) | 447 | static int __init watchdog_init(void) |
456 | { | 448 | { |
457 | int ret; | 449 | int ret; |
458 | 450 | ||
459 | /* Check whether or not the hardware watchdog is there */ | 451 | /* Check whether or not the hardware watchdog is there */ |
460 | if (!esb_getdevice () || esb_pci == NULL) | 452 | if (!esb_getdevice() || esb_pci == NULL) |
461 | return -ENODEV; | 453 | return -ENODEV; |
462 | 454 | ||
463 | /* Check that the heartbeat value is within it's range ; if not reset to the default */ | 455 | /* Check that the heartbeat value is within it's range; |
464 | if (esb_timer_set_heartbeat (heartbeat)) { | 456 | if not reset to the default */ |
465 | esb_timer_set_heartbeat (WATCHDOG_HEARTBEAT); | 457 | if (esb_timer_set_heartbeat(heartbeat)) { |
466 | printk(KERN_INFO PFX "heartbeat value must be 1<heartbeat<2046, using %d\n", | 458 | esb_timer_set_heartbeat(WATCHDOG_HEARTBEAT); |
467 | heartbeat); | 459 | printk(KERN_INFO PFX |
468 | } | 460 | "heartbeat value must be 1<heartbeat<2046, using %d\n", |
469 | 461 | heartbeat); | |
470 | ret = register_reboot_notifier(&esb_notifier); | 462 | } |
471 | if (ret != 0) { | 463 | ret = register_reboot_notifier(&esb_notifier); |
472 | printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", | 464 | if (ret != 0) { |
473 | ret); | 465 | printk(KERN_ERR PFX |
474 | goto err_unmap; | 466 | "cannot register reboot notifier (err=%d)\n", ret); |
475 | } | 467 | goto err_unmap; |
476 | 468 | } | |
477 | ret = misc_register(&esb_miscdev); | ||
478 | if (ret != 0) { | ||
479 | printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", | ||
480 | WATCHDOG_MINOR, ret); | ||
481 | goto err_notifier; | ||
482 | } | ||
483 | |||
484 | esb_timer_stop (); | ||
485 | |||
486 | printk (KERN_INFO PFX "initialized (0x%p). heartbeat=%d sec (nowayout=%d)\n", | ||
487 | BASEADDR, heartbeat, nowayout); | ||
488 | 469 | ||
489 | return 0; | 470 | ret = misc_register(&esb_miscdev); |
471 | if (ret != 0) { | ||
472 | printk(KERN_ERR PFX | ||
473 | "cannot register miscdev on minor=%d (err=%d)\n", | ||
474 | WATCHDOG_MINOR, ret); | ||
475 | goto err_notifier; | ||
476 | } | ||
477 | esb_timer_stop(); | ||
478 | printk(KERN_INFO PFX | ||
479 | "initialized (0x%p). heartbeat=%d sec (nowayout=%d)\n", | ||
480 | BASEADDR, heartbeat, nowayout); | ||
481 | return 0; | ||
490 | 482 | ||
491 | err_notifier: | 483 | err_notifier: |
492 | unregister_reboot_notifier(&esb_notifier); | 484 | unregister_reboot_notifier(&esb_notifier); |
493 | err_unmap: | 485 | err_unmap: |
494 | iounmap(BASEADDR); | 486 | iounmap(BASEADDR); |
495 | /* err_release: */ | 487 | /* err_release: */ |
@@ -498,18 +490,18 @@ err_unmap: | |||
498 | pci_disable_device(esb_pci); | 490 | pci_disable_device(esb_pci); |
499 | /* err_devput: */ | 491 | /* err_devput: */ |
500 | pci_dev_put(esb_pci); | 492 | pci_dev_put(esb_pci); |
501 | return ret; | 493 | return ret; |
502 | } | 494 | } |
503 | 495 | ||
504 | static void __exit watchdog_cleanup (void) | 496 | static void __exit watchdog_cleanup(void) |
505 | { | 497 | { |
506 | /* Stop the timer before we leave */ | 498 | /* Stop the timer before we leave */ |
507 | if (!nowayout) | 499 | if (!nowayout) |
508 | esb_timer_stop (); | 500 | esb_timer_stop(); |
509 | 501 | ||
510 | /* Deregister */ | 502 | /* Deregister */ |
511 | misc_deregister(&esb_miscdev); | 503 | misc_deregister(&esb_miscdev); |
512 | unregister_reboot_notifier(&esb_notifier); | 504 | unregister_reboot_notifier(&esb_notifier); |
513 | iounmap(BASEADDR); | 505 | iounmap(BASEADDR); |
514 | pci_release_region(esb_pci, 0); | 506 | pci_release_region(esb_pci, 0); |
515 | pci_disable_device(esb_pci); | 507 | pci_disable_device(esb_pci); |
diff --git a/drivers/watchdog/iTCO_vendor.h b/drivers/watchdog/iTCO_vendor.h new file mode 100644 index 000000000000..9e27e6422f66 --- /dev/null +++ b/drivers/watchdog/iTCO_vendor.h | |||
@@ -0,0 +1,15 @@ | |||
1 | /* iTCO Vendor Specific Support hooks */ | ||
2 | #ifdef CONFIG_ITCO_VENDOR_SUPPORT | ||
3 | extern void iTCO_vendor_pre_start(unsigned long, unsigned int); | ||
4 | extern void iTCO_vendor_pre_stop(unsigned long); | ||
5 | extern void iTCO_vendor_pre_keepalive(unsigned long, unsigned int); | ||
6 | extern void iTCO_vendor_pre_set_heartbeat(unsigned int); | ||
7 | extern int iTCO_vendor_check_noreboot_on(void); | ||
8 | #else | ||
9 | #define iTCO_vendor_pre_start(acpibase, heartbeat) {} | ||
10 | #define iTCO_vendor_pre_stop(acpibase) {} | ||
11 | #define iTCO_vendor_pre_keepalive(acpibase, heartbeat) {} | ||
12 | #define iTCO_vendor_pre_set_heartbeat(heartbeat) {} | ||
13 | #define iTCO_vendor_check_noreboot_on() 1 | ||
14 | /* 1=check noreboot; 0=don't check */ | ||
15 | #endif | ||
diff --git a/drivers/watchdog/iTCO_vendor_support.c b/drivers/watchdog/iTCO_vendor_support.c index cafc465f2ae3..ca344a85eb95 100644 --- a/drivers/watchdog/iTCO_vendor_support.c +++ b/drivers/watchdog/iTCO_vendor_support.c | |||
@@ -18,9 +18,9 @@ | |||
18 | */ | 18 | */ |
19 | 19 | ||
20 | /* Module and version information */ | 20 | /* Module and version information */ |
21 | #define DRV_NAME "iTCO_vendor_support" | 21 | #define DRV_NAME "iTCO_vendor_support" |
22 | #define DRV_VERSION "1.01" | 22 | #define DRV_VERSION "1.01" |
23 | #define DRV_RELDATE "11-Nov-2006" | 23 | #define DRV_RELDATE "11-Nov-2006" |
24 | #define PFX DRV_NAME ": " | 24 | #define PFX DRV_NAME ": " |
25 | 25 | ||
26 | /* Includes */ | 26 | /* Includes */ |
@@ -31,19 +31,22 @@ | |||
31 | #include <linux/kernel.h> /* For printk/panic/... */ | 31 | #include <linux/kernel.h> /* For printk/panic/... */ |
32 | #include <linux/init.h> /* For __init/__exit/... */ | 32 | #include <linux/init.h> /* For __init/__exit/... */ |
33 | #include <linux/ioport.h> /* For io-port access */ | 33 | #include <linux/ioport.h> /* For io-port access */ |
34 | #include <linux/io.h> /* For inb/outb/... */ | ||
34 | 35 | ||
35 | #include <asm/io.h> /* For inb/outb/... */ | 36 | #include "iTCO_vendor.h" |
36 | 37 | ||
37 | /* iTCO defines */ | 38 | /* iTCO defines */ |
38 | #define SMI_EN acpibase + 0x30 /* SMI Control and Enable Register */ | 39 | #define SMI_EN acpibase + 0x30 /* SMI Control and Enable Register */ |
39 | #define TCOBASE acpibase + 0x60 /* TCO base address */ | 40 | #define TCOBASE acpibase + 0x60 /* TCO base address */ |
40 | #define TCO1_STS TCOBASE + 0x04 /* TCO1 Status Register */ | 41 | #define TCO1_STS TCOBASE + 0x04 /* TCO1 Status Register */ |
41 | 42 | ||
42 | /* List of vendor support modes */ | 43 | /* List of vendor support modes */ |
43 | #define SUPERMICRO_OLD_BOARD 1 /* SuperMicro Pentium 3 Era 370SSE+-OEM1/P3TSSE */ | 44 | /* SuperMicro Pentium 3 Era 370SSE+-OEM1/P3TSSE */ |
44 | #define SUPERMICRO_NEW_BOARD 2 /* SuperMicro Pentium 4 / Xeon 4 / EMT64T Era Systems */ | 45 | #define SUPERMICRO_OLD_BOARD 1 |
46 | /* SuperMicro Pentium 4 / Xeon 4 / EMT64T Era Systems */ | ||
47 | #define SUPERMICRO_NEW_BOARD 2 | ||
45 | 48 | ||
46 | static int vendorsupport = 0; | 49 | static int vendorsupport; |
47 | module_param(vendorsupport, int, 0); | 50 | module_param(vendorsupport, int, 0); |
48 | MODULE_PARM_DESC(vendorsupport, "iTCO vendor specific support mode, default=0 (none), 1=SuperMicro Pent3, 2=SuperMicro Pent4+"); | 51 | MODULE_PARM_DESC(vendorsupport, "iTCO vendor specific support mode, default=0 (none), 1=SuperMicro Pent3, 2=SuperMicro Pent4+"); |
49 | 52 | ||
@@ -143,34 +146,35 @@ static void supermicro_old_pre_keepalive(unsigned long acpibase) | |||
143 | */ | 146 | */ |
144 | 147 | ||
145 | /* I/O Port's */ | 148 | /* I/O Port's */ |
146 | #define SM_REGINDEX 0x2e /* SuperMicro ICH4+ Register Index */ | 149 | #define SM_REGINDEX 0x2e /* SuperMicro ICH4+ Register Index */ |
147 | #define SM_DATAIO 0x2f /* SuperMicro ICH4+ Register Data I/O */ | 150 | #define SM_DATAIO 0x2f /* SuperMicro ICH4+ Register Data I/O */ |
148 | 151 | ||
149 | /* Control Register's */ | 152 | /* Control Register's */ |
150 | #define SM_CTLPAGESW 0x07 /* SuperMicro ICH4+ Control Page Switch */ | 153 | #define SM_CTLPAGESW 0x07 /* SuperMicro ICH4+ Control Page Switch */ |
151 | #define SM_CTLPAGE 0x08 /* SuperMicro ICH4+ Control Page Num */ | 154 | #define SM_CTLPAGE 0x08 /* SuperMicro ICH4+ Control Page Num */ |
152 | 155 | ||
153 | #define SM_WATCHENABLE 0x30 /* Watchdog enable: Bit 0: 0=off, 1=on */ | 156 | #define SM_WATCHENABLE 0x30 /* Watchdog enable: Bit 0: 0=off, 1=on */ |
154 | 157 | ||
155 | #define SM_WATCHPAGE 0x87 /* Watchdog unlock control page */ | 158 | #define SM_WATCHPAGE 0x87 /* Watchdog unlock control page */ |
156 | 159 | ||
157 | #define SM_ENDWATCH 0xAA /* Watchdog lock control page */ | 160 | #define SM_ENDWATCH 0xAA /* Watchdog lock control page */ |
158 | 161 | ||
159 | #define SM_COUNTMODE 0xf5 /* Watchdog count mode select */ | 162 | #define SM_COUNTMODE 0xf5 /* Watchdog count mode select */ |
160 | /* (Bit 3: 0 = seconds, 1 = minutes */ | 163 | /* (Bit 3: 0 = seconds, 1 = minutes */ |
161 | 164 | ||
162 | #define SM_WATCHTIMER 0xf6 /* 8-bits, Watchdog timer counter (RW) */ | 165 | #define SM_WATCHTIMER 0xf6 /* 8-bits, Watchdog timer counter (RW) */ |
163 | 166 | ||
164 | #define SM_RESETCONTROL 0xf7 /* Watchdog reset control */ | 167 | #define SM_RESETCONTROL 0xf7 /* Watchdog reset control */ |
165 | /* Bit 6: timer is reset by kbd interrupt */ | 168 | /* Bit 6: timer is reset by kbd interrupt */ |
166 | /* Bit 7: timer is reset by mouse interrupt */ | 169 | /* Bit 7: timer is reset by mouse interrupt */ |
167 | 170 | ||
168 | static void supermicro_new_unlock_watchdog(void) | 171 | static void supermicro_new_unlock_watchdog(void) |
169 | { | 172 | { |
170 | outb(SM_WATCHPAGE, SM_REGINDEX); /* Write 0x87 to port 0x2e twice */ | 173 | /* Write 0x87 to port 0x2e twice */ |
171 | outb(SM_WATCHPAGE, SM_REGINDEX); | 174 | outb(SM_WATCHPAGE, SM_REGINDEX); |
172 | 175 | outb(SM_WATCHPAGE, SM_REGINDEX); | |
173 | outb(SM_CTLPAGESW, SM_REGINDEX); /* Switch to watchdog control page */ | 176 | /* Switch to watchdog control page */ |
177 | outb(SM_CTLPAGESW, SM_REGINDEX); | ||
174 | outb(SM_CTLPAGE, SM_DATAIO); | 178 | outb(SM_CTLPAGE, SM_DATAIO); |
175 | } | 179 | } |
176 | 180 | ||
@@ -192,7 +196,7 @@ static void supermicro_new_pre_start(unsigned int heartbeat) | |||
192 | outb(val, SM_DATAIO); | 196 | outb(val, SM_DATAIO); |
193 | 197 | ||
194 | /* Write heartbeat interval to WDOG */ | 198 | /* Write heartbeat interval to WDOG */ |
195 | outb (SM_WATCHTIMER, SM_REGINDEX); | 199 | outb(SM_WATCHTIMER, SM_REGINDEX); |
196 | outb((heartbeat & 255), SM_DATAIO); | 200 | outb((heartbeat & 255), SM_DATAIO); |
197 | 201 | ||
198 | /* Make sure keyboard/mouse interrupts don't interfere */ | 202 | /* Make sure keyboard/mouse interrupts don't interfere */ |
@@ -277,7 +281,7 @@ EXPORT_SYMBOL(iTCO_vendor_pre_set_heartbeat); | |||
277 | 281 | ||
278 | int iTCO_vendor_check_noreboot_on(void) | 282 | int iTCO_vendor_check_noreboot_on(void) |
279 | { | 283 | { |
280 | switch(vendorsupport) { | 284 | switch (vendorsupport) { |
281 | case SUPERMICRO_OLD_BOARD: | 285 | case SUPERMICRO_OLD_BOARD: |
282 | return 0; | 286 | return 0; |
283 | default: | 287 | default: |
@@ -288,13 +292,13 @@ EXPORT_SYMBOL(iTCO_vendor_check_noreboot_on); | |||
288 | 292 | ||
289 | static int __init iTCO_vendor_init_module(void) | 293 | static int __init iTCO_vendor_init_module(void) |
290 | { | 294 | { |
291 | printk (KERN_INFO PFX "vendor-support=%d\n", vendorsupport); | 295 | printk(KERN_INFO PFX "vendor-support=%d\n", vendorsupport); |
292 | return 0; | 296 | return 0; |
293 | } | 297 | } |
294 | 298 | ||
295 | static void __exit iTCO_vendor_exit_module(void) | 299 | static void __exit iTCO_vendor_exit_module(void) |
296 | { | 300 | { |
297 | printk (KERN_INFO PFX "Module Unloaded\n"); | 301 | printk(KERN_INFO PFX "Module Unloaded\n"); |
298 | } | 302 | } |
299 | 303 | ||
300 | module_init(iTCO_vendor_init_module); | 304 | module_init(iTCO_vendor_init_module); |
diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c index 95ba985bd341..bfb93bc2ca9f 100644 --- a/drivers/watchdog/iTCO_wdt.c +++ b/drivers/watchdog/iTCO_wdt.c | |||
@@ -55,9 +55,9 @@ | |||
55 | */ | 55 | */ |
56 | 56 | ||
57 | /* Module and version information */ | 57 | /* Module and version information */ |
58 | #define DRV_NAME "iTCO_wdt" | 58 | #define DRV_NAME "iTCO_wdt" |
59 | #define DRV_VERSION "1.03" | 59 | #define DRV_VERSION "1.03" |
60 | #define DRV_RELDATE "30-Apr-2008" | 60 | #define DRV_RELDATE "30-Apr-2008" |
61 | #define PFX DRV_NAME ": " | 61 | #define PFX DRV_NAME ": " |
62 | 62 | ||
63 | /* Includes */ | 63 | /* Includes */ |
@@ -66,7 +66,8 @@ | |||
66 | #include <linux/types.h> /* For standard types (like size_t) */ | 66 | #include <linux/types.h> /* For standard types (like size_t) */ |
67 | #include <linux/errno.h> /* For the -ENODEV/... values */ | 67 | #include <linux/errno.h> /* For the -ENODEV/... values */ |
68 | #include <linux/kernel.h> /* For printk/panic/... */ | 68 | #include <linux/kernel.h> /* For printk/panic/... */ |
69 | #include <linux/miscdevice.h> /* For MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR) */ | 69 | #include <linux/miscdevice.h> /* For MODULE_ALIAS_MISCDEV |
70 | (WATCHDOG_MINOR) */ | ||
70 | #include <linux/watchdog.h> /* For the watchdog specific items */ | 71 | #include <linux/watchdog.h> /* For the watchdog specific items */ |
71 | #include <linux/init.h> /* For __init/__exit/... */ | 72 | #include <linux/init.h> /* For __init/__exit/... */ |
72 | #include <linux/fs.h> /* For file operations */ | 73 | #include <linux/fs.h> /* For file operations */ |
@@ -74,9 +75,10 @@ | |||
74 | #include <linux/pci.h> /* For pci functions */ | 75 | #include <linux/pci.h> /* For pci functions */ |
75 | #include <linux/ioport.h> /* For io-port access */ | 76 | #include <linux/ioport.h> /* For io-port access */ |
76 | #include <linux/spinlock.h> /* For spin_lock/spin_unlock/... */ | 77 | #include <linux/spinlock.h> /* For spin_lock/spin_unlock/... */ |
78 | #include <linux/uaccess.h> /* For copy_to_user/put_user/... */ | ||
79 | #include <linux/io.h> /* For inb/outb/... */ | ||
77 | 80 | ||
78 | #include <asm/uaccess.h> /* For copy_to_user/put_user/... */ | 81 | #include "iTCO_vendor.h" |
79 | #include <asm/io.h> /* For inb/outb/... */ | ||
80 | 82 | ||
81 | /* TCO related info */ | 83 | /* TCO related info */ |
82 | enum iTCO_chipsets { | 84 | enum iTCO_chipsets { |
@@ -105,7 +107,7 @@ enum iTCO_chipsets { | |||
105 | TCO_ICH9, /* ICH9 */ | 107 | TCO_ICH9, /* ICH9 */ |
106 | TCO_ICH9R, /* ICH9R */ | 108 | TCO_ICH9R, /* ICH9R */ |
107 | TCO_ICH9DH, /* ICH9DH */ | 109 | TCO_ICH9DH, /* ICH9DH */ |
108 | TCO_ICH9DO, /* ICH9DO */ | 110 | TCO_ICH9DO, /* ICH9DO */ |
109 | TCO_631XESB, /* 631xESB/632xESB */ | 111 | TCO_631XESB, /* 631xESB/632xESB */ |
110 | }; | 112 | }; |
111 | 113 | ||
@@ -140,7 +142,7 @@ static struct { | |||
140 | {"ICH9DH", 2}, | 142 | {"ICH9DH", 2}, |
141 | {"ICH9DO", 2}, | 143 | {"ICH9DO", 2}, |
142 | {"631xESB/632xESB", 2}, | 144 | {"631xESB/632xESB", 2}, |
143 | {NULL,0} | 145 | {NULL, 0} |
144 | }; | 146 | }; |
145 | 147 | ||
146 | #define ITCO_PCI_DEVICE(dev, data) \ | 148 | #define ITCO_PCI_DEVICE(dev, data) \ |
@@ -159,32 +161,32 @@ static struct { | |||
159 | * functions that probably will be registered by other drivers. | 161 | * functions that probably will be registered by other drivers. |
160 | */ | 162 | */ |
161 | static struct pci_device_id iTCO_wdt_pci_tbl[] = { | 163 | static struct pci_device_id iTCO_wdt_pci_tbl[] = { |
162 | { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801AA_0, TCO_ICH )}, | 164 | { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801AA_0, TCO_ICH)}, |
163 | { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801AB_0, TCO_ICH0 )}, | 165 | { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801AB_0, TCO_ICH0)}, |
164 | { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801BA_0, TCO_ICH2 )}, | 166 | { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801BA_0, TCO_ICH2)}, |
165 | { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801BA_10, TCO_ICH2M )}, | 167 | { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801BA_10, TCO_ICH2M)}, |
166 | { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801CA_0, TCO_ICH3 )}, | 168 | { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801CA_0, TCO_ICH3)}, |
167 | { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801CA_12, TCO_ICH3M )}, | 169 | { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801CA_12, TCO_ICH3M)}, |
168 | { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801DB_0, TCO_ICH4 )}, | 170 | { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801DB_0, TCO_ICH4)}, |
169 | { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801DB_12, TCO_ICH4M )}, | 171 | { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801DB_12, TCO_ICH4M)}, |
170 | { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801E_0, TCO_CICH )}, | 172 | { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801E_0, TCO_CICH)}, |
171 | { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801EB_0, TCO_ICH5 )}, | 173 | { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801EB_0, TCO_ICH5)}, |
172 | { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ESB_1, TCO_6300ESB)}, | 174 | { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ESB_1, TCO_6300ESB)}, |
173 | { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH6_0, TCO_ICH6 )}, | 175 | { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH6_0, TCO_ICH6)}, |
174 | { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH6_1, TCO_ICH6M )}, | 176 | { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH6_1, TCO_ICH6M)}, |
175 | { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH6_2, TCO_ICH6W )}, | 177 | { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH6_2, TCO_ICH6W)}, |
176 | { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_0, TCO_ICH7 )}, | 178 | { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_0, TCO_ICH7)}, |
177 | { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_1, TCO_ICH7M )}, | 179 | { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_1, TCO_ICH7M)}, |
178 | { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_31, TCO_ICH7MDH)}, | 180 | { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_31, TCO_ICH7MDH)}, |
179 | { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_0, TCO_ICH8 )}, | 181 | { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_0, TCO_ICH8)}, |
180 | { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_1, TCO_ICH8ME )}, | 182 | { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_1, TCO_ICH8ME)}, |
181 | { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_2, TCO_ICH8DH )}, | 183 | { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_2, TCO_ICH8DH)}, |
182 | { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_3, TCO_ICH8DO )}, | 184 | { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_3, TCO_ICH8DO)}, |
183 | { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_4, TCO_ICH8M )}, | 185 | { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_4, TCO_ICH8M)}, |
184 | { ITCO_PCI_DEVICE(0x2918, TCO_ICH9 )}, | 186 | { ITCO_PCI_DEVICE(0x2918, TCO_ICH9)}, |
185 | { ITCO_PCI_DEVICE(0x2916, TCO_ICH9R )}, | 187 | { ITCO_PCI_DEVICE(0x2916, TCO_ICH9R)}, |
186 | { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH9_2, TCO_ICH9DH )}, | 188 | { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH9_2, TCO_ICH9DH)}, |
187 | { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH9_4, TCO_ICH9DO )}, | 189 | { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH9_4, TCO_ICH9DO)}, |
188 | { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ESB2_0, TCO_631XESB)}, | 190 | { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ESB2_0, TCO_631XESB)}, |
189 | { ITCO_PCI_DEVICE(0x2671, TCO_631XESB)}, | 191 | { ITCO_PCI_DEVICE(0x2671, TCO_631XESB)}, |
190 | { ITCO_PCI_DEVICE(0x2672, TCO_631XESB)}, | 192 | { ITCO_PCI_DEVICE(0x2672, TCO_631XESB)}, |
@@ -203,13 +205,15 @@ static struct pci_device_id iTCO_wdt_pci_tbl[] = { | |||
203 | { ITCO_PCI_DEVICE(0x267f, TCO_631XESB)}, | 205 | { ITCO_PCI_DEVICE(0x267f, TCO_631XESB)}, |
204 | { 0, }, /* End of list */ | 206 | { 0, }, /* End of list */ |
205 | }; | 207 | }; |
206 | MODULE_DEVICE_TABLE (pci, iTCO_wdt_pci_tbl); | 208 | MODULE_DEVICE_TABLE(pci, iTCO_wdt_pci_tbl); |
207 | 209 | ||
208 | /* Address definitions for the TCO */ | 210 | /* Address definitions for the TCO */ |
209 | #define TCOBASE iTCO_wdt_private.ACPIBASE + 0x60 /* TCO base address */ | 211 | /* TCO base address */ |
210 | #define SMI_EN iTCO_wdt_private.ACPIBASE + 0x30 /* SMI Control and Enable Register */ | 212 | #define TCOBASE iTCO_wdt_private.ACPIBASE + 0x60 |
213 | /* SMI Control and Enable Register */ | ||
214 | #define SMI_EN iTCO_wdt_private.ACPIBASE + 0x30 | ||
211 | 215 | ||
212 | #define TCO_RLD TCOBASE + 0x00 /* TCO Timer Reload and Current Value */ | 216 | #define TCO_RLD TCOBASE + 0x00 /* TCO Timer Reload and Curr. Value */ |
213 | #define TCOv1_TMR TCOBASE + 0x01 /* TCOv1 Timer Initial Value */ | 217 | #define TCOv1_TMR TCOBASE + 0x01 /* TCOv1 Timer Initial Value */ |
214 | #define TCO_DAT_IN TCOBASE + 0x02 /* TCO Data In Register */ | 218 | #define TCO_DAT_IN TCOBASE + 0x02 /* TCO Data In Register */ |
215 | #define TCO_DAT_OUT TCOBASE + 0x03 /* TCO Data Out Register */ | 219 | #define TCO_DAT_OUT TCOBASE + 0x03 /* TCO Data Out Register */ |
@@ -222,15 +226,21 @@ MODULE_DEVICE_TABLE (pci, iTCO_wdt_pci_tbl); | |||
222 | /* internal variables */ | 226 | /* internal variables */ |
223 | static unsigned long is_active; | 227 | static unsigned long is_active; |
224 | static char expect_release; | 228 | static char expect_release; |
225 | static struct { /* this is private data for the iTCO_wdt device */ | 229 | static struct { /* this is private data for the iTCO_wdt device */ |
226 | unsigned int iTCO_version; /* TCO version/generation */ | 230 | /* TCO version/generation */ |
227 | unsigned long ACPIBASE; /* The cards ACPIBASE address (TCOBASE = ACPIBASE+0x60) */ | 231 | unsigned int iTCO_version; |
228 | unsigned long __iomem *gcs; /* NO_REBOOT flag is Memory-Mapped GCS register bit 5 (TCO version 2) */ | 232 | /* The cards ACPIBASE address (TCOBASE = ACPIBASE+0x60) */ |
229 | spinlock_t io_lock; /* the lock for io operations */ | 233 | unsigned long ACPIBASE; |
230 | struct pci_dev *pdev; /* the PCI-device */ | 234 | /* NO_REBOOT flag is Memory-Mapped GCS register bit 5 (TCO version 2)*/ |
235 | unsigned long __iomem *gcs; | ||
236 | /* the lock for io operations */ | ||
237 | spinlock_t io_lock; | ||
238 | /* the PCI-device */ | ||
239 | struct pci_dev *pdev; | ||
231 | } iTCO_wdt_private; | 240 | } iTCO_wdt_private; |
232 | 241 | ||
233 | static struct platform_device *iTCO_wdt_platform_device; /* the watchdog platform device */ | 242 | /* the watchdog platform device */ |
243 | static struct platform_device *iTCO_wdt_platform_device; | ||
234 | 244 | ||
235 | /* module parameters */ | 245 | /* module parameters */ |
236 | #define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat */ | 246 | #define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat */ |
@@ -240,22 +250,9 @@ MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (2<heartbeat<39 (TCO | |||
240 | 250 | ||
241 | static int nowayout = WATCHDOG_NOWAYOUT; | 251 | static int nowayout = WATCHDOG_NOWAYOUT; |
242 | module_param(nowayout, int, 0); | 252 | module_param(nowayout, int, 0); |
243 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 253 | MODULE_PARM_DESC(nowayout, |
244 | 254 | "Watchdog cannot be stopped once started (default=" | |
245 | /* iTCO Vendor Specific Support hooks */ | 255 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); |
246 | #ifdef CONFIG_ITCO_VENDOR_SUPPORT | ||
247 | extern void iTCO_vendor_pre_start(unsigned long, unsigned int); | ||
248 | extern void iTCO_vendor_pre_stop(unsigned long); | ||
249 | extern void iTCO_vendor_pre_keepalive(unsigned long, unsigned int); | ||
250 | extern void iTCO_vendor_pre_set_heartbeat(unsigned int); | ||
251 | extern int iTCO_vendor_check_noreboot_on(void); | ||
252 | #else | ||
253 | #define iTCO_vendor_pre_start(acpibase, heartbeat) {} | ||
254 | #define iTCO_vendor_pre_stop(acpibase) {} | ||
255 | #define iTCO_vendor_pre_keepalive(acpibase,heartbeat) {} | ||
256 | #define iTCO_vendor_pre_set_heartbeat(heartbeat) {} | ||
257 | #define iTCO_vendor_check_noreboot_on() 1 /* 1=check noreboot; 0=don't check */ | ||
258 | #endif | ||
259 | 256 | ||
260 | /* | 257 | /* |
261 | * Some TCO specific functions | 258 | * Some TCO specific functions |
@@ -369,11 +366,10 @@ static int iTCO_wdt_keepalive(void) | |||
369 | iTCO_vendor_pre_keepalive(iTCO_wdt_private.ACPIBASE, heartbeat); | 366 | iTCO_vendor_pre_keepalive(iTCO_wdt_private.ACPIBASE, heartbeat); |
370 | 367 | ||
371 | /* Reload the timer by writing to the TCO Timer Counter register */ | 368 | /* Reload the timer by writing to the TCO Timer Counter register */ |
372 | if (iTCO_wdt_private.iTCO_version == 2) { | 369 | if (iTCO_wdt_private.iTCO_version == 2) |
373 | outw(0x01, TCO_RLD); | 370 | outw(0x01, TCO_RLD); |
374 | } else if (iTCO_wdt_private.iTCO_version == 1) { | 371 | else if (iTCO_wdt_private.iTCO_version == 1) |
375 | outb(0x01, TCO_RLD); | 372 | outb(0x01, TCO_RLD); |
376 | } | ||
377 | 373 | ||
378 | spin_unlock(&iTCO_wdt_private.io_lock); | 374 | spin_unlock(&iTCO_wdt_private.io_lock); |
379 | return 0; | 375 | return 0; |
@@ -425,7 +421,7 @@ static int iTCO_wdt_set_heartbeat(int t) | |||
425 | return 0; | 421 | return 0; |
426 | } | 422 | } |
427 | 423 | ||
428 | static int iTCO_wdt_get_timeleft (int *time_left) | 424 | static int iTCO_wdt_get_timeleft(int *time_left) |
429 | { | 425 | { |
430 | unsigned int val16; | 426 | unsigned int val16; |
431 | unsigned char val8; | 427 | unsigned char val8; |
@@ -454,7 +450,7 @@ static int iTCO_wdt_get_timeleft (int *time_left) | |||
454 | * /dev/watchdog handling | 450 | * /dev/watchdog handling |
455 | */ | 451 | */ |
456 | 452 | ||
457 | static int iTCO_wdt_open (struct inode *inode, struct file *file) | 453 | static int iTCO_wdt_open(struct inode *inode, struct file *file) |
458 | { | 454 | { |
459 | /* /dev/watchdog can only be opened once */ | 455 | /* /dev/watchdog can only be opened once */ |
460 | if (test_and_set_bit(0, &is_active)) | 456 | if (test_and_set_bit(0, &is_active)) |
@@ -468,7 +464,7 @@ static int iTCO_wdt_open (struct inode *inode, struct file *file) | |||
468 | return nonseekable_open(inode, file); | 464 | return nonseekable_open(inode, file); |
469 | } | 465 | } |
470 | 466 | ||
471 | static int iTCO_wdt_release (struct inode *inode, struct file *file) | 467 | static int iTCO_wdt_release(struct inode *inode, struct file *file) |
472 | { | 468 | { |
473 | /* | 469 | /* |
474 | * Shut off the timer. | 470 | * Shut off the timer. |
@@ -476,7 +472,8 @@ static int iTCO_wdt_release (struct inode *inode, struct file *file) | |||
476 | if (expect_release == 42) { | 472 | if (expect_release == 42) { |
477 | iTCO_wdt_stop(); | 473 | iTCO_wdt_stop(); |
478 | } else { | 474 | } else { |
479 | printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); | 475 | printk(KERN_CRIT PFX |
476 | "Unexpected close, not stopping watchdog!\n"); | ||
480 | iTCO_wdt_keepalive(); | 477 | iTCO_wdt_keepalive(); |
481 | } | 478 | } |
482 | clear_bit(0, &is_active); | 479 | clear_bit(0, &is_active); |
@@ -484,22 +481,23 @@ static int iTCO_wdt_release (struct inode *inode, struct file *file) | |||
484 | return 0; | 481 | return 0; |
485 | } | 482 | } |
486 | 483 | ||
487 | static ssize_t iTCO_wdt_write (struct file *file, const char __user *data, | 484 | static ssize_t iTCO_wdt_write(struct file *file, const char __user *data, |
488 | size_t len, loff_t * ppos) | 485 | size_t len, loff_t *ppos) |
489 | { | 486 | { |
490 | /* See if we got the magic character 'V' and reload the timer */ | 487 | /* See if we got the magic character 'V' and reload the timer */ |
491 | if (len) { | 488 | if (len) { |
492 | if (!nowayout) { | 489 | if (!nowayout) { |
493 | size_t i; | 490 | size_t i; |
494 | 491 | ||
495 | /* note: just in case someone wrote the magic character | 492 | /* note: just in case someone wrote the magic |
496 | * five months ago... */ | 493 | character five months ago... */ |
497 | expect_release = 0; | 494 | expect_release = 0; |
498 | 495 | ||
499 | /* scan to see whether or not we got the magic character */ | 496 | /* scan to see whether or not we got the |
497 | magic character */ | ||
500 | for (i = 0; i != len; i++) { | 498 | for (i = 0; i != len; i++) { |
501 | char c; | 499 | char c; |
502 | if (get_user(c, data+i)) | 500 | if (get_user(c, data + i)) |
503 | return -EFAULT; | 501 | return -EFAULT; |
504 | if (c == 'V') | 502 | if (c == 'V') |
505 | expect_release = 42; | 503 | expect_release = 42; |
@@ -512,8 +510,8 @@ static ssize_t iTCO_wdt_write (struct file *file, const char __user *data, | |||
512 | return len; | 510 | return len; |
513 | } | 511 | } |
514 | 512 | ||
515 | static int iTCO_wdt_ioctl (struct inode *inode, struct file *file, | 513 | static long iTCO_wdt_ioctl(struct file *file, unsigned int cmd, |
516 | unsigned int cmd, unsigned long arg) | 514 | unsigned long arg) |
517 | { | 515 | { |
518 | int new_options, retval = -EINVAL; | 516 | int new_options, retval = -EINVAL; |
519 | int new_heartbeat; | 517 | int new_heartbeat; |
@@ -528,64 +526,52 @@ static int iTCO_wdt_ioctl (struct inode *inode, struct file *file, | |||
528 | }; | 526 | }; |
529 | 527 | ||
530 | switch (cmd) { | 528 | switch (cmd) { |
531 | case WDIOC_GETSUPPORT: | 529 | case WDIOC_GETSUPPORT: |
532 | return copy_to_user(argp, &ident, | 530 | return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; |
533 | sizeof (ident)) ? -EFAULT : 0; | 531 | case WDIOC_GETSTATUS: |
534 | 532 | case WDIOC_GETBOOTSTATUS: | |
535 | case WDIOC_GETSTATUS: | 533 | return put_user(0, p); |
536 | case WDIOC_GETBOOTSTATUS: | 534 | |
537 | return put_user(0, p); | 535 | case WDIOC_SETOPTIONS: |
538 | 536 | { | |
539 | case WDIOC_KEEPALIVE: | 537 | if (get_user(new_options, p)) |
540 | iTCO_wdt_keepalive(); | 538 | return -EFAULT; |
541 | return 0; | 539 | |
542 | 540 | if (new_options & WDIOS_DISABLECARD) { | |
543 | case WDIOC_SETOPTIONS: | 541 | iTCO_wdt_stop(); |
544 | { | 542 | retval = 0; |
545 | if (get_user(new_options, p)) | ||
546 | return -EFAULT; | ||
547 | |||
548 | if (new_options & WDIOS_DISABLECARD) { | ||
549 | iTCO_wdt_stop(); | ||
550 | retval = 0; | ||
551 | } | ||
552 | |||
553 | if (new_options & WDIOS_ENABLECARD) { | ||
554 | iTCO_wdt_keepalive(); | ||
555 | iTCO_wdt_start(); | ||
556 | retval = 0; | ||
557 | } | ||
558 | |||
559 | return retval; | ||
560 | } | 543 | } |
561 | 544 | if (new_options & WDIOS_ENABLECARD) { | |
562 | case WDIOC_SETTIMEOUT: | ||
563 | { | ||
564 | if (get_user(new_heartbeat, p)) | ||
565 | return -EFAULT; | ||
566 | |||
567 | if (iTCO_wdt_set_heartbeat(new_heartbeat)) | ||
568 | return -EINVAL; | ||
569 | |||
570 | iTCO_wdt_keepalive(); | 545 | iTCO_wdt_keepalive(); |
571 | /* Fall */ | 546 | iTCO_wdt_start(); |
572 | } | 547 | retval = 0; |
573 | |||
574 | case WDIOC_GETTIMEOUT: | ||
575 | return put_user(heartbeat, p); | ||
576 | |||
577 | case WDIOC_GETTIMELEFT: | ||
578 | { | ||
579 | int time_left; | ||
580 | |||
581 | if (iTCO_wdt_get_timeleft(&time_left)) | ||
582 | return -EINVAL; | ||
583 | |||
584 | return put_user(time_left, p); | ||
585 | } | 548 | } |
549 | return retval; | ||
550 | } | ||
551 | case WDIOC_KEEPALIVE: | ||
552 | iTCO_wdt_keepalive(); | ||
553 | return 0; | ||
586 | 554 | ||
587 | default: | 555 | case WDIOC_SETTIMEOUT: |
588 | return -ENOTTY; | 556 | { |
557 | if (get_user(new_heartbeat, p)) | ||
558 | return -EFAULT; | ||
559 | if (iTCO_wdt_set_heartbeat(new_heartbeat)) | ||
560 | return -EINVAL; | ||
561 | iTCO_wdt_keepalive(); | ||
562 | /* Fall */ | ||
563 | } | ||
564 | case WDIOC_GETTIMEOUT: | ||
565 | return put_user(heartbeat, p); | ||
566 | case WDIOC_GETTIMELEFT: | ||
567 | { | ||
568 | int time_left; | ||
569 | if (iTCO_wdt_get_timeleft(&time_left)) | ||
570 | return -EINVAL; | ||
571 | return put_user(time_left, p); | ||
572 | } | ||
573 | default: | ||
574 | return -ENOTTY; | ||
589 | } | 575 | } |
590 | } | 576 | } |
591 | 577 | ||
@@ -594,12 +580,12 @@ static int iTCO_wdt_ioctl (struct inode *inode, struct file *file, | |||
594 | */ | 580 | */ |
595 | 581 | ||
596 | static const struct file_operations iTCO_wdt_fops = { | 582 | static const struct file_operations iTCO_wdt_fops = { |
597 | .owner = THIS_MODULE, | 583 | .owner = THIS_MODULE, |
598 | .llseek = no_llseek, | 584 | .llseek = no_llseek, |
599 | .write = iTCO_wdt_write, | 585 | .write = iTCO_wdt_write, |
600 | .ioctl = iTCO_wdt_ioctl, | 586 | .unlocked_ioctl = iTCO_wdt_ioctl, |
601 | .open = iTCO_wdt_open, | 587 | .open = iTCO_wdt_open, |
602 | .release = iTCO_wdt_release, | 588 | .release = iTCO_wdt_release, |
603 | }; | 589 | }; |
604 | 590 | ||
605 | static struct miscdevice iTCO_wdt_miscdev = { | 591 | static struct miscdevice iTCO_wdt_miscdev = { |
@@ -612,7 +598,8 @@ static struct miscdevice iTCO_wdt_miscdev = { | |||
612 | * Init & exit routines | 598 | * Init & exit routines |
613 | */ | 599 | */ |
614 | 600 | ||
615 | static int __devinit iTCO_wdt_init(struct pci_dev *pdev, const struct pci_device_id *ent, struct platform_device *dev) | 601 | static int __devinit iTCO_wdt_init(struct pci_dev *pdev, |
602 | const struct pci_device_id *ent, struct platform_device *dev) | ||
616 | { | 603 | { |
617 | int ret; | 604 | int ret; |
618 | u32 base_address; | 605 | u32 base_address; |
@@ -632,17 +619,19 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev, const struct pci_device | |||
632 | pci_dev_put(pdev); | 619 | pci_dev_put(pdev); |
633 | return -ENODEV; | 620 | return -ENODEV; |
634 | } | 621 | } |
635 | iTCO_wdt_private.iTCO_version = iTCO_chipset_info[ent->driver_data].iTCO_version; | 622 | iTCO_wdt_private.iTCO_version = |
623 | iTCO_chipset_info[ent->driver_data].iTCO_version; | ||
636 | iTCO_wdt_private.ACPIBASE = base_address; | 624 | iTCO_wdt_private.ACPIBASE = base_address; |
637 | iTCO_wdt_private.pdev = pdev; | 625 | iTCO_wdt_private.pdev = pdev; |
638 | 626 | ||
639 | /* Get the Memory-Mapped GCS register, we need it for the NO_REBOOT flag (TCO v2) */ | 627 | /* Get the Memory-Mapped GCS register, we need it for the |
640 | /* To get access to it you have to read RCBA from PCI Config space 0xf0 | 628 | NO_REBOOT flag (TCO v2). To get access to it you have to |
641 | and use it as base. GCS = RCBA + ICH6_GCS(0x3410). */ | 629 | read RCBA from PCI Config space 0xf0 and use it as base. |
630 | GCS = RCBA + ICH6_GCS(0x3410). */ | ||
642 | if (iTCO_wdt_private.iTCO_version == 2) { | 631 | if (iTCO_wdt_private.iTCO_version == 2) { |
643 | pci_read_config_dword(pdev, 0xf0, &base_address); | 632 | pci_read_config_dword(pdev, 0xf0, &base_address); |
644 | RCBA = base_address & 0xffffc000; | 633 | RCBA = base_address & 0xffffc000; |
645 | iTCO_wdt_private.gcs = ioremap((RCBA + 0x3410),4); | 634 | iTCO_wdt_private.gcs = ioremap((RCBA + 0x3410), 4); |
646 | } | 635 | } |
647 | 636 | ||
648 | /* Check chipset's NO_REBOOT bit */ | 637 | /* Check chipset's NO_REBOOT bit */ |
@@ -657,8 +646,8 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev, const struct pci_device | |||
657 | 646 | ||
658 | /* Set the TCO_EN bit in SMI_EN register */ | 647 | /* Set the TCO_EN bit in SMI_EN register */ |
659 | if (!request_region(SMI_EN, 4, "iTCO_wdt")) { | 648 | if (!request_region(SMI_EN, 4, "iTCO_wdt")) { |
660 | printk(KERN_ERR PFX "I/O address 0x%04lx already in use\n", | 649 | printk(KERN_ERR PFX |
661 | SMI_EN ); | 650 | "I/O address 0x%04lx already in use\n", SMI_EN); |
662 | ret = -EIO; | 651 | ret = -EIO; |
663 | goto out; | 652 | goto out; |
664 | } | 653 | } |
@@ -667,18 +656,20 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev, const struct pci_device | |||
667 | outl(val32, SMI_EN); | 656 | outl(val32, SMI_EN); |
668 | release_region(SMI_EN, 4); | 657 | release_region(SMI_EN, 4); |
669 | 658 | ||
670 | /* The TCO I/O registers reside in a 32-byte range pointed to by the TCOBASE value */ | 659 | /* The TCO I/O registers reside in a 32-byte range pointed to |
671 | if (!request_region (TCOBASE, 0x20, "iTCO_wdt")) { | 660 | by the TCOBASE value */ |
672 | printk (KERN_ERR PFX "I/O address 0x%04lx already in use\n", | 661 | if (!request_region(TCOBASE, 0x20, "iTCO_wdt")) { |
662 | printk(KERN_ERR PFX "I/O address 0x%04lx already in use\n", | ||
673 | TCOBASE); | 663 | TCOBASE); |
674 | ret = -EIO; | 664 | ret = -EIO; |
675 | goto out; | 665 | goto out; |
676 | } | 666 | } |
677 | 667 | ||
678 | printk(KERN_INFO PFX "Found a %s TCO device (Version=%d, TCOBASE=0x%04lx)\n", | 668 | printk(KERN_INFO PFX |
679 | iTCO_chipset_info[ent->driver_data].name, | 669 | "Found a %s TCO device (Version=%d, TCOBASE=0x%04lx)\n", |
680 | iTCO_chipset_info[ent->driver_data].iTCO_version, | 670 | iTCO_chipset_info[ent->driver_data].name, |
681 | TCOBASE); | 671 | iTCO_chipset_info[ent->driver_data].iTCO_version, |
672 | TCOBASE); | ||
682 | 673 | ||
683 | /* Clear out the (probably old) status */ | 674 | /* Clear out the (probably old) status */ |
684 | outb(0, TCO1_STS); | 675 | outb(0, TCO1_STS); |
@@ -687,27 +678,29 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev, const struct pci_device | |||
687 | /* Make sure the watchdog is not running */ | 678 | /* Make sure the watchdog is not running */ |
688 | iTCO_wdt_stop(); | 679 | iTCO_wdt_stop(); |
689 | 680 | ||
690 | /* Check that the heartbeat value is within it's range ; if not reset to the default */ | 681 | /* Check that the heartbeat value is within it's range; |
682 | if not reset to the default */ | ||
691 | if (iTCO_wdt_set_heartbeat(heartbeat)) { | 683 | if (iTCO_wdt_set_heartbeat(heartbeat)) { |
692 | iTCO_wdt_set_heartbeat(WATCHDOG_HEARTBEAT); | 684 | iTCO_wdt_set_heartbeat(WATCHDOG_HEARTBEAT); |
693 | printk(KERN_INFO PFX "heartbeat value must be 2<heartbeat<39 (TCO v1) or 613 (TCO v2), using %d\n", | 685 | printk(KERN_INFO PFX "heartbeat value must be 2 < heartbeat < 39 (TCO v1) or 613 (TCO v2), using %d\n", |
694 | heartbeat); | 686 | heartbeat); |
695 | } | 687 | } |
696 | 688 | ||
697 | ret = misc_register(&iTCO_wdt_miscdev); | 689 | ret = misc_register(&iTCO_wdt_miscdev); |
698 | if (ret != 0) { | 690 | if (ret != 0) { |
699 | printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", | 691 | printk(KERN_ERR PFX |
700 | WATCHDOG_MINOR, ret); | 692 | "cannot register miscdev on minor=%d (err=%d)\n", |
693 | WATCHDOG_MINOR, ret); | ||
701 | goto unreg_region; | 694 | goto unreg_region; |
702 | } | 695 | } |
703 | 696 | ||
704 | printk (KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n", | 697 | printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n", |
705 | heartbeat, nowayout); | 698 | heartbeat, nowayout); |
706 | 699 | ||
707 | return 0; | 700 | return 0; |
708 | 701 | ||
709 | unreg_region: | 702 | unreg_region: |
710 | release_region (TCOBASE, 0x20); | 703 | release_region(TCOBASE, 0x20); |
711 | out: | 704 | out: |
712 | if (iTCO_wdt_private.iTCO_version == 2) | 705 | if (iTCO_wdt_private.iTCO_version == 2) |
713 | iounmap(iTCO_wdt_private.gcs); | 706 | iounmap(iTCO_wdt_private.gcs); |
@@ -796,7 +789,8 @@ static int __init iTCO_wdt_init_module(void) | |||
796 | if (err) | 789 | if (err) |
797 | return err; | 790 | return err; |
798 | 791 | ||
799 | iTCO_wdt_platform_device = platform_device_register_simple(DRV_NAME, -1, NULL, 0); | 792 | iTCO_wdt_platform_device = platform_device_register_simple(DRV_NAME, |
793 | -1, NULL, 0); | ||
800 | if (IS_ERR(iTCO_wdt_platform_device)) { | 794 | if (IS_ERR(iTCO_wdt_platform_device)) { |
801 | err = PTR_ERR(iTCO_wdt_platform_device); | 795 | err = PTR_ERR(iTCO_wdt_platform_device); |
802 | goto unreg_platform_driver; | 796 | goto unreg_platform_driver; |
diff --git a/drivers/watchdog/ib700wdt.c b/drivers/watchdog/ib700wdt.c index 4b89f401691a..05a28106e8eb 100644 --- a/drivers/watchdog/ib700wdt.c +++ b/drivers/watchdog/ib700wdt.c | |||
@@ -41,9 +41,9 @@ | |||
41 | #include <linux/spinlock.h> | 41 | #include <linux/spinlock.h> |
42 | #include <linux/moduleparam.h> | 42 | #include <linux/moduleparam.h> |
43 | #include <linux/platform_device.h> | 43 | #include <linux/platform_device.h> |
44 | #include <linux/io.h> | ||
45 | #include <linux/uaccess.h> | ||
44 | 46 | ||
45 | #include <asm/io.h> | ||
46 | #include <asm/uaccess.h> | ||
47 | #include <asm/system.h> | 47 | #include <asm/system.h> |
48 | 48 | ||
49 | static struct platform_device *ibwdt_platform_device; | 49 | static struct platform_device *ibwdt_platform_device; |
@@ -120,15 +120,16 @@ static int wd_margin = WD_TIMO; | |||
120 | 120 | ||
121 | static int nowayout = WATCHDOG_NOWAYOUT; | 121 | static int nowayout = WATCHDOG_NOWAYOUT; |
122 | module_param(nowayout, int, 0); | 122 | module_param(nowayout, int, 0); |
123 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 123 | MODULE_PARM_DESC(nowayout, |
124 | "Watchdog cannot be stopped once started (default=" | ||
125 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
124 | 126 | ||
125 | 127 | ||
126 | /* | 128 | /* |
127 | * Watchdog Operations | 129 | * Watchdog Operations |
128 | */ | 130 | */ |
129 | 131 | ||
130 | static void | 132 | static void ibwdt_ping(void) |
131 | ibwdt_ping(void) | ||
132 | { | 133 | { |
133 | spin_lock(&ibwdt_lock); | 134 | spin_lock(&ibwdt_lock); |
134 | 135 | ||
@@ -138,16 +139,14 @@ ibwdt_ping(void) | |||
138 | spin_unlock(&ibwdt_lock); | 139 | spin_unlock(&ibwdt_lock); |
139 | } | 140 | } |
140 | 141 | ||
141 | static void | 142 | static void ibwdt_disable(void) |
142 | ibwdt_disable(void) | ||
143 | { | 143 | { |
144 | spin_lock(&ibwdt_lock); | 144 | spin_lock(&ibwdt_lock); |
145 | outb_p(0, WDT_STOP); | 145 | outb_p(0, WDT_STOP); |
146 | spin_unlock(&ibwdt_lock); | 146 | spin_unlock(&ibwdt_lock); |
147 | } | 147 | } |
148 | 148 | ||
149 | static int | 149 | static int ibwdt_set_heartbeat(int t) |
150 | ibwdt_set_heartbeat(int t) | ||
151 | { | 150 | { |
152 | int i; | 151 | int i; |
153 | 152 | ||
@@ -165,8 +164,8 @@ ibwdt_set_heartbeat(int t) | |||
165 | * /dev/watchdog handling | 164 | * /dev/watchdog handling |
166 | */ | 165 | */ |
167 | 166 | ||
168 | static ssize_t | 167 | static ssize_t ibwdt_write(struct file *file, const char __user *buf, |
169 | ibwdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) | 168 | size_t count, loff_t *ppos) |
170 | { | 169 | { |
171 | if (count) { | 170 | if (count) { |
172 | if (!nowayout) { | 171 | if (!nowayout) { |
@@ -188,77 +187,71 @@ ibwdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppo | |||
188 | return count; | 187 | return count; |
189 | } | 188 | } |
190 | 189 | ||
191 | static int | 190 | static long ibwdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
192 | ibwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | ||
193 | unsigned long arg) | ||
194 | { | 191 | { |
195 | int new_margin; | 192 | int new_margin; |
196 | void __user *argp = (void __user *)arg; | 193 | void __user *argp = (void __user *)arg; |
197 | int __user *p = argp; | 194 | int __user *p = argp; |
198 | 195 | ||
199 | static struct watchdog_info ident = { | 196 | static struct watchdog_info ident = { |
200 | .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, | 197 | .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
198 | | WDIOF_MAGICCLOSE, | ||
201 | .firmware_version = 1, | 199 | .firmware_version = 1, |
202 | .identity = "IB700 WDT", | 200 | .identity = "IB700 WDT", |
203 | }; | 201 | }; |
204 | 202 | ||
205 | switch (cmd) { | 203 | switch (cmd) { |
206 | case WDIOC_GETSUPPORT: | 204 | case WDIOC_GETSUPPORT: |
207 | if (copy_to_user(argp, &ident, sizeof(ident))) | 205 | if (copy_to_user(argp, &ident, sizeof(ident))) |
208 | return -EFAULT; | 206 | return -EFAULT; |
209 | break; | 207 | break; |
210 | 208 | ||
211 | case WDIOC_GETSTATUS: | 209 | case WDIOC_GETSTATUS: |
212 | case WDIOC_GETBOOTSTATUS: | 210 | case WDIOC_GETBOOTSTATUS: |
213 | return put_user(0, p); | 211 | return put_user(0, p); |
214 | |||
215 | case WDIOC_KEEPALIVE: | ||
216 | ibwdt_ping(); | ||
217 | break; | ||
218 | |||
219 | case WDIOC_SETTIMEOUT: | ||
220 | if (get_user(new_margin, p)) | ||
221 | return -EFAULT; | ||
222 | if (ibwdt_set_heartbeat(new_margin)) | ||
223 | return -EINVAL; | ||
224 | ibwdt_ping(); | ||
225 | /* Fall */ | ||
226 | |||
227 | case WDIOC_GETTIMEOUT: | ||
228 | return put_user(wd_times[wd_margin], p); | ||
229 | 212 | ||
230 | case WDIOC_SETOPTIONS: | 213 | case WDIOC_SETOPTIONS: |
231 | { | 214 | { |
232 | int options, retval = -EINVAL; | 215 | int options, retval = -EINVAL; |
233 | 216 | ||
234 | if (get_user(options, p)) | 217 | if (get_user(options, p)) |
235 | return -EFAULT; | 218 | return -EFAULT; |
236 | 219 | ||
237 | if (options & WDIOS_DISABLECARD) { | 220 | if (options & WDIOS_DISABLECARD) { |
238 | ibwdt_disable(); | 221 | ibwdt_disable(); |
239 | retval = 0; | 222 | retval = 0; |
240 | } | 223 | } |
224 | if (options & WDIOS_ENABLECARD) { | ||
225 | ibwdt_ping(); | ||
226 | retval = 0; | ||
227 | } | ||
228 | return retval; | ||
229 | } | ||
230 | case WDIOC_KEEPALIVE: | ||
231 | ibwdt_ping(); | ||
232 | break; | ||
241 | 233 | ||
242 | if (options & WDIOS_ENABLECARD) { | 234 | case WDIOC_SETTIMEOUT: |
243 | ibwdt_ping(); | 235 | if (get_user(new_margin, p)) |
244 | retval = 0; | 236 | return -EFAULT; |
245 | } | 237 | if (ibwdt_set_heartbeat(new_margin)) |
238 | return -EINVAL; | ||
239 | ibwdt_ping(); | ||
240 | /* Fall */ | ||
246 | 241 | ||
247 | return retval; | 242 | case WDIOC_GETTIMEOUT: |
248 | } | 243 | return put_user(wd_times[wd_margin], p); |
249 | 244 | ||
250 | default: | 245 | default: |
251 | return -ENOTTY; | 246 | return -ENOTTY; |
252 | } | 247 | } |
253 | return 0; | 248 | return 0; |
254 | } | 249 | } |
255 | 250 | ||
256 | static int | 251 | static int ibwdt_open(struct inode *inode, struct file *file) |
257 | ibwdt_open(struct inode *inode, struct file *file) | ||
258 | { | 252 | { |
259 | if (test_and_set_bit(0, &ibwdt_is_open)) { | 253 | if (test_and_set_bit(0, &ibwdt_is_open)) |
260 | return -EBUSY; | 254 | return -EBUSY; |
261 | } | ||
262 | if (nowayout) | 255 | if (nowayout) |
263 | __module_get(THIS_MODULE); | 256 | __module_get(THIS_MODULE); |
264 | 257 | ||
@@ -267,13 +260,13 @@ ibwdt_open(struct inode *inode, struct file *file) | |||
267 | return nonseekable_open(inode, file); | 260 | return nonseekable_open(inode, file); |
268 | } | 261 | } |
269 | 262 | ||
270 | static int | 263 | static int ibwdt_close(struct inode *inode, struct file *file) |
271 | ibwdt_close(struct inode *inode, struct file *file) | ||
272 | { | 264 | { |
273 | if (expect_close == 42) { | 265 | if (expect_close == 42) { |
274 | ibwdt_disable(); | 266 | ibwdt_disable(); |
275 | } else { | 267 | } else { |
276 | printk(KERN_CRIT PFX "WDT device closed unexpectedly. WDT will not stop!\n"); | 268 | printk(KERN_CRIT PFX |
269 | "WDT device closed unexpectedly. WDT will not stop!\n"); | ||
277 | ibwdt_ping(); | 270 | ibwdt_ping(); |
278 | } | 271 | } |
279 | clear_bit(0, &ibwdt_is_open); | 272 | clear_bit(0, &ibwdt_is_open); |
@@ -289,7 +282,7 @@ static const struct file_operations ibwdt_fops = { | |||
289 | .owner = THIS_MODULE, | 282 | .owner = THIS_MODULE, |
290 | .llseek = no_llseek, | 283 | .llseek = no_llseek, |
291 | .write = ibwdt_write, | 284 | .write = ibwdt_write, |
292 | .ioctl = ibwdt_ioctl, | 285 | .unlocked_ioctl = ibwdt_ioctl, |
293 | .open = ibwdt_open, | 286 | .open = ibwdt_open, |
294 | .release = ibwdt_close, | 287 | .release = ibwdt_close, |
295 | }; | 288 | }; |
@@ -310,21 +303,23 @@ static int __devinit ibwdt_probe(struct platform_device *dev) | |||
310 | 303 | ||
311 | #if WDT_START != WDT_STOP | 304 | #if WDT_START != WDT_STOP |
312 | if (!request_region(WDT_STOP, 1, "IB700 WDT")) { | 305 | if (!request_region(WDT_STOP, 1, "IB700 WDT")) { |
313 | printk (KERN_ERR PFX "STOP method I/O %X is not available.\n", WDT_STOP); | 306 | printk(KERN_ERR PFX "STOP method I/O %X is not available.\n", |
307 | WDT_STOP); | ||
314 | res = -EIO; | 308 | res = -EIO; |
315 | goto out_nostopreg; | 309 | goto out_nostopreg; |
316 | } | 310 | } |
317 | #endif | 311 | #endif |
318 | 312 | ||
319 | if (!request_region(WDT_START, 1, "IB700 WDT")) { | 313 | if (!request_region(WDT_START, 1, "IB700 WDT")) { |
320 | printk (KERN_ERR PFX "START method I/O %X is not available.\n", WDT_START); | 314 | printk(KERN_ERR PFX "START method I/O %X is not available.\n", |
315 | WDT_START); | ||
321 | res = -EIO; | 316 | res = -EIO; |
322 | goto out_nostartreg; | 317 | goto out_nostartreg; |
323 | } | 318 | } |
324 | 319 | ||
325 | res = misc_register(&ibwdt_miscdev); | 320 | res = misc_register(&ibwdt_miscdev); |
326 | if (res) { | 321 | if (res) { |
327 | printk (KERN_ERR PFX "failed to register misc device\n"); | 322 | printk(KERN_ERR PFX "failed to register misc device\n"); |
328 | goto out_nomisc; | 323 | goto out_nomisc; |
329 | } | 324 | } |
330 | return 0; | 325 | return 0; |
@@ -342,9 +337,9 @@ out_nostopreg: | |||
342 | static int __devexit ibwdt_remove(struct platform_device *dev) | 337 | static int __devexit ibwdt_remove(struct platform_device *dev) |
343 | { | 338 | { |
344 | misc_deregister(&ibwdt_miscdev); | 339 | misc_deregister(&ibwdt_miscdev); |
345 | release_region(WDT_START,1); | 340 | release_region(WDT_START, 1); |
346 | #if WDT_START != WDT_STOP | 341 | #if WDT_START != WDT_STOP |
347 | release_region(WDT_STOP,1); | 342 | release_region(WDT_STOP, 1); |
348 | #endif | 343 | #endif |
349 | return 0; | 344 | return 0; |
350 | } | 345 | } |
@@ -369,13 +364,15 @@ static int __init ibwdt_init(void) | |||
369 | { | 364 | { |
370 | int err; | 365 | int err; |
371 | 366 | ||
372 | printk(KERN_INFO PFX "WDT driver for IB700 single board computer initialising.\n"); | 367 | printk(KERN_INFO PFX |
368 | "WDT driver for IB700 single board computer initialising.\n"); | ||
373 | 369 | ||
374 | err = platform_driver_register(&ibwdt_driver); | 370 | err = platform_driver_register(&ibwdt_driver); |
375 | if (err) | 371 | if (err) |
376 | return err; | 372 | return err; |
377 | 373 | ||
378 | ibwdt_platform_device = platform_device_register_simple(DRV_NAME, -1, NULL, 0); | 374 | ibwdt_platform_device = platform_device_register_simple(DRV_NAME, |
375 | -1, NULL, 0); | ||
379 | if (IS_ERR(ibwdt_platform_device)) { | 376 | if (IS_ERR(ibwdt_platform_device)) { |
380 | err = PTR_ERR(ibwdt_platform_device); | 377 | err = PTR_ERR(ibwdt_platform_device); |
381 | goto unreg_platform_driver; | 378 | goto unreg_platform_driver; |
diff --git a/drivers/watchdog/ibmasr.c b/drivers/watchdog/ibmasr.c index 94155f6136c2..b82405cfb4cd 100644 --- a/drivers/watchdog/ibmasr.c +++ b/drivers/watchdog/ibmasr.c | |||
@@ -19,9 +19,8 @@ | |||
19 | #include <linux/miscdevice.h> | 19 | #include <linux/miscdevice.h> |
20 | #include <linux/watchdog.h> | 20 | #include <linux/watchdog.h> |
21 | #include <linux/dmi.h> | 21 | #include <linux/dmi.h> |
22 | 22 | #include <linux/io.h> | |
23 | #include <asm/io.h> | 23 | #include <linux/uaccess.h> |
24 | #include <asm/uaccess.h> | ||
25 | 24 | ||
26 | 25 | ||
27 | enum { | 26 | enum { |
@@ -70,10 +69,13 @@ static char asr_expect_close; | |||
70 | static unsigned int asr_type, asr_base, asr_length; | 69 | static unsigned int asr_type, asr_base, asr_length; |
71 | static unsigned int asr_read_addr, asr_write_addr; | 70 | static unsigned int asr_read_addr, asr_write_addr; |
72 | static unsigned char asr_toggle_mask, asr_disable_mask; | 71 | static unsigned char asr_toggle_mask, asr_disable_mask; |
72 | static spinlock_t asr_lock; | ||
73 | 73 | ||
74 | static void asr_toggle(void) | 74 | static void __asr_toggle(void) |
75 | { | 75 | { |
76 | unsigned char reg = inb(asr_read_addr); | 76 | unsigned char reg; |
77 | |||
78 | reg = inb(asr_read_addr); | ||
77 | 79 | ||
78 | outb(reg & ~asr_toggle_mask, asr_write_addr); | 80 | outb(reg & ~asr_toggle_mask, asr_write_addr); |
79 | reg = inb(asr_read_addr); | 81 | reg = inb(asr_read_addr); |
@@ -83,12 +85,21 @@ static void asr_toggle(void) | |||
83 | 85 | ||
84 | outb(reg & ~asr_toggle_mask, asr_write_addr); | 86 | outb(reg & ~asr_toggle_mask, asr_write_addr); |
85 | reg = inb(asr_read_addr); | 87 | reg = inb(asr_read_addr); |
88 | spin_unlock(&asr_lock); | ||
89 | } | ||
90 | |||
91 | static void asr_toggle(void) | ||
92 | { | ||
93 | spin_lock(&asr_lock); | ||
94 | __asr_toggle(); | ||
95 | spin_unlock(&asr_lock); | ||
86 | } | 96 | } |
87 | 97 | ||
88 | static void asr_enable(void) | 98 | static void asr_enable(void) |
89 | { | 99 | { |
90 | unsigned char reg; | 100 | unsigned char reg; |
91 | 101 | ||
102 | spin_lock(&asr_lock); | ||
92 | if (asr_type == ASMTYPE_TOPAZ) { | 103 | if (asr_type == ASMTYPE_TOPAZ) { |
93 | /* asr_write_addr == asr_read_addr */ | 104 | /* asr_write_addr == asr_read_addr */ |
94 | reg = inb(asr_read_addr); | 105 | reg = inb(asr_read_addr); |
@@ -99,17 +110,21 @@ static void asr_enable(void) | |||
99 | * First make sure the hardware timer is reset by toggling | 110 | * First make sure the hardware timer is reset by toggling |
100 | * ASR hardware timer line. | 111 | * ASR hardware timer line. |
101 | */ | 112 | */ |
102 | asr_toggle(); | 113 | __asr_toggle(); |
103 | 114 | ||
104 | reg = inb(asr_read_addr); | 115 | reg = inb(asr_read_addr); |
105 | outb(reg & ~asr_disable_mask, asr_write_addr); | 116 | outb(reg & ~asr_disable_mask, asr_write_addr); |
106 | } | 117 | } |
107 | reg = inb(asr_read_addr); | 118 | reg = inb(asr_read_addr); |
119 | spin_unlock(&asr_lock); | ||
108 | } | 120 | } |
109 | 121 | ||
110 | static void asr_disable(void) | 122 | static void asr_disable(void) |
111 | { | 123 | { |
112 | unsigned char reg = inb(asr_read_addr); | 124 | unsigned char reg; |
125 | |||
126 | spin_lock(&asr_lock); | ||
127 | reg = inb(asr_read_addr); | ||
113 | 128 | ||
114 | if (asr_type == ASMTYPE_TOPAZ) | 129 | if (asr_type == ASMTYPE_TOPAZ) |
115 | /* asr_write_addr == asr_read_addr */ | 130 | /* asr_write_addr == asr_read_addr */ |
@@ -122,6 +137,7 @@ static void asr_disable(void) | |||
122 | outb(reg | asr_disable_mask, asr_write_addr); | 137 | outb(reg | asr_disable_mask, asr_write_addr); |
123 | } | 138 | } |
124 | reg = inb(asr_read_addr); | 139 | reg = inb(asr_read_addr); |
140 | spin_unlock(&asr_lock); | ||
125 | } | 141 | } |
126 | 142 | ||
127 | static int __init asr_get_base_address(void) | 143 | static int __init asr_get_base_address(void) |
@@ -133,7 +149,8 @@ static int __init asr_get_base_address(void) | |||
133 | 149 | ||
134 | switch (asr_type) { | 150 | switch (asr_type) { |
135 | case ASMTYPE_TOPAZ: | 151 | case ASMTYPE_TOPAZ: |
136 | /* SELECT SuperIO CHIP FOR QUERYING (WRITE 0x07 TO BOTH 0x2E and 0x2F) */ | 152 | /* SELECT SuperIO CHIP FOR QUERYING |
153 | (WRITE 0x07 TO BOTH 0x2E and 0x2F) */ | ||
137 | outb(0x07, 0x2e); | 154 | outb(0x07, 0x2e); |
138 | outb(0x07, 0x2f); | 155 | outb(0x07, 0x2f); |
139 | 156 | ||
@@ -154,14 +171,26 @@ static int __init asr_get_base_address(void) | |||
154 | 171 | ||
155 | case ASMTYPE_JASPER: | 172 | case ASMTYPE_JASPER: |
156 | type = "Jaspers "; | 173 | type = "Jaspers "; |
157 | 174 | #if 0 | |
158 | /* FIXME: need to use pci_config_lock here, but it's not exported */ | 175 | u32 r; |
176 | /* Suggested fix */ | ||
177 | pdev = pci_get_bus_and_slot(0, DEVFN(0x1f, 0)); | ||
178 | if (pdev == NULL) | ||
179 | return -ENODEV; | ||
180 | pci_read_config_dword(pdev, 0x58, &r); | ||
181 | asr_base = r & 0xFFFE; | ||
182 | pci_dev_put(pdev); | ||
183 | #else | ||
184 | /* FIXME: need to use pci_config_lock here, | ||
185 | but it's not exported */ | ||
159 | 186 | ||
160 | /* spin_lock_irqsave(&pci_config_lock, flags);*/ | 187 | /* spin_lock_irqsave(&pci_config_lock, flags);*/ |
161 | 188 | ||
162 | /* Select the SuperIO chip in the PCI I/O port register */ | 189 | /* Select the SuperIO chip in the PCI I/O port register */ |
163 | outl(0x8000f858, 0xcf8); | 190 | outl(0x8000f858, 0xcf8); |
164 | 191 | ||
192 | /* BUS 0, Slot 1F, fnc 0, offset 58 */ | ||
193 | |||
165 | /* | 194 | /* |
166 | * Read the base address for the SuperIO chip. | 195 | * Read the base address for the SuperIO chip. |
167 | * Only the lower 16 bits are valid, but the address is word | 196 | * Only the lower 16 bits are valid, but the address is word |
@@ -170,7 +199,7 @@ static int __init asr_get_base_address(void) | |||
170 | asr_base = inl(0xcfc) & 0xfffe; | 199 | asr_base = inl(0xcfc) & 0xfffe; |
171 | 200 | ||
172 | /* spin_unlock_irqrestore(&pci_config_lock, flags);*/ | 201 | /* spin_unlock_irqrestore(&pci_config_lock, flags);*/ |
173 | 202 | #endif | |
174 | asr_read_addr = asr_write_addr = | 203 | asr_read_addr = asr_write_addr = |
175 | asr_base + JASPER_ASR_REG_OFFSET; | 204 | asr_base + JASPER_ASR_REG_OFFSET; |
176 | asr_toggle_mask = JASPER_ASR_TOGGLE_MASK; | 205 | asr_toggle_mask = JASPER_ASR_TOGGLE_MASK; |
@@ -241,66 +270,57 @@ static ssize_t asr_write(struct file *file, const char __user *buf, | |||
241 | return count; | 270 | return count; |
242 | } | 271 | } |
243 | 272 | ||
244 | static int asr_ioctl(struct inode *inode, struct file *file, | 273 | static long asr_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
245 | unsigned int cmd, unsigned long arg) | ||
246 | { | 274 | { |
247 | static const struct watchdog_info ident = { | 275 | static const struct watchdog_info ident = { |
248 | .options = WDIOF_KEEPALIVEPING | | 276 | .options = WDIOF_KEEPALIVEPING | |
249 | WDIOF_MAGICCLOSE, | 277 | WDIOF_MAGICCLOSE, |
250 | .identity = "IBM ASR" | 278 | .identity = "IBM ASR", |
251 | }; | 279 | }; |
252 | void __user *argp = (void __user *)arg; | 280 | void __user *argp = (void __user *)arg; |
253 | int __user *p = argp; | 281 | int __user *p = argp; |
254 | int heartbeat; | 282 | int heartbeat; |
255 | 283 | ||
256 | switch (cmd) { | 284 | switch (cmd) { |
257 | case WDIOC_GETSUPPORT: | 285 | case WDIOC_GETSUPPORT: |
258 | return copy_to_user(argp, &ident, sizeof(ident)) ? | 286 | return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; |
259 | -EFAULT : 0; | 287 | case WDIOC_GETSTATUS: |
260 | 288 | case WDIOC_GETBOOTSTATUS: | |
261 | case WDIOC_GETSTATUS: | 289 | return put_user(0, p); |
262 | case WDIOC_GETBOOTSTATUS: | 290 | case WDIOC_SETOPTIONS: |
263 | return put_user(0, p); | 291 | { |
264 | 292 | int new_options, retval = -EINVAL; | |
265 | case WDIOC_KEEPALIVE: | 293 | if (get_user(new_options, p)) |
294 | return -EFAULT; | ||
295 | if (new_options & WDIOS_DISABLECARD) { | ||
296 | asr_disable(); | ||
297 | retval = 0; | ||
298 | } | ||
299 | if (new_options & WDIOS_ENABLECARD) { | ||
300 | asr_enable(); | ||
266 | asr_toggle(); | 301 | asr_toggle(); |
267 | return 0; | 302 | retval = 0; |
268 | |||
269 | /* | ||
270 | * The hardware has a fixed timeout value, so no WDIOC_SETTIMEOUT | ||
271 | * and WDIOC_GETTIMEOUT always returns 256. | ||
272 | */ | ||
273 | case WDIOC_GETTIMEOUT: | ||
274 | heartbeat = 256; | ||
275 | return put_user(heartbeat, p); | ||
276 | |||
277 | case WDIOC_SETOPTIONS: { | ||
278 | int new_options, retval = -EINVAL; | ||
279 | |||
280 | if (get_user(new_options, p)) | ||
281 | return -EFAULT; | ||
282 | |||
283 | if (new_options & WDIOS_DISABLECARD) { | ||
284 | asr_disable(); | ||
285 | retval = 0; | ||
286 | } | ||
287 | |||
288 | if (new_options & WDIOS_ENABLECARD) { | ||
289 | asr_enable(); | ||
290 | asr_toggle(); | ||
291 | retval = 0; | ||
292 | } | ||
293 | |||
294 | return retval; | ||
295 | } | 303 | } |
304 | return retval; | ||
305 | } | ||
306 | case WDIOC_KEEPALIVE: | ||
307 | asr_toggle(); | ||
308 | return 0; | ||
309 | /* | ||
310 | * The hardware has a fixed timeout value, so no WDIOC_SETTIMEOUT | ||
311 | * and WDIOC_GETTIMEOUT always returns 256. | ||
312 | */ | ||
313 | case WDIOC_GETTIMEOUT: | ||
314 | heartbeat = 256; | ||
315 | return put_user(heartbeat, p); | ||
316 | default: | ||
317 | return -ENOTTY; | ||
296 | } | 318 | } |
297 | |||
298 | return -ENOTTY; | ||
299 | } | 319 | } |
300 | 320 | ||
301 | static int asr_open(struct inode *inode, struct file *file) | 321 | static int asr_open(struct inode *inode, struct file *file) |
302 | { | 322 | { |
303 | if(test_and_set_bit(0, &asr_is_open)) | 323 | if (test_and_set_bit(0, &asr_is_open)) |
304 | return -EBUSY; | 324 | return -EBUSY; |
305 | 325 | ||
306 | asr_toggle(); | 326 | asr_toggle(); |
@@ -314,7 +334,8 @@ static int asr_release(struct inode *inode, struct file *file) | |||
314 | if (asr_expect_close == 42) | 334 | if (asr_expect_close == 42) |
315 | asr_disable(); | 335 | asr_disable(); |
316 | else { | 336 | else { |
317 | printk(KERN_CRIT PFX "unexpected close, not stopping watchdog!\n"); | 337 | printk(KERN_CRIT PFX |
338 | "unexpected close, not stopping watchdog!\n"); | ||
318 | asr_toggle(); | 339 | asr_toggle(); |
319 | } | 340 | } |
320 | clear_bit(0, &asr_is_open); | 341 | clear_bit(0, &asr_is_open); |
@@ -323,12 +344,12 @@ static int asr_release(struct inode *inode, struct file *file) | |||
323 | } | 344 | } |
324 | 345 | ||
325 | static const struct file_operations asr_fops = { | 346 | static const struct file_operations asr_fops = { |
326 | .owner = THIS_MODULE, | 347 | .owner = THIS_MODULE, |
327 | .llseek = no_llseek, | 348 | .llseek = no_llseek, |
328 | .write = asr_write, | 349 | .write = asr_write, |
329 | .ioctl = asr_ioctl, | 350 | .unlocked_ioctl = asr_ioctl, |
330 | .open = asr_open, | 351 | .open = asr_open, |
331 | .release = asr_release, | 352 | .release = asr_release, |
332 | }; | 353 | }; |
333 | 354 | ||
334 | static struct miscdevice asr_miscdev = { | 355 | static struct miscdevice asr_miscdev = { |
@@ -367,6 +388,8 @@ static int __init ibmasr_init(void) | |||
367 | if (!asr_type) | 388 | if (!asr_type) |
368 | return -ENODEV; | 389 | return -ENODEV; |
369 | 390 | ||
391 | spin_lock_init(&asr_lock); | ||
392 | |||
370 | rc = asr_get_base_address(); | 393 | rc = asr_get_base_address(); |
371 | if (rc) | 394 | if (rc) |
372 | return rc; | 395 | return rc; |
@@ -395,7 +418,9 @@ module_init(ibmasr_init); | |||
395 | module_exit(ibmasr_exit); | 418 | module_exit(ibmasr_exit); |
396 | 419 | ||
397 | module_param(nowayout, int, 0); | 420 | module_param(nowayout, int, 0); |
398 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 421 | MODULE_PARM_DESC(nowayout, |
422 | "Watchdog cannot be stopped once started (default=" | ||
423 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
399 | 424 | ||
400 | MODULE_DESCRIPTION("IBM Automatic Server Restart driver"); | 425 | MODULE_DESCRIPTION("IBM Automatic Server Restart driver"); |
401 | MODULE_AUTHOR("Andrey Panin"); | 426 | MODULE_AUTHOR("Andrey Panin"); |
diff --git a/drivers/watchdog/indydog.c b/drivers/watchdog/indydog.c index 788245bdaa7f..73c9e7992feb 100644 --- a/drivers/watchdog/indydog.c +++ b/drivers/watchdog/indydog.c | |||
@@ -1,7 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * IndyDog 0.3 A Hardware Watchdog Device for SGI IP22 | 2 | * IndyDog 0.3 A Hardware Watchdog Device for SGI IP22 |
3 | * | 3 | * |
4 | * (c) Copyright 2002 Guido Guenther <agx@sigxcpu.org>, All Rights Reserved. | 4 | * (c) Copyright 2002 Guido Guenther <agx@sigxcpu.org>, |
5 | * All Rights Reserved. | ||
5 | * | 6 | * |
6 | * This program is free software; you can redistribute it and/or | 7 | * This program is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU General Public License | 8 | * modify it under the terms of the GNU General Public License |
@@ -22,32 +23,42 @@ | |||
22 | #include <linux/notifier.h> | 23 | #include <linux/notifier.h> |
23 | #include <linux/reboot.h> | 24 | #include <linux/reboot.h> |
24 | #include <linux/init.h> | 25 | #include <linux/init.h> |
25 | #include <asm/uaccess.h> | 26 | #include <linux/uaccess.h> |
26 | #include <asm/sgi/mc.h> | 27 | #include <asm/sgi/mc.h> |
27 | 28 | ||
28 | #define PFX "indydog: " | 29 | #define PFX "indydog: " |
29 | static int indydog_alive; | 30 | static unsigned long indydog_alive; |
31 | static spinlock_t indydog_lock; | ||
30 | 32 | ||
31 | #define WATCHDOG_TIMEOUT 30 /* 30 sec default timeout */ | 33 | #define WATCHDOG_TIMEOUT 30 /* 30 sec default timeout */ |
32 | 34 | ||
33 | static int nowayout = WATCHDOG_NOWAYOUT; | 35 | static int nowayout = WATCHDOG_NOWAYOUT; |
34 | module_param(nowayout, int, 0); | 36 | module_param(nowayout, int, 0); |
35 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 37 | MODULE_PARM_DESC(nowayout, |
38 | "Watchdog cannot be stopped once started (default=" | ||
39 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
36 | 40 | ||
37 | static void indydog_start(void) | 41 | static void indydog_start(void) |
38 | { | 42 | { |
39 | u32 mc_ctrl0 = sgimc->cpuctrl0; | 43 | u32 mc_ctrl0; |
40 | 44 | ||
45 | spin_lock(&indydog_lock); | ||
46 | mc_ctrl0 = sgimc->cpuctrl0; | ||
41 | mc_ctrl0 = sgimc->cpuctrl0 | SGIMC_CCTRL0_WDOG; | 47 | mc_ctrl0 = sgimc->cpuctrl0 | SGIMC_CCTRL0_WDOG; |
42 | sgimc->cpuctrl0 = mc_ctrl0; | 48 | sgimc->cpuctrl0 = mc_ctrl0; |
49 | spin_unlock(&indydog_lock); | ||
43 | } | 50 | } |
44 | 51 | ||
45 | static void indydog_stop(void) | 52 | static void indydog_stop(void) |
46 | { | 53 | { |
47 | u32 mc_ctrl0 = sgimc->cpuctrl0; | 54 | u32 mc_ctrl0; |
48 | 55 | ||
56 | spin_lock(&indydog_lock); | ||
57 | |||
58 | mc_ctrl0 = sgimc->cpuctrl0; | ||
49 | mc_ctrl0 &= ~SGIMC_CCTRL0_WDOG; | 59 | mc_ctrl0 &= ~SGIMC_CCTRL0_WDOG; |
50 | sgimc->cpuctrl0 = mc_ctrl0; | 60 | sgimc->cpuctrl0 = mc_ctrl0; |
61 | spin_unlock(&indydog_lock); | ||
51 | 62 | ||
52 | printk(KERN_INFO PFX "Stopped watchdog timer.\n"); | 63 | printk(KERN_INFO PFX "Stopped watchdog timer.\n"); |
53 | } | 64 | } |
@@ -62,7 +73,7 @@ static void indydog_ping(void) | |||
62 | */ | 73 | */ |
63 | static int indydog_open(struct inode *inode, struct file *file) | 74 | static int indydog_open(struct inode *inode, struct file *file) |
64 | { | 75 | { |
65 | if (indydog_alive) | 76 | if (test_and_set_bit(0, &indydog_alive)) |
66 | return -EBUSY; | 77 | return -EBUSY; |
67 | 78 | ||
68 | if (nowayout) | 79 | if (nowayout) |
@@ -84,23 +95,21 @@ static int indydog_release(struct inode *inode, struct file *file) | |||
84 | * Lock it in if it's a module and we defined ...NOWAYOUT */ | 95 | * Lock it in if it's a module and we defined ...NOWAYOUT */ |
85 | if (!nowayout) | 96 | if (!nowayout) |
86 | indydog_stop(); /* Turn the WDT off */ | 97 | indydog_stop(); /* Turn the WDT off */ |
87 | 98 | clear_bit(0, &indydog_alive); | |
88 | indydog_alive = 0; | ||
89 | |||
90 | return 0; | 99 | return 0; |
91 | } | 100 | } |
92 | 101 | ||
93 | static ssize_t indydog_write(struct file *file, const char *data, size_t len, loff_t *ppos) | 102 | static ssize_t indydog_write(struct file *file, const char *data, |
103 | size_t len, loff_t *ppos) | ||
94 | { | 104 | { |
95 | /* Refresh the timer. */ | 105 | /* Refresh the timer. */ |
96 | if (len) { | 106 | if (len) |
97 | indydog_ping(); | 107 | indydog_ping(); |
98 | } | ||
99 | return len; | 108 | return len; |
100 | } | 109 | } |
101 | 110 | ||
102 | static int indydog_ioctl(struct inode *inode, struct file *file, | 111 | static long indydog_ioctl(struct file *file, unsigned int cmd, |
103 | unsigned int cmd, unsigned long arg) | 112 | unsigned long arg) |
104 | { | 113 | { |
105 | int options, retval = -EINVAL; | 114 | int options, retval = -EINVAL; |
106 | static struct watchdog_info ident = { | 115 | static struct watchdog_info ident = { |
@@ -111,42 +120,40 @@ static int indydog_ioctl(struct inode *inode, struct file *file, | |||
111 | }; | 120 | }; |
112 | 121 | ||
113 | switch (cmd) { | 122 | switch (cmd) { |
114 | default: | 123 | case WDIOC_GETSUPPORT: |
115 | return -ENOTTY; | 124 | if (copy_to_user((struct watchdog_info *)arg, |
116 | case WDIOC_GETSUPPORT: | 125 | &ident, sizeof(ident))) |
117 | if (copy_to_user((struct watchdog_info *)arg, | 126 | return -EFAULT; |
118 | &ident, sizeof(ident))) | 127 | return 0; |
119 | return -EFAULT; | 128 | case WDIOC_GETSTATUS: |
120 | return 0; | 129 | case WDIOC_GETBOOTSTATUS: |
121 | case WDIOC_GETSTATUS: | 130 | return put_user(0, (int *)arg); |
122 | case WDIOC_GETBOOTSTATUS: | 131 | case WDIOC_SETOPTIONS: |
123 | return put_user(0,(int *)arg); | 132 | { |
124 | case WDIOC_KEEPALIVE: | 133 | if (get_user(options, (int *)arg)) |
125 | indydog_ping(); | 134 | return -EFAULT; |
126 | return 0; | 135 | if (options & WDIOS_DISABLECARD) { |
127 | case WDIOC_GETTIMEOUT: | 136 | indydog_stop(); |
128 | return put_user(WATCHDOG_TIMEOUT,(int *)arg); | 137 | retval = 0; |
129 | case WDIOC_SETOPTIONS: | ||
130 | { | ||
131 | if (get_user(options, (int *)arg)) | ||
132 | return -EFAULT; | ||
133 | |||
134 | if (options & WDIOS_DISABLECARD) { | ||
135 | indydog_stop(); | ||
136 | retval = 0; | ||
137 | } | ||
138 | |||
139 | if (options & WDIOS_ENABLECARD) { | ||
140 | indydog_start(); | ||
141 | retval = 0; | ||
142 | } | ||
143 | |||
144 | return retval; | ||
145 | } | 138 | } |
139 | if (options & WDIOS_ENABLECARD) { | ||
140 | indydog_start(); | ||
141 | retval = 0; | ||
142 | } | ||
143 | return retval; | ||
144 | } | ||
145 | case WDIOC_KEEPALIVE: | ||
146 | indydog_ping(); | ||
147 | return 0; | ||
148 | case WDIOC_GETTIMEOUT: | ||
149 | return put_user(WATCHDOG_TIMEOUT, (int *)arg); | ||
150 | default: | ||
151 | return -ENOTTY; | ||
146 | } | 152 | } |
147 | } | 153 | } |
148 | 154 | ||
149 | static int indydog_notify_sys(struct notifier_block *this, unsigned long code, void *unused) | 155 | static int indydog_notify_sys(struct notifier_block *this, |
156 | unsigned long code, void *unused) | ||
150 | { | 157 | { |
151 | if (code == SYS_DOWN || code == SYS_HALT) | 158 | if (code == SYS_DOWN || code == SYS_HALT) |
152 | indydog_stop(); /* Turn the WDT off */ | 159 | indydog_stop(); /* Turn the WDT off */ |
@@ -158,7 +165,7 @@ static const struct file_operations indydog_fops = { | |||
158 | .owner = THIS_MODULE, | 165 | .owner = THIS_MODULE, |
159 | .llseek = no_llseek, | 166 | .llseek = no_llseek, |
160 | .write = indydog_write, | 167 | .write = indydog_write, |
161 | .ioctl = indydog_ioctl, | 168 | .unlocked_ioctl = indydog_ioctl, |
162 | .open = indydog_open, | 169 | .open = indydog_open, |
163 | .release = indydog_release, | 170 | .release = indydog_release, |
164 | }; | 171 | }; |
@@ -180,17 +187,20 @@ static int __init watchdog_init(void) | |||
180 | { | 187 | { |
181 | int ret; | 188 | int ret; |
182 | 189 | ||
190 | spin_lock_init(&indydog_lock); | ||
191 | |||
183 | ret = register_reboot_notifier(&indydog_notifier); | 192 | ret = register_reboot_notifier(&indydog_notifier); |
184 | if (ret) { | 193 | if (ret) { |
185 | printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", | 194 | printk(KERN_ERR PFX |
186 | ret); | 195 | "cannot register reboot notifier (err=%d)\n", ret); |
187 | return ret; | 196 | return ret; |
188 | } | 197 | } |
189 | 198 | ||
190 | ret = misc_register(&indydog_miscdev); | 199 | ret = misc_register(&indydog_miscdev); |
191 | if (ret) { | 200 | if (ret) { |
192 | printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", | 201 | printk(KERN_ERR PFX |
193 | WATCHDOG_MINOR, ret); | 202 | "cannot register miscdev on minor=%d (err=%d)\n", |
203 | WATCHDOG_MINOR, ret); | ||
194 | unregister_reboot_notifier(&indydog_notifier); | 204 | unregister_reboot_notifier(&indydog_notifier); |
195 | return ret; | 205 | return ret; |
196 | } | 206 | } |
diff --git a/drivers/watchdog/iop_wdt.c b/drivers/watchdog/iop_wdt.c index bbbd91af754d..8278b13f77c7 100644 --- a/drivers/watchdog/iop_wdt.c +++ b/drivers/watchdog/iop_wdt.c | |||
@@ -37,6 +37,7 @@ | |||
37 | static int nowayout = WATCHDOG_NOWAYOUT; | 37 | static int nowayout = WATCHDOG_NOWAYOUT; |
38 | static unsigned long wdt_status; | 38 | static unsigned long wdt_status; |
39 | static unsigned long boot_status; | 39 | static unsigned long boot_status; |
40 | static spinlock_t wdt_lock; | ||
40 | 41 | ||
41 | #define WDT_IN_USE 0 | 42 | #define WDT_IN_USE 0 |
42 | #define WDT_OK_TO_CLOSE 1 | 43 | #define WDT_OK_TO_CLOSE 1 |
@@ -68,8 +69,10 @@ static void wdt_enable(void) | |||
68 | /* Arm and enable the Timer to starting counting down from 0xFFFF.FFFF | 69 | /* Arm and enable the Timer to starting counting down from 0xFFFF.FFFF |
69 | * Takes approx. 10.7s to timeout | 70 | * Takes approx. 10.7s to timeout |
70 | */ | 71 | */ |
72 | spin_lock(&wdt_lock); | ||
71 | write_wdtcr(IOP_WDTCR_EN_ARM); | 73 | write_wdtcr(IOP_WDTCR_EN_ARM); |
72 | write_wdtcr(IOP_WDTCR_EN); | 74 | write_wdtcr(IOP_WDTCR_EN); |
75 | spin_unlock(&wdt_lock); | ||
73 | } | 76 | } |
74 | 77 | ||
75 | /* returns 0 if the timer was successfully disabled */ | 78 | /* returns 0 if the timer was successfully disabled */ |
@@ -77,9 +80,11 @@ static int wdt_disable(void) | |||
77 | { | 80 | { |
78 | /* Stop Counting */ | 81 | /* Stop Counting */ |
79 | if (wdt_supports_disable()) { | 82 | if (wdt_supports_disable()) { |
83 | spin_lock(&wdt_lock); | ||
80 | write_wdtcr(IOP_WDTCR_DIS_ARM); | 84 | write_wdtcr(IOP_WDTCR_DIS_ARM); |
81 | write_wdtcr(IOP_WDTCR_DIS); | 85 | write_wdtcr(IOP_WDTCR_DIS); |
82 | clear_bit(WDT_ENABLED, &wdt_status); | 86 | clear_bit(WDT_ENABLED, &wdt_status); |
87 | spin_unlock(&wdt_lock); | ||
83 | printk(KERN_INFO "WATCHDOG: Disabled\n"); | 88 | printk(KERN_INFO "WATCHDOG: Disabled\n"); |
84 | return 0; | 89 | return 0; |
85 | } else | 90 | } else |
@@ -92,16 +97,12 @@ static int iop_wdt_open(struct inode *inode, struct file *file) | |||
92 | return -EBUSY; | 97 | return -EBUSY; |
93 | 98 | ||
94 | clear_bit(WDT_OK_TO_CLOSE, &wdt_status); | 99 | clear_bit(WDT_OK_TO_CLOSE, &wdt_status); |
95 | |||
96 | wdt_enable(); | 100 | wdt_enable(); |
97 | |||
98 | set_bit(WDT_ENABLED, &wdt_status); | 101 | set_bit(WDT_ENABLED, &wdt_status); |
99 | |||
100 | return nonseekable_open(inode, file); | 102 | return nonseekable_open(inode, file); |
101 | } | 103 | } |
102 | 104 | ||
103 | static ssize_t | 105 | static ssize_t iop_wdt_write(struct file *file, const char *data, size_t len, |
104 | iop_wdt_write(struct file *file, const char *data, size_t len, | ||
105 | loff_t *ppos) | 106 | loff_t *ppos) |
106 | { | 107 | { |
107 | if (len) { | 108 | if (len) { |
@@ -121,46 +122,35 @@ iop_wdt_write(struct file *file, const char *data, size_t len, | |||
121 | } | 122 | } |
122 | wdt_enable(); | 123 | wdt_enable(); |
123 | } | 124 | } |
124 | |||
125 | return len; | 125 | return len; |
126 | } | 126 | } |
127 | 127 | ||
128 | static struct watchdog_info ident = { | 128 | static const struct watchdog_info ident = { |
129 | .options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING, | 129 | .options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING, |
130 | .identity = "iop watchdog", | 130 | .identity = "iop watchdog", |
131 | }; | 131 | }; |
132 | 132 | ||
133 | static int | 133 | static long iop_wdt_ioctl(struct file *file, |
134 | iop_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | 134 | unsigned int cmd, unsigned long arg) |
135 | unsigned long arg) | ||
136 | { | 135 | { |
137 | int options; | 136 | int options; |
138 | int ret = -ENOTTY; | 137 | int ret = -ENOTTY; |
138 | int __user *argp = (int __user *)arg; | ||
139 | 139 | ||
140 | switch (cmd) { | 140 | switch (cmd) { |
141 | case WDIOC_GETSUPPORT: | 141 | case WDIOC_GETSUPPORT: |
142 | if (copy_to_user | 142 | if (copy_to_user(argp, &ident, sizeof ident)) |
143 | ((struct watchdog_info *)arg, &ident, sizeof ident)) | ||
144 | ret = -EFAULT; | 143 | ret = -EFAULT; |
145 | else | 144 | else |
146 | ret = 0; | 145 | ret = 0; |
147 | break; | 146 | break; |
148 | 147 | ||
149 | case WDIOC_GETSTATUS: | 148 | case WDIOC_GETSTATUS: |
150 | ret = put_user(0, (int *)arg); | 149 | ret = put_user(0, argp); |
151 | break; | 150 | break; |
152 | 151 | ||
153 | case WDIOC_GETBOOTSTATUS: | 152 | case WDIOC_GETBOOTSTATUS: |
154 | ret = put_user(boot_status, (int *)arg); | 153 | ret = put_user(boot_status, argp); |
155 | break; | ||
156 | |||
157 | case WDIOC_GETTIMEOUT: | ||
158 | ret = put_user(iop_watchdog_timeout(), (int *)arg); | ||
159 | break; | ||
160 | |||
161 | case WDIOC_KEEPALIVE: | ||
162 | wdt_enable(); | ||
163 | ret = 0; | ||
164 | break; | 154 | break; |
165 | 155 | ||
166 | case WDIOC_SETOPTIONS: | 156 | case WDIOC_SETOPTIONS: |
@@ -177,14 +167,21 @@ iop_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | |||
177 | } else | 167 | } else |
178 | ret = 0; | 168 | ret = 0; |
179 | } | 169 | } |
180 | |||
181 | if (options & WDIOS_ENABLECARD) { | 170 | if (options & WDIOS_ENABLECARD) { |
182 | wdt_enable(); | 171 | wdt_enable(); |
183 | ret = 0; | 172 | ret = 0; |
184 | } | 173 | } |
185 | break; | 174 | break; |
186 | } | ||
187 | 175 | ||
176 | case WDIOC_KEEPALIVE: | ||
177 | wdt_enable(); | ||
178 | ret = 0; | ||
179 | break; | ||
180 | |||
181 | case WDIOC_GETTIMEOUT: | ||
182 | ret = put_user(iop_watchdog_timeout(), argp); | ||
183 | break; | ||
184 | } | ||
188 | return ret; | 185 | return ret; |
189 | } | 186 | } |
190 | 187 | ||
@@ -214,7 +211,7 @@ static const struct file_operations iop_wdt_fops = { | |||
214 | .owner = THIS_MODULE, | 211 | .owner = THIS_MODULE, |
215 | .llseek = no_llseek, | 212 | .llseek = no_llseek, |
216 | .write = iop_wdt_write, | 213 | .write = iop_wdt_write, |
217 | .ioctl = iop_wdt_ioctl, | 214 | .unlocked_ioctl = iop_wdt_ioctl, |
218 | .open = iop_wdt_open, | 215 | .open = iop_wdt_open, |
219 | .release = iop_wdt_release, | 216 | .release = iop_wdt_release, |
220 | }; | 217 | }; |
@@ -229,10 +226,8 @@ static int __init iop_wdt_init(void) | |||
229 | { | 226 | { |
230 | int ret; | 227 | int ret; |
231 | 228 | ||
232 | ret = misc_register(&iop_wdt_miscdev); | 229 | spin_lock_init(&wdt_lock); |
233 | if (ret == 0) | 230 | |
234 | printk("iop watchdog timer: timeout %lu sec\n", | ||
235 | iop_watchdog_timeout()); | ||
236 | 231 | ||
237 | /* check if the reset was caused by the watchdog timer */ | 232 | /* check if the reset was caused by the watchdog timer */ |
238 | boot_status = (read_rcsr() & IOP_RCSR_WDT) ? WDIOF_CARDRESET : 0; | 233 | boot_status = (read_rcsr() & IOP_RCSR_WDT) ? WDIOF_CARDRESET : 0; |
@@ -242,6 +237,13 @@ static int __init iop_wdt_init(void) | |||
242 | */ | 237 | */ |
243 | write_wdtsr(IOP13XX_WDTCR_IB_RESET); | 238 | write_wdtsr(IOP13XX_WDTCR_IB_RESET); |
244 | 239 | ||
240 | /* Register after we have the device set up so we cannot race | ||
241 | with an open */ | ||
242 | ret = misc_register(&iop_wdt_miscdev); | ||
243 | if (ret == 0) | ||
244 | printk(KERN_INFO "iop watchdog timer: timeout %lu sec\n", | ||
245 | iop_watchdog_timeout()); | ||
246 | |||
245 | return ret; | 247 | return ret; |
246 | } | 248 | } |
247 | 249 | ||
diff --git a/drivers/watchdog/it8712f_wdt.c b/drivers/watchdog/it8712f_wdt.c index 51bfd5721833..2270ee07c01b 100644 --- a/drivers/watchdog/it8712f_wdt.c +++ b/drivers/watchdog/it8712f_wdt.c | |||
@@ -221,7 +221,7 @@ static ssize_t it8712f_wdt_write(struct file *file, const char __user *data, | |||
221 | expect_close = 0; | 221 | expect_close = 0; |
222 | for (i = 0; i < len; ++i) { | 222 | for (i = 0; i < len; ++i) { |
223 | char c; | 223 | char c; |
224 | if (get_user(c, data+i)) | 224 | if (get_user(c, data + i)) |
225 | return -EFAULT; | 225 | return -EFAULT; |
226 | if (c == 'V') | 226 | if (c == 'V') |
227 | expect_close = 42; | 227 | expect_close = 42; |
@@ -244,8 +244,6 @@ static long it8712f_wdt_ioctl(struct file *file, unsigned int cmd, | |||
244 | int value; | 244 | int value; |
245 | 245 | ||
246 | switch (cmd) { | 246 | switch (cmd) { |
247 | default: | ||
248 | return -ENOTTY; | ||
249 | case WDIOC_GETSUPPORT: | 247 | case WDIOC_GETSUPPORT: |
250 | if (copy_to_user(argp, &ident, sizeof(ident))) | 248 | if (copy_to_user(argp, &ident, sizeof(ident))) |
251 | return -EFAULT; | 249 | return -EFAULT; |
@@ -284,6 +282,8 @@ static long it8712f_wdt_ioctl(struct file *file, unsigned int cmd, | |||
284 | if (put_user(margin, p)) | 282 | if (put_user(margin, p)) |
285 | return -EFAULT; | 283 | return -EFAULT; |
286 | return 0; | 284 | return 0; |
285 | default: | ||
286 | return -ENOTTY; | ||
287 | } | 287 | } |
288 | } | 288 | } |
289 | 289 | ||
diff --git a/drivers/watchdog/ixp2000_wdt.c b/drivers/watchdog/ixp2000_wdt.c index dc7548dcaf35..a77f69d52877 100644 --- a/drivers/watchdog/ixp2000_wdt.c +++ b/drivers/watchdog/ixp2000_wdt.c | |||
@@ -25,42 +25,45 @@ | |||
25 | #include <linux/watchdog.h> | 25 | #include <linux/watchdog.h> |
26 | #include <linux/init.h> | 26 | #include <linux/init.h> |
27 | #include <linux/bitops.h> | 27 | #include <linux/bitops.h> |
28 | #include <linux/uaccess.h> | ||
28 | 29 | ||
29 | #include <asm/hardware.h> | 30 | #include <asm/hardware.h> |
30 | #include <asm/uaccess.h> | ||
31 | 31 | ||
32 | static int nowayout = WATCHDOG_NOWAYOUT; | 32 | static int nowayout = WATCHDOG_NOWAYOUT; |
33 | static unsigned int heartbeat = 60; /* (secs) Default is 1 minute */ | 33 | static unsigned int heartbeat = 60; /* (secs) Default is 1 minute */ |
34 | static unsigned long wdt_status; | 34 | static unsigned long wdt_status; |
35 | static spinlock_t wdt_lock; | ||
35 | 36 | ||
36 | #define WDT_IN_USE 0 | 37 | #define WDT_IN_USE 0 |
37 | #define WDT_OK_TO_CLOSE 1 | 38 | #define WDT_OK_TO_CLOSE 1 |
38 | 39 | ||
39 | static unsigned long wdt_tick_rate; | 40 | static unsigned long wdt_tick_rate; |
40 | 41 | ||
41 | static void | 42 | static void wdt_enable(void) |
42 | wdt_enable(void) | ||
43 | { | 43 | { |
44 | spin_lock(&wdt_lock); | ||
44 | ixp2000_reg_write(IXP2000_RESET0, *(IXP2000_RESET0) | WDT_RESET_ENABLE); | 45 | ixp2000_reg_write(IXP2000_RESET0, *(IXP2000_RESET0) | WDT_RESET_ENABLE); |
45 | ixp2000_reg_write(IXP2000_TWDE, WDT_ENABLE); | 46 | ixp2000_reg_write(IXP2000_TWDE, WDT_ENABLE); |
46 | ixp2000_reg_write(IXP2000_T4_CLD, heartbeat * wdt_tick_rate); | 47 | ixp2000_reg_write(IXP2000_T4_CLD, heartbeat * wdt_tick_rate); |
47 | ixp2000_reg_write(IXP2000_T4_CTL, TIMER_DIVIDER_256 | TIMER_ENABLE); | 48 | ixp2000_reg_write(IXP2000_T4_CTL, TIMER_DIVIDER_256 | TIMER_ENABLE); |
49 | spin_unlock(&wdt_lock); | ||
48 | } | 50 | } |
49 | 51 | ||
50 | static void | 52 | static void wdt_disable(void) |
51 | wdt_disable(void) | ||
52 | { | 53 | { |
54 | spin_lock(&wdt_lock); | ||
53 | ixp2000_reg_write(IXP2000_T4_CTL, 0); | 55 | ixp2000_reg_write(IXP2000_T4_CTL, 0); |
56 | spin_unlock(&wdt_lock); | ||
54 | } | 57 | } |
55 | 58 | ||
56 | static void | 59 | static void wdt_keepalive(void) |
57 | wdt_keepalive(void) | ||
58 | { | 60 | { |
61 | spin_lock(&wdt_lock); | ||
59 | ixp2000_reg_write(IXP2000_T4_CLD, heartbeat * wdt_tick_rate); | 62 | ixp2000_reg_write(IXP2000_T4_CLD, heartbeat * wdt_tick_rate); |
63 | spin_unlock(&wdt_lock); | ||
60 | } | 64 | } |
61 | 65 | ||
62 | static int | 66 | static int ixp2000_wdt_open(struct inode *inode, struct file *file) |
63 | ixp2000_wdt_open(struct inode *inode, struct file *file) | ||
64 | { | 67 | { |
65 | if (test_and_set_bit(WDT_IN_USE, &wdt_status)) | 68 | if (test_and_set_bit(WDT_IN_USE, &wdt_status)) |
66 | return -EBUSY; | 69 | return -EBUSY; |
@@ -72,8 +75,8 @@ ixp2000_wdt_open(struct inode *inode, struct file *file) | |||
72 | return nonseekable_open(inode, file); | 75 | return nonseekable_open(inode, file); |
73 | } | 76 | } |
74 | 77 | ||
75 | static ssize_t | 78 | static ssize_t ixp2000_wdt_write(struct file *file, const char *data, |
76 | ixp2000_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos) | 79 | size_t len, loff_t *ppos) |
77 | { | 80 | { |
78 | if (len) { | 81 | if (len) { |
79 | if (!nowayout) { | 82 | if (!nowayout) { |
@@ -103,9 +106,8 @@ static struct watchdog_info ident = { | |||
103 | .identity = "IXP2000 Watchdog", | 106 | .identity = "IXP2000 Watchdog", |
104 | }; | 107 | }; |
105 | 108 | ||
106 | static int | 109 | static long ixp2000_wdt_ioctl(struct file *file, unsigned int cmd, |
107 | ixp2000_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | 110 | unsigned long arg) |
108 | unsigned long arg) | ||
109 | { | 111 | { |
110 | int ret = -ENOTTY; | 112 | int ret = -ENOTTY; |
111 | int time; | 113 | int time; |
@@ -124,6 +126,11 @@ ixp2000_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | |||
124 | ret = put_user(0, (int *)arg); | 126 | ret = put_user(0, (int *)arg); |
125 | break; | 127 | break; |
126 | 128 | ||
129 | case WDIOC_KEEPALIVE: | ||
130 | wdt_enable(); | ||
131 | ret = 0; | ||
132 | break; | ||
133 | |||
127 | case WDIOC_SETTIMEOUT: | 134 | case WDIOC_SETTIMEOUT: |
128 | ret = get_user(time, (int *)arg); | 135 | ret = get_user(time, (int *)arg); |
129 | if (ret) | 136 | if (ret) |
@@ -141,26 +148,18 @@ ixp2000_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | |||
141 | case WDIOC_GETTIMEOUT: | 148 | case WDIOC_GETTIMEOUT: |
142 | ret = put_user(heartbeat, (int *)arg); | 149 | ret = put_user(heartbeat, (int *)arg); |
143 | break; | 150 | break; |
144 | |||
145 | case WDIOC_KEEPALIVE: | ||
146 | wdt_enable(); | ||
147 | ret = 0; | ||
148 | break; | ||
149 | } | 151 | } |
150 | 152 | ||
151 | return ret; | 153 | return ret; |
152 | } | 154 | } |
153 | 155 | ||
154 | static int | 156 | static int ixp2000_wdt_release(struct inode *inode, struct file *file) |
155 | ixp2000_wdt_release(struct inode *inode, struct file *file) | ||
156 | { | 157 | { |
157 | if (test_bit(WDT_OK_TO_CLOSE, &wdt_status)) { | 158 | if (test_bit(WDT_OK_TO_CLOSE, &wdt_status)) |
158 | wdt_disable(); | 159 | wdt_disable(); |
159 | } else { | 160 | else |
160 | printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - " | 161 | printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - " |
161 | "timer will not stop\n"); | 162 | "timer will not stop\n"); |
162 | } | ||
163 | |||
164 | clear_bit(WDT_IN_USE, &wdt_status); | 163 | clear_bit(WDT_IN_USE, &wdt_status); |
165 | clear_bit(WDT_OK_TO_CLOSE, &wdt_status); | 164 | clear_bit(WDT_OK_TO_CLOSE, &wdt_status); |
166 | 165 | ||
@@ -168,18 +167,16 @@ ixp2000_wdt_release(struct inode *inode, struct file *file) | |||
168 | } | 167 | } |
169 | 168 | ||
170 | 169 | ||
171 | static const struct file_operations ixp2000_wdt_fops = | 170 | static const struct file_operations ixp2000_wdt_fops = { |
172 | { | ||
173 | .owner = THIS_MODULE, | 171 | .owner = THIS_MODULE, |
174 | .llseek = no_llseek, | 172 | .llseek = no_llseek, |
175 | .write = ixp2000_wdt_write, | 173 | .write = ixp2000_wdt_write, |
176 | .ioctl = ixp2000_wdt_ioctl, | 174 | .unlocked_ioctl = ixp2000_wdt_ioctl, |
177 | .open = ixp2000_wdt_open, | 175 | .open = ixp2000_wdt_open, |
178 | .release = ixp2000_wdt_release, | 176 | .release = ixp2000_wdt_release, |
179 | }; | 177 | }; |
180 | 178 | ||
181 | static struct miscdevice ixp2000_wdt_miscdev = | 179 | static struct miscdevice ixp2000_wdt_miscdev = { |
182 | { | ||
183 | .minor = WATCHDOG_MINOR, | 180 | .minor = WATCHDOG_MINOR, |
184 | .name = "watchdog", | 181 | .name = "watchdog", |
185 | .fops = &ixp2000_wdt_fops, | 182 | .fops = &ixp2000_wdt_fops, |
@@ -191,9 +188,8 @@ static int __init ixp2000_wdt_init(void) | |||
191 | printk(KERN_INFO "Unable to use IXP2000 watchdog due to IXP2800 erratum #25.\n"); | 188 | printk(KERN_INFO "Unable to use IXP2000 watchdog due to IXP2800 erratum #25.\n"); |
192 | return -EIO; | 189 | return -EIO; |
193 | } | 190 | } |
194 | |||
195 | wdt_tick_rate = (*IXP2000_T1_CLD * HZ) / 256; | 191 | wdt_tick_rate = (*IXP2000_T1_CLD * HZ) / 256; |
196 | 192 | spin_lock_init(&wdt_lock); | |
197 | return misc_register(&ixp2000_wdt_miscdev); | 193 | return misc_register(&ixp2000_wdt_miscdev); |
198 | } | 194 | } |
199 | 195 | ||
diff --git a/drivers/watchdog/ixp4xx_wdt.c b/drivers/watchdog/ixp4xx_wdt.c index 5864bb865cfe..ef3157dc9ac1 100644 --- a/drivers/watchdog/ixp4xx_wdt.c +++ b/drivers/watchdog/ixp4xx_wdt.c | |||
@@ -22,48 +22,48 @@ | |||
22 | #include <linux/watchdog.h> | 22 | #include <linux/watchdog.h> |
23 | #include <linux/init.h> | 23 | #include <linux/init.h> |
24 | #include <linux/bitops.h> | 24 | #include <linux/bitops.h> |
25 | #include <linux/uaccess.h> | ||
25 | 26 | ||
26 | #include <asm/hardware.h> | 27 | #include <asm/hardware.h> |
27 | #include <asm/uaccess.h> | ||
28 | 28 | ||
29 | static int nowayout = WATCHDOG_NOWAYOUT; | 29 | static int nowayout = WATCHDOG_NOWAYOUT; |
30 | static int heartbeat = 60; /* (secs) Default is 1 minute */ | 30 | static int heartbeat = 60; /* (secs) Default is 1 minute */ |
31 | static unsigned long wdt_status; | 31 | static unsigned long wdt_status; |
32 | static unsigned long boot_status; | 32 | static unsigned long boot_status; |
33 | static spin_lock_t wdt_lock; | ||
33 | 34 | ||
34 | #define WDT_TICK_RATE (IXP4XX_PERIPHERAL_BUS_CLOCK * 1000000UL) | 35 | #define WDT_TICK_RATE (IXP4XX_PERIPHERAL_BUS_CLOCK * 1000000UL) |
35 | 36 | ||
36 | #define WDT_IN_USE 0 | 37 | #define WDT_IN_USE 0 |
37 | #define WDT_OK_TO_CLOSE 1 | 38 | #define WDT_OK_TO_CLOSE 1 |
38 | 39 | ||
39 | static void | 40 | static void wdt_enable(void) |
40 | wdt_enable(void) | ||
41 | { | 41 | { |
42 | spin_lock(&wdt_lock); | ||
42 | *IXP4XX_OSWK = IXP4XX_WDT_KEY; | 43 | *IXP4XX_OSWK = IXP4XX_WDT_KEY; |
43 | *IXP4XX_OSWE = 0; | 44 | *IXP4XX_OSWE = 0; |
44 | *IXP4XX_OSWT = WDT_TICK_RATE * heartbeat; | 45 | *IXP4XX_OSWT = WDT_TICK_RATE * heartbeat; |
45 | *IXP4XX_OSWE = IXP4XX_WDT_COUNT_ENABLE | IXP4XX_WDT_RESET_ENABLE; | 46 | *IXP4XX_OSWE = IXP4XX_WDT_COUNT_ENABLE | IXP4XX_WDT_RESET_ENABLE; |
46 | *IXP4XX_OSWK = 0; | 47 | *IXP4XX_OSWK = 0; |
48 | spin_unlock(&wdt_lock); | ||
47 | } | 49 | } |
48 | 50 | ||
49 | static void | 51 | static void wdt_disable(void) |
50 | wdt_disable(void) | ||
51 | { | 52 | { |
53 | spin_lock(&wdt_lock); | ||
52 | *IXP4XX_OSWK = IXP4XX_WDT_KEY; | 54 | *IXP4XX_OSWK = IXP4XX_WDT_KEY; |
53 | *IXP4XX_OSWE = 0; | 55 | *IXP4XX_OSWE = 0; |
54 | *IXP4XX_OSWK = 0; | 56 | *IXP4XX_OSWK = 0; |
57 | spin_unlock(&wdt_lock); | ||
55 | } | 58 | } |
56 | 59 | ||
57 | static int | 60 | static int ixp4xx_wdt_open(struct inode *inode, struct file *file) |
58 | ixp4xx_wdt_open(struct inode *inode, struct file *file) | ||
59 | { | 61 | { |
60 | if (test_and_set_bit(WDT_IN_USE, &wdt_status)) | 62 | if (test_and_set_bit(WDT_IN_USE, &wdt_status)) |
61 | return -EBUSY; | 63 | return -EBUSY; |
62 | 64 | ||
63 | clear_bit(WDT_OK_TO_CLOSE, &wdt_status); | 65 | clear_bit(WDT_OK_TO_CLOSE, &wdt_status); |
64 | |||
65 | wdt_enable(); | 66 | wdt_enable(); |
66 | |||
67 | return nonseekable_open(inode, file); | 67 | return nonseekable_open(inode, file); |
68 | } | 68 | } |
69 | 69 | ||
@@ -87,7 +87,6 @@ ixp4xx_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos) | |||
87 | } | 87 | } |
88 | wdt_enable(); | 88 | wdt_enable(); |
89 | } | 89 | } |
90 | |||
91 | return len; | 90 | return len; |
92 | } | 91 | } |
93 | 92 | ||
@@ -98,9 +97,8 @@ static struct watchdog_info ident = { | |||
98 | }; | 97 | }; |
99 | 98 | ||
100 | 99 | ||
101 | static int | 100 | static long ixp4xx_wdt_ioctl(struct file *file, unsigned int cmd, |
102 | ixp4xx_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | 101 | unsigned long arg) |
103 | unsigned long arg) | ||
104 | { | 102 | { |
105 | int ret = -ENOTTY; | 103 | int ret = -ENOTTY; |
106 | int time; | 104 | int time; |
@@ -119,6 +117,11 @@ ixp4xx_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | |||
119 | ret = put_user(boot_status, (int *)arg); | 117 | ret = put_user(boot_status, (int *)arg); |
120 | break; | 118 | break; |
121 | 119 | ||
120 | case WDIOC_KEEPALIVE: | ||
121 | wdt_enable(); | ||
122 | ret = 0; | ||
123 | break; | ||
124 | |||
122 | case WDIOC_SETTIMEOUT: | 125 | case WDIOC_SETTIMEOUT: |
123 | ret = get_user(time, (int *)arg); | 126 | ret = get_user(time, (int *)arg); |
124 | if (ret) | 127 | if (ret) |
@@ -136,25 +139,17 @@ ixp4xx_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | |||
136 | case WDIOC_GETTIMEOUT: | 139 | case WDIOC_GETTIMEOUT: |
137 | ret = put_user(heartbeat, (int *)arg); | 140 | ret = put_user(heartbeat, (int *)arg); |
138 | break; | 141 | break; |
139 | |||
140 | case WDIOC_KEEPALIVE: | ||
141 | wdt_enable(); | ||
142 | ret = 0; | ||
143 | break; | ||
144 | } | 142 | } |
145 | return ret; | 143 | return ret; |
146 | } | 144 | } |
147 | 145 | ||
148 | static int | 146 | static int ixp4xx_wdt_release(struct inode *inode, struct file *file) |
149 | ixp4xx_wdt_release(struct inode *inode, struct file *file) | ||
150 | { | 147 | { |
151 | if (test_bit(WDT_OK_TO_CLOSE, &wdt_status)) { | 148 | if (test_bit(WDT_OK_TO_CLOSE, &wdt_status)) |
152 | wdt_disable(); | 149 | wdt_disable(); |
153 | } else { | 150 | else |
154 | printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - " | 151 | printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - " |
155 | "timer will not stop\n"); | 152 | "timer will not stop\n"); |
156 | } | ||
157 | |||
158 | clear_bit(WDT_IN_USE, &wdt_status); | 153 | clear_bit(WDT_IN_USE, &wdt_status); |
159 | clear_bit(WDT_OK_TO_CLOSE, &wdt_status); | 154 | clear_bit(WDT_OK_TO_CLOSE, &wdt_status); |
160 | 155 | ||
@@ -162,18 +157,16 @@ ixp4xx_wdt_release(struct inode *inode, struct file *file) | |||
162 | } | 157 | } |
163 | 158 | ||
164 | 159 | ||
165 | static const struct file_operations ixp4xx_wdt_fops = | 160 | static const struct file_operations ixp4xx_wdt_fops = { |
166 | { | ||
167 | .owner = THIS_MODULE, | 161 | .owner = THIS_MODULE, |
168 | .llseek = no_llseek, | 162 | .llseek = no_llseek, |
169 | .write = ixp4xx_wdt_write, | 163 | .write = ixp4xx_wdt_write, |
170 | .ioctl = ixp4xx_wdt_ioctl, | 164 | .unlocked_ioctl = ixp4xx_wdt_ioctl, |
171 | .open = ixp4xx_wdt_open, | 165 | .open = ixp4xx_wdt_open, |
172 | .release = ixp4xx_wdt_release, | 166 | .release = ixp4xx_wdt_release, |
173 | }; | 167 | }; |
174 | 168 | ||
175 | static struct miscdevice ixp4xx_wdt_miscdev = | 169 | static struct miscdevice ixp4xx_wdt_miscdev = { |
176 | { | ||
177 | .minor = WATCHDOG_MINOR, | 170 | .minor = WATCHDOG_MINOR, |
178 | .name = "watchdog", | 171 | .name = "watchdog", |
179 | .fops = &ixp4xx_wdt_fops, | 172 | .fops = &ixp4xx_wdt_fops, |
@@ -186,19 +179,18 @@ static int __init ixp4xx_wdt_init(void) | |||
186 | 179 | ||
187 | asm("mrc p15, 0, %0, cr0, cr0, 0;" : "=r"(processor_id) :); | 180 | asm("mrc p15, 0, %0, cr0, cr0, 0;" : "=r"(processor_id) :); |
188 | if (!(processor_id & 0xf) && !cpu_is_ixp46x()) { | 181 | if (!(processor_id & 0xf) && !cpu_is_ixp46x()) { |
189 | printk("IXP4XXX Watchdog: Rev. A0 IXP42x CPU detected - " | 182 | printk(KERN_ERR "IXP4XXX Watchdog: Rev. A0 IXP42x CPU detected" |
190 | "watchdog disabled\n"); | 183 | " - watchdog disabled\n"); |
191 | 184 | ||
192 | return -ENODEV; | 185 | return -ENODEV; |
193 | } | 186 | } |
194 | 187 | spin_lock_init(&wdt_lock); | |
195 | ret = misc_register(&ixp4xx_wdt_miscdev); | ||
196 | if (ret == 0) | ||
197 | printk("IXP4xx Watchdog Timer: heartbeat %d sec\n", heartbeat); | ||
198 | |||
199 | boot_status = (*IXP4XX_OSST & IXP4XX_OSST_TIMER_WARM_RESET) ? | 188 | boot_status = (*IXP4XX_OSST & IXP4XX_OSST_TIMER_WARM_RESET) ? |
200 | WDIOF_CARDRESET : 0; | 189 | WDIOF_CARDRESET : 0; |
201 | 190 | ret = misc_register(&ixp4xx_wdt_miscdev); | |
191 | if (ret == 0) | ||
192 | printk(KERN_INFO "IXP4xx Watchdog Timer: heartbeat %d sec\n", | ||
193 | heartbeat); | ||
202 | return ret; | 194 | return ret; |
203 | } | 195 | } |
204 | 196 | ||
diff --git a/drivers/watchdog/ks8695_wdt.c b/drivers/watchdog/ks8695_wdt.c index df5a6b811ccd..f8566d5c62fe 100644 --- a/drivers/watchdog/ks8695_wdt.c +++ b/drivers/watchdog/ks8695_wdt.c | |||
@@ -19,8 +19,8 @@ | |||
19 | #include <linux/platform_device.h> | 19 | #include <linux/platform_device.h> |
20 | #include <linux/types.h> | 20 | #include <linux/types.h> |
21 | #include <linux/watchdog.h> | 21 | #include <linux/watchdog.h> |
22 | #include <asm/io.h> | 22 | #include <linux/io.h> |
23 | #include <asm/uaccess.h> | 23 | #include <linux/uaccess.h> |
24 | #include <asm/arch/regs-timer.h> | 24 | #include <asm/arch/regs-timer.h> |
25 | 25 | ||
26 | 26 | ||
@@ -31,38 +31,44 @@ static int wdt_time = WDT_DEFAULT_TIME; | |||
31 | static int nowayout = WATCHDOG_NOWAYOUT; | 31 | static int nowayout = WATCHDOG_NOWAYOUT; |
32 | 32 | ||
33 | module_param(wdt_time, int, 0); | 33 | module_param(wdt_time, int, 0); |
34 | MODULE_PARM_DESC(wdt_time, "Watchdog time in seconds. (default="__MODULE_STRING(WDT_DEFAULT_TIME) ")"); | 34 | MODULE_PARM_DESC(wdt_time, "Watchdog time in seconds. (default=" |
35 | __MODULE_STRING(WDT_DEFAULT_TIME) ")"); | ||
35 | 36 | ||
36 | #ifdef CONFIG_WATCHDOG_NOWAYOUT | 37 | #ifdef CONFIG_WATCHDOG_NOWAYOUT |
37 | module_param(nowayout, int, 0); | 38 | module_param(nowayout, int, 0); |
38 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 39 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" |
40 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
39 | #endif | 41 | #endif |
40 | 42 | ||
41 | 43 | ||
42 | static unsigned long ks8695wdt_busy; | 44 | static unsigned long ks8695wdt_busy; |
45 | static spinlock_t ks8695_lock; | ||
43 | 46 | ||
44 | /* ......................................................................... */ | 47 | /* ......................................................................... */ |
45 | 48 | ||
46 | /* | 49 | /* |
47 | * Disable the watchdog. | 50 | * Disable the watchdog. |
48 | */ | 51 | */ |
49 | static void inline ks8695_wdt_stop(void) | 52 | static inline void ks8695_wdt_stop(void) |
50 | { | 53 | { |
51 | unsigned long tmcon; | 54 | unsigned long tmcon; |
52 | 55 | ||
56 | spin_lock(&ks8695_lock); | ||
53 | /* disable timer0 */ | 57 | /* disable timer0 */ |
54 | tmcon = __raw_readl(KS8695_TMR_VA + KS8695_TMCON); | 58 | tmcon = __raw_readl(KS8695_TMR_VA + KS8695_TMCON); |
55 | __raw_writel(tmcon & ~TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON); | 59 | __raw_writel(tmcon & ~TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON); |
60 | spin_unlock(&ks8695_lock); | ||
56 | } | 61 | } |
57 | 62 | ||
58 | /* | 63 | /* |
59 | * Enable and reset the watchdog. | 64 | * Enable and reset the watchdog. |
60 | */ | 65 | */ |
61 | static void inline ks8695_wdt_start(void) | 66 | static inline void ks8695_wdt_start(void) |
62 | { | 67 | { |
63 | unsigned long tmcon; | 68 | unsigned long tmcon; |
64 | unsigned long tval = wdt_time * CLOCK_TICK_RATE; | 69 | unsigned long tval = wdt_time * CLOCK_TICK_RATE; |
65 | 70 | ||
71 | spin_lock(&ks8695_lock); | ||
66 | /* disable timer0 */ | 72 | /* disable timer0 */ |
67 | tmcon = __raw_readl(KS8695_TMR_VA + KS8695_TMCON); | 73 | tmcon = __raw_readl(KS8695_TMR_VA + KS8695_TMCON); |
68 | __raw_writel(tmcon & ~TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON); | 74 | __raw_writel(tmcon & ~TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON); |
@@ -73,19 +79,22 @@ static void inline ks8695_wdt_start(void) | |||
73 | /* re-enable timer0 */ | 79 | /* re-enable timer0 */ |
74 | tmcon = __raw_readl(KS8695_TMR_VA + KS8695_TMCON); | 80 | tmcon = __raw_readl(KS8695_TMR_VA + KS8695_TMCON); |
75 | __raw_writel(tmcon | TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON); | 81 | __raw_writel(tmcon | TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON); |
82 | spin_unlock(&ks8695_lock); | ||
76 | } | 83 | } |
77 | 84 | ||
78 | /* | 85 | /* |
79 | * Reload the watchdog timer. (ie, pat the watchdog) | 86 | * Reload the watchdog timer. (ie, pat the watchdog) |
80 | */ | 87 | */ |
81 | static void inline ks8695_wdt_reload(void) | 88 | static inline void ks8695_wdt_reload(void) |
82 | { | 89 | { |
83 | unsigned long tmcon; | 90 | unsigned long tmcon; |
84 | 91 | ||
92 | spin_lock(&ks8695_lock); | ||
85 | /* disable, then re-enable timer0 */ | 93 | /* disable, then re-enable timer0 */ |
86 | tmcon = __raw_readl(KS8695_TMR_VA + KS8695_TMCON); | 94 | tmcon = __raw_readl(KS8695_TMR_VA + KS8695_TMCON); |
87 | __raw_writel(tmcon & ~TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON); | 95 | __raw_writel(tmcon & ~TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON); |
88 | __raw_writel(tmcon | TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON); | 96 | __raw_writel(tmcon | TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON); |
97 | spin_unlock(&ks8695_lock); | ||
89 | } | 98 | } |
90 | 99 | ||
91 | /* | 100 | /* |
@@ -102,7 +111,8 @@ static int ks8695_wdt_settimeout(int new_time) | |||
102 | if ((new_time <= 0) || (new_time > WDT_MAX_TIME)) | 111 | if ((new_time <= 0) || (new_time > WDT_MAX_TIME)) |
103 | return -EINVAL; | 112 | return -EINVAL; |
104 | 113 | ||
105 | /* Set new watchdog time. It will be used when ks8695_wdt_start() is called. */ | 114 | /* Set new watchdog time. It will be used when |
115 | ks8695_wdt_start() is called. */ | ||
106 | wdt_time = new_time; | 116 | wdt_time = new_time; |
107 | return 0; | 117 | return 0; |
108 | } | 118 | } |
@@ -128,9 +138,9 @@ static int ks8695_wdt_open(struct inode *inode, struct file *file) | |||
128 | */ | 138 | */ |
129 | static int ks8695_wdt_close(struct inode *inode, struct file *file) | 139 | static int ks8695_wdt_close(struct inode *inode, struct file *file) |
130 | { | 140 | { |
141 | /* Disable the watchdog when file is closed */ | ||
131 | if (!nowayout) | 142 | if (!nowayout) |
132 | ks8695_wdt_stop(); /* Disable the watchdog when file is closed */ | 143 | ks8695_wdt_stop(); |
133 | |||
134 | clear_bit(0, &ks8695wdt_busy); | 144 | clear_bit(0, &ks8695wdt_busy); |
135 | return 0; | 145 | return 0; |
136 | } | 146 | } |
@@ -143,60 +153,52 @@ static struct watchdog_info ks8695_wdt_info = { | |||
143 | /* | 153 | /* |
144 | * Handle commands from user-space. | 154 | * Handle commands from user-space. |
145 | */ | 155 | */ |
146 | static int ks8695_wdt_ioctl(struct inode *inode, struct file *file, | 156 | static long ks8695_wdt_ioctl(struct file *file, unsigned int cmd, |
147 | unsigned int cmd, unsigned long arg) | 157 | unsigned long arg) |
148 | { | 158 | { |
149 | void __user *argp = (void __user *)arg; | 159 | void __user *argp = (void __user *)arg; |
150 | int __user *p = argp; | 160 | int __user *p = argp; |
151 | int new_value; | 161 | int new_value; |
152 | 162 | ||
153 | switch(cmd) { | 163 | switch (cmd) { |
154 | case WDIOC_KEEPALIVE: | 164 | case WDIOC_GETSUPPORT: |
155 | ks8695_wdt_reload(); /* pat the watchdog */ | 165 | return copy_to_user(argp, &ks8695_wdt_info, |
156 | return 0; | 166 | sizeof(ks8695_wdt_info)) ? -EFAULT : 0; |
157 | 167 | case WDIOC_GETSTATUS: | |
158 | case WDIOC_GETSUPPORT: | 168 | case WDIOC_GETBOOTSTATUS: |
159 | return copy_to_user(argp, &ks8695_wdt_info, sizeof(ks8695_wdt_info)) ? -EFAULT : 0; | 169 | return put_user(0, p); |
160 | 170 | case WDIOC_SETOPTIONS: | |
161 | case WDIOC_SETTIMEOUT: | 171 | if (get_user(new_value, p)) |
162 | if (get_user(new_value, p)) | 172 | return -EFAULT; |
163 | return -EFAULT; | 173 | if (new_value & WDIOS_DISABLECARD) |
164 | 174 | ks8695_wdt_stop(); | |
165 | if (ks8695_wdt_settimeout(new_value)) | 175 | if (new_value & WDIOS_ENABLECARD) |
166 | return -EINVAL; | ||
167 | |||
168 | /* Enable new time value */ | ||
169 | ks8695_wdt_start(); | 176 | ks8695_wdt_start(); |
170 | 177 | return 0; | |
171 | /* Return current value */ | 178 | case WDIOC_KEEPALIVE: |
172 | return put_user(wdt_time, p); | 179 | ks8695_wdt_reload(); /* pat the watchdog */ |
173 | 180 | return 0; | |
174 | case WDIOC_GETTIMEOUT: | 181 | case WDIOC_SETTIMEOUT: |
175 | return put_user(wdt_time, p); | 182 | if (get_user(new_value, p)) |
176 | 183 | return -EFAULT; | |
177 | case WDIOC_GETSTATUS: | 184 | if (ks8695_wdt_settimeout(new_value)) |
178 | case WDIOC_GETBOOTSTATUS: | 185 | return -EINVAL; |
179 | return put_user(0, p); | 186 | /* Enable new time value */ |
180 | 187 | ks8695_wdt_start(); | |
181 | case WDIOC_SETOPTIONS: | 188 | /* Return current value */ |
182 | if (get_user(new_value, p)) | 189 | return put_user(wdt_time, p); |
183 | return -EFAULT; | 190 | case WDIOC_GETTIMEOUT: |
184 | 191 | return put_user(wdt_time, p); | |
185 | if (new_value & WDIOS_DISABLECARD) | 192 | default: |
186 | ks8695_wdt_stop(); | 193 | return -ENOTTY; |
187 | if (new_value & WDIOS_ENABLECARD) | ||
188 | ks8695_wdt_start(); | ||
189 | return 0; | ||
190 | |||
191 | default: | ||
192 | return -ENOTTY; | ||
193 | } | 194 | } |
194 | } | 195 | } |
195 | 196 | ||
196 | /* | 197 | /* |
197 | * Pat the watchdog whenever device is written to. | 198 | * Pat the watchdog whenever device is written to. |
198 | */ | 199 | */ |
199 | static ssize_t ks8695_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos) | 200 | static ssize_t ks8695_wdt_write(struct file *file, const char *data, |
201 | size_t len, loff_t *ppos) | ||
200 | { | 202 | { |
201 | ks8695_wdt_reload(); /* pat the watchdog */ | 203 | ks8695_wdt_reload(); /* pat the watchdog */ |
202 | return len; | 204 | return len; |
@@ -207,7 +209,7 @@ static ssize_t ks8695_wdt_write(struct file *file, const char *data, size_t len, | |||
207 | static const struct file_operations ks8695wdt_fops = { | 209 | static const struct file_operations ks8695wdt_fops = { |
208 | .owner = THIS_MODULE, | 210 | .owner = THIS_MODULE, |
209 | .llseek = no_llseek, | 211 | .llseek = no_llseek, |
210 | .ioctl = ks8695_wdt_ioctl, | 212 | .unlocked_ioctl = ks8695_wdt_ioctl, |
211 | .open = ks8695_wdt_open, | 213 | .open = ks8695_wdt_open, |
212 | .release = ks8695_wdt_close, | 214 | .release = ks8695_wdt_close, |
213 | .write = ks8695_wdt_write, | 215 | .write = ks8695_wdt_write, |
@@ -231,7 +233,8 @@ static int __init ks8695wdt_probe(struct platform_device *pdev) | |||
231 | if (res) | 233 | if (res) |
232 | return res; | 234 | return res; |
233 | 235 | ||
234 | printk("KS8695 Watchdog Timer enabled (%d seconds%s)\n", wdt_time, nowayout ? ", nowayout" : ""); | 236 | printk(KERN_INFO "KS8695 Watchdog Timer enabled (%d seconds%s)\n", |
237 | wdt_time, nowayout ? ", nowayout" : ""); | ||
235 | return 0; | 238 | return 0; |
236 | } | 239 | } |
237 | 240 | ||
@@ -285,12 +288,14 @@ static struct platform_driver ks8695wdt_driver = { | |||
285 | 288 | ||
286 | static int __init ks8695_wdt_init(void) | 289 | static int __init ks8695_wdt_init(void) |
287 | { | 290 | { |
288 | /* Check that the heartbeat value is within range; if not reset to the default */ | 291 | spin_lock_init(&ks8695_lock); |
292 | /* Check that the heartbeat value is within range; | ||
293 | if not reset to the default */ | ||
289 | if (ks8695_wdt_settimeout(wdt_time)) { | 294 | if (ks8695_wdt_settimeout(wdt_time)) { |
290 | ks8695_wdt_settimeout(WDT_DEFAULT_TIME); | 295 | ks8695_wdt_settimeout(WDT_DEFAULT_TIME); |
291 | pr_info("ks8695_wdt: wdt_time value must be 1 <= wdt_time <= %i, using %d\n", wdt_time, WDT_MAX_TIME); | 296 | pr_info("ks8695_wdt: wdt_time value must be 1 <= wdt_time <= %i, using %d\n", |
297 | wdt_time, WDT_MAX_TIME); | ||
292 | } | 298 | } |
293 | |||
294 | return platform_driver_register(&ks8695wdt_driver); | 299 | return platform_driver_register(&ks8695wdt_driver); |
295 | } | 300 | } |
296 | 301 | ||
diff --git a/drivers/watchdog/machzwd.c b/drivers/watchdog/machzwd.c index 6905135a776c..2dfc27559bf7 100644 --- a/drivers/watchdog/machzwd.c +++ b/drivers/watchdog/machzwd.c | |||
@@ -40,9 +40,9 @@ | |||
40 | #include <linux/notifier.h> | 40 | #include <linux/notifier.h> |
41 | #include <linux/reboot.h> | 41 | #include <linux/reboot.h> |
42 | #include <linux/init.h> | 42 | #include <linux/init.h> |
43 | #include <linux/io.h> | ||
44 | #include <linux/uaccess.h> | ||
43 | 45 | ||
44 | #include <asm/io.h> | ||
45 | #include <asm/uaccess.h> | ||
46 | #include <asm/system.h> | 46 | #include <asm/system.h> |
47 | 47 | ||
48 | /* ports */ | 48 | /* ports */ |
@@ -95,7 +95,9 @@ MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); | |||
95 | 95 | ||
96 | static int nowayout = WATCHDOG_NOWAYOUT; | 96 | static int nowayout = WATCHDOG_NOWAYOUT; |
97 | module_param(nowayout, int, 0); | 97 | module_param(nowayout, int, 0); |
98 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 98 | MODULE_PARM_DESC(nowayout, |
99 | "Watchdog cannot be stopped once started (default=" | ||
100 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
99 | 101 | ||
100 | #define PFX "machzwd" | 102 | #define PFX "machzwd" |
101 | 103 | ||
@@ -114,7 +116,7 @@ static struct watchdog_info zf_info = { | |||
114 | * 3 = GEN_SCI | 116 | * 3 = GEN_SCI |
115 | * defaults to GEN_RESET (0) | 117 | * defaults to GEN_RESET (0) |
116 | */ | 118 | */ |
117 | static int action = 0; | 119 | static int action; |
118 | module_param(action, int, 0); | 120 | module_param(action, int, 0); |
119 | MODULE_PARM_DESC(action, "after watchdog resets, generate: 0 = RESET(*) 1 = SMI 2 = NMI 3 = SCI"); | 121 | MODULE_PARM_DESC(action, "after watchdog resets, generate: 0 = RESET(*) 1 = SMI 2 = NMI 3 = SCI"); |
120 | 122 | ||
@@ -123,10 +125,9 @@ static void zf_ping(unsigned long data); | |||
123 | static int zf_action = GEN_RESET; | 125 | static int zf_action = GEN_RESET; |
124 | static unsigned long zf_is_open; | 126 | static unsigned long zf_is_open; |
125 | static char zf_expect_close; | 127 | static char zf_expect_close; |
126 | static DEFINE_SPINLOCK(zf_lock); | ||
127 | static DEFINE_SPINLOCK(zf_port_lock); | 128 | static DEFINE_SPINLOCK(zf_port_lock); |
128 | static DEFINE_TIMER(zf_timer, zf_ping, 0, 0); | 129 | static DEFINE_TIMER(zf_timer, zf_ping, 0, 0); |
129 | static unsigned long next_heartbeat = 0; | 130 | static unsigned long next_heartbeat; |
130 | 131 | ||
131 | 132 | ||
132 | /* timeout for user land heart beat (10 seconds) */ | 133 | /* timeout for user land heart beat (10 seconds) */ |
@@ -171,13 +172,13 @@ static inline void zf_set_control(unsigned short new) | |||
171 | 172 | ||
172 | static inline void zf_set_timer(unsigned short new, unsigned char n) | 173 | static inline void zf_set_timer(unsigned short new, unsigned char n) |
173 | { | 174 | { |
174 | switch(n){ | 175 | switch (n) { |
175 | case WD1: | 176 | case WD1: |
176 | zf_writew(COUNTER_1, new); | 177 | zf_writew(COUNTER_1, new); |
177 | case WD2: | 178 | case WD2: |
178 | zf_writeb(COUNTER_2, new > 0xff ? 0xff : new); | 179 | zf_writeb(COUNTER_2, new > 0xff ? 0xff : new); |
179 | default: | 180 | default: |
180 | return; | 181 | return; |
181 | } | 182 | } |
182 | } | 183 | } |
183 | 184 | ||
@@ -241,10 +242,8 @@ static void zf_ping(unsigned long data) | |||
241 | 242 | ||
242 | zf_writeb(COUNTER_2, 0xff); | 243 | zf_writeb(COUNTER_2, 0xff); |
243 | 244 | ||
244 | if(time_before(jiffies, next_heartbeat)){ | 245 | if (time_before(jiffies, next_heartbeat)) { |
245 | |||
246 | dprintk("time_before: %ld\n", next_heartbeat - jiffies); | 246 | dprintk("time_before: %ld\n", next_heartbeat - jiffies); |
247 | |||
248 | /* | 247 | /* |
249 | * reset event is activated by transition from 0 to 1 on | 248 | * reset event is activated by transition from 0 to 1 on |
250 | * RESET_WD1 bit and we assume that it is already zero... | 249 | * RESET_WD1 bit and we assume that it is already zero... |
@@ -261,24 +260,21 @@ static void zf_ping(unsigned long data) | |||
261 | spin_unlock_irqrestore(&zf_port_lock, flags); | 260 | spin_unlock_irqrestore(&zf_port_lock, flags); |
262 | 261 | ||
263 | mod_timer(&zf_timer, jiffies + ZF_HW_TIMEO); | 262 | mod_timer(&zf_timer, jiffies + ZF_HW_TIMEO); |
264 | }else{ | 263 | } else |
265 | printk(KERN_CRIT PFX ": I will reset your machine\n"); | 264 | printk(KERN_CRIT PFX ": I will reset your machine\n"); |
266 | } | ||
267 | } | 265 | } |
268 | 266 | ||
269 | static ssize_t zf_write(struct file *file, const char __user *buf, size_t count, | 267 | static ssize_t zf_write(struct file *file, const char __user *buf, size_t count, |
270 | loff_t *ppos) | 268 | loff_t *ppos) |
271 | { | 269 | { |
272 | /* See if we got the magic character */ | 270 | /* See if we got the magic character */ |
273 | if(count){ | 271 | if (count) { |
274 | |||
275 | /* | 272 | /* |
276 | * no need to check for close confirmation | 273 | * no need to check for close confirmation |
277 | * no way to disable watchdog ;) | 274 | * no way to disable watchdog ;) |
278 | */ | 275 | */ |
279 | if (!nowayout) { | 276 | if (!nowayout) { |
280 | size_t ofs; | 277 | size_t ofs; |
281 | |||
282 | /* | 278 | /* |
283 | * note: just in case someone wrote the magic character | 279 | * note: just in case someone wrote the magic character |
284 | * five months ago... | 280 | * five months ago... |
@@ -286,11 +282,11 @@ static ssize_t zf_write(struct file *file, const char __user *buf, size_t count, | |||
286 | zf_expect_close = 0; | 282 | zf_expect_close = 0; |
287 | 283 | ||
288 | /* now scan */ | 284 | /* now scan */ |
289 | for (ofs = 0; ofs != count; ofs++){ | 285 | for (ofs = 0; ofs != count; ofs++) { |
290 | char c; | 286 | char c; |
291 | if (get_user(c, buf + ofs)) | 287 | if (get_user(c, buf + ofs)) |
292 | return -EFAULT; | 288 | return -EFAULT; |
293 | if (c == 'V'){ | 289 | if (c == 'V') { |
294 | zf_expect_close = 42; | 290 | zf_expect_close = 42; |
295 | dprintk("zf_expect_close = 42\n"); | 291 | dprintk("zf_expect_close = 42\n"); |
296 | } | 292 | } |
@@ -303,14 +299,11 @@ static ssize_t zf_write(struct file *file, const char __user *buf, size_t count, | |||
303 | */ | 299 | */ |
304 | next_heartbeat = jiffies + ZF_USER_TIMEO; | 300 | next_heartbeat = jiffies + ZF_USER_TIMEO; |
305 | dprintk("user ping at %ld\n", jiffies); | 301 | dprintk("user ping at %ld\n", jiffies); |
306 | |||
307 | } | 302 | } |
308 | |||
309 | return count; | 303 | return count; |
310 | } | 304 | } |
311 | 305 | ||
312 | static int zf_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | 306 | static long zf_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
313 | unsigned long arg) | ||
314 | { | 307 | { |
315 | void __user *argp = (void __user *)arg; | 308 | void __user *argp = (void __user *)arg; |
316 | int __user *p = argp; | 309 | int __user *p = argp; |
@@ -319,55 +312,38 @@ static int zf_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | |||
319 | if (copy_to_user(argp, &zf_info, sizeof(zf_info))) | 312 | if (copy_to_user(argp, &zf_info, sizeof(zf_info))) |
320 | return -EFAULT; | 313 | return -EFAULT; |
321 | break; | 314 | break; |
322 | |||
323 | case WDIOC_GETSTATUS: | 315 | case WDIOC_GETSTATUS: |
324 | case WDIOC_GETBOOTSTATUS: | 316 | case WDIOC_GETBOOTSTATUS: |
325 | return put_user(0, p); | 317 | return put_user(0, p); |
326 | |||
327 | case WDIOC_KEEPALIVE: | 318 | case WDIOC_KEEPALIVE: |
328 | zf_ping(0); | 319 | zf_ping(0); |
329 | break; | 320 | break; |
330 | |||
331 | default: | 321 | default: |
332 | return -ENOTTY; | 322 | return -ENOTTY; |
333 | } | 323 | } |
334 | |||
335 | return 0; | 324 | return 0; |
336 | } | 325 | } |
337 | 326 | ||
338 | static int zf_open(struct inode *inode, struct file *file) | 327 | static int zf_open(struct inode *inode, struct file *file) |
339 | { | 328 | { |
340 | spin_lock(&zf_lock); | 329 | if (test_and_set_bit(0, &zf_is_open)) |
341 | if(test_and_set_bit(0, &zf_is_open)) { | ||
342 | spin_unlock(&zf_lock); | ||
343 | return -EBUSY; | 330 | return -EBUSY; |
344 | } | ||
345 | |||
346 | if (nowayout) | 331 | if (nowayout) |
347 | __module_get(THIS_MODULE); | 332 | __module_get(THIS_MODULE); |
348 | |||
349 | spin_unlock(&zf_lock); | ||
350 | |||
351 | zf_timer_on(); | 333 | zf_timer_on(); |
352 | |||
353 | return nonseekable_open(inode, file); | 334 | return nonseekable_open(inode, file); |
354 | } | 335 | } |
355 | 336 | ||
356 | static int zf_close(struct inode *inode, struct file *file) | 337 | static int zf_close(struct inode *inode, struct file *file) |
357 | { | 338 | { |
358 | if(zf_expect_close == 42){ | 339 | if (zf_expect_close == 42) |
359 | zf_timer_off(); | 340 | zf_timer_off(); |
360 | } else { | 341 | else { |
361 | del_timer(&zf_timer); | 342 | del_timer(&zf_timer); |
362 | printk(KERN_ERR PFX ": device file closed unexpectedly. Will not stop the WDT!\n"); | 343 | printk(KERN_ERR PFX ": device file closed unexpectedly. Will not stop the WDT!\n"); |
363 | } | 344 | } |
364 | |||
365 | spin_lock(&zf_lock); | ||
366 | clear_bit(0, &zf_is_open); | 345 | clear_bit(0, &zf_is_open); |
367 | spin_unlock(&zf_lock); | ||
368 | |||
369 | zf_expect_close = 0; | 346 | zf_expect_close = 0; |
370 | |||
371 | return 0; | 347 | return 0; |
372 | } | 348 | } |
373 | 349 | ||
@@ -378,23 +354,18 @@ static int zf_close(struct inode *inode, struct file *file) | |||
378 | static int zf_notify_sys(struct notifier_block *this, unsigned long code, | 354 | static int zf_notify_sys(struct notifier_block *this, unsigned long code, |
379 | void *unused) | 355 | void *unused) |
380 | { | 356 | { |
381 | if(code == SYS_DOWN || code == SYS_HALT){ | 357 | if (code == SYS_DOWN || code == SYS_HALT) |
382 | zf_timer_off(); | 358 | zf_timer_off(); |
383 | } | ||
384 | |||
385 | return NOTIFY_DONE; | 359 | return NOTIFY_DONE; |
386 | } | 360 | } |
387 | 361 | ||
388 | |||
389 | |||
390 | |||
391 | static const struct file_operations zf_fops = { | 362 | static const struct file_operations zf_fops = { |
392 | .owner = THIS_MODULE, | 363 | .owner = THIS_MODULE, |
393 | .llseek = no_llseek, | 364 | .llseek = no_llseek, |
394 | .write = zf_write, | 365 | .write = zf_write, |
395 | .ioctl = zf_ioctl, | 366 | .unlocked_ioctl = zf_ioctl, |
396 | .open = zf_open, | 367 | .open = zf_open, |
397 | .release = zf_close, | 368 | .release = zf_close, |
398 | }; | 369 | }; |
399 | 370 | ||
400 | static struct miscdevice zf_miscdev = { | 371 | static struct miscdevice zf_miscdev = { |
@@ -402,7 +373,7 @@ static struct miscdevice zf_miscdev = { | |||
402 | .name = "watchdog", | 373 | .name = "watchdog", |
403 | .fops = &zf_fops, | 374 | .fops = &zf_fops, |
404 | }; | 375 | }; |
405 | 376 | ||
406 | 377 | ||
407 | /* | 378 | /* |
408 | * The device needs to learn about soft shutdowns in order to | 379 | * The device needs to learn about soft shutdowns in order to |
@@ -423,22 +394,23 @@ static int __init zf_init(void) | |||
423 | { | 394 | { |
424 | int ret; | 395 | int ret; |
425 | 396 | ||
426 | printk(KERN_INFO PFX ": MachZ ZF-Logic Watchdog driver initializing.\n"); | 397 | printk(KERN_INFO PFX |
398 | ": MachZ ZF-Logic Watchdog driver initializing.\n"); | ||
427 | 399 | ||
428 | ret = zf_get_ZFL_version(); | 400 | ret = zf_get_ZFL_version(); |
429 | if ((!ret) || (ret == 0xffff)) { | 401 | if (!ret || ret == 0xffff) { |
430 | printk(KERN_WARNING PFX ": no ZF-Logic found\n"); | 402 | printk(KERN_WARNING PFX ": no ZF-Logic found\n"); |
431 | return -ENODEV; | 403 | return -ENODEV; |
432 | } | 404 | } |
433 | 405 | ||
434 | if((action <= 3) && (action >= 0)){ | 406 | if (action <= 3 && action >= 0) |
435 | zf_action = zf_action>>action; | 407 | zf_action = zf_action >> action; |
436 | } else | 408 | else |
437 | action = 0; | 409 | action = 0; |
438 | 410 | ||
439 | zf_show_action(action); | 411 | zf_show_action(action); |
440 | 412 | ||
441 | if(!request_region(ZF_IOBASE, 3, "MachZ ZFL WDT")){ | 413 | if (!request_region(ZF_IOBASE, 3, "MachZ ZFL WDT")) { |
442 | printk(KERN_ERR "cannot reserve I/O ports at %d\n", | 414 | printk(KERN_ERR "cannot reserve I/O ports at %d\n", |
443 | ZF_IOBASE); | 415 | ZF_IOBASE); |
444 | ret = -EBUSY; | 416 | ret = -EBUSY; |
@@ -446,14 +418,14 @@ static int __init zf_init(void) | |||
446 | } | 418 | } |
447 | 419 | ||
448 | ret = register_reboot_notifier(&zf_notifier); | 420 | ret = register_reboot_notifier(&zf_notifier); |
449 | if(ret){ | 421 | if (ret) { |
450 | printk(KERN_ERR "can't register reboot notifier (err=%d)\n", | 422 | printk(KERN_ERR "can't register reboot notifier (err=%d)\n", |
451 | ret); | 423 | ret); |
452 | goto no_reboot; | 424 | goto no_reboot; |
453 | } | 425 | } |
454 | 426 | ||
455 | ret = misc_register(&zf_miscdev); | 427 | ret = misc_register(&zf_miscdev); |
456 | if (ret){ | 428 | if (ret) { |
457 | printk(KERN_ERR "can't misc_register on minor=%d\n", | 429 | printk(KERN_ERR "can't misc_register on minor=%d\n", |
458 | WATCHDOG_MINOR); | 430 | WATCHDOG_MINOR); |
459 | goto no_misc; | 431 | goto no_misc; |
diff --git a/drivers/watchdog/mixcomwd.c b/drivers/watchdog/mixcomwd.c index 1adf1d56027d..407b025cb104 100644 --- a/drivers/watchdog/mixcomwd.c +++ b/drivers/watchdog/mixcomwd.c | |||
@@ -29,7 +29,8 @@ | |||
29 | * - support for one more type board | 29 | * - support for one more type board |
30 | * | 30 | * |
31 | * Version 0.5 (2001/12/14) Matt Domsch <Matt_Domsch@dell.com> | 31 | * Version 0.5 (2001/12/14) Matt Domsch <Matt_Domsch@dell.com> |
32 | * - added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT | 32 | * - added nowayout module option to override |
33 | * CONFIG_WATCHDOG_NOWAYOUT | ||
33 | * | 34 | * |
34 | * Version 0.6 (2002/04/12): Rob Radez <rob@osinvestor.com> | 35 | * Version 0.6 (2002/04/12): Rob Radez <rob@osinvestor.com> |
35 | * - make mixcomwd_opened unsigned, | 36 | * - make mixcomwd_opened unsigned, |
@@ -53,8 +54,8 @@ | |||
53 | #include <linux/init.h> | 54 | #include <linux/init.h> |
54 | #include <linux/jiffies.h> | 55 | #include <linux/jiffies.h> |
55 | #include <linux/timer.h> | 56 | #include <linux/timer.h> |
56 | #include <asm/uaccess.h> | 57 | #include <linux/uaccess.h> |
57 | #include <asm/io.h> | 58 | #include <linux/io.h> |
58 | 59 | ||
59 | /* | 60 | /* |
60 | * We have two types of cards that can be probed: | 61 | * We have two types of cards that can be probed: |
@@ -108,18 +109,19 @@ static char expect_close; | |||
108 | 109 | ||
109 | static int nowayout = WATCHDOG_NOWAYOUT; | 110 | static int nowayout = WATCHDOG_NOWAYOUT; |
110 | module_param(nowayout, int, 0); | 111 | module_param(nowayout, int, 0); |
111 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 112 | MODULE_PARM_DESC(nowayout, |
113 | "Watchdog cannot be stopped once started (default=" | ||
114 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
112 | 115 | ||
113 | static void mixcomwd_ping(void) | 116 | static void mixcomwd_ping(void) |
114 | { | 117 | { |
115 | outb_p(55,watchdog_port); | 118 | outb_p(55, watchdog_port); |
116 | return; | 119 | return; |
117 | } | 120 | } |
118 | 121 | ||
119 | static void mixcomwd_timerfun(unsigned long d) | 122 | static void mixcomwd_timerfun(unsigned long d) |
120 | { | 123 | { |
121 | mixcomwd_ping(); | 124 | mixcomwd_ping(); |
122 | |||
123 | mod_timer(&mixcomwd_timer, jiffies + 5 * HZ); | 125 | mod_timer(&mixcomwd_timer, jiffies + 5 * HZ); |
124 | } | 126 | } |
125 | 127 | ||
@@ -129,22 +131,22 @@ static void mixcomwd_timerfun(unsigned long d) | |||
129 | 131 | ||
130 | static int mixcomwd_open(struct inode *inode, struct file *file) | 132 | static int mixcomwd_open(struct inode *inode, struct file *file) |
131 | { | 133 | { |
132 | if(test_and_set_bit(0,&mixcomwd_opened)) { | 134 | if (test_and_set_bit(0, &mixcomwd_opened)) |
133 | return -EBUSY; | 135 | return -EBUSY; |
134 | } | 136 | |
135 | mixcomwd_ping(); | 137 | mixcomwd_ping(); |
136 | 138 | ||
137 | if (nowayout) { | 139 | if (nowayout) |
138 | /* | 140 | /* |
139 | * fops_get() code via open() has already done | 141 | * fops_get() code via open() has already done |
140 | * a try_module_get() so it is safe to do the | 142 | * a try_module_get() so it is safe to do the |
141 | * __module_get(). | 143 | * __module_get(). |
142 | */ | 144 | */ |
143 | __module_get(THIS_MODULE); | 145 | __module_get(THIS_MODULE); |
144 | } else { | 146 | else { |
145 | if(mixcomwd_timer_alive) { | 147 | if (mixcomwd_timer_alive) { |
146 | del_timer(&mixcomwd_timer); | 148 | del_timer(&mixcomwd_timer); |
147 | mixcomwd_timer_alive=0; | 149 | mixcomwd_timer_alive = 0; |
148 | } | 150 | } |
149 | } | 151 | } |
150 | return nonseekable_open(inode, file); | 152 | return nonseekable_open(inode, file); |
@@ -153,26 +155,27 @@ static int mixcomwd_open(struct inode *inode, struct file *file) | |||
153 | static int mixcomwd_release(struct inode *inode, struct file *file) | 155 | static int mixcomwd_release(struct inode *inode, struct file *file) |
154 | { | 156 | { |
155 | if (expect_close == 42) { | 157 | if (expect_close == 42) { |
156 | if(mixcomwd_timer_alive) { | 158 | if (mixcomwd_timer_alive) { |
157 | printk(KERN_ERR PFX "release called while internal timer alive"); | 159 | printk(KERN_ERR PFX |
160 | "release called while internal timer alive"); | ||
158 | return -EBUSY; | 161 | return -EBUSY; |
159 | } | 162 | } |
160 | mixcomwd_timer_alive=1; | 163 | mixcomwd_timer_alive = 1; |
161 | mod_timer(&mixcomwd_timer, jiffies + 5 * HZ); | 164 | mod_timer(&mixcomwd_timer, jiffies + 5 * HZ); |
162 | } else { | 165 | } else |
163 | printk(KERN_CRIT PFX "WDT device closed unexpectedly. WDT will not stop!\n"); | 166 | printk(KERN_CRIT PFX |
164 | } | 167 | "WDT device closed unexpectedly. WDT will not stop!\n"); |
165 | 168 | ||
166 | clear_bit(0,&mixcomwd_opened); | 169 | clear_bit(0, &mixcomwd_opened); |
167 | expect_close=0; | 170 | expect_close = 0; |
168 | return 0; | 171 | return 0; |
169 | } | 172 | } |
170 | 173 | ||
171 | 174 | ||
172 | static ssize_t mixcomwd_write(struct file *file, const char __user *data, size_t len, loff_t *ppos) | 175 | static ssize_t mixcomwd_write(struct file *file, const char __user *data, |
176 | size_t len, loff_t *ppos) | ||
173 | { | 177 | { |
174 | if(len) | 178 | if (len) { |
175 | { | ||
176 | if (!nowayout) { | 179 | if (!nowayout) { |
177 | size_t i; | 180 | size_t i; |
178 | 181 | ||
@@ -192,8 +195,8 @@ static ssize_t mixcomwd_write(struct file *file, const char __user *data, size_t | |||
192 | return len; | 195 | return len; |
193 | } | 196 | } |
194 | 197 | ||
195 | static int mixcomwd_ioctl(struct inode *inode, struct file *file, | 198 | static long mixcomwd_ioctl(struct file *file, |
196 | unsigned int cmd, unsigned long arg) | 199 | unsigned int cmd, unsigned long arg) |
197 | { | 200 | { |
198 | void __user *argp = (void __user *)arg; | 201 | void __user *argp = (void __user *)arg; |
199 | int __user *p = argp; | 202 | int __user *p = argp; |
@@ -204,32 +207,23 @@ static int mixcomwd_ioctl(struct inode *inode, struct file *file, | |||
204 | .identity = "MixCOM watchdog", | 207 | .identity = "MixCOM watchdog", |
205 | }; | 208 | }; |
206 | 209 | ||
207 | switch(cmd) | 210 | switch (cmd) { |
208 | { | 211 | case WDIOC_GETSUPPORT: |
209 | case WDIOC_GETSTATUS: | 212 | if (copy_to_user(argp, &ident, sizeof(ident))) |
210 | status=mixcomwd_opened; | 213 | return -EFAULT; |
211 | if (!nowayout) { | 214 | break; |
212 | status|=mixcomwd_timer_alive; | 215 | case WDIOC_GETSTATUS: |
213 | } | 216 | status = mixcomwd_opened; |
214 | if (copy_to_user(p, &status, sizeof(int))) { | 217 | if (!nowayout) |
215 | return -EFAULT; | 218 | status |= mixcomwd_timer_alive; |
216 | } | 219 | return put_user(status, p); |
217 | break; | 220 | case WDIOC_GETBOOTSTATUS: |
218 | case WDIOC_GETBOOTSTATUS: | 221 | return put_user(0, p); |
219 | if (copy_to_user(p, &status, sizeof(int))) { | 222 | case WDIOC_KEEPALIVE: |
220 | return -EFAULT; | 223 | mixcomwd_ping(); |
221 | } | 224 | break; |
222 | break; | 225 | default: |
223 | case WDIOC_GETSUPPORT: | 226 | return -ENOTTY; |
224 | if (copy_to_user(argp, &ident, sizeof(ident))) { | ||
225 | return -EFAULT; | ||
226 | } | ||
227 | break; | ||
228 | case WDIOC_KEEPALIVE: | ||
229 | mixcomwd_ping(); | ||
230 | break; | ||
231 | default: | ||
232 | return -ENOTTY; | ||
233 | } | 227 | } |
234 | return 0; | 228 | return 0; |
235 | } | 229 | } |
@@ -238,7 +232,7 @@ static const struct file_operations mixcomwd_fops = { | |||
238 | .owner = THIS_MODULE, | 232 | .owner = THIS_MODULE, |
239 | .llseek = no_llseek, | 233 | .llseek = no_llseek, |
240 | .write = mixcomwd_write, | 234 | .write = mixcomwd_write, |
241 | .ioctl = mixcomwd_ioctl, | 235 | .unlocked_ioctl = mixcomwd_ioctl, |
242 | .open = mixcomwd_open, | 236 | .open = mixcomwd_open, |
243 | .release = mixcomwd_release, | 237 | .release = mixcomwd_release, |
244 | }; | 238 | }; |
@@ -253,15 +247,14 @@ static int __init checkcard(int port, int card_id) | |||
253 | { | 247 | { |
254 | int id; | 248 | int id; |
255 | 249 | ||
256 | if (!request_region(port, 1, "MixCOM watchdog")) { | 250 | if (!request_region(port, 1, "MixCOM watchdog")) |
257 | return 0; | 251 | return 0; |
258 | } | ||
259 | 252 | ||
260 | id=inb_p(port); | 253 | id = inb_p(port); |
261 | if (card_id==MIXCOM_ID) | 254 | if (card_id == MIXCOM_ID) |
262 | id &= 0x3f; | 255 | id &= 0x3f; |
263 | 256 | ||
264 | if (id!=card_id) { | 257 | if (id != card_id) { |
265 | release_region(port, 1); | 258 | release_region(port, 1); |
266 | return 0; | 259 | return 0; |
267 | } | 260 | } |
@@ -270,9 +263,7 @@ static int __init checkcard(int port, int card_id) | |||
270 | 263 | ||
271 | static int __init mixcomwd_init(void) | 264 | static int __init mixcomwd_init(void) |
272 | { | 265 | { |
273 | int i; | 266 | int i, ret, found = 0; |
274 | int ret; | ||
275 | int found=0; | ||
276 | 267 | ||
277 | for (i = 0; !found && mixcomwd_io_info[i].ioport != 0; i++) { | 268 | for (i = 0; !found && mixcomwd_io_info[i].ioport != 0; i++) { |
278 | if (checkcard(mixcomwd_io_info[i].ioport, | 269 | if (checkcard(mixcomwd_io_info[i].ioport, |
@@ -283,20 +274,22 @@ static int __init mixcomwd_init(void) | |||
283 | } | 274 | } |
284 | 275 | ||
285 | if (!found) { | 276 | if (!found) { |
286 | printk(KERN_ERR PFX "No card detected, or port not available.\n"); | 277 | printk(KERN_ERR PFX |
278 | "No card detected, or port not available.\n"); | ||
287 | return -ENODEV; | 279 | return -ENODEV; |
288 | } | 280 | } |
289 | 281 | ||
290 | ret = misc_register(&mixcomwd_miscdev); | 282 | ret = misc_register(&mixcomwd_miscdev); |
291 | if (ret) | 283 | if (ret) { |
292 | { | 284 | printk(KERN_ERR PFX |
293 | printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", | 285 | "cannot register miscdev on minor=%d (err=%d)\n", |
294 | WATCHDOG_MINOR, ret); | 286 | WATCHDOG_MINOR, ret); |
295 | goto error_misc_register_watchdog; | 287 | goto error_misc_register_watchdog; |
296 | } | 288 | } |
297 | 289 | ||
298 | printk(KERN_INFO "MixCOM watchdog driver v%s, watchdog port at 0x%3x\n", | 290 | printk(KERN_INFO |
299 | VERSION, watchdog_port); | 291 | "MixCOM watchdog driver v%s, watchdog port at 0x%3x\n", |
292 | VERSION, watchdog_port); | ||
300 | 293 | ||
301 | return 0; | 294 | return 0; |
302 | 295 | ||
@@ -309,15 +302,15 @@ error_misc_register_watchdog: | |||
309 | static void __exit mixcomwd_exit(void) | 302 | static void __exit mixcomwd_exit(void) |
310 | { | 303 | { |
311 | if (!nowayout) { | 304 | if (!nowayout) { |
312 | if(mixcomwd_timer_alive) { | 305 | if (mixcomwd_timer_alive) { |
313 | printk(KERN_WARNING PFX "I quit now, hardware will" | 306 | printk(KERN_WARNING PFX "I quit now, hardware will" |
314 | " probably reboot!\n"); | 307 | " probably reboot!\n"); |
315 | del_timer_sync(&mixcomwd_timer); | 308 | del_timer_sync(&mixcomwd_timer); |
316 | mixcomwd_timer_alive=0; | 309 | mixcomwd_timer_alive = 0; |
317 | } | 310 | } |
318 | } | 311 | } |
319 | misc_deregister(&mixcomwd_miscdev); | 312 | misc_deregister(&mixcomwd_miscdev); |
320 | release_region(watchdog_port,1); | 313 | release_region(watchdog_port, 1); |
321 | } | 314 | } |
322 | 315 | ||
323 | module_init(mixcomwd_init); | 316 | module_init(mixcomwd_init); |
diff --git a/drivers/watchdog/mpc5200_wdt.c b/drivers/watchdog/mpc5200_wdt.c index 77c1c2ae2cc2..db91892558f2 100644 --- a/drivers/watchdog/mpc5200_wdt.c +++ b/drivers/watchdog/mpc5200_wdt.c | |||
@@ -5,7 +5,7 @@ | |||
5 | #include <linux/io.h> | 5 | #include <linux/io.h> |
6 | #include <linux/spinlock.h> | 6 | #include <linux/spinlock.h> |
7 | #include <linux/of_platform.h> | 7 | #include <linux/of_platform.h> |
8 | #include <asm/uaccess.h> | 8 | #include <linux/uaccess.h> |
9 | #include <asm/mpc52xx.h> | 9 | #include <asm/mpc52xx.h> |
10 | 10 | ||
11 | 11 | ||
@@ -57,7 +57,8 @@ static int mpc5200_wdt_start(struct mpc5200_wdt *wdt) | |||
57 | /* set timeout, with maximum prescaler */ | 57 | /* set timeout, with maximum prescaler */ |
58 | out_be32(&wdt->regs->count, 0x0 | wdt->count); | 58 | out_be32(&wdt->regs->count, 0x0 | wdt->count); |
59 | /* enable watchdog */ | 59 | /* enable watchdog */ |
60 | out_be32(&wdt->regs->mode, GPT_MODE_CE | GPT_MODE_WDT | GPT_MODE_MS_TIMER); | 60 | out_be32(&wdt->regs->mode, GPT_MODE_CE | GPT_MODE_WDT | |
61 | GPT_MODE_MS_TIMER); | ||
61 | spin_unlock(&wdt->io_lock); | 62 | spin_unlock(&wdt->io_lock); |
62 | 63 | ||
63 | return 0; | 64 | return 0; |
@@ -66,7 +67,8 @@ static int mpc5200_wdt_ping(struct mpc5200_wdt *wdt) | |||
66 | { | 67 | { |
67 | spin_lock(&wdt->io_lock); | 68 | spin_lock(&wdt->io_lock); |
68 | /* writing A5 to OCPW resets the watchdog */ | 69 | /* writing A5 to OCPW resets the watchdog */ |
69 | out_be32(&wdt->regs->mode, 0xA5000000 | (0xffffff & in_be32(&wdt->regs->mode))); | 70 | out_be32(&wdt->regs->mode, 0xA5000000 | |
71 | (0xffffff & in_be32(&wdt->regs->mode))); | ||
70 | spin_unlock(&wdt->io_lock); | 72 | spin_unlock(&wdt->io_lock); |
71 | return 0; | 73 | return 0; |
72 | } | 74 | } |
@@ -92,8 +94,8 @@ static struct watchdog_info mpc5200_wdt_info = { | |||
92 | .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, | 94 | .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, |
93 | .identity = "mpc5200 watchdog on GPT0", | 95 | .identity = "mpc5200 watchdog on GPT0", |
94 | }; | 96 | }; |
95 | static int mpc5200_wdt_ioctl(struct inode *inode, struct file *file, | 97 | static long mpc5200_wdt_ioctl(struct file *file, unsigned int cmd, |
96 | unsigned int cmd, unsigned long arg) | 98 | unsigned long arg) |
97 | { | 99 | { |
98 | struct mpc5200_wdt *wdt = file->private_data; | 100 | struct mpc5200_wdt *wdt = file->private_data; |
99 | int __user *data = (int __user *)arg; | 101 | int __user *data = (int __user *)arg; |
@@ -103,7 +105,7 @@ static int mpc5200_wdt_ioctl(struct inode *inode, struct file *file, | |||
103 | switch (cmd) { | 105 | switch (cmd) { |
104 | case WDIOC_GETSUPPORT: | 106 | case WDIOC_GETSUPPORT: |
105 | ret = copy_to_user(data, &mpc5200_wdt_info, | 107 | ret = copy_to_user(data, &mpc5200_wdt_info, |
106 | sizeof(mpc5200_wdt_info)); | 108 | sizeof(mpc5200_wdt_info)); |
107 | if (ret) | 109 | if (ret) |
108 | ret = -EFAULT; | 110 | ret = -EFAULT; |
109 | break; | 111 | break; |
@@ -135,6 +137,7 @@ static int mpc5200_wdt_ioctl(struct inode *inode, struct file *file, | |||
135 | } | 137 | } |
136 | return ret; | 138 | return ret; |
137 | } | 139 | } |
140 | |||
138 | static int mpc5200_wdt_open(struct inode *inode, struct file *file) | 141 | static int mpc5200_wdt_open(struct inode *inode, struct file *file) |
139 | { | 142 | { |
140 | /* /dev/watchdog can only be opened once */ | 143 | /* /dev/watchdog can only be opened once */ |
@@ -161,13 +164,14 @@ static int mpc5200_wdt_release(struct inode *inode, struct file *file) | |||
161 | static const struct file_operations mpc5200_wdt_fops = { | 164 | static const struct file_operations mpc5200_wdt_fops = { |
162 | .owner = THIS_MODULE, | 165 | .owner = THIS_MODULE, |
163 | .write = mpc5200_wdt_write, | 166 | .write = mpc5200_wdt_write, |
164 | .ioctl = mpc5200_wdt_ioctl, | 167 | .unlocked_ioctl = mpc5200_wdt_ioctl, |
165 | .open = mpc5200_wdt_open, | 168 | .open = mpc5200_wdt_open, |
166 | .release = mpc5200_wdt_release, | 169 | .release = mpc5200_wdt_release, |
167 | }; | 170 | }; |
168 | 171 | ||
169 | /* module operations */ | 172 | /* module operations */ |
170 | static int mpc5200_wdt_probe(struct of_device *op, const struct of_device_id *match) | 173 | static int mpc5200_wdt_probe(struct of_device *op, |
174 | const struct of_device_id *match) | ||
171 | { | 175 | { |
172 | struct mpc5200_wdt *wdt; | 176 | struct mpc5200_wdt *wdt; |
173 | int err; | 177 | int err; |
@@ -215,9 +219,9 @@ static int mpc5200_wdt_probe(struct of_device *op, const struct of_device_id *ma | |||
215 | return 0; | 219 | return 0; |
216 | 220 | ||
217 | iounmap(wdt->regs); | 221 | iounmap(wdt->regs); |
218 | out_release: | 222 | out_release: |
219 | release_mem_region(wdt->mem.start, size); | 223 | release_mem_region(wdt->mem.start, size); |
220 | out_free: | 224 | out_free: |
221 | kfree(wdt); | 225 | kfree(wdt); |
222 | return err; | 226 | return err; |
223 | } | 227 | } |
diff --git a/drivers/watchdog/mpc83xx_wdt.c b/drivers/watchdog/mpc83xx_wdt.c deleted file mode 100644 index b16c5cd972eb..000000000000 --- a/drivers/watchdog/mpc83xx_wdt.c +++ /dev/null | |||
@@ -1,230 +0,0 @@ | |||
1 | /* | ||
2 | * mpc83xx_wdt.c - MPC83xx watchdog userspace interface | ||
3 | * | ||
4 | * Authors: Dave Updegraff <dave@cray.org> | ||
5 | * Kumar Gala <galak@kernel.crashing.org> | ||
6 | * Attribution: from 83xx_wst: Florian Schirmer <jolt@tuxbox.org> | ||
7 | * ..and from sc520_wdt | ||
8 | * | ||
9 | * Note: it appears that you can only actually ENABLE or DISABLE the thing | ||
10 | * once after POR. Once enabled, you cannot disable, and vice versa. | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify it | ||
13 | * under the terms of the GNU General Public License as published by the | ||
14 | * Free Software Foundation; either version 2 of the License, or (at your | ||
15 | * option) any later version. | ||
16 | */ | ||
17 | |||
18 | #include <linux/fs.h> | ||
19 | #include <linux/init.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/miscdevice.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/watchdog.h> | ||
25 | #include <asm/io.h> | ||
26 | #include <asm/uaccess.h> | ||
27 | |||
28 | struct mpc83xx_wdt { | ||
29 | __be32 res0; | ||
30 | __be32 swcrr; /* System watchdog control register */ | ||
31 | #define SWCRR_SWTC 0xFFFF0000 /* Software Watchdog Time Count. */ | ||
32 | #define SWCRR_SWEN 0x00000004 /* Watchdog Enable bit. */ | ||
33 | #define SWCRR_SWRI 0x00000002 /* Software Watchdog Reset/Interrupt Select bit.*/ | ||
34 | #define SWCRR_SWPR 0x00000001 /* Software Watchdog Counter Prescale bit. */ | ||
35 | __be32 swcnr; /* System watchdog count register */ | ||
36 | u8 res1[2]; | ||
37 | __be16 swsrr; /* System watchdog service register */ | ||
38 | u8 res2[0xF0]; | ||
39 | }; | ||
40 | |||
41 | static struct mpc83xx_wdt __iomem *wd_base; | ||
42 | |||
43 | static u16 timeout = 0xffff; | ||
44 | module_param(timeout, ushort, 0); | ||
45 | MODULE_PARM_DESC(timeout, "Watchdog timeout in ticks. (0<timeout<65536, default=65535"); | ||
46 | |||
47 | static int reset = 1; | ||
48 | module_param(reset, bool, 0); | ||
49 | MODULE_PARM_DESC(reset, "Watchdog Interrupt/Reset Mode. 0 = interrupt, 1 = reset"); | ||
50 | |||
51 | /* | ||
52 | * We always prescale, but if someone really doesn't want to they can set this | ||
53 | * to 0 | ||
54 | */ | ||
55 | static int prescale = 1; | ||
56 | static unsigned int timeout_sec; | ||
57 | |||
58 | static unsigned long wdt_is_open; | ||
59 | static DEFINE_SPINLOCK(wdt_spinlock); | ||
60 | |||
61 | static void mpc83xx_wdt_keepalive(void) | ||
62 | { | ||
63 | /* Ping the WDT */ | ||
64 | spin_lock(&wdt_spinlock); | ||
65 | out_be16(&wd_base->swsrr, 0x556c); | ||
66 | out_be16(&wd_base->swsrr, 0xaa39); | ||
67 | spin_unlock(&wdt_spinlock); | ||
68 | } | ||
69 | |||
70 | static ssize_t mpc83xx_wdt_write(struct file *file, const char __user *buf, | ||
71 | size_t count, loff_t *ppos) | ||
72 | { | ||
73 | if (count) | ||
74 | mpc83xx_wdt_keepalive(); | ||
75 | return count; | ||
76 | } | ||
77 | |||
78 | static int mpc83xx_wdt_open(struct inode *inode, struct file *file) | ||
79 | { | ||
80 | u32 tmp = SWCRR_SWEN; | ||
81 | if (test_and_set_bit(0, &wdt_is_open)) | ||
82 | return -EBUSY; | ||
83 | |||
84 | /* Once we start the watchdog we can't stop it */ | ||
85 | __module_get(THIS_MODULE); | ||
86 | |||
87 | /* Good, fire up the show */ | ||
88 | if (prescale) | ||
89 | tmp |= SWCRR_SWPR; | ||
90 | if (reset) | ||
91 | tmp |= SWCRR_SWRI; | ||
92 | |||
93 | tmp |= timeout << 16; | ||
94 | |||
95 | out_be32(&wd_base->swcrr, tmp); | ||
96 | |||
97 | return nonseekable_open(inode, file); | ||
98 | } | ||
99 | |||
100 | static int mpc83xx_wdt_release(struct inode *inode, struct file *file) | ||
101 | { | ||
102 | printk(KERN_CRIT "Unexpected close, not stopping watchdog!\n"); | ||
103 | mpc83xx_wdt_keepalive(); | ||
104 | clear_bit(0, &wdt_is_open); | ||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | static int mpc83xx_wdt_ioctl(struct inode *inode, struct file *file, | ||
109 | unsigned int cmd, unsigned long arg) | ||
110 | { | ||
111 | void __user *argp = (void __user *)arg; | ||
112 | int __user *p = argp; | ||
113 | static struct watchdog_info ident = { | ||
114 | .options = WDIOF_KEEPALIVEPING, | ||
115 | .firmware_version = 1, | ||
116 | .identity = "MPC83xx", | ||
117 | }; | ||
118 | |||
119 | switch (cmd) { | ||
120 | case WDIOC_GETSUPPORT: | ||
121 | return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; | ||
122 | case WDIOC_GETSTATUS: | ||
123 | case WDIOC_GETBOOTSTATUS: | ||
124 | return put_user(0, p); | ||
125 | case WDIOC_KEEPALIVE: | ||
126 | mpc83xx_wdt_keepalive(); | ||
127 | return 0; | ||
128 | case WDIOC_GETTIMEOUT: | ||
129 | return put_user(timeout_sec, p); | ||
130 | default: | ||
131 | return -ENOTTY; | ||
132 | } | ||
133 | } | ||
134 | |||
135 | static const struct file_operations mpc83xx_wdt_fops = { | ||
136 | .owner = THIS_MODULE, | ||
137 | .llseek = no_llseek, | ||
138 | .write = mpc83xx_wdt_write, | ||
139 | .ioctl = mpc83xx_wdt_ioctl, | ||
140 | .open = mpc83xx_wdt_open, | ||
141 | .release = mpc83xx_wdt_release, | ||
142 | }; | ||
143 | |||
144 | static struct miscdevice mpc83xx_wdt_miscdev = { | ||
145 | .minor = WATCHDOG_MINOR, | ||
146 | .name = "watchdog", | ||
147 | .fops = &mpc83xx_wdt_fops, | ||
148 | }; | ||
149 | |||
150 | static int __devinit mpc83xx_wdt_probe(struct platform_device *dev) | ||
151 | { | ||
152 | struct resource *r; | ||
153 | int ret; | ||
154 | unsigned int *freq = dev->dev.platform_data; | ||
155 | |||
156 | /* get a pointer to the register memory */ | ||
157 | r = platform_get_resource(dev, IORESOURCE_MEM, 0); | ||
158 | |||
159 | if (!r) { | ||
160 | ret = -ENODEV; | ||
161 | goto err_out; | ||
162 | } | ||
163 | |||
164 | wd_base = ioremap(r->start, sizeof (struct mpc83xx_wdt)); | ||
165 | |||
166 | if (wd_base == NULL) { | ||
167 | ret = -ENOMEM; | ||
168 | goto err_out; | ||
169 | } | ||
170 | |||
171 | ret = misc_register(&mpc83xx_wdt_miscdev); | ||
172 | if (ret) { | ||
173 | printk(KERN_ERR "cannot register miscdev on minor=%d " | ||
174 | "(err=%d)\n", | ||
175 | WATCHDOG_MINOR, ret); | ||
176 | goto err_unmap; | ||
177 | } | ||
178 | |||
179 | /* Calculate the timeout in seconds */ | ||
180 | if (prescale) | ||
181 | timeout_sec = (timeout * 0x10000) / (*freq); | ||
182 | else | ||
183 | timeout_sec = timeout / (*freq); | ||
184 | |||
185 | printk(KERN_INFO "WDT driver for MPC83xx initialized. " | ||
186 | "mode:%s timeout=%d (%d seconds)\n", | ||
187 | reset ? "reset":"interrupt", timeout, timeout_sec); | ||
188 | return 0; | ||
189 | |||
190 | err_unmap: | ||
191 | iounmap(wd_base); | ||
192 | err_out: | ||
193 | return ret; | ||
194 | } | ||
195 | |||
196 | static int __devexit mpc83xx_wdt_remove(struct platform_device *dev) | ||
197 | { | ||
198 | misc_deregister(&mpc83xx_wdt_miscdev); | ||
199 | iounmap(wd_base); | ||
200 | |||
201 | return 0; | ||
202 | } | ||
203 | |||
204 | static struct platform_driver mpc83xx_wdt_driver = { | ||
205 | .probe = mpc83xx_wdt_probe, | ||
206 | .remove = __devexit_p(mpc83xx_wdt_remove), | ||
207 | .driver = { | ||
208 | .name = "mpc83xx_wdt", | ||
209 | .owner = THIS_MODULE, | ||
210 | }, | ||
211 | }; | ||
212 | |||
213 | static int __init mpc83xx_wdt_init(void) | ||
214 | { | ||
215 | return platform_driver_register(&mpc83xx_wdt_driver); | ||
216 | } | ||
217 | |||
218 | static void __exit mpc83xx_wdt_exit(void) | ||
219 | { | ||
220 | platform_driver_unregister(&mpc83xx_wdt_driver); | ||
221 | } | ||
222 | |||
223 | module_init(mpc83xx_wdt_init); | ||
224 | module_exit(mpc83xx_wdt_exit); | ||
225 | |||
226 | MODULE_AUTHOR("Dave Updegraff, Kumar Gala"); | ||
227 | MODULE_DESCRIPTION("Driver for watchdog timer in MPC83xx uProcessor"); | ||
228 | MODULE_LICENSE("GPL"); | ||
229 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); | ||
230 | MODULE_ALIAS("platform:mpc83xx_wdt"); | ||
diff --git a/drivers/watchdog/mpc8xx_wdt.c b/drivers/watchdog/mpc8xx_wdt.c index 85b5734403a5..1336425acf20 100644 --- a/drivers/watchdog/mpc8xx_wdt.c +++ b/drivers/watchdog/mpc8xx_wdt.c | |||
@@ -16,36 +16,35 @@ | |||
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <linux/watchdog.h> | 17 | #include <linux/watchdog.h> |
18 | #include <asm/8xx_immap.h> | 18 | #include <asm/8xx_immap.h> |
19 | #include <asm/uaccess.h> | 19 | #include <linux/uaccess.h> |
20 | #include <asm/io.h> | 20 | #include <linux/io.h> |
21 | #include <syslib/m8xx_wdt.h> | 21 | #include <syslib/m8xx_wdt.h> |
22 | 22 | ||
23 | static unsigned long wdt_opened; | 23 | static unsigned long wdt_opened; |
24 | static int wdt_status; | 24 | static int wdt_status; |
25 | static spinlock_t wdt_lock; | ||
25 | 26 | ||
26 | static void mpc8xx_wdt_handler_disable(void) | 27 | static void mpc8xx_wdt_handler_disable(void) |
27 | { | 28 | { |
28 | volatile uint __iomem *piscr; | 29 | volatile uint __iomem *piscr; |
29 | piscr = (uint *)&((immap_t*)IMAP_ADDR)->im_sit.sit_piscr; | 30 | piscr = (uint *)&((immap_t *)IMAP_ADDR)->im_sit.sit_piscr; |
30 | 31 | ||
31 | if (!m8xx_has_internal_rtc) | 32 | if (!m8xx_has_internal_rtc) |
32 | m8xx_wdt_stop_timer(); | 33 | m8xx_wdt_stop_timer(); |
33 | else | 34 | else |
34 | out_be32(piscr, in_be32(piscr) & ~(PISCR_PIE | PISCR_PTE)); | 35 | out_be32(piscr, in_be32(piscr) & ~(PISCR_PIE | PISCR_PTE)); |
35 | |||
36 | printk(KERN_NOTICE "mpc8xx_wdt: keep-alive handler deactivated\n"); | 36 | printk(KERN_NOTICE "mpc8xx_wdt: keep-alive handler deactivated\n"); |
37 | } | 37 | } |
38 | 38 | ||
39 | static void mpc8xx_wdt_handler_enable(void) | 39 | static void mpc8xx_wdt_handler_enable(void) |
40 | { | 40 | { |
41 | volatile uint __iomem *piscr; | 41 | volatile uint __iomem *piscr; |
42 | piscr = (uint *)&((immap_t*)IMAP_ADDR)->im_sit.sit_piscr; | 42 | piscr = (uint *)&((immap_t *)IMAP_ADDR)->im_sit.sit_piscr; |
43 | 43 | ||
44 | if (!m8xx_has_internal_rtc) | 44 | if (!m8xx_has_internal_rtc) |
45 | m8xx_wdt_install_timer(); | 45 | m8xx_wdt_install_timer(); |
46 | else | 46 | else |
47 | out_be32(piscr, in_be32(piscr) | PISCR_PIE | PISCR_PTE); | 47 | out_be32(piscr, in_be32(piscr) | PISCR_PIE | PISCR_PTE); |
48 | |||
49 | printk(KERN_NOTICE "mpc8xx_wdt: keep-alive handler activated\n"); | 48 | printk(KERN_NOTICE "mpc8xx_wdt: keep-alive handler activated\n"); |
50 | } | 49 | } |
51 | 50 | ||
@@ -53,37 +52,34 @@ static int mpc8xx_wdt_open(struct inode *inode, struct file *file) | |||
53 | { | 52 | { |
54 | if (test_and_set_bit(0, &wdt_opened)) | 53 | if (test_and_set_bit(0, &wdt_opened)) |
55 | return -EBUSY; | 54 | return -EBUSY; |
56 | |||
57 | m8xx_wdt_reset(); | 55 | m8xx_wdt_reset(); |
58 | mpc8xx_wdt_handler_disable(); | 56 | mpc8xx_wdt_handler_disable(); |
59 | |||
60 | return nonseekable_open(inode, file); | 57 | return nonseekable_open(inode, file); |
61 | } | 58 | } |
62 | 59 | ||
63 | static int mpc8xx_wdt_release(struct inode *inode, struct file *file) | 60 | static int mpc8xx_wdt_release(struct inode *inode, struct file *file) |
64 | { | 61 | { |
65 | m8xx_wdt_reset(); | 62 | m8xx_wdt_reset(); |
66 | |||
67 | #if !defined(CONFIG_WATCHDOG_NOWAYOUT) | 63 | #if !defined(CONFIG_WATCHDOG_NOWAYOUT) |
68 | mpc8xx_wdt_handler_enable(); | 64 | mpc8xx_wdt_handler_enable(); |
69 | #endif | 65 | #endif |
70 | |||
71 | clear_bit(0, &wdt_opened); | 66 | clear_bit(0, &wdt_opened); |
72 | |||
73 | return 0; | 67 | return 0; |
74 | } | 68 | } |
75 | 69 | ||
76 | static ssize_t mpc8xx_wdt_write(struct file *file, const char *data, size_t len, | 70 | static ssize_t mpc8xx_wdt_write(struct file *file, const char *data, |
77 | loff_t * ppos) | 71 | size_t len, loff_t *ppos) |
78 | { | 72 | { |
79 | if (len) | 73 | if (len) { |
74 | spin_lock(&wdt_lock); | ||
80 | m8xx_wdt_reset(); | 75 | m8xx_wdt_reset(); |
81 | 76 | spin_unlock(&wdt_lock); | |
77 | } | ||
82 | return len; | 78 | return len; |
83 | } | 79 | } |
84 | 80 | ||
85 | static int mpc8xx_wdt_ioctl(struct inode *inode, struct file *file, | 81 | static long mpc8xx_wdt_ioctl(struct file *file, |
86 | unsigned int cmd, unsigned long arg) | 82 | unsigned int cmd, unsigned long arg) |
87 | { | 83 | { |
88 | int timeout; | 84 | int timeout; |
89 | static struct watchdog_info info = { | 85 | static struct watchdog_info info = { |
@@ -112,15 +108,19 @@ static int mpc8xx_wdt_ioctl(struct inode *inode, struct file *file, | |||
112 | return -EOPNOTSUPP; | 108 | return -EOPNOTSUPP; |
113 | 109 | ||
114 | case WDIOC_KEEPALIVE: | 110 | case WDIOC_KEEPALIVE: |
111 | spin_lock(&wdt_lock); | ||
115 | m8xx_wdt_reset(); | 112 | m8xx_wdt_reset(); |
116 | wdt_status |= WDIOF_KEEPALIVEPING; | 113 | wdt_status |= WDIOF_KEEPALIVEPING; |
114 | spin_unlock(&wdt_lock); | ||
117 | break; | 115 | break; |
118 | 116 | ||
119 | case WDIOC_SETTIMEOUT: | 117 | case WDIOC_SETTIMEOUT: |
120 | return -EOPNOTSUPP; | 118 | return -EOPNOTSUPP; |
121 | 119 | ||
122 | case WDIOC_GETTIMEOUT: | 120 | case WDIOC_GETTIMEOUT: |
121 | spin_lock(&wdt_lock); | ||
123 | timeout = m8xx_wdt_get_timeout(); | 122 | timeout = m8xx_wdt_get_timeout(); |
123 | spin_unlock(&wdt_lock); | ||
124 | if (put_user(timeout, (int *)arg)) | 124 | if (put_user(timeout, (int *)arg)) |
125 | return -EFAULT; | 125 | return -EFAULT; |
126 | break; | 126 | break; |
@@ -136,7 +136,7 @@ static const struct file_operations mpc8xx_wdt_fops = { | |||
136 | .owner = THIS_MODULE, | 136 | .owner = THIS_MODULE, |
137 | .llseek = no_llseek, | 137 | .llseek = no_llseek, |
138 | .write = mpc8xx_wdt_write, | 138 | .write = mpc8xx_wdt_write, |
139 | .ioctl = mpc8xx_wdt_ioctl, | 139 | .unlocked_ioctl = mpc8xx_wdt_ioctl, |
140 | .open = mpc8xx_wdt_open, | 140 | .open = mpc8xx_wdt_open, |
141 | .release = mpc8xx_wdt_release, | 141 | .release = mpc8xx_wdt_release, |
142 | }; | 142 | }; |
@@ -149,6 +149,7 @@ static struct miscdevice mpc8xx_wdt_miscdev = { | |||
149 | 149 | ||
150 | static int __init mpc8xx_wdt_init(void) | 150 | static int __init mpc8xx_wdt_init(void) |
151 | { | 151 | { |
152 | spin_lock_init(&wdt_lock); | ||
152 | return misc_register(&mpc8xx_wdt_miscdev); | 153 | return misc_register(&mpc8xx_wdt_miscdev); |
153 | } | 154 | } |
154 | 155 | ||
diff --git a/drivers/watchdog/mpc8xxx_wdt.c b/drivers/watchdog/mpc8xxx_wdt.c new file mode 100644 index 000000000000..f2094960e662 --- /dev/null +++ b/drivers/watchdog/mpc8xxx_wdt.c | |||
@@ -0,0 +1,316 @@ | |||
1 | /* | ||
2 | * mpc8xxx_wdt.c - MPC8xx/MPC83xx/MPC86xx watchdog userspace interface | ||
3 | * | ||
4 | * Authors: Dave Updegraff <dave@cray.org> | ||
5 | * Kumar Gala <galak@kernel.crashing.org> | ||
6 | * Attribution: from 83xx_wst: Florian Schirmer <jolt@tuxbox.org> | ||
7 | * ..and from sc520_wdt | ||
8 | * Copyright (c) 2008 MontaVista Software, Inc. | ||
9 | * Anton Vorontsov <avorontsov@ru.mvista.com> | ||
10 | * | ||
11 | * Note: it appears that you can only actually ENABLE or DISABLE the thing | ||
12 | * once after POR. Once enabled, you cannot disable, and vice versa. | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or modify it | ||
15 | * under the terms of the GNU General Public License as published by the | ||
16 | * Free Software Foundation; either version 2 of the License, or (at your | ||
17 | * option) any later version. | ||
18 | */ | ||
19 | |||
20 | #include <linux/fs.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/kernel.h> | ||
23 | #include <linux/timer.h> | ||
24 | #include <linux/miscdevice.h> | ||
25 | #include <linux/of_platform.h> | ||
26 | #include <linux/module.h> | ||
27 | #include <linux/watchdog.h> | ||
28 | #include <linux/io.h> | ||
29 | #include <linux/uaccess.h> | ||
30 | #include <sysdev/fsl_soc.h> | ||
31 | |||
32 | struct mpc8xxx_wdt { | ||
33 | __be32 res0; | ||
34 | __be32 swcrr; /* System watchdog control register */ | ||
35 | #define SWCRR_SWTC 0xFFFF0000 /* Software Watchdog Time Count. */ | ||
36 | #define SWCRR_SWEN 0x00000004 /* Watchdog Enable bit. */ | ||
37 | #define SWCRR_SWRI 0x00000002 /* Software Watchdog Reset/Interrupt Select bit.*/ | ||
38 | #define SWCRR_SWPR 0x00000001 /* Software Watchdog Counter Prescale bit. */ | ||
39 | __be32 swcnr; /* System watchdog count register */ | ||
40 | u8 res1[2]; | ||
41 | __be16 swsrr; /* System watchdog service register */ | ||
42 | u8 res2[0xF0]; | ||
43 | }; | ||
44 | |||
45 | struct mpc8xxx_wdt_type { | ||
46 | int prescaler; | ||
47 | bool hw_enabled; | ||
48 | }; | ||
49 | |||
50 | static struct mpc8xxx_wdt __iomem *wd_base; | ||
51 | |||
52 | static u16 timeout = 0xffff; | ||
53 | module_param(timeout, ushort, 0); | ||
54 | MODULE_PARM_DESC(timeout, | ||
55 | "Watchdog timeout in ticks. (0<timeout<65536, default=65535"); | ||
56 | |||
57 | static int reset = 1; | ||
58 | module_param(reset, bool, 0); | ||
59 | MODULE_PARM_DESC(reset, | ||
60 | "Watchdog Interrupt/Reset Mode. 0 = interrupt, 1 = reset"); | ||
61 | |||
62 | static int nowayout = WATCHDOG_NOWAYOUT; | ||
63 | module_param(nowayout, int, 0); | ||
64 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started " | ||
65 | "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
66 | |||
67 | /* | ||
68 | * We always prescale, but if someone really doesn't want to they can set this | ||
69 | * to 0 | ||
70 | */ | ||
71 | static int prescale = 1; | ||
72 | static unsigned int timeout_sec; | ||
73 | |||
74 | static unsigned long wdt_is_open; | ||
75 | static DEFINE_SPINLOCK(wdt_spinlock); | ||
76 | |||
77 | static void mpc8xxx_wdt_keepalive(void) | ||
78 | { | ||
79 | /* Ping the WDT */ | ||
80 | spin_lock(&wdt_spinlock); | ||
81 | out_be16(&wd_base->swsrr, 0x556c); | ||
82 | out_be16(&wd_base->swsrr, 0xaa39); | ||
83 | spin_unlock(&wdt_spinlock); | ||
84 | } | ||
85 | |||
86 | static void mpc8xxx_wdt_timer_ping(unsigned long arg); | ||
87 | static DEFINE_TIMER(wdt_timer, mpc8xxx_wdt_timer_ping, 0, 0); | ||
88 | |||
89 | static void mpc8xxx_wdt_timer_ping(unsigned long arg) | ||
90 | { | ||
91 | mpc8xxx_wdt_keepalive(); | ||
92 | /* We're pinging it twice faster than needed, just to be sure. */ | ||
93 | mod_timer(&wdt_timer, jiffies + HZ * timeout_sec / 2); | ||
94 | } | ||
95 | |||
96 | static void mpc8xxx_wdt_pr_warn(const char *msg) | ||
97 | { | ||
98 | pr_crit("mpc8xxx_wdt: %s, expect the %s soon!\n", msg, | ||
99 | reset ? "reset" : "machine check exception"); | ||
100 | } | ||
101 | |||
102 | static ssize_t mpc8xxx_wdt_write(struct file *file, const char __user *buf, | ||
103 | size_t count, loff_t *ppos) | ||
104 | { | ||
105 | if (count) | ||
106 | mpc8xxx_wdt_keepalive(); | ||
107 | return count; | ||
108 | } | ||
109 | |||
110 | static int mpc8xxx_wdt_open(struct inode *inode, struct file *file) | ||
111 | { | ||
112 | u32 tmp = SWCRR_SWEN; | ||
113 | if (test_and_set_bit(0, &wdt_is_open)) | ||
114 | return -EBUSY; | ||
115 | |||
116 | /* Once we start the watchdog we can't stop it */ | ||
117 | if (nowayout) | ||
118 | __module_get(THIS_MODULE); | ||
119 | |||
120 | /* Good, fire up the show */ | ||
121 | if (prescale) | ||
122 | tmp |= SWCRR_SWPR; | ||
123 | if (reset) | ||
124 | tmp |= SWCRR_SWRI; | ||
125 | |||
126 | tmp |= timeout << 16; | ||
127 | |||
128 | out_be32(&wd_base->swcrr, tmp); | ||
129 | |||
130 | del_timer_sync(&wdt_timer); | ||
131 | |||
132 | return nonseekable_open(inode, file); | ||
133 | } | ||
134 | |||
135 | static int mpc8xxx_wdt_release(struct inode *inode, struct file *file) | ||
136 | { | ||
137 | if (!nowayout) | ||
138 | mpc8xxx_wdt_timer_ping(0); | ||
139 | else | ||
140 | mpc8xxx_wdt_pr_warn("watchdog closed"); | ||
141 | clear_bit(0, &wdt_is_open); | ||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | static long mpc8xxx_wdt_ioctl(struct file *file, unsigned int cmd, | ||
146 | unsigned long arg) | ||
147 | { | ||
148 | void __user *argp = (void __user *)arg; | ||
149 | int __user *p = argp; | ||
150 | static struct watchdog_info ident = { | ||
151 | .options = WDIOF_KEEPALIVEPING, | ||
152 | .firmware_version = 1, | ||
153 | .identity = "MPC8xxx", | ||
154 | }; | ||
155 | |||
156 | switch (cmd) { | ||
157 | case WDIOC_GETSUPPORT: | ||
158 | return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; | ||
159 | case WDIOC_GETSTATUS: | ||
160 | case WDIOC_GETBOOTSTATUS: | ||
161 | return put_user(0, p); | ||
162 | case WDIOC_KEEPALIVE: | ||
163 | mpc8xxx_wdt_keepalive(); | ||
164 | return 0; | ||
165 | case WDIOC_GETTIMEOUT: | ||
166 | return put_user(timeout_sec, p); | ||
167 | default: | ||
168 | return -ENOTTY; | ||
169 | } | ||
170 | } | ||
171 | |||
172 | static const struct file_operations mpc8xxx_wdt_fops = { | ||
173 | .owner = THIS_MODULE, | ||
174 | .llseek = no_llseek, | ||
175 | .write = mpc8xxx_wdt_write, | ||
176 | .unlocked_ioctl = mpc8xxx_wdt_ioctl, | ||
177 | .open = mpc8xxx_wdt_open, | ||
178 | .release = mpc8xxx_wdt_release, | ||
179 | }; | ||
180 | |||
181 | static struct miscdevice mpc8xxx_wdt_miscdev = { | ||
182 | .minor = WATCHDOG_MINOR, | ||
183 | .name = "watchdog", | ||
184 | .fops = &mpc8xxx_wdt_fops, | ||
185 | }; | ||
186 | |||
187 | static int __devinit mpc8xxx_wdt_probe(struct of_device *ofdev, | ||
188 | const struct of_device_id *match) | ||
189 | { | ||
190 | int ret; | ||
191 | struct device_node *np = ofdev->node; | ||
192 | struct mpc8xxx_wdt_type *wdt_type = match->data; | ||
193 | u32 freq = fsl_get_sys_freq(); | ||
194 | bool enabled; | ||
195 | |||
196 | if (!freq || freq == -1) | ||
197 | return -EINVAL; | ||
198 | |||
199 | wd_base = of_iomap(np, 0); | ||
200 | if (!wd_base) | ||
201 | return -ENOMEM; | ||
202 | |||
203 | enabled = in_be32(&wd_base->swcrr) & SWCRR_SWEN; | ||
204 | if (!enabled && wdt_type->hw_enabled) { | ||
205 | pr_info("mpc8xxx_wdt: could not be enabled in software\n"); | ||
206 | ret = -ENOSYS; | ||
207 | goto err_unmap; | ||
208 | } | ||
209 | |||
210 | /* Calculate the timeout in seconds */ | ||
211 | if (prescale) | ||
212 | timeout_sec = (timeout * wdt_type->prescaler) / freq; | ||
213 | else | ||
214 | timeout_sec = timeout / freq; | ||
215 | |||
216 | pr_info("WDT driver for MPC8xxx initialized. mode:%s timeout=%d " | ||
217 | "(%d seconds)\n", reset ? "reset" : "interrupt", timeout, | ||
218 | timeout_sec); | ||
219 | |||
220 | /* | ||
221 | * If the watchdog was previously enabled or we're running on | ||
222 | * MPC8xxx, we should ping the wdt from the kernel until the | ||
223 | * userspace handles it. | ||
224 | */ | ||
225 | if (enabled) | ||
226 | mpc8xxx_wdt_timer_ping(0); | ||
227 | return 0; | ||
228 | err_unmap: | ||
229 | iounmap(wd_base); | ||
230 | wd_base = NULL; | ||
231 | return ret; | ||
232 | } | ||
233 | |||
234 | static int __devexit mpc8xxx_wdt_remove(struct of_device *ofdev) | ||
235 | { | ||
236 | mpc8xxx_wdt_pr_warn("watchdog removed"); | ||
237 | del_timer_sync(&wdt_timer); | ||
238 | misc_deregister(&mpc8xxx_wdt_miscdev); | ||
239 | iounmap(wd_base); | ||
240 | |||
241 | return 0; | ||
242 | } | ||
243 | |||
244 | static const struct of_device_id mpc8xxx_wdt_match[] = { | ||
245 | { | ||
246 | .compatible = "mpc83xx_wdt", | ||
247 | .data = &(struct mpc8xxx_wdt_type) { | ||
248 | .prescaler = 0x10000, | ||
249 | }, | ||
250 | }, | ||
251 | { | ||
252 | .compatible = "fsl,mpc8610-wdt", | ||
253 | .data = &(struct mpc8xxx_wdt_type) { | ||
254 | .prescaler = 0x10000, | ||
255 | .hw_enabled = true, | ||
256 | }, | ||
257 | }, | ||
258 | { | ||
259 | .compatible = "fsl,mpc823-wdt", | ||
260 | .data = &(struct mpc8xxx_wdt_type) { | ||
261 | .prescaler = 0x800, | ||
262 | }, | ||
263 | }, | ||
264 | {}, | ||
265 | }; | ||
266 | MODULE_DEVICE_TABLE(of, mpc8xxx_wdt_match); | ||
267 | |||
268 | static struct of_platform_driver mpc8xxx_wdt_driver = { | ||
269 | .match_table = mpc8xxx_wdt_match, | ||
270 | .probe = mpc8xxx_wdt_probe, | ||
271 | .remove = __devexit_p(mpc8xxx_wdt_remove), | ||
272 | .driver = { | ||
273 | .name = "mpc8xxx_wdt", | ||
274 | .owner = THIS_MODULE, | ||
275 | }, | ||
276 | }; | ||
277 | |||
278 | /* | ||
279 | * We do wdt initialization in two steps: arch_initcall probes the wdt | ||
280 | * very early to start pinging the watchdog (misc devices are not yet | ||
281 | * available), and later module_init() just registers the misc device. | ||
282 | */ | ||
283 | static int __init mpc8xxx_wdt_init_late(void) | ||
284 | { | ||
285 | int ret; | ||
286 | |||
287 | if (!wd_base) | ||
288 | return -ENODEV; | ||
289 | |||
290 | ret = misc_register(&mpc8xxx_wdt_miscdev); | ||
291 | if (ret) { | ||
292 | pr_err("cannot register miscdev on minor=%d (err=%d)\n", | ||
293 | WATCHDOG_MINOR, ret); | ||
294 | return ret; | ||
295 | } | ||
296 | return 0; | ||
297 | } | ||
298 | module_init(mpc8xxx_wdt_init_late); | ||
299 | |||
300 | static int __init mpc8xxx_wdt_init(void) | ||
301 | { | ||
302 | return of_register_platform_driver(&mpc8xxx_wdt_driver); | ||
303 | } | ||
304 | arch_initcall(mpc8xxx_wdt_init); | ||
305 | |||
306 | static void __exit mpc8xxx_wdt_exit(void) | ||
307 | { | ||
308 | of_unregister_platform_driver(&mpc8xxx_wdt_driver); | ||
309 | } | ||
310 | module_exit(mpc8xxx_wdt_exit); | ||
311 | |||
312 | MODULE_AUTHOR("Dave Updegraff, Kumar Gala"); | ||
313 | MODULE_DESCRIPTION("Driver for watchdog timer in MPC8xx/MPC83xx/MPC86xx " | ||
314 | "uProcessors"); | ||
315 | MODULE_LICENSE("GPL"); | ||
316 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); | ||
diff --git a/drivers/watchdog/mpcore_wdt.c b/drivers/watchdog/mpcore_wdt.c index 009573b81496..2a9bfa81f9d6 100644 --- a/drivers/watchdog/mpcore_wdt.c +++ b/drivers/watchdog/mpcore_wdt.c | |||
@@ -29,9 +29,9 @@ | |||
29 | #include <linux/init.h> | 29 | #include <linux/init.h> |
30 | #include <linux/interrupt.h> | 30 | #include <linux/interrupt.h> |
31 | #include <linux/platform_device.h> | 31 | #include <linux/platform_device.h> |
32 | #include <linux/uaccess.h> | ||
32 | 33 | ||
33 | #include <asm/hardware/arm_twd.h> | 34 | #include <asm/hardware/arm_twd.h> |
34 | #include <asm/uaccess.h> | ||
35 | 35 | ||
36 | struct mpcore_wdt { | 36 | struct mpcore_wdt { |
37 | unsigned long timer_alive; | 37 | unsigned long timer_alive; |
@@ -43,17 +43,20 @@ struct mpcore_wdt { | |||
43 | }; | 43 | }; |
44 | 44 | ||
45 | static struct platform_device *mpcore_wdt_dev; | 45 | static struct platform_device *mpcore_wdt_dev; |
46 | |||
47 | extern unsigned int mpcore_timer_rate; | 46 | extern unsigned int mpcore_timer_rate; |
48 | 47 | ||
49 | #define TIMER_MARGIN 60 | 48 | #define TIMER_MARGIN 60 |
50 | static int mpcore_margin = TIMER_MARGIN; | 49 | static int mpcore_margin = TIMER_MARGIN; |
51 | module_param(mpcore_margin, int, 0); | 50 | module_param(mpcore_margin, int, 0); |
52 | MODULE_PARM_DESC(mpcore_margin, "MPcore timer margin in seconds. (0<mpcore_margin<65536, default=" __MODULE_STRING(TIMER_MARGIN) ")"); | 51 | MODULE_PARM_DESC(mpcore_margin, |
52 | "MPcore timer margin in seconds. (0 < mpcore_margin < 65536, default=" | ||
53 | __MODULE_STRING(TIMER_MARGIN) ")"); | ||
53 | 54 | ||
54 | static int nowayout = WATCHDOG_NOWAYOUT; | 55 | static int nowayout = WATCHDOG_NOWAYOUT; |
55 | module_param(nowayout, int, 0); | 56 | module_param(nowayout, int, 0); |
56 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 57 | MODULE_PARM_DESC(nowayout, |
58 | "Watchdog cannot be stopped once started (default=" | ||
59 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
57 | 60 | ||
58 | #define ONLY_TESTING 0 | 61 | #define ONLY_TESTING 0 |
59 | static int mpcore_noboot = ONLY_TESTING; | 62 | static int mpcore_noboot = ONLY_TESTING; |
@@ -70,14 +73,12 @@ static irqreturn_t mpcore_wdt_fire(int irq, void *arg) | |||
70 | 73 | ||
71 | /* Check it really was our interrupt */ | 74 | /* Check it really was our interrupt */ |
72 | if (readl(wdt->base + TWD_WDOG_INTSTAT)) { | 75 | if (readl(wdt->base + TWD_WDOG_INTSTAT)) { |
73 | dev_printk(KERN_CRIT, wdt->dev, "Triggered - Reboot ignored.\n"); | 76 | dev_printk(KERN_CRIT, wdt->dev, |
74 | 77 | "Triggered - Reboot ignored.\n"); | |
75 | /* Clear the interrupt on the watchdog */ | 78 | /* Clear the interrupt on the watchdog */ |
76 | writel(1, wdt->base + TWD_WDOG_INTSTAT); | 79 | writel(1, wdt->base + TWD_WDOG_INTSTAT); |
77 | |||
78 | return IRQ_HANDLED; | 80 | return IRQ_HANDLED; |
79 | } | 81 | } |
80 | |||
81 | return IRQ_NONE; | 82 | return IRQ_NONE; |
82 | } | 83 | } |
83 | 84 | ||
@@ -96,22 +97,26 @@ static void mpcore_wdt_keepalive(struct mpcore_wdt *wdt) | |||
96 | count = (mpcore_timer_rate / 256) * mpcore_margin; | 97 | count = (mpcore_timer_rate / 256) * mpcore_margin; |
97 | 98 | ||
98 | /* Reload the counter */ | 99 | /* Reload the counter */ |
100 | spin_lock(&wdt_lock); | ||
99 | writel(count + wdt->perturb, wdt->base + TWD_WDOG_LOAD); | 101 | writel(count + wdt->perturb, wdt->base + TWD_WDOG_LOAD); |
100 | |||
101 | wdt->perturb = wdt->perturb ? 0 : 1; | 102 | wdt->perturb = wdt->perturb ? 0 : 1; |
103 | spin_unlock(&wdt_lock); | ||
102 | } | 104 | } |
103 | 105 | ||
104 | static void mpcore_wdt_stop(struct mpcore_wdt *wdt) | 106 | static void mpcore_wdt_stop(struct mpcore_wdt *wdt) |
105 | { | 107 | { |
108 | spin_lock(&wdt_lock); | ||
106 | writel(0x12345678, wdt->base + TWD_WDOG_DISABLE); | 109 | writel(0x12345678, wdt->base + TWD_WDOG_DISABLE); |
107 | writel(0x87654321, wdt->base + TWD_WDOG_DISABLE); | 110 | writel(0x87654321, wdt->base + TWD_WDOG_DISABLE); |
108 | writel(0x0, wdt->base + TWD_WDOG_CONTROL); | 111 | writel(0x0, wdt->base + TWD_WDOG_CONTROL); |
112 | spin_unlock(&wdt_lock); | ||
109 | } | 113 | } |
110 | 114 | ||
111 | static void mpcore_wdt_start(struct mpcore_wdt *wdt) | 115 | static void mpcore_wdt_start(struct mpcore_wdt *wdt) |
112 | { | 116 | { |
113 | dev_printk(KERN_INFO, wdt->dev, "enabling watchdog.\n"); | 117 | dev_printk(KERN_INFO, wdt->dev, "enabling watchdog.\n"); |
114 | 118 | ||
119 | spin_lock(&wdt_lock); | ||
115 | /* This loads the count register but does NOT start the count yet */ | 120 | /* This loads the count register but does NOT start the count yet */ |
116 | mpcore_wdt_keepalive(wdt); | 121 | mpcore_wdt_keepalive(wdt); |
117 | 122 | ||
@@ -122,6 +127,7 @@ static void mpcore_wdt_start(struct mpcore_wdt *wdt) | |||
122 | /* Enable watchdog - prescale=256, watchdog mode=1, enable=1 */ | 127 | /* Enable watchdog - prescale=256, watchdog mode=1, enable=1 */ |
123 | writel(0x0000FF09, wdt->base + TWD_WDOG_CONTROL); | 128 | writel(0x0000FF09, wdt->base + TWD_WDOG_CONTROL); |
124 | } | 129 | } |
130 | spin_unlock(&wdt_lock); | ||
125 | } | 131 | } |
126 | 132 | ||
127 | static int mpcore_wdt_set_heartbeat(int t) | 133 | static int mpcore_wdt_set_heartbeat(int t) |
@@ -164,10 +170,11 @@ static int mpcore_wdt_release(struct inode *inode, struct file *file) | |||
164 | * Shut off the timer. | 170 | * Shut off the timer. |
165 | * Lock it in if it's a module and we set nowayout | 171 | * Lock it in if it's a module and we set nowayout |
166 | */ | 172 | */ |
167 | if (wdt->expect_close == 42) { | 173 | if (wdt->expect_close == 42) |
168 | mpcore_wdt_stop(wdt); | 174 | mpcore_wdt_stop(wdt); |
169 | } else { | 175 | else { |
170 | dev_printk(KERN_CRIT, wdt->dev, "unexpected close, not stopping watchdog!\n"); | 176 | dev_printk(KERN_CRIT, wdt->dev, |
177 | "unexpected close, not stopping watchdog!\n"); | ||
171 | mpcore_wdt_keepalive(wdt); | 178 | mpcore_wdt_keepalive(wdt); |
172 | } | 179 | } |
173 | clear_bit(0, &wdt->timer_alive); | 180 | clear_bit(0, &wdt->timer_alive); |
@@ -175,7 +182,8 @@ static int mpcore_wdt_release(struct inode *inode, struct file *file) | |||
175 | return 0; | 182 | return 0; |
176 | } | 183 | } |
177 | 184 | ||
178 | static ssize_t mpcore_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos) | 185 | static ssize_t mpcore_wdt_write(struct file *file, const char *data, |
186 | size_t len, loff_t *ppos) | ||
179 | { | 187 | { |
180 | struct mpcore_wdt *wdt = file->private_data; | 188 | struct mpcore_wdt *wdt = file->private_data; |
181 | 189 | ||
@@ -210,8 +218,8 @@ static struct watchdog_info ident = { | |||
210 | .identity = "MPcore Watchdog", | 218 | .identity = "MPcore Watchdog", |
211 | }; | 219 | }; |
212 | 220 | ||
213 | static int mpcore_wdt_ioctl(struct inode *inode, struct file *file, | 221 | static long mpcore_wdt_ioctl(struct file *file, unsigned int cmd, |
214 | unsigned int cmd, unsigned long arg) | 222 | unsigned long arg) |
215 | { | 223 | { |
216 | struct mpcore_wdt *wdt = file->private_data; | 224 | struct mpcore_wdt *wdt = file->private_data; |
217 | int ret; | 225 | int ret; |
@@ -235,6 +243,12 @@ static int mpcore_wdt_ioctl(struct inode *inode, struct file *file, | |||
235 | ret = 0; | 243 | ret = 0; |
236 | break; | 244 | break; |
237 | 245 | ||
246 | case WDIOC_GETSTATUS: | ||
247 | case WDIOC_GETBOOTSTATUS: | ||
248 | uarg.i = 0; | ||
249 | ret = 0; | ||
250 | break; | ||
251 | |||
238 | case WDIOC_SETOPTIONS: | 252 | case WDIOC_SETOPTIONS: |
239 | ret = -EINVAL; | 253 | ret = -EINVAL; |
240 | if (uarg.i & WDIOS_DISABLECARD) { | 254 | if (uarg.i & WDIOS_DISABLECARD) { |
@@ -247,12 +261,6 @@ static int mpcore_wdt_ioctl(struct inode *inode, struct file *file, | |||
247 | } | 261 | } |
248 | break; | 262 | break; |
249 | 263 | ||
250 | case WDIOC_GETSTATUS: | ||
251 | case WDIOC_GETBOOTSTATUS: | ||
252 | uarg.i = 0; | ||
253 | ret = 0; | ||
254 | break; | ||
255 | |||
256 | case WDIOC_KEEPALIVE: | 264 | case WDIOC_KEEPALIVE: |
257 | mpcore_wdt_keepalive(wdt); | 265 | mpcore_wdt_keepalive(wdt); |
258 | ret = 0; | 266 | ret = 0; |
@@ -301,7 +309,7 @@ static const struct file_operations mpcore_wdt_fops = { | |||
301 | .owner = THIS_MODULE, | 309 | .owner = THIS_MODULE, |
302 | .llseek = no_llseek, | 310 | .llseek = no_llseek, |
303 | .write = mpcore_wdt_write, | 311 | .write = mpcore_wdt_write, |
304 | .ioctl = mpcore_wdt_ioctl, | 312 | .unlocked_ioctl = mpcore_wdt_ioctl, |
305 | .open = mpcore_wdt_open, | 313 | .open = mpcore_wdt_open, |
306 | .release = mpcore_wdt_release, | 314 | .release = mpcore_wdt_release, |
307 | }; | 315 | }; |
@@ -349,14 +357,17 @@ static int __devinit mpcore_wdt_probe(struct platform_device *dev) | |||
349 | mpcore_wdt_miscdev.parent = &dev->dev; | 357 | mpcore_wdt_miscdev.parent = &dev->dev; |
350 | ret = misc_register(&mpcore_wdt_miscdev); | 358 | ret = misc_register(&mpcore_wdt_miscdev); |
351 | if (ret) { | 359 | if (ret) { |
352 | dev_printk(KERN_ERR, _dev, "cannot register miscdev on minor=%d (err=%d)\n", | 360 | dev_printk(KERN_ERR, _dev, |
353 | WATCHDOG_MINOR, ret); | 361 | "cannot register miscdev on minor=%d (err=%d)\n", |
362 | WATCHDOG_MINOR, ret); | ||
354 | goto err_misc; | 363 | goto err_misc; |
355 | } | 364 | } |
356 | 365 | ||
357 | ret = request_irq(wdt->irq, mpcore_wdt_fire, IRQF_DISABLED, "mpcore_wdt", wdt); | 366 | ret = request_irq(wdt->irq, mpcore_wdt_fire, IRQF_DISABLED, |
367 | "mpcore_wdt", wdt); | ||
358 | if (ret) { | 368 | if (ret) { |
359 | dev_printk(KERN_ERR, _dev, "cannot register IRQ%d for watchdog\n", wdt->irq); | 369 | dev_printk(KERN_ERR, _dev, |
370 | "cannot register IRQ%d for watchdog\n", wdt->irq); | ||
360 | goto err_irq; | 371 | goto err_irq; |
361 | } | 372 | } |
362 | 373 | ||
@@ -366,13 +377,13 @@ static int __devinit mpcore_wdt_probe(struct platform_device *dev) | |||
366 | 377 | ||
367 | return 0; | 378 | return 0; |
368 | 379 | ||
369 | err_irq: | 380 | err_irq: |
370 | misc_deregister(&mpcore_wdt_miscdev); | 381 | misc_deregister(&mpcore_wdt_miscdev); |
371 | err_misc: | 382 | err_misc: |
372 | iounmap(wdt->base); | 383 | iounmap(wdt->base); |
373 | err_free: | 384 | err_free: |
374 | kfree(wdt); | 385 | kfree(wdt); |
375 | err_out: | 386 | err_out: |
376 | return ret; | 387 | return ret; |
377 | } | 388 | } |
378 | 389 | ||
@@ -415,7 +426,7 @@ static int __init mpcore_wdt_init(void) | |||
415 | */ | 426 | */ |
416 | if (mpcore_wdt_set_heartbeat(mpcore_margin)) { | 427 | if (mpcore_wdt_set_heartbeat(mpcore_margin)) { |
417 | mpcore_wdt_set_heartbeat(TIMER_MARGIN); | 428 | mpcore_wdt_set_heartbeat(TIMER_MARGIN); |
418 | printk(KERN_INFO "mpcore_margin value must be 0<mpcore_margin<65536, using %d\n", | 429 | printk(KERN_INFO "mpcore_margin value must be 0 < mpcore_margin < 65536, using %d\n", |
419 | TIMER_MARGIN); | 430 | TIMER_MARGIN); |
420 | } | 431 | } |
421 | 432 | ||
diff --git a/drivers/watchdog/mtx-1_wdt.c b/drivers/watchdog/mtx-1_wdt.c index a8e67383784e..b4b7b0a4c119 100644 --- a/drivers/watchdog/mtx-1_wdt.c +++ b/drivers/watchdog/mtx-1_wdt.c | |||
@@ -1,7 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * Driver for the MTX-1 Watchdog. | 2 | * Driver for the MTX-1 Watchdog. |
3 | * | 3 | * |
4 | * (C) Copyright 2005 4G Systems <info@4g-systems.biz>, All Rights Reserved. | 4 | * (C) Copyright 2005 4G Systems <info@4g-systems.biz>, |
5 | * All Rights Reserved. | ||
5 | * http://www.4g-systems.biz | 6 | * http://www.4g-systems.biz |
6 | * | 7 | * |
7 | * (C) Copyright 2007 OpenWrt.org, Florian Fainelli <florian@openwrt.org> | 8 | * (C) Copyright 2007 OpenWrt.org, Florian Fainelli <florian@openwrt.org> |
@@ -46,12 +47,11 @@ | |||
46 | #include <linux/jiffies.h> | 47 | #include <linux/jiffies.h> |
47 | #include <linux/watchdog.h> | 48 | #include <linux/watchdog.h> |
48 | #include <linux/platform_device.h> | 49 | #include <linux/platform_device.h> |
49 | 50 | #include <linux/io.h> | |
50 | #include <asm/io.h> | 51 | #include <linux/uaccess.h> |
51 | #include <asm/uaccess.h> | 52 | #include <linux/gpio.h> |
52 | 53 | ||
53 | #include <asm/mach-au1x00/au1000.h> | 54 | #include <asm/mach-au1x00/au1000.h> |
54 | #include <asm/gpio.h> | ||
55 | 55 | ||
56 | #define MTX1_WDT_INTERVAL (5 * HZ) | 56 | #define MTX1_WDT_INTERVAL (5 * HZ) |
57 | 57 | ||
@@ -59,6 +59,7 @@ static int ticks = 100 * HZ; | |||
59 | 59 | ||
60 | static struct { | 60 | static struct { |
61 | struct completion stop; | 61 | struct completion stop; |
62 | spinlock_t lock; | ||
62 | int running; | 63 | int running; |
63 | struct timer_list timer; | 64 | struct timer_list timer; |
64 | int queue; | 65 | int queue; |
@@ -71,6 +72,7 @@ static void mtx1_wdt_trigger(unsigned long unused) | |||
71 | { | 72 | { |
72 | u32 tmp; | 73 | u32 tmp; |
73 | 74 | ||
75 | spin_lock(&mtx1_wdt_device.lock); | ||
74 | if (mtx1_wdt_device.running) | 76 | if (mtx1_wdt_device.running) |
75 | ticks--; | 77 | ticks--; |
76 | /* | 78 | /* |
@@ -79,13 +81,13 @@ static void mtx1_wdt_trigger(unsigned long unused) | |||
79 | tmp = au_readl(GPIO2_DIR); | 81 | tmp = au_readl(GPIO2_DIR); |
80 | tmp = (tmp & ~(1 << mtx1_wdt_device.gpio)) | | 82 | tmp = (tmp & ~(1 << mtx1_wdt_device.gpio)) | |
81 | ((~tmp) & (1 << mtx1_wdt_device.gpio)); | 83 | ((~tmp) & (1 << mtx1_wdt_device.gpio)); |
82 | au_writel (tmp, GPIO2_DIR); | 84 | au_writel(tmp, GPIO2_DIR); |
83 | 85 | ||
84 | if (mtx1_wdt_device.queue && ticks) | 86 | if (mtx1_wdt_device.queue && ticks) |
85 | mod_timer(&mtx1_wdt_device.timer, jiffies + MTX1_WDT_INTERVAL); | 87 | mod_timer(&mtx1_wdt_device.timer, jiffies + MTX1_WDT_INTERVAL); |
86 | else { | 88 | else |
87 | complete(&mtx1_wdt_device.stop); | 89 | complete(&mtx1_wdt_device.stop); |
88 | } | 90 | spin_unlock(&mtx1_wdt_device.lock); |
89 | } | 91 | } |
90 | 92 | ||
91 | static void mtx1_wdt_reset(void) | 93 | static void mtx1_wdt_reset(void) |
@@ -96,23 +98,25 @@ static void mtx1_wdt_reset(void) | |||
96 | 98 | ||
97 | static void mtx1_wdt_start(void) | 99 | static void mtx1_wdt_start(void) |
98 | { | 100 | { |
101 | spin_lock_irqsave(&mtx1_wdt_device.lock, flags); | ||
99 | if (!mtx1_wdt_device.queue) { | 102 | if (!mtx1_wdt_device.queue) { |
100 | mtx1_wdt_device.queue = 1; | 103 | mtx1_wdt_device.queue = 1; |
101 | gpio_set_value(mtx1_wdt_device.gpio, 1); | 104 | gpio_set_value(mtx1_wdt_device.gpio, 1); |
102 | mod_timer(&mtx1_wdt_device.timer, jiffies + MTX1_WDT_INTERVAL); | 105 | mod_timer(&mtx1_wdt_device.timer, jiffies + MTX1_WDT_INTERVAL); |
103 | } | 106 | } |
104 | mtx1_wdt_device.running++; | 107 | mtx1_wdt_device.running++; |
108 | spin_unlock_irqrestore(&mtx1_wdt_device.lock, flags); | ||
105 | } | 109 | } |
106 | 110 | ||
107 | static int mtx1_wdt_stop(void) | 111 | static int mtx1_wdt_stop(void) |
108 | { | 112 | { |
113 | spin_lock_irqsave(&mtx1_wdt_device.lock, flags); | ||
109 | if (mtx1_wdt_device.queue) { | 114 | if (mtx1_wdt_device.queue) { |
110 | mtx1_wdt_device.queue = 0; | 115 | mtx1_wdt_device.queue = 0; |
111 | gpio_set_value(mtx1_wdt_device.gpio, 0); | 116 | gpio_set_value(mtx1_wdt_device.gpio, 0); |
112 | } | 117 | } |
113 | |||
114 | ticks = mtx1_wdt_device.default_ticks; | 118 | ticks = mtx1_wdt_device.default_ticks; |
115 | 119 | spin_unlock_irqrestore(&mtx1_wdt_device.lock, flags); | |
116 | return 0; | 120 | return 0; |
117 | } | 121 | } |
118 | 122 | ||
@@ -122,7 +126,6 @@ static int mtx1_wdt_open(struct inode *inode, struct file *file) | |||
122 | { | 126 | { |
123 | if (test_and_set_bit(0, &mtx1_wdt_device.inuse)) | 127 | if (test_and_set_bit(0, &mtx1_wdt_device.inuse)) |
124 | return -EBUSY; | 128 | return -EBUSY; |
125 | |||
126 | return nonseekable_open(inode, file); | 129 | return nonseekable_open(inode, file); |
127 | } | 130 | } |
128 | 131 | ||
@@ -133,54 +136,51 @@ static int mtx1_wdt_release(struct inode *inode, struct file *file) | |||
133 | return 0; | 136 | return 0; |
134 | } | 137 | } |
135 | 138 | ||
136 | static int mtx1_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) | 139 | static long mtx1_wdt_ioctl(struct file *file, unsigned int cmd, |
140 | unsigned long arg) | ||
137 | { | 141 | { |
138 | void __user *argp = (void __user *)arg; | 142 | void __user *argp = (void __user *)arg; |
143 | int __user *p = (int __user *)argp; | ||
139 | unsigned int value; | 144 | unsigned int value; |
140 | static struct watchdog_info ident = | 145 | static const struct watchdog_info ident = { |
141 | { | ||
142 | .options = WDIOF_CARDRESET, | 146 | .options = WDIOF_CARDRESET, |
143 | .identity = "MTX-1 WDT", | 147 | .identity = "MTX-1 WDT", |
144 | }; | 148 | }; |
145 | 149 | ||
146 | switch(cmd) { | 150 | switch (cmd) { |
147 | case WDIOC_KEEPALIVE: | 151 | case WDIOC_GETSUPPORT: |
148 | mtx1_wdt_reset(); | 152 | if (copy_to_user(argp, &ident, sizeof(ident))) |
149 | break; | 153 | return -EFAULT; |
150 | case WDIOC_GETSTATUS: | 154 | break; |
151 | case WDIOC_GETBOOTSTATUS: | 155 | case WDIOC_GETSTATUS: |
152 | if ( copy_to_user(argp, &value, sizeof(int)) ) | 156 | case WDIOC_GETBOOTSTATUS: |
153 | return -EFAULT; | 157 | put_user(0, p); |
154 | break; | 158 | break; |
155 | case WDIOC_GETSUPPORT: | 159 | case WDIOC_SETOPTIONS: |
156 | if ( copy_to_user(argp, &ident, sizeof(ident)) ) | 160 | if (get_user(value, p)) |
157 | return -EFAULT; | 161 | return -EFAULT; |
158 | break; | 162 | if (value & WDIOS_ENABLECARD) |
159 | case WDIOC_SETOPTIONS: | 163 | mtx1_wdt_start(); |
160 | if ( copy_from_user(&value, argp, sizeof(int)) ) | 164 | else if (value & WDIOS_DISABLECARD) |
161 | return -EFAULT; | 165 | mtx1_wdt_stop(); |
162 | switch(value) { | 166 | else |
163 | case WDIOS_ENABLECARD: | 167 | return -EINVAL; |
164 | mtx1_wdt_start(); | 168 | return 0; |
165 | break; | 169 | case WDIOC_KEEPALIVE: |
166 | case WDIOS_DISABLECARD: | 170 | mtx1_wdt_reset(); |
167 | return mtx1_wdt_stop(); | 171 | break; |
168 | default: | 172 | default: |
169 | return -EINVAL; | 173 | return -ENOTTY; |
170 | } | ||
171 | break; | ||
172 | default: | ||
173 | return -ENOTTY; | ||
174 | } | 174 | } |
175 | return 0; | 175 | return 0; |
176 | } | 176 | } |
177 | 177 | ||
178 | 178 | ||
179 | static ssize_t mtx1_wdt_write(struct file *file, const char *buf, size_t count, loff_t *ppos) | 179 | static ssize_t mtx1_wdt_write(struct file *file, const char *buf, |
180 | size_t count, loff_t *ppos) | ||
180 | { | 181 | { |
181 | if (!count) | 182 | if (!count) |
182 | return -EIO; | 183 | return -EIO; |
183 | |||
184 | mtx1_wdt_reset(); | 184 | mtx1_wdt_reset(); |
185 | return count; | 185 | return count; |
186 | } | 186 | } |
@@ -188,17 +188,17 @@ static ssize_t mtx1_wdt_write(struct file *file, const char *buf, size_t count, | |||
188 | static const struct file_operations mtx1_wdt_fops = { | 188 | static const struct file_operations mtx1_wdt_fops = { |
189 | .owner = THIS_MODULE, | 189 | .owner = THIS_MODULE, |
190 | .llseek = no_llseek, | 190 | .llseek = no_llseek, |
191 | .ioctl = mtx1_wdt_ioctl, | 191 | .unlocked_ioctl = mtx1_wdt_ioctl, |
192 | .open = mtx1_wdt_open, | 192 | .open = mtx1_wdt_open, |
193 | .write = mtx1_wdt_write, | 193 | .write = mtx1_wdt_write, |
194 | .release = mtx1_wdt_release | 194 | .release = mtx1_wdt_release, |
195 | }; | 195 | }; |
196 | 196 | ||
197 | 197 | ||
198 | static struct miscdevice mtx1_wdt_misc = { | 198 | static struct miscdevice mtx1_wdt_misc = { |
199 | .minor = WATCHDOG_MINOR, | 199 | .minor = WATCHDOG_MINOR, |
200 | .name = "watchdog", | 200 | .name = "watchdog", |
201 | .fops = &mtx1_wdt_fops | 201 | .fops = &mtx1_wdt_fops, |
202 | }; | 202 | }; |
203 | 203 | ||
204 | 204 | ||
@@ -208,29 +208,26 @@ static int mtx1_wdt_probe(struct platform_device *pdev) | |||
208 | 208 | ||
209 | mtx1_wdt_device.gpio = pdev->resource[0].start; | 209 | mtx1_wdt_device.gpio = pdev->resource[0].start; |
210 | 210 | ||
211 | if ((ret = misc_register(&mtx1_wdt_misc)) < 0) { | 211 | spin_lock_init(&mtx1_wdt_device.lock); |
212 | printk(KERN_ERR " mtx-1_wdt : failed to register\n"); | ||
213 | return ret; | ||
214 | } | ||
215 | |||
216 | init_completion(&mtx1_wdt_device.stop); | 212 | init_completion(&mtx1_wdt_device.stop); |
217 | mtx1_wdt_device.queue = 0; | 213 | mtx1_wdt_device.queue = 0; |
218 | |||
219 | clear_bit(0, &mtx1_wdt_device.inuse); | 214 | clear_bit(0, &mtx1_wdt_device.inuse); |
220 | |||
221 | setup_timer(&mtx1_wdt_device.timer, mtx1_wdt_trigger, 0L); | 215 | setup_timer(&mtx1_wdt_device.timer, mtx1_wdt_trigger, 0L); |
222 | |||
223 | mtx1_wdt_device.default_ticks = ticks; | 216 | mtx1_wdt_device.default_ticks = ticks; |
224 | 217 | ||
218 | ret = misc_register(&mtx1_wdt_misc); | ||
219 | if (ret < 0) { | ||
220 | printk(KERN_ERR " mtx-1_wdt : failed to register\n"); | ||
221 | return ret; | ||
222 | } | ||
225 | mtx1_wdt_start(); | 223 | mtx1_wdt_start(); |
226 | |||
227 | printk(KERN_INFO "MTX-1 Watchdog driver\n"); | 224 | printk(KERN_INFO "MTX-1 Watchdog driver\n"); |
228 | |||
229 | return 0; | 225 | return 0; |
230 | } | 226 | } |
231 | 227 | ||
232 | static int mtx1_wdt_remove(struct platform_device *pdev) | 228 | static int mtx1_wdt_remove(struct platform_device *pdev) |
233 | { | 229 | { |
230 | /* FIXME: do we need to lock this test ? */ | ||
234 | if (mtx1_wdt_device.queue) { | 231 | if (mtx1_wdt_device.queue) { |
235 | mtx1_wdt_device.queue = 0; | 232 | mtx1_wdt_device.queue = 0; |
236 | wait_for_completion(&mtx1_wdt_device.stop); | 233 | wait_for_completion(&mtx1_wdt_device.stop); |
diff --git a/drivers/watchdog/mv64x60_wdt.c b/drivers/watchdog/mv64x60_wdt.c index b59ca3273967..acf589dc057c 100644 --- a/drivers/watchdog/mv64x60_wdt.c +++ b/drivers/watchdog/mv64x60_wdt.c | |||
@@ -8,7 +8,7 @@ | |||
8 | * and services the watchdog. | 8 | * and services the watchdog. |
9 | * | 9 | * |
10 | * Derived from mpc8xx_wdt.c, with the following copyright. | 10 | * Derived from mpc8xx_wdt.c, with the following copyright. |
11 | * | 11 | * |
12 | * 2002 (c) Florian Schirmer <jolt@tuxbox.org> This file is licensed under | 12 | * 2002 (c) Florian Schirmer <jolt@tuxbox.org> This file is licensed under |
13 | * the terms of the GNU General Public License version 2. This program | 13 | * the terms of the GNU General Public License version 2. This program |
14 | * is licensed "as is" without any warranty of any kind, whether express | 14 | * is licensed "as is" without any warranty of any kind, whether express |
@@ -22,10 +22,9 @@ | |||
22 | #include <linux/module.h> | 22 | #include <linux/module.h> |
23 | #include <linux/watchdog.h> | 23 | #include <linux/watchdog.h> |
24 | #include <linux/platform_device.h> | 24 | #include <linux/platform_device.h> |
25 | |||
26 | #include <linux/mv643xx.h> | 25 | #include <linux/mv643xx.h> |
27 | #include <asm/uaccess.h> | 26 | #include <linux/uaccess.h> |
28 | #include <asm/io.h> | 27 | #include <linux/io.h> |
29 | 28 | ||
30 | #define MV64x60_WDT_WDC_OFFSET 0 | 29 | #define MV64x60_WDT_WDC_OFFSET 0 |
31 | 30 | ||
@@ -61,7 +60,9 @@ static DEFINE_SPINLOCK(mv64x60_wdt_spinlock); | |||
61 | 60 | ||
62 | static int nowayout = WATCHDOG_NOWAYOUT; | 61 | static int nowayout = WATCHDOG_NOWAYOUT; |
63 | module_param(nowayout, int, 0); | 62 | module_param(nowayout, int, 0); |
64 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 63 | MODULE_PARM_DESC(nowayout, |
64 | "Watchdog cannot be stopped once started (default=" | ||
65 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
65 | 66 | ||
66 | static int mv64x60_wdt_toggle_wdc(int enabled_predicate, int field_shift) | 67 | static int mv64x60_wdt_toggle_wdc(int enabled_predicate, int field_shift) |
67 | { | 68 | { |
@@ -150,7 +151,7 @@ static int mv64x60_wdt_release(struct inode *inode, struct file *file) | |||
150 | } | 151 | } |
151 | 152 | ||
152 | static ssize_t mv64x60_wdt_write(struct file *file, const char __user *data, | 153 | static ssize_t mv64x60_wdt_write(struct file *file, const char __user *data, |
153 | size_t len, loff_t * ppos) | 154 | size_t len, loff_t *ppos) |
154 | { | 155 | { |
155 | if (len) { | 156 | if (len) { |
156 | if (!nowayout) { | 157 | if (!nowayout) { |
@@ -160,7 +161,7 @@ static ssize_t mv64x60_wdt_write(struct file *file, const char __user *data, | |||
160 | 161 | ||
161 | for (i = 0; i != len; i++) { | 162 | for (i = 0; i != len; i++) { |
162 | char c; | 163 | char c; |
163 | if(get_user(c, data + i)) | 164 | if (get_user(c, data + i)) |
164 | return -EFAULT; | 165 | return -EFAULT; |
165 | if (c == 'V') | 166 | if (c == 'V') |
166 | expect_close = 42; | 167 | expect_close = 42; |
@@ -172,8 +173,8 @@ static ssize_t mv64x60_wdt_write(struct file *file, const char __user *data, | |||
172 | return len; | 173 | return len; |
173 | } | 174 | } |
174 | 175 | ||
175 | static int mv64x60_wdt_ioctl(struct inode *inode, struct file *file, | 176 | static long mv64x60_wdt_ioctl(struct file *file, |
176 | unsigned int cmd, unsigned long arg) | 177 | unsigned int cmd, unsigned long arg) |
177 | { | 178 | { |
178 | int timeout; | 179 | int timeout; |
179 | int options; | 180 | int options; |
@@ -240,7 +241,7 @@ static const struct file_operations mv64x60_wdt_fops = { | |||
240 | .owner = THIS_MODULE, | 241 | .owner = THIS_MODULE, |
241 | .llseek = no_llseek, | 242 | .llseek = no_llseek, |
242 | .write = mv64x60_wdt_write, | 243 | .write = mv64x60_wdt_write, |
243 | .ioctl = mv64x60_wdt_ioctl, | 244 | .unlocked_ioctl = mv64x60_wdt_ioctl, |
244 | .open = mv64x60_wdt_open, | 245 | .open = mv64x60_wdt_open, |
245 | .release = mv64x60_wdt_release, | 246 | .release = mv64x60_wdt_release, |
246 | }; | 247 | }; |
diff --git a/drivers/watchdog/omap_wdt.c b/drivers/watchdog/omap_wdt.c index 74bc39aa1ce8..6f5420f478a9 100644 --- a/drivers/watchdog/omap_wdt.c +++ b/drivers/watchdog/omap_wdt.c | |||
@@ -40,10 +40,9 @@ | |||
40 | #include <linux/moduleparam.h> | 40 | #include <linux/moduleparam.h> |
41 | #include <linux/clk.h> | 41 | #include <linux/clk.h> |
42 | #include <linux/bitops.h> | 42 | #include <linux/bitops.h> |
43 | 43 | #include <linux/io.h> | |
44 | #include <asm/io.h> | 44 | #include <linux/uaccess.h> |
45 | #include <asm/uaccess.h> | 45 | #include <linux/hardware.h> |
46 | #include <asm/hardware.h> | ||
47 | 46 | ||
48 | #include <asm/arch/prcm.h> | 47 | #include <asm/arch/prcm.h> |
49 | 48 | ||
@@ -54,11 +53,12 @@ module_param(timer_margin, uint, 0); | |||
54 | MODULE_PARM_DESC(timer_margin, "initial watchdog timeout (in seconds)"); | 53 | MODULE_PARM_DESC(timer_margin, "initial watchdog timeout (in seconds)"); |
55 | 54 | ||
56 | static int omap_wdt_users; | 55 | static int omap_wdt_users; |
57 | static struct clk *armwdt_ck = NULL; | 56 | static struct clk *armwdt_ck; |
58 | static struct clk *mpu_wdt_ick = NULL; | 57 | static struct clk *mpu_wdt_ick; |
59 | static struct clk *mpu_wdt_fck = NULL; | 58 | static struct clk *mpu_wdt_fck; |
60 | 59 | ||
61 | static unsigned int wdt_trgr_pattern = 0x1234; | 60 | static unsigned int wdt_trgr_pattern = 0x1234; |
61 | static spinlock_t wdt_lock; | ||
62 | 62 | ||
63 | static void omap_wdt_ping(void) | 63 | static void omap_wdt_ping(void) |
64 | { | 64 | { |
@@ -174,30 +174,29 @@ static int omap_wdt_release(struct inode *inode, struct file *file) | |||
174 | return 0; | 174 | return 0; |
175 | } | 175 | } |
176 | 176 | ||
177 | static ssize_t | 177 | static ssize_t omap_wdt_write(struct file *file, const char __user *data, |
178 | omap_wdt_write(struct file *file, const char __user *data, | ||
179 | size_t len, loff_t *ppos) | 178 | size_t len, loff_t *ppos) |
180 | { | 179 | { |
181 | /* Refresh LOAD_TIME. */ | 180 | /* Refresh LOAD_TIME. */ |
182 | if (len) | 181 | if (len) { |
182 | spin_lock(&wdt_lock); | ||
183 | omap_wdt_ping(); | 183 | omap_wdt_ping(); |
184 | spin_unlock(&wdt_lock); | ||
185 | } | ||
184 | return len; | 186 | return len; |
185 | } | 187 | } |
186 | 188 | ||
187 | static int | 189 | static long omap_wdt_ioctl(struct file *file, unsigned int cmd, |
188 | omap_wdt_ioctl(struct inode *inode, struct file *file, | 190 | unsigned long arg) |
189 | unsigned int cmd, unsigned long arg) | ||
190 | { | 191 | { |
191 | int new_margin; | 192 | int new_margin; |
192 | static struct watchdog_info ident = { | 193 | static const struct watchdog_info ident = { |
193 | .identity = "OMAP Watchdog", | 194 | .identity = "OMAP Watchdog", |
194 | .options = WDIOF_SETTIMEOUT, | 195 | .options = WDIOF_SETTIMEOUT, |
195 | .firmware_version = 0, | 196 | .firmware_version = 0, |
196 | }; | 197 | }; |
197 | 198 | ||
198 | switch (cmd) { | 199 | switch (cmd) { |
199 | default: | ||
200 | return -ENOTTY; | ||
201 | case WDIOC_GETSUPPORT: | 200 | case WDIOC_GETSUPPORT: |
202 | return copy_to_user((struct watchdog_info __user *)arg, &ident, | 201 | return copy_to_user((struct watchdog_info __user *)arg, &ident, |
203 | sizeof(ident)); | 202 | sizeof(ident)); |
@@ -211,28 +210,34 @@ omap_wdt_ioctl(struct inode *inode, struct file *file, | |||
211 | return put_user(omap_prcm_get_reset_sources(), | 210 | return put_user(omap_prcm_get_reset_sources(), |
212 | (int __user *)arg); | 211 | (int __user *)arg); |
213 | case WDIOC_KEEPALIVE: | 212 | case WDIOC_KEEPALIVE: |
213 | spin_lock(&wdt_lock); | ||
214 | omap_wdt_ping(); | 214 | omap_wdt_ping(); |
215 | spin_unlock(&wdt_lock); | ||
215 | return 0; | 216 | return 0; |
216 | case WDIOC_SETTIMEOUT: | 217 | case WDIOC_SETTIMEOUT: |
217 | if (get_user(new_margin, (int __user *)arg)) | 218 | if (get_user(new_margin, (int __user *)arg)) |
218 | return -EFAULT; | 219 | return -EFAULT; |
219 | omap_wdt_adjust_timeout(new_margin); | 220 | omap_wdt_adjust_timeout(new_margin); |
220 | 221 | ||
222 | spin_lock(&wdt_lock); | ||
221 | omap_wdt_disable(); | 223 | omap_wdt_disable(); |
222 | omap_wdt_set_timeout(); | 224 | omap_wdt_set_timeout(); |
223 | omap_wdt_enable(); | 225 | omap_wdt_enable(); |
224 | 226 | ||
225 | omap_wdt_ping(); | 227 | omap_wdt_ping(); |
228 | spin_unlock(&wdt_lock); | ||
226 | /* Fall */ | 229 | /* Fall */ |
227 | case WDIOC_GETTIMEOUT: | 230 | case WDIOC_GETTIMEOUT: |
228 | return put_user(timer_margin, (int __user *)arg); | 231 | return put_user(timer_margin, (int __user *)arg); |
232 | default: | ||
233 | return -ENOTTY; | ||
229 | } | 234 | } |
230 | } | 235 | } |
231 | 236 | ||
232 | static const struct file_operations omap_wdt_fops = { | 237 | static const struct file_operations omap_wdt_fops = { |
233 | .owner = THIS_MODULE, | 238 | .owner = THIS_MODULE, |
234 | .write = omap_wdt_write, | 239 | .write = omap_wdt_write, |
235 | .ioctl = omap_wdt_ioctl, | 240 | .unlocked_ioctl = omap_wdt_ioctl, |
236 | .open = omap_wdt_open, | 241 | .open = omap_wdt_open, |
237 | .release = omap_wdt_release, | 242 | .release = omap_wdt_release, |
238 | }; | 243 | }; |
@@ -240,7 +245,7 @@ static const struct file_operations omap_wdt_fops = { | |||
240 | static struct miscdevice omap_wdt_miscdev = { | 245 | static struct miscdevice omap_wdt_miscdev = { |
241 | .minor = WATCHDOG_MINOR, | 246 | .minor = WATCHDOG_MINOR, |
242 | .name = "watchdog", | 247 | .name = "watchdog", |
243 | .fops = &omap_wdt_fops | 248 | .fops = &omap_wdt_fops, |
244 | }; | 249 | }; |
245 | 250 | ||
246 | static int __init omap_wdt_probe(struct platform_device *pdev) | 251 | static int __init omap_wdt_probe(struct platform_device *pdev) |
@@ -373,6 +378,7 @@ static struct platform_driver omap_wdt_driver = { | |||
373 | 378 | ||
374 | static int __init omap_wdt_init(void) | 379 | static int __init omap_wdt_init(void) |
375 | { | 380 | { |
381 | spin_lock_init(&wdt_lock); | ||
376 | return platform_driver_register(&omap_wdt_driver); | 382 | return platform_driver_register(&omap_wdt_driver); |
377 | } | 383 | } |
378 | 384 | ||
diff --git a/drivers/watchdog/pc87413_wdt.c b/drivers/watchdog/pc87413_wdt.c index 15e4f8887a9e..e91ada72da1d 100644 --- a/drivers/watchdog/pc87413_wdt.c +++ b/drivers/watchdog/pc87413_wdt.c | |||
@@ -31,14 +31,14 @@ | |||
31 | #include <linux/spinlock.h> | 31 | #include <linux/spinlock.h> |
32 | #include <linux/moduleparam.h> | 32 | #include <linux/moduleparam.h> |
33 | #include <linux/version.h> | 33 | #include <linux/version.h> |
34 | #include <linux/io.h> | ||
35 | #include <linux/uaccess.h> | ||
34 | 36 | ||
35 | #include <asm/io.h> | ||
36 | #include <asm/uaccess.h> | ||
37 | #include <asm/system.h> | 37 | #include <asm/system.h> |
38 | 38 | ||
39 | /* #define DEBUG 1 */ | 39 | /* #define DEBUG 1 */ |
40 | 40 | ||
41 | #define DEFAULT_TIMEOUT 1 /* 1 minute */ | 41 | #define DEFAULT_TIMEOUT 1 /* 1 minute */ |
42 | #define MAX_TIMEOUT 255 | 42 | #define MAX_TIMEOUT 255 |
43 | 43 | ||
44 | #define VERSION "1.1" | 44 | #define VERSION "1.1" |
@@ -46,22 +46,22 @@ | |||
46 | #define PFX MODNAME ": " | 46 | #define PFX MODNAME ": " |
47 | #define DPFX MODNAME " - DEBUG: " | 47 | #define DPFX MODNAME " - DEBUG: " |
48 | 48 | ||
49 | #define WDT_INDEX_IO_PORT (io+0) /* I/O port base (index register) */ | 49 | #define WDT_INDEX_IO_PORT (io+0) /* I/O port base (index register) */ |
50 | #define WDT_DATA_IO_PORT (WDT_INDEX_IO_PORT+1) | 50 | #define WDT_DATA_IO_PORT (WDT_INDEX_IO_PORT+1) |
51 | #define SWC_LDN 0x04 | 51 | #define SWC_LDN 0x04 |
52 | #define SIOCFG2 0x22 /* Serial IO register */ | 52 | #define SIOCFG2 0x22 /* Serial IO register */ |
53 | #define WDCTL 0x10 /* Watchdog-Timer-Controll-Register */ | 53 | #define WDCTL 0x10 /* Watchdog-Timer-Controll-Register */ |
54 | #define WDTO 0x11 /* Watchdog timeout register */ | 54 | #define WDTO 0x11 /* Watchdog timeout register */ |
55 | #define WDCFG 0x12 /* Watchdog config register */ | 55 | #define WDCFG 0x12 /* Watchdog config register */ |
56 | 56 | ||
57 | static int io = 0x2E; /* Address used on Portwell Boards */ | 57 | static int io = 0x2E; /* Address used on Portwell Boards */ |
58 | 58 | ||
59 | static int timeout = DEFAULT_TIMEOUT; /* timeout value */ | 59 | static int timeout = DEFAULT_TIMEOUT; /* timeout value */ |
60 | static unsigned long timer_enabled = 0; /* is the timer enabled? */ | 60 | static unsigned long timer_enabled; /* is the timer enabled? */ |
61 | 61 | ||
62 | static char expect_close; /* is the close expected? */ | 62 | static char expect_close; /* is the close expected? */ |
63 | 63 | ||
64 | static DEFINE_SPINLOCK(io_lock);/* to guard the watchdog from io races */ | 64 | static DEFINE_SPINLOCK(io_lock); /* to guard us from io races */ |
65 | 65 | ||
66 | static int nowayout = WATCHDOG_NOWAYOUT; | 66 | static int nowayout = WATCHDOG_NOWAYOUT; |
67 | 67 | ||
@@ -69,7 +69,7 @@ static int nowayout = WATCHDOG_NOWAYOUT; | |||
69 | 69 | ||
70 | /* Select pins for Watchdog output */ | 70 | /* Select pins for Watchdog output */ |
71 | 71 | ||
72 | static inline void pc87413_select_wdt_out (void) | 72 | static inline void pc87413_select_wdt_out(void) |
73 | { | 73 | { |
74 | unsigned int cr_data = 0; | 74 | unsigned int cr_data = 0; |
75 | 75 | ||
@@ -77,7 +77,7 @@ static inline void pc87413_select_wdt_out (void) | |||
77 | 77 | ||
78 | outb_p(SIOCFG2, WDT_INDEX_IO_PORT); | 78 | outb_p(SIOCFG2, WDT_INDEX_IO_PORT); |
79 | 79 | ||
80 | cr_data = inb (WDT_DATA_IO_PORT); | 80 | cr_data = inb(WDT_DATA_IO_PORT); |
81 | 81 | ||
82 | cr_data |= 0x80; /* Set Bit7 to 1*/ | 82 | cr_data |= 0x80; /* Set Bit7 to 1*/ |
83 | outb_p(SIOCFG2, WDT_INDEX_IO_PORT); | 83 | outb_p(SIOCFG2, WDT_INDEX_IO_PORT); |
@@ -85,8 +85,9 @@ static inline void pc87413_select_wdt_out (void) | |||
85 | outb_p(cr_data, WDT_DATA_IO_PORT); | 85 | outb_p(cr_data, WDT_DATA_IO_PORT); |
86 | 86 | ||
87 | #ifdef DEBUG | 87 | #ifdef DEBUG |
88 | printk(KERN_INFO DPFX "Select multiple pin,pin55,as WDT output:" | 88 | printk(KERN_INFO DPFX |
89 | " Bit7 to 1: %d\n", cr_data); | 89 | "Select multiple pin,pin55,as WDT output: Bit7 to 1: %d\n", |
90 | cr_data); | ||
90 | #endif | 91 | #endif |
91 | } | 92 | } |
92 | 93 | ||
@@ -94,18 +95,18 @@ static inline void pc87413_select_wdt_out (void) | |||
94 | 95 | ||
95 | static inline void pc87413_enable_swc(void) | 96 | static inline void pc87413_enable_swc(void) |
96 | { | 97 | { |
97 | unsigned int cr_data=0; | 98 | unsigned int cr_data = 0; |
98 | 99 | ||
99 | /* Step 2: Enable SWC functions */ | 100 | /* Step 2: Enable SWC functions */ |
100 | 101 | ||
101 | outb_p(0x07, WDT_INDEX_IO_PORT); /* Point SWC_LDN (LDN=4) */ | 102 | outb_p(0x07, WDT_INDEX_IO_PORT); /* Point SWC_LDN (LDN=4) */ |
102 | outb_p(SWC_LDN, WDT_DATA_IO_PORT); | 103 | outb_p(SWC_LDN, WDT_DATA_IO_PORT); |
103 | 104 | ||
104 | outb_p(0x30, WDT_INDEX_IO_PORT); /* Read Index 0x30 First */ | 105 | outb_p(0x30, WDT_INDEX_IO_PORT); /* Read Index 0x30 First */ |
105 | cr_data = inb(WDT_DATA_IO_PORT); | 106 | cr_data = inb(WDT_DATA_IO_PORT); |
106 | cr_data |= 0x01; /* Set Bit0 to 1 */ | 107 | cr_data |= 0x01; /* Set Bit0 to 1 */ |
107 | outb_p(0x30, WDT_INDEX_IO_PORT); | 108 | outb_p(0x30, WDT_INDEX_IO_PORT); |
108 | outb_p(cr_data, WDT_DATA_IO_PORT); /* Index0x30_bit0P1 */ | 109 | outb_p(cr_data, WDT_DATA_IO_PORT); /* Index0x30_bit0P1 */ |
109 | 110 | ||
110 | #ifdef DEBUG | 111 | #ifdef DEBUG |
111 | printk(KERN_INFO DPFX "pc87413 - Enable SWC functions\n"); | 112 | printk(KERN_INFO DPFX "pc87413 - Enable SWC functions\n"); |
@@ -121,20 +122,19 @@ static inline unsigned int pc87413_get_swc_base(void) | |||
121 | 122 | ||
122 | /* Step 3: Read SWC I/O Base Address */ | 123 | /* Step 3: Read SWC I/O Base Address */ |
123 | 124 | ||
124 | outb_p(0x60, WDT_INDEX_IO_PORT); /* Read Index 0x60 */ | 125 | outb_p(0x60, WDT_INDEX_IO_PORT); /* Read Index 0x60 */ |
125 | addr_h = inb(WDT_DATA_IO_PORT); | 126 | addr_h = inb(WDT_DATA_IO_PORT); |
126 | 127 | ||
127 | outb_p(0x61, WDT_INDEX_IO_PORT); /* Read Index 0x61 */ | 128 | outb_p(0x61, WDT_INDEX_IO_PORT); /* Read Index 0x61 */ |
128 | 129 | ||
129 | addr_l = inb(WDT_DATA_IO_PORT); | 130 | addr_l = inb(WDT_DATA_IO_PORT); |
130 | 131 | ||
131 | swc_base_addr = (addr_h << 8) + addr_l; | 132 | swc_base_addr = (addr_h << 8) + addr_l; |
132 | |||
133 | #ifdef DEBUG | 133 | #ifdef DEBUG |
134 | printk(KERN_INFO DPFX "Read SWC I/O Base Address: low %d, high %d," | 134 | printk(KERN_INFO DPFX |
135 | " res %d\n", addr_l, addr_h, swc_base_addr); | 135 | "Read SWC I/O Base Address: low %d, high %d, res %d\n", |
136 | addr_l, addr_h, swc_base_addr); | ||
136 | #endif | 137 | #endif |
137 | |||
138 | return swc_base_addr; | 138 | return swc_base_addr; |
139 | } | 139 | } |
140 | 140 | ||
@@ -143,9 +143,7 @@ static inline unsigned int pc87413_get_swc_base(void) | |||
143 | static inline void pc87413_swc_bank3(unsigned int swc_base_addr) | 143 | static inline void pc87413_swc_bank3(unsigned int swc_base_addr) |
144 | { | 144 | { |
145 | /* Step 4: Select Bank3 of SWC */ | 145 | /* Step 4: Select Bank3 of SWC */ |
146 | |||
147 | outb_p(inb(swc_base_addr + 0x0f) | 0x03, swc_base_addr + 0x0f); | 146 | outb_p(inb(swc_base_addr + 0x0f) | 0x03, swc_base_addr + 0x0f); |
148 | |||
149 | #ifdef DEBUG | 147 | #ifdef DEBUG |
150 | printk(KERN_INFO DPFX "Select Bank3 of SWC\n"); | 148 | printk(KERN_INFO DPFX "Select Bank3 of SWC\n"); |
151 | #endif | 149 | #endif |
@@ -157,9 +155,7 @@ static inline void pc87413_programm_wdto(unsigned int swc_base_addr, | |||
157 | char pc87413_time) | 155 | char pc87413_time) |
158 | { | 156 | { |
159 | /* Step 5: Programm WDTO, Twd. */ | 157 | /* Step 5: Programm WDTO, Twd. */ |
160 | |||
161 | outb_p(pc87413_time, swc_base_addr + WDTO); | 158 | outb_p(pc87413_time, swc_base_addr + WDTO); |
162 | |||
163 | #ifdef DEBUG | 159 | #ifdef DEBUG |
164 | printk(KERN_INFO DPFX "Set WDTO to %d minutes\n", pc87413_time); | 160 | printk(KERN_INFO DPFX "Set WDTO to %d minutes\n", pc87413_time); |
165 | #endif | 161 | #endif |
@@ -170,9 +166,7 @@ static inline void pc87413_programm_wdto(unsigned int swc_base_addr, | |||
170 | static inline void pc87413_enable_wden(unsigned int swc_base_addr) | 166 | static inline void pc87413_enable_wden(unsigned int swc_base_addr) |
171 | { | 167 | { |
172 | /* Step 6: Enable WDEN */ | 168 | /* Step 6: Enable WDEN */ |
173 | 169 | outb_p(inb(swc_base_addr + WDCTL) | 0x01, swc_base_addr + WDCTL); | |
174 | outb_p(inb (swc_base_addr + WDCTL) | 0x01, swc_base_addr + WDCTL); | ||
175 | |||
176 | #ifdef DEBUG | 170 | #ifdef DEBUG |
177 | printk(KERN_INFO DPFX "Enable WDEN\n"); | 171 | printk(KERN_INFO DPFX "Enable WDEN\n"); |
178 | #endif | 172 | #endif |
@@ -182,9 +176,7 @@ static inline void pc87413_enable_wden(unsigned int swc_base_addr) | |||
182 | static inline void pc87413_enable_sw_wd_tren(unsigned int swc_base_addr) | 176 | static inline void pc87413_enable_sw_wd_tren(unsigned int swc_base_addr) |
183 | { | 177 | { |
184 | /* Enable SW_WD_TREN */ | 178 | /* Enable SW_WD_TREN */ |
185 | 179 | outb_p(inb(swc_base_addr + WDCFG) | 0x80, swc_base_addr + WDCFG); | |
186 | outb_p(inb (swc_base_addr + WDCFG) | 0x80, swc_base_addr + WDCFG); | ||
187 | |||
188 | #ifdef DEBUG | 180 | #ifdef DEBUG |
189 | printk(KERN_INFO DPFX "Enable SW_WD_TREN\n"); | 181 | printk(KERN_INFO DPFX "Enable SW_WD_TREN\n"); |
190 | #endif | 182 | #endif |
@@ -195,9 +187,7 @@ static inline void pc87413_enable_sw_wd_tren(unsigned int swc_base_addr) | |||
195 | static inline void pc87413_disable_sw_wd_tren(unsigned int swc_base_addr) | 187 | static inline void pc87413_disable_sw_wd_tren(unsigned int swc_base_addr) |
196 | { | 188 | { |
197 | /* Disable SW_WD_TREN */ | 189 | /* Disable SW_WD_TREN */ |
198 | 190 | outb_p(inb(swc_base_addr + WDCFG) & 0x7f, swc_base_addr + WDCFG); | |
199 | outb_p(inb (swc_base_addr + WDCFG) & 0x7f, swc_base_addr + WDCFG); | ||
200 | |||
201 | #ifdef DEBUG | 191 | #ifdef DEBUG |
202 | printk(KERN_INFO DPFX "pc87413 - Disable SW_WD_TREN\n"); | 192 | printk(KERN_INFO DPFX "pc87413 - Disable SW_WD_TREN\n"); |
203 | #endif | 193 | #endif |
@@ -208,9 +198,7 @@ static inline void pc87413_disable_sw_wd_tren(unsigned int swc_base_addr) | |||
208 | static inline void pc87413_enable_sw_wd_trg(unsigned int swc_base_addr) | 198 | static inline void pc87413_enable_sw_wd_trg(unsigned int swc_base_addr) |
209 | { | 199 | { |
210 | /* Enable SW_WD_TRG */ | 200 | /* Enable SW_WD_TRG */ |
211 | 201 | outb_p(inb(swc_base_addr + WDCTL) | 0x80, swc_base_addr + WDCTL); | |
212 | outb_p(inb (swc_base_addr + WDCTL) | 0x80, swc_base_addr + WDCTL); | ||
213 | |||
214 | #ifdef DEBUG | 202 | #ifdef DEBUG |
215 | printk(KERN_INFO DPFX "pc87413 - Enable SW_WD_TRG\n"); | 203 | printk(KERN_INFO DPFX "pc87413 - Enable SW_WD_TRG\n"); |
216 | #endif | 204 | #endif |
@@ -221,9 +209,7 @@ static inline void pc87413_enable_sw_wd_trg(unsigned int swc_base_addr) | |||
221 | static inline void pc87413_disable_sw_wd_trg(unsigned int swc_base_addr) | 209 | static inline void pc87413_disable_sw_wd_trg(unsigned int swc_base_addr) |
222 | { | 210 | { |
223 | /* Disable SW_WD_TRG */ | 211 | /* Disable SW_WD_TRG */ |
224 | 212 | outb_p(inb(swc_base_addr + WDCTL) & 0x7f, swc_base_addr + WDCTL); | |
225 | outb_p(inb (swc_base_addr + WDCTL) & 0x7f, swc_base_addr + WDCTL); | ||
226 | |||
227 | #ifdef DEBUG | 213 | #ifdef DEBUG |
228 | printk(KERN_INFO DPFX "Disable SW_WD_TRG\n"); | 214 | printk(KERN_INFO DPFX "Disable SW_WD_TRG\n"); |
229 | #endif | 215 | #endif |
@@ -314,8 +300,8 @@ static int pc87413_open(struct inode *inode, struct file *file) | |||
314 | /* Reload and activate timer */ | 300 | /* Reload and activate timer */ |
315 | pc87413_refresh(); | 301 | pc87413_refresh(); |
316 | 302 | ||
317 | printk(KERN_INFO MODNAME "Watchdog enabled. Timeout set to" | 303 | printk(KERN_INFO MODNAME |
318 | " %d minute(s).\n", timeout); | 304 | "Watchdog enabled. Timeout set to %d minute(s).\n", timeout); |
319 | 305 | ||
320 | return nonseekable_open(inode, file); | 306 | return nonseekable_open(inode, file); |
321 | } | 307 | } |
@@ -338,17 +324,15 @@ static int pc87413_release(struct inode *inode, struct file *file) | |||
338 | 324 | ||
339 | if (expect_close == 42) { | 325 | if (expect_close == 42) { |
340 | pc87413_disable(); | 326 | pc87413_disable(); |
341 | printk(KERN_INFO MODNAME "Watchdog disabled," | 327 | printk(KERN_INFO MODNAME |
342 | " sleeping again...\n"); | 328 | "Watchdog disabled, sleeping again...\n"); |
343 | } else { | 329 | } else { |
344 | printk(KERN_CRIT MODNAME "Unexpected close, not stopping" | 330 | printk(KERN_CRIT MODNAME |
345 | " watchdog!\n"); | 331 | "Unexpected close, not stopping watchdog!\n"); |
346 | pc87413_refresh(); | 332 | pc87413_refresh(); |
347 | } | 333 | } |
348 | |||
349 | clear_bit(0, &timer_enabled); | 334 | clear_bit(0, &timer_enabled); |
350 | expect_close = 0; | 335 | expect_close = 0; |
351 | |||
352 | return 0; | 336 | return 0; |
353 | } | 337 | } |
354 | 338 | ||
@@ -386,10 +370,11 @@ static ssize_t pc87413_write(struct file *file, const char __user *data, | |||
386 | /* reset expect flag */ | 370 | /* reset expect flag */ |
387 | expect_close = 0; | 371 | expect_close = 0; |
388 | 372 | ||
389 | /* scan to see whether or not we got the magic character */ | 373 | /* scan to see whether or not we got the |
374 | magic character */ | ||
390 | for (i = 0; i != len; i++) { | 375 | for (i = 0; i != len; i++) { |
391 | char c; | 376 | char c; |
392 | if (get_user(c, data+i)) | 377 | if (get_user(c, data + i)) |
393 | return -EFAULT; | 378 | return -EFAULT; |
394 | if (c == 'V') | 379 | if (c == 'V') |
395 | expect_close = 42; | 380 | expect_close = 42; |
@@ -404,7 +389,6 @@ static ssize_t pc87413_write(struct file *file, const char __user *data, | |||
404 | 389 | ||
405 | /** | 390 | /** |
406 | * pc87413_ioctl: | 391 | * pc87413_ioctl: |
407 | * @inode: inode of the device | ||
408 | * @file: file handle to the device | 392 | * @file: file handle to the device |
409 | * @cmd: watchdog command | 393 | * @cmd: watchdog command |
410 | * @arg: argument pointer | 394 | * @arg: argument pointer |
@@ -414,8 +398,8 @@ static ssize_t pc87413_write(struct file *file, const char __user *data, | |||
414 | * querying capabilities and current status. | 398 | * querying capabilities and current status. |
415 | */ | 399 | */ |
416 | 400 | ||
417 | static int pc87413_ioctl(struct inode *inode, struct file *file, | 401 | static long pc87413_ioctl(struct file *file, unsigned int cmd, |
418 | unsigned int cmd, unsigned long arg) | 402 | unsigned long arg) |
419 | { | 403 | { |
420 | int new_timeout; | 404 | int new_timeout; |
421 | 405 | ||
@@ -426,75 +410,58 @@ static int pc87413_ioctl(struct inode *inode, struct file *file, | |||
426 | 410 | ||
427 | static struct watchdog_info ident = { | 411 | static struct watchdog_info ident = { |
428 | .options = WDIOF_KEEPALIVEPING | | 412 | .options = WDIOF_KEEPALIVEPING | |
429 | WDIOF_SETTIMEOUT | | 413 | WDIOF_SETTIMEOUT | |
430 | WDIOF_MAGICCLOSE, | 414 | WDIOF_MAGICCLOSE, |
431 | .firmware_version = 1, | 415 | .firmware_version = 1, |
432 | .identity = "PC87413(HF/F) watchdog" | 416 | .identity = "PC87413(HF/F) watchdog", |
433 | }; | 417 | }; |
434 | 418 | ||
435 | uarg.i = (int __user *)arg; | 419 | uarg.i = (int __user *)arg; |
436 | 420 | ||
437 | switch(cmd) { | 421 | switch (cmd) { |
438 | default: | 422 | case WDIOC_GETSUPPORT: |
439 | return -ENOTTY; | 423 | return copy_to_user(uarg.ident, &ident, |
440 | 424 | sizeof(ident)) ? -EFAULT : 0; | |
441 | case WDIOC_GETSUPPORT: | 425 | case WDIOC_GETSTATUS: |
442 | return copy_to_user(uarg.ident, &ident, | 426 | return put_user(pc87413_status(), uarg.i); |
443 | sizeof(ident)) ? -EFAULT : 0; | 427 | case WDIOC_GETBOOTSTATUS: |
444 | 428 | return put_user(0, uarg.i); | |
445 | case WDIOC_GETSTATUS: | 429 | case WDIOC_SETOPTIONS: |
446 | return put_user(pc87413_status(), uarg.i); | 430 | { |
447 | 431 | int options, retval = -EINVAL; | |
448 | case WDIOC_GETBOOTSTATUS: | 432 | if (get_user(options, uarg.i)) |
449 | return put_user(0, uarg.i); | 433 | return -EFAULT; |
450 | 434 | if (options & WDIOS_DISABLECARD) { | |
451 | case WDIOC_KEEPALIVE: | 435 | pc87413_disable(); |
452 | pc87413_refresh(); | 436 | retval = 0; |
437 | } | ||
438 | if (options & WDIOS_ENABLECARD) { | ||
439 | pc87413_enable(); | ||
440 | retval = 0; | ||
441 | } | ||
442 | return retval; | ||
443 | } | ||
444 | case WDIOC_KEEPALIVE: | ||
445 | pc87413_refresh(); | ||
453 | #ifdef DEBUG | 446 | #ifdef DEBUG |
454 | printk(KERN_INFO DPFX "keepalive\n"); | 447 | printk(KERN_INFO DPFX "keepalive\n"); |
455 | #endif | 448 | #endif |
456 | return 0; | 449 | return 0; |
457 | 450 | case WDIOC_SETTIMEOUT: | |
458 | case WDIOC_SETTIMEOUT: | 451 | if (get_user(new_timeout, uarg.i)) |
459 | if (get_user(new_timeout, uarg.i)) | 452 | return -EFAULT; |
460 | return -EFAULT; | 453 | /* the API states this is given in secs */ |
461 | 454 | new_timeout /= 60; | |
462 | // the API states this is given in secs | 455 | if (new_timeout < 0 || new_timeout > MAX_TIMEOUT) |
463 | new_timeout /= 60; | 456 | return -EINVAL; |
464 | 457 | timeout = new_timeout; | |
465 | if (new_timeout < 0 || new_timeout > MAX_TIMEOUT) | 458 | pc87413_refresh(); |
466 | return -EINVAL; | 459 | /* fall through and return the new timeout... */ |
467 | 460 | case WDIOC_GETTIMEOUT: | |
468 | timeout = new_timeout; | 461 | new_timeout = timeout * 60; |
469 | pc87413_refresh(); | 462 | return put_user(new_timeout, uarg.i); |
470 | 463 | default: | |
471 | // fall through and return the new timeout... | 464 | return -ENOTTY; |
472 | |||
473 | case WDIOC_GETTIMEOUT: | ||
474 | |||
475 | new_timeout = timeout * 60; | ||
476 | |||
477 | return put_user(new_timeout, uarg.i); | ||
478 | |||
479 | case WDIOC_SETOPTIONS: | ||
480 | { | ||
481 | int options, retval = -EINVAL; | ||
482 | |||
483 | if (get_user(options, uarg.i)) | ||
484 | return -EFAULT; | ||
485 | |||
486 | if (options & WDIOS_DISABLECARD) { | ||
487 | pc87413_disable(); | ||
488 | retval = 0; | ||
489 | } | ||
490 | |||
491 | if (options & WDIOS_ENABLECARD) { | ||
492 | pc87413_enable(); | ||
493 | retval = 0; | ||
494 | } | ||
495 | |||
496 | return retval; | ||
497 | } | ||
498 | } | 465 | } |
499 | } | 466 | } |
500 | 467 | ||
@@ -517,10 +484,8 @@ static int pc87413_notify_sys(struct notifier_block *this, | |||
517 | void *unused) | 484 | void *unused) |
518 | { | 485 | { |
519 | if (code == SYS_DOWN || code == SYS_HALT) | 486 | if (code == SYS_DOWN || code == SYS_HALT) |
520 | { | ||
521 | /* Turn the card off */ | 487 | /* Turn the card off */ |
522 | pc87413_disable(); | 488 | pc87413_disable(); |
523 | } | ||
524 | return NOTIFY_DONE; | 489 | return NOTIFY_DONE; |
525 | } | 490 | } |
526 | 491 | ||
@@ -530,21 +495,19 @@ static const struct file_operations pc87413_fops = { | |||
530 | .owner = THIS_MODULE, | 495 | .owner = THIS_MODULE, |
531 | .llseek = no_llseek, | 496 | .llseek = no_llseek, |
532 | .write = pc87413_write, | 497 | .write = pc87413_write, |
533 | .ioctl = pc87413_ioctl, | 498 | .unlocked_ioctl = pc87413_ioctl, |
534 | .open = pc87413_open, | 499 | .open = pc87413_open, |
535 | .release = pc87413_release, | 500 | .release = pc87413_release, |
536 | }; | 501 | }; |
537 | 502 | ||
538 | static struct notifier_block pc87413_notifier = | 503 | static struct notifier_block pc87413_notifier = { |
539 | { | ||
540 | .notifier_call = pc87413_notify_sys, | 504 | .notifier_call = pc87413_notify_sys, |
541 | }; | 505 | }; |
542 | 506 | ||
543 | static struct miscdevice pc87413_miscdev= | 507 | static struct miscdevice pc87413_miscdev = { |
544 | { | ||
545 | .minor = WATCHDOG_MINOR, | 508 | .minor = WATCHDOG_MINOR, |
546 | .name = "watchdog", | 509 | .name = "watchdog", |
547 | .fops = &pc87413_fops | 510 | .fops = &pc87413_fops, |
548 | }; | 511 | }; |
549 | 512 | ||
550 | /* -- Module init functions -------------------------------------*/ | 513 | /* -- Module init functions -------------------------------------*/ |
@@ -561,29 +524,26 @@ static int __init pc87413_init(void) | |||
561 | { | 524 | { |
562 | int ret; | 525 | int ret; |
563 | 526 | ||
564 | printk(KERN_INFO PFX "Version " VERSION " at io 0x%X\n", WDT_INDEX_IO_PORT); | 527 | printk(KERN_INFO PFX "Version " VERSION " at io 0x%X\n", |
528 | WDT_INDEX_IO_PORT); | ||
565 | 529 | ||
566 | /* request_region(io, 2, "pc87413"); */ | 530 | /* request_region(io, 2, "pc87413"); */ |
567 | 531 | ||
568 | ret = register_reboot_notifier(&pc87413_notifier); | 532 | ret = register_reboot_notifier(&pc87413_notifier); |
569 | if (ret != 0) { | 533 | if (ret != 0) { |
570 | printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", | 534 | printk(KERN_ERR PFX |
571 | ret); | 535 | "cannot register reboot notifier (err=%d)\n", ret); |
572 | } | 536 | } |
573 | 537 | ||
574 | ret = misc_register(&pc87413_miscdev); | 538 | ret = misc_register(&pc87413_miscdev); |
575 | |||
576 | if (ret != 0) { | 539 | if (ret != 0) { |
577 | printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", | 540 | printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", |
578 | WATCHDOG_MINOR, ret); | 541 | WATCHDOG_MINOR, ret); |
579 | unregister_reboot_notifier(&pc87413_notifier); | 542 | unregister_reboot_notifier(&pc87413_notifier); |
580 | return ret; | 543 | return ret; |
581 | } | 544 | } |
582 | |||
583 | printk(KERN_INFO PFX "initialized. timeout=%d min \n", timeout); | 545 | printk(KERN_INFO PFX "initialized. timeout=%d min \n", timeout); |
584 | |||
585 | pc87413_enable(); | 546 | pc87413_enable(); |
586 | |||
587 | return 0; | 547 | return 0; |
588 | } | 548 | } |
589 | 549 | ||
@@ -600,17 +560,16 @@ static int __init pc87413_init(void) | |||
600 | static void __exit pc87413_exit(void) | 560 | static void __exit pc87413_exit(void) |
601 | { | 561 | { |
602 | /* Stop the timer before we leave */ | 562 | /* Stop the timer before we leave */ |
603 | if (!nowayout) | 563 | if (!nowayout) { |
604 | { | ||
605 | pc87413_disable(); | 564 | pc87413_disable(); |
606 | printk(KERN_INFO MODNAME "Watchdog disabled.\n"); | 565 | printk(KERN_INFO MODNAME "Watchdog disabled.\n"); |
607 | } | 566 | } |
608 | 567 | ||
609 | misc_deregister(&pc87413_miscdev); | 568 | misc_deregister(&pc87413_miscdev); |
610 | unregister_reboot_notifier(&pc87413_notifier); | 569 | unregister_reboot_notifier(&pc87413_notifier); |
611 | /* release_region(io,2); */ | 570 | /* release_region(io, 2); */ |
612 | 571 | ||
613 | printk(MODNAME " watchdog component driver removed.\n"); | 572 | printk(KERN_INFO MODNAME " watchdog component driver removed.\n"); |
614 | } | 573 | } |
615 | 574 | ||
616 | module_init(pc87413_init); | 575 | module_init(pc87413_init); |
@@ -626,8 +585,12 @@ module_param(io, int, 0); | |||
626 | MODULE_PARM_DESC(io, MODNAME " I/O port (default: " __MODULE_STRING(io) ")."); | 585 | MODULE_PARM_DESC(io, MODNAME " I/O port (default: " __MODULE_STRING(io) ")."); |
627 | 586 | ||
628 | module_param(timeout, int, 0); | 587 | module_param(timeout, int, 0); |
629 | MODULE_PARM_DESC(timeout, "Watchdog timeout in minutes (default=" __MODULE_STRING(timeout) ")."); | 588 | MODULE_PARM_DESC(timeout, |
589 | "Watchdog timeout in minutes (default=" | ||
590 | __MODULE_STRING(timeout) ")."); | ||
630 | 591 | ||
631 | module_param(nowayout, int, 0); | 592 | module_param(nowayout, int, 0); |
632 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 593 | MODULE_PARM_DESC(nowayout, |
594 | "Watchdog cannot be stopped once started (default=" | ||
595 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
633 | 596 | ||
diff --git a/drivers/watchdog/pcwd.c b/drivers/watchdog/pcwd.c index 7b41434fac8c..3b0ddc7fcf3f 100644 --- a/drivers/watchdog/pcwd.c +++ b/drivers/watchdog/pcwd.c | |||
@@ -40,13 +40,15 @@ | |||
40 | * fairly useless proc entry. | 40 | * fairly useless proc entry. |
41 | * 990610 removed said useless proc code for the merge <alan> | 41 | * 990610 removed said useless proc code for the merge <alan> |
42 | * 000403 Removed last traces of proc code. <davej> | 42 | * 000403 Removed last traces of proc code. <davej> |
43 | * 011214 Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT <Matt_Domsch@dell.com> | 43 | * 011214 Added nowayout module option to override |
44 | * CONFIG_WATCHDOG_NOWAYOUT <Matt_Domsch@dell.com> | ||
44 | * Added timeout module option to override default | 45 | * Added timeout module option to override default |
45 | */ | 46 | */ |
46 | 47 | ||
47 | /* | 48 | /* |
48 | * A bells and whistles driver is available from http://www.pcwd.de/ | 49 | * A bells and whistles driver is available from http://www.pcwd.de/ |
49 | * More info available at http://www.berkprod.com/ or http://www.pcwatchdog.com/ | 50 | * More info available at http://www.berkprod.com/ or |
51 | * http://www.pcwatchdog.com/ | ||
50 | */ | 52 | */ |
51 | 53 | ||
52 | #include <linux/module.h> /* For module specific items */ | 54 | #include <linux/module.h> /* For module specific items */ |
@@ -65,9 +67,8 @@ | |||
65 | #include <linux/isa.h> /* For isa devices */ | 67 | #include <linux/isa.h> /* For isa devices */ |
66 | #include <linux/ioport.h> /* For io-port access */ | 68 | #include <linux/ioport.h> /* For io-port access */ |
67 | #include <linux/spinlock.h> /* For spin_lock/spin_unlock/... */ | 69 | #include <linux/spinlock.h> /* For spin_lock/spin_unlock/... */ |
68 | 70 | #include <linux/uaccess.h> /* For copy_to_user/put_user/... */ | |
69 | #include <asm/uaccess.h> /* For copy_to_user/put_user/... */ | 71 | #include <linux/io.h> /* For inb/outb/... */ |
70 | #include <asm/io.h> /* For inb/outb/... */ | ||
71 | 72 | ||
72 | /* Module and version information */ | 73 | /* Module and version information */ |
73 | #define WATCHDOG_VERSION "1.20" | 74 | #define WATCHDOG_VERSION "1.20" |
@@ -111,14 +112,16 @@ static int pcwd_ioports[] = { 0x270, 0x350, 0x370, 0x000 }; | |||
111 | #define WD_REVC_WTRP 0x01 /* Watchdog Trip status */ | 112 | #define WD_REVC_WTRP 0x01 /* Watchdog Trip status */ |
112 | #define WD_REVC_HRBT 0x02 /* Watchdog Heartbeat */ | 113 | #define WD_REVC_HRBT 0x02 /* Watchdog Heartbeat */ |
113 | #define WD_REVC_TTRP 0x04 /* Temperature Trip status */ | 114 | #define WD_REVC_TTRP 0x04 /* Temperature Trip status */ |
114 | #define WD_REVC_RL2A 0x08 /* Relay 2 activated by on-board processor */ | 115 | #define WD_REVC_RL2A 0x08 /* Relay 2 activated by |
116 | on-board processor */ | ||
115 | #define WD_REVC_RL1A 0x10 /* Relay 1 active */ | 117 | #define WD_REVC_RL1A 0x10 /* Relay 1 active */ |
116 | #define WD_REVC_R2DS 0x40 /* Relay 2 disable */ | 118 | #define WD_REVC_R2DS 0x40 /* Relay 2 disable */ |
117 | #define WD_REVC_RLY2 0x80 /* Relay 2 activated? */ | 119 | #define WD_REVC_RLY2 0x80 /* Relay 2 activated? */ |
118 | /* Port 2 : Control Status #2 */ | 120 | /* Port 2 : Control Status #2 */ |
119 | #define WD_WDIS 0x10 /* Watchdog Disabled */ | 121 | #define WD_WDIS 0x10 /* Watchdog Disabled */ |
120 | #define WD_ENTP 0x20 /* Watchdog Enable Temperature Trip */ | 122 | #define WD_ENTP 0x20 /* Watchdog Enable Temperature Trip */ |
121 | #define WD_SSEL 0x40 /* Watchdog Switch Select (1:SW1 <-> 0:SW2) */ | 123 | #define WD_SSEL 0x40 /* Watchdog Switch Select |
124 | (1:SW1 <-> 0:SW2) */ | ||
122 | #define WD_WCMD 0x80 /* Watchdog Command Mode */ | 125 | #define WD_WCMD 0x80 /* Watchdog Command Mode */ |
123 | 126 | ||
124 | /* max. time we give an ISA watchdog card to process a command */ | 127 | /* max. time we give an ISA watchdog card to process a command */ |
@@ -142,7 +145,7 @@ static int pcwd_ioports[] = { 0x270, 0x350, 0x370, 0x000 }; | |||
142 | #define CMD_ISA_RESET_RELAYS 0x0D | 145 | #define CMD_ISA_RESET_RELAYS 0x0D |
143 | 146 | ||
144 | /* Watchdog's Dip Switch heartbeat values */ | 147 | /* Watchdog's Dip Switch heartbeat values */ |
145 | static const int heartbeat_tbl [] = { | 148 | static const int heartbeat_tbl[] = { |
146 | 20, /* OFF-OFF-OFF = 20 Sec */ | 149 | 20, /* OFF-OFF-OFF = 20 Sec */ |
147 | 40, /* OFF-OFF-ON = 40 Sec */ | 150 | 40, /* OFF-OFF-ON = 40 Sec */ |
148 | 60, /* OFF-ON-OFF = 1 Min */ | 151 | 60, /* OFF-ON-OFF = 1 Min */ |
@@ -168,11 +171,15 @@ static int cards_found; | |||
168 | static atomic_t open_allowed = ATOMIC_INIT(1); | 171 | static atomic_t open_allowed = ATOMIC_INIT(1); |
169 | static char expect_close; | 172 | static char expect_close; |
170 | static int temp_panic; | 173 | static int temp_panic; |
171 | static struct { /* this is private data for each ISA-PC watchdog card */ | 174 | |
175 | /* this is private data for each ISA-PC watchdog card */ | ||
176 | static struct { | ||
172 | char fw_ver_str[6]; /* The cards firmware version */ | 177 | char fw_ver_str[6]; /* The cards firmware version */ |
173 | int revision; /* The card's revision */ | 178 | int revision; /* The card's revision */ |
174 | int supports_temp; /* Wether or not the card has a temperature device */ | 179 | int supports_temp; /* Whether or not the card has |
175 | int command_mode; /* Wether or not the card is in command mode */ | 180 | a temperature device */ |
181 | int command_mode; /* Whether or not the card is in | ||
182 | command mode */ | ||
176 | int boot_status; /* The card's boot status */ | 183 | int boot_status; /* The card's boot status */ |
177 | int io_addr; /* The cards I/O address */ | 184 | int io_addr; /* The cards I/O address */ |
178 | spinlock_t io_lock; /* the lock for io operations */ | 185 | spinlock_t io_lock; /* the lock for io operations */ |
@@ -186,16 +193,20 @@ static struct { /* this is private data for each ISA-PC watchdog card */ | |||
186 | #define DEBUG 2 /* print fancy stuff too */ | 193 | #define DEBUG 2 /* print fancy stuff too */ |
187 | static int debug = QUIET; | 194 | static int debug = QUIET; |
188 | module_param(debug, int, 0); | 195 | module_param(debug, int, 0); |
189 | MODULE_PARM_DESC(debug, "Debug level: 0=Quiet, 1=Verbose, 2=Debug (default=0)"); | 196 | MODULE_PARM_DESC(debug, |
197 | "Debug level: 0=Quiet, 1=Verbose, 2=Debug (default=0)"); | ||
190 | 198 | ||
191 | #define WATCHDOG_HEARTBEAT 0 /* default heartbeat = delay-time from dip-switches */ | 199 | /* default heartbeat = delay-time from dip-switches */ |
200 | #define WATCHDOG_HEARTBEAT 0 | ||
192 | static int heartbeat = WATCHDOG_HEARTBEAT; | 201 | static int heartbeat = WATCHDOG_HEARTBEAT; |
193 | module_param(heartbeat, int, 0); | 202 | module_param(heartbeat, int, 0); |
194 | MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (2<=heartbeat<=7200 or 0=delay-time from dip-switches, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")"); | 203 | MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (2 <= heartbeat <= 7200 or 0=delay-time from dip-switches, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")"); |
195 | 204 | ||
196 | static int nowayout = WATCHDOG_NOWAYOUT; | 205 | static int nowayout = WATCHDOG_NOWAYOUT; |
197 | module_param(nowayout, int, 0); | 206 | module_param(nowayout, int, 0); |
198 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 207 | MODULE_PARM_DESC(nowayout, |
208 | "Watchdog cannot be stopped once started (default=" | ||
209 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
199 | 210 | ||
200 | /* | 211 | /* |
201 | * Internal functions | 212 | * Internal functions |
@@ -224,7 +235,7 @@ static int send_isa_command(int cmd) | |||
224 | if (port0 == last_port0) | 235 | if (port0 == last_port0) |
225 | break; /* Data is stable */ | 236 | break; /* Data is stable */ |
226 | 237 | ||
227 | udelay (250); | 238 | udelay(250); |
228 | } | 239 | } |
229 | 240 | ||
230 | if (debug >= DEBUG) | 241 | if (debug >= DEBUG) |
@@ -236,7 +247,7 @@ static int send_isa_command(int cmd) | |||
236 | 247 | ||
237 | static int set_command_mode(void) | 248 | static int set_command_mode(void) |
238 | { | 249 | { |
239 | int i, found=0, count=0; | 250 | int i, found = 0, count = 0; |
240 | 251 | ||
241 | /* Set the card into command mode */ | 252 | /* Set the card into command mode */ |
242 | spin_lock(&pcwd_private.io_lock); | 253 | spin_lock(&pcwd_private.io_lock); |
@@ -261,7 +272,7 @@ static int set_command_mode(void) | |||
261 | printk(KERN_DEBUG PFX "command_mode=%d\n", | 272 | printk(KERN_DEBUG PFX "command_mode=%d\n", |
262 | pcwd_private.command_mode); | 273 | pcwd_private.command_mode); |
263 | 274 | ||
264 | return(found); | 275 | return found; |
265 | } | 276 | } |
266 | 277 | ||
267 | static void unset_command_mode(void) | 278 | static void unset_command_mode(void) |
@@ -296,7 +307,8 @@ static inline void pcwd_get_firmware(void) | |||
296 | ten = send_isa_command(CMD_ISA_VERSION_TENTH); | 307 | ten = send_isa_command(CMD_ISA_VERSION_TENTH); |
297 | hund = send_isa_command(CMD_ISA_VERSION_HUNDRETH); | 308 | hund = send_isa_command(CMD_ISA_VERSION_HUNDRETH); |
298 | minor = send_isa_command(CMD_ISA_VERSION_MINOR); | 309 | minor = send_isa_command(CMD_ISA_VERSION_MINOR); |
299 | sprintf(pcwd_private.fw_ver_str, "%c.%c%c%c", one, ten, hund, minor); | 310 | sprintf(pcwd_private.fw_ver_str, "%c.%c%c%c", |
311 | one, ten, hund, minor); | ||
300 | } | 312 | } |
301 | unset_command_mode(); | 313 | unset_command_mode(); |
302 | 314 | ||
@@ -305,7 +317,7 @@ static inline void pcwd_get_firmware(void) | |||
305 | 317 | ||
306 | static inline int pcwd_get_option_switches(void) | 318 | static inline int pcwd_get_option_switches(void) |
307 | { | 319 | { |
308 | int option_switches=0; | 320 | int option_switches = 0; |
309 | 321 | ||
310 | if (set_command_mode()) { | 322 | if (set_command_mode()) { |
311 | /* Get switch settings */ | 323 | /* Get switch settings */ |
@@ -313,7 +325,7 @@ static inline int pcwd_get_option_switches(void) | |||
313 | } | 325 | } |
314 | 326 | ||
315 | unset_command_mode(); | 327 | unset_command_mode(); |
316 | return(option_switches); | 328 | return option_switches; |
317 | } | 329 | } |
318 | 330 | ||
319 | static void pcwd_show_card_info(void) | 331 | static void pcwd_show_card_info(void) |
@@ -322,7 +334,9 @@ static void pcwd_show_card_info(void) | |||
322 | 334 | ||
323 | /* Get some extra info from the hardware (in command/debug/diag mode) */ | 335 | /* Get some extra info from the hardware (in command/debug/diag mode) */ |
324 | if (pcwd_private.revision == PCWD_REVISION_A) | 336 | if (pcwd_private.revision == PCWD_REVISION_A) |
325 | printk(KERN_INFO PFX "ISA-PC Watchdog (REV.A) detected at port 0x%04x\n", pcwd_private.io_addr); | 337 | printk(KERN_INFO PFX |
338 | "ISA-PC Watchdog (REV.A) detected at port 0x%04x\n", | ||
339 | pcwd_private.io_addr); | ||
326 | else if (pcwd_private.revision == PCWD_REVISION_C) { | 340 | else if (pcwd_private.revision == PCWD_REVISION_C) { |
327 | pcwd_get_firmware(); | 341 | pcwd_get_firmware(); |
328 | printk(KERN_INFO PFX "ISA-PC Watchdog (REV.C) detected at port 0x%04x (Firmware version: %s)\n", | 342 | printk(KERN_INFO PFX "ISA-PC Watchdog (REV.C) detected at port 0x%04x (Firmware version: %s)\n", |
@@ -347,12 +361,15 @@ static void pcwd_show_card_info(void) | |||
347 | printk(KERN_INFO PFX "Previous reboot was caused by the card\n"); | 361 | printk(KERN_INFO PFX "Previous reboot was caused by the card\n"); |
348 | 362 | ||
349 | if (pcwd_private.boot_status & WDIOF_OVERHEAT) { | 363 | if (pcwd_private.boot_status & WDIOF_OVERHEAT) { |
350 | printk(KERN_EMERG PFX "Card senses a CPU Overheat. Panicking!\n"); | 364 | printk(KERN_EMERG PFX |
351 | printk(KERN_EMERG PFX "CPU Overheat\n"); | 365 | "Card senses a CPU Overheat. Panicking!\n"); |
366 | printk(KERN_EMERG PFX | ||
367 | "CPU Overheat\n"); | ||
352 | } | 368 | } |
353 | 369 | ||
354 | if (pcwd_private.boot_status == 0) | 370 | if (pcwd_private.boot_status == 0) |
355 | printk(KERN_INFO PFX "No previous trip detected - Cold boot or reset\n"); | 371 | printk(KERN_INFO PFX |
372 | "No previous trip detected - Cold boot or reset\n"); | ||
356 | } | 373 | } |
357 | 374 | ||
358 | static void pcwd_timer_ping(unsigned long data) | 375 | static void pcwd_timer_ping(unsigned long data) |
@@ -361,11 +378,12 @@ static void pcwd_timer_ping(unsigned long data) | |||
361 | 378 | ||
362 | /* If we got a heartbeat pulse within the WDT_INTERVAL | 379 | /* If we got a heartbeat pulse within the WDT_INTERVAL |
363 | * we agree to ping the WDT */ | 380 | * we agree to ping the WDT */ |
364 | if(time_before(jiffies, pcwd_private.next_heartbeat)) { | 381 | if (time_before(jiffies, pcwd_private.next_heartbeat)) { |
365 | /* Ping the watchdog */ | 382 | /* Ping the watchdog */ |
366 | spin_lock(&pcwd_private.io_lock); | 383 | spin_lock(&pcwd_private.io_lock); |
367 | if (pcwd_private.revision == PCWD_REVISION_A) { | 384 | if (pcwd_private.revision == PCWD_REVISION_A) { |
368 | /* Rev A cards are reset by setting the WD_WDRST bit in register 1 */ | 385 | /* Rev A cards are reset by setting the |
386 | WD_WDRST bit in register 1 */ | ||
369 | wdrst_stat = inb_p(pcwd_private.io_addr); | 387 | wdrst_stat = inb_p(pcwd_private.io_addr); |
370 | wdrst_stat &= 0x0F; | 388 | wdrst_stat &= 0x0F; |
371 | wdrst_stat |= WD_WDRST; | 389 | wdrst_stat |= WD_WDRST; |
@@ -381,7 +399,8 @@ static void pcwd_timer_ping(unsigned long data) | |||
381 | 399 | ||
382 | spin_unlock(&pcwd_private.io_lock); | 400 | spin_unlock(&pcwd_private.io_lock); |
383 | } else { | 401 | } else { |
384 | printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n"); | 402 | printk(KERN_WARNING PFX |
403 | "Heartbeat lost! Will not ping the watchdog\n"); | ||
385 | } | 404 | } |
386 | } | 405 | } |
387 | 406 | ||
@@ -454,7 +473,7 @@ static int pcwd_keepalive(void) | |||
454 | 473 | ||
455 | static int pcwd_set_heartbeat(int t) | 474 | static int pcwd_set_heartbeat(int t) |
456 | { | 475 | { |
457 | if ((t < 2) || (t > 7200)) /* arbitrary upper limit */ | 476 | if (t < 2 || t > 7200) /* arbitrary upper limit */ |
458 | return -EINVAL; | 477 | return -EINVAL; |
459 | 478 | ||
460 | heartbeat = t; | 479 | heartbeat = t; |
@@ -470,7 +489,7 @@ static int pcwd_get_status(int *status) | |||
470 | { | 489 | { |
471 | int control_status; | 490 | int control_status; |
472 | 491 | ||
473 | *status=0; | 492 | *status = 0; |
474 | spin_lock(&pcwd_private.io_lock); | 493 | spin_lock(&pcwd_private.io_lock); |
475 | if (pcwd_private.revision == PCWD_REVISION_A) | 494 | if (pcwd_private.revision == PCWD_REVISION_A) |
476 | /* Rev A cards return status information from | 495 | /* Rev A cards return status information from |
@@ -494,9 +513,9 @@ static int pcwd_get_status(int *status) | |||
494 | if (control_status & WD_T110) { | 513 | if (control_status & WD_T110) { |
495 | *status |= WDIOF_OVERHEAT; | 514 | *status |= WDIOF_OVERHEAT; |
496 | if (temp_panic) { | 515 | if (temp_panic) { |
497 | printk(KERN_INFO PFX "Temperature overheat trip!\n"); | 516 | printk(KERN_INFO PFX |
517 | "Temperature overheat trip!\n"); | ||
498 | kernel_power_off(); | 518 | kernel_power_off(); |
499 | /* or should we just do a: panic(PFX "Temperature overheat trip!\n"); */ | ||
500 | } | 519 | } |
501 | } | 520 | } |
502 | } else { | 521 | } else { |
@@ -506,9 +525,9 @@ static int pcwd_get_status(int *status) | |||
506 | if (control_status & WD_REVC_TTRP) { | 525 | if (control_status & WD_REVC_TTRP) { |
507 | *status |= WDIOF_OVERHEAT; | 526 | *status |= WDIOF_OVERHEAT; |
508 | if (temp_panic) { | 527 | if (temp_panic) { |
509 | printk(KERN_INFO PFX "Temperature overheat trip!\n"); | 528 | printk(KERN_INFO PFX |
529 | "Temperature overheat trip!\n"); | ||
510 | kernel_power_off(); | 530 | kernel_power_off(); |
511 | /* or should we just do a: panic(PFX "Temperature overheat trip!\n"); */ | ||
512 | } | 531 | } |
513 | } | 532 | } |
514 | } | 533 | } |
@@ -524,18 +543,21 @@ static int pcwd_clear_status(void) | |||
524 | spin_lock(&pcwd_private.io_lock); | 543 | spin_lock(&pcwd_private.io_lock); |
525 | 544 | ||
526 | if (debug >= VERBOSE) | 545 | if (debug >= VERBOSE) |
527 | printk(KERN_INFO PFX "clearing watchdog trip status\n"); | 546 | printk(KERN_INFO PFX |
547 | "clearing watchdog trip status\n"); | ||
528 | 548 | ||
529 | control_status = inb_p(pcwd_private.io_addr + 1); | 549 | control_status = inb_p(pcwd_private.io_addr + 1); |
530 | 550 | ||
531 | if (debug >= DEBUG) { | 551 | if (debug >= DEBUG) { |
532 | printk(KERN_DEBUG PFX "status was: 0x%02x\n", control_status); | 552 | printk(KERN_DEBUG PFX "status was: 0x%02x\n", |
553 | control_status); | ||
533 | printk(KERN_DEBUG PFX "sending: 0x%02x\n", | 554 | printk(KERN_DEBUG PFX "sending: 0x%02x\n", |
534 | (control_status & WD_REVC_R2DS)); | 555 | (control_status & WD_REVC_R2DS)); |
535 | } | 556 | } |
536 | 557 | ||
537 | /* clear reset status & Keep Relay 2 disable state as it is */ | 558 | /* clear reset status & Keep Relay 2 disable state as it is */ |
538 | outb_p((control_status & WD_REVC_R2DS), pcwd_private.io_addr + 1); | 559 | outb_p((control_status & WD_REVC_R2DS), |
560 | pcwd_private.io_addr + 1); | ||
539 | 561 | ||
540 | spin_unlock(&pcwd_private.io_lock); | 562 | spin_unlock(&pcwd_private.io_lock); |
541 | } | 563 | } |
@@ -572,8 +594,7 @@ static int pcwd_get_temperature(int *temperature) | |||
572 | * /dev/watchdog handling | 594 | * /dev/watchdog handling |
573 | */ | 595 | */ |
574 | 596 | ||
575 | static int pcwd_ioctl(struct inode *inode, struct file *file, | 597 | static long pcwd_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
576 | unsigned int cmd, unsigned long arg) | ||
577 | { | 598 | { |
578 | int rv; | 599 | int rv; |
579 | int status; | 600 | int status; |
@@ -590,12 +611,9 @@ static int pcwd_ioctl(struct inode *inode, struct file *file, | |||
590 | .identity = "PCWD", | 611 | .identity = "PCWD", |
591 | }; | 612 | }; |
592 | 613 | ||
593 | switch(cmd) { | 614 | switch (cmd) { |
594 | default: | ||
595 | return -ENOTTY; | ||
596 | |||
597 | case WDIOC_GETSUPPORT: | 615 | case WDIOC_GETSUPPORT: |
598 | if(copy_to_user(argp, &ident, sizeof(ident))) | 616 | if (copy_to_user(argp, &ident, sizeof(ident))) |
599 | return -EFAULT; | 617 | return -EFAULT; |
600 | return 0; | 618 | return 0; |
601 | 619 | ||
@@ -613,25 +631,22 @@ static int pcwd_ioctl(struct inode *inode, struct file *file, | |||
613 | return put_user(temperature, argp); | 631 | return put_user(temperature, argp); |
614 | 632 | ||
615 | case WDIOC_SETOPTIONS: | 633 | case WDIOC_SETOPTIONS: |
616 | if (pcwd_private.revision == PCWD_REVISION_C) | 634 | if (pcwd_private.revision == PCWD_REVISION_C) { |
617 | { | 635 | if (get_user(rv, argp)) |
618 | if(copy_from_user(&rv, argp, sizeof(int))) | ||
619 | return -EFAULT; | 636 | return -EFAULT; |
620 | 637 | ||
621 | if (rv & WDIOS_DISABLECARD) | 638 | if (rv & WDIOS_DISABLECARD) { |
622 | { | 639 | status = pcwd_stop(); |
623 | return pcwd_stop(); | 640 | if (status < 0) |
641 | return status; | ||
624 | } | 642 | } |
625 | 643 | if (rv & WDIOS_ENABLECARD) { | |
626 | if (rv & WDIOS_ENABLECARD) | 644 | status = pcwd_start(); |
627 | { | 645 | if (status < 0) |
628 | return pcwd_start(); | 646 | return status; |
629 | } | 647 | } |
630 | |||
631 | if (rv & WDIOS_TEMPPANIC) | 648 | if (rv & WDIOS_TEMPPANIC) |
632 | { | ||
633 | temp_panic = 1; | 649 | temp_panic = 1; |
634 | } | ||
635 | } | 650 | } |
636 | return -EINVAL; | 651 | return -EINVAL; |
637 | 652 | ||
@@ -651,6 +666,9 @@ static int pcwd_ioctl(struct inode *inode, struct file *file, | |||
651 | 666 | ||
652 | case WDIOC_GETTIMEOUT: | 667 | case WDIOC_GETTIMEOUT: |
653 | return put_user(heartbeat, argp); | 668 | return put_user(heartbeat, argp); |
669 | |||
670 | default: | ||
671 | return -ENOTTY; | ||
654 | } | 672 | } |
655 | 673 | ||
656 | return 0; | 674 | return 0; |
@@ -682,16 +700,10 @@ static ssize_t pcwd_write(struct file *file, const char __user *buf, size_t len, | |||
682 | 700 | ||
683 | static int pcwd_open(struct inode *inode, struct file *file) | 701 | static int pcwd_open(struct inode *inode, struct file *file) |
684 | { | 702 | { |
685 | if (!atomic_dec_and_test(&open_allowed) ) { | 703 | if (test_and_set_bit(0, &open_allowed)) |
686 | if (debug >= VERBOSE) | ||
687 | printk(KERN_ERR PFX "Attempt to open already opened device.\n"); | ||
688 | atomic_inc( &open_allowed ); | ||
689 | return -EBUSY; | 704 | return -EBUSY; |
690 | } | ||
691 | |||
692 | if (nowayout) | 705 | if (nowayout) |
693 | __module_get(THIS_MODULE); | 706 | __module_get(THIS_MODULE); |
694 | |||
695 | /* Activate */ | 707 | /* Activate */ |
696 | pcwd_start(); | 708 | pcwd_start(); |
697 | pcwd_keepalive(); | 709 | pcwd_keepalive(); |
@@ -700,14 +712,15 @@ static int pcwd_open(struct inode *inode, struct file *file) | |||
700 | 712 | ||
701 | static int pcwd_close(struct inode *inode, struct file *file) | 713 | static int pcwd_close(struct inode *inode, struct file *file) |
702 | { | 714 | { |
703 | if (expect_close == 42) { | 715 | if (expect_close == 42) |
704 | pcwd_stop(); | 716 | pcwd_stop(); |
705 | } else { | 717 | else { |
706 | printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); | 718 | printk(KERN_CRIT PFX |
719 | "Unexpected close, not stopping watchdog!\n"); | ||
707 | pcwd_keepalive(); | 720 | pcwd_keepalive(); |
708 | } | 721 | } |
709 | expect_close = 0; | 722 | expect_close = 0; |
710 | atomic_inc( &open_allowed ); | 723 | clear_bit(0, &open_allowed); |
711 | return 0; | 724 | return 0; |
712 | } | 725 | } |
713 | 726 | ||
@@ -750,7 +763,7 @@ static const struct file_operations pcwd_fops = { | |||
750 | .owner = THIS_MODULE, | 763 | .owner = THIS_MODULE, |
751 | .llseek = no_llseek, | 764 | .llseek = no_llseek, |
752 | .write = pcwd_write, | 765 | .write = pcwd_write, |
753 | .ioctl = pcwd_ioctl, | 766 | .unlocked_ioctl = pcwd_ioctl, |
754 | .open = pcwd_open, | 767 | .open = pcwd_open, |
755 | .release = pcwd_close, | 768 | .release = pcwd_close, |
756 | }; | 769 | }; |
@@ -788,7 +801,7 @@ static inline int get_revision(void) | |||
788 | * presumes a floating bus reads as 0xff. */ | 801 | * presumes a floating bus reads as 0xff. */ |
789 | if ((inb(pcwd_private.io_addr + 2) == 0xFF) || | 802 | if ((inb(pcwd_private.io_addr + 2) == 0xFF) || |
790 | (inb(pcwd_private.io_addr + 3) == 0xFF)) | 803 | (inb(pcwd_private.io_addr + 3) == 0xFF)) |
791 | r=PCWD_REVISION_A; | 804 | r = PCWD_REVISION_A; |
792 | spin_unlock(&pcwd_private.io_lock); | 805 | spin_unlock(&pcwd_private.io_lock); |
793 | 806 | ||
794 | return r; | 807 | return r; |
@@ -803,7 +816,7 @@ static inline int get_revision(void) | |||
803 | */ | 816 | */ |
804 | static int __devinit pcwd_isa_match(struct device *dev, unsigned int id) | 817 | static int __devinit pcwd_isa_match(struct device *dev, unsigned int id) |
805 | { | 818 | { |
806 | int base_addr=pcwd_ioports[id]; | 819 | int base_addr = pcwd_ioports[id]; |
807 | int port0, last_port0; /* Reg 0, in case it's REV A */ | 820 | int port0, last_port0; /* Reg 0, in case it's REV A */ |
808 | int port1, last_port1; /* Register 1 for REV C cards */ | 821 | int port1, last_port1; /* Register 1 for REV C cards */ |
809 | int i; | 822 | int i; |
@@ -813,7 +826,7 @@ static int __devinit pcwd_isa_match(struct device *dev, unsigned int id) | |||
813 | printk(KERN_DEBUG PFX "pcwd_isa_match id=%d\n", | 826 | printk(KERN_DEBUG PFX "pcwd_isa_match id=%d\n", |
814 | id); | 827 | id); |
815 | 828 | ||
816 | if (!request_region (base_addr, 4, "PCWD")) { | 829 | if (!request_region(base_addr, 4, "PCWD")) { |
817 | printk(KERN_INFO PFX "Port 0x%04x unavailable\n", base_addr); | 830 | printk(KERN_INFO PFX "Port 0x%04x unavailable\n", base_addr); |
818 | return 0; | 831 | return 0; |
819 | } | 832 | } |
@@ -842,7 +855,7 @@ static int __devinit pcwd_isa_match(struct device *dev, unsigned int id) | |||
842 | } | 855 | } |
843 | } | 856 | } |
844 | } | 857 | } |
845 | release_region (base_addr, 4); | 858 | release_region(base_addr, 4); |
846 | 859 | ||
847 | return retval; | 860 | return retval; |
848 | } | 861 | } |
@@ -857,7 +870,8 @@ static int __devinit pcwd_isa_probe(struct device *dev, unsigned int id) | |||
857 | 870 | ||
858 | cards_found++; | 871 | cards_found++; |
859 | if (cards_found == 1) | 872 | if (cards_found == 1) |
860 | printk(KERN_INFO PFX "v%s Ken Hollis (kenji@bitgate.com)\n", WD_VER); | 873 | printk(KERN_INFO PFX "v%s Ken Hollis (kenji@bitgate.com)\n", |
874 | WD_VER); | ||
861 | 875 | ||
862 | if (cards_found > 1) { | 876 | if (cards_found > 1) { |
863 | printk(KERN_ERR PFX "This driver only supports 1 device\n"); | 877 | printk(KERN_ERR PFX "This driver only supports 1 device\n"); |
@@ -875,10 +889,11 @@ static int __devinit pcwd_isa_probe(struct device *dev, unsigned int id) | |||
875 | /* Check card's revision */ | 889 | /* Check card's revision */ |
876 | pcwd_private.revision = get_revision(); | 890 | pcwd_private.revision = get_revision(); |
877 | 891 | ||
878 | if (!request_region(pcwd_private.io_addr, (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4, "PCWD")) { | 892 | if (!request_region(pcwd_private.io_addr, |
893 | (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4, "PCWD")) { | ||
879 | printk(KERN_ERR PFX "I/O address 0x%04x already in use\n", | 894 | printk(KERN_ERR PFX "I/O address 0x%04x already in use\n", |
880 | pcwd_private.io_addr); | 895 | pcwd_private.io_addr); |
881 | ret=-EIO; | 896 | ret = -EIO; |
882 | goto error_request_region; | 897 | goto error_request_region; |
883 | } | 898 | } |
884 | 899 | ||
@@ -908,26 +923,30 @@ static int __devinit pcwd_isa_probe(struct device *dev, unsigned int id) | |||
908 | if (heartbeat == 0) | 923 | if (heartbeat == 0) |
909 | heartbeat = heartbeat_tbl[(pcwd_get_option_switches() & 0x07)]; | 924 | heartbeat = heartbeat_tbl[(pcwd_get_option_switches() & 0x07)]; |
910 | 925 | ||
911 | /* Check that the heartbeat value is within it's range ; if not reset to the default */ | 926 | /* Check that the heartbeat value is within it's range; |
927 | if not reset to the default */ | ||
912 | if (pcwd_set_heartbeat(heartbeat)) { | 928 | if (pcwd_set_heartbeat(heartbeat)) { |
913 | pcwd_set_heartbeat(WATCHDOG_HEARTBEAT); | 929 | pcwd_set_heartbeat(WATCHDOG_HEARTBEAT); |
914 | printk(KERN_INFO PFX "heartbeat value must be 2<=heartbeat<=7200, using %d\n", | 930 | printk(KERN_INFO PFX |
915 | WATCHDOG_HEARTBEAT); | 931 | "heartbeat value must be 2 <= heartbeat <= 7200, using %d\n", |
932 | WATCHDOG_HEARTBEAT); | ||
916 | } | 933 | } |
917 | 934 | ||
918 | if (pcwd_private.supports_temp) { | 935 | if (pcwd_private.supports_temp) { |
919 | ret = misc_register(&temp_miscdev); | 936 | ret = misc_register(&temp_miscdev); |
920 | if (ret) { | 937 | if (ret) { |
921 | printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", | 938 | printk(KERN_ERR PFX |
922 | TEMP_MINOR, ret); | 939 | "cannot register miscdev on minor=%d (err=%d)\n", |
940 | TEMP_MINOR, ret); | ||
923 | goto error_misc_register_temp; | 941 | goto error_misc_register_temp; |
924 | } | 942 | } |
925 | } | 943 | } |
926 | 944 | ||
927 | ret = misc_register(&pcwd_miscdev); | 945 | ret = misc_register(&pcwd_miscdev); |
928 | if (ret) { | 946 | if (ret) { |
929 | printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", | 947 | printk(KERN_ERR PFX |
930 | WATCHDOG_MINOR, ret); | 948 | "cannot register miscdev on minor=%d (err=%d)\n", |
949 | WATCHDOG_MINOR, ret); | ||
931 | goto error_misc_register_watchdog; | 950 | goto error_misc_register_watchdog; |
932 | } | 951 | } |
933 | 952 | ||
@@ -940,7 +959,8 @@ error_misc_register_watchdog: | |||
940 | if (pcwd_private.supports_temp) | 959 | if (pcwd_private.supports_temp) |
941 | misc_deregister(&temp_miscdev); | 960 | misc_deregister(&temp_miscdev); |
942 | error_misc_register_temp: | 961 | error_misc_register_temp: |
943 | release_region(pcwd_private.io_addr, (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4); | 962 | release_region(pcwd_private.io_addr, |
963 | (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4); | ||
944 | error_request_region: | 964 | error_request_region: |
945 | pcwd_private.io_addr = 0x0000; | 965 | pcwd_private.io_addr = 0x0000; |
946 | cards_found--; | 966 | cards_found--; |
@@ -964,7 +984,8 @@ static int __devexit pcwd_isa_remove(struct device *dev, unsigned int id) | |||
964 | misc_deregister(&pcwd_miscdev); | 984 | misc_deregister(&pcwd_miscdev); |
965 | if (pcwd_private.supports_temp) | 985 | if (pcwd_private.supports_temp) |
966 | misc_deregister(&temp_miscdev); | 986 | misc_deregister(&temp_miscdev); |
967 | release_region(pcwd_private.io_addr, (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4); | 987 | release_region(pcwd_private.io_addr, |
988 | (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4); | ||
968 | pcwd_private.io_addr = 0x0000; | 989 | pcwd_private.io_addr = 0x0000; |
969 | cards_found--; | 990 | cards_found--; |
970 | 991 | ||
diff --git a/drivers/watchdog/pcwd_pci.c b/drivers/watchdog/pcwd_pci.c index 61a89e959642..90eb1d4271d7 100644 --- a/drivers/watchdog/pcwd_pci.c +++ b/drivers/watchdog/pcwd_pci.c | |||
@@ -46,9 +46,8 @@ | |||
46 | #include <linux/pci.h> /* For pci functions */ | 46 | #include <linux/pci.h> /* For pci functions */ |
47 | #include <linux/ioport.h> /* For io-port access */ | 47 | #include <linux/ioport.h> /* For io-port access */ |
48 | #include <linux/spinlock.h> /* For spin_lock/spin_unlock/... */ | 48 | #include <linux/spinlock.h> /* For spin_lock/spin_unlock/... */ |
49 | 49 | #include <linux/uaccess.h> /* For copy_to_user/put_user/... */ | |
50 | #include <asm/uaccess.h> /* For copy_to_user/put_user/... */ | 50 | #include <linux/io.h> /* For inb/outb/... */ |
51 | #include <asm/io.h> /* For inb/outb/... */ | ||
52 | 51 | ||
53 | /* Module and version information */ | 52 | /* Module and version information */ |
54 | #define WATCHDOG_VERSION "1.03" | 53 | #define WATCHDOG_VERSION "1.03" |
@@ -97,7 +96,7 @@ | |||
97 | #define CMD_GET_CLEAR_RESET_COUNT 0x84 | 96 | #define CMD_GET_CLEAR_RESET_COUNT 0x84 |
98 | 97 | ||
99 | /* Watchdog's Dip Switch heartbeat values */ | 98 | /* Watchdog's Dip Switch heartbeat values */ |
100 | static const int heartbeat_tbl [] = { | 99 | static const int heartbeat_tbl[] = { |
101 | 5, /* OFF-OFF-OFF = 5 Sec */ | 100 | 5, /* OFF-OFF-OFF = 5 Sec */ |
102 | 10, /* OFF-OFF-ON = 10 Sec */ | 101 | 10, /* OFF-OFF-ON = 10 Sec */ |
103 | 30, /* OFF-ON-OFF = 30 Sec */ | 102 | 30, /* OFF-ON-OFF = 30 Sec */ |
@@ -220,11 +219,10 @@ static void pcipcwd_show_card_info(void) | |||
220 | int option_switches; | 219 | int option_switches; |
221 | 220 | ||
222 | got_fw_rev = send_command(CMD_GET_FIRMWARE_VERSION, &fw_rev_major, &fw_rev_minor); | 221 | got_fw_rev = send_command(CMD_GET_FIRMWARE_VERSION, &fw_rev_major, &fw_rev_minor); |
223 | if (got_fw_rev) { | 222 | if (got_fw_rev) |
224 | sprintf(fw_ver_str, "%u.%02u", fw_rev_major, fw_rev_minor); | 223 | sprintf(fw_ver_str, "%u.%02u", fw_rev_major, fw_rev_minor); |
225 | } else { | 224 | else |
226 | sprintf(fw_ver_str, "<card no answer>"); | 225 | sprintf(fw_ver_str, "<card no answer>"); |
227 | } | ||
228 | 226 | ||
229 | /* Get switch settings */ | 227 | /* Get switch settings */ |
230 | option_switches = pcipcwd_get_option_switches(); | 228 | option_switches = pcipcwd_get_option_switches(); |
@@ -331,7 +329,7 @@ static int pcipcwd_get_status(int *status) | |||
331 | { | 329 | { |
332 | int control_status; | 330 | int control_status; |
333 | 331 | ||
334 | *status=0; | 332 | *status = 0; |
335 | control_status = inb_p(pcipcwd_private.io_addr + 1); | 333 | control_status = inb_p(pcipcwd_private.io_addr + 1); |
336 | if (control_status & WD_PCI_WTRP) | 334 | if (control_status & WD_PCI_WTRP) |
337 | *status |= WDIOF_CARDRESET; | 335 | *status |= WDIOF_CARDRESET; |
@@ -369,8 +367,8 @@ static int pcipcwd_clear_status(void) | |||
369 | outb_p((control_status & WD_PCI_R2DS) | WD_PCI_WTRP, pcipcwd_private.io_addr + 1); | 367 | outb_p((control_status & WD_PCI_R2DS) | WD_PCI_WTRP, pcipcwd_private.io_addr + 1); |
370 | 368 | ||
371 | /* clear reset counter */ | 369 | /* clear reset counter */ |
372 | msb=0; | 370 | msb = 0; |
373 | reset_counter=0xff; | 371 | reset_counter = 0xff; |
374 | send_command(CMD_GET_CLEAR_RESET_COUNT, &msb, &reset_counter); | 372 | send_command(CMD_GET_CLEAR_RESET_COUNT, &msb, &reset_counter); |
375 | 373 | ||
376 | if (debug >= DEBUG) { | 374 | if (debug >= DEBUG) { |
@@ -442,7 +440,7 @@ static ssize_t pcipcwd_write(struct file *file, const char __user *data, | |||
442 | /* scan to see whether or not we got the magic character */ | 440 | /* scan to see whether or not we got the magic character */ |
443 | for (i = 0; i != len; i++) { | 441 | for (i = 0; i != len; i++) { |
444 | char c; | 442 | char c; |
445 | if(get_user(c, data+i)) | 443 | if (get_user(c, data + i)) |
446 | return -EFAULT; | 444 | return -EFAULT; |
447 | if (c == 'V') | 445 | if (c == 'V') |
448 | expect_release = 42; | 446 | expect_release = 42; |
@@ -455,8 +453,8 @@ static ssize_t pcipcwd_write(struct file *file, const char __user *data, | |||
455 | return len; | 453 | return len; |
456 | } | 454 | } |
457 | 455 | ||
458 | static int pcipcwd_ioctl(struct inode *inode, struct file *file, | 456 | static long pcipcwd_ioctl(struct file *file, unsigned int cmd, |
459 | unsigned int cmd, unsigned long arg) | 457 | unsigned long arg) |
460 | { | 458 | { |
461 | void __user *argp = (void __user *)arg; | 459 | void __user *argp = (void __user *)arg; |
462 | int __user *p = argp; | 460 | int __user *p = argp; |
@@ -471,92 +469,89 @@ static int pcipcwd_ioctl(struct inode *inode, struct file *file, | |||
471 | }; | 469 | }; |
472 | 470 | ||
473 | switch (cmd) { | 471 | switch (cmd) { |
474 | case WDIOC_GETSUPPORT: | 472 | case WDIOC_GETSUPPORT: |
475 | return copy_to_user(argp, &ident, | 473 | return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; |
476 | sizeof (ident)) ? -EFAULT : 0; | 474 | |
475 | case WDIOC_GETSTATUS: | ||
476 | { | ||
477 | int status; | ||
478 | pcipcwd_get_status(&status); | ||
479 | return put_user(status, p); | ||
480 | } | ||
477 | 481 | ||
478 | case WDIOC_GETSTATUS: | 482 | case WDIOC_GETBOOTSTATUS: |
479 | { | 483 | return put_user(pcipcwd_private.boot_status, p); |
480 | int status; | ||
481 | 484 | ||
482 | pcipcwd_get_status(&status); | 485 | case WDIOC_GETTEMP: |
486 | { | ||
487 | int temperature; | ||
483 | 488 | ||
484 | return put_user(status, p); | 489 | if (pcipcwd_get_temperature(&temperature)) |
485 | } | 490 | return -EFAULT; |
486 | 491 | ||
487 | case WDIOC_GETBOOTSTATUS: | 492 | return put_user(temperature, p); |
488 | return put_user(pcipcwd_private.boot_status, p); | 493 | } |
489 | 494 | ||
490 | case WDIOC_GETTEMP: | 495 | case WDIOC_SETOPTIONS: |
491 | { | 496 | { |
492 | int temperature; | 497 | int new_options, retval = -EINVAL; |
493 | 498 | ||
494 | if (pcipcwd_get_temperature(&temperature)) | 499 | if (get_user(new_options, p)) |
495 | return -EFAULT; | 500 | return -EFAULT; |
496 | 501 | ||
497 | return put_user(temperature, p); | 502 | if (new_options & WDIOS_DISABLECARD) { |
503 | if (pcipcwd_stop()) | ||
504 | return -EIO; | ||
505 | retval = 0; | ||
498 | } | 506 | } |
499 | 507 | ||
500 | case WDIOC_KEEPALIVE: | 508 | if (new_options & WDIOS_ENABLECARD) { |
501 | pcipcwd_keepalive(); | 509 | if (pcipcwd_start()) |
502 | return 0; | 510 | return -EIO; |
503 | 511 | retval = 0; | |
504 | case WDIOC_SETOPTIONS: | 512 | } |
505 | { | ||
506 | int new_options, retval = -EINVAL; | ||
507 | |||
508 | if (get_user (new_options, p)) | ||
509 | return -EFAULT; | ||
510 | |||
511 | if (new_options & WDIOS_DISABLECARD) { | ||
512 | if (pcipcwd_stop()) | ||
513 | return -EIO; | ||
514 | retval = 0; | ||
515 | } | ||
516 | 513 | ||
517 | if (new_options & WDIOS_ENABLECARD) { | 514 | if (new_options & WDIOS_TEMPPANIC) { |
518 | if (pcipcwd_start()) | 515 | temp_panic = 1; |
519 | return -EIO; | 516 | retval = 0; |
520 | retval = 0; | 517 | } |
521 | } | ||
522 | 518 | ||
523 | if (new_options & WDIOS_TEMPPANIC) { | 519 | return retval; |
524 | temp_panic = 1; | 520 | } |
525 | retval = 0; | ||
526 | } | ||
527 | 521 | ||
528 | return retval; | 522 | case WDIOC_KEEPALIVE: |
529 | } | 523 | pcipcwd_keepalive(); |
524 | return 0; | ||
530 | 525 | ||
531 | case WDIOC_SETTIMEOUT: | 526 | case WDIOC_SETTIMEOUT: |
532 | { | 527 | { |
533 | int new_heartbeat; | 528 | int new_heartbeat; |
534 | 529 | ||
535 | if (get_user(new_heartbeat, p)) | 530 | if (get_user(new_heartbeat, p)) |
536 | return -EFAULT; | 531 | return -EFAULT; |
537 | 532 | ||
538 | if (pcipcwd_set_heartbeat(new_heartbeat)) | 533 | if (pcipcwd_set_heartbeat(new_heartbeat)) |
539 | return -EINVAL; | 534 | return -EINVAL; |
540 | 535 | ||
541 | pcipcwd_keepalive(); | 536 | pcipcwd_keepalive(); |
542 | /* Fall */ | 537 | /* Fall */ |
543 | } | 538 | } |
544 | 539 | ||
545 | case WDIOC_GETTIMEOUT: | 540 | case WDIOC_GETTIMEOUT: |
546 | return put_user(heartbeat, p); | 541 | return put_user(heartbeat, p); |
547 | 542 | ||
548 | case WDIOC_GETTIMELEFT: | 543 | case WDIOC_GETTIMELEFT: |
549 | { | 544 | { |
550 | int time_left; | 545 | int time_left; |
551 | 546 | ||
552 | if (pcipcwd_get_timeleft(&time_left)) | 547 | if (pcipcwd_get_timeleft(&time_left)) |
553 | return -EFAULT; | 548 | return -EFAULT; |
554 | 549 | ||
555 | return put_user(time_left, p); | 550 | return put_user(time_left, p); |
556 | } | 551 | } |
557 | 552 | ||
558 | default: | 553 | default: |
559 | return -ENOTTY; | 554 | return -ENOTTY; |
560 | } | 555 | } |
561 | } | 556 | } |
562 | 557 | ||
@@ -603,7 +598,7 @@ static ssize_t pcipcwd_temp_read(struct file *file, char __user *data, | |||
603 | if (pcipcwd_get_temperature(&temperature)) | 598 | if (pcipcwd_get_temperature(&temperature)) |
604 | return -EFAULT; | 599 | return -EFAULT; |
605 | 600 | ||
606 | if (copy_to_user (data, &temperature, 1)) | 601 | if (copy_to_user(data, &temperature, 1)) |
607 | return -EFAULT; | 602 | return -EFAULT; |
608 | 603 | ||
609 | return 1; | 604 | return 1; |
@@ -628,10 +623,8 @@ static int pcipcwd_temp_release(struct inode *inode, struct file *file) | |||
628 | 623 | ||
629 | static int pcipcwd_notify_sys(struct notifier_block *this, unsigned long code, void *unused) | 624 | static int pcipcwd_notify_sys(struct notifier_block *this, unsigned long code, void *unused) |
630 | { | 625 | { |
631 | if (code==SYS_DOWN || code==SYS_HALT) { | 626 | if (code == SYS_DOWN || code == SYS_HALT) |
632 | /* Turn the WDT off */ | 627 | pcipcwd_stop(); /* Turn the WDT off */ |
633 | pcipcwd_stop(); | ||
634 | } | ||
635 | 628 | ||
636 | return NOTIFY_DONE; | 629 | return NOTIFY_DONE; |
637 | } | 630 | } |
@@ -644,7 +637,7 @@ static const struct file_operations pcipcwd_fops = { | |||
644 | .owner = THIS_MODULE, | 637 | .owner = THIS_MODULE, |
645 | .llseek = no_llseek, | 638 | .llseek = no_llseek, |
646 | .write = pcipcwd_write, | 639 | .write = pcipcwd_write, |
647 | .ioctl = pcipcwd_ioctl, | 640 | .unlocked_ioctl = pcipcwd_ioctl, |
648 | .open = pcipcwd_open, | 641 | .open = pcipcwd_open, |
649 | .release = pcipcwd_release, | 642 | .release = pcipcwd_release, |
650 | }; | 643 | }; |
diff --git a/drivers/watchdog/pcwd_usb.c b/drivers/watchdog/pcwd_usb.c index bf443d077a1e..c1685c942de6 100644 --- a/drivers/watchdog/pcwd_usb.c +++ b/drivers/watchdog/pcwd_usb.c | |||
@@ -40,8 +40,7 @@ | |||
40 | #include <linux/slab.h> /* For kmalloc, ... */ | 40 | #include <linux/slab.h> /* For kmalloc, ... */ |
41 | #include <linux/mutex.h> /* For mutex locking */ | 41 | #include <linux/mutex.h> /* For mutex locking */ |
42 | #include <linux/hid.h> /* For HID_REQ_SET_REPORT & HID_DT_REPORT */ | 42 | #include <linux/hid.h> /* For HID_REQ_SET_REPORT & HID_DT_REPORT */ |
43 | 43 | #include <linux/uaccess.h> /* For copy_to_user/put_user/... */ | |
44 | #include <asm/uaccess.h> /* For copy_to_user/put_user/... */ | ||
45 | 44 | ||
46 | 45 | ||
47 | #ifdef CONFIG_USB_DEBUG | 46 | #ifdef CONFIG_USB_DEBUG |
@@ -88,7 +87,7 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" _ | |||
88 | #define USB_PCWD_PRODUCT_ID 0x1140 | 87 | #define USB_PCWD_PRODUCT_ID 0x1140 |
89 | 88 | ||
90 | /* table of devices that work with this driver */ | 89 | /* table of devices that work with this driver */ |
91 | static struct usb_device_id usb_pcwd_table [] = { | 90 | static struct usb_device_id usb_pcwd_table[] = { |
92 | { USB_DEVICE(USB_PCWD_VENDOR_ID, USB_PCWD_PRODUCT_ID) }, | 91 | { USB_DEVICE(USB_PCWD_VENDOR_ID, USB_PCWD_PRODUCT_ID) }, |
93 | { } /* Terminating entry */ | 92 | { } /* Terminating entry */ |
94 | }; | 93 | }; |
@@ -110,7 +109,7 @@ MODULE_DEVICE_TABLE (usb, usb_pcwd_table); | |||
110 | #define CMD_DISABLE_WATCHDOG CMD_ENABLE_WATCHDOG | 109 | #define CMD_DISABLE_WATCHDOG CMD_ENABLE_WATCHDOG |
111 | 110 | ||
112 | /* Watchdog's Dip Switch heartbeat values */ | 111 | /* Watchdog's Dip Switch heartbeat values */ |
113 | static const int heartbeat_tbl [] = { | 112 | static const int heartbeat_tbl[] = { |
114 | 5, /* OFF-OFF-OFF = 5 Sec */ | 113 | 5, /* OFF-OFF-OFF = 5 Sec */ |
115 | 10, /* OFF-OFF-ON = 10 Sec */ | 114 | 10, /* OFF-OFF-ON = 10 Sec */ |
116 | 30, /* OFF-ON-OFF = 30 Sec */ | 115 | 30, /* OFF-ON-OFF = 30 Sec */ |
@@ -130,15 +129,15 @@ static char expect_release; | |||
130 | 129 | ||
131 | /* Structure to hold all of our device specific stuff */ | 130 | /* Structure to hold all of our device specific stuff */ |
132 | struct usb_pcwd_private { | 131 | struct usb_pcwd_private { |
133 | struct usb_device * udev; /* save off the usb device pointer */ | 132 | struct usb_device *udev; /* save off the usb device pointer */ |
134 | struct usb_interface * interface; /* the interface for this device */ | 133 | struct usb_interface *interface; /* the interface for this device */ |
135 | 134 | ||
136 | unsigned int interface_number; /* the interface number used for cmd's */ | 135 | unsigned int interface_number; /* the interface number used for cmd's */ |
137 | 136 | ||
138 | unsigned char * intr_buffer; /* the buffer to intr data */ | 137 | unsigned char *intr_buffer; /* the buffer to intr data */ |
139 | dma_addr_t intr_dma; /* the dma address for the intr buffer */ | 138 | dma_addr_t intr_dma; /* the dma address for the intr buffer */ |
140 | size_t intr_size; /* the size of the intr buffer */ | 139 | size_t intr_size; /* the size of the intr buffer */ |
141 | struct urb * intr_urb; /* the urb used for the intr pipe */ | 140 | struct urb *intr_urb; /* the urb used for the intr pipe */ |
142 | 141 | ||
143 | unsigned char cmd_command; /* The command that is reported back */ | 142 | unsigned char cmd_command; /* The command that is reported back */ |
144 | unsigned char cmd_data_msb; /* The data MSB that is reported back */ | 143 | unsigned char cmd_data_msb; /* The data MSB that is reported back */ |
@@ -154,8 +153,8 @@ static struct usb_pcwd_private *usb_pcwd_device; | |||
154 | static DEFINE_MUTEX(disconnect_mutex); | 153 | static DEFINE_MUTEX(disconnect_mutex); |
155 | 154 | ||
156 | /* local function prototypes */ | 155 | /* local function prototypes */ |
157 | static int usb_pcwd_probe (struct usb_interface *interface, const struct usb_device_id *id); | 156 | static int usb_pcwd_probe(struct usb_interface *interface, const struct usb_device_id *id); |
158 | static void usb_pcwd_disconnect (struct usb_interface *interface); | 157 | static void usb_pcwd_disconnect(struct usb_interface *interface); |
159 | 158 | ||
160 | /* usb specific object needed to register this driver with the usb subsystem */ | 159 | /* usb specific object needed to register this driver with the usb subsystem */ |
161 | static struct usb_driver usb_pcwd_driver = { | 160 | static struct usb_driver usb_pcwd_driver = { |
@@ -195,10 +194,10 @@ static void usb_pcwd_intr_done(struct urb *urb) | |||
195 | usb_pcwd->cmd_data_lsb = data[2]; | 194 | usb_pcwd->cmd_data_lsb = data[2]; |
196 | 195 | ||
197 | /* notify anyone waiting that the cmd has finished */ | 196 | /* notify anyone waiting that the cmd has finished */ |
198 | atomic_set (&usb_pcwd->cmd_received, 1); | 197 | atomic_set(&usb_pcwd->cmd_received, 1); |
199 | 198 | ||
200 | resubmit: | 199 | resubmit: |
201 | retval = usb_submit_urb (urb, GFP_ATOMIC); | 200 | retval = usb_submit_urb(urb, GFP_ATOMIC); |
202 | if (retval) | 201 | if (retval) |
203 | printk(KERN_ERR PFX "can't resubmit intr, usb_submit_urb failed with result %d\n", | 202 | printk(KERN_ERR PFX "can't resubmit intr, usb_submit_urb failed with result %d\n", |
204 | retval); | 203 | retval); |
@@ -224,7 +223,7 @@ static int usb_pcwd_send_command(struct usb_pcwd_private *usb_pcwd, unsigned cha | |||
224 | dbg("sending following data cmd=0x%02x msb=0x%02x lsb=0x%02x", | 223 | dbg("sending following data cmd=0x%02x msb=0x%02x lsb=0x%02x", |
225 | buf[0], buf[1], buf[2]); | 224 | buf[0], buf[1], buf[2]); |
226 | 225 | ||
227 | atomic_set (&usb_pcwd->cmd_received, 0); | 226 | atomic_set(&usb_pcwd->cmd_received, 0); |
228 | 227 | ||
229 | if (usb_control_msg(usb_pcwd->udev, usb_sndctrlpipe(usb_pcwd->udev, 0), | 228 | if (usb_control_msg(usb_pcwd->udev, usb_sndctrlpipe(usb_pcwd->udev, 0), |
230 | HID_REQ_SET_REPORT, HID_DT_REPORT, | 229 | HID_REQ_SET_REPORT, HID_DT_REPORT, |
@@ -237,7 +236,7 @@ static int usb_pcwd_send_command(struct usb_pcwd_private *usb_pcwd, unsigned cha | |||
237 | got_response = 0; | 236 | got_response = 0; |
238 | for (count = 0; (count < USB_COMMAND_TIMEOUT) && (!got_response); count++) { | 237 | for (count = 0; (count < USB_COMMAND_TIMEOUT) && (!got_response); count++) { |
239 | mdelay(1); | 238 | mdelay(1); |
240 | if (atomic_read (&usb_pcwd->cmd_received)) | 239 | if (atomic_read(&usb_pcwd->cmd_received)) |
241 | got_response = 1; | 240 | got_response = 1; |
242 | } | 241 | } |
243 | 242 | ||
@@ -356,7 +355,7 @@ static ssize_t usb_pcwd_write(struct file *file, const char __user *data, | |||
356 | /* scan to see whether or not we got the magic character */ | 355 | /* scan to see whether or not we got the magic character */ |
357 | for (i = 0; i != len; i++) { | 356 | for (i = 0; i != len; i++) { |
358 | char c; | 357 | char c; |
359 | if(get_user(c, data+i)) | 358 | if (get_user(c, data + i)) |
360 | return -EFAULT; | 359 | return -EFAULT; |
361 | if (c == 'V') | 360 | if (c == 'V') |
362 | expect_release = 42; | 361 | expect_release = 42; |
@@ -369,8 +368,8 @@ static ssize_t usb_pcwd_write(struct file *file, const char __user *data, | |||
369 | return len; | 368 | return len; |
370 | } | 369 | } |
371 | 370 | ||
372 | static int usb_pcwd_ioctl(struct inode *inode, struct file *file, | 371 | static long usb_pcwd_ioctl(struct file *file, unsigned int cmd, |
373 | unsigned int cmd, unsigned long arg) | 372 | unsigned long arg) |
374 | { | 373 | { |
375 | void __user *argp = (void __user *)arg; | 374 | void __user *argp = (void __user *)arg; |
376 | int __user *p = argp; | 375 | int __user *p = argp; |
@@ -383,77 +382,76 @@ static int usb_pcwd_ioctl(struct inode *inode, struct file *file, | |||
383 | }; | 382 | }; |
384 | 383 | ||
385 | switch (cmd) { | 384 | switch (cmd) { |
386 | case WDIOC_GETSUPPORT: | 385 | case WDIOC_GETSUPPORT: |
387 | return copy_to_user(argp, &ident, | 386 | return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; |
388 | sizeof (ident)) ? -EFAULT : 0; | ||
389 | 387 | ||
390 | case WDIOC_GETSTATUS: | 388 | case WDIOC_GETSTATUS: |
391 | case WDIOC_GETBOOTSTATUS: | 389 | case WDIOC_GETBOOTSTATUS: |
392 | return put_user(0, p); | 390 | return put_user(0, p); |
393 | 391 | ||
394 | case WDIOC_GETTEMP: | 392 | case WDIOC_GETTEMP: |
395 | { | 393 | { |
396 | int temperature; | 394 | int temperature; |
397 | 395 | ||
398 | if (usb_pcwd_get_temperature(usb_pcwd_device, &temperature)) | 396 | if (usb_pcwd_get_temperature(usb_pcwd_device, &temperature)) |
399 | return -EFAULT; | 397 | return -EFAULT; |
400 | 398 | ||
401 | return put_user(temperature, p); | 399 | return put_user(temperature, p); |
402 | } | 400 | } |
403 | 401 | ||
404 | case WDIOC_KEEPALIVE: | 402 | case WDIOC_SETOPTIONS: |
405 | usb_pcwd_keepalive(usb_pcwd_device); | 403 | { |
406 | return 0; | 404 | int new_options, retval = -EINVAL; |
407 | 405 | ||
408 | case WDIOC_SETOPTIONS: | 406 | if (get_user(new_options, p)) |
409 | { | 407 | return -EFAULT; |
410 | int new_options, retval = -EINVAL; | ||
411 | 408 | ||
412 | if (get_user (new_options, p)) | 409 | if (new_options & WDIOS_DISABLECARD) { |
413 | return -EFAULT; | 410 | usb_pcwd_stop(usb_pcwd_device); |
411 | retval = 0; | ||
412 | } | ||
414 | 413 | ||
415 | if (new_options & WDIOS_DISABLECARD) { | 414 | if (new_options & WDIOS_ENABLECARD) { |
416 | usb_pcwd_stop(usb_pcwd_device); | 415 | usb_pcwd_start(usb_pcwd_device); |
417 | retval = 0; | 416 | retval = 0; |
418 | } | 417 | } |
419 | 418 | ||
420 | if (new_options & WDIOS_ENABLECARD) { | 419 | return retval; |
421 | usb_pcwd_start(usb_pcwd_device); | 420 | } |
422 | retval = 0; | ||
423 | } | ||
424 | 421 | ||
425 | return retval; | 422 | case WDIOC_KEEPALIVE: |
426 | } | 423 | usb_pcwd_keepalive(usb_pcwd_device); |
424 | return 0; | ||
427 | 425 | ||
428 | case WDIOC_SETTIMEOUT: | 426 | case WDIOC_SETTIMEOUT: |
429 | { | 427 | { |
430 | int new_heartbeat; | 428 | int new_heartbeat; |
431 | 429 | ||
432 | if (get_user(new_heartbeat, p)) | 430 | if (get_user(new_heartbeat, p)) |
433 | return -EFAULT; | 431 | return -EFAULT; |
434 | 432 | ||
435 | if (usb_pcwd_set_heartbeat(usb_pcwd_device, new_heartbeat)) | 433 | if (usb_pcwd_set_heartbeat(usb_pcwd_device, new_heartbeat)) |
436 | return -EINVAL; | 434 | return -EINVAL; |
437 | 435 | ||
438 | usb_pcwd_keepalive(usb_pcwd_device); | 436 | usb_pcwd_keepalive(usb_pcwd_device); |
439 | /* Fall */ | 437 | /* Fall */ |
440 | } | 438 | } |
441 | 439 | ||
442 | case WDIOC_GETTIMEOUT: | 440 | case WDIOC_GETTIMEOUT: |
443 | return put_user(heartbeat, p); | 441 | return put_user(heartbeat, p); |
444 | 442 | ||
445 | case WDIOC_GETTIMELEFT: | 443 | case WDIOC_GETTIMELEFT: |
446 | { | 444 | { |
447 | int time_left; | 445 | int time_left; |
448 | 446 | ||
449 | if (usb_pcwd_get_timeleft(usb_pcwd_device, &time_left)) | 447 | if (usb_pcwd_get_timeleft(usb_pcwd_device, &time_left)) |
450 | return -EFAULT; | 448 | return -EFAULT; |
451 | 449 | ||
452 | return put_user(time_left, p); | 450 | return put_user(time_left, p); |
453 | } | 451 | } |
454 | 452 | ||
455 | default: | 453 | default: |
456 | return -ENOTTY; | 454 | return -ENOTTY; |
457 | } | 455 | } |
458 | } | 456 | } |
459 | 457 | ||
@@ -519,10 +517,8 @@ static int usb_pcwd_temperature_release(struct inode *inode, struct file *file) | |||
519 | 517 | ||
520 | static int usb_pcwd_notify_sys(struct notifier_block *this, unsigned long code, void *unused) | 518 | static int usb_pcwd_notify_sys(struct notifier_block *this, unsigned long code, void *unused) |
521 | { | 519 | { |
522 | if (code==SYS_DOWN || code==SYS_HALT) { | 520 | if (code == SYS_DOWN || code == SYS_HALT) |
523 | /* Turn the WDT off */ | 521 | usb_pcwd_stop(usb_pcwd_device); /* Turn the WDT off */ |
524 | usb_pcwd_stop(usb_pcwd_device); | ||
525 | } | ||
526 | 522 | ||
527 | return NOTIFY_DONE; | 523 | return NOTIFY_DONE; |
528 | } | 524 | } |
@@ -535,7 +531,7 @@ static const struct file_operations usb_pcwd_fops = { | |||
535 | .owner = THIS_MODULE, | 531 | .owner = THIS_MODULE, |
536 | .llseek = no_llseek, | 532 | .llseek = no_llseek, |
537 | .write = usb_pcwd_write, | 533 | .write = usb_pcwd_write, |
538 | .ioctl = usb_pcwd_ioctl, | 534 | .unlocked_ioctl = usb_pcwd_ioctl, |
539 | .open = usb_pcwd_open, | 535 | .open = usb_pcwd_open, |
540 | .release = usb_pcwd_release, | 536 | .release = usb_pcwd_release, |
541 | }; | 537 | }; |
@@ -567,13 +563,13 @@ static struct notifier_block usb_pcwd_notifier = { | |||
567 | /** | 563 | /** |
568 | * usb_pcwd_delete | 564 | * usb_pcwd_delete |
569 | */ | 565 | */ |
570 | static inline void usb_pcwd_delete (struct usb_pcwd_private *usb_pcwd) | 566 | static inline void usb_pcwd_delete(struct usb_pcwd_private *usb_pcwd) |
571 | { | 567 | { |
572 | usb_free_urb(usb_pcwd->intr_urb); | 568 | usb_free_urb(usb_pcwd->intr_urb); |
573 | if (usb_pcwd->intr_buffer != NULL) | 569 | if (usb_pcwd->intr_buffer != NULL) |
574 | usb_buffer_free(usb_pcwd->udev, usb_pcwd->intr_size, | 570 | usb_buffer_free(usb_pcwd->udev, usb_pcwd->intr_size, |
575 | usb_pcwd->intr_buffer, usb_pcwd->intr_dma); | 571 | usb_pcwd->intr_buffer, usb_pcwd->intr_dma); |
576 | kfree (usb_pcwd); | 572 | kfree(usb_pcwd); |
577 | } | 573 | } |
578 | 574 | ||
579 | /** | 575 | /** |
@@ -626,7 +622,7 @@ static int usb_pcwd_probe(struct usb_interface *interface, const struct usb_devi | |||
626 | maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); | 622 | maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); |
627 | 623 | ||
628 | /* allocate memory for our device and initialize it */ | 624 | /* allocate memory for our device and initialize it */ |
629 | usb_pcwd = kzalloc (sizeof(struct usb_pcwd_private), GFP_KERNEL); | 625 | usb_pcwd = kzalloc(sizeof(struct usb_pcwd_private), GFP_KERNEL); |
630 | if (usb_pcwd == NULL) { | 626 | if (usb_pcwd == NULL) { |
631 | printk(KERN_ERR PFX "Out of memory\n"); | 627 | printk(KERN_ERR PFX "Out of memory\n"); |
632 | goto error; | 628 | goto error; |
@@ -641,7 +637,8 @@ static int usb_pcwd_probe(struct usb_interface *interface, const struct usb_devi | |||
641 | usb_pcwd->intr_size = (le16_to_cpu(endpoint->wMaxPacketSize) > 8 ? le16_to_cpu(endpoint->wMaxPacketSize) : 8); | 637 | usb_pcwd->intr_size = (le16_to_cpu(endpoint->wMaxPacketSize) > 8 ? le16_to_cpu(endpoint->wMaxPacketSize) : 8); |
642 | 638 | ||
643 | /* set up the memory buffer's */ | 639 | /* set up the memory buffer's */ |
644 | if (!(usb_pcwd->intr_buffer = usb_buffer_alloc(udev, usb_pcwd->intr_size, GFP_ATOMIC, &usb_pcwd->intr_dma))) { | 640 | usb_pcwd->intr_buffer = usb_buffer_alloc(udev, usb_pcwd->intr_size, GFP_ATOMIC, &usb_pcwd->intr_dma); |
641 | if (!usb_pcwd->intr_buffer) { | ||
645 | printk(KERN_ERR PFX "Out of memory\n"); | 642 | printk(KERN_ERR PFX "Out of memory\n"); |
646 | goto error; | 643 | goto error; |
647 | } | 644 | } |
@@ -675,11 +672,10 @@ static int usb_pcwd_probe(struct usb_interface *interface, const struct usb_devi | |||
675 | 672 | ||
676 | /* Get the Firmware Version */ | 673 | /* Get the Firmware Version */ |
677 | got_fw_rev = usb_pcwd_send_command(usb_pcwd, CMD_GET_FIRMWARE_VERSION, &fw_rev_major, &fw_rev_minor); | 674 | got_fw_rev = usb_pcwd_send_command(usb_pcwd, CMD_GET_FIRMWARE_VERSION, &fw_rev_major, &fw_rev_minor); |
678 | if (got_fw_rev) { | 675 | if (got_fw_rev) |
679 | sprintf(fw_ver_str, "%u.%02u", fw_rev_major, fw_rev_minor); | 676 | sprintf(fw_ver_str, "%u.%02u", fw_rev_major, fw_rev_minor); |
680 | } else { | 677 | else |
681 | sprintf(fw_ver_str, "<card no answer>"); | 678 | sprintf(fw_ver_str, "<card no answer>"); |
682 | } | ||
683 | 679 | ||
684 | printk(KERN_INFO PFX "Found card (Firmware: %s) with temp option\n", | 680 | printk(KERN_INFO PFX "Found card (Firmware: %s) with temp option\n", |
685 | fw_ver_str); | 681 | fw_ver_str); |
@@ -725,7 +721,7 @@ static int usb_pcwd_probe(struct usb_interface *interface, const struct usb_devi | |||
725 | } | 721 | } |
726 | 722 | ||
727 | /* we can register the device now, as it is ready */ | 723 | /* we can register the device now, as it is ready */ |
728 | usb_set_intfdata (interface, usb_pcwd); | 724 | usb_set_intfdata(interface, usb_pcwd); |
729 | 725 | ||
730 | printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n", | 726 | printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n", |
731 | heartbeat, nowayout); | 727 | heartbeat, nowayout); |
@@ -759,8 +755,8 @@ static void usb_pcwd_disconnect(struct usb_interface *interface) | |||
759 | /* prevent races with open() */ | 755 | /* prevent races with open() */ |
760 | mutex_lock(&disconnect_mutex); | 756 | mutex_lock(&disconnect_mutex); |
761 | 757 | ||
762 | usb_pcwd = usb_get_intfdata (interface); | 758 | usb_pcwd = usb_get_intfdata(interface); |
763 | usb_set_intfdata (interface, NULL); | 759 | usb_set_intfdata(interface, NULL); |
764 | 760 | ||
765 | mutex_lock(&usb_pcwd->mtx); | 761 | mutex_lock(&usb_pcwd->mtx); |
766 | 762 | ||
@@ -820,5 +816,5 @@ static void __exit usb_pcwd_exit(void) | |||
820 | } | 816 | } |
821 | 817 | ||
822 | 818 | ||
823 | module_init (usb_pcwd_init); | 819 | module_init(usb_pcwd_init); |
824 | module_exit (usb_pcwd_exit); | 820 | module_exit(usb_pcwd_exit); |
diff --git a/drivers/watchdog/pnx4008_wdt.c b/drivers/watchdog/pnx4008_wdt.c index 6b8483d3c783..6eadf5ebb9b3 100644 --- a/drivers/watchdog/pnx4008_wdt.c +++ b/drivers/watchdog/pnx4008_wdt.c | |||
@@ -28,10 +28,10 @@ | |||
28 | #include <linux/platform_device.h> | 28 | #include <linux/platform_device.h> |
29 | #include <linux/clk.h> | 29 | #include <linux/clk.h> |
30 | #include <linux/spinlock.h> | 30 | #include <linux/spinlock.h> |
31 | #include <linux/uaccess.h> | ||
32 | #include <linux/io.h> | ||
31 | 33 | ||
32 | #include <asm/hardware.h> | 34 | #include <asm/hardware.h> |
33 | #include <asm/uaccess.h> | ||
34 | #include <asm/io.h> | ||
35 | 35 | ||
36 | #define MODULE_NAME "PNX4008-WDT: " | 36 | #define MODULE_NAME "PNX4008-WDT: " |
37 | 37 | ||
@@ -144,9 +144,8 @@ static int pnx4008_wdt_open(struct inode *inode, struct file *file) | |||
144 | return nonseekable_open(inode, file); | 144 | return nonseekable_open(inode, file); |
145 | } | 145 | } |
146 | 146 | ||
147 | static ssize_t | 147 | static ssize_t pnx4008_wdt_write(struct file *file, const char *data, |
148 | pnx4008_wdt_write(struct file *file, const char *data, size_t len, | 148 | size_t len, loff_t *ppos) |
149 | loff_t * ppos) | ||
150 | { | 149 | { |
151 | if (len) { | 150 | if (len) { |
152 | if (!nowayout) { | 151 | if (!nowayout) { |
@@ -169,15 +168,14 @@ pnx4008_wdt_write(struct file *file, const char *data, size_t len, | |||
169 | return len; | 168 | return len; |
170 | } | 169 | } |
171 | 170 | ||
172 | static struct watchdog_info ident = { | 171 | static const struct watchdog_info ident = { |
173 | .options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE | | 172 | .options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE | |
174 | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, | 173 | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, |
175 | .identity = "PNX4008 Watchdog", | 174 | .identity = "PNX4008 Watchdog", |
176 | }; | 175 | }; |
177 | 176 | ||
178 | static int | 177 | static long pnx4008_wdt_ioctl(struct inode *inode, struct file *file, |
179 | pnx4008_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | 178 | unsigned int cmd, unsigned long arg) |
180 | unsigned long arg) | ||
181 | { | 179 | { |
182 | int ret = -ENOTTY; | 180 | int ret = -ENOTTY; |
183 | int time; | 181 | int time; |
@@ -196,6 +194,11 @@ pnx4008_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | |||
196 | ret = put_user(boot_status, (int *)arg); | 194 | ret = put_user(boot_status, (int *)arg); |
197 | break; | 195 | break; |
198 | 196 | ||
197 | case WDIOC_KEEPALIVE: | ||
198 | wdt_enable(); | ||
199 | ret = 0; | ||
200 | break; | ||
201 | |||
199 | case WDIOC_SETTIMEOUT: | 202 | case WDIOC_SETTIMEOUT: |
200 | ret = get_user(time, (int *)arg); | 203 | ret = get_user(time, (int *)arg); |
201 | if (ret) | 204 | if (ret) |
@@ -213,11 +216,6 @@ pnx4008_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | |||
213 | case WDIOC_GETTIMEOUT: | 216 | case WDIOC_GETTIMEOUT: |
214 | ret = put_user(heartbeat, (int *)arg); | 217 | ret = put_user(heartbeat, (int *)arg); |
215 | break; | 218 | break; |
216 | |||
217 | case WDIOC_KEEPALIVE: | ||
218 | wdt_enable(); | ||
219 | ret = 0; | ||
220 | break; | ||
221 | } | 219 | } |
222 | return ret; | 220 | return ret; |
223 | } | 221 | } |
@@ -238,7 +236,7 @@ static const struct file_operations pnx4008_wdt_fops = { | |||
238 | .owner = THIS_MODULE, | 236 | .owner = THIS_MODULE, |
239 | .llseek = no_llseek, | 237 | .llseek = no_llseek, |
240 | .write = pnx4008_wdt_write, | 238 | .write = pnx4008_wdt_write, |
241 | .ioctl = pnx4008_wdt_ioctl, | 239 | .unlocked_ioctl = pnx4008_wdt_ioctl, |
242 | .open = pnx4008_wdt_open, | 240 | .open = pnx4008_wdt_open, |
243 | .release = pnx4008_wdt_release, | 241 | .release = pnx4008_wdt_release, |
244 | }; | 242 | }; |
diff --git a/drivers/watchdog/rm9k_wdt.c b/drivers/watchdog/rm9k_wdt.c index 5c921e471564..f1ae3729a19e 100644 --- a/drivers/watchdog/rm9k_wdt.c +++ b/drivers/watchdog/rm9k_wdt.c | |||
@@ -29,10 +29,10 @@ | |||
29 | #include <linux/notifier.h> | 29 | #include <linux/notifier.h> |
30 | #include <linux/miscdevice.h> | 30 | #include <linux/miscdevice.h> |
31 | #include <linux/watchdog.h> | 31 | #include <linux/watchdog.h> |
32 | #include <asm/io.h> | 32 | #include <linux/io.h> |
33 | #include <linux/uaccess.h> | ||
33 | #include <asm/atomic.h> | 34 | #include <asm/atomic.h> |
34 | #include <asm/processor.h> | 35 | #include <asm/processor.h> |
35 | #include <asm/uaccess.h> | ||
36 | #include <asm/system.h> | 36 | #include <asm/system.h> |
37 | #include <asm/rm9k-ocd.h> | 37 | #include <asm/rm9k-ocd.h> |
38 | 38 | ||
@@ -53,10 +53,12 @@ static void wdt_gpi_stop(void); | |||
53 | static void wdt_gpi_set_timeout(unsigned int); | 53 | static void wdt_gpi_set_timeout(unsigned int); |
54 | static int wdt_gpi_open(struct inode *, struct file *); | 54 | static int wdt_gpi_open(struct inode *, struct file *); |
55 | static int wdt_gpi_release(struct inode *, struct file *); | 55 | static int wdt_gpi_release(struct inode *, struct file *); |
56 | static ssize_t wdt_gpi_write(struct file *, const char __user *, size_t, loff_t *); | 56 | static ssize_t wdt_gpi_write(struct file *, const char __user *, size_t, |
57 | loff_t *); | ||
57 | static long wdt_gpi_ioctl(struct file *, unsigned int, unsigned long); | 58 | static long wdt_gpi_ioctl(struct file *, unsigned int, unsigned long); |
58 | static int wdt_gpi_notify(struct notifier_block *, unsigned long, void *); | 59 | static int wdt_gpi_notify(struct notifier_block *, unsigned long, void *); |
59 | static const struct resource *wdt_gpi_get_resource(struct platform_device *, const char *, unsigned int); | 60 | static const struct resource *wdt_gpi_get_resource(struct platform_device *, |
61 | const char *, unsigned int); | ||
60 | static int __init wdt_gpi_probe(struct device *); | 62 | static int __init wdt_gpi_probe(struct device *); |
61 | static int __exit wdt_gpi_remove(struct device *); | 63 | static int __exit wdt_gpi_remove(struct device *); |
62 | 64 | ||
@@ -68,7 +70,7 @@ static int locked; | |||
68 | 70 | ||
69 | 71 | ||
70 | /* These are set from device resources */ | 72 | /* These are set from device resources */ |
71 | static void __iomem * wd_regs; | 73 | static void __iomem *wd_regs; |
72 | static unsigned int wd_irq, wd_ctr; | 74 | static unsigned int wd_irq, wd_ctr; |
73 | 75 | ||
74 | 76 | ||
@@ -216,7 +218,8 @@ static int wdt_gpi_release(struct inode *inode, struct file *file) | |||
216 | if (expect_close) { | 218 | if (expect_close) { |
217 | wdt_gpi_stop(); | 219 | wdt_gpi_stop(); |
218 | free_irq(wd_irq, &miscdev); | 220 | free_irq(wd_irq, &miscdev); |
219 | printk(KERN_INFO "%s: watchdog stopped\n", wdt_gpi_name); | 221 | printk(KERN_INFO "%s: watchdog stopped\n", |
222 | wdt_gpi_name); | ||
220 | } else { | 223 | } else { |
221 | printk(KERN_CRIT "%s: unexpected close() -" | 224 | printk(KERN_CRIT "%s: unexpected close() -" |
222 | " watchdog left running\n", | 225 | " watchdog left running\n", |
@@ -231,8 +234,8 @@ static int wdt_gpi_release(struct inode *inode, struct file *file) | |||
231 | return 0; | 234 | return 0; |
232 | } | 235 | } |
233 | 236 | ||
234 | static ssize_t | 237 | static ssize_t wdt_gpi_write(struct file *f, const char __user *d, size_t s, |
235 | wdt_gpi_write(struct file *f, const char __user *d, size_t s, loff_t *o) | 238 | loff_t *o) |
236 | { | 239 | { |
237 | char val; | 240 | char val; |
238 | 241 | ||
@@ -241,8 +244,7 @@ wdt_gpi_write(struct file *f, const char __user *d, size_t s, loff_t *o) | |||
241 | return s ? 1 : 0; | 244 | return s ? 1 : 0; |
242 | } | 245 | } |
243 | 246 | ||
244 | static long | 247 | static long wdt_gpi_ioctl(struct file *f, unsigned int cmd, unsigned long arg) |
245 | wdt_gpi_ioctl(struct file *f, unsigned int cmd, unsigned long arg) | ||
246 | { | 248 | { |
247 | long res = -ENOTTY; | 249 | long res = -ENOTTY; |
248 | const long size = _IOC_SIZE(cmd); | 250 | const long size = _IOC_SIZE(cmd); |
@@ -271,7 +273,8 @@ wdt_gpi_ioctl(struct file *f, unsigned int cmd, unsigned long arg) | |||
271 | case WDIOC_GETSUPPORT: | 273 | case WDIOC_GETSUPPORT: |
272 | wdinfo.options = nowayout ? | 274 | wdinfo.options = nowayout ? |
273 | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING : | 275 | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING : |
274 | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE; | 276 | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | |
277 | WDIOF_MAGICCLOSE; | ||
275 | res = __copy_to_user(argp, &wdinfo, size) ? -EFAULT : size; | 278 | res = __copy_to_user(argp, &wdinfo, size) ? -EFAULT : size; |
276 | break; | 279 | break; |
277 | 280 | ||
@@ -322,8 +325,8 @@ wdt_gpi_ioctl(struct file *f, unsigned int cmd, unsigned long arg) | |||
322 | 325 | ||
323 | 326 | ||
324 | /* Shutdown notifier */ | 327 | /* Shutdown notifier */ |
325 | static int | 328 | static int wdt_gpi_notify(struct notifier_block *this, unsigned long code, |
326 | wdt_gpi_notify(struct notifier_block *this, unsigned long code, void *unused) | 329 | void *unused) |
327 | { | 330 | { |
328 | if (code == SYS_DOWN || code == SYS_HALT) | 331 | if (code == SYS_DOWN || code == SYS_HALT) |
329 | wdt_gpi_stop(); | 332 | wdt_gpi_stop(); |
@@ -333,9 +336,8 @@ wdt_gpi_notify(struct notifier_block *this, unsigned long code, void *unused) | |||
333 | 336 | ||
334 | 337 | ||
335 | /* Init & exit procedures */ | 338 | /* Init & exit procedures */ |
336 | static const struct resource * | 339 | static const struct resource *wdt_gpi_get_resource(struct platform_device *pdv, |
337 | wdt_gpi_get_resource(struct platform_device *pdv, const char *name, | 340 | const char *name, unsigned int type) |
338 | unsigned int type) | ||
339 | { | 341 | { |
340 | char buf[80]; | 342 | char buf[80]; |
341 | if (snprintf(buf, sizeof buf, "%s_0", name) >= sizeof buf) | 343 | if (snprintf(buf, sizeof buf, "%s_0", name) >= sizeof buf) |
diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c index 97b4a2e8eb09..c417fb5e913f 100644 --- a/drivers/watchdog/s3c2410_wdt.c +++ b/drivers/watchdog/s3c2410_wdt.c | |||
@@ -119,17 +119,6 @@ static void __s3c2410wdt_stop(void) | |||
119 | { | 119 | { |
120 | unsigned long wtcon; | 120 | unsigned long wtcon; |
121 | 121 | ||
122 | spin_lock(&wdt_lock); | ||
123 | wtcon = readl(wdt_base + S3C2410_WTCON); | ||
124 | wtcon &= ~(S3C2410_WTCON_ENABLE | S3C2410_WTCON_RSTEN); | ||
125 | writel(wtcon, wdt_base + S3C2410_WTCON); | ||
126 | spin_unlock(&wdt_lock); | ||
127 | } | ||
128 | |||
129 | static void __s3c2410wdt_stop(void) | ||
130 | { | ||
131 | unsigned long wtcon; | ||
132 | |||
133 | wtcon = readl(wdt_base + S3C2410_WTCON); | 122 | wtcon = readl(wdt_base + S3C2410_WTCON); |
134 | wtcon &= ~(S3C2410_WTCON_ENABLE | S3C2410_WTCON_RSTEN); | 123 | wtcon &= ~(S3C2410_WTCON_ENABLE | S3C2410_WTCON_RSTEN); |
135 | writel(wtcon, wdt_base + S3C2410_WTCON); | 124 | writel(wtcon, wdt_base + S3C2410_WTCON); |
@@ -305,8 +294,6 @@ static long s3c2410wdt_ioctl(struct file *file, unsigned int cmd, | |||
305 | int new_margin; | 294 | int new_margin; |
306 | 295 | ||
307 | switch (cmd) { | 296 | switch (cmd) { |
308 | default: | ||
309 | return -ENOTTY; | ||
310 | case WDIOC_GETSUPPORT: | 297 | case WDIOC_GETSUPPORT: |
311 | return copy_to_user(argp, &s3c2410_wdt_ident, | 298 | return copy_to_user(argp, &s3c2410_wdt_ident, |
312 | sizeof(s3c2410_wdt_ident)) ? -EFAULT : 0; | 299 | sizeof(s3c2410_wdt_ident)) ? -EFAULT : 0; |
@@ -325,6 +312,8 @@ static long s3c2410wdt_ioctl(struct file *file, unsigned int cmd, | |||
325 | return put_user(tmr_margin, p); | 312 | return put_user(tmr_margin, p); |
326 | case WDIOC_GETTIMEOUT: | 313 | case WDIOC_GETTIMEOUT: |
327 | return put_user(tmr_margin, p); | 314 | return put_user(tmr_margin, p); |
315 | default: | ||
316 | return -ENOTTY; | ||
328 | } | 317 | } |
329 | } | 318 | } |
330 | 319 | ||
diff --git a/drivers/watchdog/sa1100_wdt.c b/drivers/watchdog/sa1100_wdt.c index 34a2b3b81800..27d6898a7c98 100644 --- a/drivers/watchdog/sa1100_wdt.c +++ b/drivers/watchdog/sa1100_wdt.c | |||
@@ -26,13 +26,13 @@ | |||
26 | #include <linux/watchdog.h> | 26 | #include <linux/watchdog.h> |
27 | #include <linux/init.h> | 27 | #include <linux/init.h> |
28 | #include <linux/bitops.h> | 28 | #include <linux/bitops.h> |
29 | #include <linux/uaccess.h> | ||
29 | 30 | ||
30 | #ifdef CONFIG_ARCH_PXA | 31 | #ifdef CONFIG_ARCH_PXA |
31 | #include <asm/arch/pxa-regs.h> | 32 | #include <asm/arch/pxa-regs.h> |
32 | #endif | 33 | #endif |
33 | 34 | ||
34 | #include <asm/hardware.h> | 35 | #include <asm/hardware.h> |
35 | #include <asm/uaccess.h> | ||
36 | 36 | ||
37 | #define OSCR_FREQ CLOCK_TICK_RATE | 37 | #define OSCR_FREQ CLOCK_TICK_RATE |
38 | 38 | ||
@@ -45,7 +45,7 @@ static int boot_status; | |||
45 | */ | 45 | */ |
46 | static int sa1100dog_open(struct inode *inode, struct file *file) | 46 | static int sa1100dog_open(struct inode *inode, struct file *file) |
47 | { | 47 | { |
48 | if (test_and_set_bit(1,&sa1100wdt_users)) | 48 | if (test_and_set_bit(1, &sa1100wdt_users)) |
49 | return -EBUSY; | 49 | return -EBUSY; |
50 | 50 | ||
51 | /* Activate SA1100 Watchdog timer */ | 51 | /* Activate SA1100 Watchdog timer */ |
@@ -66,28 +66,27 @@ static int sa1100dog_open(struct inode *inode, struct file *file) | |||
66 | static int sa1100dog_release(struct inode *inode, struct file *file) | 66 | static int sa1100dog_release(struct inode *inode, struct file *file) |
67 | { | 67 | { |
68 | printk(KERN_CRIT "WATCHDOG: Device closed - timer will not stop\n"); | 68 | printk(KERN_CRIT "WATCHDOG: Device closed - timer will not stop\n"); |
69 | |||
70 | clear_bit(1, &sa1100wdt_users); | 69 | clear_bit(1, &sa1100wdt_users); |
71 | |||
72 | return 0; | 70 | return 0; |
73 | } | 71 | } |
74 | 72 | ||
75 | static ssize_t sa1100dog_write(struct file *file, const char __user *data, size_t len, loff_t *ppos) | 73 | static ssize_t sa1100dog_write(struct file *file, const char __user *data, |
74 | size_t len, loff_t *ppos) | ||
76 | { | 75 | { |
77 | if (len) | 76 | if (len) |
78 | /* Refresh OSMR3 timer. */ | 77 | /* Refresh OSMR3 timer. */ |
79 | OSMR3 = OSCR + pre_margin; | 78 | OSMR3 = OSCR + pre_margin; |
80 | |||
81 | return len; | 79 | return len; |
82 | } | 80 | } |
83 | 81 | ||
84 | static struct watchdog_info ident = { | 82 | static const struct watchdog_info ident = { |
85 | .options = WDIOF_CARDRESET | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, | 83 | .options = WDIOF_CARDRESET | WDIOF_SETTIMEOUT |
84 | | WDIOF_KEEPALIVEPING, | ||
86 | .identity = "SA1100/PXA255 Watchdog", | 85 | .identity = "SA1100/PXA255 Watchdog", |
87 | }; | 86 | }; |
88 | 87 | ||
89 | static int sa1100dog_ioctl(struct inode *inode, struct file *file, | 88 | static long sa1100dog_ioctl(struct file *file, unsigned int cmd, |
90 | unsigned int cmd, unsigned long arg) | 89 | unsigned long arg) |
91 | { | 90 | { |
92 | int ret = -ENOTTY; | 91 | int ret = -ENOTTY; |
93 | int time; | 92 | int time; |
@@ -108,6 +107,11 @@ static int sa1100dog_ioctl(struct inode *inode, struct file *file, | |||
108 | ret = put_user(boot_status, p); | 107 | ret = put_user(boot_status, p); |
109 | break; | 108 | break; |
110 | 109 | ||
110 | case WDIOC_KEEPALIVE: | ||
111 | OSMR3 = OSCR + pre_margin; | ||
112 | ret = 0; | ||
113 | break; | ||
114 | |||
111 | case WDIOC_SETTIMEOUT: | 115 | case WDIOC_SETTIMEOUT: |
112 | ret = get_user(time, p); | 116 | ret = get_user(time, p); |
113 | if (ret) | 117 | if (ret) |
@@ -125,27 +129,20 @@ static int sa1100dog_ioctl(struct inode *inode, struct file *file, | |||
125 | case WDIOC_GETTIMEOUT: | 129 | case WDIOC_GETTIMEOUT: |
126 | ret = put_user(pre_margin / OSCR_FREQ, p); | 130 | ret = put_user(pre_margin / OSCR_FREQ, p); |
127 | break; | 131 | break; |
128 | |||
129 | case WDIOC_KEEPALIVE: | ||
130 | OSMR3 = OSCR + pre_margin; | ||
131 | ret = 0; | ||
132 | break; | ||
133 | } | 132 | } |
134 | return ret; | 133 | return ret; |
135 | } | 134 | } |
136 | 135 | ||
137 | static const struct file_operations sa1100dog_fops = | 136 | static const struct file_operations sa1100dog_fops = { |
138 | { | ||
139 | .owner = THIS_MODULE, | 137 | .owner = THIS_MODULE, |
140 | .llseek = no_llseek, | 138 | .llseek = no_llseek, |
141 | .write = sa1100dog_write, | 139 | .write = sa1100dog_write, |
142 | .ioctl = sa1100dog_ioctl, | 140 | .unlocked_ioctl = sa1100dog_ioctl, |
143 | .open = sa1100dog_open, | 141 | .open = sa1100dog_open, |
144 | .release = sa1100dog_release, | 142 | .release = sa1100dog_release, |
145 | }; | 143 | }; |
146 | 144 | ||
147 | static struct miscdevice sa1100dog_miscdev = | 145 | static struct miscdevice sa1100dog_miscdev = { |
148 | { | ||
149 | .minor = WATCHDOG_MINOR, | 146 | .minor = WATCHDOG_MINOR, |
150 | .name = "watchdog", | 147 | .name = "watchdog", |
151 | .fops = &sa1100dog_fops, | 148 | .fops = &sa1100dog_fops, |
@@ -167,8 +164,9 @@ static int __init sa1100dog_init(void) | |||
167 | 164 | ||
168 | ret = misc_register(&sa1100dog_miscdev); | 165 | ret = misc_register(&sa1100dog_miscdev); |
169 | if (ret == 0) | 166 | if (ret == 0) |
170 | printk("SA1100/PXA2xx Watchdog Timer: timer margin %d sec\n", | 167 | printk(KERN_INFO |
171 | margin); | 168 | "SA1100/PXA2xx Watchdog Timer: timer margin %d sec\n", |
169 | margin); | ||
172 | return ret; | 170 | return ret; |
173 | } | 171 | } |
174 | 172 | ||
diff --git a/drivers/watchdog/sb_wdog.c b/drivers/watchdog/sb_wdog.c index b94431433695..27e526a07c9a 100644 --- a/drivers/watchdog/sb_wdog.c +++ b/drivers/watchdog/sb_wdog.c | |||
@@ -57,6 +57,7 @@ | |||
57 | #include <asm/sibyte/sb1250_int.h> | 57 | #include <asm/sibyte/sb1250_int.h> |
58 | #include <asm/sibyte/sb1250_scd.h> | 58 | #include <asm/sibyte/sb1250_scd.h> |
59 | 59 | ||
60 | static DEFINE_SPINLOCK(sbwd_lock); | ||
60 | 61 | ||
61 | /* | 62 | /* |
62 | * set the initial count value of a timer | 63 | * set the initial count value of a timer |
@@ -65,8 +66,10 @@ | |||
65 | */ | 66 | */ |
66 | void sbwdog_set(char __iomem *wdog, unsigned long t) | 67 | void sbwdog_set(char __iomem *wdog, unsigned long t) |
67 | { | 68 | { |
69 | spin_lock(&sbwd_lock); | ||
68 | __raw_writeb(0, wdog - 0x10); | 70 | __raw_writeb(0, wdog - 0x10); |
69 | __raw_writeq(t & 0x7fffffUL, wdog); | 71 | __raw_writeq(t & 0x7fffffUL, wdog); |
72 | spin_unlock(&sbwd_lock); | ||
70 | } | 73 | } |
71 | 74 | ||
72 | /* | 75 | /* |
@@ -77,7 +80,9 @@ void sbwdog_set(char __iomem *wdog, unsigned long t) | |||
77 | */ | 80 | */ |
78 | void sbwdog_pet(char __iomem *wdog) | 81 | void sbwdog_pet(char __iomem *wdog) |
79 | { | 82 | { |
83 | spin_lock(&sbwd_lock); | ||
80 | __raw_writeb(__raw_readb(wdog) | 1, wdog); | 84 | __raw_writeb(__raw_readb(wdog) | 1, wdog); |
85 | spin_unlock(&sbwd_lock); | ||
81 | } | 86 | } |
82 | 87 | ||
83 | static unsigned long sbwdog_gate; /* keeps it to one thread only */ | 88 | static unsigned long sbwdog_gate; /* keeps it to one thread only */ |
@@ -86,8 +91,9 @@ static char __iomem *user_dog = (char __iomem *)(IO_BASE + (A_SCD_WDOG_CFG_1)); | |||
86 | static unsigned long timeout = 0x7fffffUL; /* useconds: 8.3ish secs. */ | 91 | static unsigned long timeout = 0x7fffffUL; /* useconds: 8.3ish secs. */ |
87 | static int expect_close; | 92 | static int expect_close; |
88 | 93 | ||
89 | static struct watchdog_info ident = { | 94 | static const struct watchdog_info ident = { |
90 | .options = WDIOF_CARDRESET | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, | 95 | .options = WDIOF_CARDRESET | WDIOF_SETTIMEOUT | |
96 | WDIOF_KEEPALIVEPING, | ||
91 | .identity = "SiByte Watchdog", | 97 | .identity = "SiByte Watchdog", |
92 | }; | 98 | }; |
93 | 99 | ||
@@ -97,9 +103,8 @@ static struct watchdog_info ident = { | |||
97 | static int sbwdog_open(struct inode *inode, struct file *file) | 103 | static int sbwdog_open(struct inode *inode, struct file *file) |
98 | { | 104 | { |
99 | nonseekable_open(inode, file); | 105 | nonseekable_open(inode, file); |
100 | if (test_and_set_bit(0, &sbwdog_gate)) { | 106 | if (test_and_set_bit(0, &sbwdog_gate)) |
101 | return -EBUSY; | 107 | return -EBUSY; |
102 | } | ||
103 | __module_get(THIS_MODULE); | 108 | __module_get(THIS_MODULE); |
104 | 109 | ||
105 | /* | 110 | /* |
@@ -120,8 +125,9 @@ static int sbwdog_release(struct inode *inode, struct file *file) | |||
120 | __raw_writeb(0, user_dog); | 125 | __raw_writeb(0, user_dog); |
121 | module_put(THIS_MODULE); | 126 | module_put(THIS_MODULE); |
122 | } else { | 127 | } else { |
123 | printk(KERN_CRIT "%s: Unexpected close, not stopping watchdog!\n", | 128 | printk(KERN_CRIT |
124 | ident.identity); | 129 | "%s: Unexpected close, not stopping watchdog!\n", |
130 | ident.identity); | ||
125 | sbwdog_pet(user_dog); | 131 | sbwdog_pet(user_dog); |
126 | } | 132 | } |
127 | clear_bit(0, &sbwdog_gate); | 133 | clear_bit(0, &sbwdog_gate); |
@@ -147,12 +153,10 @@ static ssize_t sbwdog_write(struct file *file, const char __user *data, | |||
147 | for (i = 0; i != len; i++) { | 153 | for (i = 0; i != len; i++) { |
148 | char c; | 154 | char c; |
149 | 155 | ||
150 | if (get_user(c, data + i)) { | 156 | if (get_user(c, data + i)) |
151 | return -EFAULT; | 157 | return -EFAULT; |
152 | } | 158 | if (c == 'V') |
153 | if (c == 'V') { | ||
154 | expect_close = 42; | 159 | expect_close = 42; |
155 | } | ||
156 | } | 160 | } |
157 | sbwdog_pet(user_dog); | 161 | sbwdog_pet(user_dog); |
158 | } | 162 | } |
@@ -160,8 +164,8 @@ static ssize_t sbwdog_write(struct file *file, const char __user *data, | |||
160 | return len; | 164 | return len; |
161 | } | 165 | } |
162 | 166 | ||
163 | static int sbwdog_ioctl(struct inode *inode, struct file *file, | 167 | static long sbwdog_ioctl(struct file *file, unsigned int cmd, |
164 | unsigned int cmd, unsigned long arg) | 168 | unsigned long arg) |
165 | { | 169 | { |
166 | int ret = -ENOTTY; | 170 | int ret = -ENOTTY; |
167 | unsigned long time; | 171 | unsigned long time; |
@@ -178,11 +182,15 @@ static int sbwdog_ioctl(struct inode *inode, struct file *file, | |||
178 | ret = put_user(0, p); | 182 | ret = put_user(0, p); |
179 | break; | 183 | break; |
180 | 184 | ||
185 | case WDIOC_KEEPALIVE: | ||
186 | sbwdog_pet(user_dog); | ||
187 | ret = 0; | ||
188 | break; | ||
189 | |||
181 | case WDIOC_SETTIMEOUT: | 190 | case WDIOC_SETTIMEOUT: |
182 | ret = get_user(time, p); | 191 | ret = get_user(time, p); |
183 | if (ret) { | 192 | if (ret) |
184 | break; | 193 | break; |
185 | } | ||
186 | 194 | ||
187 | time *= 1000000; | 195 | time *= 1000000; |
188 | if (time > 0x7fffffUL) { | 196 | if (time > 0x7fffffUL) { |
@@ -200,11 +208,6 @@ static int sbwdog_ioctl(struct inode *inode, struct file *file, | |||
200 | */ | 208 | */ |
201 | ret = put_user(__raw_readq(user_dog - 8) / 1000000, p); | 209 | ret = put_user(__raw_readq(user_dog - 8) / 1000000, p); |
202 | break; | 210 | break; |
203 | |||
204 | case WDIOC_KEEPALIVE: | ||
205 | sbwdog_pet(user_dog); | ||
206 | ret = 0; | ||
207 | break; | ||
208 | } | 211 | } |
209 | return ret; | 212 | return ret; |
210 | } | 213 | } |
@@ -212,8 +215,8 @@ static int sbwdog_ioctl(struct inode *inode, struct file *file, | |||
212 | /* | 215 | /* |
213 | * Notifier for system down | 216 | * Notifier for system down |
214 | */ | 217 | */ |
215 | static int | 218 | static int sbwdog_notify_sys(struct notifier_block *this, unsigned long code, |
216 | sbwdog_notify_sys(struct notifier_block *this, unsigned long code, void *erf) | 219 | void *erf) |
217 | { | 220 | { |
218 | if (code == SYS_DOWN || code == SYS_HALT) { | 221 | if (code == SYS_DOWN || code == SYS_HALT) { |
219 | /* | 222 | /* |
@@ -226,18 +229,16 @@ sbwdog_notify_sys(struct notifier_block *this, unsigned long code, void *erf) | |||
226 | return NOTIFY_DONE; | 229 | return NOTIFY_DONE; |
227 | } | 230 | } |
228 | 231 | ||
229 | static const struct file_operations sbwdog_fops = | 232 | static const struct file_operations sbwdog_fops = { |
230 | { | ||
231 | .owner = THIS_MODULE, | 233 | .owner = THIS_MODULE, |
232 | .llseek = no_llseek, | 234 | .llseek = no_llseek, |
233 | .write = sbwdog_write, | 235 | .write = sbwdog_write, |
234 | .ioctl = sbwdog_ioctl, | 236 | .unlocked_ioctl = sbwdog_ioctl, |
235 | .open = sbwdog_open, | 237 | .open = sbwdog_open, |
236 | .release = sbwdog_release, | 238 | .release = sbwdog_release, |
237 | }; | 239 | }; |
238 | 240 | ||
239 | static struct miscdevice sbwdog_miscdev = | 241 | static struct miscdevice sbwdog_miscdev = { |
240 | { | ||
241 | .minor = WATCHDOG_MINOR, | 242 | .minor = WATCHDOG_MINOR, |
242 | .name = "watchdog", | 243 | .name = "watchdog", |
243 | .fops = &sbwdog_fops, | 244 | .fops = &sbwdog_fops, |
@@ -267,13 +268,12 @@ irqreturn_t sbwdog_interrupt(int irq, void *addr) | |||
267 | /* | 268 | /* |
268 | * if it's the second watchdog timer, it's for those users | 269 | * if it's the second watchdog timer, it's for those users |
269 | */ | 270 | */ |
270 | if (wd_cfg_reg == user_dog) { | 271 | if (wd_cfg_reg == user_dog) |
271 | printk(KERN_CRIT | 272 | printk(KERN_CRIT |
272 | "%s in danger of initiating system reset in %ld.%01ld seconds\n", | 273 | "%s in danger of initiating system reset in %ld.%01ld seconds\n", |
273 | ident.identity, wd_init / 1000000, (wd_init / 100000) % 10); | 274 | ident.identity, wd_init / 1000000, (wd_init / 100000) % 10); |
274 | } else { | 275 | else |
275 | cfg |= 1; | 276 | cfg |= 1; |
276 | } | ||
277 | 277 | ||
278 | __raw_writeb(cfg, wd_cfg_reg); | 278 | __raw_writeb(cfg, wd_cfg_reg); |
279 | 279 | ||
@@ -289,28 +289,31 @@ static int __init sbwdog_init(void) | |||
289 | */ | 289 | */ |
290 | ret = register_reboot_notifier(&sbwdog_notifier); | 290 | ret = register_reboot_notifier(&sbwdog_notifier); |
291 | if (ret) { | 291 | if (ret) { |
292 | printk (KERN_ERR "%s: cannot register reboot notifier (err=%d)\n", | 292 | printk(KERN_ERR |
293 | ident.identity, ret); | 293 | "%s: cannot register reboot notifier (err=%d)\n", |
294 | ident.identity, ret); | ||
294 | return ret; | 295 | return ret; |
295 | } | 296 | } |
296 | 297 | ||
297 | /* | 298 | /* |
298 | * get the resources | 299 | * get the resources |
299 | */ | 300 | */ |
300 | ret = misc_register(&sbwdog_miscdev); | ||
301 | if (ret == 0) { | ||
302 | printk(KERN_INFO "%s: timeout is %ld.%ld secs\n", ident.identity, | ||
303 | timeout / 1000000, (timeout / 100000) % 10); | ||
304 | } | ||
305 | 301 | ||
306 | ret = request_irq(1, sbwdog_interrupt, IRQF_DISABLED | IRQF_SHARED, | 302 | ret = request_irq(1, sbwdog_interrupt, IRQF_DISABLED | IRQF_SHARED, |
307 | ident.identity, (void *)user_dog); | 303 | ident.identity, (void *)user_dog); |
308 | if (ret) { | 304 | if (ret) { |
309 | printk(KERN_ERR "%s: failed to request irq 1 - %d\n", ident.identity, | 305 | printk(KERN_ERR "%s: failed to request irq 1 - %d\n", |
310 | ret); | 306 | ident.identity, ret); |
311 | misc_deregister(&sbwdog_miscdev); | 307 | return ret; |
312 | } | 308 | } |
313 | 309 | ||
310 | ret = misc_register(&sbwdog_miscdev); | ||
311 | if (ret == 0) { | ||
312 | printk(KERN_INFO "%s: timeout is %ld.%ld secs\n", | ||
313 | ident.identity, | ||
314 | timeout / 1000000, (timeout / 100000) % 10); | ||
315 | } else | ||
316 | free_irq(1, (void *)user_dog); | ||
314 | return ret; | 317 | return ret; |
315 | } | 318 | } |
316 | 319 | ||
@@ -327,7 +330,7 @@ MODULE_DESCRIPTION("SiByte Watchdog"); | |||
327 | 330 | ||
328 | module_param(timeout, ulong, 0); | 331 | module_param(timeout, ulong, 0); |
329 | MODULE_PARM_DESC(timeout, | 332 | MODULE_PARM_DESC(timeout, |
330 | "Watchdog timeout in microseconds (max/default 8388607 or 8.3ish secs)"); | 333 | "Watchdog timeout in microseconds (max/default 8388607 or 8.3ish secs)"); |
331 | 334 | ||
332 | MODULE_LICENSE("GPL"); | 335 | MODULE_LICENSE("GPL"); |
333 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); | 336 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); |
@@ -336,16 +339,15 @@ MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); | |||
336 | * example code that can be put in a platform code area to utilize the | 339 | * example code that can be put in a platform code area to utilize the |
337 | * first watchdog timer for the kernels own purpose. | 340 | * first watchdog timer for the kernels own purpose. |
338 | 341 | ||
339 | void | 342 | void platform_wd_setup(void) |
340 | platform_wd_setup(void) | ||
341 | { | 343 | { |
342 | int ret; | 344 | int ret; |
343 | 345 | ||
344 | ret = request_irq(0, sbwdog_interrupt, IRQF_DISABLED | IRQF_SHARED, | 346 | ret = request_irq(1, sbwdog_interrupt, IRQF_DISABLED | IRQF_SHARED, |
345 | "Kernel Watchdog", IOADDR(A_SCD_WDOG_CFG_0)); | 347 | "Kernel Watchdog", IOADDR(A_SCD_WDOG_CFG_0)); |
346 | if (ret) { | 348 | if (ret) { |
347 | printk(KERN_CRIT "Watchdog IRQ zero(0) failed to be requested - %d\n", | 349 | printk(KERN_CRIT |
348 | ret); | 350 | "Watchdog IRQ zero(0) failed to be requested - %d\n", ret); |
349 | } | 351 | } |
350 | } | 352 | } |
351 | 353 | ||
diff --git a/drivers/watchdog/sbc60xxwdt.c b/drivers/watchdog/sbc60xxwdt.c index ef76f01625e7..3266daaaecf8 100644 --- a/drivers/watchdog/sbc60xxwdt.c +++ b/drivers/watchdog/sbc60xxwdt.c | |||
@@ -16,19 +16,23 @@ | |||
16 | * | 16 | * |
17 | * 12/4 - 2000 [Initial revision] | 17 | * 12/4 - 2000 [Initial revision] |
18 | * 25/4 - 2000 Added /dev/watchdog support | 18 | * 25/4 - 2000 Added /dev/watchdog support |
19 | * 09/5 - 2001 [smj@oro.net] fixed fop_write to "return 1" on success | 19 | * 09/5 - 2001 [smj@oro.net] fixed fop_write to "return 1" |
20 | * on success | ||
20 | * 12/4 - 2002 [rob@osinvestor.com] eliminate fop_read | 21 | * 12/4 - 2002 [rob@osinvestor.com] eliminate fop_read |
21 | * fix possible wdt_is_open race | 22 | * fix possible wdt_is_open race |
22 | * add CONFIG_WATCHDOG_NOWAYOUT support | 23 | * add CONFIG_WATCHDOG_NOWAYOUT support |
23 | * remove lock_kernel/unlock_kernel pairs | 24 | * remove lock_kernel/unlock_kernel pairs |
24 | * added KERN_* to printk's | 25 | * added KERN_* to printk's |
25 | * got rid of extraneous comments | 26 | * got rid of extraneous comments |
26 | * changed watchdog_info to correctly reflect what the driver offers | 27 | * changed watchdog_info to correctly reflect what |
27 | * added WDIOC_GETSTATUS, WDIOC_GETBOOTSTATUS, WDIOC_SETTIMEOUT, | 28 | * the driver offers |
28 | * WDIOC_GETTIMEOUT, and WDIOC_SETOPTIONS ioctls | 29 | * added WDIOC_GETSTATUS, WDIOC_GETBOOTSTATUS, |
30 | * WDIOC_SETTIMEOUT, WDIOC_GETTIMEOUT, and | ||
31 | * WDIOC_SETOPTIONS ioctls | ||
29 | * 09/8 - 2003 [wim@iguana.be] cleanup of trailing spaces | 32 | * 09/8 - 2003 [wim@iguana.be] cleanup of trailing spaces |
30 | * use module_param | 33 | * use module_param |
31 | * made timeout (the emulated heartbeat) a module_param | 34 | * made timeout (the emulated heartbeat) a |
35 | * module_param | ||
32 | * made the keepalive ping an internal subroutine | 36 | * made the keepalive ping an internal subroutine |
33 | * made wdt_stop and wdt_start module params | 37 | * made wdt_stop and wdt_start module params |
34 | * added extra printk's for startup problems | 38 | * added extra printk's for startup problems |
@@ -56,9 +60,9 @@ | |||
56 | #include <linux/notifier.h> | 60 | #include <linux/notifier.h> |
57 | #include <linux/reboot.h> | 61 | #include <linux/reboot.h> |
58 | #include <linux/init.h> | 62 | #include <linux/init.h> |
63 | #include <linux/io.h> | ||
64 | #include <linux/uaccess.h> | ||
59 | 65 | ||
60 | #include <asm/io.h> | ||
61 | #include <asm/uaccess.h> | ||
62 | #include <asm/system.h> | 66 | #include <asm/system.h> |
63 | 67 | ||
64 | #define OUR_NAME "sbc60xxwdt" | 68 | #define OUR_NAME "sbc60xxwdt" |
@@ -94,13 +98,18 @@ MODULE_PARM_DESC(wdt_start, "SBC60xx WDT 'start' io port (default 0x443)"); | |||
94 | */ | 98 | */ |
95 | 99 | ||
96 | #define WATCHDOG_TIMEOUT 30 /* 30 sec default timeout */ | 100 | #define WATCHDOG_TIMEOUT 30 /* 30 sec default timeout */ |
97 | static int timeout = WATCHDOG_TIMEOUT; /* in seconds, will be multiplied by HZ to get seconds to wait for a ping */ | 101 | static int timeout = WATCHDOG_TIMEOUT; /* in seconds, multiplied by HZ to |
102 | get seconds to wait for a ping */ | ||
98 | module_param(timeout, int, 0); | 103 | module_param(timeout, int, 0); |
99 | MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (1<=timeout<=3600, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")"); | 104 | MODULE_PARM_DESC(timeout, |
105 | "Watchdog timeout in seconds. (1<=timeout<=3600, default=" | ||
106 | __MODULE_STRING(WATCHDOG_TIMEOUT) ")"); | ||
100 | 107 | ||
101 | static int nowayout = WATCHDOG_NOWAYOUT; | 108 | static int nowayout = WATCHDOG_NOWAYOUT; |
102 | module_param(nowayout, int, 0); | 109 | module_param(nowayout, int, 0); |
103 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 110 | MODULE_PARM_DESC(nowayout, |
111 | "Watchdog cannot be stopped once started (default=" | ||
112 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
104 | 113 | ||
105 | static void wdt_timer_ping(unsigned long); | 114 | static void wdt_timer_ping(unsigned long); |
106 | static DEFINE_TIMER(timer, wdt_timer_ping, 0, 0); | 115 | static DEFINE_TIMER(timer, wdt_timer_ping, 0, 0); |
@@ -117,15 +126,14 @@ static void wdt_timer_ping(unsigned long data) | |||
117 | /* If we got a heartbeat pulse within the WDT_US_INTERVAL | 126 | /* If we got a heartbeat pulse within the WDT_US_INTERVAL |
118 | * we agree to ping the WDT | 127 | * we agree to ping the WDT |
119 | */ | 128 | */ |
120 | if(time_before(jiffies, next_heartbeat)) | 129 | if (time_before(jiffies, next_heartbeat)) { |
121 | { | ||
122 | /* Ping the WDT by reading from wdt_start */ | 130 | /* Ping the WDT by reading from wdt_start */ |
123 | inb_p(wdt_start); | 131 | inb_p(wdt_start); |
124 | /* Re-set the timer interval */ | 132 | /* Re-set the timer interval */ |
125 | mod_timer(&timer, jiffies + WDT_INTERVAL); | 133 | mod_timer(&timer, jiffies + WDT_INTERVAL); |
126 | } else { | 134 | } else |
127 | printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n"); | 135 | printk(KERN_WARNING PFX |
128 | } | 136 | "Heartbeat lost! Will not ping the watchdog\n"); |
129 | } | 137 | } |
130 | 138 | ||
131 | /* | 139 | /* |
@@ -159,40 +167,40 @@ static void wdt_keepalive(void) | |||
159 | * /dev/watchdog handling | 167 | * /dev/watchdog handling |
160 | */ | 168 | */ |
161 | 169 | ||
162 | static ssize_t fop_write(struct file * file, const char __user * buf, size_t count, loff_t * ppos) | 170 | static ssize_t fop_write(struct file *file, const char __user *buf, |
171 | size_t count, loff_t *ppos) | ||
163 | { | 172 | { |
164 | /* See if we got the magic character 'V' and reload the timer */ | 173 | /* See if we got the magic character 'V' and reload the timer */ |
165 | if(count) | 174 | if (count) { |
166 | { | 175 | if (!nowayout) { |
167 | if (!nowayout) | ||
168 | { | ||
169 | size_t ofs; | 176 | size_t ofs; |
170 | 177 | ||
171 | /* note: just in case someone wrote the magic character | 178 | /* note: just in case someone wrote the |
172 | * five months ago... */ | 179 | magic character five months ago... */ |
173 | wdt_expect_close = 0; | 180 | wdt_expect_close = 0; |
174 | 181 | ||
175 | /* scan to see whether or not we got the magic character */ | 182 | /* scan to see whether or not we got the |
176 | for(ofs = 0; ofs != count; ofs++) | 183 | magic character */ |
177 | { | 184 | for (ofs = 0; ofs != count; ofs++) { |
178 | char c; | 185 | char c; |
179 | if(get_user(c, buf+ofs)) | 186 | if (get_user(c, buf + ofs)) |
180 | return -EFAULT; | 187 | return -EFAULT; |
181 | if(c == 'V') | 188 | if (c == 'V') |
182 | wdt_expect_close = 42; | 189 | wdt_expect_close = 42; |
183 | } | 190 | } |
184 | } | 191 | } |
185 | 192 | ||
186 | /* Well, anyhow someone wrote to us, we should return that favour */ | 193 | /* Well, anyhow someone wrote to us, we should |
194 | return that favour */ | ||
187 | wdt_keepalive(); | 195 | wdt_keepalive(); |
188 | } | 196 | } |
189 | return count; | 197 | return count; |
190 | } | 198 | } |
191 | 199 | ||
192 | static int fop_open(struct inode * inode, struct file * file) | 200 | static int fop_open(struct inode *inode, struct file *file) |
193 | { | 201 | { |
194 | /* Just in case we're already talking to someone... */ | 202 | /* Just in case we're already talking to someone... */ |
195 | if(test_and_set_bit(0, &wdt_is_open)) | 203 | if (test_and_set_bit(0, &wdt_is_open)) |
196 | return -EBUSY; | 204 | return -EBUSY; |
197 | 205 | ||
198 | if (nowayout) | 206 | if (nowayout) |
@@ -203,78 +211,72 @@ static int fop_open(struct inode * inode, struct file * file) | |||
203 | return nonseekable_open(inode, file); | 211 | return nonseekable_open(inode, file); |
204 | } | 212 | } |
205 | 213 | ||
206 | static int fop_close(struct inode * inode, struct file * file) | 214 | static int fop_close(struct inode *inode, struct file *file) |
207 | { | 215 | { |
208 | if(wdt_expect_close == 42) | 216 | if (wdt_expect_close == 42) |
209 | wdt_turnoff(); | 217 | wdt_turnoff(); |
210 | else { | 218 | else { |
211 | del_timer(&timer); | 219 | del_timer(&timer); |
212 | printk(KERN_CRIT PFX "device file closed unexpectedly. Will not stop the WDT!\n"); | 220 | printk(KERN_CRIT PFX |
221 | "device file closed unexpectedly. Will not stop the WDT!\n"); | ||
213 | } | 222 | } |
214 | clear_bit(0, &wdt_is_open); | 223 | clear_bit(0, &wdt_is_open); |
215 | wdt_expect_close = 0; | 224 | wdt_expect_close = 0; |
216 | return 0; | 225 | return 0; |
217 | } | 226 | } |
218 | 227 | ||
219 | static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | 228 | static long fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
220 | unsigned long arg) | ||
221 | { | 229 | { |
222 | void __user *argp = (void __user *)arg; | 230 | void __user *argp = (void __user *)arg; |
223 | int __user *p = argp; | 231 | int __user *p = argp; |
224 | static struct watchdog_info ident= | 232 | static const struct watchdog_info ident = { |
225 | { | 233 | .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | |
226 | .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, | 234 | WDIOF_MAGICCLOSE, |
227 | .firmware_version = 1, | 235 | .firmware_version = 1, |
228 | .identity = "SBC60xx", | 236 | .identity = "SBC60xx", |
229 | }; | 237 | }; |
230 | 238 | ||
231 | switch(cmd) | 239 | switch (cmd) { |
240 | case WDIOC_GETSUPPORT: | ||
241 | return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; | ||
242 | case WDIOC_GETSTATUS: | ||
243 | case WDIOC_GETBOOTSTATUS: | ||
244 | return put_user(0, p); | ||
245 | case WDIOC_SETOPTIONS: | ||
232 | { | 246 | { |
233 | default: | 247 | int new_options, retval = -EINVAL; |
234 | return -ENOTTY; | 248 | if (get_user(new_options, p)) |
235 | case WDIOC_GETSUPPORT: | 249 | return -EFAULT; |
236 | return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0; | 250 | if (new_options & WDIOS_DISABLECARD) { |
237 | case WDIOC_GETSTATUS: | 251 | wdt_turnoff(); |
238 | case WDIOC_GETBOOTSTATUS: | 252 | retval = 0; |
239 | return put_user(0, p); | ||
240 | case WDIOC_KEEPALIVE: | ||
241 | wdt_keepalive(); | ||
242 | return 0; | ||
243 | case WDIOC_SETOPTIONS: | ||
244 | { | ||
245 | int new_options, retval = -EINVAL; | ||
246 | |||
247 | if(get_user(new_options, p)) | ||
248 | return -EFAULT; | ||
249 | |||
250 | if(new_options & WDIOS_DISABLECARD) { | ||
251 | wdt_turnoff(); | ||
252 | retval = 0; | ||
253 | } | ||
254 | |||
255 | if(new_options & WDIOS_ENABLECARD) { | ||
256 | wdt_startup(); | ||
257 | retval = 0; | ||
258 | } | ||
259 | |||
260 | return retval; | ||
261 | } | 253 | } |
262 | case WDIOC_SETTIMEOUT: | 254 | if (new_options & WDIOS_ENABLECARD) { |
263 | { | 255 | wdt_startup(); |
264 | int new_timeout; | 256 | retval = 0; |
265 | |||
266 | if(get_user(new_timeout, p)) | ||
267 | return -EFAULT; | ||
268 | |||
269 | if(new_timeout < 1 || new_timeout > 3600) /* arbitrary upper limit */ | ||
270 | return -EINVAL; | ||
271 | |||
272 | timeout = new_timeout; | ||
273 | wdt_keepalive(); | ||
274 | /* Fall through */ | ||
275 | } | 257 | } |
276 | case WDIOC_GETTIMEOUT: | 258 | return retval; |
277 | return put_user(timeout, p); | 259 | } |
260 | case WDIOC_KEEPALIVE: | ||
261 | wdt_keepalive(); | ||
262 | return 0; | ||
263 | case WDIOC_SETTIMEOUT: | ||
264 | { | ||
265 | int new_timeout; | ||
266 | if (get_user(new_timeout, p)) | ||
267 | return -EFAULT; | ||
268 | /* arbitrary upper limit */ | ||
269 | if (new_timeout < 1 || new_timeout > 3600) | ||
270 | return -EINVAL; | ||
271 | |||
272 | timeout = new_timeout; | ||
273 | wdt_keepalive(); | ||
274 | /* Fall through */ | ||
275 | } | ||
276 | case WDIOC_GETTIMEOUT: | ||
277 | return put_user(timeout, p); | ||
278 | default: | ||
279 | return -ENOTTY; | ||
278 | } | 280 | } |
279 | } | 281 | } |
280 | 282 | ||
@@ -284,7 +286,7 @@ static const struct file_operations wdt_fops = { | |||
284 | .write = fop_write, | 286 | .write = fop_write, |
285 | .open = fop_open, | 287 | .open = fop_open, |
286 | .release = fop_close, | 288 | .release = fop_close, |
287 | .ioctl = fop_ioctl, | 289 | .unlocked_ioctl = fop_ioctl, |
288 | }; | 290 | }; |
289 | 291 | ||
290 | static struct miscdevice wdt_miscdev = { | 292 | static struct miscdevice wdt_miscdev = { |
@@ -300,7 +302,7 @@ static struct miscdevice wdt_miscdev = { | |||
300 | static int wdt_notify_sys(struct notifier_block *this, unsigned long code, | 302 | static int wdt_notify_sys(struct notifier_block *this, unsigned long code, |
301 | void *unused) | 303 | void *unused) |
302 | { | 304 | { |
303 | if(code==SYS_DOWN || code==SYS_HALT) | 305 | if (code == SYS_DOWN || code == SYS_HALT) |
304 | wdt_turnoff(); | 306 | wdt_turnoff(); |
305 | return NOTIFY_DONE; | 307 | return NOTIFY_DONE; |
306 | } | 308 | } |
@@ -310,8 +312,7 @@ static int wdt_notify_sys(struct notifier_block *this, unsigned long code, | |||
310 | * turn the timebomb registers off. | 312 | * turn the timebomb registers off. |
311 | */ | 313 | */ |
312 | 314 | ||
313 | static struct notifier_block wdt_notifier= | 315 | static struct notifier_block wdt_notifier = { |
314 | { | ||
315 | .notifier_call = wdt_notify_sys, | 316 | .notifier_call = wdt_notify_sys, |
316 | }; | 317 | }; |
317 | 318 | ||
@@ -324,23 +325,22 @@ static void __exit sbc60xxwdt_unload(void) | |||
324 | 325 | ||
325 | unregister_reboot_notifier(&wdt_notifier); | 326 | unregister_reboot_notifier(&wdt_notifier); |
326 | if ((wdt_stop != 0x45) && (wdt_stop != wdt_start)) | 327 | if ((wdt_stop != 0x45) && (wdt_stop != wdt_start)) |
327 | release_region(wdt_stop,1); | 328 | release_region(wdt_stop, 1); |
328 | release_region(wdt_start,1); | 329 | release_region(wdt_start, 1); |
329 | } | 330 | } |
330 | 331 | ||
331 | static int __init sbc60xxwdt_init(void) | 332 | static int __init sbc60xxwdt_init(void) |
332 | { | 333 | { |
333 | int rc = -EBUSY; | 334 | int rc = -EBUSY; |
334 | 335 | ||
335 | if(timeout < 1 || timeout > 3600) /* arbitrary upper limit */ | 336 | if (timeout < 1 || timeout > 3600) { /* arbitrary upper limit */ |
336 | { | ||
337 | timeout = WATCHDOG_TIMEOUT; | 337 | timeout = WATCHDOG_TIMEOUT; |
338 | printk(KERN_INFO PFX "timeout value must be 1<=x<=3600, using %d\n", | 338 | printk(KERN_INFO PFX |
339 | timeout); | 339 | "timeout value must be 1 <= x <= 3600, using %d\n", |
340 | } | 340 | timeout); |
341 | } | ||
341 | 342 | ||
342 | if (!request_region(wdt_start, 1, "SBC 60XX WDT")) | 343 | if (!request_region(wdt_start, 1, "SBC 60XX WDT")) { |
343 | { | ||
344 | printk(KERN_ERR PFX "I/O address 0x%04x already in use\n", | 344 | printk(KERN_ERR PFX "I/O address 0x%04x already in use\n", |
345 | wdt_start); | 345 | wdt_start); |
346 | rc = -EIO; | 346 | rc = -EIO; |
@@ -348,33 +348,30 @@ static int __init sbc60xxwdt_init(void) | |||
348 | } | 348 | } |
349 | 349 | ||
350 | /* We cannot reserve 0x45 - the kernel already has! */ | 350 | /* We cannot reserve 0x45 - the kernel already has! */ |
351 | if ((wdt_stop != 0x45) && (wdt_stop != wdt_start)) | 351 | if (wdt_stop != 0x45 && wdt_stop != wdt_start) { |
352 | { | 352 | if (!request_region(wdt_stop, 1, "SBC 60XX WDT")) { |
353 | if (!request_region(wdt_stop, 1, "SBC 60XX WDT")) | 353 | printk(KERN_ERR PFX |
354 | { | 354 | "I/O address 0x%04x already in use\n", |
355 | printk(KERN_ERR PFX "I/O address 0x%04x already in use\n", | 355 | wdt_stop); |
356 | wdt_stop); | ||
357 | rc = -EIO; | 356 | rc = -EIO; |
358 | goto err_out_region1; | 357 | goto err_out_region1; |
359 | } | 358 | } |
360 | } | 359 | } |
361 | 360 | ||
362 | rc = register_reboot_notifier(&wdt_notifier); | 361 | rc = register_reboot_notifier(&wdt_notifier); |
363 | if (rc) | 362 | if (rc) { |
364 | { | 363 | printk(KERN_ERR PFX |
365 | printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", | 364 | "cannot register reboot notifier (err=%d)\n", rc); |
366 | rc); | ||
367 | goto err_out_region2; | 365 | goto err_out_region2; |
368 | } | 366 | } |
369 | 367 | ||
370 | rc = misc_register(&wdt_miscdev); | 368 | rc = misc_register(&wdt_miscdev); |
371 | if (rc) | 369 | if (rc) { |
372 | { | 370 | printk(KERN_ERR PFX |
373 | printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", | 371 | "cannot register miscdev on minor=%d (err=%d)\n", |
374 | wdt_miscdev.minor, rc); | 372 | wdt_miscdev.minor, rc); |
375 | goto err_out_reboot; | 373 | goto err_out_reboot; |
376 | } | 374 | } |
377 | |||
378 | printk(KERN_INFO PFX "WDT driver for 60XX single board computer initialised. timeout=%d sec (nowayout=%d)\n", | 375 | printk(KERN_INFO PFX "WDT driver for 60XX single board computer initialised. timeout=%d sec (nowayout=%d)\n", |
379 | timeout, nowayout); | 376 | timeout, nowayout); |
380 | 377 | ||
@@ -383,10 +380,10 @@ static int __init sbc60xxwdt_init(void) | |||
383 | err_out_reboot: | 380 | err_out_reboot: |
384 | unregister_reboot_notifier(&wdt_notifier); | 381 | unregister_reboot_notifier(&wdt_notifier); |
385 | err_out_region2: | 382 | err_out_region2: |
386 | if ((wdt_stop != 0x45) && (wdt_stop != wdt_start)) | 383 | if (wdt_stop != 0x45 && wdt_stop != wdt_start) |
387 | release_region(wdt_stop,1); | 384 | release_region(wdt_stop, 1); |
388 | err_out_region1: | 385 | err_out_region1: |
389 | release_region(wdt_start,1); | 386 | release_region(wdt_start, 1); |
390 | err_out: | 387 | err_out: |
391 | return rc; | 388 | return rc; |
392 | } | 389 | } |
diff --git a/drivers/watchdog/sbc7240_wdt.c b/drivers/watchdog/sbc7240_wdt.c index 4c8cefbd8627..67ddeb1c830a 100644 --- a/drivers/watchdog/sbc7240_wdt.c +++ b/drivers/watchdog/sbc7240_wdt.c | |||
@@ -27,10 +27,10 @@ | |||
27 | #include <linux/reboot.h> | 27 | #include <linux/reboot.h> |
28 | #include <linux/types.h> | 28 | #include <linux/types.h> |
29 | #include <linux/watchdog.h> | 29 | #include <linux/watchdog.h> |
30 | #include <linux/io.h> | ||
31 | #include <linux/uaccess.h> | ||
30 | #include <asm/atomic.h> | 32 | #include <asm/atomic.h> |
31 | #include <asm/io.h> | ||
32 | #include <asm/system.h> | 33 | #include <asm/system.h> |
33 | #include <asm/uaccess.h> | ||
34 | 34 | ||
35 | #define SBC7240_PREFIX "sbc7240_wdt: " | 35 | #define SBC7240_PREFIX "sbc7240_wdt: " |
36 | 36 | ||
@@ -159,7 +159,7 @@ static int fop_close(struct inode *inode, struct file *file) | |||
159 | return 0; | 159 | return 0; |
160 | } | 160 | } |
161 | 161 | ||
162 | static struct watchdog_info ident = { | 162 | static const struct watchdog_info ident = { |
163 | .options = WDIOF_KEEPALIVEPING| | 163 | .options = WDIOF_KEEPALIVEPING| |
164 | WDIOF_SETTIMEOUT| | 164 | WDIOF_SETTIMEOUT| |
165 | WDIOF_MAGICCLOSE, | 165 | WDIOF_MAGICCLOSE, |
@@ -168,50 +168,50 @@ static struct watchdog_info ident = { | |||
168 | }; | 168 | }; |
169 | 169 | ||
170 | 170 | ||
171 | static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | 171 | static long fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
172 | unsigned long arg) | ||
173 | { | 172 | { |
174 | switch (cmd) { | 173 | switch (cmd) { |
175 | case WDIOC_GETSUPPORT: | 174 | case WDIOC_GETSUPPORT: |
176 | return copy_to_user | 175 | return copy_to_user((void __user *)arg, &ident, sizeof(ident)) |
177 | ((void __user *)arg, &ident, sizeof(ident)) | 176 | ? -EFAULT : 0; |
178 | ? -EFAULT : 0; | ||
179 | case WDIOC_GETSTATUS: | 177 | case WDIOC_GETSTATUS: |
180 | case WDIOC_GETBOOTSTATUS: | 178 | case WDIOC_GETBOOTSTATUS: |
181 | return put_user(0, (int __user *)arg); | 179 | return put_user(0, (int __user *)arg); |
182 | case WDIOC_KEEPALIVE: | 180 | case WDIOC_SETOPTIONS: |
183 | wdt_keepalive(); | 181 | { |
184 | return 0; | 182 | int options; |
185 | case WDIOC_SETOPTIONS:{ | 183 | int retval = -EINVAL; |
186 | int options; | ||
187 | int retval = -EINVAL; | ||
188 | 184 | ||
189 | if (get_user(options, (int __user *)arg)) | 185 | if (get_user(options, (int __user *)arg)) |
190 | return -EFAULT; | 186 | return -EFAULT; |
191 | 187 | ||
192 | if (options & WDIOS_DISABLECARD) { | 188 | if (options & WDIOS_DISABLECARD) { |
193 | wdt_disable(); | 189 | wdt_disable(); |
194 | retval = 0; | 190 | retval = 0; |
195 | } | 191 | } |
196 | |||
197 | if (options & WDIOS_ENABLECARD) { | ||
198 | wdt_enable(); | ||
199 | retval = 0; | ||
200 | } | ||
201 | 192 | ||
202 | return retval; | 193 | if (options & WDIOS_ENABLECARD) { |
194 | wdt_enable(); | ||
195 | retval = 0; | ||
203 | } | 196 | } |
204 | case WDIOC_SETTIMEOUT:{ | ||
205 | int new_timeout; | ||
206 | 197 | ||
207 | if (get_user(new_timeout, (int __user *)arg)) | 198 | return retval; |
208 | return -EFAULT; | 199 | } |
200 | case WDIOC_KEEPALIVE: | ||
201 | wdt_keepalive(); | ||
202 | return 0; | ||
203 | case WDIOC_SETTIMEOUT: | ||
204 | { | ||
205 | int new_timeout; | ||
209 | 206 | ||
210 | if (wdt_set_timeout(new_timeout)) | 207 | if (get_user(new_timeout, (int __user *)arg)) |
211 | return -EINVAL; | 208 | return -EFAULT; |
212 | 209 | ||
213 | /* Fall through */ | 210 | if (wdt_set_timeout(new_timeout)) |
214 | } | 211 | return -EINVAL; |
212 | |||
213 | /* Fall through */ | ||
214 | } | ||
215 | case WDIOC_GETTIMEOUT: | 215 | case WDIOC_GETTIMEOUT: |
216 | return put_user(timeout, (int __user *)arg); | 216 | return put_user(timeout, (int __user *)arg); |
217 | default: | 217 | default: |
@@ -225,7 +225,7 @@ static const struct file_operations wdt_fops = { | |||
225 | .write = fop_write, | 225 | .write = fop_write, |
226 | .open = fop_open, | 226 | .open = fop_open, |
227 | .release = fop_close, | 227 | .release = fop_close, |
228 | .ioctl = fop_ioctl, | 228 | .unlocked_ioctl = fop_ioctl, |
229 | }; | 229 | }; |
230 | 230 | ||
231 | static struct miscdevice wdt_miscdev = { | 231 | static struct miscdevice wdt_miscdev = { |
diff --git a/drivers/watchdog/sbc8360.c b/drivers/watchdog/sbc8360.c index 2ee2677f3648..fd83dd052d8c 100644 --- a/drivers/watchdog/sbc8360.c +++ b/drivers/watchdog/sbc8360.c | |||
@@ -48,13 +48,12 @@ | |||
48 | #include <linux/init.h> | 48 | #include <linux/init.h> |
49 | #include <linux/spinlock.h> | 49 | #include <linux/spinlock.h> |
50 | #include <linux/moduleparam.h> | 50 | #include <linux/moduleparam.h> |
51 | #include <linux/io.h> | ||
52 | #include <linux/uaccess.h> | ||
51 | 53 | ||
52 | #include <asm/io.h> | ||
53 | #include <asm/uaccess.h> | ||
54 | #include <asm/system.h> | 54 | #include <asm/system.h> |
55 | 55 | ||
56 | static unsigned long sbc8360_is_open; | 56 | static unsigned long sbc8360_is_open; |
57 | static DEFINE_SPINLOCK(sbc8360_lock); | ||
58 | static char expect_close; | 57 | static char expect_close; |
59 | 58 | ||
60 | #define PFX "sbc8360: " | 59 | #define PFX "sbc8360: " |
@@ -204,7 +203,8 @@ module_param(timeout, int, 0); | |||
204 | MODULE_PARM_DESC(timeout, "Index into timeout table (0-63) (default=27 (60s))"); | 203 | MODULE_PARM_DESC(timeout, "Index into timeout table (0-63) (default=27 (60s))"); |
205 | module_param(nowayout, int, 0); | 204 | module_param(nowayout, int, 0); |
206 | MODULE_PARM_DESC(nowayout, | 205 | MODULE_PARM_DESC(nowayout, |
207 | "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 206 | "Watchdog cannot be stopped once started (default=" |
207 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
208 | 208 | ||
209 | /* | 209 | /* |
210 | * Kernel methods. | 210 | * Kernel methods. |
@@ -231,9 +231,16 @@ static void sbc8360_ping(void) | |||
231 | outb(wd_margin, SBC8360_BASETIME); | 231 | outb(wd_margin, SBC8360_BASETIME); |
232 | } | 232 | } |
233 | 233 | ||
234 | /* stop watchdog */ | ||
235 | static void sbc8360_stop(void) | ||
236 | { | ||
237 | /* De-activate the watchdog */ | ||
238 | outb(0, SBC8360_ENABLE); | ||
239 | } | ||
240 | |||
234 | /* Userspace pings kernel driver, or requests clean close */ | 241 | /* Userspace pings kernel driver, or requests clean close */ |
235 | static ssize_t sbc8360_write(struct file *file, const char __user * buf, | 242 | static ssize_t sbc8360_write(struct file *file, const char __user *buf, |
236 | size_t count, loff_t * ppos) | 243 | size_t count, loff_t *ppos) |
237 | { | 244 | { |
238 | if (count) { | 245 | if (count) { |
239 | if (!nowayout) { | 246 | if (!nowayout) { |
@@ -257,16 +264,12 @@ static ssize_t sbc8360_write(struct file *file, const char __user * buf, | |||
257 | 264 | ||
258 | static int sbc8360_open(struct inode *inode, struct file *file) | 265 | static int sbc8360_open(struct inode *inode, struct file *file) |
259 | { | 266 | { |
260 | spin_lock(&sbc8360_lock); | 267 | if (test_and_set_bit(0, &sbc8360_is_open)) |
261 | if (test_and_set_bit(0, &sbc8360_is_open)) { | ||
262 | spin_unlock(&sbc8360_lock); | ||
263 | return -EBUSY; | 268 | return -EBUSY; |
264 | } | ||
265 | if (nowayout) | 269 | if (nowayout) |
266 | __module_get(THIS_MODULE); | 270 | __module_get(THIS_MODULE); |
267 | 271 | ||
268 | /* Activate and ping once to start the countdown */ | 272 | /* Activate and ping once to start the countdown */ |
269 | spin_unlock(&sbc8360_lock); | ||
270 | sbc8360_activate(); | 273 | sbc8360_activate(); |
271 | sbc8360_ping(); | 274 | sbc8360_ping(); |
272 | return nonseekable_open(inode, file); | 275 | return nonseekable_open(inode, file); |
@@ -274,16 +277,14 @@ static int sbc8360_open(struct inode *inode, struct file *file) | |||
274 | 277 | ||
275 | static int sbc8360_close(struct inode *inode, struct file *file) | 278 | static int sbc8360_close(struct inode *inode, struct file *file) |
276 | { | 279 | { |
277 | spin_lock(&sbc8360_lock); | ||
278 | if (expect_close == 42) | 280 | if (expect_close == 42) |
279 | outb(0, SBC8360_ENABLE); | 281 | sbc8360_stop(); |
280 | else | 282 | else |
281 | printk(KERN_CRIT PFX | 283 | printk(KERN_CRIT PFX |
282 | "SBC8360 device closed unexpectedly. SBC8360 will not stop!\n"); | 284 | "SBC8360 device closed unexpectedly. SBC8360 will not stop!\n"); |
283 | 285 | ||
284 | clear_bit(0, &sbc8360_is_open); | 286 | clear_bit(0, &sbc8360_is_open); |
285 | expect_close = 0; | 287 | expect_close = 0; |
286 | spin_unlock(&sbc8360_lock); | ||
287 | return 0; | 288 | return 0; |
288 | } | 289 | } |
289 | 290 | ||
@@ -294,10 +295,9 @@ static int sbc8360_close(struct inode *inode, struct file *file) | |||
294 | static int sbc8360_notify_sys(struct notifier_block *this, unsigned long code, | 295 | static int sbc8360_notify_sys(struct notifier_block *this, unsigned long code, |
295 | void *unused) | 296 | void *unused) |
296 | { | 297 | { |
297 | if (code == SYS_DOWN || code == SYS_HALT) { | 298 | if (code == SYS_DOWN || code == SYS_HALT) |
298 | /* Disable the SBC8360 Watchdog */ | 299 | sbc8360_stop(); /* Disable the SBC8360 Watchdog */ |
299 | outb(0, SBC8360_ENABLE); | 300 | |
300 | } | ||
301 | return NOTIFY_DONE; | 301 | return NOTIFY_DONE; |
302 | } | 302 | } |
303 | 303 | ||
@@ -382,13 +382,13 @@ static int __init sbc8360_init(void) | |||
382 | 382 | ||
383 | return 0; | 383 | return 0; |
384 | 384 | ||
385 | out_nomisc: | 385 | out_nomisc: |
386 | unregister_reboot_notifier(&sbc8360_notifier); | 386 | unregister_reboot_notifier(&sbc8360_notifier); |
387 | out_noreboot: | 387 | out_noreboot: |
388 | release_region(SBC8360_BASETIME, 1); | 388 | release_region(SBC8360_BASETIME, 1); |
389 | out_nobasetimereg: | 389 | out_nobasetimereg: |
390 | release_region(SBC8360_ENABLE, 1); | 390 | release_region(SBC8360_ENABLE, 1); |
391 | out: | 391 | out: |
392 | return res; | 392 | return res; |
393 | } | 393 | } |
394 | 394 | ||
diff --git a/drivers/watchdog/sbc_epx_c3.c b/drivers/watchdog/sbc_epx_c3.c index 82cbd8809a69..e5e470ca7759 100644 --- a/drivers/watchdog/sbc_epx_c3.c +++ b/drivers/watchdog/sbc_epx_c3.c | |||
@@ -25,8 +25,8 @@ | |||
25 | #include <linux/reboot.h> | 25 | #include <linux/reboot.h> |
26 | #include <linux/init.h> | 26 | #include <linux/init.h> |
27 | #include <linux/ioport.h> | 27 | #include <linux/ioport.h> |
28 | #include <asm/uaccess.h> | 28 | #include <linux/uaccess.h> |
29 | #include <asm/io.h> | 29 | #include <linux/io.h> |
30 | 30 | ||
31 | #define PFX "epx_c3: " | 31 | #define PFX "epx_c3: " |
32 | static int epx_c3_alive; | 32 | static int epx_c3_alive; |
@@ -100,12 +100,12 @@ static ssize_t epx_c3_write(struct file *file, const char __user *data, | |||
100 | return len; | 100 | return len; |
101 | } | 101 | } |
102 | 102 | ||
103 | static int epx_c3_ioctl(struct inode *inode, struct file *file, | 103 | static long epx_c3_ioctl(struct file *file, unsigned int cmd, |
104 | unsigned int cmd, unsigned long arg) | 104 | unsigned long arg) |
105 | { | 105 | { |
106 | int options, retval = -EINVAL; | 106 | int options, retval = -EINVAL; |
107 | int __user *argp = (void __user *)arg; | 107 | int __user *argp = (void __user *)arg; |
108 | static struct watchdog_info ident = { | 108 | static const struct watchdog_info ident = { |
109 | .options = WDIOF_KEEPALIVEPING | | 109 | .options = WDIOF_KEEPALIVEPING | |
110 | WDIOF_MAGICCLOSE, | 110 | WDIOF_MAGICCLOSE, |
111 | .firmware_version = 0, | 111 | .firmware_version = 0, |
@@ -120,11 +120,6 @@ static int epx_c3_ioctl(struct inode *inode, struct file *file, | |||
120 | case WDIOC_GETSTATUS: | 120 | case WDIOC_GETSTATUS: |
121 | case WDIOC_GETBOOTSTATUS: | 121 | case WDIOC_GETBOOTSTATUS: |
122 | return put_user(0, argp); | 122 | return put_user(0, argp); |
123 | case WDIOC_KEEPALIVE: | ||
124 | epx_c3_pet(); | ||
125 | return 0; | ||
126 | case WDIOC_GETTIMEOUT: | ||
127 | return put_user(WATCHDOG_TIMEOUT, argp); | ||
128 | case WDIOC_SETOPTIONS: | 123 | case WDIOC_SETOPTIONS: |
129 | if (get_user(options, argp)) | 124 | if (get_user(options, argp)) |
130 | return -EFAULT; | 125 | return -EFAULT; |
@@ -140,6 +135,11 @@ static int epx_c3_ioctl(struct inode *inode, struct file *file, | |||
140 | } | 135 | } |
141 | 136 | ||
142 | return retval; | 137 | return retval; |
138 | case WDIOC_KEEPALIVE: | ||
139 | epx_c3_pet(); | ||
140 | return 0; | ||
141 | case WDIOC_GETTIMEOUT: | ||
142 | return put_user(WATCHDOG_TIMEOUT, argp); | ||
143 | default: | 143 | default: |
144 | return -ENOTTY; | 144 | return -ENOTTY; |
145 | } | 145 | } |
@@ -158,7 +158,7 @@ static const struct file_operations epx_c3_fops = { | |||
158 | .owner = THIS_MODULE, | 158 | .owner = THIS_MODULE, |
159 | .llseek = no_llseek, | 159 | .llseek = no_llseek, |
160 | .write = epx_c3_write, | 160 | .write = epx_c3_write, |
161 | .ioctl = epx_c3_ioctl, | 161 | .unlocked_ioctl = epx_c3_ioctl, |
162 | .open = epx_c3_open, | 162 | .open = epx_c3_open, |
163 | .release = epx_c3_release, | 163 | .release = epx_c3_release, |
164 | }; | 164 | }; |
diff --git a/drivers/watchdog/sc1200wdt.c b/drivers/watchdog/sc1200wdt.c index 621ebad56d86..23da3ccd832a 100644 --- a/drivers/watchdog/sc1200wdt.c +++ b/drivers/watchdog/sc1200wdt.c | |||
@@ -196,7 +196,6 @@ static long sc1200wdt_ioctl(struct file *file, unsigned int cmd, | |||
196 | }; | 196 | }; |
197 | 197 | ||
198 | switch (cmd) { | 198 | switch (cmd) { |
199 | |||
200 | case WDIOC_GETSUPPORT: | 199 | case WDIOC_GETSUPPORT: |
201 | if (copy_to_user(argp, &ident, sizeof ident)) | 200 | if (copy_to_user(argp, &ident, sizeof ident)) |
202 | return -EFAULT; | 201 | return -EFAULT; |
@@ -208,24 +207,6 @@ static long sc1200wdt_ioctl(struct file *file, unsigned int cmd, | |||
208 | case WDIOC_GETBOOTSTATUS: | 207 | case WDIOC_GETBOOTSTATUS: |
209 | return put_user(0, p); | 208 | return put_user(0, p); |
210 | 209 | ||
211 | case WDIOC_KEEPALIVE: | ||
212 | sc1200wdt_write_data(WDTO, timeout); | ||
213 | return 0; | ||
214 | |||
215 | case WDIOC_SETTIMEOUT: | ||
216 | if (get_user(new_timeout, p)) | ||
217 | return -EFAULT; | ||
218 | /* the API states this is given in secs */ | ||
219 | new_timeout /= 60; | ||
220 | if (new_timeout < 0 || new_timeout > MAX_TIMEOUT) | ||
221 | return -EINVAL; | ||
222 | timeout = new_timeout; | ||
223 | sc1200wdt_write_data(WDTO, timeout); | ||
224 | /* fall through and return the new timeout */ | ||
225 | |||
226 | case WDIOC_GETTIMEOUT: | ||
227 | return put_user(timeout * 60, p); | ||
228 | |||
229 | case WDIOC_SETOPTIONS: | 210 | case WDIOC_SETOPTIONS: |
230 | { | 211 | { |
231 | int options, retval = -EINVAL; | 212 | int options, retval = -EINVAL; |
@@ -245,6 +226,24 @@ static long sc1200wdt_ioctl(struct file *file, unsigned int cmd, | |||
245 | 226 | ||
246 | return retval; | 227 | return retval; |
247 | } | 228 | } |
229 | case WDIOC_KEEPALIVE: | ||
230 | sc1200wdt_write_data(WDTO, timeout); | ||
231 | return 0; | ||
232 | |||
233 | case WDIOC_SETTIMEOUT: | ||
234 | if (get_user(new_timeout, p)) | ||
235 | return -EFAULT; | ||
236 | /* the API states this is given in secs */ | ||
237 | new_timeout /= 60; | ||
238 | if (new_timeout < 0 || new_timeout > MAX_TIMEOUT) | ||
239 | return -EINVAL; | ||
240 | timeout = new_timeout; | ||
241 | sc1200wdt_write_data(WDTO, timeout); | ||
242 | /* fall through and return the new timeout */ | ||
243 | |||
244 | case WDIOC_GETTIMEOUT: | ||
245 | return put_user(timeout * 60, p); | ||
246 | |||
248 | default: | 247 | default: |
249 | return -ENOTTY; | 248 | return -ENOTTY; |
250 | } | 249 | } |
@@ -280,7 +279,7 @@ static ssize_t sc1200wdt_write(struct file *file, const char __user *data, | |||
280 | for (i = 0; i != len; i++) { | 279 | for (i = 0; i != len; i++) { |
281 | char c; | 280 | char c; |
282 | 281 | ||
283 | if (get_user(c, data+i)) | 282 | if (get_user(c, data + i)) |
284 | return -EFAULT; | 283 | return -EFAULT; |
285 | if (c == 'V') | 284 | if (c == 'V') |
286 | expect_close = 42; | 285 | expect_close = 42; |
diff --git a/drivers/watchdog/sc520_wdt.c b/drivers/watchdog/sc520_wdt.c index 2847324a2be2..a2b6c1067ec5 100644 --- a/drivers/watchdog/sc520_wdt.c +++ b/drivers/watchdog/sc520_wdt.c | |||
@@ -64,9 +64,9 @@ | |||
64 | #include <linux/reboot.h> | 64 | #include <linux/reboot.h> |
65 | #include <linux/init.h> | 65 | #include <linux/init.h> |
66 | #include <linux/jiffies.h> | 66 | #include <linux/jiffies.h> |
67 | #include <linux/io.h> | ||
68 | #include <linux/uaccess.h> | ||
67 | 69 | ||
68 | #include <asm/io.h> | ||
69 | #include <asm/uaccess.h> | ||
70 | #include <asm/system.h> | 70 | #include <asm/system.h> |
71 | 71 | ||
72 | #define OUR_NAME "sc520_wdt" | 72 | #define OUR_NAME "sc520_wdt" |
@@ -91,13 +91,18 @@ | |||
91 | */ | 91 | */ |
92 | 92 | ||
93 | #define WATCHDOG_TIMEOUT 30 /* 30 sec default timeout */ | 93 | #define WATCHDOG_TIMEOUT 30 /* 30 sec default timeout */ |
94 | static int timeout = WATCHDOG_TIMEOUT; /* in seconds, will be multiplied by HZ to get seconds to wait for a ping */ | 94 | /* in seconds, will be multiplied by HZ to get seconds to wait for a ping */ |
95 | static int timeout = WATCHDOG_TIMEOUT; | ||
95 | module_param(timeout, int, 0); | 96 | module_param(timeout, int, 0); |
96 | MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (1<=timeout<=3600, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")"); | 97 | MODULE_PARM_DESC(timeout, |
98 | "Watchdog timeout in seconds. (1 <= timeout <= 3600, default=" | ||
99 | __MODULE_STRING(WATCHDOG_TIMEOUT) ")"); | ||
97 | 100 | ||
98 | static int nowayout = WATCHDOG_NOWAYOUT; | 101 | static int nowayout = WATCHDOG_NOWAYOUT; |
99 | module_param(nowayout, int, 0); | 102 | module_param(nowayout, int, 0); |
100 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 103 | MODULE_PARM_DESC(nowayout, |
104 | "Watchdog cannot be stopped once started (default=" | ||
105 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
101 | 106 | ||
102 | /* | 107 | /* |
103 | * AMD Elan SC520 - Watchdog Timer Registers | 108 | * AMD Elan SC520 - Watchdog Timer Registers |
@@ -136,8 +141,7 @@ static void wdt_timer_ping(unsigned long data) | |||
136 | /* If we got a heartbeat pulse within the WDT_US_INTERVAL | 141 | /* If we got a heartbeat pulse within the WDT_US_INTERVAL |
137 | * we agree to ping the WDT | 142 | * we agree to ping the WDT |
138 | */ | 143 | */ |
139 | if(time_before(jiffies, next_heartbeat)) | 144 | if (time_before(jiffies, next_heartbeat)) { |
140 | { | ||
141 | /* Ping the WDT */ | 145 | /* Ping the WDT */ |
142 | spin_lock(&wdt_spinlock); | 146 | spin_lock(&wdt_spinlock); |
143 | writew(0xAAAA, wdtmrctl); | 147 | writew(0xAAAA, wdtmrctl); |
@@ -146,9 +150,9 @@ static void wdt_timer_ping(unsigned long data) | |||
146 | 150 | ||
147 | /* Re-set the timer interval */ | 151 | /* Re-set the timer interval */ |
148 | mod_timer(&timer, jiffies + WDT_INTERVAL); | 152 | mod_timer(&timer, jiffies + WDT_INTERVAL); |
149 | } else { | 153 | } else |
150 | printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n"); | 154 | printk(KERN_WARNING PFX |
151 | } | 155 | "Heartbeat lost! Will not ping the watchdog\n"); |
152 | } | 156 | } |
153 | 157 | ||
154 | /* | 158 | /* |
@@ -162,7 +166,7 @@ static void wdt_config(int writeval) | |||
162 | 166 | ||
163 | /* buy some time (ping) */ | 167 | /* buy some time (ping) */ |
164 | spin_lock_irqsave(&wdt_spinlock, flags); | 168 | spin_lock_irqsave(&wdt_spinlock, flags); |
165 | dummy=readw(wdtmrctl); /* ensure write synchronization */ | 169 | dummy = readw(wdtmrctl); /* ensure write synchronization */ |
166 | writew(0xAAAA, wdtmrctl); | 170 | writew(0xAAAA, wdtmrctl); |
167 | writew(0x5555, wdtmrctl); | 171 | writew(0x5555, wdtmrctl); |
168 | /* unlock WDT = make WDT configuration register writable one time */ | 172 | /* unlock WDT = make WDT configuration register writable one time */ |
@@ -219,10 +223,11 @@ static int wdt_set_heartbeat(int t) | |||
219 | * /dev/watchdog handling | 223 | * /dev/watchdog handling |
220 | */ | 224 | */ |
221 | 225 | ||
222 | static ssize_t fop_write(struct file * file, const char __user * buf, size_t count, loff_t * ppos) | 226 | static ssize_t fop_write(struct file *file, const char __user *buf, |
227 | size_t count, loff_t *ppos) | ||
223 | { | 228 | { |
224 | /* See if we got the magic character 'V' and reload the timer */ | 229 | /* See if we got the magic character 'V' and reload the timer */ |
225 | if(count) { | 230 | if (count) { |
226 | if (!nowayout) { | 231 | if (!nowayout) { |
227 | size_t ofs; | 232 | size_t ofs; |
228 | 233 | ||
@@ -231,25 +236,26 @@ static ssize_t fop_write(struct file * file, const char __user * buf, size_t cou | |||
231 | wdt_expect_close = 0; | 236 | wdt_expect_close = 0; |
232 | 237 | ||
233 | /* now scan */ | 238 | /* now scan */ |
234 | for(ofs = 0; ofs != count; ofs++) { | 239 | for (ofs = 0; ofs != count; ofs++) { |
235 | char c; | 240 | char c; |
236 | if (get_user(c, buf + ofs)) | 241 | if (get_user(c, buf + ofs)) |
237 | return -EFAULT; | 242 | return -EFAULT; |
238 | if(c == 'V') | 243 | if (c == 'V') |
239 | wdt_expect_close = 42; | 244 | wdt_expect_close = 42; |
240 | } | 245 | } |
241 | } | 246 | } |
242 | 247 | ||
243 | /* Well, anyhow someone wrote to us, we should return that favour */ | 248 | /* Well, anyhow someone wrote to us, we should |
249 | return that favour */ | ||
244 | wdt_keepalive(); | 250 | wdt_keepalive(); |
245 | } | 251 | } |
246 | return count; | 252 | return count; |
247 | } | 253 | } |
248 | 254 | ||
249 | static int fop_open(struct inode * inode, struct file * file) | 255 | static int fop_open(struct inode *inode, struct file *file) |
250 | { | 256 | { |
251 | /* Just in case we're already talking to someone... */ | 257 | /* Just in case we're already talking to someone... */ |
252 | if(test_and_set_bit(0, &wdt_is_open)) | 258 | if (test_and_set_bit(0, &wdt_is_open)) |
253 | return -EBUSY; | 259 | return -EBUSY; |
254 | if (nowayout) | 260 | if (nowayout) |
255 | __module_get(THIS_MODULE); | 261 | __module_get(THIS_MODULE); |
@@ -259,12 +265,13 @@ static int fop_open(struct inode * inode, struct file * file) | |||
259 | return nonseekable_open(inode, file); | 265 | return nonseekable_open(inode, file); |
260 | } | 266 | } |
261 | 267 | ||
262 | static int fop_close(struct inode * inode, struct file * file) | 268 | static int fop_close(struct inode *inode, struct file *file) |
263 | { | 269 | { |
264 | if(wdt_expect_close == 42) { | 270 | if (wdt_expect_close == 42) |
265 | wdt_turnoff(); | 271 | wdt_turnoff(); |
266 | } else { | 272 | else { |
267 | printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); | 273 | printk(KERN_CRIT PFX |
274 | "Unexpected close, not stopping watchdog!\n"); | ||
268 | wdt_keepalive(); | 275 | wdt_keepalive(); |
269 | } | 276 | } |
270 | clear_bit(0, &wdt_is_open); | 277 | clear_bit(0, &wdt_is_open); |
@@ -272,63 +279,62 @@ static int fop_close(struct inode * inode, struct file * file) | |||
272 | return 0; | 279 | return 0; |
273 | } | 280 | } |
274 | 281 | ||
275 | static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | 282 | static long fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
276 | unsigned long arg) | ||
277 | { | 283 | { |
278 | void __user *argp = (void __user *)arg; | 284 | void __user *argp = (void __user *)arg; |
279 | int __user *p = argp; | 285 | int __user *p = argp; |
280 | static struct watchdog_info ident = { | 286 | static const struct watchdog_info ident = { |
281 | .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, | 287 | .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
288 | | WDIOF_MAGICCLOSE, | ||
282 | .firmware_version = 1, | 289 | .firmware_version = 1, |
283 | .identity = "SC520", | 290 | .identity = "SC520", |
284 | }; | 291 | }; |
285 | 292 | ||
286 | switch(cmd) | 293 | switch (cmd) { |
294 | case WDIOC_GETSUPPORT: | ||
295 | return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; | ||
296 | case WDIOC_GETSTATUS: | ||
297 | case WDIOC_GETBOOTSTATUS: | ||
298 | return put_user(0, p); | ||
299 | case WDIOC_SETOPTIONS: | ||
287 | { | 300 | { |
288 | default: | 301 | int new_options, retval = -EINVAL; |
289 | return -ENOTTY; | ||
290 | case WDIOC_GETSUPPORT: | ||
291 | return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0; | ||
292 | case WDIOC_GETSTATUS: | ||
293 | case WDIOC_GETBOOTSTATUS: | ||
294 | return put_user(0, p); | ||
295 | case WDIOC_KEEPALIVE: | ||
296 | wdt_keepalive(); | ||
297 | return 0; | ||
298 | case WDIOC_SETOPTIONS: | ||
299 | { | ||
300 | int new_options, retval = -EINVAL; | ||
301 | |||
302 | if(get_user(new_options, p)) | ||
303 | return -EFAULT; | ||
304 | |||
305 | if(new_options & WDIOS_DISABLECARD) { | ||
306 | wdt_turnoff(); | ||
307 | retval = 0; | ||
308 | } | ||
309 | 302 | ||
310 | if(new_options & WDIOS_ENABLECARD) { | 303 | if (get_user(new_options, p)) |
311 | wdt_startup(); | 304 | return -EFAULT; |
312 | retval = 0; | ||
313 | } | ||
314 | 305 | ||
315 | return retval; | 306 | if (new_options & WDIOS_DISABLECARD) { |
307 | wdt_turnoff(); | ||
308 | retval = 0; | ||
316 | } | 309 | } |
317 | case WDIOC_SETTIMEOUT: | ||
318 | { | ||
319 | int new_timeout; | ||
320 | 310 | ||
321 | if(get_user(new_timeout, p)) | 311 | if (new_options & WDIOS_ENABLECARD) { |
322 | return -EFAULT; | 312 | wdt_startup(); |
313 | retval = 0; | ||
314 | } | ||
323 | 315 | ||
324 | if(wdt_set_heartbeat(new_timeout)) | 316 | return retval; |
325 | return -EINVAL; | 317 | } |
318 | case WDIOC_KEEPALIVE: | ||
319 | wdt_keepalive(); | ||
320 | return 0; | ||
321 | case WDIOC_SETTIMEOUT: | ||
322 | { | ||
323 | int new_timeout; | ||
326 | 324 | ||
327 | wdt_keepalive(); | 325 | if (get_user(new_timeout, p)) |
328 | /* Fall through */ | 326 | return -EFAULT; |
329 | } | 327 | |
330 | case WDIOC_GETTIMEOUT: | 328 | if (wdt_set_heartbeat(new_timeout)) |
331 | return put_user(timeout, p); | 329 | return -EINVAL; |
330 | |||
331 | wdt_keepalive(); | ||
332 | /* Fall through */ | ||
333 | } | ||
334 | case WDIOC_GETTIMEOUT: | ||
335 | return put_user(timeout, p); | ||
336 | default: | ||
337 | return -ENOTTY; | ||
332 | } | 338 | } |
333 | } | 339 | } |
334 | 340 | ||
@@ -338,7 +344,7 @@ static const struct file_operations wdt_fops = { | |||
338 | .write = fop_write, | 344 | .write = fop_write, |
339 | .open = fop_open, | 345 | .open = fop_open, |
340 | .release = fop_close, | 346 | .release = fop_close, |
341 | .ioctl = fop_ioctl, | 347 | .unlocked_ioctl = fop_ioctl, |
342 | }; | 348 | }; |
343 | 349 | ||
344 | static struct miscdevice wdt_miscdev = { | 350 | static struct miscdevice wdt_miscdev = { |
@@ -354,7 +360,7 @@ static struct miscdevice wdt_miscdev = { | |||
354 | static int wdt_notify_sys(struct notifier_block *this, unsigned long code, | 360 | static int wdt_notify_sys(struct notifier_block *this, unsigned long code, |
355 | void *unused) | 361 | void *unused) |
356 | { | 362 | { |
357 | if(code==SYS_DOWN || code==SYS_HALT) | 363 | if (code == SYS_DOWN || code == SYS_HALT) |
358 | wdt_turnoff(); | 364 | wdt_turnoff(); |
359 | return NOTIFY_DONE; | 365 | return NOTIFY_DONE; |
360 | } | 366 | } |
@@ -383,11 +389,13 @@ static int __init sc520_wdt_init(void) | |||
383 | { | 389 | { |
384 | int rc = -EBUSY; | 390 | int rc = -EBUSY; |
385 | 391 | ||
386 | /* Check that the timeout value is within it's range ; if not reset to the default */ | 392 | /* Check that the timeout value is within it's range ; |
393 | if not reset to the default */ | ||
387 | if (wdt_set_heartbeat(timeout)) { | 394 | if (wdt_set_heartbeat(timeout)) { |
388 | wdt_set_heartbeat(WATCHDOG_TIMEOUT); | 395 | wdt_set_heartbeat(WATCHDOG_TIMEOUT); |
389 | printk(KERN_INFO PFX "timeout value must be 1<=timeout<=3600, using %d\n", | 396 | printk(KERN_INFO PFX |
390 | WATCHDOG_TIMEOUT); | 397 | "timeout value must be 1 <= timeout <= 3600, using %d\n", |
398 | WATCHDOG_TIMEOUT); | ||
391 | } | 399 | } |
392 | 400 | ||
393 | wdtmrctl = ioremap((unsigned long)(MMCR_BASE + OFFS_WDTMRCTL), 2); | 401 | wdtmrctl = ioremap((unsigned long)(MMCR_BASE + OFFS_WDTMRCTL), 2); |
@@ -399,20 +407,22 @@ static int __init sc520_wdt_init(void) | |||
399 | 407 | ||
400 | rc = register_reboot_notifier(&wdt_notifier); | 408 | rc = register_reboot_notifier(&wdt_notifier); |
401 | if (rc) { | 409 | if (rc) { |
402 | printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", | 410 | printk(KERN_ERR PFX |
403 | rc); | 411 | "cannot register reboot notifier (err=%d)\n", rc); |
404 | goto err_out_ioremap; | 412 | goto err_out_ioremap; |
405 | } | 413 | } |
406 | 414 | ||
407 | rc = misc_register(&wdt_miscdev); | 415 | rc = misc_register(&wdt_miscdev); |
408 | if (rc) { | 416 | if (rc) { |
409 | printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", | 417 | printk(KERN_ERR PFX |
410 | WATCHDOG_MINOR, rc); | 418 | "cannot register miscdev on minor=%d (err=%d)\n", |
419 | WATCHDOG_MINOR, rc); | ||
411 | goto err_out_notifier; | 420 | goto err_out_notifier; |
412 | } | 421 | } |
413 | 422 | ||
414 | printk(KERN_INFO PFX "WDT driver for SC520 initialised. timeout=%d sec (nowayout=%d)\n", | 423 | printk(KERN_INFO PFX |
415 | timeout,nowayout); | 424 | "WDT driver for SC520 initialised. timeout=%d sec (nowayout=%d)\n", |
425 | timeout, nowayout); | ||
416 | 426 | ||
417 | return 0; | 427 | return 0; |
418 | 428 | ||
diff --git a/drivers/watchdog/scx200_wdt.c b/drivers/watchdog/scx200_wdt.c index d55882bca319..9e19a10a5bb9 100644 --- a/drivers/watchdog/scx200_wdt.c +++ b/drivers/watchdog/scx200_wdt.c | |||
@@ -27,9 +27,8 @@ | |||
27 | #include <linux/fs.h> | 27 | #include <linux/fs.h> |
28 | #include <linux/ioport.h> | 28 | #include <linux/ioport.h> |
29 | #include <linux/scx200.h> | 29 | #include <linux/scx200.h> |
30 | 30 | #include <linux/uaccess.h> | |
31 | #include <asm/uaccess.h> | 31 | #include <linux/io.h> |
32 | #include <asm/io.h> | ||
33 | 32 | ||
34 | #define NAME "scx200_wdt" | 33 | #define NAME "scx200_wdt" |
35 | 34 | ||
@@ -47,8 +46,9 @@ module_param(nowayout, int, 0); | |||
47 | MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close"); | 46 | MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close"); |
48 | 47 | ||
49 | static u16 wdto_restart; | 48 | static u16 wdto_restart; |
50 | static struct semaphore open_semaphore; | ||
51 | static char expect_close; | 49 | static char expect_close; |
50 | static unsigned long open_lock; | ||
51 | static DEFINE_SPINLOCK(scx_lock); | ||
52 | 52 | ||
53 | /* Bits of the WDCNFG register */ | 53 | /* Bits of the WDCNFG register */ |
54 | #define W_ENABLE 0x00fa /* Enable watchdog */ | 54 | #define W_ENABLE 0x00fa /* Enable watchdog */ |
@@ -59,7 +59,9 @@ static char expect_close; | |||
59 | 59 | ||
60 | static void scx200_wdt_ping(void) | 60 | static void scx200_wdt_ping(void) |
61 | { | 61 | { |
62 | spin_lock(&scx_lock); | ||
62 | outw(wdto_restart, scx200_cb_base + SCx200_WDT_WDTO); | 63 | outw(wdto_restart, scx200_cb_base + SCx200_WDT_WDTO); |
64 | spin_unlock(&scx_lock); | ||
63 | } | 65 | } |
64 | 66 | ||
65 | static void scx200_wdt_update_margin(void) | 67 | static void scx200_wdt_update_margin(void) |
@@ -73,9 +75,11 @@ static void scx200_wdt_enable(void) | |||
73 | printk(KERN_DEBUG NAME ": enabling watchdog timer, wdto_restart = %d\n", | 75 | printk(KERN_DEBUG NAME ": enabling watchdog timer, wdto_restart = %d\n", |
74 | wdto_restart); | 76 | wdto_restart); |
75 | 77 | ||
78 | spin_lock(&scx_lock); | ||
76 | outw(0, scx200_cb_base + SCx200_WDT_WDTO); | 79 | outw(0, scx200_cb_base + SCx200_WDT_WDTO); |
77 | outb(SCx200_WDT_WDSTS_WDOVF, scx200_cb_base + SCx200_WDT_WDSTS); | 80 | outb(SCx200_WDT_WDSTS_WDOVF, scx200_cb_base + SCx200_WDT_WDSTS); |
78 | outw(W_ENABLE, scx200_cb_base + SCx200_WDT_WDCNFG); | 81 | outw(W_ENABLE, scx200_cb_base + SCx200_WDT_WDCNFG); |
82 | spin_unlock(&scx_lock); | ||
79 | 83 | ||
80 | scx200_wdt_ping(); | 84 | scx200_wdt_ping(); |
81 | } | 85 | } |
@@ -84,15 +88,17 @@ static void scx200_wdt_disable(void) | |||
84 | { | 88 | { |
85 | printk(KERN_DEBUG NAME ": disabling watchdog timer\n"); | 89 | printk(KERN_DEBUG NAME ": disabling watchdog timer\n"); |
86 | 90 | ||
91 | spin_lock(&scx_lock); | ||
87 | outw(0, scx200_cb_base + SCx200_WDT_WDTO); | 92 | outw(0, scx200_cb_base + SCx200_WDT_WDTO); |
88 | outb(SCx200_WDT_WDSTS_WDOVF, scx200_cb_base + SCx200_WDT_WDSTS); | 93 | outb(SCx200_WDT_WDSTS_WDOVF, scx200_cb_base + SCx200_WDT_WDSTS); |
89 | outw(W_DISABLE, scx200_cb_base + SCx200_WDT_WDCNFG); | 94 | outw(W_DISABLE, scx200_cb_base + SCx200_WDT_WDCNFG); |
95 | spin_unlock(&scx_lock); | ||
90 | } | 96 | } |
91 | 97 | ||
92 | static int scx200_wdt_open(struct inode *inode, struct file *file) | 98 | static int scx200_wdt_open(struct inode *inode, struct file *file) |
93 | { | 99 | { |
94 | /* only allow one at a time */ | 100 | /* only allow one at a time */ |
95 | if (down_trylock(&open_semaphore)) | 101 | if (test_and_set_bit(0, &open_lock)) |
96 | return -EBUSY; | 102 | return -EBUSY; |
97 | scx200_wdt_enable(); | 103 | scx200_wdt_enable(); |
98 | 104 | ||
@@ -101,13 +107,12 @@ static int scx200_wdt_open(struct inode *inode, struct file *file) | |||
101 | 107 | ||
102 | static int scx200_wdt_release(struct inode *inode, struct file *file) | 108 | static int scx200_wdt_release(struct inode *inode, struct file *file) |
103 | { | 109 | { |
104 | if (expect_close != 42) { | 110 | if (expect_close != 42) |
105 | printk(KERN_WARNING NAME ": watchdog device closed unexpectedly, will not disable the watchdog timer\n"); | 111 | printk(KERN_WARNING NAME ": watchdog device closed unexpectedly, will not disable the watchdog timer\n"); |
106 | } else if (!nowayout) { | 112 | else if (!nowayout) |
107 | scx200_wdt_disable(); | 113 | scx200_wdt_disable(); |
108 | } | ||
109 | expect_close = 0; | 114 | expect_close = 0; |
110 | up(&open_semaphore); | 115 | clear_bit(0, &open_lock); |
111 | 116 | ||
112 | return 0; | 117 | return 0; |
113 | } | 118 | } |
@@ -122,8 +127,7 @@ static int scx200_wdt_notify_sys(struct notifier_block *this, | |||
122 | return NOTIFY_DONE; | 127 | return NOTIFY_DONE; |
123 | } | 128 | } |
124 | 129 | ||
125 | static struct notifier_block scx200_wdt_notifier = | 130 | static struct notifier_block scx200_wdt_notifier = { |
126 | { | ||
127 | .notifier_call = scx200_wdt_notify_sys, | 131 | .notifier_call = scx200_wdt_notify_sys, |
128 | }; | 132 | }; |
129 | 133 | ||
@@ -131,8 +135,7 @@ static ssize_t scx200_wdt_write(struct file *file, const char __user *data, | |||
131 | size_t len, loff_t *ppos) | 135 | size_t len, loff_t *ppos) |
132 | { | 136 | { |
133 | /* check for a magic close character */ | 137 | /* check for a magic close character */ |
134 | if (len) | 138 | if (len) { |
135 | { | ||
136 | size_t i; | 139 | size_t i; |
137 | 140 | ||
138 | scx200_wdt_ping(); | 141 | scx200_wdt_ping(); |
@@ -140,7 +143,7 @@ static ssize_t scx200_wdt_write(struct file *file, const char __user *data, | |||
140 | expect_close = 0; | 143 | expect_close = 0; |
141 | for (i = 0; i < len; ++i) { | 144 | for (i = 0; i < len; ++i) { |
142 | char c; | 145 | char c; |
143 | if (get_user(c, data+i)) | 146 | if (get_user(c, data + i)) |
144 | return -EFAULT; | 147 | return -EFAULT; |
145 | if (c == 'V') | 148 | if (c == 'V') |
146 | expect_close = 42; | 149 | expect_close = 42; |
@@ -152,23 +155,21 @@ static ssize_t scx200_wdt_write(struct file *file, const char __user *data, | |||
152 | return 0; | 155 | return 0; |
153 | } | 156 | } |
154 | 157 | ||
155 | static int scx200_wdt_ioctl(struct inode *inode, struct file *file, | 158 | static long scx200_wdt_ioctl(struct file *file, unsigned int cmd, |
156 | unsigned int cmd, unsigned long arg) | 159 | unsigned long arg) |
157 | { | 160 | { |
158 | void __user *argp = (void __user *)arg; | 161 | void __user *argp = (void __user *)arg; |
159 | int __user *p = argp; | 162 | int __user *p = argp; |
160 | static struct watchdog_info ident = { | 163 | static const struct watchdog_info ident = { |
161 | .identity = "NatSemi SCx200 Watchdog", | 164 | .identity = "NatSemi SCx200 Watchdog", |
162 | .firmware_version = 1, | 165 | .firmware_version = 1, |
163 | .options = (WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING), | 166 | .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, |
164 | }; | 167 | }; |
165 | int new_margin; | 168 | int new_margin; |
166 | 169 | ||
167 | switch (cmd) { | 170 | switch (cmd) { |
168 | default: | ||
169 | return -ENOTTY; | ||
170 | case WDIOC_GETSUPPORT: | 171 | case WDIOC_GETSUPPORT: |
171 | if(copy_to_user(argp, &ident, sizeof(ident))) | 172 | if (copy_to_user(argp, &ident, sizeof(ident))) |
172 | return -EFAULT; | 173 | return -EFAULT; |
173 | return 0; | 174 | return 0; |
174 | case WDIOC_GETSTATUS: | 175 | case WDIOC_GETSTATUS: |
@@ -191,22 +192,24 @@ static int scx200_wdt_ioctl(struct inode *inode, struct file *file, | |||
191 | if (put_user(margin, p)) | 192 | if (put_user(margin, p)) |
192 | return -EFAULT; | 193 | return -EFAULT; |
193 | return 0; | 194 | return 0; |
195 | default: | ||
196 | return -ENOTTY; | ||
194 | } | 197 | } |
195 | } | 198 | } |
196 | 199 | ||
197 | static const struct file_operations scx200_wdt_fops = { | 200 | static const struct file_operations scx200_wdt_fops = { |
198 | .owner = THIS_MODULE, | 201 | .owner = THIS_MODULE, |
199 | .llseek = no_llseek, | 202 | .llseek = no_llseek, |
200 | .write = scx200_wdt_write, | 203 | .write = scx200_wdt_write, |
201 | .ioctl = scx200_wdt_ioctl, | 204 | .unlocked_ioctl = scx200_wdt_ioctl, |
202 | .open = scx200_wdt_open, | 205 | .open = scx200_wdt_open, |
203 | .release = scx200_wdt_release, | 206 | .release = scx200_wdt_release, |
204 | }; | 207 | }; |
205 | 208 | ||
206 | static struct miscdevice scx200_wdt_miscdev = { | 209 | static struct miscdevice scx200_wdt_miscdev = { |
207 | .minor = WATCHDOG_MINOR, | 210 | .minor = WATCHDOG_MINOR, |
208 | .name = "watchdog", | 211 | .name = "watchdog", |
209 | .fops = &scx200_wdt_fops, | 212 | .fops = &scx200_wdt_fops, |
210 | }; | 213 | }; |
211 | 214 | ||
212 | static int __init scx200_wdt_init(void) | 215 | static int __init scx200_wdt_init(void) |
@@ -229,8 +232,6 @@ static int __init scx200_wdt_init(void) | |||
229 | scx200_wdt_update_margin(); | 232 | scx200_wdt_update_margin(); |
230 | scx200_wdt_disable(); | 233 | scx200_wdt_disable(); |
231 | 234 | ||
232 | sema_init(&open_semaphore, 1); | ||
233 | |||
234 | r = register_reboot_notifier(&scx200_wdt_notifier); | 235 | r = register_reboot_notifier(&scx200_wdt_notifier); |
235 | if (r) { | 236 | if (r) { |
236 | printk(KERN_ERR NAME ": unable to register reboot notifier"); | 237 | printk(KERN_ERR NAME ": unable to register reboot notifier"); |
@@ -263,7 +264,7 @@ module_exit(scx200_wdt_cleanup); | |||
263 | 264 | ||
264 | /* | 265 | /* |
265 | Local variables: | 266 | Local variables: |
266 | compile-command: "make -k -C ../.. SUBDIRS=drivers/char modules" | 267 | compile-command: "make -k -C ../.. SUBDIRS=drivers/char modules" |
267 | c-basic-offset: 8 | 268 | c-basic-offset: 8 |
268 | End: | 269 | End: |
269 | */ | 270 | */ |
diff --git a/drivers/watchdog/shwdt.c b/drivers/watchdog/shwdt.c index 1277f7e9cc54..824125adf90a 100644 --- a/drivers/watchdog/shwdt.c +++ b/drivers/watchdog/shwdt.c | |||
@@ -28,9 +28,9 @@ | |||
28 | #include <linux/ioport.h> | 28 | #include <linux/ioport.h> |
29 | #include <linux/fs.h> | 29 | #include <linux/fs.h> |
30 | #include <linux/mm.h> | 30 | #include <linux/mm.h> |
31 | #include <asm/io.h> | 31 | #include <linux/io.h> |
32 | #include <asm/uaccess.h> | 32 | #include <linux/uaccess.h> |
33 | #include <asm/watchdog.h> | 33 | #include <linux/watchdog.h> |
34 | 34 | ||
35 | #define PFX "shwdt: " | 35 | #define PFX "shwdt: " |
36 | 36 | ||
@@ -72,6 +72,7 @@ static struct watchdog_info sh_wdt_info; | |||
72 | static char shwdt_expect_close; | 72 | static char shwdt_expect_close; |
73 | static DEFINE_TIMER(timer, sh_wdt_ping, 0, 0); | 73 | static DEFINE_TIMER(timer, sh_wdt_ping, 0, 0); |
74 | static unsigned long next_heartbeat; | 74 | static unsigned long next_heartbeat; |
75 | static DEFINE_SPINLOCK(shwdt_lock); | ||
75 | 76 | ||
76 | #define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat */ | 77 | #define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat */ |
77 | static int heartbeat = WATCHDOG_HEARTBEAT; /* in seconds */ | 78 | static int heartbeat = WATCHDOG_HEARTBEAT; /* in seconds */ |
@@ -86,6 +87,9 @@ static int nowayout = WATCHDOG_NOWAYOUT; | |||
86 | static void sh_wdt_start(void) | 87 | static void sh_wdt_start(void) |
87 | { | 88 | { |
88 | __u8 csr; | 89 | __u8 csr; |
90 | unsigned long flags; | ||
91 | |||
92 | spin_lock_irqsave(&wdt_lock, flags); | ||
89 | 93 | ||
90 | next_heartbeat = jiffies + (heartbeat * HZ); | 94 | next_heartbeat = jiffies + (heartbeat * HZ); |
91 | mod_timer(&timer, next_ping_period(clock_division_ratio)); | 95 | mod_timer(&timer, next_ping_period(clock_division_ratio)); |
@@ -123,6 +127,7 @@ static void sh_wdt_start(void) | |||
123 | csr &= ~RSTCSR_RSTS; | 127 | csr &= ~RSTCSR_RSTS; |
124 | sh_wdt_write_rstcsr(csr); | 128 | sh_wdt_write_rstcsr(csr); |
125 | #endif | 129 | #endif |
130 | spin_unlock_irqrestore(&wdt_lock, flags); | ||
126 | } | 131 | } |
127 | 132 | ||
128 | /** | 133 | /** |
@@ -132,12 +137,16 @@ static void sh_wdt_start(void) | |||
132 | static void sh_wdt_stop(void) | 137 | static void sh_wdt_stop(void) |
133 | { | 138 | { |
134 | __u8 csr; | 139 | __u8 csr; |
140 | unsigned long flags; | ||
141 | |||
142 | spin_lock_irqsave(&wdt_lock, flags); | ||
135 | 143 | ||
136 | del_timer(&timer); | 144 | del_timer(&timer); |
137 | 145 | ||
138 | csr = sh_wdt_read_csr(); | 146 | csr = sh_wdt_read_csr(); |
139 | csr &= ~WTCSR_TME; | 147 | csr &= ~WTCSR_TME; |
140 | sh_wdt_write_csr(csr); | 148 | sh_wdt_write_csr(csr); |
149 | spin_unlock_irqrestore(&wdt_lock, flags); | ||
141 | } | 150 | } |
142 | 151 | ||
143 | /** | 152 | /** |
@@ -146,7 +155,11 @@ static void sh_wdt_stop(void) | |||
146 | */ | 155 | */ |
147 | static inline void sh_wdt_keepalive(void) | 156 | static inline void sh_wdt_keepalive(void) |
148 | { | 157 | { |
158 | unsigned long flags; | ||
159 | |||
160 | spin_lock_irqsave(&wdt_lock, flags); | ||
149 | next_heartbeat = jiffies + (heartbeat * HZ); | 161 | next_heartbeat = jiffies + (heartbeat * HZ); |
162 | spin_unlock_irqrestore(&wdt_lock, flags); | ||
150 | } | 163 | } |
151 | 164 | ||
152 | /** | 165 | /** |
@@ -155,10 +168,14 @@ static inline void sh_wdt_keepalive(void) | |||
155 | */ | 168 | */ |
156 | static int sh_wdt_set_heartbeat(int t) | 169 | static int sh_wdt_set_heartbeat(int t) |
157 | { | 170 | { |
158 | if (unlikely((t < 1) || (t > 3600))) /* arbitrary upper limit */ | 171 | unsigned long flags; |
172 | |||
173 | if (unlikely(t < 1 || t > 3600)) /* arbitrary upper limit */ | ||
159 | return -EINVAL; | 174 | return -EINVAL; |
160 | 175 | ||
176 | spin_lock_irqsave(&wdt_lock, flags); | ||
161 | heartbeat = t; | 177 | heartbeat = t; |
178 | spin_unlock_irqrestore(&wdt_lock, flags); | ||
162 | return 0; | 179 | return 0; |
163 | } | 180 | } |
164 | 181 | ||
@@ -170,6 +187,9 @@ static int sh_wdt_set_heartbeat(int t) | |||
170 | */ | 187 | */ |
171 | static void sh_wdt_ping(unsigned long data) | 188 | static void sh_wdt_ping(unsigned long data) |
172 | { | 189 | { |
190 | unsigned long flags; | ||
191 | |||
192 | spin_lock_irqsave(&wdt_lock, flags); | ||
173 | if (time_before(jiffies, next_heartbeat)) { | 193 | if (time_before(jiffies, next_heartbeat)) { |
174 | __u8 csr; | 194 | __u8 csr; |
175 | 195 | ||
@@ -183,6 +203,7 @@ static void sh_wdt_ping(unsigned long data) | |||
183 | } else | 203 | } else |
184 | printk(KERN_WARNING PFX "Heartbeat lost! Will not ping " | 204 | printk(KERN_WARNING PFX "Heartbeat lost! Will not ping " |
185 | "the watchdog\n"); | 205 | "the watchdog\n"); |
206 | spin_unlock_irqrestore(&wdt_lock, flags); | ||
186 | } | 207 | } |
187 | 208 | ||
188 | /** | 209 | /** |
@@ -310,7 +331,6 @@ static int sh_wdt_mmap(struct file *file, struct vm_area_struct *vma) | |||
310 | 331 | ||
311 | /** | 332 | /** |
312 | * sh_wdt_ioctl - Query Device | 333 | * sh_wdt_ioctl - Query Device |
313 | * @inode: inode of device | ||
314 | * @file: file handle of device | 334 | * @file: file handle of device |
315 | * @cmd: watchdog command | 335 | * @cmd: watchdog command |
316 | * @arg: argument | 336 | * @arg: argument |
@@ -318,53 +338,51 @@ static int sh_wdt_mmap(struct file *file, struct vm_area_struct *vma) | |||
318 | * Query basic information from the device or ping it, as outlined by the | 338 | * Query basic information from the device or ping it, as outlined by the |
319 | * watchdog API. | 339 | * watchdog API. |
320 | */ | 340 | */ |
321 | static int sh_wdt_ioctl(struct inode *inode, struct file *file, | 341 | static long sh_wdt_ioctl(struct file *file, unsigned int cmd, |
322 | unsigned int cmd, unsigned long arg) | 342 | unsigned long arg) |
323 | { | 343 | { |
324 | int new_heartbeat; | 344 | int new_heartbeat; |
325 | int options, retval = -EINVAL; | 345 | int options, retval = -EINVAL; |
326 | 346 | ||
327 | switch (cmd) { | 347 | switch (cmd) { |
328 | case WDIOC_GETSUPPORT: | 348 | case WDIOC_GETSUPPORT: |
329 | return copy_to_user((struct watchdog_info *)arg, | 349 | return copy_to_user((struct watchdog_info *)arg, |
330 | &sh_wdt_info, | 350 | &sh_wdt_info, sizeof(sh_wdt_info)) ? -EFAULT : 0; |
331 | sizeof(sh_wdt_info)) ? -EFAULT : 0; | 351 | case WDIOC_GETSTATUS: |
332 | case WDIOC_GETSTATUS: | 352 | case WDIOC_GETBOOTSTATUS: |
333 | case WDIOC_GETBOOTSTATUS: | 353 | return put_user(0, (int *)arg); |
334 | return put_user(0, (int *)arg); | 354 | case WDIOC_SETOPTIONS: |
335 | case WDIOC_KEEPALIVE: | 355 | if (get_user(options, (int *)arg)) |
336 | sh_wdt_keepalive(); | 356 | return -EFAULT; |
337 | return 0; | 357 | |
338 | case WDIOC_SETTIMEOUT: | 358 | if (options & WDIOS_DISABLECARD) { |
339 | if (get_user(new_heartbeat, (int *)arg)) | 359 | sh_wdt_stop(); |
340 | return -EFAULT; | 360 | retval = 0; |
341 | 361 | } | |
342 | if (sh_wdt_set_heartbeat(new_heartbeat)) | ||
343 | return -EINVAL; | ||
344 | |||
345 | sh_wdt_keepalive(); | ||
346 | /* Fall */ | ||
347 | case WDIOC_GETTIMEOUT: | ||
348 | return put_user(heartbeat, (int *)arg); | ||
349 | case WDIOC_SETOPTIONS: | ||
350 | if (get_user(options, (int *)arg)) | ||
351 | return -EFAULT; | ||
352 | |||
353 | if (options & WDIOS_DISABLECARD) { | ||
354 | sh_wdt_stop(); | ||
355 | retval = 0; | ||
356 | } | ||
357 | 362 | ||
358 | if (options & WDIOS_ENABLECARD) { | 363 | if (options & WDIOS_ENABLECARD) { |
359 | sh_wdt_start(); | 364 | sh_wdt_start(); |
360 | retval = 0; | 365 | retval = 0; |
361 | } | 366 | } |
362 | 367 | ||
363 | return retval; | 368 | return retval; |
364 | default: | 369 | case WDIOC_KEEPALIVE: |
365 | return -ENOTTY; | 370 | sh_wdt_keepalive(); |
366 | } | 371 | return 0; |
372 | case WDIOC_SETTIMEOUT: | ||
373 | if (get_user(new_heartbeat, (int *)arg)) | ||
374 | return -EFAULT; | ||
375 | |||
376 | if (sh_wdt_set_heartbeat(new_heartbeat)) | ||
377 | return -EINVAL; | ||
367 | 378 | ||
379 | sh_wdt_keepalive(); | ||
380 | /* Fall */ | ||
381 | case WDIOC_GETTIMEOUT: | ||
382 | return put_user(heartbeat, (int *)arg); | ||
383 | default: | ||
384 | return -ENOTTY; | ||
385 | } | ||
368 | return 0; | 386 | return 0; |
369 | } | 387 | } |
370 | 388 | ||
@@ -390,13 +408,13 @@ static const struct file_operations sh_wdt_fops = { | |||
390 | .owner = THIS_MODULE, | 408 | .owner = THIS_MODULE, |
391 | .llseek = no_llseek, | 409 | .llseek = no_llseek, |
392 | .write = sh_wdt_write, | 410 | .write = sh_wdt_write, |
393 | .ioctl = sh_wdt_ioctl, | 411 | .unlocked_ioctl = sh_wdt_ioctl, |
394 | .open = sh_wdt_open, | 412 | .open = sh_wdt_open, |
395 | .release = sh_wdt_close, | 413 | .release = sh_wdt_close, |
396 | .mmap = sh_wdt_mmap, | 414 | .mmap = sh_wdt_mmap, |
397 | }; | 415 | }; |
398 | 416 | ||
399 | static struct watchdog_info sh_wdt_info = { | 417 | static const struct watchdog_info sh_wdt_info = { |
400 | .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | | 418 | .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | |
401 | WDIOF_MAGICCLOSE, | 419 | WDIOF_MAGICCLOSE, |
402 | .firmware_version = 1, | 420 | .firmware_version = 1, |
@@ -422,30 +440,33 @@ static int __init sh_wdt_init(void) | |||
422 | { | 440 | { |
423 | int rc; | 441 | int rc; |
424 | 442 | ||
425 | if ((clock_division_ratio < 0x5) || (clock_division_ratio > 0x7)) { | 443 | if (clock_division_ratio < 0x5 || clock_division_ratio > 0x7) { |
426 | clock_division_ratio = WTCSR_CKS_4096; | 444 | clock_division_ratio = WTCSR_CKS_4096; |
427 | printk(KERN_INFO PFX "clock_division_ratio value must " | 445 | printk(KERN_INFO PFX |
428 | "be 0x5<=x<=0x7, using %d\n", clock_division_ratio); | 446 | "clock_division_ratio value must be 0x5<=x<=0x7, using %d\n", |
447 | clock_division_ratio); | ||
429 | } | 448 | } |
430 | 449 | ||
431 | rc = sh_wdt_set_heartbeat(heartbeat); | 450 | rc = sh_wdt_set_heartbeat(heartbeat); |
432 | if (unlikely(rc)) { | 451 | if (unlikely(rc)) { |
433 | heartbeat = WATCHDOG_HEARTBEAT; | 452 | heartbeat = WATCHDOG_HEARTBEAT; |
434 | printk(KERN_INFO PFX "heartbeat value must " | 453 | printk(KERN_INFO PFX |
435 | "be 1<=x<=3600, using %d\n", heartbeat); | 454 | "heartbeat value must be 1<=x<=3600, using %d\n", |
455 | heartbeat); | ||
436 | } | 456 | } |
437 | 457 | ||
438 | rc = register_reboot_notifier(&sh_wdt_notifier); | 458 | rc = register_reboot_notifier(&sh_wdt_notifier); |
439 | if (unlikely(rc)) { | 459 | if (unlikely(rc)) { |
440 | printk(KERN_ERR PFX "Can't register reboot notifier (err=%d)\n", | 460 | printk(KERN_ERR PFX |
441 | rc); | 461 | "Can't register reboot notifier (err=%d)\n", rc); |
442 | return rc; | 462 | return rc; |
443 | } | 463 | } |
444 | 464 | ||
445 | rc = misc_register(&sh_wdt_miscdev); | 465 | rc = misc_register(&sh_wdt_miscdev); |
446 | if (unlikely(rc)) { | 466 | if (unlikely(rc)) { |
447 | printk(KERN_ERR PFX "Can't register miscdev on " | 467 | printk(KERN_ERR PFX |
448 | "minor=%d (err=%d)\n", sh_wdt_miscdev.minor, rc); | 468 | "Can't register miscdev on minor=%d (err=%d)\n", |
469 | sh_wdt_miscdev.minor, rc); | ||
449 | unregister_reboot_notifier(&sh_wdt_notifier); | 470 | unregister_reboot_notifier(&sh_wdt_notifier); |
450 | return rc; | 471 | return rc; |
451 | } | 472 | } |
@@ -476,10 +497,14 @@ module_param(clock_division_ratio, int, 0); | |||
476 | MODULE_PARM_DESC(clock_division_ratio, "Clock division ratio. Valid ranges are from 0x5 (1.31ms) to 0x7 (5.25ms). (default=" __MODULE_STRING(clock_division_ratio) ")"); | 497 | MODULE_PARM_DESC(clock_division_ratio, "Clock division ratio. Valid ranges are from 0x5 (1.31ms) to 0x7 (5.25ms). (default=" __MODULE_STRING(clock_division_ratio) ")"); |
477 | 498 | ||
478 | module_param(heartbeat, int, 0); | 499 | module_param(heartbeat, int, 0); |
479 | MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (1<=heartbeat<=3600, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")"); | 500 | MODULE_PARM_DESC(heartbeat, |
501 | "Watchdog heartbeat in seconds. (1 <= heartbeat <= 3600, default=" | ||
502 | __MODULE_STRING(WATCHDOG_HEARTBEAT) ")"); | ||
480 | 503 | ||
481 | module_param(nowayout, int, 0); | 504 | module_param(nowayout, int, 0); |
482 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 505 | MODULE_PARM_DESC(nowayout, |
506 | "Watchdog cannot be stopped once started (default=" | ||
507 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
483 | 508 | ||
484 | module_init(sh_wdt_init); | 509 | module_init(sh_wdt_init); |
485 | module_exit(sh_wdt_exit); | 510 | module_exit(sh_wdt_exit); |
diff --git a/drivers/watchdog/smsc37b787_wdt.c b/drivers/watchdog/smsc37b787_wdt.c index 5d2b5ba61414..988ff1d5b4be 100644 --- a/drivers/watchdog/smsc37b787_wdt.c +++ b/drivers/watchdog/smsc37b787_wdt.c | |||
@@ -18,7 +18,7 @@ | |||
18 | * History: | 18 | * History: |
19 | * 2003 - Created version 1.0 for Linux 2.4.x. | 19 | * 2003 - Created version 1.0 for Linux 2.4.x. |
20 | * 2006 - Ported to Linux 2.6, added nowayout and MAGICCLOSE | 20 | * 2006 - Ported to Linux 2.6, added nowayout and MAGICCLOSE |
21 | * features. Released version 1.1 | 21 | * features. Released version 1.1 |
22 | * | 22 | * |
23 | * Theory of operation: | 23 | * Theory of operation: |
24 | * | 24 | * |
@@ -55,9 +55,9 @@ | |||
55 | #include <linux/reboot.h> | 55 | #include <linux/reboot.h> |
56 | #include <linux/init.h> | 56 | #include <linux/init.h> |
57 | #include <linux/spinlock.h> | 57 | #include <linux/spinlock.h> |
58 | #include <linux/io.h> | ||
59 | #include <linux/uaccess.h> | ||
58 | 60 | ||
59 | #include <asm/io.h> | ||
60 | #include <asm/uaccess.h> | ||
61 | #include <asm/system.h> | 61 | #include <asm/system.h> |
62 | 62 | ||
63 | /* enable support for minutes as units? */ | 63 | /* enable support for minutes as units? */ |
@@ -71,15 +71,15 @@ | |||
71 | #define UNIT_MINUTE 1 | 71 | #define UNIT_MINUTE 1 |
72 | 72 | ||
73 | #define MODNAME "smsc37b787_wdt: " | 73 | #define MODNAME "smsc37b787_wdt: " |
74 | #define VERSION "1.1" | 74 | #define VERSION "1.1" |
75 | 75 | ||
76 | #define IOPORT 0x3F0 | 76 | #define IOPORT 0x3F0 |
77 | #define IOPORT_SIZE 2 | 77 | #define IOPORT_SIZE 2 |
78 | #define IODEV_NO 8 | 78 | #define IODEV_NO 8 |
79 | 79 | ||
80 | static int unit = UNIT_SECOND; /* timer's unit */ | 80 | static int unit = UNIT_SECOND; /* timer's unit */ |
81 | static int timeout = 60; /* timeout value: default is 60 "units" */ | 81 | static int timeout = 60; /* timeout value: default is 60 "units" */ |
82 | static unsigned long timer_enabled = 0; /* is the timer enabled? */ | 82 | static unsigned long timer_enabled; /* is the timer enabled? */ |
83 | 83 | ||
84 | static char expect_close; /* is the close expected? */ | 84 | static char expect_close; /* is the close expected? */ |
85 | 85 | ||
@@ -93,114 +93,121 @@ static int nowayout = WATCHDOG_NOWAYOUT; | |||
93 | 93 | ||
94 | static inline void open_io_config(void) | 94 | static inline void open_io_config(void) |
95 | { | 95 | { |
96 | outb(0x55, IOPORT); | 96 | outb(0x55, IOPORT); |
97 | mdelay(1); | 97 | mdelay(1); |
98 | outb(0x55, IOPORT); | 98 | outb(0x55, IOPORT); |
99 | } | 99 | } |
100 | 100 | ||
101 | /* lock the IO chip */ | 101 | /* lock the IO chip */ |
102 | static inline void close_io_config(void) | 102 | static inline void close_io_config(void) |
103 | { | 103 | { |
104 | outb(0xAA, IOPORT); | 104 | outb(0xAA, IOPORT); |
105 | } | 105 | } |
106 | 106 | ||
107 | /* select the IO device */ | 107 | /* select the IO device */ |
108 | static inline void select_io_device(unsigned char devno) | 108 | static inline void select_io_device(unsigned char devno) |
109 | { | 109 | { |
110 | outb(0x07, IOPORT); | 110 | outb(0x07, IOPORT); |
111 | outb(devno, IOPORT+1); | 111 | outb(devno, IOPORT+1); |
112 | } | 112 | } |
113 | 113 | ||
114 | /* write to the control register */ | 114 | /* write to the control register */ |
115 | static inline void write_io_cr(unsigned char reg, unsigned char data) | 115 | static inline void write_io_cr(unsigned char reg, unsigned char data) |
116 | { | 116 | { |
117 | outb(reg, IOPORT); | 117 | outb(reg, IOPORT); |
118 | outb(data, IOPORT+1); | 118 | outb(data, IOPORT+1); |
119 | } | 119 | } |
120 | 120 | ||
121 | /* read from the control register */ | 121 | /* read from the control register */ |
122 | static inline char read_io_cr(unsigned char reg) | 122 | static inline char read_io_cr(unsigned char reg) |
123 | { | 123 | { |
124 | outb(reg, IOPORT); | 124 | outb(reg, IOPORT); |
125 | return inb(IOPORT+1); | 125 | return inb(IOPORT+1); |
126 | } | 126 | } |
127 | 127 | ||
128 | /* -- Medium level functions ------------------------------------*/ | 128 | /* -- Medium level functions ------------------------------------*/ |
129 | 129 | ||
130 | static inline void gpio_bit12(unsigned char reg) | 130 | static inline void gpio_bit12(unsigned char reg) |
131 | { | 131 | { |
132 | // -- General Purpose I/O Bit 1.2 -- | 132 | /* -- General Purpose I/O Bit 1.2 -- |
133 | // Bit 0, In/Out: 0 = Output, 1 = Input | 133 | * Bit 0, In/Out: 0 = Output, 1 = Input |
134 | // Bit 1, Polarity: 0 = No Invert, 1 = Invert | 134 | * Bit 1, Polarity: 0 = No Invert, 1 = Invert |
135 | // Bit 2, Group Enable Intr.: 0 = Disable, 1 = Enable | 135 | * Bit 2, Group Enable Intr.: 0 = Disable, 1 = Enable |
136 | // Bit 3/4, Function select: 00 = GPI/O, 01 = WDT, 10 = P17, | 136 | * Bit 3/4, Function select: 00 = GPI/O, 01 = WDT, 10 = P17, |
137 | // 11 = Either Edge Triggered Intr. 2 | 137 | * 11 = Either Edge Triggered Intr. 2 |
138 | // Bit 5/6 (Reserved) | 138 | * Bit 5/6 (Reserved) |
139 | // Bit 7, Output Type: 0 = Push Pull Bit, 1 = Open Drain | 139 | * Bit 7, Output Type: 0 = Push Pull Bit, 1 = Open Drain |
140 | write_io_cr(0xE2, reg); | 140 | */ |
141 | write_io_cr(0xE2, reg); | ||
141 | } | 142 | } |
142 | 143 | ||
143 | static inline void gpio_bit13(unsigned char reg) | 144 | static inline void gpio_bit13(unsigned char reg) |
144 | { | 145 | { |
145 | // -- General Purpose I/O Bit 1.3 -- | 146 | /* -- General Purpose I/O Bit 1.3 -- |
146 | // Bit 0, In/Out: 0 = Output, 1 = Input | 147 | * Bit 0, In/Out: 0 = Output, 1 = Input |
147 | // Bit 1, Polarity: 0 = No Invert, 1 = Invert | 148 | * Bit 1, Polarity: 0 = No Invert, 1 = Invert |
148 | // Bit 2, Group Enable Intr.: 0 = Disable, 1 = Enable | 149 | * Bit 2, Group Enable Intr.: 0 = Disable, 1 = Enable |
149 | // Bit 3, Function select: 0 = GPI/O, 1 = LED | 150 | * Bit 3, Function select: 0 = GPI/O, 1 = LED |
150 | // Bit 4-6 (Reserved) | 151 | * Bit 4-6 (Reserved) |
151 | // Bit 7, Output Type: 0 = Push Pull Bit, 1 = Open Drain | 152 | * Bit 7, Output Type: 0 = Push Pull Bit, 1 = Open Drain |
152 | write_io_cr(0xE3, reg); | 153 | */ |
154 | write_io_cr(0xE3, reg); | ||
153 | } | 155 | } |
154 | 156 | ||
155 | static inline void wdt_timer_units(unsigned char new_units) | 157 | static inline void wdt_timer_units(unsigned char new_units) |
156 | { | 158 | { |
157 | // -- Watchdog timer units -- | 159 | /* -- Watchdog timer units -- |
158 | // Bit 0-6 (Reserved) | 160 | * Bit 0-6 (Reserved) |
159 | // Bit 7, WDT Time-out Value Units Select | 161 | * Bit 7, WDT Time-out Value Units Select |
160 | // (0 = Minutes, 1 = Seconds) | 162 | * (0 = Minutes, 1 = Seconds) |
161 | write_io_cr(0xF1, new_units); | 163 | */ |
164 | write_io_cr(0xF1, new_units); | ||
162 | } | 165 | } |
163 | 166 | ||
164 | static inline void wdt_timeout_value(unsigned char new_timeout) | 167 | static inline void wdt_timeout_value(unsigned char new_timeout) |
165 | { | 168 | { |
166 | // -- Watchdog Timer Time-out Value -- | 169 | /* -- Watchdog Timer Time-out Value -- |
167 | // Bit 0-7 Binary coded units (0=Disabled, 1..255) | 170 | * Bit 0-7 Binary coded units (0=Disabled, 1..255) |
168 | write_io_cr(0xF2, new_timeout); | 171 | */ |
172 | write_io_cr(0xF2, new_timeout); | ||
169 | } | 173 | } |
170 | 174 | ||
171 | static inline void wdt_timer_conf(unsigned char conf) | 175 | static inline void wdt_timer_conf(unsigned char conf) |
172 | { | 176 | { |
173 | // -- Watchdog timer configuration -- | 177 | /* -- Watchdog timer configuration -- |
174 | // Bit 0 Joystick enable: 0* = No Reset, 1 = Reset WDT upon Gameport I/O | 178 | * Bit 0 Joystick enable: 0* = No Reset, 1 = Reset WDT upon |
175 | // Bit 1 Keyboard enable: 0* = No Reset, 1 = Reset WDT upon KBD Intr. | 179 | * Gameport I/O |
176 | // Bit 2 Mouse enable: 0* = No Reset, 1 = Reset WDT upon Mouse Intr. | 180 | * Bit 1 Keyboard enable: 0* = No Reset, 1 = Reset WDT upon KBD Intr. |
177 | // Bit 3 Reset the timer | 181 | * Bit 2 Mouse enable: 0* = No Reset, 1 = Reset WDT upon Mouse Intr |
178 | // (Wrong in SMsC documentation? Given as: PowerLED Timout Enabled) | 182 | * Bit 3 Reset the timer |
179 | // Bit 4-7 WDT Interrupt Mapping: (0000* = Disabled, | 183 | * (Wrong in SMsC documentation? Given as: PowerLED Timout |
180 | // 0001=IRQ1, 0010=(Invalid), 0011=IRQ3 to 1111=IRQ15) | 184 | * Enabled) |
181 | write_io_cr(0xF3, conf); | 185 | * Bit 4-7 WDT Interrupt Mapping: (0000* = Disabled, |
186 | * 0001=IRQ1, 0010=(Invalid), 0011=IRQ3 to 1111=IRQ15) | ||
187 | */ | ||
188 | write_io_cr(0xF3, conf); | ||
182 | } | 189 | } |
183 | 190 | ||
184 | static inline void wdt_timer_ctrl(unsigned char reg) | 191 | static inline void wdt_timer_ctrl(unsigned char reg) |
185 | { | 192 | { |
186 | // -- Watchdog timer control -- | 193 | /* -- Watchdog timer control -- |
187 | // Bit 0 Status Bit: 0 = Timer counting, 1 = Timeout occured | 194 | * Bit 0 Status Bit: 0 = Timer counting, 1 = Timeout occured |
188 | // Bit 1 Power LED Toggle: 0 = Disable Toggle, 1 = Toggle at 1 Hz | 195 | * Bit 1 Power LED Toggle: 0 = Disable Toggle, 1 = Toggle at 1 Hz |
189 | // Bit 2 Force Timeout: 1 = Forces WD timeout event (self-cleaning) | 196 | * Bit 2 Force Timeout: 1 = Forces WD timeout event (self-cleaning) |
190 | // Bit 3 P20 Force Timeout enabled: | 197 | * Bit 3 P20 Force Timeout enabled: |
191 | // 0 = P20 activity does not generate the WD timeout event | 198 | * 0 = P20 activity does not generate the WD timeout event |
192 | // 1 = P20 Allows rising edge of P20, from the keyboard | 199 | * 1 = P20 Allows rising edge of P20, from the keyboard |
193 | // controller, to force the WD timeout event. | 200 | * controller, to force the WD timeout event. |
194 | // Bit 4 (Reserved) | 201 | * Bit 4 (Reserved) |
195 | // -- Soft power management -- | 202 | * -- Soft power management -- |
196 | // Bit 5 Stop Counter: 1 = Stop software power down counter | 203 | * Bit 5 Stop Counter: 1 = Stop software power down counter |
197 | // set via register 0xB8, (self-cleaning) | 204 | * set via register 0xB8, (self-cleaning) |
198 | // (Upon read: 0 = Counter running, 1 = Counter stopped) | 205 | * (Upon read: 0 = Counter running, 1 = Counter stopped) |
199 | // Bit 6 Restart Counter: 1 = Restart software power down counter | 206 | * Bit 6 Restart Counter: 1 = Restart software power down counter |
200 | // set via register 0xB8, (self-cleaning) | 207 | * set via register 0xB8, (self-cleaning) |
201 | // Bit 7 SPOFF: 1 = Force software power down (self-cleaning) | 208 | * Bit 7 SPOFF: 1 = Force software power down (self-cleaning) |
202 | 209 | */ | |
203 | write_io_cr(0xF4, reg); | 210 | write_io_cr(0xF4, reg); |
204 | } | 211 | } |
205 | 212 | ||
206 | /* -- Higher level functions ------------------------------------*/ | 213 | /* -- Higher level functions ------------------------------------*/ |
@@ -209,33 +216,34 @@ static inline void wdt_timer_ctrl(unsigned char reg) | |||
209 | 216 | ||
210 | static void wb_smsc_wdt_initialize(void) | 217 | static void wb_smsc_wdt_initialize(void) |
211 | { | 218 | { |
212 | unsigned char old; | 219 | unsigned char old; |
213 | 220 | ||
214 | spin_lock(&io_lock); | 221 | spin_lock(&io_lock); |
215 | open_io_config(); | 222 | open_io_config(); |
216 | select_io_device(IODEV_NO); | 223 | select_io_device(IODEV_NO); |
217 | 224 | ||
218 | // enable the watchdog | 225 | /* enable the watchdog */ |
219 | gpio_bit13(0x08); // Select pin 80 = LED not GPIO | 226 | gpio_bit13(0x08); /* Select pin 80 = LED not GPIO */ |
220 | gpio_bit12(0x0A); // Set pin 79 = WDT not GPIO/Output/Polarity=Invert | 227 | gpio_bit12(0x0A); /* Set pin 79 = WDT not |
228 | GPIO/Output/Polarity=Invert */ | ||
229 | /* disable the timeout */ | ||
230 | wdt_timeout_value(0); | ||
221 | 231 | ||
222 | // disable the timeout | 232 | /* reset control register */ |
223 | wdt_timeout_value(0); | 233 | wdt_timer_ctrl(0x00); |
224 | 234 | ||
225 | // reset control register | 235 | /* reset configuration register */ |
226 | wdt_timer_ctrl(0x00); | ||
227 | |||
228 | // reset configuration register | ||
229 | wdt_timer_conf(0x00); | 236 | wdt_timer_conf(0x00); |
230 | 237 | ||
231 | // read old (timer units) register | 238 | /* read old (timer units) register */ |
232 | old = read_io_cr(0xF1) & 0x7F; | 239 | old = read_io_cr(0xF1) & 0x7F; |
233 | if (unit == UNIT_SECOND) old |= 0x80; // set to seconds | 240 | if (unit == UNIT_SECOND) |
241 | old |= 0x80; /* set to seconds */ | ||
234 | 242 | ||
235 | // set the watchdog timer units | 243 | /* set the watchdog timer units */ |
236 | wdt_timer_units(old); | 244 | wdt_timer_units(old); |
237 | 245 | ||
238 | close_io_config(); | 246 | close_io_config(); |
239 | spin_unlock(&io_lock); | 247 | spin_unlock(&io_lock); |
240 | } | 248 | } |
241 | 249 | ||
@@ -244,23 +252,23 @@ static void wb_smsc_wdt_initialize(void) | |||
244 | static void wb_smsc_wdt_shutdown(void) | 252 | static void wb_smsc_wdt_shutdown(void) |
245 | { | 253 | { |
246 | spin_lock(&io_lock); | 254 | spin_lock(&io_lock); |
247 | open_io_config(); | 255 | open_io_config(); |
248 | select_io_device(IODEV_NO); | 256 | select_io_device(IODEV_NO); |
249 | 257 | ||
250 | // disable the watchdog | 258 | /* disable the watchdog */ |
251 | gpio_bit13(0x09); | 259 | gpio_bit13(0x09); |
252 | gpio_bit12(0x09); | 260 | gpio_bit12(0x09); |
253 | 261 | ||
254 | // reset watchdog config register | 262 | /* reset watchdog config register */ |
255 | wdt_timer_conf(0x00); | 263 | wdt_timer_conf(0x00); |
256 | 264 | ||
257 | // reset watchdog control register | 265 | /* reset watchdog control register */ |
258 | wdt_timer_ctrl(0x00); | 266 | wdt_timer_ctrl(0x00); |
259 | 267 | ||
260 | // disable timeout | 268 | /* disable timeout */ |
261 | wdt_timeout_value(0x00); | 269 | wdt_timeout_value(0x00); |
262 | 270 | ||
263 | close_io_config(); | 271 | close_io_config(); |
264 | spin_unlock(&io_lock); | 272 | spin_unlock(&io_lock); |
265 | } | 273 | } |
266 | 274 | ||
@@ -269,16 +277,16 @@ static void wb_smsc_wdt_shutdown(void) | |||
269 | static void wb_smsc_wdt_set_timeout(unsigned char new_timeout) | 277 | static void wb_smsc_wdt_set_timeout(unsigned char new_timeout) |
270 | { | 278 | { |
271 | spin_lock(&io_lock); | 279 | spin_lock(&io_lock); |
272 | open_io_config(); | 280 | open_io_config(); |
273 | select_io_device(IODEV_NO); | 281 | select_io_device(IODEV_NO); |
274 | 282 | ||
275 | // set Power LED to blink, if we enable the timeout | 283 | /* set Power LED to blink, if we enable the timeout */ |
276 | wdt_timer_ctrl((new_timeout == 0) ? 0x00 : 0x02); | 284 | wdt_timer_ctrl((new_timeout == 0) ? 0x00 : 0x02); |
277 | 285 | ||
278 | // set timeout value | 286 | /* set timeout value */ |
279 | wdt_timeout_value(new_timeout); | 287 | wdt_timeout_value(new_timeout); |
280 | 288 | ||
281 | close_io_config(); | 289 | close_io_config(); |
282 | spin_unlock(&io_lock); | 290 | spin_unlock(&io_lock); |
283 | } | 291 | } |
284 | 292 | ||
@@ -286,32 +294,32 @@ static void wb_smsc_wdt_set_timeout(unsigned char new_timeout) | |||
286 | 294 | ||
287 | static unsigned char wb_smsc_wdt_get_timeout(void) | 295 | static unsigned char wb_smsc_wdt_get_timeout(void) |
288 | { | 296 | { |
289 | unsigned char set_timeout; | 297 | unsigned char set_timeout; |
290 | 298 | ||
291 | spin_lock(&io_lock); | 299 | spin_lock(&io_lock); |
292 | open_io_config(); | 300 | open_io_config(); |
293 | select_io_device(IODEV_NO); | 301 | select_io_device(IODEV_NO); |
294 | set_timeout = read_io_cr(0xF2); | 302 | set_timeout = read_io_cr(0xF2); |
295 | close_io_config(); | 303 | close_io_config(); |
296 | spin_unlock(&io_lock); | 304 | spin_unlock(&io_lock); |
297 | 305 | ||
298 | return set_timeout; | 306 | return set_timeout; |
299 | } | 307 | } |
300 | 308 | ||
301 | /* disable watchdog */ | 309 | /* disable watchdog */ |
302 | 310 | ||
303 | static void wb_smsc_wdt_disable(void) | 311 | static void wb_smsc_wdt_disable(void) |
304 | { | 312 | { |
305 | // set the timeout to 0 to disable the watchdog | 313 | /* set the timeout to 0 to disable the watchdog */ |
306 | wb_smsc_wdt_set_timeout(0); | 314 | wb_smsc_wdt_set_timeout(0); |
307 | } | 315 | } |
308 | 316 | ||
309 | /* enable watchdog by setting the current timeout */ | 317 | /* enable watchdog by setting the current timeout */ |
310 | 318 | ||
311 | static void wb_smsc_wdt_enable(void) | 319 | static void wb_smsc_wdt_enable(void) |
312 | { | 320 | { |
313 | // set the current timeout... | 321 | /* set the current timeout... */ |
314 | wb_smsc_wdt_set_timeout(timeout); | 322 | wb_smsc_wdt_set_timeout(timeout); |
315 | } | 323 | } |
316 | 324 | ||
317 | /* reset the timer */ | 325 | /* reset the timer */ |
@@ -319,14 +327,14 @@ static void wb_smsc_wdt_enable(void) | |||
319 | static void wb_smsc_wdt_reset_timer(void) | 327 | static void wb_smsc_wdt_reset_timer(void) |
320 | { | 328 | { |
321 | spin_lock(&io_lock); | 329 | spin_lock(&io_lock); |
322 | open_io_config(); | 330 | open_io_config(); |
323 | select_io_device(IODEV_NO); | 331 | select_io_device(IODEV_NO); |
324 | 332 | ||
325 | // reset the timer | 333 | /* reset the timer */ |
326 | wdt_timeout_value(timeout); | 334 | wdt_timeout_value(timeout); |
327 | wdt_timer_conf(0x08); | 335 | wdt_timer_conf(0x08); |
328 | 336 | ||
329 | close_io_config(); | 337 | close_io_config(); |
330 | spin_unlock(&io_lock); | 338 | spin_unlock(&io_lock); |
331 | } | 339 | } |
332 | 340 | ||
@@ -355,7 +363,9 @@ static int wb_smsc_wdt_open(struct inode *inode, struct file *file) | |||
355 | /* Reload and activate timer */ | 363 | /* Reload and activate timer */ |
356 | wb_smsc_wdt_enable(); | 364 | wb_smsc_wdt_enable(); |
357 | 365 | ||
358 | printk(KERN_INFO MODNAME "Watchdog enabled. Timeout set to %d %s.\n", timeout, (unit == UNIT_SECOND) ? "second(s)" : "minute(s)"); | 366 | printk(KERN_INFO MODNAME |
367 | "Watchdog enabled. Timeout set to %d %s.\n", | ||
368 | timeout, (unit == UNIT_SECOND) ? "second(s)" : "minute(s)"); | ||
359 | 369 | ||
360 | return nonseekable_open(inode, file); | 370 | return nonseekable_open(inode, file); |
361 | } | 371 | } |
@@ -367,10 +377,12 @@ static int wb_smsc_wdt_release(struct inode *inode, struct file *file) | |||
367 | /* Shut off the timer. */ | 377 | /* Shut off the timer. */ |
368 | 378 | ||
369 | if (expect_close == 42) { | 379 | if (expect_close == 42) { |
370 | wb_smsc_wdt_disable(); | 380 | wb_smsc_wdt_disable(); |
371 | printk(KERN_INFO MODNAME "Watchdog disabled, sleeping again...\n"); | 381 | printk(KERN_INFO MODNAME |
382 | "Watchdog disabled, sleeping again...\n"); | ||
372 | } else { | 383 | } else { |
373 | printk(KERN_CRIT MODNAME "Unexpected close, not stopping watchdog!\n"); | 384 | printk(KERN_CRIT MODNAME |
385 | "Unexpected close, not stopping watchdog!\n"); | ||
374 | wb_smsc_wdt_reset_timer(); | 386 | wb_smsc_wdt_reset_timer(); |
375 | } | 387 | } |
376 | 388 | ||
@@ -392,10 +404,11 @@ static ssize_t wb_smsc_wdt_write(struct file *file, const char __user *data, | |||
392 | /* reset expect flag */ | 404 | /* reset expect flag */ |
393 | expect_close = 0; | 405 | expect_close = 0; |
394 | 406 | ||
395 | /* scan to see whether or not we got the magic character */ | 407 | /* scan to see whether or not we got the |
408 | magic character */ | ||
396 | for (i = 0; i != len; i++) { | 409 | for (i = 0; i != len; i++) { |
397 | char c; | 410 | char c; |
398 | if (get_user(c, data+i)) | 411 | if (get_user(c, data + i)) |
399 | return -EFAULT; | 412 | return -EFAULT; |
400 | if (c == 'V') | 413 | if (c == 'V') |
401 | expect_close = 42; | 414 | expect_close = 42; |
@@ -410,8 +423,8 @@ static ssize_t wb_smsc_wdt_write(struct file *file, const char __user *data, | |||
410 | 423 | ||
411 | /* ioctl => control interface */ | 424 | /* ioctl => control interface */ |
412 | 425 | ||
413 | static int wb_smsc_wdt_ioctl(struct inode *inode, struct file *file, | 426 | static long wb_smsc_wdt_ioctl(struct file *file, |
414 | unsigned int cmd, unsigned long arg) | 427 | unsigned int cmd, unsigned long arg) |
415 | { | 428 | { |
416 | int new_timeout; | 429 | int new_timeout; |
417 | 430 | ||
@@ -420,89 +433,73 @@ static int wb_smsc_wdt_ioctl(struct inode *inode, struct file *file, | |||
420 | int __user *i; | 433 | int __user *i; |
421 | } uarg; | 434 | } uarg; |
422 | 435 | ||
423 | static struct watchdog_info ident = { | 436 | static const struct watchdog_info ident = { |
424 | .options = WDIOF_KEEPALIVEPING | | 437 | .options = WDIOF_KEEPALIVEPING | |
425 | WDIOF_SETTIMEOUT | | 438 | WDIOF_SETTIMEOUT | |
426 | WDIOF_MAGICCLOSE, | 439 | WDIOF_MAGICCLOSE, |
427 | .firmware_version = 0, | 440 | .firmware_version = 0, |
428 | .identity = "SMsC 37B787 Watchdog" | 441 | .identity = "SMsC 37B787 Watchdog", |
429 | }; | 442 | }; |
430 | 443 | ||
431 | uarg.i = (int __user *)arg; | 444 | uarg.i = (int __user *)arg; |
432 | 445 | ||
433 | switch (cmd) { | 446 | switch (cmd) { |
434 | default: | 447 | case WDIOC_GETSUPPORT: |
435 | return -ENOTTY; | 448 | return copy_to_user(uarg.ident, &ident, sizeof(ident)) |
436 | 449 | ? -EFAULT : 0; | |
437 | case WDIOC_GETSUPPORT: | 450 | case WDIOC_GETSTATUS: |
438 | return copy_to_user(uarg.ident, &ident, | 451 | return put_user(wb_smsc_wdt_status(), uarg.i); |
439 | sizeof(ident)) ? -EFAULT : 0; | 452 | case WDIOC_GETBOOTSTATUS: |
440 | 453 | return put_user(0, uarg.i); | |
441 | case WDIOC_GETSTATUS: | 454 | case WDIOC_SETOPTIONS: |
442 | return put_user(wb_smsc_wdt_status(), uarg.i); | 455 | { |
443 | 456 | int options, retval = -EINVAL; | |
444 | case WDIOC_GETBOOTSTATUS: | ||
445 | return put_user(0, uarg.i); | ||
446 | |||
447 | case WDIOC_KEEPALIVE: | ||
448 | wb_smsc_wdt_reset_timer(); | ||
449 | return 0; | ||
450 | |||
451 | case WDIOC_SETTIMEOUT: | ||
452 | if (get_user(new_timeout, uarg.i)) | ||
453 | return -EFAULT; | ||
454 | |||
455 | // the API states this is given in secs | ||
456 | if (unit == UNIT_MINUTE) | ||
457 | new_timeout /= 60; | ||
458 | |||
459 | if (new_timeout < 0 || new_timeout > MAX_TIMEOUT) | ||
460 | return -EINVAL; | ||
461 | |||
462 | timeout = new_timeout; | ||
463 | wb_smsc_wdt_set_timeout(timeout); | ||
464 | |||
465 | // fall through and return the new timeout... | ||
466 | |||
467 | case WDIOC_GETTIMEOUT: | ||
468 | |||
469 | new_timeout = timeout; | ||
470 | |||
471 | if (unit == UNIT_MINUTE) | ||
472 | new_timeout *= 60; | ||
473 | |||
474 | return put_user(new_timeout, uarg.i); | ||
475 | |||
476 | case WDIOC_SETOPTIONS: | ||
477 | { | ||
478 | int options, retval = -EINVAL; | ||
479 | |||
480 | if (get_user(options, uarg.i)) | ||
481 | return -EFAULT; | ||
482 | |||
483 | if (options & WDIOS_DISABLECARD) { | ||
484 | wb_smsc_wdt_disable(); | ||
485 | retval = 0; | ||
486 | } | ||
487 | 457 | ||
488 | if (options & WDIOS_ENABLECARD) { | 458 | if (get_user(options, uarg.i)) |
489 | wb_smsc_wdt_enable(); | 459 | return -EFAULT; |
490 | retval = 0; | ||
491 | } | ||
492 | 460 | ||
493 | return retval; | 461 | if (options & WDIOS_DISABLECARD) { |
462 | wb_smsc_wdt_disable(); | ||
463 | retval = 0; | ||
464 | } | ||
465 | if (options & WDIOS_ENABLECARD) { | ||
466 | wb_smsc_wdt_enable(); | ||
467 | retval = 0; | ||
494 | } | 468 | } |
469 | return retval; | ||
470 | } | ||
471 | case WDIOC_KEEPALIVE: | ||
472 | wb_smsc_wdt_reset_timer(); | ||
473 | return 0; | ||
474 | case WDIOC_SETTIMEOUT: | ||
475 | if (get_user(new_timeout, uarg.i)) | ||
476 | return -EFAULT; | ||
477 | /* the API states this is given in secs */ | ||
478 | if (unit == UNIT_MINUTE) | ||
479 | new_timeout /= 60; | ||
480 | if (new_timeout < 0 || new_timeout > MAX_TIMEOUT) | ||
481 | return -EINVAL; | ||
482 | timeout = new_timeout; | ||
483 | wb_smsc_wdt_set_timeout(timeout); | ||
484 | /* fall through and return the new timeout... */ | ||
485 | case WDIOC_GETTIMEOUT: | ||
486 | new_timeout = timeout; | ||
487 | if (unit == UNIT_MINUTE) | ||
488 | new_timeout *= 60; | ||
489 | return put_user(new_timeout, uarg.i); | ||
490 | default: | ||
491 | return -ENOTTY; | ||
495 | } | 492 | } |
496 | } | 493 | } |
497 | 494 | ||
498 | /* -- Notifier funtions -----------------------------------------*/ | 495 | /* -- Notifier funtions -----------------------------------------*/ |
499 | 496 | ||
500 | static int wb_smsc_wdt_notify_sys(struct notifier_block *this, unsigned long code, void *unused) | 497 | static int wb_smsc_wdt_notify_sys(struct notifier_block *this, |
498 | unsigned long code, void *unused) | ||
501 | { | 499 | { |
502 | if (code == SYS_DOWN || code == SYS_HALT) | 500 | if (code == SYS_DOWN || code == SYS_HALT) { |
503 | { | 501 | /* set timeout to 0, to avoid possible race-condition */ |
504 | // set timeout to 0, to avoid possible race-condition | 502 | timeout = 0; |
505 | timeout = 0; | ||
506 | wb_smsc_wdt_disable(); | 503 | wb_smsc_wdt_disable(); |
507 | } | 504 | } |
508 | return NOTIFY_DONE; | 505 | return NOTIFY_DONE; |
@@ -510,23 +507,20 @@ static int wb_smsc_wdt_notify_sys(struct notifier_block *this, unsigned long cod | |||
510 | 507 | ||
511 | /* -- Module's structures ---------------------------------------*/ | 508 | /* -- Module's structures ---------------------------------------*/ |
512 | 509 | ||
513 | static const struct file_operations wb_smsc_wdt_fops = | 510 | static const struct file_operations wb_smsc_wdt_fops = { |
514 | { | 511 | .owner = THIS_MODULE, |
515 | .owner = THIS_MODULE, | ||
516 | .llseek = no_llseek, | 512 | .llseek = no_llseek, |
517 | .write = wb_smsc_wdt_write, | 513 | .write = wb_smsc_wdt_write, |
518 | .ioctl = wb_smsc_wdt_ioctl, | 514 | .unlocked_ioctl = wb_smsc_wdt_ioctl, |
519 | .open = wb_smsc_wdt_open, | 515 | .open = wb_smsc_wdt_open, |
520 | .release = wb_smsc_wdt_release, | 516 | .release = wb_smsc_wdt_release, |
521 | }; | 517 | }; |
522 | 518 | ||
523 | static struct notifier_block wb_smsc_wdt_notifier = | 519 | static struct notifier_block wb_smsc_wdt_notifier = { |
524 | { | ||
525 | .notifier_call = wb_smsc_wdt_notify_sys, | 520 | .notifier_call = wb_smsc_wdt_notify_sys, |
526 | }; | 521 | }; |
527 | 522 | ||
528 | static struct miscdevice wb_smsc_wdt_miscdev = | 523 | static struct miscdevice wb_smsc_wdt_miscdev = { |
529 | { | ||
530 | .minor = WATCHDOG_MINOR, | 524 | .minor = WATCHDOG_MINOR, |
531 | .name = "watchdog", | 525 | .name = "watchdog", |
532 | .fops = &wb_smsc_wdt_fops, | 526 | .fops = &wb_smsc_wdt_fops, |
@@ -540,39 +534,44 @@ static int __init wb_smsc_wdt_init(void) | |||
540 | { | 534 | { |
541 | int ret; | 535 | int ret; |
542 | 536 | ||
543 | printk("SMsC 37B787 watchdog component driver " VERSION " initialising...\n"); | 537 | printk(KERN_INFO "SMsC 37B787 watchdog component driver " |
538 | VERSION " initialising...\n"); | ||
544 | 539 | ||
545 | if (!request_region(IOPORT, IOPORT_SIZE, "SMsC 37B787 watchdog")) { | 540 | if (!request_region(IOPORT, IOPORT_SIZE, "SMsC 37B787 watchdog")) { |
546 | printk(KERN_ERR MODNAME "Unable to register IO port %#x\n", IOPORT); | 541 | printk(KERN_ERR MODNAME "Unable to register IO port %#x\n", |
542 | IOPORT); | ||
547 | ret = -EBUSY; | 543 | ret = -EBUSY; |
548 | goto out_pnp; | 544 | goto out_pnp; |
549 | } | 545 | } |
550 | 546 | ||
551 | // set new maximum, if it's too big | 547 | /* set new maximum, if it's too big */ |
552 | if (timeout > MAX_TIMEOUT) | 548 | if (timeout > MAX_TIMEOUT) |
553 | timeout = MAX_TIMEOUT; | 549 | timeout = MAX_TIMEOUT; |
554 | 550 | ||
555 | // init the watchdog timer | 551 | /* init the watchdog timer */ |
556 | wb_smsc_wdt_initialize(); | 552 | wb_smsc_wdt_initialize(); |
557 | 553 | ||
558 | ret = register_reboot_notifier(&wb_smsc_wdt_notifier); | 554 | ret = register_reboot_notifier(&wb_smsc_wdt_notifier); |
559 | if (ret) { | 555 | if (ret) { |
560 | printk(KERN_ERR MODNAME "Unable to register reboot notifier err = %d\n", ret); | 556 | printk(KERN_ERR MODNAME |
557 | "Unable to register reboot notifier err = %d\n", ret); | ||
561 | goto out_io; | 558 | goto out_io; |
562 | } | 559 | } |
563 | 560 | ||
564 | ret = misc_register(&wb_smsc_wdt_miscdev); | 561 | ret = misc_register(&wb_smsc_wdt_miscdev); |
565 | if (ret) { | 562 | if (ret) { |
566 | printk(KERN_ERR MODNAME "Unable to register miscdev on minor %d\n", WATCHDOG_MINOR); | 563 | printk(KERN_ERR MODNAME |
564 | "Unable to register miscdev on minor %d\n", | ||
565 | WATCHDOG_MINOR); | ||
567 | goto out_rbt; | 566 | goto out_rbt; |
568 | } | 567 | } |
569 | 568 | ||
570 | // output info | 569 | /* output info */ |
571 | printk(KERN_INFO MODNAME "Timeout set to %d %s.\n", timeout, (unit == UNIT_SECOND) ? "second(s)" : "minute(s)"); | 570 | printk(KERN_INFO MODNAME "Timeout set to %d %s.\n", |
572 | printk(KERN_INFO MODNAME "Watchdog initialized and sleeping (nowayout=%d)...\n", nowayout); | 571 | timeout, (unit == UNIT_SECOND) ? "second(s)" : "minute(s)"); |
573 | 572 | printk(KERN_INFO MODNAME | |
574 | // ret = 0 | 573 | "Watchdog initialized and sleeping (nowayout=%d)...\n", |
575 | 574 | nowayout); | |
576 | out_clean: | 575 | out_clean: |
577 | return ret; | 576 | return ret; |
578 | 577 | ||
@@ -591,8 +590,7 @@ out_pnp: | |||
591 | static void __exit wb_smsc_wdt_exit(void) | 590 | static void __exit wb_smsc_wdt_exit(void) |
592 | { | 591 | { |
593 | /* Stop the timer before we leave */ | 592 | /* Stop the timer before we leave */ |
594 | if (!nowayout) | 593 | if (!nowayout) { |
595 | { | ||
596 | wb_smsc_wdt_shutdown(); | 594 | wb_smsc_wdt_shutdown(); |
597 | printk(KERN_INFO MODNAME "Watchdog disabled.\n"); | 595 | printk(KERN_INFO MODNAME "Watchdog disabled.\n"); |
598 | } | 596 | } |
@@ -601,25 +599,29 @@ static void __exit wb_smsc_wdt_exit(void) | |||
601 | unregister_reboot_notifier(&wb_smsc_wdt_notifier); | 599 | unregister_reboot_notifier(&wb_smsc_wdt_notifier); |
602 | release_region(IOPORT, IOPORT_SIZE); | 600 | release_region(IOPORT, IOPORT_SIZE); |
603 | 601 | ||
604 | printk("SMsC 37B787 watchdog component driver removed.\n"); | 602 | printk(KERN_INFO "SMsC 37B787 watchdog component driver removed.\n"); |
605 | } | 603 | } |
606 | 604 | ||
607 | module_init(wb_smsc_wdt_init); | 605 | module_init(wb_smsc_wdt_init); |
608 | module_exit(wb_smsc_wdt_exit); | 606 | module_exit(wb_smsc_wdt_exit); |
609 | 607 | ||
610 | MODULE_AUTHOR("Sven Anders <anders@anduras.de>"); | 608 | MODULE_AUTHOR("Sven Anders <anders@anduras.de>"); |
611 | MODULE_DESCRIPTION("Driver for SMsC 37B787 watchdog component (Version " VERSION ")"); | 609 | MODULE_DESCRIPTION("Driver for SMsC 37B787 watchdog component (Version " |
610 | VERSION ")"); | ||
612 | MODULE_LICENSE("GPL"); | 611 | MODULE_LICENSE("GPL"); |
613 | 612 | ||
614 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); | 613 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); |
615 | 614 | ||
616 | #ifdef SMSC_SUPPORT_MINUTES | 615 | #ifdef SMSC_SUPPORT_MINUTES |
617 | module_param(unit, int, 0); | 616 | module_param(unit, int, 0); |
618 | MODULE_PARM_DESC(unit, "set unit to use, 0=seconds or 1=minutes, default is 0"); | 617 | MODULE_PARM_DESC(unit, |
618 | "set unit to use, 0=seconds or 1=minutes, default is 0"); | ||
619 | #endif | 619 | #endif |
620 | 620 | ||
621 | module_param(timeout, int, 0); | 621 | module_param(timeout, int, 0); |
622 | MODULE_PARM_DESC(timeout, "range is 1-255 units, default is 60"); | 622 | MODULE_PARM_DESC(timeout, "range is 1-255 units, default is 60"); |
623 | 623 | ||
624 | module_param(nowayout, int, 0); | 624 | module_param(nowayout, int, 0); |
625 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 625 | MODULE_PARM_DESC(nowayout, |
626 | "Watchdog cannot be stopped once started (default=" | ||
627 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
diff --git a/drivers/watchdog/softdog.c b/drivers/watchdog/softdog.c index 9c3694909243..c650464c5c63 100644 --- a/drivers/watchdog/softdog.c +++ b/drivers/watchdog/softdog.c | |||
@@ -47,19 +47,22 @@ | |||
47 | #include <linux/reboot.h> | 47 | #include <linux/reboot.h> |
48 | #include <linux/init.h> | 48 | #include <linux/init.h> |
49 | #include <linux/jiffies.h> | 49 | #include <linux/jiffies.h> |
50 | 50 | #include <linux/uaccess.h> | |
51 | #include <asm/uaccess.h> | ||
52 | 51 | ||
53 | #define PFX "SoftDog: " | 52 | #define PFX "SoftDog: " |
54 | 53 | ||
55 | #define TIMER_MARGIN 60 /* Default is 60 seconds */ | 54 | #define TIMER_MARGIN 60 /* Default is 60 seconds */ |
56 | static int soft_margin = TIMER_MARGIN; /* in seconds */ | 55 | static int soft_margin = TIMER_MARGIN; /* in seconds */ |
57 | module_param(soft_margin, int, 0); | 56 | module_param(soft_margin, int, 0); |
58 | MODULE_PARM_DESC(soft_margin, "Watchdog soft_margin in seconds. (0<soft_margin<65536, default=" __MODULE_STRING(TIMER_MARGIN) ")"); | 57 | MODULE_PARM_DESC(soft_margin, |
58 | "Watchdog soft_margin in seconds. (0 < soft_margin < 65536, default=" | ||
59 | __MODULE_STRING(TIMER_MARGIN) ")"); | ||
59 | 60 | ||
60 | static int nowayout = WATCHDOG_NOWAYOUT; | 61 | static int nowayout = WATCHDOG_NOWAYOUT; |
61 | module_param(nowayout, int, 0); | 62 | module_param(nowayout, int, 0); |
62 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 63 | MODULE_PARM_DESC(nowayout, |
64 | "Watchdog cannot be stopped once started (default=" | ||
65 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
63 | 66 | ||
64 | #ifdef ONLY_TESTING | 67 | #ifdef ONLY_TESTING |
65 | static int soft_noboot = 1; | 68 | static int soft_noboot = 1; |
@@ -93,8 +96,7 @@ static void watchdog_fire(unsigned long data) | |||
93 | 96 | ||
94 | if (soft_noboot) | 97 | if (soft_noboot) |
95 | printk(KERN_CRIT PFX "Triggered - Reboot ignored.\n"); | 98 | printk(KERN_CRIT PFX "Triggered - Reboot ignored.\n"); |
96 | else | 99 | else { |
97 | { | ||
98 | printk(KERN_CRIT PFX "Initiating system reboot.\n"); | 100 | printk(KERN_CRIT PFX "Initiating system reboot.\n"); |
99 | emergency_restart(); | 101 | emergency_restart(); |
100 | printk(KERN_CRIT PFX "Reboot didn't ?????\n"); | 102 | printk(KERN_CRIT PFX "Reboot didn't ?????\n"); |
@@ -153,7 +155,8 @@ static int softdog_release(struct inode *inode, struct file *file) | |||
153 | softdog_stop(); | 155 | softdog_stop(); |
154 | module_put(THIS_MODULE); | 156 | module_put(THIS_MODULE); |
155 | } else { | 157 | } else { |
156 | printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); | 158 | printk(KERN_CRIT PFX |
159 | "Unexpected close, not stopping watchdog!\n"); | ||
157 | set_bit(0, &orphan_timer); | 160 | set_bit(0, &orphan_timer); |
158 | softdog_keepalive(); | 161 | softdog_keepalive(); |
159 | } | 162 | } |
@@ -162,12 +165,13 @@ static int softdog_release(struct inode *inode, struct file *file) | |||
162 | return 0; | 165 | return 0; |
163 | } | 166 | } |
164 | 167 | ||
165 | static ssize_t softdog_write(struct file *file, const char __user *data, size_t len, loff_t *ppos) | 168 | static ssize_t softdog_write(struct file *file, const char __user *data, |
169 | size_t len, loff_t *ppos) | ||
166 | { | 170 | { |
167 | /* | 171 | /* |
168 | * Refresh the timer. | 172 | * Refresh the timer. |
169 | */ | 173 | */ |
170 | if(len) { | 174 | if (len) { |
171 | if (!nowayout) { | 175 | if (!nowayout) { |
172 | size_t i; | 176 | size_t i; |
173 | 177 | ||
@@ -188,13 +192,13 @@ static ssize_t softdog_write(struct file *file, const char __user *data, size_t | |||
188 | return len; | 192 | return len; |
189 | } | 193 | } |
190 | 194 | ||
191 | static int softdog_ioctl(struct inode *inode, struct file *file, | 195 | static long softdog_ioctl(struct file *file, unsigned int cmd, |
192 | unsigned int cmd, unsigned long arg) | 196 | unsigned long arg) |
193 | { | 197 | { |
194 | void __user *argp = (void __user *)arg; | 198 | void __user *argp = (void __user *)arg; |
195 | int __user *p = argp; | 199 | int __user *p = argp; |
196 | int new_margin; | 200 | int new_margin; |
197 | static struct watchdog_info ident = { | 201 | static const struct watchdog_info ident = { |
198 | .options = WDIOF_SETTIMEOUT | | 202 | .options = WDIOF_SETTIMEOUT | |
199 | WDIOF_KEEPALIVEPING | | 203 | WDIOF_KEEPALIVEPING | |
200 | WDIOF_MAGICCLOSE, | 204 | WDIOF_MAGICCLOSE, |
@@ -202,26 +206,25 @@ static int softdog_ioctl(struct inode *inode, struct file *file, | |||
202 | .identity = "Software Watchdog", | 206 | .identity = "Software Watchdog", |
203 | }; | 207 | }; |
204 | switch (cmd) { | 208 | switch (cmd) { |
205 | default: | 209 | case WDIOC_GETSUPPORT: |
206 | return -ENOTTY; | 210 | return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; |
207 | case WDIOC_GETSUPPORT: | 211 | case WDIOC_GETSTATUS: |
208 | return copy_to_user(argp, &ident, | 212 | case WDIOC_GETBOOTSTATUS: |
209 | sizeof(ident)) ? -EFAULT : 0; | 213 | return put_user(0, p); |
210 | case WDIOC_GETSTATUS: | 214 | case WDIOC_KEEPALIVE: |
211 | case WDIOC_GETBOOTSTATUS: | 215 | softdog_keepalive(); |
212 | return put_user(0, p); | 216 | return 0; |
213 | case WDIOC_KEEPALIVE: | 217 | case WDIOC_SETTIMEOUT: |
214 | softdog_keepalive(); | 218 | if (get_user(new_margin, p)) |
215 | return 0; | 219 | return -EFAULT; |
216 | case WDIOC_SETTIMEOUT: | 220 | if (softdog_set_heartbeat(new_margin)) |
217 | if (get_user(new_margin, p)) | 221 | return -EINVAL; |
218 | return -EFAULT; | 222 | softdog_keepalive(); |
219 | if (softdog_set_heartbeat(new_margin)) | 223 | /* Fall */ |
220 | return -EINVAL; | 224 | case WDIOC_GETTIMEOUT: |
221 | softdog_keepalive(); | 225 | return put_user(soft_margin, p); |
222 | /* Fall */ | 226 | default: |
223 | case WDIOC_GETTIMEOUT: | 227 | return -ENOTTY; |
224 | return put_user(soft_margin, p); | ||
225 | } | 228 | } |
226 | } | 229 | } |
227 | 230 | ||
@@ -232,10 +235,9 @@ static int softdog_ioctl(struct inode *inode, struct file *file, | |||
232 | static int softdog_notify_sys(struct notifier_block *this, unsigned long code, | 235 | static int softdog_notify_sys(struct notifier_block *this, unsigned long code, |
233 | void *unused) | 236 | void *unused) |
234 | { | 237 | { |
235 | if(code==SYS_DOWN || code==SYS_HALT) { | 238 | if (code == SYS_DOWN || code == SYS_HALT) |
236 | /* Turn the WDT off */ | 239 | /* Turn the WDT off */ |
237 | softdog_stop(); | 240 | softdog_stop(); |
238 | } | ||
239 | return NOTIFY_DONE; | 241 | return NOTIFY_DONE; |
240 | } | 242 | } |
241 | 243 | ||
@@ -247,7 +249,7 @@ static const struct file_operations softdog_fops = { | |||
247 | .owner = THIS_MODULE, | 249 | .owner = THIS_MODULE, |
248 | .llseek = no_llseek, | 250 | .llseek = no_llseek, |
249 | .write = softdog_write, | 251 | .write = softdog_write, |
250 | .ioctl = softdog_ioctl, | 252 | .unlocked_ioctl = softdog_ioctl, |
251 | .open = softdog_open, | 253 | .open = softdog_open, |
252 | .release = softdog_release, | 254 | .release = softdog_release, |
253 | }; | 255 | }; |
@@ -268,24 +270,27 @@ static int __init watchdog_init(void) | |||
268 | { | 270 | { |
269 | int ret; | 271 | int ret; |
270 | 272 | ||
271 | /* Check that the soft_margin value is within it's range ; if not reset to the default */ | 273 | /* Check that the soft_margin value is within it's range; |
274 | if not reset to the default */ | ||
272 | if (softdog_set_heartbeat(soft_margin)) { | 275 | if (softdog_set_heartbeat(soft_margin)) { |
273 | softdog_set_heartbeat(TIMER_MARGIN); | 276 | softdog_set_heartbeat(TIMER_MARGIN); |
274 | printk(KERN_INFO PFX "soft_margin value must be 0<soft_margin<65536, using %d\n", | 277 | printk(KERN_INFO PFX |
278 | "soft_margin must be 0 < soft_margin < 65536, using %d\n", | ||
275 | TIMER_MARGIN); | 279 | TIMER_MARGIN); |
276 | } | 280 | } |
277 | 281 | ||
278 | ret = register_reboot_notifier(&softdog_notifier); | 282 | ret = register_reboot_notifier(&softdog_notifier); |
279 | if (ret) { | 283 | if (ret) { |
280 | printk (KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", | 284 | printk(KERN_ERR PFX |
281 | ret); | 285 | "cannot register reboot notifier (err=%d)\n", ret); |
282 | return ret; | 286 | return ret; |
283 | } | 287 | } |
284 | 288 | ||
285 | ret = misc_register(&softdog_miscdev); | 289 | ret = misc_register(&softdog_miscdev); |
286 | if (ret) { | 290 | if (ret) { |
287 | printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", | 291 | printk(KERN_ERR PFX |
288 | WATCHDOG_MINOR, ret); | 292 | "cannot register miscdev on minor=%d (err=%d)\n", |
293 | WATCHDOG_MINOR, ret); | ||
289 | unregister_reboot_notifier(&softdog_notifier); | 294 | unregister_reboot_notifier(&softdog_notifier); |
290 | return ret; | 295 | return ret; |
291 | } | 296 | } |
diff --git a/drivers/watchdog/txx9wdt.c b/drivers/watchdog/txx9wdt.c index 57cefef27ce3..dbbc018a5f46 100644 --- a/drivers/watchdog/txx9wdt.c +++ b/drivers/watchdog/txx9wdt.c | |||
@@ -45,27 +45,34 @@ static unsigned long txx9wdt_alive; | |||
45 | static int expect_close; | 45 | static int expect_close; |
46 | static struct txx9_tmr_reg __iomem *txx9wdt_reg; | 46 | static struct txx9_tmr_reg __iomem *txx9wdt_reg; |
47 | static struct clk *txx9_imclk; | 47 | static struct clk *txx9_imclk; |
48 | static DECLARE_LOCK(txx9_lock); | ||
48 | 49 | ||
49 | static void txx9wdt_ping(void) | 50 | static void txx9wdt_ping(void) |
50 | { | 51 | { |
52 | spin_lock(&txx9_lock); | ||
51 | __raw_writel(TXx9_TMWTMR_TWIE | TXx9_TMWTMR_TWC, &txx9wdt_reg->wtmr); | 53 | __raw_writel(TXx9_TMWTMR_TWIE | TXx9_TMWTMR_TWC, &txx9wdt_reg->wtmr); |
54 | spin_unlock(&txx9_lock); | ||
52 | } | 55 | } |
53 | 56 | ||
54 | static void txx9wdt_start(void) | 57 | static void txx9wdt_start(void) |
55 | { | 58 | { |
59 | spin_lock(&txx9_lock); | ||
56 | __raw_writel(WD_TIMER_CLK * timeout, &txx9wdt_reg->cpra); | 60 | __raw_writel(WD_TIMER_CLK * timeout, &txx9wdt_reg->cpra); |
57 | __raw_writel(WD_TIMER_CCD, &txx9wdt_reg->ccdr); | 61 | __raw_writel(WD_TIMER_CCD, &txx9wdt_reg->ccdr); |
58 | __raw_writel(0, &txx9wdt_reg->tisr); /* clear pending interrupt */ | 62 | __raw_writel(0, &txx9wdt_reg->tisr); /* clear pending interrupt */ |
59 | __raw_writel(TXx9_TMTCR_TCE | TXx9_TMTCR_CCDE | TXx9_TMTCR_TMODE_WDOG, | 63 | __raw_writel(TXx9_TMTCR_TCE | TXx9_TMTCR_CCDE | TXx9_TMTCR_TMODE_WDOG, |
60 | &txx9wdt_reg->tcr); | 64 | &txx9wdt_reg->tcr); |
61 | __raw_writel(TXx9_TMWTMR_TWIE | TXx9_TMWTMR_TWC, &txx9wdt_reg->wtmr); | 65 | __raw_writel(TXx9_TMWTMR_TWIE | TXx9_TMWTMR_TWC, &txx9wdt_reg->wtmr); |
66 | spin_unlock(&txx9_lock); | ||
62 | } | 67 | } |
63 | 68 | ||
64 | static void txx9wdt_stop(void) | 69 | static void txx9wdt_stop(void) |
65 | { | 70 | { |
71 | spin_lock(&txx9_lock); | ||
66 | __raw_writel(TXx9_TMWTMR_WDIS, &txx9wdt_reg->wtmr); | 72 | __raw_writel(TXx9_TMWTMR_WDIS, &txx9wdt_reg->wtmr); |
67 | __raw_writel(__raw_readl(&txx9wdt_reg->tcr) & ~TXx9_TMTCR_TCE, | 73 | __raw_writel(__raw_readl(&txx9wdt_reg->tcr) & ~TXx9_TMTCR_TCE, |
68 | &txx9wdt_reg->tcr); | 74 | &txx9wdt_reg->tcr); |
75 | spin_unlock(&txx9_lock); | ||
69 | } | 76 | } |
70 | 77 | ||
71 | static int txx9wdt_open(struct inode *inode, struct file *file) | 78 | static int txx9wdt_open(struct inode *inode, struct file *file) |
@@ -120,13 +127,13 @@ static ssize_t txx9wdt_write(struct file *file, const char __user *data, | |||
120 | return len; | 127 | return len; |
121 | } | 128 | } |
122 | 129 | ||
123 | static int txx9wdt_ioctl(struct inode *inode, struct file *file, | 130 | static long txx9wdt_ioctl(struct file *file, unsigned int cmd, |
124 | unsigned int cmd, unsigned long arg) | 131 | unsigned long arg) |
125 | { | 132 | { |
126 | void __user *argp = (void __user *)arg; | 133 | void __user *argp = (void __user *)arg; |
127 | int __user *p = argp; | 134 | int __user *p = argp; |
128 | int new_timeout; | 135 | int new_timeout; |
129 | static struct watchdog_info ident = { | 136 | static const struct watchdog_info ident = { |
130 | .options = WDIOF_SETTIMEOUT | | 137 | .options = WDIOF_SETTIMEOUT | |
131 | WDIOF_KEEPALIVEPING | | 138 | WDIOF_KEEPALIVEPING | |
132 | WDIOF_MAGICCLOSE, | 139 | WDIOF_MAGICCLOSE, |
@@ -135,8 +142,6 @@ static int txx9wdt_ioctl(struct inode *inode, struct file *file, | |||
135 | }; | 142 | }; |
136 | 143 | ||
137 | switch (cmd) { | 144 | switch (cmd) { |
138 | default: | ||
139 | return -ENOTTY; | ||
140 | case WDIOC_GETSUPPORT: | 145 | case WDIOC_GETSUPPORT: |
141 | return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; | 146 | return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; |
142 | case WDIOC_GETSTATUS: | 147 | case WDIOC_GETSTATUS: |
@@ -156,6 +161,8 @@ static int txx9wdt_ioctl(struct inode *inode, struct file *file, | |||
156 | /* Fall */ | 161 | /* Fall */ |
157 | case WDIOC_GETTIMEOUT: | 162 | case WDIOC_GETTIMEOUT: |
158 | return put_user(timeout, p); | 163 | return put_user(timeout, p); |
164 | default: | ||
165 | return -ENOTTY; | ||
159 | } | 166 | } |
160 | } | 167 | } |
161 | 168 | ||
@@ -168,22 +175,22 @@ static int txx9wdt_notify_sys(struct notifier_block *this, unsigned long code, | |||
168 | } | 175 | } |
169 | 176 | ||
170 | static const struct file_operations txx9wdt_fops = { | 177 | static const struct file_operations txx9wdt_fops = { |
171 | .owner = THIS_MODULE, | 178 | .owner = THIS_MODULE, |
172 | .llseek = no_llseek, | 179 | .llseek = no_llseek, |
173 | .write = txx9wdt_write, | 180 | .write = txx9wdt_write, |
174 | .ioctl = txx9wdt_ioctl, | 181 | .unlocked_ioctl = txx9wdt_ioctl, |
175 | .open = txx9wdt_open, | 182 | .open = txx9wdt_open, |
176 | .release = txx9wdt_release, | 183 | .release = txx9wdt_release, |
177 | }; | 184 | }; |
178 | 185 | ||
179 | static struct miscdevice txx9wdt_miscdev = { | 186 | static struct miscdevice txx9wdt_miscdev = { |
180 | .minor = WATCHDOG_MINOR, | 187 | .minor = WATCHDOG_MINOR, |
181 | .name = "watchdog", | 188 | .name = "watchdog", |
182 | .fops = &txx9wdt_fops, | 189 | .fops = &txx9wdt_fops, |
183 | }; | 190 | }; |
184 | 191 | ||
185 | static struct notifier_block txx9wdt_notifier = { | 192 | static struct notifier_block txx9wdt_notifier = { |
186 | .notifier_call = txx9wdt_notify_sys | 193 | .notifier_call = txx9wdt_notify_sys, |
187 | }; | 194 | }; |
188 | 195 | ||
189 | static int __init txx9wdt_probe(struct platform_device *dev) | 196 | static int __init txx9wdt_probe(struct platform_device *dev) |
diff --git a/drivers/watchdog/w83627hf_wdt.c b/drivers/watchdog/w83627hf_wdt.c index 386492821fc2..69396adaa5c3 100644 --- a/drivers/watchdog/w83627hf_wdt.c +++ b/drivers/watchdog/w83627hf_wdt.c | |||
@@ -37,9 +37,9 @@ | |||
37 | #include <linux/reboot.h> | 37 | #include <linux/reboot.h> |
38 | #include <linux/init.h> | 38 | #include <linux/init.h> |
39 | #include <linux/spinlock.h> | 39 | #include <linux/spinlock.h> |
40 | #include <linux/io.h> | ||
41 | #include <linux/uaccess.h> | ||
40 | 42 | ||
41 | #include <asm/io.h> | ||
42 | #include <asm/uaccess.h> | ||
43 | #include <asm/system.h> | 43 | #include <asm/system.h> |
44 | 44 | ||
45 | #define WATCHDOG_NAME "w83627hf/thf/hg WDT" | 45 | #define WATCHDOG_NAME "w83627hf/thf/hg WDT" |
@@ -57,22 +57,26 @@ MODULE_PARM_DESC(wdt_io, "w83627hf/thf WDT io port (default 0x2E)"); | |||
57 | 57 | ||
58 | static int timeout = WATCHDOG_TIMEOUT; /* in seconds */ | 58 | static int timeout = WATCHDOG_TIMEOUT; /* in seconds */ |
59 | module_param(timeout, int, 0); | 59 | module_param(timeout, int, 0); |
60 | MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=255, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) "."); | 60 | MODULE_PARM_DESC(timeout, |
61 | "Watchdog timeout in seconds. 1 <= timeout <= 255, default=" | ||
62 | __MODULE_STRING(WATCHDOG_TIMEOUT) "."); | ||
61 | 63 | ||
62 | static int nowayout = WATCHDOG_NOWAYOUT; | 64 | static int nowayout = WATCHDOG_NOWAYOUT; |
63 | module_param(nowayout, int, 0); | 65 | module_param(nowayout, int, 0); |
64 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 66 | MODULE_PARM_DESC(nowayout, |
67 | "Watchdog cannot be stopped once started (default=" | ||
68 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
65 | 69 | ||
66 | /* | 70 | /* |
67 | * Kernel methods. | 71 | * Kernel methods. |
68 | */ | 72 | */ |
69 | 73 | ||
70 | #define WDT_EFER (wdt_io+0) /* Extended Function Enable Registers */ | 74 | #define WDT_EFER (wdt_io+0) /* Extended Function Enable Registers */ |
71 | #define WDT_EFIR (wdt_io+0) /* Extended Function Index Register (same as EFER) */ | 75 | #define WDT_EFIR (wdt_io+0) /* Extended Function Index Register |
76 | (same as EFER) */ | ||
72 | #define WDT_EFDR (WDT_EFIR+1) /* Extended Function Data Register */ | 77 | #define WDT_EFDR (WDT_EFIR+1) /* Extended Function Data Register */ |
73 | 78 | ||
74 | static void | 79 | static void w83627hf_select_wd_register(void) |
75 | w83627hf_select_wd_register(void) | ||
76 | { | 80 | { |
77 | unsigned char c; | 81 | unsigned char c; |
78 | outb_p(0x87, WDT_EFER); /* Enter extended function mode */ | 82 | outb_p(0x87, WDT_EFER); /* Enter extended function mode */ |
@@ -93,43 +97,45 @@ w83627hf_select_wd_register(void) | |||
93 | outb_p(0x01, WDT_EFDR); /* set bit 0 to activate GPIO2 */ | 97 | outb_p(0x01, WDT_EFDR); /* set bit 0 to activate GPIO2 */ |
94 | } | 98 | } |
95 | 99 | ||
96 | static void | 100 | static void w83627hf_unselect_wd_register(void) |
97 | w83627hf_unselect_wd_register(void) | ||
98 | { | 101 | { |
99 | outb_p(0xAA, WDT_EFER); /* Leave extended function mode */ | 102 | outb_p(0xAA, WDT_EFER); /* Leave extended function mode */ |
100 | } | 103 | } |
101 | 104 | ||
102 | /* tyan motherboards seem to set F5 to 0x4C ? | 105 | /* tyan motherboards seem to set F5 to 0x4C ? |
103 | * So explicitly init to appropriate value. */ | 106 | * So explicitly init to appropriate value. */ |
104 | static void | 107 | |
105 | w83627hf_init(void) | 108 | static void w83627hf_init(void) |
106 | { | 109 | { |
107 | unsigned char t; | 110 | unsigned char t; |
108 | 111 | ||
109 | w83627hf_select_wd_register(); | 112 | w83627hf_select_wd_register(); |
110 | 113 | ||
111 | outb_p(0xF6, WDT_EFER); /* Select CRF6 */ | 114 | outb_p(0xF6, WDT_EFER); /* Select CRF6 */ |
112 | t=inb_p(WDT_EFDR); /* read CRF6 */ | 115 | t = inb_p(WDT_EFDR); /* read CRF6 */ |
113 | if (t != 0) { | 116 | if (t != 0) { |
114 | printk (KERN_INFO PFX "Watchdog already running. Resetting timeout to %d sec\n", timeout); | 117 | printk(KERN_INFO PFX |
118 | "Watchdog already running. Resetting timeout to %d sec\n", | ||
119 | timeout); | ||
115 | outb_p(timeout, WDT_EFDR); /* Write back to CRF6 */ | 120 | outb_p(timeout, WDT_EFDR); /* Write back to CRF6 */ |
116 | } | 121 | } |
117 | 122 | ||
118 | outb_p(0xF5, WDT_EFER); /* Select CRF5 */ | 123 | outb_p(0xF5, WDT_EFER); /* Select CRF5 */ |
119 | t=inb_p(WDT_EFDR); /* read CRF5 */ | 124 | t = inb_p(WDT_EFDR); /* read CRF5 */ |
120 | t&=~0x0C; /* set second mode & disable keyboard turning off watchdog */ | 125 | t &= ~0x0C; /* set second mode & disable keyboard |
126 | turning off watchdog */ | ||
121 | outb_p(t, WDT_EFDR); /* Write back to CRF5 */ | 127 | outb_p(t, WDT_EFDR); /* Write back to CRF5 */ |
122 | 128 | ||
123 | outb_p(0xF7, WDT_EFER); /* Select CRF7 */ | 129 | outb_p(0xF7, WDT_EFER); /* Select CRF7 */ |
124 | t=inb_p(WDT_EFDR); /* read CRF7 */ | 130 | t = inb_p(WDT_EFDR); /* read CRF7 */ |
125 | t&=~0xC0; /* disable keyboard & mouse turning off watchdog */ | 131 | t &= ~0xC0; /* disable keyboard & mouse turning off |
132 | watchdog */ | ||
126 | outb_p(t, WDT_EFDR); /* Write back to CRF7 */ | 133 | outb_p(t, WDT_EFDR); /* Write back to CRF7 */ |
127 | 134 | ||
128 | w83627hf_unselect_wd_register(); | 135 | w83627hf_unselect_wd_register(); |
129 | } | 136 | } |
130 | 137 | ||
131 | static void | 138 | static void wdt_ctrl(int timeout) |
132 | wdt_ctrl(int timeout) | ||
133 | { | 139 | { |
134 | spin_lock(&io_lock); | 140 | spin_lock(&io_lock); |
135 | 141 | ||
@@ -143,32 +149,28 @@ wdt_ctrl(int timeout) | |||
143 | spin_unlock(&io_lock); | 149 | spin_unlock(&io_lock); |
144 | } | 150 | } |
145 | 151 | ||
146 | static int | 152 | static int wdt_ping(void) |
147 | wdt_ping(void) | ||
148 | { | 153 | { |
149 | wdt_ctrl(timeout); | 154 | wdt_ctrl(timeout); |
150 | return 0; | 155 | return 0; |
151 | } | 156 | } |
152 | 157 | ||
153 | static int | 158 | static int wdt_disable(void) |
154 | wdt_disable(void) | ||
155 | { | 159 | { |
156 | wdt_ctrl(0); | 160 | wdt_ctrl(0); |
157 | return 0; | 161 | return 0; |
158 | } | 162 | } |
159 | 163 | ||
160 | static int | 164 | static int wdt_set_heartbeat(int t) |
161 | wdt_set_heartbeat(int t) | ||
162 | { | 165 | { |
163 | if ((t < 1) || (t > 255)) | 166 | if (t < 1 || t > 255) |
164 | return -EINVAL; | 167 | return -EINVAL; |
165 | |||
166 | timeout = t; | 168 | timeout = t; |
167 | return 0; | 169 | return 0; |
168 | } | 170 | } |
169 | 171 | ||
170 | static ssize_t | 172 | static ssize_t wdt_write(struct file *file, const char __user *buf, |
171 | wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) | 173 | size_t count, loff_t *ppos) |
172 | { | 174 | { |
173 | if (count) { | 175 | if (count) { |
174 | if (!nowayout) { | 176 | if (!nowayout) { |
@@ -178,7 +180,7 @@ wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) | |||
178 | 180 | ||
179 | for (i = 0; i != count; i++) { | 181 | for (i = 0; i != count; i++) { |
180 | char c; | 182 | char c; |
181 | if (get_user(c, buf+i)) | 183 | if (get_user(c, buf + i)) |
182 | return -EFAULT; | 184 | return -EFAULT; |
183 | if (c == 'V') | 185 | if (c == 'V') |
184 | expect_close = 42; | 186 | expect_close = 42; |
@@ -189,72 +191,61 @@ wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) | |||
189 | return count; | 191 | return count; |
190 | } | 192 | } |
191 | 193 | ||
192 | static int | 194 | static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
193 | wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | ||
194 | unsigned long arg) | ||
195 | { | 195 | { |
196 | void __user *argp = (void __user *)arg; | 196 | void __user *argp = (void __user *)arg; |
197 | int __user *p = argp; | 197 | int __user *p = argp; |
198 | int new_timeout; | 198 | int new_timeout; |
199 | static struct watchdog_info ident = { | 199 | static struct watchdog_info ident = { |
200 | .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, | 200 | .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | |
201 | WDIOF_MAGICCLOSE, | ||
201 | .firmware_version = 1, | 202 | .firmware_version = 1, |
202 | .identity = "W83627HF WDT", | 203 | .identity = "W83627HF WDT", |
203 | }; | 204 | }; |
204 | 205 | ||
205 | switch (cmd) { | 206 | switch (cmd) { |
206 | case WDIOC_GETSUPPORT: | 207 | case WDIOC_GETSUPPORT: |
207 | if (copy_to_user(argp, &ident, sizeof(ident))) | 208 | if (copy_to_user(argp, &ident, sizeof(ident))) |
208 | return -EFAULT; | 209 | return -EFAULT; |
209 | break; | 210 | break; |
210 | |||
211 | case WDIOC_GETSTATUS: | 211 | case WDIOC_GETSTATUS: |
212 | case WDIOC_GETBOOTSTATUS: | 212 | case WDIOC_GETBOOTSTATUS: |
213 | return put_user(0, p); | 213 | return put_user(0, p); |
214 | |||
215 | case WDIOC_KEEPALIVE: | ||
216 | wdt_ping(); | ||
217 | break; | ||
218 | |||
219 | case WDIOC_SETTIMEOUT: | ||
220 | if (get_user(new_timeout, p)) | ||
221 | return -EFAULT; | ||
222 | if (wdt_set_heartbeat(new_timeout)) | ||
223 | return -EINVAL; | ||
224 | wdt_ping(); | ||
225 | /* Fall */ | ||
226 | |||
227 | case WDIOC_GETTIMEOUT: | ||
228 | return put_user(timeout, p); | ||
229 | |||
230 | case WDIOC_SETOPTIONS: | 214 | case WDIOC_SETOPTIONS: |
231 | { | 215 | { |
232 | int options, retval = -EINVAL; | 216 | int options, retval = -EINVAL; |
233 | |||
234 | if (get_user(options, p)) | ||
235 | return -EFAULT; | ||
236 | |||
237 | if (options & WDIOS_DISABLECARD) { | ||
238 | wdt_disable(); | ||
239 | retval = 0; | ||
240 | } | ||
241 | |||
242 | if (options & WDIOS_ENABLECARD) { | ||
243 | wdt_ping(); | ||
244 | retval = 0; | ||
245 | } | ||
246 | 217 | ||
247 | return retval; | 218 | if (get_user(options, p)) |
219 | return -EFAULT; | ||
220 | if (options & WDIOS_DISABLECARD) { | ||
221 | wdt_disable(); | ||
222 | retval = 0; | ||
223 | } | ||
224 | if (options & WDIOS_ENABLECARD) { | ||
225 | wdt_ping(); | ||
226 | retval = 0; | ||
227 | } | ||
228 | return retval; | ||
248 | } | 229 | } |
249 | 230 | case WDIOC_KEEPALIVE: | |
231 | wdt_ping(); | ||
232 | break; | ||
233 | case WDIOC_SETTIMEOUT: | ||
234 | if (get_user(new_timeout, p)) | ||
235 | return -EFAULT; | ||
236 | if (wdt_set_heartbeat(new_timeout)) | ||
237 | return -EINVAL; | ||
238 | wdt_ping(); | ||
239 | /* Fall */ | ||
240 | case WDIOC_GETTIMEOUT: | ||
241 | return put_user(timeout, p); | ||
250 | default: | 242 | default: |
251 | return -ENOTTY; | 243 | return -ENOTTY; |
252 | } | 244 | } |
253 | return 0; | 245 | return 0; |
254 | } | 246 | } |
255 | 247 | ||
256 | static int | 248 | static int wdt_open(struct inode *inode, struct file *file) |
257 | wdt_open(struct inode *inode, struct file *file) | ||
258 | { | 249 | { |
259 | if (test_and_set_bit(0, &wdt_is_open)) | 250 | if (test_and_set_bit(0, &wdt_is_open)) |
260 | return -EBUSY; | 251 | return -EBUSY; |
@@ -266,13 +257,13 @@ wdt_open(struct inode *inode, struct file *file) | |||
266 | return nonseekable_open(inode, file); | 257 | return nonseekable_open(inode, file); |
267 | } | 258 | } |
268 | 259 | ||
269 | static int | 260 | static int wdt_close(struct inode *inode, struct file *file) |
270 | wdt_close(struct inode *inode, struct file *file) | ||
271 | { | 261 | { |
272 | if (expect_close == 42) { | 262 | if (expect_close == 42) |
273 | wdt_disable(); | 263 | wdt_disable(); |
274 | } else { | 264 | else { |
275 | printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); | 265 | printk(KERN_CRIT PFX |
266 | "Unexpected close, not stopping watchdog!\n"); | ||
276 | wdt_ping(); | 267 | wdt_ping(); |
277 | } | 268 | } |
278 | expect_close = 0; | 269 | expect_close = 0; |
@@ -284,14 +275,12 @@ wdt_close(struct inode *inode, struct file *file) | |||
284 | * Notifier for system down | 275 | * Notifier for system down |
285 | */ | 276 | */ |
286 | 277 | ||
287 | static int | 278 | static int wdt_notify_sys(struct notifier_block *this, unsigned long code, |
288 | wdt_notify_sys(struct notifier_block *this, unsigned long code, | ||
289 | void *unused) | 279 | void *unused) |
290 | { | 280 | { |
291 | if (code == SYS_DOWN || code == SYS_HALT) { | 281 | if (code == SYS_DOWN || code == SYS_HALT) |
292 | /* Turn the WDT off */ | 282 | wdt_disable(); /* Turn the WDT off */ |
293 | wdt_disable(); | 283 | |
294 | } | ||
295 | return NOTIFY_DONE; | 284 | return NOTIFY_DONE; |
296 | } | 285 | } |
297 | 286 | ||
@@ -303,7 +292,7 @@ static const struct file_operations wdt_fops = { | |||
303 | .owner = THIS_MODULE, | 292 | .owner = THIS_MODULE, |
304 | .llseek = no_llseek, | 293 | .llseek = no_llseek, |
305 | .write = wdt_write, | 294 | .write = wdt_write, |
306 | .ioctl = wdt_ioctl, | 295 | .unlocked_ioctl = wdt_ioctl, |
307 | .open = wdt_open, | 296 | .open = wdt_open, |
308 | .release = wdt_close, | 297 | .release = wdt_close, |
309 | }; | 298 | }; |
@@ -323,8 +312,7 @@ static struct notifier_block wdt_notifier = { | |||
323 | .notifier_call = wdt_notify_sys, | 312 | .notifier_call = wdt_notify_sys, |
324 | }; | 313 | }; |
325 | 314 | ||
326 | static int __init | 315 | static int __init wdt_init(void) |
327 | wdt_init(void) | ||
328 | { | 316 | { |
329 | int ret; | 317 | int ret; |
330 | 318 | ||
@@ -332,12 +320,13 @@ wdt_init(void) | |||
332 | 320 | ||
333 | if (wdt_set_heartbeat(timeout)) { | 321 | if (wdt_set_heartbeat(timeout)) { |
334 | wdt_set_heartbeat(WATCHDOG_TIMEOUT); | 322 | wdt_set_heartbeat(WATCHDOG_TIMEOUT); |
335 | printk (KERN_INFO PFX "timeout value must be 1<=timeout<=255, using %d\n", | 323 | printk(KERN_INFO PFX |
336 | WATCHDOG_TIMEOUT); | 324 | "timeout value must be 1 <= timeout <= 255, using %d\n", |
325 | WATCHDOG_TIMEOUT); | ||
337 | } | 326 | } |
338 | 327 | ||
339 | if (!request_region(wdt_io, 1, WATCHDOG_NAME)) { | 328 | if (!request_region(wdt_io, 1, WATCHDOG_NAME)) { |
340 | printk (KERN_ERR PFX "I/O address 0x%04x already in use\n", | 329 | printk(KERN_ERR PFX "I/O address 0x%04x already in use\n", |
341 | wdt_io); | 330 | wdt_io); |
342 | ret = -EIO; | 331 | ret = -EIO; |
343 | goto out; | 332 | goto out; |
@@ -347,20 +336,22 @@ wdt_init(void) | |||
347 | 336 | ||
348 | ret = register_reboot_notifier(&wdt_notifier); | 337 | ret = register_reboot_notifier(&wdt_notifier); |
349 | if (ret != 0) { | 338 | if (ret != 0) { |
350 | printk (KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", | 339 | printk(KERN_ERR PFX |
351 | ret); | 340 | "cannot register reboot notifier (err=%d)\n", ret); |
352 | goto unreg_regions; | 341 | goto unreg_regions; |
353 | } | 342 | } |
354 | 343 | ||
355 | ret = misc_register(&wdt_miscdev); | 344 | ret = misc_register(&wdt_miscdev); |
356 | if (ret != 0) { | 345 | if (ret != 0) { |
357 | printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", | 346 | printk(KERN_ERR PFX |
358 | WATCHDOG_MINOR, ret); | 347 | "cannot register miscdev on minor=%d (err=%d)\n", |
348 | WATCHDOG_MINOR, ret); | ||
359 | goto unreg_reboot; | 349 | goto unreg_reboot; |
360 | } | 350 | } |
361 | 351 | ||
362 | printk (KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n", | 352 | printk(KERN_INFO PFX |
363 | timeout, nowayout); | 353 | "initialized. timeout=%d sec (nowayout=%d)\n", |
354 | timeout, nowayout); | ||
364 | 355 | ||
365 | out: | 356 | out: |
366 | return ret; | 357 | return ret; |
@@ -371,12 +362,11 @@ unreg_regions: | |||
371 | goto out; | 362 | goto out; |
372 | } | 363 | } |
373 | 364 | ||
374 | static void __exit | 365 | static void __exit wdt_exit(void) |
375 | wdt_exit(void) | ||
376 | { | 366 | { |
377 | misc_deregister(&wdt_miscdev); | 367 | misc_deregister(&wdt_miscdev); |
378 | unregister_reboot_notifier(&wdt_notifier); | 368 | unregister_reboot_notifier(&wdt_notifier); |
379 | release_region(wdt_io,1); | 369 | release_region(wdt_io, 1); |
380 | } | 370 | } |
381 | 371 | ||
382 | module_init(wdt_init); | 372 | module_init(wdt_init); |
diff --git a/drivers/watchdog/w83697hf_wdt.c b/drivers/watchdog/w83697hf_wdt.c index 528b882420b6..445d30a01ed3 100644 --- a/drivers/watchdog/w83697hf_wdt.c +++ b/drivers/watchdog/w83697hf_wdt.c | |||
@@ -36,9 +36,9 @@ | |||
36 | #include <linux/reboot.h> | 36 | #include <linux/reboot.h> |
37 | #include <linux/init.h> | 37 | #include <linux/init.h> |
38 | #include <linux/spinlock.h> | 38 | #include <linux/spinlock.h> |
39 | #include <linux/io.h> | ||
40 | #include <linux/uaccess.h> | ||
39 | 41 | ||
40 | #include <asm/io.h> | ||
41 | #include <asm/uaccess.h> | ||
42 | #include <asm/system.h> | 42 | #include <asm/system.h> |
43 | 43 | ||
44 | #define WATCHDOG_NAME "w83697hf/hg WDT" | 44 | #define WATCHDOG_NAME "w83697hf/hg WDT" |
@@ -53,37 +53,43 @@ static DEFINE_SPINLOCK(io_lock); | |||
53 | /* You must set this - there is no sane way to probe for this board. */ | 53 | /* You must set this - there is no sane way to probe for this board. */ |
54 | static int wdt_io = 0x2e; | 54 | static int wdt_io = 0x2e; |
55 | module_param(wdt_io, int, 0); | 55 | module_param(wdt_io, int, 0); |
56 | MODULE_PARM_DESC(wdt_io, "w83697hf/hg WDT io port (default 0x2e, 0 = autodetect)"); | 56 | MODULE_PARM_DESC(wdt_io, |
57 | "w83697hf/hg WDT io port (default 0x2e, 0 = autodetect)"); | ||
57 | 58 | ||
58 | static int timeout = WATCHDOG_TIMEOUT; /* in seconds */ | 59 | static int timeout = WATCHDOG_TIMEOUT; /* in seconds */ |
59 | module_param(timeout, int, 0); | 60 | module_param(timeout, int, 0); |
60 | MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=255 (default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")"); | 61 | MODULE_PARM_DESC(timeout, |
62 | "Watchdog timeout in seconds. 1<= timeout <=255 (default=" | ||
63 | __MODULE_STRING(WATCHDOG_TIMEOUT) ")"); | ||
61 | 64 | ||
62 | static int nowayout = WATCHDOG_NOWAYOUT; | 65 | static int nowayout = WATCHDOG_NOWAYOUT; |
63 | module_param(nowayout, int, 0); | 66 | module_param(nowayout, int, 0); |
64 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 67 | MODULE_PARM_DESC(nowayout, |
68 | "Watchdog cannot be stopped once started (default=" | ||
69 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
65 | 70 | ||
66 | static int early_disable = WATCHDOG_EARLY_DISABLE; | 71 | static int early_disable = WATCHDOG_EARLY_DISABLE; |
67 | module_param(early_disable, int, 0); | 72 | module_param(early_disable, int, 0); |
68 | MODULE_PARM_DESC(early_disable, "Watchdog gets disabled at boot time (default=" __MODULE_STRING(WATCHDOG_EARLY_DISABLE) ")"); | 73 | MODULE_PARM_DESC(early_disable, |
74 | "Watchdog gets disabled at boot time (default=" | ||
75 | __MODULE_STRING(WATCHDOG_EARLY_DISABLE) ")"); | ||
69 | 76 | ||
70 | /* | 77 | /* |
71 | * Kernel methods. | 78 | * Kernel methods. |
72 | */ | 79 | */ |
73 | 80 | ||
74 | #define W83697HF_EFER (wdt_io+0) /* Extended Function Enable Register */ | 81 | #define W83697HF_EFER (wdt_io + 0) /* Extended Function Enable Register */ |
75 | #define W83697HF_EFIR (wdt_io+0) /* Extended Function Index Register (same as EFER) */ | 82 | #define W83697HF_EFIR (wdt_io + 0) /* Extended Function Index Register |
76 | #define W83697HF_EFDR (wdt_io+1) /* Extended Function Data Register */ | 83 | (same as EFER) */ |
84 | #define W83697HF_EFDR (wdt_io + 1) /* Extended Function Data Register */ | ||
77 | 85 | ||
78 | static inline void | 86 | static inline void w83697hf_unlock(void) |
79 | w83697hf_unlock(void) | ||
80 | { | 87 | { |
81 | outb_p(0x87, W83697HF_EFER); /* Enter extended function mode */ | 88 | outb_p(0x87, W83697HF_EFER); /* Enter extended function mode */ |
82 | outb_p(0x87, W83697HF_EFER); /* Again according to manual */ | 89 | outb_p(0x87, W83697HF_EFER); /* Again according to manual */ |
83 | } | 90 | } |
84 | 91 | ||
85 | static inline void | 92 | static inline void w83697hf_lock(void) |
86 | w83697hf_lock(void) | ||
87 | { | 93 | { |
88 | outb_p(0xAA, W83697HF_EFER); /* Leave extended function mode */ | 94 | outb_p(0xAA, W83697HF_EFER); /* Leave extended function mode */ |
89 | } | 95 | } |
@@ -93,41 +99,36 @@ w83697hf_lock(void) | |||
93 | * w83697hf_write_timeout() must be called with the device unlocked. | 99 | * w83697hf_write_timeout() must be called with the device unlocked. |
94 | */ | 100 | */ |
95 | 101 | ||
96 | static unsigned char | 102 | static unsigned char w83697hf_get_reg(unsigned char reg) |
97 | w83697hf_get_reg(unsigned char reg) | ||
98 | { | 103 | { |
99 | outb_p(reg, W83697HF_EFIR); | 104 | outb_p(reg, W83697HF_EFIR); |
100 | return inb_p(W83697HF_EFDR); | 105 | return inb_p(W83697HF_EFDR); |
101 | } | 106 | } |
102 | 107 | ||
103 | static void | 108 | static void w83697hf_set_reg(unsigned char reg, unsigned char data) |
104 | w83697hf_set_reg(unsigned char reg, unsigned char data) | ||
105 | { | 109 | { |
106 | outb_p(reg, W83697HF_EFIR); | 110 | outb_p(reg, W83697HF_EFIR); |
107 | outb_p(data, W83697HF_EFDR); | 111 | outb_p(data, W83697HF_EFDR); |
108 | } | 112 | } |
109 | 113 | ||
110 | static void | 114 | static void w83697hf_write_timeout(int timeout) |
111 | w83697hf_write_timeout(int timeout) | ||
112 | { | 115 | { |
113 | w83697hf_set_reg(0xF4, timeout); /* Write Timeout counter to CRF4 */ | 116 | /* Write Timeout counter to CRF4 */ |
117 | w83697hf_set_reg(0xF4, timeout); | ||
114 | } | 118 | } |
115 | 119 | ||
116 | static void | 120 | static void w83697hf_select_wdt(void) |
117 | w83697hf_select_wdt(void) | ||
118 | { | 121 | { |
119 | w83697hf_unlock(); | 122 | w83697hf_unlock(); |
120 | w83697hf_set_reg(0x07, 0x08); /* Switch to logic device 8 (GPIO2) */ | 123 | w83697hf_set_reg(0x07, 0x08); /* Switch to logic device 8 (GPIO2) */ |
121 | } | 124 | } |
122 | 125 | ||
123 | static inline void | 126 | static inline void w83697hf_deselect_wdt(void) |
124 | w83697hf_deselect_wdt(void) | ||
125 | { | 127 | { |
126 | w83697hf_lock(); | 128 | w83697hf_lock(); |
127 | } | 129 | } |
128 | 130 | ||
129 | static void | 131 | static void w83697hf_init(void) |
130 | w83697hf_init(void) | ||
131 | { | 132 | { |
132 | unsigned char bbuf; | 133 | unsigned char bbuf; |
133 | 134 | ||
@@ -136,7 +137,9 @@ w83697hf_init(void) | |||
136 | bbuf = w83697hf_get_reg(0x29); | 137 | bbuf = w83697hf_get_reg(0x29); |
137 | bbuf &= ~0x60; | 138 | bbuf &= ~0x60; |
138 | bbuf |= 0x20; | 139 | bbuf |= 0x20; |
139 | w83697hf_set_reg(0x29, bbuf); /* Set pin 119 to WDTO# mode (= CR29, WDT0) */ | 140 | |
141 | /* Set pin 119 to WDTO# mode (= CR29, WDT0) */ | ||
142 | w83697hf_set_reg(0x29, bbuf); | ||
140 | 143 | ||
141 | bbuf = w83697hf_get_reg(0xF3); | 144 | bbuf = w83697hf_get_reg(0xF3); |
142 | bbuf &= ~0x04; | 145 | bbuf &= ~0x04; |
@@ -145,8 +148,7 @@ w83697hf_init(void) | |||
145 | w83697hf_deselect_wdt(); | 148 | w83697hf_deselect_wdt(); |
146 | } | 149 | } |
147 | 150 | ||
148 | static void | 151 | static void wdt_ping(void) |
149 | wdt_ping(void) | ||
150 | { | 152 | { |
151 | spin_lock(&io_lock); | 153 | spin_lock(&io_lock); |
152 | w83697hf_select_wdt(); | 154 | w83697hf_select_wdt(); |
@@ -157,8 +159,7 @@ wdt_ping(void) | |||
157 | spin_unlock(&io_lock); | 159 | spin_unlock(&io_lock); |
158 | } | 160 | } |
159 | 161 | ||
160 | static void | 162 | static void wdt_enable(void) |
161 | wdt_enable(void) | ||
162 | { | 163 | { |
163 | spin_lock(&io_lock); | 164 | spin_lock(&io_lock); |
164 | w83697hf_select_wdt(); | 165 | w83697hf_select_wdt(); |
@@ -170,8 +171,7 @@ wdt_enable(void) | |||
170 | spin_unlock(&io_lock); | 171 | spin_unlock(&io_lock); |
171 | } | 172 | } |
172 | 173 | ||
173 | static void | 174 | static void wdt_disable(void) |
174 | wdt_disable(void) | ||
175 | { | 175 | { |
176 | spin_lock(&io_lock); | 176 | spin_lock(&io_lock); |
177 | w83697hf_select_wdt(); | 177 | w83697hf_select_wdt(); |
@@ -183,8 +183,7 @@ wdt_disable(void) | |||
183 | spin_unlock(&io_lock); | 183 | spin_unlock(&io_lock); |
184 | } | 184 | } |
185 | 185 | ||
186 | static unsigned char | 186 | static unsigned char wdt_running(void) |
187 | wdt_running(void) | ||
188 | { | 187 | { |
189 | unsigned char t; | 188 | unsigned char t; |
190 | 189 | ||
@@ -199,18 +198,17 @@ wdt_running(void) | |||
199 | return t; | 198 | return t; |
200 | } | 199 | } |
201 | 200 | ||
202 | static int | 201 | static int wdt_set_heartbeat(int t) |
203 | wdt_set_heartbeat(int t) | ||
204 | { | 202 | { |
205 | if ((t < 1) || (t > 255)) | 203 | if (t < 1 || t > 255) |
206 | return -EINVAL; | 204 | return -EINVAL; |
207 | 205 | ||
208 | timeout = t; | 206 | timeout = t; |
209 | return 0; | 207 | return 0; |
210 | } | 208 | } |
211 | 209 | ||
212 | static ssize_t | 210 | static ssize_t wdt_write(struct file *file, const char __user *buf, |
213 | wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) | 211 | size_t count, loff_t *ppos) |
214 | { | 212 | { |
215 | if (count) { | 213 | if (count) { |
216 | if (!nowayout) { | 214 | if (!nowayout) { |
@@ -220,7 +218,7 @@ wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) | |||
220 | 218 | ||
221 | for (i = 0; i != count; i++) { | 219 | for (i = 0; i != count; i++) { |
222 | char c; | 220 | char c; |
223 | if (get_user(c, buf+i)) | 221 | if (get_user(c, buf + i)) |
224 | return -EFAULT; | 222 | return -EFAULT; |
225 | if (c == 'V') | 223 | if (c == 'V') |
226 | expect_close = 42; | 224 | expect_close = 42; |
@@ -231,15 +229,14 @@ wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) | |||
231 | return count; | 229 | return count; |
232 | } | 230 | } |
233 | 231 | ||
234 | static int | 232 | static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
235 | wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | ||
236 | unsigned long arg) | ||
237 | { | 233 | { |
238 | void __user *argp = (void __user *)arg; | 234 | void __user *argp = (void __user *)arg; |
239 | int __user *p = argp; | 235 | int __user *p = argp; |
240 | int new_timeout; | 236 | int new_timeout; |
241 | static struct watchdog_info ident = { | 237 | static const struct watchdog_info ident = { |
242 | .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, | 238 | .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
239 | | WDIOF_MAGICCLOSE, | ||
243 | .firmware_version = 1, | 240 | .firmware_version = 1, |
244 | .identity = "W83697HF WDT", | 241 | .identity = "W83697HF WDT", |
245 | }; | 242 | }; |
@@ -254,21 +251,6 @@ wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | |||
254 | case WDIOC_GETBOOTSTATUS: | 251 | case WDIOC_GETBOOTSTATUS: |
255 | return put_user(0, p); | 252 | return put_user(0, p); |
256 | 253 | ||
257 | case WDIOC_KEEPALIVE: | ||
258 | wdt_ping(); | ||
259 | break; | ||
260 | |||
261 | case WDIOC_SETTIMEOUT: | ||
262 | if (get_user(new_timeout, p)) | ||
263 | return -EFAULT; | ||
264 | if (wdt_set_heartbeat(new_timeout)) | ||
265 | return -EINVAL; | ||
266 | wdt_ping(); | ||
267 | /* Fall */ | ||
268 | |||
269 | case WDIOC_GETTIMEOUT: | ||
270 | return put_user(timeout, p); | ||
271 | |||
272 | case WDIOC_SETOPTIONS: | 254 | case WDIOC_SETOPTIONS: |
273 | { | 255 | { |
274 | int options, retval = -EINVAL; | 256 | int options, retval = -EINVAL; |
@@ -289,14 +271,28 @@ wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | |||
289 | return retval; | 271 | return retval; |
290 | } | 272 | } |
291 | 273 | ||
274 | case WDIOC_KEEPALIVE: | ||
275 | wdt_ping(); | ||
276 | break; | ||
277 | |||
278 | case WDIOC_SETTIMEOUT: | ||
279 | if (get_user(new_timeout, p)) | ||
280 | return -EFAULT; | ||
281 | if (wdt_set_heartbeat(new_timeout)) | ||
282 | return -EINVAL; | ||
283 | wdt_ping(); | ||
284 | /* Fall */ | ||
285 | |||
286 | case WDIOC_GETTIMEOUT: | ||
287 | return put_user(timeout, p); | ||
288 | |||
292 | default: | 289 | default: |
293 | return -ENOTTY; | 290 | return -ENOTTY; |
294 | } | 291 | } |
295 | return 0; | 292 | return 0; |
296 | } | 293 | } |
297 | 294 | ||
298 | static int | 295 | static int wdt_open(struct inode *inode, struct file *file) |
299 | wdt_open(struct inode *inode, struct file *file) | ||
300 | { | 296 | { |
301 | if (test_and_set_bit(0, &wdt_is_open)) | 297 | if (test_and_set_bit(0, &wdt_is_open)) |
302 | return -EBUSY; | 298 | return -EBUSY; |
@@ -308,13 +304,13 @@ wdt_open(struct inode *inode, struct file *file) | |||
308 | return nonseekable_open(inode, file); | 304 | return nonseekable_open(inode, file); |
309 | } | 305 | } |
310 | 306 | ||
311 | static int | 307 | static int wdt_close(struct inode *inode, struct file *file) |
312 | wdt_close(struct inode *inode, struct file *file) | ||
313 | { | 308 | { |
314 | if (expect_close == 42) { | 309 | if (expect_close == 42) |
315 | wdt_disable(); | 310 | wdt_disable(); |
316 | } else { | 311 | else { |
317 | printk (KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); | 312 | printk(KERN_CRIT PFX |
313 | "Unexpected close, not stopping watchdog!\n"); | ||
318 | wdt_ping(); | 314 | wdt_ping(); |
319 | } | 315 | } |
320 | expect_close = 0; | 316 | expect_close = 0; |
@@ -326,14 +322,12 @@ wdt_close(struct inode *inode, struct file *file) | |||
326 | * Notifier for system down | 322 | * Notifier for system down |
327 | */ | 323 | */ |
328 | 324 | ||
329 | static int | 325 | static int wdt_notify_sys(struct notifier_block *this, unsigned long code, |
330 | wdt_notify_sys(struct notifier_block *this, unsigned long code, | ||
331 | void *unused) | 326 | void *unused) |
332 | { | 327 | { |
333 | if (code == SYS_DOWN || code == SYS_HALT) { | 328 | if (code == SYS_DOWN || code == SYS_HALT) |
334 | /* Turn the WDT off */ | 329 | wdt_disable(); /* Turn the WDT off */ |
335 | wdt_disable(); | 330 | |
336 | } | ||
337 | return NOTIFY_DONE; | 331 | return NOTIFY_DONE; |
338 | } | 332 | } |
339 | 333 | ||
@@ -345,7 +339,7 @@ static const struct file_operations wdt_fops = { | |||
345 | .owner = THIS_MODULE, | 339 | .owner = THIS_MODULE, |
346 | .llseek = no_llseek, | 340 | .llseek = no_llseek, |
347 | .write = wdt_write, | 341 | .write = wdt_write, |
348 | .ioctl = wdt_ioctl, | 342 | .unlocked_ioctl = wdt_ioctl, |
349 | .open = wdt_open, | 343 | .open = wdt_open, |
350 | .release = wdt_close, | 344 | .release = wdt_close, |
351 | }; | 345 | }; |
@@ -365,36 +359,38 @@ static struct notifier_block wdt_notifier = { | |||
365 | .notifier_call = wdt_notify_sys, | 359 | .notifier_call = wdt_notify_sys, |
366 | }; | 360 | }; |
367 | 361 | ||
368 | static int | 362 | static int w83697hf_check_wdt(void) |
369 | w83697hf_check_wdt(void) | ||
370 | { | 363 | { |
371 | if (!request_region(wdt_io, 2, WATCHDOG_NAME)) { | 364 | if (!request_region(wdt_io, 2, WATCHDOG_NAME)) { |
372 | printk (KERN_ERR PFX "I/O address 0x%x already in use\n", wdt_io); | 365 | printk(KERN_ERR PFX |
366 | "I/O address 0x%x already in use\n", wdt_io); | ||
373 | return -EIO; | 367 | return -EIO; |
374 | } | 368 | } |
375 | 369 | ||
376 | printk (KERN_DEBUG PFX "Looking for watchdog at address 0x%x\n", wdt_io); | 370 | printk(KERN_DEBUG PFX |
371 | "Looking for watchdog at address 0x%x\n", wdt_io); | ||
377 | w83697hf_unlock(); | 372 | w83697hf_unlock(); |
378 | if (w83697hf_get_reg(0x20) == 0x60) { | 373 | if (w83697hf_get_reg(0x20) == 0x60) { |
379 | printk (KERN_INFO PFX "watchdog found at address 0x%x\n", wdt_io); | 374 | printk(KERN_INFO PFX |
375 | "watchdog found at address 0x%x\n", wdt_io); | ||
380 | w83697hf_lock(); | 376 | w83697hf_lock(); |
381 | return 0; | 377 | return 0; |
382 | } | 378 | } |
383 | w83697hf_lock(); /* Reprotect in case it was a compatible device */ | 379 | /* Reprotect in case it was a compatible device */ |
380 | w83697hf_lock(); | ||
384 | 381 | ||
385 | printk (KERN_INFO PFX "watchdog not found at address 0x%x\n", wdt_io); | 382 | printk(KERN_INFO PFX "watchdog not found at address 0x%x\n", wdt_io); |
386 | release_region(wdt_io, 2); | 383 | release_region(wdt_io, 2); |
387 | return -EIO; | 384 | return -EIO; |
388 | } | 385 | } |
389 | 386 | ||
390 | static int w83697hf_ioports[] = { 0x2e, 0x4e, 0x00 }; | 387 | static int w83697hf_ioports[] = { 0x2e, 0x4e, 0x00 }; |
391 | 388 | ||
392 | static int __init | 389 | static int __init wdt_init(void) |
393 | wdt_init(void) | ||
394 | { | 390 | { |
395 | int ret, i, found = 0; | 391 | int ret, i, found = 0; |
396 | 392 | ||
397 | printk (KERN_INFO PFX "WDT driver for W83697HF/HG initializing\n"); | 393 | printk(KERN_INFO PFX "WDT driver for W83697HF/HG initializing\n"); |
398 | 394 | ||
399 | if (wdt_io == 0) { | 395 | if (wdt_io == 0) { |
400 | /* we will autodetect the W83697HF/HG watchdog */ | 396 | /* we will autodetect the W83697HF/HG watchdog */ |
@@ -409,7 +405,7 @@ wdt_init(void) | |||
409 | } | 405 | } |
410 | 406 | ||
411 | if (!found) { | 407 | if (!found) { |
412 | printk (KERN_ERR PFX "No W83697HF/HG could be found\n"); | 408 | printk(KERN_ERR PFX "No W83697HF/HG could be found\n"); |
413 | ret = -EIO; | 409 | ret = -EIO; |
414 | goto out; | 410 | goto out; |
415 | } | 411 | } |
@@ -417,31 +413,33 @@ wdt_init(void) | |||
417 | w83697hf_init(); | 413 | w83697hf_init(); |
418 | if (early_disable) { | 414 | if (early_disable) { |
419 | if (wdt_running()) | 415 | if (wdt_running()) |
420 | printk (KERN_WARNING PFX "Stopping previously enabled watchdog until userland kicks in\n"); | 416 | printk(KERN_WARNING PFX "Stopping previously enabled watchdog until userland kicks in\n"); |
421 | wdt_disable(); | 417 | wdt_disable(); |
422 | } | 418 | } |
423 | 419 | ||
424 | if (wdt_set_heartbeat(timeout)) { | 420 | if (wdt_set_heartbeat(timeout)) { |
425 | wdt_set_heartbeat(WATCHDOG_TIMEOUT); | 421 | wdt_set_heartbeat(WATCHDOG_TIMEOUT); |
426 | printk (KERN_INFO PFX "timeout value must be 1<=timeout<=255, using %d\n", | 422 | printk(KERN_INFO PFX |
427 | WATCHDOG_TIMEOUT); | 423 | "timeout value must be 1 <= timeout <= 255, using %d\n", |
424 | WATCHDOG_TIMEOUT); | ||
428 | } | 425 | } |
429 | 426 | ||
430 | ret = register_reboot_notifier(&wdt_notifier); | 427 | ret = register_reboot_notifier(&wdt_notifier); |
431 | if (ret != 0) { | 428 | if (ret != 0) { |
432 | printk (KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", | 429 | printk(KERN_ERR PFX |
433 | ret); | 430 | "cannot register reboot notifier (err=%d)\n", ret); |
434 | goto unreg_regions; | 431 | goto unreg_regions; |
435 | } | 432 | } |
436 | 433 | ||
437 | ret = misc_register(&wdt_miscdev); | 434 | ret = misc_register(&wdt_miscdev); |
438 | if (ret != 0) { | 435 | if (ret != 0) { |
439 | printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", | 436 | printk(KERN_ERR PFX |
440 | WATCHDOG_MINOR, ret); | 437 | "cannot register miscdev on minor=%d (err=%d)\n", |
438 | WATCHDOG_MINOR, ret); | ||
441 | goto unreg_reboot; | 439 | goto unreg_reboot; |
442 | } | 440 | } |
443 | 441 | ||
444 | printk (KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n", | 442 | printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n", |
445 | timeout, nowayout); | 443 | timeout, nowayout); |
446 | 444 | ||
447 | out: | 445 | out: |
@@ -453,8 +451,7 @@ unreg_regions: | |||
453 | goto out; | 451 | goto out; |
454 | } | 452 | } |
455 | 453 | ||
456 | static void __exit | 454 | static void __exit wdt_exit(void) |
457 | wdt_exit(void) | ||
458 | { | 455 | { |
459 | misc_deregister(&wdt_miscdev); | 456 | misc_deregister(&wdt_miscdev); |
460 | unregister_reboot_notifier(&wdt_notifier); | 457 | unregister_reboot_notifier(&wdt_notifier); |
diff --git a/drivers/watchdog/w83877f_wdt.c b/drivers/watchdog/w83877f_wdt.c index f510a3a595e6..24587d2060c4 100644 --- a/drivers/watchdog/w83877f_wdt.c +++ b/drivers/watchdog/w83877f_wdt.c | |||
@@ -23,13 +23,16 @@ | |||
23 | * Added KERN_* tags to printks | 23 | * Added KERN_* tags to printks |
24 | * add CONFIG_WATCHDOG_NOWAYOUT support | 24 | * add CONFIG_WATCHDOG_NOWAYOUT support |
25 | * fix possible wdt_is_open race | 25 | * fix possible wdt_is_open race |
26 | * changed watchdog_info to correctly reflect what the driver offers | 26 | * changed watchdog_info to correctly reflect what |
27 | * added WDIOC_GETSTATUS, WDIOC_GETBOOTSTATUS, WDIOC_SETTIMEOUT, | 27 | * the driver offers |
28 | * added WDIOC_GETSTATUS, WDIOC_GETBOOTSTATUS, | ||
29 | * WDIOC_SETTIMEOUT, | ||
28 | * WDIOC_GETTIMEOUT, and WDIOC_SETOPTIONS ioctls | 30 | * WDIOC_GETTIMEOUT, and WDIOC_SETOPTIONS ioctls |
29 | * 09/8 - 2003 [wim@iguana.be] cleanup of trailing spaces | 31 | * 09/8 - 2003 [wim@iguana.be] cleanup of trailing spaces |
30 | * added extra printk's for startup problems | 32 | * added extra printk's for startup problems |
31 | * use module_param | 33 | * use module_param |
32 | * made timeout (the emulated heartbeat) a module_param | 34 | * made timeout (the emulated heartbeat) a |
35 | * module_param | ||
33 | * made the keepalive ping an internal subroutine | 36 | * made the keepalive ping an internal subroutine |
34 | * | 37 | * |
35 | * This WDT driver is different from most other Linux WDT | 38 | * This WDT driver is different from most other Linux WDT |
@@ -51,8 +54,8 @@ | |||
51 | #include <linux/notifier.h> | 54 | #include <linux/notifier.h> |
52 | #include <linux/reboot.h> | 55 | #include <linux/reboot.h> |
53 | #include <linux/init.h> | 56 | #include <linux/init.h> |
54 | #include <asm/io.h> | 57 | #include <linux/io.h> |
55 | #include <asm/uaccess.h> | 58 | #include <linux/uaccess.h> |
56 | #include <asm/system.h> | 59 | #include <asm/system.h> |
57 | 60 | ||
58 | #define OUR_NAME "w83877f_wdt" | 61 | #define OUR_NAME "w83877f_wdt" |
@@ -80,14 +83,19 @@ | |||
80 | */ | 83 | */ |
81 | 84 | ||
82 | #define WATCHDOG_TIMEOUT 30 /* 30 sec default timeout */ | 85 | #define WATCHDOG_TIMEOUT 30 /* 30 sec default timeout */ |
83 | static int timeout = WATCHDOG_TIMEOUT; /* in seconds, will be multiplied by HZ to get seconds to wait for a ping */ | 86 | /* in seconds, will be multiplied by HZ to get seconds to wait for a ping */ |
87 | static int timeout = WATCHDOG_TIMEOUT; | ||
84 | module_param(timeout, int, 0); | 88 | module_param(timeout, int, 0); |
85 | MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (1<=timeout<=3600, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")"); | 89 | MODULE_PARM_DESC(timeout, |
90 | "Watchdog timeout in seconds. (1<=timeout<=3600, default=" | ||
91 | __MODULE_STRING(WATCHDOG_TIMEOUT) ")"); | ||
86 | 92 | ||
87 | 93 | ||
88 | static int nowayout = WATCHDOG_NOWAYOUT; | 94 | static int nowayout = WATCHDOG_NOWAYOUT; |
89 | module_param(nowayout, int, 0); | 95 | module_param(nowayout, int, 0); |
90 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 96 | MODULE_PARM_DESC(nowayout, |
97 | "Watchdog cannot be stopped once started (default=" | ||
98 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
91 | 99 | ||
92 | static void wdt_timer_ping(unsigned long); | 100 | static void wdt_timer_ping(unsigned long); |
93 | static DEFINE_TIMER(timer, wdt_timer_ping, 0, 0); | 101 | static DEFINE_TIMER(timer, wdt_timer_ping, 0, 0); |
@@ -105,8 +113,7 @@ static void wdt_timer_ping(unsigned long data) | |||
105 | /* If we got a heartbeat pulse within the WDT_US_INTERVAL | 113 | /* If we got a heartbeat pulse within the WDT_US_INTERVAL |
106 | * we agree to ping the WDT | 114 | * we agree to ping the WDT |
107 | */ | 115 | */ |
108 | if(time_before(jiffies, next_heartbeat)) | 116 | if (time_before(jiffies, next_heartbeat)) { |
109 | { | ||
110 | /* Ping the WDT */ | 117 | /* Ping the WDT */ |
111 | spin_lock(&wdt_spinlock); | 118 | spin_lock(&wdt_spinlock); |
112 | 119 | ||
@@ -118,9 +125,9 @@ static void wdt_timer_ping(unsigned long data) | |||
118 | 125 | ||
119 | spin_unlock(&wdt_spinlock); | 126 | spin_unlock(&wdt_spinlock); |
120 | 127 | ||
121 | } else { | 128 | } else |
122 | printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n"); | 129 | printk(KERN_WARNING PFX |
123 | } | 130 | "Heartbeat lost! Will not ping the watchdog\n"); |
124 | } | 131 | } |
125 | 132 | ||
126 | /* | 133 | /* |
@@ -181,22 +188,21 @@ static void wdt_keepalive(void) | |||
181 | * /dev/watchdog handling | 188 | * /dev/watchdog handling |
182 | */ | 189 | */ |
183 | 190 | ||
184 | static ssize_t fop_write(struct file * file, const char __user * buf, size_t count, loff_t * ppos) | 191 | static ssize_t fop_write(struct file *file, const char __user *buf, |
192 | size_t count, loff_t *ppos) | ||
185 | { | 193 | { |
186 | /* See if we got the magic character 'V' and reload the timer */ | 194 | /* See if we got the magic character 'V' and reload the timer */ |
187 | if(count) | 195 | if (count) { |
188 | { | 196 | if (!nowayout) { |
189 | if (!nowayout) | ||
190 | { | ||
191 | size_t ofs; | 197 | size_t ofs; |
192 | 198 | ||
193 | /* note: just in case someone wrote the magic character | 199 | /* note: just in case someone wrote the magic |
194 | * five months ago... */ | 200 | character five months ago... */ |
195 | wdt_expect_close = 0; | 201 | wdt_expect_close = 0; |
196 | 202 | ||
197 | /* scan to see whether or not we got the magic character */ | 203 | /* scan to see whether or not we got the |
198 | for(ofs = 0; ofs != count; ofs++) | 204 | magic character */ |
199 | { | 205 | for (ofs = 0; ofs != count; ofs++) { |
200 | char c; | 206 | char c; |
201 | if (get_user(c, buf + ofs)) | 207 | if (get_user(c, buf + ofs)) |
202 | return -EFAULT; | 208 | return -EFAULT; |
@@ -211,10 +217,10 @@ static ssize_t fop_write(struct file * file, const char __user * buf, size_t cou | |||
211 | return count; | 217 | return count; |
212 | } | 218 | } |
213 | 219 | ||
214 | static int fop_open(struct inode * inode, struct file * file) | 220 | static int fop_open(struct inode *inode, struct file *file) |
215 | { | 221 | { |
216 | /* Just in case we're already talking to someone... */ | 222 | /* Just in case we're already talking to someone... */ |
217 | if(test_and_set_bit(0, &wdt_is_open)) | 223 | if (test_and_set_bit(0, &wdt_is_open)) |
218 | return -EBUSY; | 224 | return -EBUSY; |
219 | 225 | ||
220 | /* Good, fire up the show */ | 226 | /* Good, fire up the show */ |
@@ -222,78 +228,78 @@ static int fop_open(struct inode * inode, struct file * file) | |||
222 | return nonseekable_open(inode, file); | 228 | return nonseekable_open(inode, file); |
223 | } | 229 | } |
224 | 230 | ||
225 | static int fop_close(struct inode * inode, struct file * file) | 231 | static int fop_close(struct inode *inode, struct file *file) |
226 | { | 232 | { |
227 | if(wdt_expect_close == 42) | 233 | if (wdt_expect_close == 42) |
228 | wdt_turnoff(); | 234 | wdt_turnoff(); |
229 | else { | 235 | else { |
230 | del_timer(&timer); | 236 | del_timer(&timer); |
231 | printk(KERN_CRIT PFX "device file closed unexpectedly. Will not stop the WDT!\n"); | 237 | printk(KERN_CRIT PFX |
238 | "device file closed unexpectedly. Will not stop the WDT!\n"); | ||
232 | } | 239 | } |
233 | clear_bit(0, &wdt_is_open); | 240 | clear_bit(0, &wdt_is_open); |
234 | wdt_expect_close = 0; | 241 | wdt_expect_close = 0; |
235 | return 0; | 242 | return 0; |
236 | } | 243 | } |
237 | 244 | ||
238 | static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | 245 | static long fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
239 | unsigned long arg) | ||
240 | { | 246 | { |
241 | void __user *argp = (void __user *)arg; | 247 | void __user *argp = (void __user *)arg; |
242 | int __user *p = argp; | 248 | int __user *p = argp; |
243 | static struct watchdog_info ident= | 249 | static const struct watchdog_info ident = { |
244 | { | 250 | .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
245 | .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, | 251 | | WDIOF_MAGICCLOSE, |
246 | .firmware_version = 1, | 252 | .firmware_version = 1, |
247 | .identity = "W83877F", | 253 | .identity = "W83877F", |
248 | }; | 254 | }; |
249 | 255 | ||
250 | switch(cmd) | 256 | switch (cmd) { |
257 | case WDIOC_GETSUPPORT: | ||
258 | return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; | ||
259 | case WDIOC_GETSTATUS: | ||
260 | case WDIOC_GETBOOTSTATUS: | ||
261 | return put_user(0, p); | ||
262 | case WDIOC_SETOPTIONS: | ||
251 | { | 263 | { |
252 | default: | 264 | int new_options, retval = -EINVAL; |
253 | return -ENOTTY; | ||
254 | case WDIOC_GETSUPPORT: | ||
255 | return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0; | ||
256 | case WDIOC_GETSTATUS: | ||
257 | case WDIOC_GETBOOTSTATUS: | ||
258 | return put_user(0, p); | ||
259 | case WDIOC_KEEPALIVE: | ||
260 | wdt_keepalive(); | ||
261 | return 0; | ||
262 | case WDIOC_SETOPTIONS: | ||
263 | { | ||
264 | int new_options, retval = -EINVAL; | ||
265 | |||
266 | if(get_user(new_options, p)) | ||
267 | return -EFAULT; | ||
268 | |||
269 | if(new_options & WDIOS_DISABLECARD) { | ||
270 | wdt_turnoff(); | ||
271 | retval = 0; | ||
272 | } | ||
273 | 265 | ||
274 | if(new_options & WDIOS_ENABLECARD) { | 266 | if (get_user(new_options, p)) |
275 | wdt_startup(); | 267 | return -EFAULT; |
276 | retval = 0; | ||
277 | } | ||
278 | 268 | ||
279 | return retval; | 269 | if (new_options & WDIOS_DISABLECARD) { |
270 | wdt_turnoff(); | ||
271 | retval = 0; | ||
280 | } | 272 | } |
281 | case WDIOC_SETTIMEOUT: | ||
282 | { | ||
283 | int new_timeout; | ||
284 | 273 | ||
285 | if(get_user(new_timeout, p)) | 274 | if (new_options & WDIOS_ENABLECARD) { |
286 | return -EFAULT; | 275 | wdt_startup(); |
276 | retval = 0; | ||
277 | } | ||
287 | 278 | ||
288 | if(new_timeout < 1 || new_timeout > 3600) /* arbitrary upper limit */ | 279 | return retval; |
289 | return -EINVAL; | 280 | } |
281 | case WDIOC_KEEPALIVE: | ||
282 | wdt_keepalive(); | ||
283 | return 0; | ||
284 | case WDIOC_SETTIMEOUT: | ||
285 | { | ||
286 | int new_timeout; | ||
290 | 287 | ||
291 | timeout = new_timeout; | 288 | if (get_user(new_timeout, p)) |
292 | wdt_keepalive(); | 289 | return -EFAULT; |
293 | /* Fall through */ | 290 | |
294 | } | 291 | /* arbitrary upper limit */ |
295 | case WDIOC_GETTIMEOUT: | 292 | if (new_timeout < 1 || new_timeout > 3600) |
296 | return put_user(timeout, p); | 293 | return -EINVAL; |
294 | |||
295 | timeout = new_timeout; | ||
296 | wdt_keepalive(); | ||
297 | /* Fall through */ | ||
298 | } | ||
299 | case WDIOC_GETTIMEOUT: | ||
300 | return put_user(timeout, p); | ||
301 | default: | ||
302 | return -ENOTTY; | ||
297 | } | 303 | } |
298 | } | 304 | } |
299 | 305 | ||
@@ -303,7 +309,7 @@ static const struct file_operations wdt_fops = { | |||
303 | .write = fop_write, | 309 | .write = fop_write, |
304 | .open = fop_open, | 310 | .open = fop_open, |
305 | .release = fop_close, | 311 | .release = fop_close, |
306 | .ioctl = fop_ioctl, | 312 | .unlocked_ioctl = fop_ioctl, |
307 | }; | 313 | }; |
308 | 314 | ||
309 | static struct miscdevice wdt_miscdev = { | 315 | static struct miscdevice wdt_miscdev = { |
@@ -319,7 +325,7 @@ static struct miscdevice wdt_miscdev = { | |||
319 | static int wdt_notify_sys(struct notifier_block *this, unsigned long code, | 325 | static int wdt_notify_sys(struct notifier_block *this, unsigned long code, |
320 | void *unused) | 326 | void *unused) |
321 | { | 327 | { |
322 | if(code==SYS_DOWN || code==SYS_HALT) | 328 | if (code == SYS_DOWN || code == SYS_HALT) |
323 | wdt_turnoff(); | 329 | wdt_turnoff(); |
324 | return NOTIFY_DONE; | 330 | return NOTIFY_DONE; |
325 | } | 331 | } |
@@ -329,8 +335,7 @@ static int wdt_notify_sys(struct notifier_block *this, unsigned long code, | |||
329 | * turn the timebomb registers off. | 335 | * turn the timebomb registers off. |
330 | */ | 336 | */ |
331 | 337 | ||
332 | static struct notifier_block wdt_notifier= | 338 | static struct notifier_block wdt_notifier = { |
333 | { | ||
334 | .notifier_call = wdt_notify_sys, | 339 | .notifier_call = wdt_notify_sys, |
335 | }; | 340 | }; |
336 | 341 | ||
@@ -342,31 +347,29 @@ static void __exit w83877f_wdt_unload(void) | |||
342 | misc_deregister(&wdt_miscdev); | 347 | misc_deregister(&wdt_miscdev); |
343 | 348 | ||
344 | unregister_reboot_notifier(&wdt_notifier); | 349 | unregister_reboot_notifier(&wdt_notifier); |
345 | release_region(WDT_PING,1); | 350 | release_region(WDT_PING, 1); |
346 | release_region(ENABLE_W83877F_PORT,2); | 351 | release_region(ENABLE_W83877F_PORT, 2); |
347 | } | 352 | } |
348 | 353 | ||
349 | static int __init w83877f_wdt_init(void) | 354 | static int __init w83877f_wdt_init(void) |
350 | { | 355 | { |
351 | int rc = -EBUSY; | 356 | int rc = -EBUSY; |
352 | 357 | ||
353 | if(timeout < 1 || timeout > 3600) /* arbitrary upper limit */ | 358 | if (timeout < 1 || timeout > 3600) { /* arbitrary upper limit */ |
354 | { | ||
355 | timeout = WATCHDOG_TIMEOUT; | 359 | timeout = WATCHDOG_TIMEOUT; |
356 | printk(KERN_INFO PFX "timeout value must be 1<=x<=3600, using %d\n", | 360 | printk(KERN_INFO PFX |
357 | timeout); | 361 | "timeout value must be 1 <= x <= 3600, using %d\n", |
362 | timeout); | ||
358 | } | 363 | } |
359 | 364 | ||
360 | if (!request_region(ENABLE_W83877F_PORT, 2, "W83877F WDT")) | 365 | if (!request_region(ENABLE_W83877F_PORT, 2, "W83877F WDT")) { |
361 | { | ||
362 | printk(KERN_ERR PFX "I/O address 0x%04x already in use\n", | 366 | printk(KERN_ERR PFX "I/O address 0x%04x already in use\n", |
363 | ENABLE_W83877F_PORT); | 367 | ENABLE_W83877F_PORT); |
364 | rc = -EIO; | 368 | rc = -EIO; |
365 | goto err_out; | 369 | goto err_out; |
366 | } | 370 | } |
367 | 371 | ||
368 | if (!request_region(WDT_PING, 1, "W8387FF WDT")) | 372 | if (!request_region(WDT_PING, 1, "W8387FF WDT")) { |
369 | { | ||
370 | printk(KERN_ERR PFX "I/O address 0x%04x already in use\n", | 373 | printk(KERN_ERR PFX "I/O address 0x%04x already in use\n", |
371 | WDT_PING); | 374 | WDT_PING); |
372 | rc = -EIO; | 375 | rc = -EIO; |
@@ -374,22 +377,22 @@ static int __init w83877f_wdt_init(void) | |||
374 | } | 377 | } |
375 | 378 | ||
376 | rc = register_reboot_notifier(&wdt_notifier); | 379 | rc = register_reboot_notifier(&wdt_notifier); |
377 | if (rc) | 380 | if (rc) { |
378 | { | 381 | printk(KERN_ERR PFX |
379 | printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", | 382 | "cannot register reboot notifier (err=%d)\n", rc); |
380 | rc); | ||
381 | goto err_out_region2; | 383 | goto err_out_region2; |
382 | } | 384 | } |
383 | 385 | ||
384 | rc = misc_register(&wdt_miscdev); | 386 | rc = misc_register(&wdt_miscdev); |
385 | if (rc) | 387 | if (rc) { |
386 | { | 388 | printk(KERN_ERR PFX |
387 | printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", | 389 | "cannot register miscdev on minor=%d (err=%d)\n", |
388 | wdt_miscdev.minor, rc); | 390 | wdt_miscdev.minor, rc); |
389 | goto err_out_reboot; | 391 | goto err_out_reboot; |
390 | } | 392 | } |
391 | 393 | ||
392 | printk(KERN_INFO PFX "WDT driver for W83877F initialised. timeout=%d sec (nowayout=%d)\n", | 394 | printk(KERN_INFO PFX |
395 | "WDT driver for W83877F initialised. timeout=%d sec (nowayout=%d)\n", | ||
393 | timeout, nowayout); | 396 | timeout, nowayout); |
394 | 397 | ||
395 | return 0; | 398 | return 0; |
@@ -397,9 +400,9 @@ static int __init w83877f_wdt_init(void) | |||
397 | err_out_reboot: | 400 | err_out_reboot: |
398 | unregister_reboot_notifier(&wdt_notifier); | 401 | unregister_reboot_notifier(&wdt_notifier); |
399 | err_out_region2: | 402 | err_out_region2: |
400 | release_region(WDT_PING,1); | 403 | release_region(WDT_PING, 1); |
401 | err_out_region1: | 404 | err_out_region1: |
402 | release_region(ENABLE_W83877F_PORT,2); | 405 | release_region(ENABLE_W83877F_PORT, 2); |
403 | err_out: | 406 | err_out: |
404 | return rc; | 407 | return rc; |
405 | } | 408 | } |
diff --git a/drivers/watchdog/w83977f_wdt.c b/drivers/watchdog/w83977f_wdt.c index b209bcd7f789..2525da5080ca 100644 --- a/drivers/watchdog/w83977f_wdt.c +++ b/drivers/watchdog/w83977f_wdt.c | |||
@@ -26,10 +26,10 @@ | |||
26 | #include <linux/watchdog.h> | 26 | #include <linux/watchdog.h> |
27 | #include <linux/notifier.h> | 27 | #include <linux/notifier.h> |
28 | #include <linux/reboot.h> | 28 | #include <linux/reboot.h> |
29 | #include <linux/uaccess.h> | ||
30 | #include <linux/io.h> | ||
29 | 31 | ||
30 | #include <asm/io.h> | ||
31 | #include <asm/system.h> | 32 | #include <asm/system.h> |
32 | #include <asm/uaccess.h> | ||
33 | 33 | ||
34 | #define WATCHDOG_VERSION "1.00" | 34 | #define WATCHDOG_VERSION "1.00" |
35 | #define WATCHDOG_NAME "W83977F WDT" | 35 | #define WATCHDOG_NAME "W83977F WDT" |
@@ -53,13 +53,17 @@ static char expect_close; | |||
53 | static DEFINE_SPINLOCK(spinlock); | 53 | static DEFINE_SPINLOCK(spinlock); |
54 | 54 | ||
55 | module_param(timeout, int, 0); | 55 | module_param(timeout, int, 0); |
56 | MODULE_PARM_DESC(timeout,"Watchdog timeout in seconds (15..7635), default=" __MODULE_STRING(DEFAULT_TIMEOUT) ")"); | 56 | MODULE_PARM_DESC(timeout, |
57 | "Watchdog timeout in seconds (15..7635), default=" | ||
58 | __MODULE_STRING(DEFAULT_TIMEOUT) ")"); | ||
57 | module_param(testmode, int, 0); | 59 | module_param(testmode, int, 0); |
58 | MODULE_PARM_DESC(testmode,"Watchdog testmode (1 = no reboot), default=0"); | 60 | MODULE_PARM_DESC(testmode, "Watchdog testmode (1 = no reboot), default=0"); |
59 | 61 | ||
60 | static int nowayout = WATCHDOG_NOWAYOUT; | 62 | static int nowayout = WATCHDOG_NOWAYOUT; |
61 | module_param(nowayout, int, 0); | 63 | module_param(nowayout, int, 0); |
62 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 64 | MODULE_PARM_DESC(nowayout, |
65 | "Watchdog cannot be stopped once started (default=" | ||
66 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
63 | 67 | ||
64 | /* | 68 | /* |
65 | * Start the watchdog | 69 | * Start the watchdog |
@@ -72,8 +76,8 @@ static int wdt_start(void) | |||
72 | spin_lock_irqsave(&spinlock, flags); | 76 | spin_lock_irqsave(&spinlock, flags); |
73 | 77 | ||
74 | /* Unlock the SuperIO chip */ | 78 | /* Unlock the SuperIO chip */ |
75 | outb_p(UNLOCK_DATA,IO_INDEX_PORT); | 79 | outb_p(UNLOCK_DATA, IO_INDEX_PORT); |
76 | outb_p(UNLOCK_DATA,IO_INDEX_PORT); | 80 | outb_p(UNLOCK_DATA, IO_INDEX_PORT); |
77 | 81 | ||
78 | /* | 82 | /* |
79 | * Select device Aux2 (device=8) to set watchdog regs F2, F3 and F4. | 83 | * Select device Aux2 (device=8) to set watchdog regs F2, F3 and F4. |
@@ -81,50 +85,49 @@ static int wdt_start(void) | |||
81 | * F3 is set to enable watchdog LED blink at timeout. | 85 | * F3 is set to enable watchdog LED blink at timeout. |
82 | * F4 is used to just clear the TIMEOUT'ed state (bit 0). | 86 | * F4 is used to just clear the TIMEOUT'ed state (bit 0). |
83 | */ | 87 | */ |
84 | outb_p(DEVICE_REGISTER,IO_INDEX_PORT); | 88 | outb_p(DEVICE_REGISTER, IO_INDEX_PORT); |
85 | outb_p(0x08,IO_DATA_PORT); | 89 | outb_p(0x08, IO_DATA_PORT); |
86 | outb_p(0xF2,IO_INDEX_PORT); | 90 | outb_p(0xF2, IO_INDEX_PORT); |
87 | outb_p(timeoutW,IO_DATA_PORT); | 91 | outb_p(timeoutW, IO_DATA_PORT); |
88 | outb_p(0xF3,IO_INDEX_PORT); | 92 | outb_p(0xF3, IO_INDEX_PORT); |
89 | outb_p(0x08,IO_DATA_PORT); | 93 | outb_p(0x08, IO_DATA_PORT); |
90 | outb_p(0xF4,IO_INDEX_PORT); | 94 | outb_p(0xF4, IO_INDEX_PORT); |
91 | outb_p(0x00,IO_DATA_PORT); | 95 | outb_p(0x00, IO_DATA_PORT); |
92 | 96 | ||
93 | /* Set device Aux2 active */ | 97 | /* Set device Aux2 active */ |
94 | outb_p(0x30,IO_INDEX_PORT); | 98 | outb_p(0x30, IO_INDEX_PORT); |
95 | outb_p(0x01,IO_DATA_PORT); | 99 | outb_p(0x01, IO_DATA_PORT); |
96 | 100 | ||
97 | /* | 101 | /* |
98 | * Select device Aux1 (dev=7) to set GP16 as the watchdog output | 102 | * Select device Aux1 (dev=7) to set GP16 as the watchdog output |
99 | * (in reg E6) and GP13 as the watchdog LED output (in reg E3). | 103 | * (in reg E6) and GP13 as the watchdog LED output (in reg E3). |
100 | * Map GP16 at pin 119. | 104 | * Map GP16 at pin 119. |
101 | * In test mode watch the bit 0 on F4 to indicate "triggered" or | 105 | * In test mode watch the bit 0 on F4 to indicate "triggered" or |
102 | * check watchdog LED on SBC. | 106 | * check watchdog LED on SBC. |
103 | */ | 107 | */ |
104 | outb_p(DEVICE_REGISTER,IO_INDEX_PORT); | 108 | outb_p(DEVICE_REGISTER, IO_INDEX_PORT); |
105 | outb_p(0x07,IO_DATA_PORT); | 109 | outb_p(0x07, IO_DATA_PORT); |
106 | if (!testmode) | 110 | if (!testmode) { |
107 | { | ||
108 | unsigned pin_map; | 111 | unsigned pin_map; |
109 | 112 | ||
110 | outb_p(0xE6,IO_INDEX_PORT); | 113 | outb_p(0xE6, IO_INDEX_PORT); |
111 | outb_p(0x0A,IO_DATA_PORT); | 114 | outb_p(0x0A, IO_DATA_PORT); |
112 | outb_p(0x2C,IO_INDEX_PORT); | 115 | outb_p(0x2C, IO_INDEX_PORT); |
113 | pin_map = inb_p(IO_DATA_PORT); | 116 | pin_map = inb_p(IO_DATA_PORT); |
114 | pin_map |= 0x10; | 117 | pin_map |= 0x10; |
115 | pin_map &= ~(0x20); | 118 | pin_map &= ~(0x20); |
116 | outb_p(0x2C,IO_INDEX_PORT); | 119 | outb_p(0x2C, IO_INDEX_PORT); |
117 | outb_p(pin_map,IO_DATA_PORT); | 120 | outb_p(pin_map, IO_DATA_PORT); |
118 | } | 121 | } |
119 | outb_p(0xE3,IO_INDEX_PORT); | 122 | outb_p(0xE3, IO_INDEX_PORT); |
120 | outb_p(0x08,IO_DATA_PORT); | 123 | outb_p(0x08, IO_DATA_PORT); |
121 | 124 | ||
122 | /* Set device Aux1 active */ | 125 | /* Set device Aux1 active */ |
123 | outb_p(0x30,IO_INDEX_PORT); | 126 | outb_p(0x30, IO_INDEX_PORT); |
124 | outb_p(0x01,IO_DATA_PORT); | 127 | outb_p(0x01, IO_DATA_PORT); |
125 | 128 | ||
126 | /* Lock the SuperIO chip */ | 129 | /* Lock the SuperIO chip */ |
127 | outb_p(LOCK_DATA,IO_INDEX_PORT); | 130 | outb_p(LOCK_DATA, IO_INDEX_PORT); |
128 | 131 | ||
129 | spin_unlock_irqrestore(&spinlock, flags); | 132 | spin_unlock_irqrestore(&spinlock, flags); |
130 | 133 | ||
@@ -144,42 +147,41 @@ static int wdt_stop(void) | |||
144 | spin_lock_irqsave(&spinlock, flags); | 147 | spin_lock_irqsave(&spinlock, flags); |
145 | 148 | ||
146 | /* Unlock the SuperIO chip */ | 149 | /* Unlock the SuperIO chip */ |
147 | outb_p(UNLOCK_DATA,IO_INDEX_PORT); | 150 | outb_p(UNLOCK_DATA, IO_INDEX_PORT); |
148 | outb_p(UNLOCK_DATA,IO_INDEX_PORT); | 151 | outb_p(UNLOCK_DATA, IO_INDEX_PORT); |
149 | 152 | ||
150 | /* | 153 | /* |
151 | * Select device Aux2 (device=8) to set watchdog regs F2, F3 and F4. | 154 | * Select device Aux2 (device=8) to set watchdog regs F2, F3 and F4. |
152 | * F2 is reset to its default value (watchdog timer disabled). | 155 | * F2 is reset to its default value (watchdog timer disabled). |
153 | * F3 is reset to its default state. | 156 | * F3 is reset to its default state. |
154 | * F4 clears the TIMEOUT'ed state (bit 0) - back to default. | 157 | * F4 clears the TIMEOUT'ed state (bit 0) - back to default. |
155 | */ | 158 | */ |
156 | outb_p(DEVICE_REGISTER,IO_INDEX_PORT); | 159 | outb_p(DEVICE_REGISTER, IO_INDEX_PORT); |
157 | outb_p(0x08,IO_DATA_PORT); | 160 | outb_p(0x08, IO_DATA_PORT); |
158 | outb_p(0xF2,IO_INDEX_PORT); | 161 | outb_p(0xF2, IO_INDEX_PORT); |
159 | outb_p(0xFF,IO_DATA_PORT); | 162 | outb_p(0xFF, IO_DATA_PORT); |
160 | outb_p(0xF3,IO_INDEX_PORT); | 163 | outb_p(0xF3, IO_INDEX_PORT); |
161 | outb_p(0x00,IO_DATA_PORT); | 164 | outb_p(0x00, IO_DATA_PORT); |
162 | outb_p(0xF4,IO_INDEX_PORT); | 165 | outb_p(0xF4, IO_INDEX_PORT); |
163 | outb_p(0x00,IO_DATA_PORT); | 166 | outb_p(0x00, IO_DATA_PORT); |
164 | outb_p(0xF2,IO_INDEX_PORT); | 167 | outb_p(0xF2, IO_INDEX_PORT); |
165 | outb_p(0x00,IO_DATA_PORT); | 168 | outb_p(0x00, IO_DATA_PORT); |
166 | 169 | ||
167 | /* | 170 | /* |
168 | * Select device Aux1 (dev=7) to set GP16 (in reg E6) and | 171 | * Select device Aux1 (dev=7) to set GP16 (in reg E6) and |
169 | * Gp13 (in reg E3) as inputs. | 172 | * Gp13 (in reg E3) as inputs. |
170 | */ | 173 | */ |
171 | outb_p(DEVICE_REGISTER,IO_INDEX_PORT); | 174 | outb_p(DEVICE_REGISTER, IO_INDEX_PORT); |
172 | outb_p(0x07,IO_DATA_PORT); | 175 | outb_p(0x07, IO_DATA_PORT); |
173 | if (!testmode) | 176 | if (!testmode) { |
174 | { | 177 | outb_p(0xE6, IO_INDEX_PORT); |
175 | outb_p(0xE6,IO_INDEX_PORT); | 178 | outb_p(0x01, IO_DATA_PORT); |
176 | outb_p(0x01,IO_DATA_PORT); | ||
177 | } | 179 | } |
178 | outb_p(0xE3,IO_INDEX_PORT); | 180 | outb_p(0xE3, IO_INDEX_PORT); |
179 | outb_p(0x01,IO_DATA_PORT); | 181 | outb_p(0x01, IO_DATA_PORT); |
180 | 182 | ||
181 | /* Lock the SuperIO chip */ | 183 | /* Lock the SuperIO chip */ |
182 | outb_p(LOCK_DATA,IO_INDEX_PORT); | 184 | outb_p(LOCK_DATA, IO_INDEX_PORT); |
183 | 185 | ||
184 | spin_unlock_irqrestore(&spinlock, flags); | 186 | spin_unlock_irqrestore(&spinlock, flags); |
185 | 187 | ||
@@ -200,17 +202,17 @@ static int wdt_keepalive(void) | |||
200 | spin_lock_irqsave(&spinlock, flags); | 202 | spin_lock_irqsave(&spinlock, flags); |
201 | 203 | ||
202 | /* Unlock the SuperIO chip */ | 204 | /* Unlock the SuperIO chip */ |
203 | outb_p(UNLOCK_DATA,IO_INDEX_PORT); | 205 | outb_p(UNLOCK_DATA, IO_INDEX_PORT); |
204 | outb_p(UNLOCK_DATA,IO_INDEX_PORT); | 206 | outb_p(UNLOCK_DATA, IO_INDEX_PORT); |
205 | 207 | ||
206 | /* Select device Aux2 (device=8) to kick watchdog reg F2 */ | 208 | /* Select device Aux2 (device=8) to kick watchdog reg F2 */ |
207 | outb_p(DEVICE_REGISTER,IO_INDEX_PORT); | 209 | outb_p(DEVICE_REGISTER, IO_INDEX_PORT); |
208 | outb_p(0x08,IO_DATA_PORT); | 210 | outb_p(0x08, IO_DATA_PORT); |
209 | outb_p(0xF2,IO_INDEX_PORT); | 211 | outb_p(0xF2, IO_INDEX_PORT); |
210 | outb_p(timeoutW,IO_DATA_PORT); | 212 | outb_p(timeoutW, IO_DATA_PORT); |
211 | 213 | ||
212 | /* Lock the SuperIO chip */ | 214 | /* Lock the SuperIO chip */ |
213 | outb_p(LOCK_DATA,IO_INDEX_PORT); | 215 | outb_p(LOCK_DATA, IO_INDEX_PORT); |
214 | 216 | ||
215 | spin_unlock_irqrestore(&spinlock, flags); | 217 | spin_unlock_irqrestore(&spinlock, flags); |
216 | 218 | ||
@@ -227,7 +229,7 @@ static int wdt_set_timeout(int t) | |||
227 | 229 | ||
228 | /* | 230 | /* |
229 | * Convert seconds to watchdog counter time units, rounding up. | 231 | * Convert seconds to watchdog counter time units, rounding up. |
230 | * On PCM-5335 watchdog units are 30 seconds/step with 15 sec startup | 232 | * On PCM-5335 watchdog units are 30 seconds/step with 15 sec startup |
231 | * value. This information is supplied in the PCM-5335 manual and was | 233 | * value. This information is supplied in the PCM-5335 manual and was |
232 | * checked by me on a real board. This is a bit strange because W83977f | 234 | * checked by me on a real board. This is a bit strange because W83977f |
233 | * datasheet says counter unit is in minutes! | 235 | * datasheet says counter unit is in minutes! |
@@ -241,7 +243,7 @@ static int wdt_set_timeout(int t) | |||
241 | return -EINVAL; | 243 | return -EINVAL; |
242 | 244 | ||
243 | /* | 245 | /* |
244 | * timeout is the timeout in seconds, | 246 | * timeout is the timeout in seconds, |
245 | * timeoutW is the timeout in watchdog counter units. | 247 | * timeoutW is the timeout in watchdog counter units. |
246 | */ | 248 | */ |
247 | timeoutW = tmrval; | 249 | timeoutW = tmrval; |
@@ -261,17 +263,17 @@ static int wdt_get_status(int *status) | |||
261 | spin_lock_irqsave(&spinlock, flags); | 263 | spin_lock_irqsave(&spinlock, flags); |
262 | 264 | ||
263 | /* Unlock the SuperIO chip */ | 265 | /* Unlock the SuperIO chip */ |
264 | outb_p(UNLOCK_DATA,IO_INDEX_PORT); | 266 | outb_p(UNLOCK_DATA, IO_INDEX_PORT); |
265 | outb_p(UNLOCK_DATA,IO_INDEX_PORT); | 267 | outb_p(UNLOCK_DATA, IO_INDEX_PORT); |
266 | 268 | ||
267 | /* Select device Aux2 (device=8) to read watchdog reg F4 */ | 269 | /* Select device Aux2 (device=8) to read watchdog reg F4 */ |
268 | outb_p(DEVICE_REGISTER,IO_INDEX_PORT); | 270 | outb_p(DEVICE_REGISTER, IO_INDEX_PORT); |
269 | outb_p(0x08,IO_DATA_PORT); | 271 | outb_p(0x08, IO_DATA_PORT); |
270 | outb_p(0xF4,IO_INDEX_PORT); | 272 | outb_p(0xF4, IO_INDEX_PORT); |
271 | new_status = inb_p(IO_DATA_PORT); | 273 | new_status = inb_p(IO_DATA_PORT); |
272 | 274 | ||
273 | /* Lock the SuperIO chip */ | 275 | /* Lock the SuperIO chip */ |
274 | outb_p(LOCK_DATA,IO_INDEX_PORT); | 276 | outb_p(LOCK_DATA, IO_INDEX_PORT); |
275 | 277 | ||
276 | spin_unlock_irqrestore(&spinlock, flags); | 278 | spin_unlock_irqrestore(&spinlock, flags); |
277 | 279 | ||
@@ -290,7 +292,7 @@ static int wdt_get_status(int *status) | |||
290 | static int wdt_open(struct inode *inode, struct file *file) | 292 | static int wdt_open(struct inode *inode, struct file *file) |
291 | { | 293 | { |
292 | /* If the watchdog is alive we don't need to start it again */ | 294 | /* If the watchdog is alive we don't need to start it again */ |
293 | if( test_and_set_bit(0, &timer_alive) ) | 295 | if (test_and_set_bit(0, &timer_alive)) |
294 | return -EBUSY; | 296 | return -EBUSY; |
295 | 297 | ||
296 | if (nowayout) | 298 | if (nowayout) |
@@ -306,13 +308,13 @@ static int wdt_release(struct inode *inode, struct file *file) | |||
306 | * Shut off the timer. | 308 | * Shut off the timer. |
307 | * Lock it in if it's a module and we set nowayout | 309 | * Lock it in if it's a module and we set nowayout |
308 | */ | 310 | */ |
309 | if (expect_close == 42) | 311 | if (expect_close == 42) { |
310 | { | ||
311 | wdt_stop(); | 312 | wdt_stop(); |
312 | clear_bit(0, &timer_alive); | 313 | clear_bit(0, &timer_alive); |
313 | } else { | 314 | } else { |
314 | wdt_keepalive(); | 315 | wdt_keepalive(); |
315 | printk(KERN_CRIT PFX "unexpected close, not stopping watchdog!\n"); | 316 | printk(KERN_CRIT PFX |
317 | "unexpected close, not stopping watchdog!\n"); | ||
316 | } | 318 | } |
317 | expect_close = 0; | 319 | expect_close = 0; |
318 | return 0; | 320 | return 0; |
@@ -333,24 +335,22 @@ static ssize_t wdt_write(struct file *file, const char __user *buf, | |||
333 | size_t count, loff_t *ppos) | 335 | size_t count, loff_t *ppos) |
334 | { | 336 | { |
335 | /* See if we got the magic character 'V' and reload the timer */ | 337 | /* See if we got the magic character 'V' and reload the timer */ |
336 | if(count) | 338 | if (count) { |
337 | { | 339 | if (!nowayout) { |
338 | if (!nowayout) | ||
339 | { | ||
340 | size_t ofs; | 340 | size_t ofs; |
341 | 341 | ||
342 | /* note: just in case someone wrote the magic character long ago */ | 342 | /* note: just in case someone wrote the |
343 | magic character long ago */ | ||
343 | expect_close = 0; | 344 | expect_close = 0; |
344 | 345 | ||
345 | /* scan to see whether or not we got the magic character */ | 346 | /* scan to see whether or not we got the |
346 | for(ofs = 0; ofs != count; ofs++) | 347 | magic character */ |
347 | { | 348 | for (ofs = 0; ofs != count; ofs++) { |
348 | char c; | 349 | char c; |
349 | if (get_user(c, buf + ofs)) | 350 | if (get_user(c, buf + ofs)) |
350 | return -EFAULT; | 351 | return -EFAULT; |
351 | if (c == 'V') { | 352 | if (c == 'V') |
352 | expect_close = 42; | 353 | expect_close = 42; |
353 | } | ||
354 | } | 354 | } |
355 | } | 355 | } |
356 | 356 | ||
@@ -377,8 +377,7 @@ static struct watchdog_info ident = { | |||
377 | .identity = WATCHDOG_NAME, | 377 | .identity = WATCHDOG_NAME, |
378 | }; | 378 | }; |
379 | 379 | ||
380 | static int wdt_ioctl(struct inode *inode, struct file *file, | 380 | static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
381 | unsigned int cmd, unsigned long arg) | ||
382 | { | 381 | { |
383 | int status; | 382 | int status; |
384 | int new_options, retval = -EINVAL; | 383 | int new_options, retval = -EINVAL; |
@@ -390,13 +389,10 @@ static int wdt_ioctl(struct inode *inode, struct file *file, | |||
390 | 389 | ||
391 | uarg.i = (int __user *)arg; | 390 | uarg.i = (int __user *)arg; |
392 | 391 | ||
393 | switch(cmd) | 392 | switch (cmd) { |
394 | { | ||
395 | default: | ||
396 | return -ENOTTY; | ||
397 | |||
398 | case WDIOC_GETSUPPORT: | 393 | case WDIOC_GETSUPPORT: |
399 | return copy_to_user(uarg.ident, &ident, sizeof(ident)) ? -EFAULT : 0; | 394 | return copy_to_user(uarg.ident, &ident, |
395 | sizeof(ident)) ? -EFAULT : 0; | ||
400 | 396 | ||
401 | case WDIOC_GETSTATUS: | 397 | case WDIOC_GETSTATUS: |
402 | wdt_get_status(&status); | 398 | wdt_get_status(&status); |
@@ -405,12 +401,8 @@ static int wdt_ioctl(struct inode *inode, struct file *file, | |||
405 | case WDIOC_GETBOOTSTATUS: | 401 | case WDIOC_GETBOOTSTATUS: |
406 | return put_user(0, uarg.i); | 402 | return put_user(0, uarg.i); |
407 | 403 | ||
408 | case WDIOC_KEEPALIVE: | ||
409 | wdt_keepalive(); | ||
410 | return 0; | ||
411 | |||
412 | case WDIOC_SETOPTIONS: | 404 | case WDIOC_SETOPTIONS: |
413 | if (get_user (new_options, uarg.i)) | 405 | if (get_user(new_options, uarg.i)) |
414 | return -EFAULT; | 406 | return -EFAULT; |
415 | 407 | ||
416 | if (new_options & WDIOS_DISABLECARD) { | 408 | if (new_options & WDIOS_DISABLECARD) { |
@@ -425,6 +417,10 @@ static int wdt_ioctl(struct inode *inode, struct file *file, | |||
425 | 417 | ||
426 | return retval; | 418 | return retval; |
427 | 419 | ||
420 | case WDIOC_KEEPALIVE: | ||
421 | wdt_keepalive(); | ||
422 | return 0; | ||
423 | |||
428 | case WDIOC_SETTIMEOUT: | 424 | case WDIOC_SETTIMEOUT: |
429 | if (get_user(new_timeout, uarg.i)) | 425 | if (get_user(new_timeout, uarg.i)) |
430 | return -EFAULT; | 426 | return -EFAULT; |
@@ -438,29 +434,30 @@ static int wdt_ioctl(struct inode *inode, struct file *file, | |||
438 | case WDIOC_GETTIMEOUT: | 434 | case WDIOC_GETTIMEOUT: |
439 | return put_user(timeout, uarg.i); | 435 | return put_user(timeout, uarg.i); |
440 | 436 | ||
437 | default: | ||
438 | return -ENOTTY; | ||
439 | |||
441 | } | 440 | } |
442 | } | 441 | } |
443 | 442 | ||
444 | static int wdt_notify_sys(struct notifier_block *this, unsigned long code, | 443 | static int wdt_notify_sys(struct notifier_block *this, unsigned long code, |
445 | void *unused) | 444 | void *unused) |
446 | { | 445 | { |
447 | if (code==SYS_DOWN || code==SYS_HALT) | 446 | if (code == SYS_DOWN || code == SYS_HALT) |
448 | wdt_stop(); | 447 | wdt_stop(); |
449 | return NOTIFY_DONE; | 448 | return NOTIFY_DONE; |
450 | } | 449 | } |
451 | 450 | ||
452 | static const struct file_operations wdt_fops= | 451 | static const struct file_operations wdt_fops = { |
453 | { | ||
454 | .owner = THIS_MODULE, | 452 | .owner = THIS_MODULE, |
455 | .llseek = no_llseek, | 453 | .llseek = no_llseek, |
456 | .write = wdt_write, | 454 | .write = wdt_write, |
457 | .ioctl = wdt_ioctl, | 455 | .unlocked_ioctl = wdt_ioctl, |
458 | .open = wdt_open, | 456 | .open = wdt_open, |
459 | .release = wdt_release, | 457 | .release = wdt_release, |
460 | }; | 458 | }; |
461 | 459 | ||
462 | static struct miscdevice wdt_miscdev= | 460 | static struct miscdevice wdt_miscdev = { |
463 | { | ||
464 | .minor = WATCHDOG_MINOR, | 461 | .minor = WATCHDOG_MINOR, |
465 | .name = "watchdog", | 462 | .name = "watchdog", |
466 | .fops = &wdt_fops, | 463 | .fops = &wdt_fops, |
@@ -474,20 +471,20 @@ static int __init w83977f_wdt_init(void) | |||
474 | { | 471 | { |
475 | int rc; | 472 | int rc; |
476 | 473 | ||
477 | printk(KERN_INFO PFX DRIVER_VERSION); | 474 | printk(KERN_INFO PFX DRIVER_VERSION); |
478 | 475 | ||
479 | /* | 476 | /* |
480 | * Check that the timeout value is within it's range ; | 477 | * Check that the timeout value is within it's range; |
481 | * if not reset to the default | 478 | * if not reset to the default |
482 | */ | 479 | */ |
483 | if (wdt_set_timeout(timeout)) { | 480 | if (wdt_set_timeout(timeout)) { |
484 | wdt_set_timeout(DEFAULT_TIMEOUT); | 481 | wdt_set_timeout(DEFAULT_TIMEOUT); |
485 | printk(KERN_INFO PFX "timeout value must be 15<=timeout<=7635, using %d\n", | 482 | printk(KERN_INFO PFX |
486 | DEFAULT_TIMEOUT); | 483 | "timeout value must be 15 <= timeout <= 7635, using %d\n", |
484 | DEFAULT_TIMEOUT); | ||
487 | } | 485 | } |
488 | 486 | ||
489 | if (!request_region(IO_INDEX_PORT, 2, WATCHDOG_NAME)) | 487 | if (!request_region(IO_INDEX_PORT, 2, WATCHDOG_NAME)) { |
490 | { | ||
491 | printk(KERN_ERR PFX "I/O address 0x%04x already in use\n", | 488 | printk(KERN_ERR PFX "I/O address 0x%04x already in use\n", |
492 | IO_INDEX_PORT); | 489 | IO_INDEX_PORT); |
493 | rc = -EIO; | 490 | rc = -EIO; |
@@ -495,30 +492,30 @@ static int __init w83977f_wdt_init(void) | |||
495 | } | 492 | } |
496 | 493 | ||
497 | rc = register_reboot_notifier(&wdt_notifier); | 494 | rc = register_reboot_notifier(&wdt_notifier); |
498 | if (rc) | 495 | if (rc) { |
499 | { | 496 | printk(KERN_ERR PFX |
500 | printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", | 497 | "cannot register reboot notifier (err=%d)\n", rc); |
501 | rc); | ||
502 | goto err_out_region; | 498 | goto err_out_region; |
503 | } | 499 | } |
504 | 500 | ||
505 | rc = misc_register(&wdt_miscdev); | 501 | rc = misc_register(&wdt_miscdev); |
506 | if (rc) | 502 | if (rc) { |
507 | { | 503 | printk(KERN_ERR PFX |
508 | printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", | 504 | "cannot register miscdev on minor=%d (err=%d)\n", |
509 | wdt_miscdev.minor, rc); | 505 | wdt_miscdev.minor, rc); |
510 | goto err_out_reboot; | 506 | goto err_out_reboot; |
511 | } | 507 | } |
512 | 508 | ||
513 | printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d testmode=%d)\n", | 509 | printk(KERN_INFO PFX |
514 | timeout, nowayout, testmode); | 510 | "initialized. timeout=%d sec (nowayout=%d testmode=%d)\n", |
511 | timeout, nowayout, testmode); | ||
515 | 512 | ||
516 | return 0; | 513 | return 0; |
517 | 514 | ||
518 | err_out_reboot: | 515 | err_out_reboot: |
519 | unregister_reboot_notifier(&wdt_notifier); | 516 | unregister_reboot_notifier(&wdt_notifier); |
520 | err_out_region: | 517 | err_out_region: |
521 | release_region(IO_INDEX_PORT,2); | 518 | release_region(IO_INDEX_PORT, 2); |
522 | err_out: | 519 | err_out: |
523 | return rc; | 520 | return rc; |
524 | } | 521 | } |
@@ -528,7 +525,7 @@ static void __exit w83977f_wdt_exit(void) | |||
528 | wdt_stop(); | 525 | wdt_stop(); |
529 | misc_deregister(&wdt_miscdev); | 526 | misc_deregister(&wdt_miscdev); |
530 | unregister_reboot_notifier(&wdt_notifier); | 527 | unregister_reboot_notifier(&wdt_notifier); |
531 | release_region(IO_INDEX_PORT,2); | 528 | release_region(IO_INDEX_PORT, 2); |
532 | } | 529 | } |
533 | 530 | ||
534 | module_init(w83977f_wdt_init); | 531 | module_init(w83977f_wdt_init); |
diff --git a/drivers/watchdog/wafer5823wdt.c b/drivers/watchdog/wafer5823wdt.c index 9e368091f799..68377ae171ff 100644 --- a/drivers/watchdog/wafer5823wdt.c +++ b/drivers/watchdog/wafer5823wdt.c | |||
@@ -1,11 +1,11 @@ | |||
1 | /* | 1 | /* |
2 | * ICP Wafer 5823 Single Board Computer WDT driver | 2 | * ICP Wafer 5823 Single Board Computer WDT driver |
3 | * http://www.icpamerica.com/wafer_5823.php | 3 | * http://www.icpamerica.com/wafer_5823.php |
4 | * May also work on other similar models | 4 | * May also work on other similar models |
5 | * | 5 | * |
6 | * (c) Copyright 2002 Justin Cormack <justin@street-vision.com> | 6 | * (c) Copyright 2002 Justin Cormack <justin@street-vision.com> |
7 | * | 7 | * |
8 | * Release 0.02 | 8 | * Release 0.02 |
9 | * | 9 | * |
10 | * Based on advantechwdt.c which is based on wdt.c. | 10 | * Based on advantechwdt.c which is based on wdt.c. |
11 | * Original copyright messages: | 11 | * Original copyright messages: |
@@ -36,8 +36,8 @@ | |||
36 | #include <linux/reboot.h> | 36 | #include <linux/reboot.h> |
37 | #include <linux/init.h> | 37 | #include <linux/init.h> |
38 | #include <linux/spinlock.h> | 38 | #include <linux/spinlock.h> |
39 | #include <asm/io.h> | 39 | #include <linux/io.h> |
40 | #include <asm/uaccess.h> | 40 | #include <linux/uaccess.h> |
41 | 41 | ||
42 | #define WATCHDOG_NAME "Wafer 5823 WDT" | 42 | #define WATCHDOG_NAME "Wafer 5823 WDT" |
43 | #define PFX WATCHDOG_NAME ": " | 43 | #define PFX WATCHDOG_NAME ": " |
@@ -50,10 +50,10 @@ static DEFINE_SPINLOCK(wafwdt_lock); | |||
50 | /* | 50 | /* |
51 | * You must set these - there is no sane way to probe for this board. | 51 | * You must set these - there is no sane way to probe for this board. |
52 | * | 52 | * |
53 | * To enable, write the timeout value in seconds (1 to 255) to I/O | 53 | * To enable, write the timeout value in seconds (1 to 255) to I/O |
54 | * port WDT_START, then read the port to start the watchdog. To pat | 54 | * port WDT_START, then read the port to start the watchdog. To pat |
55 | * the dog, read port WDT_STOP to stop the timer, then read WDT_START | 55 | * the dog, read port WDT_STOP to stop the timer, then read WDT_START |
56 | * to restart it again. | 56 | * to restart it again. |
57 | */ | 57 | */ |
58 | 58 | ||
59 | static int wdt_stop = 0x843; | 59 | static int wdt_stop = 0x843; |
@@ -61,11 +61,15 @@ static int wdt_start = 0x443; | |||
61 | 61 | ||
62 | static int timeout = WD_TIMO; /* in seconds */ | 62 | static int timeout = WD_TIMO; /* in seconds */ |
63 | module_param(timeout, int, 0); | 63 | module_param(timeout, int, 0); |
64 | MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=255, default=" __MODULE_STRING(WD_TIMO) "."); | 64 | MODULE_PARM_DESC(timeout, |
65 | "Watchdog timeout in seconds. 1 <= timeout <= 255, default=" | ||
66 | __MODULE_STRING(WD_TIMO) "."); | ||
65 | 67 | ||
66 | static int nowayout = WATCHDOG_NOWAYOUT; | 68 | static int nowayout = WATCHDOG_NOWAYOUT; |
67 | module_param(nowayout, int, 0); | 69 | module_param(nowayout, int, 0); |
68 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 70 | MODULE_PARM_DESC(nowayout, |
71 | "Watchdog cannot be stopped once started (default=" | ||
72 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
69 | 73 | ||
70 | static void wafwdt_ping(void) | 74 | static void wafwdt_ping(void) |
71 | { | 75 | { |
@@ -83,14 +87,14 @@ static void wafwdt_start(void) | |||
83 | inb_p(wdt_start); | 87 | inb_p(wdt_start); |
84 | } | 88 | } |
85 | 89 | ||
86 | static void | 90 | static void wafwdt_stop(void) |
87 | wafwdt_stop(void) | ||
88 | { | 91 | { |
89 | /* stop watchdog */ | 92 | /* stop watchdog */ |
90 | inb_p(wdt_stop); | 93 | inb_p(wdt_stop); |
91 | } | 94 | } |
92 | 95 | ||
93 | static ssize_t wafwdt_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos) | 96 | static ssize_t wafwdt_write(struct file *file, const char __user *buf, |
97 | size_t count, loff_t *ppos) | ||
94 | { | 98 | { |
95 | /* See if we got the magic character 'V' and reload the timer */ | 99 | /* See if we got the magic character 'V' and reload the timer */ |
96 | if (count) { | 100 | if (count) { |
@@ -100,7 +104,8 @@ static ssize_t wafwdt_write(struct file *file, const char __user *buf, size_t co | |||
100 | /* In case it was set long ago */ | 104 | /* In case it was set long ago */ |
101 | expect_close = 0; | 105 | expect_close = 0; |
102 | 106 | ||
103 | /* scan to see whether or not we got the magic character */ | 107 | /* scan to see whether or not we got the magic |
108 | character */ | ||
104 | for (i = 0; i != count; i++) { | 109 | for (i = 0; i != count; i++) { |
105 | char c; | 110 | char c; |
106 | if (get_user(c, buf + i)) | 111 | if (get_user(c, buf + i)) |
@@ -109,27 +114,29 @@ static ssize_t wafwdt_write(struct file *file, const char __user *buf, size_t co | |||
109 | expect_close = 42; | 114 | expect_close = 42; |
110 | } | 115 | } |
111 | } | 116 | } |
112 | /* Well, anyhow someone wrote to us, we should return that favour */ | 117 | /* Well, anyhow someone wrote to us, we should |
118 | return that favour */ | ||
113 | wafwdt_ping(); | 119 | wafwdt_ping(); |
114 | } | 120 | } |
115 | return count; | 121 | return count; |
116 | } | 122 | } |
117 | 123 | ||
118 | static int wafwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | 124 | static long wafwdt_ioctl(struct file *file, unsigned int cmd, |
119 | unsigned long arg) | 125 | unsigned long arg) |
120 | { | 126 | { |
121 | int new_timeout; | 127 | int new_timeout; |
122 | void __user *argp = (void __user *)arg; | 128 | void __user *argp = (void __user *)arg; |
123 | int __user *p = argp; | 129 | int __user *p = argp; |
124 | static struct watchdog_info ident = { | 130 | static const struct watchdog_info ident = { |
125 | .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, | 131 | .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | |
132 | WDIOF_MAGICCLOSE, | ||
126 | .firmware_version = 1, | 133 | .firmware_version = 1, |
127 | .identity = "Wafer 5823 WDT", | 134 | .identity = "Wafer 5823 WDT", |
128 | }; | 135 | }; |
129 | 136 | ||
130 | switch (cmd) { | 137 | switch (cmd) { |
131 | case WDIOC_GETSUPPORT: | 138 | case WDIOC_GETSUPPORT: |
132 | if (copy_to_user(argp, &ident, sizeof (ident))) | 139 | if (copy_to_user(argp, &ident, sizeof(ident))) |
133 | return -EFAULT; | 140 | return -EFAULT; |
134 | break; | 141 | break; |
135 | 142 | ||
@@ -137,22 +144,6 @@ static int wafwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd | |||
137 | case WDIOC_GETBOOTSTATUS: | 144 | case WDIOC_GETBOOTSTATUS: |
138 | return put_user(0, p); | 145 | return put_user(0, p); |
139 | 146 | ||
140 | case WDIOC_KEEPALIVE: | ||
141 | wafwdt_ping(); | ||
142 | break; | ||
143 | |||
144 | case WDIOC_SETTIMEOUT: | ||
145 | if (get_user(new_timeout, p)) | ||
146 | return -EFAULT; | ||
147 | if ((new_timeout < 1) || (new_timeout > 255)) | ||
148 | return -EINVAL; | ||
149 | timeout = new_timeout; | ||
150 | wafwdt_stop(); | ||
151 | wafwdt_start(); | ||
152 | /* Fall */ | ||
153 | case WDIOC_GETTIMEOUT: | ||
154 | return put_user(timeout, p); | ||
155 | |||
156 | case WDIOC_SETOPTIONS: | 147 | case WDIOC_SETOPTIONS: |
157 | { | 148 | { |
158 | int options, retval = -EINVAL; | 149 | int options, retval = -EINVAL; |
@@ -173,6 +164,22 @@ static int wafwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd | |||
173 | return retval; | 164 | return retval; |
174 | } | 165 | } |
175 | 166 | ||
167 | case WDIOC_KEEPALIVE: | ||
168 | wafwdt_ping(); | ||
169 | break; | ||
170 | |||
171 | case WDIOC_SETTIMEOUT: | ||
172 | if (get_user(new_timeout, p)) | ||
173 | return -EFAULT; | ||
174 | if ((new_timeout < 1) || (new_timeout > 255)) | ||
175 | return -EINVAL; | ||
176 | timeout = new_timeout; | ||
177 | wafwdt_stop(); | ||
178 | wafwdt_start(); | ||
179 | /* Fall */ | ||
180 | case WDIOC_GETTIMEOUT: | ||
181 | return put_user(timeout, p); | ||
182 | |||
176 | default: | 183 | default: |
177 | return -ENOTTY; | 184 | return -ENOTTY; |
178 | } | 185 | } |
@@ -191,13 +198,13 @@ static int wafwdt_open(struct inode *inode, struct file *file) | |||
191 | return nonseekable_open(inode, file); | 198 | return nonseekable_open(inode, file); |
192 | } | 199 | } |
193 | 200 | ||
194 | static int | 201 | static int wafwdt_close(struct inode *inode, struct file *file) |
195 | wafwdt_close(struct inode *inode, struct file *file) | ||
196 | { | 202 | { |
197 | if (expect_close == 42) { | 203 | if (expect_close == 42) |
198 | wafwdt_stop(); | 204 | wafwdt_stop(); |
199 | } else { | 205 | else { |
200 | printk(KERN_CRIT PFX "WDT device closed unexpectedly. WDT will not stop!\n"); | 206 | printk(KERN_CRIT PFX |
207 | "WDT device closed unexpectedly. WDT will not stop!\n"); | ||
201 | wafwdt_ping(); | 208 | wafwdt_ping(); |
202 | } | 209 | } |
203 | clear_bit(0, &wafwdt_is_open); | 210 | clear_bit(0, &wafwdt_is_open); |
@@ -209,12 +216,11 @@ wafwdt_close(struct inode *inode, struct file *file) | |||
209 | * Notifier for system down | 216 | * Notifier for system down |
210 | */ | 217 | */ |
211 | 218 | ||
212 | static int wafwdt_notify_sys(struct notifier_block *this, unsigned long code, void *unused) | 219 | static int wafwdt_notify_sys(struct notifier_block *this, unsigned long code, |
220 | void *unused) | ||
213 | { | 221 | { |
214 | if (code == SYS_DOWN || code == SYS_HALT) { | 222 | if (code == SYS_DOWN || code == SYS_HALT) |
215 | /* Turn the WDT off */ | ||
216 | wafwdt_stop(); | 223 | wafwdt_stop(); |
217 | } | ||
218 | return NOTIFY_DONE; | 224 | return NOTIFY_DONE; |
219 | } | 225 | } |
220 | 226 | ||
@@ -226,7 +232,7 @@ static const struct file_operations wafwdt_fops = { | |||
226 | .owner = THIS_MODULE, | 232 | .owner = THIS_MODULE, |
227 | .llseek = no_llseek, | 233 | .llseek = no_llseek, |
228 | .write = wafwdt_write, | 234 | .write = wafwdt_write, |
229 | .ioctl = wafwdt_ioctl, | 235 | .unlocked_ioctl = wafwdt_ioctl, |
230 | .open = wafwdt_open, | 236 | .open = wafwdt_open, |
231 | .release = wafwdt_close, | 237 | .release = wafwdt_close, |
232 | }; | 238 | }; |
@@ -250,25 +256,28 @@ static int __init wafwdt_init(void) | |||
250 | { | 256 | { |
251 | int ret; | 257 | int ret; |
252 | 258 | ||
253 | printk(KERN_INFO "WDT driver for Wafer 5823 single board computer initialising.\n"); | 259 | printk(KERN_INFO |
260 | "WDT driver for Wafer 5823 single board computer initialising.\n"); | ||
254 | 261 | ||
255 | if (timeout < 1 || timeout > 255) { | 262 | if (timeout < 1 || timeout > 255) { |
256 | timeout = WD_TIMO; | 263 | timeout = WD_TIMO; |
257 | printk (KERN_INFO PFX "timeout value must be 1<=x<=255, using %d\n", | 264 | printk(KERN_INFO PFX |
258 | timeout); | 265 | "timeout value must be 1 <= x <= 255, using %d\n", |
266 | timeout); | ||
259 | } | 267 | } |
260 | 268 | ||
261 | if (wdt_stop != wdt_start) { | 269 | if (wdt_stop != wdt_start) { |
262 | if(!request_region(wdt_stop, 1, "Wafer 5823 WDT")) { | 270 | if (!request_region(wdt_stop, 1, "Wafer 5823 WDT")) { |
263 | printk (KERN_ERR PFX "I/O address 0x%04x already in use\n", | 271 | printk(KERN_ERR PFX |
264 | wdt_stop); | 272 | "I/O address 0x%04x already in use\n", |
273 | wdt_stop); | ||
265 | ret = -EIO; | 274 | ret = -EIO; |
266 | goto error; | 275 | goto error; |
267 | } | 276 | } |
268 | } | 277 | } |
269 | 278 | ||
270 | if(!request_region(wdt_start, 1, "Wafer 5823 WDT")) { | 279 | if (!request_region(wdt_start, 1, "Wafer 5823 WDT")) { |
271 | printk (KERN_ERR PFX "I/O address 0x%04x already in use\n", | 280 | printk(KERN_ERR PFX "I/O address 0x%04x already in use\n", |
272 | wdt_start); | 281 | wdt_start); |
273 | ret = -EIO; | 282 | ret = -EIO; |
274 | goto error2; | 283 | goto error2; |
@@ -276,19 +285,20 @@ static int __init wafwdt_init(void) | |||
276 | 285 | ||
277 | ret = register_reboot_notifier(&wafwdt_notifier); | 286 | ret = register_reboot_notifier(&wafwdt_notifier); |
278 | if (ret != 0) { | 287 | if (ret != 0) { |
279 | printk (KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", | 288 | printk(KERN_ERR PFX |
280 | ret); | 289 | "cannot register reboot notifier (err=%d)\n", ret); |
281 | goto error3; | 290 | goto error3; |
282 | } | 291 | } |
283 | 292 | ||
284 | ret = misc_register(&wafwdt_miscdev); | 293 | ret = misc_register(&wafwdt_miscdev); |
285 | if (ret != 0) { | 294 | if (ret != 0) { |
286 | printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", | 295 | printk(KERN_ERR PFX |
287 | WATCHDOG_MINOR, ret); | 296 | "cannot register miscdev on minor=%d (err=%d)\n", |
297 | WATCHDOG_MINOR, ret); | ||
288 | goto error4; | 298 | goto error4; |
289 | } | 299 | } |
290 | 300 | ||
291 | printk (KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n", | 301 | printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n", |
292 | timeout, nowayout); | 302 | timeout, nowayout); |
293 | 303 | ||
294 | return ret; | 304 | return ret; |
@@ -307,7 +317,7 @@ static void __exit wafwdt_exit(void) | |||
307 | { | 317 | { |
308 | misc_deregister(&wafwdt_miscdev); | 318 | misc_deregister(&wafwdt_miscdev); |
309 | unregister_reboot_notifier(&wafwdt_notifier); | 319 | unregister_reboot_notifier(&wafwdt_notifier); |
310 | if(wdt_stop != wdt_start) | 320 | if (wdt_stop != wdt_start) |
311 | release_region(wdt_stop, 1); | 321 | release_region(wdt_stop, 1); |
312 | release_region(wdt_start, 1); | 322 | release_region(wdt_start, 1); |
313 | } | 323 | } |
diff --git a/drivers/watchdog/wd501p.h b/drivers/watchdog/wd501p.h index a4504f40394d..db34853c28ae 100644 --- a/drivers/watchdog/wd501p.h +++ b/drivers/watchdog/wd501p.h | |||
@@ -12,7 +12,7 @@ | |||
12 | * http://www.cymru.net | 12 | * http://www.cymru.net |
13 | * | 13 | * |
14 | * This driver is provided under the GNU General Public License, incorporated | 14 | * This driver is provided under the GNU General Public License, incorporated |
15 | * herein by reference. The driver is provided without warranty or | 15 | * herein by reference. The driver is provided without warranty or |
16 | * support. | 16 | * support. |
17 | * | 17 | * |
18 | * Release 0.04. | 18 | * Release 0.04. |
diff --git a/drivers/watchdog/wdrtas.c b/drivers/watchdog/wdrtas.c index 1d64e277567d..5d3b1a8e28b0 100644 --- a/drivers/watchdog/wdrtas.c +++ b/drivers/watchdog/wdrtas.c | |||
@@ -35,9 +35,9 @@ | |||
35 | #include <linux/reboot.h> | 35 | #include <linux/reboot.h> |
36 | #include <linux/types.h> | 36 | #include <linux/types.h> |
37 | #include <linux/watchdog.h> | 37 | #include <linux/watchdog.h> |
38 | #include <linux/uaccess.h> | ||
38 | 39 | ||
39 | #include <asm/rtas.h> | 40 | #include <asm/rtas.h> |
40 | #include <asm/uaccess.h> | ||
41 | 41 | ||
42 | #define WDRTAS_MAGIC_CHAR 42 | 42 | #define WDRTAS_MAGIC_CHAR 42 |
43 | #define WDRTAS_SUPPORTED_MASK (WDIOF_SETTIMEOUT | \ | 43 | #define WDRTAS_SUPPORTED_MASK (WDIOF_SETTIMEOUT | \ |
@@ -56,7 +56,7 @@ static int wdrtas_nowayout = 0; | |||
56 | #endif | 56 | #endif |
57 | 57 | ||
58 | static atomic_t wdrtas_miscdev_open = ATOMIC_INIT(0); | 58 | static atomic_t wdrtas_miscdev_open = ATOMIC_INIT(0); |
59 | static char wdrtas_expect_close = 0; | 59 | static char wdrtas_expect_close; |
60 | 60 | ||
61 | static int wdrtas_interval; | 61 | static int wdrtas_interval; |
62 | 62 | ||
@@ -86,8 +86,8 @@ static char wdrtas_logbuffer[WDRTAS_LOGBUFFER_LEN]; | |||
86 | * RTAS function set-indicator (surveillance). The unit of interval is | 86 | * RTAS function set-indicator (surveillance). The unit of interval is |
87 | * seconds. | 87 | * seconds. |
88 | */ | 88 | */ |
89 | static int | 89 | |
90 | wdrtas_set_interval(int interval) | 90 | static int wdrtas_set_interval(int interval) |
91 | { | 91 | { |
92 | long result; | 92 | long result; |
93 | static int print_msg = 10; | 93 | static int print_msg = 10; |
@@ -97,7 +97,7 @@ wdrtas_set_interval(int interval) | |||
97 | 97 | ||
98 | result = rtas_call(wdrtas_token_set_indicator, 3, 1, NULL, | 98 | result = rtas_call(wdrtas_token_set_indicator, 3, 1, NULL, |
99 | WDRTAS_SURVEILLANCE_IND, 0, interval); | 99 | WDRTAS_SURVEILLANCE_IND, 0, interval); |
100 | if ( (result < 0) && (print_msg) ) { | 100 | if (result < 0 && print_msg) { |
101 | printk(KERN_ERR "wdrtas: setting the watchdog to %i " | 101 | printk(KERN_ERR "wdrtas: setting the watchdog to %i " |
102 | "timeout failed: %li\n", interval, result); | 102 | "timeout failed: %li\n", interval, result); |
103 | print_msg--; | 103 | print_msg--; |
@@ -116,16 +116,14 @@ wdrtas_set_interval(int interval) | |||
116 | * as reported by the RTAS function ibm,get-system-parameter. The unit | 116 | * as reported by the RTAS function ibm,get-system-parameter. The unit |
117 | * of the return value is seconds. | 117 | * of the return value is seconds. |
118 | */ | 118 | */ |
119 | static int | 119 | static int wdrtas_get_interval(int fallback_value) |
120 | wdrtas_get_interval(int fallback_value) | ||
121 | { | 120 | { |
122 | long result; | 121 | long result; |
123 | char value[4]; | 122 | char value[4]; |
124 | 123 | ||
125 | result = rtas_call(wdrtas_token_get_sp, 3, 1, NULL, | 124 | result = rtas_call(wdrtas_token_get_sp, 3, 1, NULL, |
126 | WDRTAS_SP_SPI, (void *)__pa(&value), 4); | 125 | WDRTAS_SP_SPI, (void *)__pa(&value), 4); |
127 | if ( (value[0] != 0) || (value[1] != 2) || (value[3] != 0) || | 126 | if (value[0] != 0 || value[1] != 2 || value[3] != 0 || result < 0) { |
128 | (result < 0) ) { | ||
129 | printk(KERN_WARNING "wdrtas: could not get sp_spi watchdog " | 127 | printk(KERN_WARNING "wdrtas: could not get sp_spi watchdog " |
130 | "timeout (%li). Continuing\n", result); | 128 | "timeout (%li). Continuing\n", result); |
131 | return fallback_value; | 129 | return fallback_value; |
@@ -141,8 +139,7 @@ wdrtas_get_interval(int fallback_value) | |||
141 | * wdrtas_timer_start starts the watchdog by calling the RTAS function | 139 | * wdrtas_timer_start starts the watchdog by calling the RTAS function |
142 | * set-interval (surveillance) | 140 | * set-interval (surveillance) |
143 | */ | 141 | */ |
144 | static void | 142 | static void wdrtas_timer_start(void) |
145 | wdrtas_timer_start(void) | ||
146 | { | 143 | { |
147 | wdrtas_set_interval(wdrtas_interval); | 144 | wdrtas_set_interval(wdrtas_interval); |
148 | } | 145 | } |
@@ -153,8 +150,7 @@ wdrtas_timer_start(void) | |||
153 | * wdrtas_timer_stop stops the watchdog timer by calling the RTAS function | 150 | * wdrtas_timer_stop stops the watchdog timer by calling the RTAS function |
154 | * set-interval (surveillance) | 151 | * set-interval (surveillance) |
155 | */ | 152 | */ |
156 | static void | 153 | static void wdrtas_timer_stop(void) |
157 | wdrtas_timer_stop(void) | ||
158 | { | 154 | { |
159 | wdrtas_set_interval(0); | 155 | wdrtas_set_interval(0); |
160 | } | 156 | } |
@@ -165,8 +161,7 @@ wdrtas_timer_stop(void) | |||
165 | * wdrtas_log_scanned_event prints a message to the log buffer dumping | 161 | * wdrtas_log_scanned_event prints a message to the log buffer dumping |
166 | * the results of the last event-scan call | 162 | * the results of the last event-scan call |
167 | */ | 163 | */ |
168 | static void | 164 | static void wdrtas_log_scanned_event(void) |
169 | wdrtas_log_scanned_event(void) | ||
170 | { | 165 | { |
171 | int i; | 166 | int i; |
172 | 167 | ||
@@ -175,13 +170,13 @@ wdrtas_log_scanned_event(void) | |||
175 | "%02x %02x %02x %02x %02x %02x %02x %02x " | 170 | "%02x %02x %02x %02x %02x %02x %02x %02x " |
176 | "%02x %02x %02x %02x %02x %02x %02x %02x\n", | 171 | "%02x %02x %02x %02x %02x %02x %02x %02x\n", |
177 | (i / 16) + 1, (WDRTAS_LOGBUFFER_LEN / 16), | 172 | (i / 16) + 1, (WDRTAS_LOGBUFFER_LEN / 16), |
178 | wdrtas_logbuffer[i + 0], wdrtas_logbuffer[i + 1], | 173 | wdrtas_logbuffer[i + 0], wdrtas_logbuffer[i + 1], |
179 | wdrtas_logbuffer[i + 2], wdrtas_logbuffer[i + 3], | 174 | wdrtas_logbuffer[i + 2], wdrtas_logbuffer[i + 3], |
180 | wdrtas_logbuffer[i + 4], wdrtas_logbuffer[i + 5], | 175 | wdrtas_logbuffer[i + 4], wdrtas_logbuffer[i + 5], |
181 | wdrtas_logbuffer[i + 6], wdrtas_logbuffer[i + 7], | 176 | wdrtas_logbuffer[i + 6], wdrtas_logbuffer[i + 7], |
182 | wdrtas_logbuffer[i + 8], wdrtas_logbuffer[i + 9], | 177 | wdrtas_logbuffer[i + 8], wdrtas_logbuffer[i + 9], |
183 | wdrtas_logbuffer[i + 10], wdrtas_logbuffer[i + 11], | 178 | wdrtas_logbuffer[i + 10], wdrtas_logbuffer[i + 11], |
184 | wdrtas_logbuffer[i + 12], wdrtas_logbuffer[i + 13], | 179 | wdrtas_logbuffer[i + 12], wdrtas_logbuffer[i + 13], |
185 | wdrtas_logbuffer[i + 14], wdrtas_logbuffer[i + 15]); | 180 | wdrtas_logbuffer[i + 14], wdrtas_logbuffer[i + 15]); |
186 | } | 181 | } |
187 | 182 | ||
@@ -192,8 +187,7 @@ wdrtas_log_scanned_event(void) | |||
192 | * RTAS function event-scan and repeats these calls as long as there are | 187 | * RTAS function event-scan and repeats these calls as long as there are |
193 | * events available. All events will be dumped. | 188 | * events available. All events will be dumped. |
194 | */ | 189 | */ |
195 | static void | 190 | static void wdrtas_timer_keepalive(void) |
196 | wdrtas_timer_keepalive(void) | ||
197 | { | 191 | { |
198 | long result; | 192 | long result; |
199 | 193 | ||
@@ -218,8 +212,7 @@ wdrtas_timer_keepalive(void) | |||
218 | * wdrtas_get_temperature returns the current temperature in Fahrenheit. It | 212 | * wdrtas_get_temperature returns the current temperature in Fahrenheit. It |
219 | * uses the RTAS call get-sensor-state, token 3 to do so | 213 | * uses the RTAS call get-sensor-state, token 3 to do so |
220 | */ | 214 | */ |
221 | static int | 215 | static int wdrtas_get_temperature(void) |
222 | wdrtas_get_temperature(void) | ||
223 | { | 216 | { |
224 | long result; | 217 | long result; |
225 | int temperature = 0; | 218 | int temperature = 0; |
@@ -243,8 +236,7 @@ wdrtas_get_temperature(void) | |||
243 | * returns a bitmask of defines WDIOF_... as defined in | 236 | * returns a bitmask of defines WDIOF_... as defined in |
244 | * include/linux/watchdog.h | 237 | * include/linux/watchdog.h |
245 | */ | 238 | */ |
246 | static int | 239 | static int wdrtas_get_status(void) |
247 | wdrtas_get_status(void) | ||
248 | { | 240 | { |
249 | return 0; /* TODO */ | 241 | return 0; /* TODO */ |
250 | } | 242 | } |
@@ -255,8 +247,7 @@ wdrtas_get_status(void) | |||
255 | * returns a bitmask of defines WDIOF_... as defined in | 247 | * returns a bitmask of defines WDIOF_... as defined in |
256 | * include/linux/watchdog.h, indicating why the watchdog rebooted the system | 248 | * include/linux/watchdog.h, indicating why the watchdog rebooted the system |
257 | */ | 249 | */ |
258 | static int | 250 | static int wdrtas_get_boot_status(void) |
259 | wdrtas_get_boot_status(void) | ||
260 | { | 251 | { |
261 | return 0; /* TODO */ | 252 | return 0; /* TODO */ |
262 | } | 253 | } |
@@ -276,8 +267,7 @@ wdrtas_get_boot_status(void) | |||
276 | * character 'V'. This character allows the watchdog device to be closed | 267 | * character 'V'. This character allows the watchdog device to be closed |
277 | * properly. | 268 | * properly. |
278 | */ | 269 | */ |
279 | static ssize_t | 270 | static ssize_t wdrtas_write(struct file *file, const char __user *buf, |
280 | wdrtas_write(struct file *file, const char __user *buf, | ||
281 | size_t len, loff_t *ppos) | 271 | size_t len, loff_t *ppos) |
282 | { | 272 | { |
283 | int i; | 273 | int i; |
@@ -306,7 +296,6 @@ out: | |||
306 | 296 | ||
307 | /** | 297 | /** |
308 | * wdrtas_ioctl - ioctl function for the watchdog device | 298 | * wdrtas_ioctl - ioctl function for the watchdog device |
309 | * @inode: inode structure | ||
310 | * @file: file structure | 299 | * @file: file structure |
311 | * @cmd: command for ioctl | 300 | * @cmd: command for ioctl |
312 | * @arg: argument pointer | 301 | * @arg: argument pointer |
@@ -315,16 +304,16 @@ out: | |||
315 | * | 304 | * |
316 | * wdrtas_ioctl implements the watchdog API ioctls | 305 | * wdrtas_ioctl implements the watchdog API ioctls |
317 | */ | 306 | */ |
318 | static int | 307 | |
319 | wdrtas_ioctl(struct inode *inode, struct file *file, | 308 | static long wdrtas_ioctl(struct file *file, unsigned int cmd, |
320 | unsigned int cmd, unsigned long arg) | 309 | unsigned long arg) |
321 | { | 310 | { |
322 | int __user *argp = (void __user *)arg; | 311 | int __user *argp = (void __user *)arg; |
323 | int i; | 312 | int i; |
324 | static struct watchdog_info wdinfo = { | 313 | static struct watchdog_info wdinfo = { |
325 | .options = WDRTAS_SUPPORTED_MASK, | 314 | .options = WDRTAS_SUPPORTED_MASK, |
326 | .firmware_version = 0, | 315 | .firmware_version = 0, |
327 | .identity = "wdrtas" | 316 | .identity = "wdrtas", |
328 | }; | 317 | }; |
329 | 318 | ||
330 | switch (cmd) { | 319 | switch (cmd) { |
@@ -357,9 +346,9 @@ wdrtas_ioctl(struct inode *inode, struct file *file, | |||
357 | wdrtas_timer_keepalive(); | 346 | wdrtas_timer_keepalive(); |
358 | wdrtas_timer_start(); | 347 | wdrtas_timer_start(); |
359 | } | 348 | } |
349 | /* not implemented. Done by H8 | ||
360 | if (i & WDIOS_TEMPPANIC) { | 350 | if (i & WDIOS_TEMPPANIC) { |
361 | /* not implemented. Done by H8 */ | 351 | } */ |
362 | } | ||
363 | return 0; | 352 | return 0; |
364 | 353 | ||
365 | case WDIOC_KEEPALIVE: | 354 | case WDIOC_KEEPALIVE: |
@@ -399,8 +388,7 @@ wdrtas_ioctl(struct inode *inode, struct file *file, | |||
399 | * | 388 | * |
400 | * function called when watchdog device is opened | 389 | * function called when watchdog device is opened |
401 | */ | 390 | */ |
402 | static int | 391 | static int wdrtas_open(struct inode *inode, struct file *file) |
403 | wdrtas_open(struct inode *inode, struct file *file) | ||
404 | { | 392 | { |
405 | /* only open once */ | 393 | /* only open once */ |
406 | if (atomic_inc_return(&wdrtas_miscdev_open) > 1) { | 394 | if (atomic_inc_return(&wdrtas_miscdev_open) > 1) { |
@@ -423,8 +411,7 @@ wdrtas_open(struct inode *inode, struct file *file) | |||
423 | * | 411 | * |
424 | * close function. Always succeeds | 412 | * close function. Always succeeds |
425 | */ | 413 | */ |
426 | static int | 414 | static int wdrtas_close(struct inode *inode, struct file *file) |
427 | wdrtas_close(struct inode *inode, struct file *file) | ||
428 | { | 415 | { |
429 | /* only stop watchdog, if this was announced using 'V' before */ | 416 | /* only stop watchdog, if this was announced using 'V' before */ |
430 | if (wdrtas_expect_close == WDRTAS_MAGIC_CHAR) | 417 | if (wdrtas_expect_close == WDRTAS_MAGIC_CHAR) |
@@ -453,8 +440,7 @@ wdrtas_close(struct inode *inode, struct file *file) | |||
453 | * wdrtas_temp_read gives the temperature to the users by copying this | 440 | * wdrtas_temp_read gives the temperature to the users by copying this |
454 | * value as one byte into the user space buffer. The unit is Fahrenheit... | 441 | * value as one byte into the user space buffer. The unit is Fahrenheit... |
455 | */ | 442 | */ |
456 | static ssize_t | 443 | static ssize_t wdrtas_temp_read(struct file *file, char __user *buf, |
457 | wdrtas_temp_read(struct file *file, char __user *buf, | ||
458 | size_t count, loff_t *ppos) | 444 | size_t count, loff_t *ppos) |
459 | { | 445 | { |
460 | int temperature = 0; | 446 | int temperature = 0; |
@@ -478,8 +464,7 @@ wdrtas_temp_read(struct file *file, char __user *buf, | |||
478 | * | 464 | * |
479 | * function called when temperature device is opened | 465 | * function called when temperature device is opened |
480 | */ | 466 | */ |
481 | static int | 467 | static int wdrtas_temp_open(struct inode *inode, struct file *file) |
482 | wdrtas_temp_open(struct inode *inode, struct file *file) | ||
483 | { | 468 | { |
484 | return nonseekable_open(inode, file); | 469 | return nonseekable_open(inode, file); |
485 | } | 470 | } |
@@ -493,8 +478,7 @@ wdrtas_temp_open(struct inode *inode, struct file *file) | |||
493 | * | 478 | * |
494 | * close function. Always succeeds | 479 | * close function. Always succeeds |
495 | */ | 480 | */ |
496 | static int | 481 | static int wdrtas_temp_close(struct inode *inode, struct file *file) |
497 | wdrtas_temp_close(struct inode *inode, struct file *file) | ||
498 | { | 482 | { |
499 | return 0; | 483 | return 0; |
500 | } | 484 | } |
@@ -509,10 +493,10 @@ wdrtas_temp_close(struct inode *inode, struct file *file) | |||
509 | * | 493 | * |
510 | * wdrtas_reboot stops the watchdog in case of a reboot | 494 | * wdrtas_reboot stops the watchdog in case of a reboot |
511 | */ | 495 | */ |
512 | static int | 496 | static int wdrtas_reboot(struct notifier_block *this, |
513 | wdrtas_reboot(struct notifier_block *this, unsigned long code, void *ptr) | 497 | unsigned long code, void *ptr) |
514 | { | 498 | { |
515 | if ( (code==SYS_DOWN) || (code==SYS_HALT) ) | 499 | if (code == SYS_DOWN || code == SYS_HALT) |
516 | wdrtas_timer_stop(); | 500 | wdrtas_timer_stop(); |
517 | 501 | ||
518 | return NOTIFY_DONE; | 502 | return NOTIFY_DONE; |
@@ -524,7 +508,7 @@ static const struct file_operations wdrtas_fops = { | |||
524 | .owner = THIS_MODULE, | 508 | .owner = THIS_MODULE, |
525 | .llseek = no_llseek, | 509 | .llseek = no_llseek, |
526 | .write = wdrtas_write, | 510 | .write = wdrtas_write, |
527 | .ioctl = wdrtas_ioctl, | 511 | .unlocked_ioctl = wdrtas_ioctl, |
528 | .open = wdrtas_open, | 512 | .open = wdrtas_open, |
529 | .release = wdrtas_close, | 513 | .release = wdrtas_close, |
530 | }; | 514 | }; |
@@ -562,8 +546,7 @@ static struct notifier_block wdrtas_notifier = { | |||
562 | * this watchdog driver. It tolerates, if "get-sensor-state" and | 546 | * this watchdog driver. It tolerates, if "get-sensor-state" and |
563 | * "ibm,get-system-parameter" are not available. | 547 | * "ibm,get-system-parameter" are not available. |
564 | */ | 548 | */ |
565 | static int | 549 | static int wdrtas_get_tokens(void) |
566 | wdrtas_get_tokens(void) | ||
567 | { | 550 | { |
568 | wdrtas_token_get_sensor_state = rtas_token("get-sensor-state"); | 551 | wdrtas_token_get_sensor_state = rtas_token("get-sensor-state"); |
569 | if (wdrtas_token_get_sensor_state == RTAS_UNKNOWN_SERVICE) { | 552 | if (wdrtas_token_get_sensor_state == RTAS_UNKNOWN_SERVICE) { |
@@ -603,8 +586,7 @@ wdrtas_get_tokens(void) | |||
603 | * wdrtas_register_devs unregisters the watchdog and temperature watchdog | 586 | * wdrtas_register_devs unregisters the watchdog and temperature watchdog |
604 | * misc devs | 587 | * misc devs |
605 | */ | 588 | */ |
606 | static void | 589 | static void wdrtas_unregister_devs(void) |
607 | wdrtas_unregister_devs(void) | ||
608 | { | 590 | { |
609 | misc_deregister(&wdrtas_miscdev); | 591 | misc_deregister(&wdrtas_miscdev); |
610 | if (wdrtas_token_get_sensor_state != RTAS_UNKNOWN_SERVICE) | 592 | if (wdrtas_token_get_sensor_state != RTAS_UNKNOWN_SERVICE) |
@@ -619,8 +601,7 @@ wdrtas_unregister_devs(void) | |||
619 | * wdrtas_register_devs registers the watchdog and temperature watchdog | 601 | * wdrtas_register_devs registers the watchdog and temperature watchdog |
620 | * misc devs | 602 | * misc devs |
621 | */ | 603 | */ |
622 | static int | 604 | static int wdrtas_register_devs(void) |
623 | wdrtas_register_devs(void) | ||
624 | { | 605 | { |
625 | int result; | 606 | int result; |
626 | 607 | ||
@@ -651,8 +632,7 @@ wdrtas_register_devs(void) | |||
651 | * | 632 | * |
652 | * registers the file handlers and the reboot notifier | 633 | * registers the file handlers and the reboot notifier |
653 | */ | 634 | */ |
654 | static int __init | 635 | static int __init wdrtas_init(void) |
655 | wdrtas_init(void) | ||
656 | { | 636 | { |
657 | if (wdrtas_get_tokens()) | 637 | if (wdrtas_get_tokens()) |
658 | return -ENODEV; | 638 | return -ENODEV; |
@@ -680,8 +660,7 @@ wdrtas_init(void) | |||
680 | * | 660 | * |
681 | * unregisters the file handlers and the reboot notifier | 661 | * unregisters the file handlers and the reboot notifier |
682 | */ | 662 | */ |
683 | static void __exit | 663 | static void __exit wdrtas_exit(void) |
684 | wdrtas_exit(void) | ||
685 | { | 664 | { |
686 | if (!wdrtas_nowayout) | 665 | if (!wdrtas_nowayout) |
687 | wdrtas_timer_stop(); | 666 | wdrtas_timer_stop(); |
diff --git a/drivers/watchdog/wdt.c b/drivers/watchdog/wdt.c index 53a6b18bcb9a..deeebb2b13ea 100644 --- a/drivers/watchdog/wdt.c +++ b/drivers/watchdog/wdt.c | |||
@@ -373,8 +373,6 @@ static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
373 | #endif /* CONFIG_WDT_501 */ | 373 | #endif /* CONFIG_WDT_501 */ |
374 | 374 | ||
375 | switch (cmd) { | 375 | switch (cmd) { |
376 | default: | ||
377 | return -ENOTTY; | ||
378 | case WDIOC_GETSUPPORT: | 376 | case WDIOC_GETSUPPORT: |
379 | return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; | 377 | return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; |
380 | case WDIOC_GETSTATUS: | 378 | case WDIOC_GETSTATUS: |
@@ -394,6 +392,8 @@ static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
394 | /* Fall */ | 392 | /* Fall */ |
395 | case WDIOC_GETTIMEOUT: | 393 | case WDIOC_GETTIMEOUT: |
396 | return put_user(heartbeat, p); | 394 | return put_user(heartbeat, p); |
395 | default: | ||
396 | return -ENOTTY; | ||
397 | } | 397 | } |
398 | } | 398 | } |
399 | 399 | ||
diff --git a/drivers/watchdog/wdt285.c b/drivers/watchdog/wdt285.c index e4cf661dc890..fea398a4ca32 100644 --- a/drivers/watchdog/wdt285.c +++ b/drivers/watchdog/wdt285.c | |||
@@ -26,9 +26,9 @@ | |||
26 | #include <linux/reboot.h> | 26 | #include <linux/reboot.h> |
27 | #include <linux/init.h> | 27 | #include <linux/init.h> |
28 | #include <linux/interrupt.h> | 28 | #include <linux/interrupt.h> |
29 | #include <linux/uaccess.h> | ||
30 | #include <linux/irq.h> | ||
29 | 31 | ||
30 | #include <asm/irq.h> | ||
31 | #include <asm/uaccess.h> | ||
32 | #include <asm/hardware.h> | 32 | #include <asm/hardware.h> |
33 | #include <asm/mach-types.h> | 33 | #include <asm/mach-types.h> |
34 | #include <asm/hardware/dec21285.h> | 34 | #include <asm/hardware/dec21285.h> |
@@ -115,8 +115,8 @@ static int watchdog_release(struct inode *inode, struct file *file) | |||
115 | return 0; | 115 | return 0; |
116 | } | 116 | } |
117 | 117 | ||
118 | static ssize_t | 118 | static ssize_t watchdog_write(struct file *file, const char *data, |
119 | watchdog_write(struct file *file, const char *data, size_t len, loff_t *ppos) | 119 | size_t len, loff_t *ppos) |
120 | { | 120 | { |
121 | /* | 121 | /* |
122 | * Refresh the timer. | 122 | * Refresh the timer. |
@@ -127,19 +127,18 @@ watchdog_write(struct file *file, const char *data, size_t len, loff_t *ppos) | |||
127 | return len; | 127 | return len; |
128 | } | 128 | } |
129 | 129 | ||
130 | static struct watchdog_info ident = { | 130 | static const struct watchdog_info ident = { |
131 | .options = WDIOF_SETTIMEOUT, | 131 | .options = WDIOF_SETTIMEOUT, |
132 | .identity = "Footbridge Watchdog", | 132 | .identity = "Footbridge Watchdog", |
133 | }; | 133 | }; |
134 | 134 | ||
135 | static int | 135 | static long watchdog_ioctl(struct file *file, unsigned int cmd, |
136 | watchdog_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | 136 | unsigned long arg) |
137 | unsigned long arg) | ||
138 | { | 137 | { |
139 | unsigned int new_margin; | 138 | unsigned int new_margin; |
140 | int ret = -ENOTTY; | 139 | int ret = -ENOTTY; |
141 | 140 | ||
142 | switch(cmd) { | 141 | switch (cmd) { |
143 | case WDIOC_GETSUPPORT: | 142 | case WDIOC_GETSUPPORT: |
144 | ret = 0; | 143 | ret = 0; |
145 | if (copy_to_user((void *)arg, &ident, sizeof(ident))) | 144 | if (copy_to_user((void *)arg, &ident, sizeof(ident))) |
@@ -148,7 +147,7 @@ watchdog_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | |||
148 | 147 | ||
149 | case WDIOC_GETSTATUS: | 148 | case WDIOC_GETSTATUS: |
150 | case WDIOC_GETBOOTSTATUS: | 149 | case WDIOC_GETBOOTSTATUS: |
151 | ret = put_user(0,(int *)arg); | 150 | ret = put_user(0, (int *)arg); |
152 | break; | 151 | break; |
153 | 152 | ||
154 | case WDIOC_KEEPALIVE: | 153 | case WDIOC_KEEPALIVE: |
@@ -182,7 +181,7 @@ static const struct file_operations watchdog_fops = { | |||
182 | .owner = THIS_MODULE, | 181 | .owner = THIS_MODULE, |
183 | .llseek = no_llseek, | 182 | .llseek = no_llseek, |
184 | .write = watchdog_write, | 183 | .write = watchdog_write, |
185 | .ioctl = watchdog_ioctl, | 184 | .unlocked_ioctl = watchdog_ioctl, |
186 | .open = watchdog_open, | 185 | .open = watchdog_open, |
187 | .release = watchdog_release, | 186 | .release = watchdog_release, |
188 | }; | 187 | }; |
@@ -204,11 +203,13 @@ static int __init footbridge_watchdog_init(void) | |||
204 | if (retval < 0) | 203 | if (retval < 0) |
205 | return retval; | 204 | return retval; |
206 | 205 | ||
207 | printk("Footbridge Watchdog Timer: 0.01, timer margin: %d sec\n", | 206 | printk(KERN_INFO |
208 | soft_margin); | 207 | "Footbridge Watchdog Timer: 0.01, timer margin: %d sec\n", |
208 | soft_margin); | ||
209 | 209 | ||
210 | if (machine_is_cats()) | 210 | if (machine_is_cats()) |
211 | printk("Warning: Watchdog reset may not work on this machine.\n"); | 211 | printk(KERN_WARN |
212 | "Warning: Watchdog reset may not work on this machine.\n"); | ||
212 | return 0; | 213 | return 0; |
213 | } | 214 | } |
214 | 215 | ||
@@ -223,7 +224,7 @@ MODULE_LICENSE("GPL"); | |||
223 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); | 224 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); |
224 | 225 | ||
225 | module_param(soft_margin, int, 0); | 226 | module_param(soft_margin, int, 0); |
226 | MODULE_PARM_DESC(soft_margin,"Watchdog timeout in seconds"); | 227 | MODULE_PARM_DESC(soft_margin, "Watchdog timeout in seconds"); |
227 | 228 | ||
228 | module_init(footbridge_watchdog_init); | 229 | module_init(footbridge_watchdog_init); |
229 | module_exit(footbridge_watchdog_exit); | 230 | module_exit(footbridge_watchdog_exit); |
diff --git a/drivers/watchdog/wdt977.c b/drivers/watchdog/wdt977.c index fb4b876c9fda..60e28d49ff52 100644 --- a/drivers/watchdog/wdt977.c +++ b/drivers/watchdog/wdt977.c | |||
@@ -19,7 +19,8 @@ | |||
19 | * 07-Jul-2003 Daniele Bellucci: Audit return code of misc_register in | 19 | * 07-Jul-2003 Daniele Bellucci: Audit return code of misc_register in |
20 | * nwwatchdog_init. | 20 | * nwwatchdog_init. |
21 | * 25-Oct-2005 Woody Suwalski: Convert addresses to #defs, add spinlocks | 21 | * 25-Oct-2005 Woody Suwalski: Convert addresses to #defs, add spinlocks |
22 | * remove limitiation to be used on Netwinders only | 22 | * remove limitiation to be used on |
23 | * Netwinders only | ||
23 | */ | 24 | */ |
24 | 25 | ||
25 | #include <linux/module.h> | 26 | #include <linux/module.h> |
@@ -33,11 +34,11 @@ | |||
33 | #include <linux/watchdog.h> | 34 | #include <linux/watchdog.h> |
34 | #include <linux/notifier.h> | 35 | #include <linux/notifier.h> |
35 | #include <linux/reboot.h> | 36 | #include <linux/reboot.h> |
37 | #include <linux/io.h> | ||
38 | #include <linux/uaccess.h> | ||
36 | 39 | ||
37 | #include <asm/io.h> | ||
38 | #include <asm/system.h> | 40 | #include <asm/system.h> |
39 | #include <asm/mach-types.h> | 41 | #include <asm/mach-types.h> |
40 | #include <asm/uaccess.h> | ||
41 | 42 | ||
42 | #define WATCHDOG_VERSION "0.04" | 43 | #define WATCHDOG_VERSION "0.04" |
43 | #define WATCHDOG_NAME "Wdt977" | 44 | #define WATCHDOG_NAME "Wdt977" |
@@ -45,7 +46,7 @@ | |||
45 | #define DRIVER_VERSION WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n" | 46 | #define DRIVER_VERSION WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n" |
46 | 47 | ||
47 | #define IO_INDEX_PORT 0x370 /* on some systems it can be 0x3F0 */ | 48 | #define IO_INDEX_PORT 0x370 /* on some systems it can be 0x3F0 */ |
48 | #define IO_DATA_PORT (IO_INDEX_PORT+1) | 49 | #define IO_DATA_PORT (IO_INDEX_PORT + 1) |
49 | 50 | ||
50 | #define UNLOCK_DATA 0x87 | 51 | #define UNLOCK_DATA 0x87 |
51 | #define LOCK_DATA 0xAA | 52 | #define LOCK_DATA 0xAA |
@@ -62,13 +63,16 @@ static char expect_close; | |||
62 | static DEFINE_SPINLOCK(spinlock); | 63 | static DEFINE_SPINLOCK(spinlock); |
63 | 64 | ||
64 | module_param(timeout, int, 0); | 65 | module_param(timeout, int, 0); |
65 | MODULE_PARM_DESC(timeout,"Watchdog timeout in seconds (60..15300), default=" __MODULE_STRING(DEFAULT_TIMEOUT) ")"); | 66 | MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (60..15300), default=" |
67 | __MODULE_STRING(DEFAULT_TIMEOUT) ")"); | ||
66 | module_param(testmode, int, 0); | 68 | module_param(testmode, int, 0); |
67 | MODULE_PARM_DESC(testmode,"Watchdog testmode (1 = no reboot), default=0"); | 69 | MODULE_PARM_DESC(testmode, "Watchdog testmode (1 = no reboot), default=0"); |
68 | 70 | ||
69 | static int nowayout = WATCHDOG_NOWAYOUT; | 71 | static int nowayout = WATCHDOG_NOWAYOUT; |
70 | module_param(nowayout, int, 0); | 72 | module_param(nowayout, int, 0); |
71 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 73 | MODULE_PARM_DESC(nowayout, |
74 | "Watchdog cannot be stopped once started (default=" | ||
75 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
72 | 76 | ||
73 | /* | 77 | /* |
74 | * Start the watchdog | 78 | * Start the watchdog |
@@ -95,14 +99,16 @@ static int wdt977_start(void) | |||
95 | outb_p(0xF2, IO_INDEX_PORT); | 99 | outb_p(0xF2, IO_INDEX_PORT); |
96 | outb_p(timeoutM, IO_DATA_PORT); | 100 | outb_p(timeoutM, IO_DATA_PORT); |
97 | outb_p(0xF3, IO_INDEX_PORT); | 101 | outb_p(0xF3, IO_INDEX_PORT); |
98 | outb_p(0x00, IO_DATA_PORT); /* another setting is 0E for kbd/mouse/LED */ | 102 | outb_p(0x00, IO_DATA_PORT); /* another setting is 0E for |
103 | kbd/mouse/LED */ | ||
99 | outb_p(0xF4, IO_INDEX_PORT); | 104 | outb_p(0xF4, IO_INDEX_PORT); |
100 | outb_p(0x00, IO_DATA_PORT); | 105 | outb_p(0x00, IO_DATA_PORT); |
101 | 106 | ||
102 | /* at last select device Aux1 (dev=7) and set GP16 as a watchdog output */ | 107 | /* At last select device Aux1 (dev=7) and set GP16 as a |
103 | /* in test mode watch the bit 1 on F4 to indicate "triggered" */ | 108 | * watchdog output. In test mode watch the bit 1 on F4 to |
104 | if (!testmode) | 109 | * indicate "triggered" |
105 | { | 110 | */ |
111 | if (!testmode) { | ||
106 | outb_p(DEVICE_REGISTER, IO_INDEX_PORT); | 112 | outb_p(DEVICE_REGISTER, IO_INDEX_PORT); |
107 | outb_p(0x07, IO_DATA_PORT); | 113 | outb_p(0x07, IO_DATA_PORT); |
108 | outb_p(0xE6, IO_INDEX_PORT); | 114 | outb_p(0xE6, IO_INDEX_PORT); |
@@ -147,7 +153,8 @@ static int wdt977_stop(void) | |||
147 | outb_p(0xF2, IO_INDEX_PORT); | 153 | outb_p(0xF2, IO_INDEX_PORT); |
148 | outb_p(0x00, IO_DATA_PORT); | 154 | outb_p(0x00, IO_DATA_PORT); |
149 | 155 | ||
150 | /* at last select device Aux1 (dev=7) and set GP16 as a watchdog output */ | 156 | /* at last select device Aux1 (dev=7) and set |
157 | GP16 as a watchdog output */ | ||
151 | outb_p(DEVICE_REGISTER, IO_INDEX_PORT); | 158 | outb_p(DEVICE_REGISTER, IO_INDEX_PORT); |
152 | outb_p(0x07, IO_DATA_PORT); | 159 | outb_p(0x07, IO_DATA_PORT); |
153 | outb_p(0xE6, IO_INDEX_PORT); | 160 | outb_p(0xE6, IO_INDEX_PORT); |
@@ -202,16 +209,18 @@ static int wdt977_set_timeout(int t) | |||
202 | tmrval = (t + 59) / 60; | 209 | tmrval = (t + 59) / 60; |
203 | 210 | ||
204 | if (machine_is_netwinder()) { | 211 | if (machine_is_netwinder()) { |
205 | /* we have a hw bug somewhere, so each 977 minute is actually only 30sec | 212 | /* we have a hw bug somewhere, so each 977 minute is actually |
206 | * this limits the max timeout to half of device max of 255 minutes... | 213 | * only 30sec. This limits the max timeout to half of device |
214 | * max of 255 minutes... | ||
207 | */ | 215 | */ |
208 | tmrval += tmrval; | 216 | tmrval += tmrval; |
209 | } | 217 | } |
210 | 218 | ||
211 | if ((tmrval < 1) || (tmrval > 255)) | 219 | if (tmrval < 1 || tmrval > 255) |
212 | return -EINVAL; | 220 | return -EINVAL; |
213 | 221 | ||
214 | /* timeout is the timeout in seconds, timeoutM is the timeout in minutes) */ | 222 | /* timeout is the timeout in seconds, timeoutM is |
223 | the timeout in minutes) */ | ||
215 | timeout = t; | 224 | timeout = t; |
216 | timeoutM = tmrval; | 225 | timeoutM = tmrval; |
217 | return 0; | 226 | return 0; |
@@ -243,7 +252,7 @@ static int wdt977_get_status(int *status) | |||
243 | 252 | ||
244 | spin_unlock_irqrestore(&spinlock, flags); | 253 | spin_unlock_irqrestore(&spinlock, flags); |
245 | 254 | ||
246 | *status=0; | 255 | *status = 0; |
247 | if (new_status & 1) | 256 | if (new_status & 1) |
248 | *status |= WDIOF_CARDRESET; | 257 | *status |= WDIOF_CARDRESET; |
249 | 258 | ||
@@ -258,7 +267,7 @@ static int wdt977_get_status(int *status) | |||
258 | static int wdt977_open(struct inode *inode, struct file *file) | 267 | static int wdt977_open(struct inode *inode, struct file *file) |
259 | { | 268 | { |
260 | /* If the watchdog is alive we don't need to start it again */ | 269 | /* If the watchdog is alive we don't need to start it again */ |
261 | if( test_and_set_bit(0,&timer_alive) ) | 270 | if (test_and_set_bit(0, &timer_alive)) |
262 | return -EBUSY; | 271 | return -EBUSY; |
263 | 272 | ||
264 | if (nowayout) | 273 | if (nowayout) |
@@ -274,13 +283,13 @@ static int wdt977_release(struct inode *inode, struct file *file) | |||
274 | * Shut off the timer. | 283 | * Shut off the timer. |
275 | * Lock it in if it's a module and we set nowayout | 284 | * Lock it in if it's a module and we set nowayout |
276 | */ | 285 | */ |
277 | if (expect_close == 42) | 286 | if (expect_close == 42) { |
278 | { | ||
279 | wdt977_stop(); | 287 | wdt977_stop(); |
280 | clear_bit(0,&timer_alive); | 288 | clear_bit(0, &timer_alive); |
281 | } else { | 289 | } else { |
282 | wdt977_keepalive(); | 290 | wdt977_keepalive(); |
283 | printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); | 291 | printk(KERN_CRIT PFX |
292 | "Unexpected close, not stopping watchdog!\n"); | ||
284 | } | 293 | } |
285 | expect_close = 0; | 294 | expect_close = 0; |
286 | return 0; | 295 | return 0; |
@@ -301,17 +310,14 @@ static int wdt977_release(struct inode *inode, struct file *file) | |||
301 | static ssize_t wdt977_write(struct file *file, const char __user *buf, | 310 | static ssize_t wdt977_write(struct file *file, const char __user *buf, |
302 | size_t count, loff_t *ppos) | 311 | size_t count, loff_t *ppos) |
303 | { | 312 | { |
304 | if (count) | 313 | if (count) { |
305 | { | 314 | if (!nowayout) { |
306 | if (!nowayout) | ||
307 | { | ||
308 | size_t i; | 315 | size_t i; |
309 | 316 | ||
310 | /* In case it was set long ago */ | 317 | /* In case it was set long ago */ |
311 | expect_close = 0; | 318 | expect_close = 0; |
312 | 319 | ||
313 | for (i = 0; i != count; i++) | 320 | for (i = 0; i != count; i++) { |
314 | { | ||
315 | char c; | 321 | char c; |
316 | if (get_user(c, buf + i)) | 322 | if (get_user(c, buf + i)) |
317 | return -EFAULT; | 323 | return -EFAULT; |
@@ -326,6 +332,14 @@ static ssize_t wdt977_write(struct file *file, const char __user *buf, | |||
326 | return count; | 332 | return count; |
327 | } | 333 | } |
328 | 334 | ||
335 | static const struct watchdog_info ident = { | ||
336 | .options = WDIOF_SETTIMEOUT | | ||
337 | WDIOF_MAGICCLOSE | | ||
338 | WDIOF_KEEPALIVEPING, | ||
339 | .firmware_version = 1, | ||
340 | .identity = WATCHDOG_NAME, | ||
341 | }; | ||
342 | |||
329 | /* | 343 | /* |
330 | * wdt977_ioctl: | 344 | * wdt977_ioctl: |
331 | * @inode: inode of the device | 345 | * @inode: inode of the device |
@@ -337,16 +351,8 @@ static ssize_t wdt977_write(struct file *file, const char __user *buf, | |||
337 | * according to their available features. | 351 | * according to their available features. |
338 | */ | 352 | */ |
339 | 353 | ||
340 | static struct watchdog_info ident = { | 354 | static long wdt977_ioctl(struct file *file, unsigned int cmd, |
341 | .options = WDIOF_SETTIMEOUT | | 355 | unsigned long arg) |
342 | WDIOF_MAGICCLOSE | | ||
343 | WDIOF_KEEPALIVEPING, | ||
344 | .firmware_version = 1, | ||
345 | .identity = WATCHDOG_NAME, | ||
346 | }; | ||
347 | |||
348 | static int wdt977_ioctl(struct inode *inode, struct file *file, | ||
349 | unsigned int cmd, unsigned long arg) | ||
350 | { | 356 | { |
351 | int status; | 357 | int status; |
352 | int new_options, retval = -EINVAL; | 358 | int new_options, retval = -EINVAL; |
@@ -358,11 +364,7 @@ static int wdt977_ioctl(struct inode *inode, struct file *file, | |||
358 | 364 | ||
359 | uarg.i = (int __user *)arg; | 365 | uarg.i = (int __user *)arg; |
360 | 366 | ||
361 | switch(cmd) | 367 | switch (cmd) { |
362 | { | ||
363 | default: | ||
364 | return -ENOTTY; | ||
365 | |||
366 | case WDIOC_GETSUPPORT: | 368 | case WDIOC_GETSUPPORT: |
367 | return copy_to_user(uarg.ident, &ident, | 369 | return copy_to_user(uarg.ident, &ident, |
368 | sizeof(ident)) ? -EFAULT : 0; | 370 | sizeof(ident)) ? -EFAULT : 0; |
@@ -374,12 +376,8 @@ static int wdt977_ioctl(struct inode *inode, struct file *file, | |||
374 | case WDIOC_GETBOOTSTATUS: | 376 | case WDIOC_GETBOOTSTATUS: |
375 | return put_user(0, uarg.i); | 377 | return put_user(0, uarg.i); |
376 | 378 | ||
377 | case WDIOC_KEEPALIVE: | ||
378 | wdt977_keepalive(); | ||
379 | return 0; | ||
380 | |||
381 | case WDIOC_SETOPTIONS: | 379 | case WDIOC_SETOPTIONS: |
382 | if (get_user (new_options, uarg.i)) | 380 | if (get_user(new_options, uarg.i)) |
383 | return -EFAULT; | 381 | return -EFAULT; |
384 | 382 | ||
385 | if (new_options & WDIOS_DISABLECARD) { | 383 | if (new_options & WDIOS_DISABLECARD) { |
@@ -394,6 +392,10 @@ static int wdt977_ioctl(struct inode *inode, struct file *file, | |||
394 | 392 | ||
395 | return retval; | 393 | return retval; |
396 | 394 | ||
395 | case WDIOC_KEEPALIVE: | ||
396 | wdt977_keepalive(); | ||
397 | return 0; | ||
398 | |||
397 | case WDIOC_SETTIMEOUT: | 399 | case WDIOC_SETTIMEOUT: |
398 | if (get_user(new_timeout, uarg.i)) | 400 | if (get_user(new_timeout, uarg.i)) |
399 | return -EFAULT; | 401 | return -EFAULT; |
@@ -407,29 +409,30 @@ static int wdt977_ioctl(struct inode *inode, struct file *file, | |||
407 | case WDIOC_GETTIMEOUT: | 409 | case WDIOC_GETTIMEOUT: |
408 | return put_user(timeout, uarg.i); | 410 | return put_user(timeout, uarg.i); |
409 | 411 | ||
412 | default: | ||
413 | return -ENOTTY; | ||
414 | |||
410 | } | 415 | } |
411 | } | 416 | } |
412 | 417 | ||
413 | static int wdt977_notify_sys(struct notifier_block *this, unsigned long code, | 418 | static int wdt977_notify_sys(struct notifier_block *this, unsigned long code, |
414 | void *unused) | 419 | void *unused) |
415 | { | 420 | { |
416 | if(code==SYS_DOWN || code==SYS_HALT) | 421 | if (code == SYS_DOWN || code == SYS_HALT) |
417 | wdt977_stop(); | 422 | wdt977_stop(); |
418 | return NOTIFY_DONE; | 423 | return NOTIFY_DONE; |
419 | } | 424 | } |
420 | 425 | ||
421 | static const struct file_operations wdt977_fops= | 426 | static const struct file_operations wdt977_fops = { |
422 | { | ||
423 | .owner = THIS_MODULE, | 427 | .owner = THIS_MODULE, |
424 | .llseek = no_llseek, | 428 | .llseek = no_llseek, |
425 | .write = wdt977_write, | 429 | .write = wdt977_write, |
426 | .ioctl = wdt977_ioctl, | 430 | .unlocked_ioctl = wdt977_ioctl, |
427 | .open = wdt977_open, | 431 | .open = wdt977_open, |
428 | .release = wdt977_release, | 432 | .release = wdt977_release, |
429 | }; | 433 | }; |
430 | 434 | ||
431 | static struct miscdevice wdt977_miscdev= | 435 | static struct miscdevice wdt977_miscdev = { |
432 | { | ||
433 | .minor = WATCHDOG_MINOR, | 436 | .minor = WATCHDOG_MINOR, |
434 | .name = "watchdog", | 437 | .name = "watchdog", |
435 | .fops = &wdt977_fops, | 438 | .fops = &wdt977_fops, |
@@ -443,51 +446,48 @@ static int __init wd977_init(void) | |||
443 | { | 446 | { |
444 | int rc; | 447 | int rc; |
445 | 448 | ||
446 | //if (!machine_is_netwinder()) | ||
447 | // return -ENODEV; | ||
448 | |||
449 | printk(KERN_INFO PFX DRIVER_VERSION); | 449 | printk(KERN_INFO PFX DRIVER_VERSION); |
450 | 450 | ||
451 | /* Check that the timeout value is within it's range ; if not reset to the default */ | 451 | /* Check that the timeout value is within its range; |
452 | if (wdt977_set_timeout(timeout)) | 452 | if not reset to the default */ |
453 | { | 453 | if (wdt977_set_timeout(timeout)) { |
454 | wdt977_set_timeout(DEFAULT_TIMEOUT); | 454 | wdt977_set_timeout(DEFAULT_TIMEOUT); |
455 | printk(KERN_INFO PFX "timeout value must be 60<timeout<15300, using %d\n", | 455 | printk(KERN_INFO PFX |
456 | DEFAULT_TIMEOUT); | 456 | "timeout value must be 60 < timeout < 15300, using %d\n", |
457 | DEFAULT_TIMEOUT); | ||
457 | } | 458 | } |
458 | 459 | ||
459 | /* on Netwinder the IOports are already reserved by | 460 | /* on Netwinder the IOports are already reserved by |
460 | * arch/arm/mach-footbridge/netwinder-hw.c | 461 | * arch/arm/mach-footbridge/netwinder-hw.c |
461 | */ | 462 | */ |
462 | if (!machine_is_netwinder()) | 463 | if (!machine_is_netwinder()) { |
463 | { | 464 | if (!request_region(IO_INDEX_PORT, 2, WATCHDOG_NAME)) { |
464 | if (!request_region(IO_INDEX_PORT, 2, WATCHDOG_NAME)) | 465 | printk(KERN_ERR PFX |
465 | { | 466 | "I/O address 0x%04x already in use\n", |
466 | printk(KERN_ERR PFX "I/O address 0x%04x already in use\n", | 467 | IO_INDEX_PORT); |
467 | IO_INDEX_PORT); | ||
468 | rc = -EIO; | 468 | rc = -EIO; |
469 | goto err_out; | 469 | goto err_out; |
470 | } | 470 | } |
471 | } | 471 | } |
472 | 472 | ||
473 | rc = register_reboot_notifier(&wdt977_notifier); | 473 | rc = register_reboot_notifier(&wdt977_notifier); |
474 | if (rc) | 474 | if (rc) { |
475 | { | 475 | printk(KERN_ERR PFX |
476 | printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", | 476 | "cannot register reboot notifier (err=%d)\n", rc); |
477 | rc); | ||
478 | goto err_out_region; | 477 | goto err_out_region; |
479 | } | 478 | } |
480 | 479 | ||
481 | rc = misc_register(&wdt977_miscdev); | 480 | rc = misc_register(&wdt977_miscdev); |
482 | if (rc) | 481 | if (rc) { |
483 | { | 482 | printk(KERN_ERR PFX |
484 | printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", | 483 | "cannot register miscdev on minor=%d (err=%d)\n", |
485 | wdt977_miscdev.minor, rc); | 484 | wdt977_miscdev.minor, rc); |
486 | goto err_out_reboot; | 485 | goto err_out_reboot; |
487 | } | 486 | } |
488 | 487 | ||
489 | printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d, testmode=%i)\n", | 488 | printk(KERN_INFO PFX |
490 | timeout, nowayout, testmode); | 489 | "initialized. timeout=%d sec (nowayout=%d, testmode=%i)\n", |
490 | timeout, nowayout, testmode); | ||
491 | 491 | ||
492 | return 0; | 492 | return 0; |
493 | 493 | ||
@@ -495,7 +495,7 @@ err_out_reboot: | |||
495 | unregister_reboot_notifier(&wdt977_notifier); | 495 | unregister_reboot_notifier(&wdt977_notifier); |
496 | err_out_region: | 496 | err_out_region: |
497 | if (!machine_is_netwinder()) | 497 | if (!machine_is_netwinder()) |
498 | release_region(IO_INDEX_PORT,2); | 498 | release_region(IO_INDEX_PORT, 2); |
499 | err_out: | 499 | err_out: |
500 | return rc; | 500 | return rc; |
501 | } | 501 | } |
@@ -505,7 +505,7 @@ static void __exit wd977_exit(void) | |||
505 | wdt977_stop(); | 505 | wdt977_stop(); |
506 | misc_deregister(&wdt977_miscdev); | 506 | misc_deregister(&wdt977_miscdev); |
507 | unregister_reboot_notifier(&wdt977_notifier); | 507 | unregister_reboot_notifier(&wdt977_notifier); |
508 | release_region(IO_INDEX_PORT,2); | 508 | release_region(IO_INDEX_PORT, 2); |
509 | } | 509 | } |
510 | 510 | ||
511 | module_init(wd977_init); | 511 | module_init(wd977_init); |
diff --git a/drivers/watchdog/wdt_pci.c b/drivers/watchdog/wdt_pci.c index 5d922fd6eafc..ed02bdb38c09 100644 --- a/drivers/watchdog/wdt_pci.c +++ b/drivers/watchdog/wdt_pci.c | |||
@@ -381,7 +381,7 @@ static ssize_t wdtpci_write(struct file *file, const char __user *buf, | |||
381 | 381 | ||
382 | for (i = 0; i != count; i++) { | 382 | for (i = 0; i != count; i++) { |
383 | char c; | 383 | char c; |
384 | if (get_user(c, buf+i)) | 384 | if (get_user(c, buf + i)) |
385 | return -EFAULT; | 385 | return -EFAULT; |
386 | if (c == 'V') | 386 | if (c == 'V') |
387 | expect_close = 42; | 387 | expect_close = 42; |
@@ -428,8 +428,6 @@ static long wdtpci_ioctl(struct file *file, unsigned int cmd, | |||
428 | #endif /* CONFIG_WDT_501_PCI */ | 428 | #endif /* CONFIG_WDT_501_PCI */ |
429 | 429 | ||
430 | switch (cmd) { | 430 | switch (cmd) { |
431 | default: | ||
432 | return -ENOTTY; | ||
433 | case WDIOC_GETSUPPORT: | 431 | case WDIOC_GETSUPPORT: |
434 | return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; | 432 | return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; |
435 | case WDIOC_GETSTATUS: | 433 | case WDIOC_GETSTATUS: |
@@ -449,7 +447,9 @@ static long wdtpci_ioctl(struct file *file, unsigned int cmd, | |||
449 | /* Fall */ | 447 | /* Fall */ |
450 | case WDIOC_GETTIMEOUT: | 448 | case WDIOC_GETTIMEOUT: |
451 | return put_user(heartbeat, p); | 449 | return put_user(heartbeat, p); |
452 | } | 450 | default: |
451 | return -ENOTTY; | ||
452 | } | ||
453 | } | 453 | } |
454 | 454 | ||
455 | /** | 455 | /** |