1 /*
2  * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <assert.h>
8 #include <string.h>
9 
10 #include <common/debug.h>
11 #include <drivers/io/io_driver.h>
12 #include <drivers/io/io_dummy.h>
13 #include <drivers/io/io_storage.h>
14 
15 struct file_state {
16 	int in_use;
17 	size_t size;
18 };
19 
20 static struct file_state current_file = {0};
21 
22 /* Identify the device type as dummy */
device_type_dummy(void)23 static io_type_t device_type_dummy(void)
24 {
25 	return IO_TYPE_DUMMY;
26 }
27 
28 /* Dummy device functions */
29 static int dummy_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info);
30 static int dummy_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
31 			     io_entity_t *entity);
32 static int dummy_block_len(io_entity_t *entity, size_t *length);
33 static int dummy_block_read(io_entity_t *entity, uintptr_t buffer,
34 			     size_t length, size_t *length_read);
35 static int dummy_block_close(io_entity_t *entity);
36 static int dummy_dev_close(io_dev_info_t *dev_info);
37 
38 
39 static const io_dev_connector_t dummy_dev_connector = {
40 	.dev_open = dummy_dev_open
41 };
42 
43 
44 static const io_dev_funcs_t dummy_dev_funcs = {
45 	.type = device_type_dummy,
46 	.open = dummy_block_open,
47 	.seek = NULL,
48 	.size = dummy_block_len,
49 	.read = dummy_block_read,
50 	.write = NULL,
51 	.close = dummy_block_close,
52 	.dev_init = NULL,
53 	.dev_close = dummy_dev_close,
54 };
55 
56 
57 static const io_dev_info_t dummy_dev_info = {
58 	.funcs = &dummy_dev_funcs,
59 	.info = (uintptr_t)NULL
60 };
61 
62 
63 /* Open a connection to the dummy device */
dummy_dev_open(const uintptr_t dev_spec,io_dev_info_t ** dev_info)64 static int dummy_dev_open(const uintptr_t dev_spec __attribute__((unused)),
65 			   io_dev_info_t **dev_info)
66 {
67 	assert(dev_info != NULL);
68 	*dev_info = (io_dev_info_t *)&dummy_dev_info;
69 
70 	return 0;
71 }
72 
73 
74 /* Close a connection to the dummy device */
dummy_dev_close(io_dev_info_t * dev_info)75 static int dummy_dev_close(io_dev_info_t *dev_info)
76 {
77 	return 0;
78 }
79 
80 
81 /* Open a file on the dummy device */
dummy_block_open(io_dev_info_t * dev_info,const uintptr_t spec,io_entity_t * entity)82 static int dummy_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
83 			     io_entity_t *entity)
84 {
85 	int result;
86 	const io_block_spec_t *block_spec = (io_block_spec_t *)spec;
87 
88 	if (current_file.in_use == 0) {
89 		assert(block_spec != NULL);
90 		assert(entity != NULL);
91 
92 		current_file.in_use = 1;
93 		current_file.size = block_spec->length;
94 		entity->info = (uintptr_t)&current_file;
95 		result = 0;
96 	} else {
97 		WARN("A Dummy device is already active. Close first.\n");
98 		result = -ENOMEM;
99 	}
100 
101 	return result;
102 }
103 
104 
105 /* Return the size of a file on the dummy device */
dummy_block_len(io_entity_t * entity,size_t * length)106 static int dummy_block_len(io_entity_t *entity, size_t *length)
107 {
108 	assert(entity != NULL);
109 	assert(length != NULL);
110 
111 	*length =  ((struct file_state *)entity->info)->size;
112 
113 	return 0;
114 }
115 
116 
117 /* Read data from a file on the dummy device */
dummy_block_read(io_entity_t * entity,uintptr_t buffer,size_t length,size_t * length_read)118 static int dummy_block_read(io_entity_t *entity, uintptr_t buffer,
119 			     size_t length, size_t *length_read)
120 {
121 	assert(length_read != NULL);
122 
123 	*length_read = length;
124 
125 	return 0;
126 }
127 
128 
129 /* Close a file on the dummy device */
dummy_block_close(io_entity_t * entity)130 static int dummy_block_close(io_entity_t *entity)
131 {
132 	assert(entity != NULL);
133 
134 	entity->info = 0;
135 	current_file.in_use = 0;
136 
137 	return 0;
138 }
139 
140 
141 /* Exported functions */
142 
143 /* Register the dummy driver with the IO abstraction */
register_io_dev_dummy(const io_dev_connector_t ** dev_con)144 int register_io_dev_dummy(const io_dev_connector_t **dev_con)
145 {
146 	int result;
147 
148 	assert(dev_con != NULL);
149 
150 	result = io_register_device(&dummy_dev_info);
151 	if (result == 0)
152 		*dev_con = &dummy_dev_connector;
153 
154 	return result;
155 }
156