diff options
Diffstat (limited to 'drivers/mtd/devices')
-rw-r--r-- | drivers/mtd/devices/docg3.c | 121 | ||||
-rw-r--r-- | drivers/mtd/devices/docg3.h | 13 |
2 files changed, 134 insertions, 0 deletions
diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c index 35df3778f8fd..d7df3114aa17 100644 --- a/drivers/mtd/devices/docg3.c +++ b/drivers/mtd/devices/docg3.c | |||
@@ -1513,6 +1513,123 @@ static int doc_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
1513 | return ret; | 1513 | return ret; |
1514 | } | 1514 | } |
1515 | 1515 | ||
1516 | static struct docg3 *sysfs_dev2docg3(struct device *dev, | ||
1517 | struct device_attribute *attr) | ||
1518 | { | ||
1519 | int floor; | ||
1520 | struct platform_device *pdev = to_platform_device(dev); | ||
1521 | struct mtd_info **docg3_floors = platform_get_drvdata(pdev); | ||
1522 | |||
1523 | floor = attr->attr.name[1] - '0'; | ||
1524 | if (floor < 0 || floor >= DOC_MAX_NBFLOORS) | ||
1525 | return NULL; | ||
1526 | else | ||
1527 | return docg3_floors[floor]->priv; | ||
1528 | } | ||
1529 | |||
1530 | static ssize_t dps0_is_key_locked(struct device *dev, | ||
1531 | struct device_attribute *attr, char *buf) | ||
1532 | { | ||
1533 | struct docg3 *docg3 = sysfs_dev2docg3(dev, attr); | ||
1534 | int dps0; | ||
1535 | |||
1536 | doc_set_device_id(docg3, docg3->device_id); | ||
1537 | dps0 = doc_register_readb(docg3, DOC_DPS0_STATUS); | ||
1538 | doc_set_device_id(docg3, 0); | ||
1539 | |||
1540 | return sprintf(buf, "%d\n", !(dps0 & DOC_DPS_KEY_OK)); | ||
1541 | } | ||
1542 | |||
1543 | static ssize_t dps1_is_key_locked(struct device *dev, | ||
1544 | struct device_attribute *attr, char *buf) | ||
1545 | { | ||
1546 | struct docg3 *docg3 = sysfs_dev2docg3(dev, attr); | ||
1547 | int dps1; | ||
1548 | |||
1549 | doc_set_device_id(docg3, docg3->device_id); | ||
1550 | dps1 = doc_register_readb(docg3, DOC_DPS1_STATUS); | ||
1551 | doc_set_device_id(docg3, 0); | ||
1552 | |||
1553 | return sprintf(buf, "%d\n", !(dps1 & DOC_DPS_KEY_OK)); | ||
1554 | } | ||
1555 | |||
1556 | static ssize_t dps0_insert_key(struct device *dev, | ||
1557 | struct device_attribute *attr, | ||
1558 | const char *buf, size_t count) | ||
1559 | { | ||
1560 | struct docg3 *docg3 = sysfs_dev2docg3(dev, attr); | ||
1561 | int i; | ||
1562 | |||
1563 | if (count != DOC_LAYOUT_DPS_KEY_LENGTH) | ||
1564 | return -EINVAL; | ||
1565 | |||
1566 | doc_set_device_id(docg3, docg3->device_id); | ||
1567 | for (i = 0; i < DOC_LAYOUT_DPS_KEY_LENGTH; i++) | ||
1568 | doc_writeb(docg3, buf[i], DOC_DPS0_KEY); | ||
1569 | doc_set_device_id(docg3, 0); | ||
1570 | return count; | ||
1571 | } | ||
1572 | |||
1573 | static ssize_t dps1_insert_key(struct device *dev, | ||
1574 | struct device_attribute *attr, | ||
1575 | const char *buf, size_t count) | ||
1576 | { | ||
1577 | struct docg3 *docg3 = sysfs_dev2docg3(dev, attr); | ||
1578 | int i; | ||
1579 | |||
1580 | if (count != DOC_LAYOUT_DPS_KEY_LENGTH) | ||
1581 | return -EINVAL; | ||
1582 | |||
1583 | doc_set_device_id(docg3, docg3->device_id); | ||
1584 | for (i = 0; i < DOC_LAYOUT_DPS_KEY_LENGTH; i++) | ||
1585 | doc_writeb(docg3, buf[i], DOC_DPS1_KEY); | ||
1586 | doc_set_device_id(docg3, 0); | ||
1587 | return count; | ||
1588 | } | ||
1589 | |||
1590 | #define FLOOR_SYSFS(id) { \ | ||
1591 | __ATTR(f##id##_dps0_is_keylocked, S_IRUGO, dps0_is_key_locked, NULL), \ | ||
1592 | __ATTR(f##id##_dps1_is_keylocked, S_IRUGO, dps1_is_key_locked, NULL), \ | ||
1593 | __ATTR(f##id##_dps0_protection_key, S_IWUGO, NULL, dps0_insert_key), \ | ||
1594 | __ATTR(f##id##_dps1_protection_key, S_IWUGO, NULL, dps1_insert_key), \ | ||
1595 | } | ||
1596 | |||
1597 | static struct device_attribute doc_sys_attrs[DOC_MAX_NBFLOORS][4] = { | ||
1598 | FLOOR_SYSFS(0), FLOOR_SYSFS(1), FLOOR_SYSFS(2), FLOOR_SYSFS(3) | ||
1599 | }; | ||
1600 | |||
1601 | static int doc_register_sysfs(struct platform_device *pdev, | ||
1602 | struct mtd_info **floors) | ||
1603 | { | ||
1604 | int ret = 0, floor, i = 0; | ||
1605 | struct device *dev = &pdev->dev; | ||
1606 | |||
1607 | for (floor = 0; !ret && floor < DOC_MAX_NBFLOORS && floors[floor]; | ||
1608 | floor++) | ||
1609 | for (i = 0; !ret && i < 4; i++) | ||
1610 | ret = device_create_file(dev, &doc_sys_attrs[floor][i]); | ||
1611 | if (!ret) | ||
1612 | return 0; | ||
1613 | do { | ||
1614 | while (--i >= 0) | ||
1615 | device_remove_file(dev, &doc_sys_attrs[floor][i]); | ||
1616 | i = 4; | ||
1617 | } while (--floor >= 0); | ||
1618 | return ret; | ||
1619 | } | ||
1620 | |||
1621 | static void doc_unregister_sysfs(struct platform_device *pdev, | ||
1622 | struct mtd_info **floors) | ||
1623 | { | ||
1624 | struct device *dev = &pdev->dev; | ||
1625 | int floor, i; | ||
1626 | |||
1627 | for (floor = 0; floor < DOC_MAX_NBFLOORS && floors[floor]; | ||
1628 | floor++) | ||
1629 | for (i = 0; i < 4; i++) | ||
1630 | device_remove_file(dev, &doc_sys_attrs[floor][i]); | ||
1631 | } | ||
1632 | |||
1516 | /* | 1633 | /* |
1517 | * Debug sysfs entries | 1634 | * Debug sysfs entries |
1518 | */ | 1635 | */ |
@@ -1927,6 +2044,9 @@ static int __init docg3_probe(struct platform_device *pdev) | |||
1927 | found++; | 2044 | found++; |
1928 | } | 2045 | } |
1929 | 2046 | ||
2047 | ret = doc_register_sysfs(pdev, docg3_floors); | ||
2048 | if (ret) | ||
2049 | goto err_probe; | ||
1930 | if (!found) | 2050 | if (!found) |
1931 | goto notfound; | 2051 | goto notfound; |
1932 | 2052 | ||
@@ -1963,6 +2083,7 @@ static int __exit docg3_release(struct platform_device *pdev) | |||
1963 | void __iomem *base = docg3->base; | 2083 | void __iomem *base = docg3->base; |
1964 | int floor; | 2084 | int floor; |
1965 | 2085 | ||
2086 | doc_unregister_sysfs(pdev, docg3_floors); | ||
1966 | doc_dbg_unregister(docg3); | 2087 | doc_dbg_unregister(docg3); |
1967 | for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++) | 2088 | for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++) |
1968 | if (docg3_floors[floor]) | 2089 | if (docg3_floors[floor]) |
diff --git a/drivers/mtd/devices/docg3.h b/drivers/mtd/devices/docg3.h index 07182f9d484d..a349915da77d 100644 --- a/drivers/mtd/devices/docg3.h +++ b/drivers/mtd/devices/docg3.h | |||
@@ -118,6 +118,8 @@ | |||
118 | #define DOC_BCH_SYNDROM(idx) (0x1048 + (idx << 0)) | 118 | #define DOC_BCH_SYNDROM(idx) (0x1048 + (idx << 0)) |
119 | 119 | ||
120 | #define DOC_PROTECTION 0x1056 | 120 | #define DOC_PROTECTION 0x1056 |
121 | #define DOC_DPS0_KEY 0x105c | ||
122 | #define DOC_DPS1_KEY 0x105e | ||
121 | #define DOC_DPS0_ADDRLOW 0x1060 | 123 | #define DOC_DPS0_ADDRLOW 0x1060 |
122 | #define DOC_DPS0_ADDRHIGH 0x1062 | 124 | #define DOC_DPS0_ADDRHIGH 0x1062 |
123 | #define DOC_DPS1_ADDRLOW 0x1064 | 125 | #define DOC_DPS1_ADDRLOW 0x1064 |
@@ -252,6 +254,17 @@ | |||
252 | #define DOC_PLANES_STATUS_PLANE0_KO 0x02 | 254 | #define DOC_PLANES_STATUS_PLANE0_KO 0x02 |
253 | #define DOC_PLANES_STATUS_PLANE1_KO 0x04 | 255 | #define DOC_PLANES_STATUS_PLANE1_KO 0x04 |
254 | 256 | ||
257 | /* | ||
258 | * DPS key management | ||
259 | * | ||
260 | * Each floor of docg3 has 2 protection areas: DPS0 and DPS1. These areas span | ||
261 | * across block boundaries, and define whether these blocks can be read or | ||
262 | * written. | ||
263 | * The definition is dynamically stored in page 0 of blocks (2,3) for DPS0, and | ||
264 | * page 0 of blocks (4,5) for DPS1. | ||
265 | */ | ||
266 | #define DOC_LAYOUT_DPS_KEY_LENGTH 8 | ||
267 | |||
255 | /** | 268 | /** |
256 | * struct docg3 - DiskOnChip driver private data | 269 | * struct docg3 - DiskOnChip driver private data |
257 | * @dev: the device currently under control | 270 | * @dev: the device currently under control |