-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Some hardware platforms, the TS-7800[1] is one for example, can supply the kernel with an entropy source, albeit a slow one for TS-7800 users, by just reading a particular IO address. This source must not be read above a certain rate otherwise the quality suffers. The driver is then hooked into by calling platform_device_(register|add|del) passing a structure similar to: ------ static struct timeriomem_rng_data ts78xx_ts_rng_data = { .address = (u32 *__iomem) TS_RNG, .period = 1000000, /* one second */ }; static struct platform_device ts78xx_ts_rng_device = { .name = "timeriomem_rng", .id = -1, .dev = { .platform_data = &ts78xx_ts_rng_data, }, .num_resources = 0, }; ------ [1] http://www.embeddedarm.com/products/board-detail.php?product=TS-7800 Signed-off-by: Alexander Clouter <alex@digriz.org.uk> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
- Loading branch information
Alexander Clouter
authored and
Herbert Xu
committed
Feb 22, 2009
1 parent
0a2e821
commit 9c3c133
Showing
4 changed files
with
187 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
/* | ||
* drivers/char/hw_random/timeriomem-rng.c | ||
* | ||
* Copyright (C) 2009 Alexander Clouter <alex@digriz.org.uk> | ||
* | ||
* Derived from drivers/char/hw_random/omap-rng.c | ||
* Copyright 2005 (c) MontaVista Software, Inc. | ||
* Author: Deepak Saxena <dsaxena@plexity.net> | ||
* | ||
* This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License version 2 as | ||
* published by the Free Software Foundation. | ||
* | ||
* Overview: | ||
* This driver is useful for platforms that have an IO range that provides | ||
* periodic random data from a single IO memory address. All the platform | ||
* has to do is provide the address and 'wait time' that new data becomes | ||
* available. | ||
* | ||
* TODO: add support for reading sizes other than 32bits and masking | ||
*/ | ||
|
||
#include <linux/module.h> | ||
#include <linux/kernel.h> | ||
#include <linux/platform_device.h> | ||
#include <linux/hw_random.h> | ||
#include <linux/io.h> | ||
#include <linux/timeriomem-rng.h> | ||
#include <linux/jiffies.h> | ||
#include <linux/sched.h> | ||
#include <linux/timer.h> | ||
#include <linux/completion.h> | ||
|
||
static struct timeriomem_rng_data *timeriomem_rng_data; | ||
|
||
static void timeriomem_rng_trigger(unsigned long); | ||
static DEFINE_TIMER(timeriomem_rng_timer, timeriomem_rng_trigger, 0, 0); | ||
|
||
/* | ||
* have data return 1, however return 0 if we have nothing | ||
*/ | ||
static int timeriomem_rng_data_present(struct hwrng *rng, int wait) | ||
{ | ||
if (rng->priv == 0) | ||
return 1; | ||
|
||
if (!wait || timeriomem_rng_data->present) | ||
return timeriomem_rng_data->present; | ||
|
||
wait_for_completion(&timeriomem_rng_data->completion); | ||
|
||
return 1; | ||
} | ||
|
||
static int timeriomem_rng_data_read(struct hwrng *rng, u32 *data) | ||
{ | ||
unsigned long cur; | ||
s32 delay; | ||
|
||
*data = readl(timeriomem_rng_data->address); | ||
|
||
if (rng->priv != 0) { | ||
cur = jiffies; | ||
|
||
delay = cur - timeriomem_rng_timer.expires; | ||
delay = rng->priv - (delay % rng->priv); | ||
|
||
timeriomem_rng_timer.expires = cur + delay; | ||
timeriomem_rng_data->present = 0; | ||
|
||
init_completion(&timeriomem_rng_data->completion); | ||
add_timer(&timeriomem_rng_timer); | ||
} | ||
|
||
return 4; | ||
} | ||
|
||
static void timeriomem_rng_trigger(unsigned long dummy) | ||
{ | ||
timeriomem_rng_data->present = 1; | ||
complete(&timeriomem_rng_data->completion); | ||
} | ||
|
||
static struct hwrng timeriomem_rng_ops = { | ||
.name = "timeriomem", | ||
.data_present = timeriomem_rng_data_present, | ||
.data_read = timeriomem_rng_data_read, | ||
.priv = 0, | ||
}; | ||
|
||
static int __init timeriomem_rng_probe(struct platform_device *pdev) | ||
{ | ||
int ret; | ||
|
||
timeriomem_rng_data = pdev->dev.platform_data; | ||
|
||
if (timeriomem_rng_data->period != 0 | ||
&& usecs_to_jiffies(timeriomem_rng_data->period) > 0) { | ||
timeriomem_rng_timer.expires = jiffies; | ||
|
||
timeriomem_rng_ops.priv = usecs_to_jiffies( | ||
timeriomem_rng_data->period); | ||
} | ||
timeriomem_rng_data->present = 1; | ||
|
||
ret = hwrng_register(&timeriomem_rng_ops); | ||
if (ret) { | ||
dev_err(&pdev->dev, "problem registering\n"); | ||
return ret; | ||
} | ||
|
||
dev_info(&pdev->dev, "32bits from 0x%p @ %dus\n", | ||
timeriomem_rng_data->address, | ||
timeriomem_rng_data->period); | ||
|
||
return 0; | ||
} | ||
|
||
static int __devexit timeriomem_rng_remove(struct platform_device *pdev) | ||
{ | ||
del_timer_sync(&timeriomem_rng_timer); | ||
hwrng_unregister(&timeriomem_rng_ops); | ||
|
||
return 0; | ||
} | ||
|
||
static struct platform_driver timeriomem_rng_driver = { | ||
.driver = { | ||
.name = "timeriomem_rng", | ||
.owner = THIS_MODULE, | ||
}, | ||
.probe = timeriomem_rng_probe, | ||
.remove = __devexit_p(timeriomem_rng_remove), | ||
}; | ||
|
||
static int __init timeriomem_rng_init(void) | ||
{ | ||
return platform_driver_register(&timeriomem_rng_driver); | ||
} | ||
|
||
static void __exit timeriomem_rng_exit(void) | ||
{ | ||
platform_driver_unregister(&timeriomem_rng_driver); | ||
} | ||
|
||
module_init(timeriomem_rng_init); | ||
module_exit(timeriomem_rng_exit); | ||
|
||
MODULE_LICENSE("GPL"); | ||
MODULE_AUTHOR("Alexander Clouter <alex@digriz.org.uk>"); | ||
MODULE_DESCRIPTION("Timer IOMEM H/W RNG driver"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
/* | ||
* linux/include/linux/timeriomem-rng.h | ||
* | ||
* Copyright (c) 2009 Alexander Clouter <alex@digriz.org.uk> | ||
* | ||
* This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License version 2 as | ||
* published by the Free Software Foundation. | ||
*/ | ||
|
||
#include <linux/completion.h> | ||
|
||
struct timeriomem_rng_data { | ||
struct completion completion; | ||
unsigned int present:1; | ||
|
||
u32 __iomem *address; | ||
|
||
/* measures in usecs */ | ||
unsigned int period; | ||
}; |