OSDN Git Service

2013.10.24
[uclinux-h8/uClinux-dist.git] / lib / libnvram / flash_api.c
1 #include <fcntl.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <unistd.h>
6 #include <sys/ioctl.h>
7 #include <linux/types.h>
8
9 struct mtd_info_user {
10         u_char type;
11         u_int32_t flags;
12         u_int32_t size;
13         u_int32_t erasesize;
14         u_int32_t oobblock;
15         u_int32_t oobsize;
16         u_int32_t ecctype;
17         u_int32_t eccsize;
18 };
19
20 struct erase_info_user {
21         u_int32_t start;
22         u_int32_t length;
23 };
24
25 #define MEMGETINFO      _IOR('M', 1, struct mtd_info_user)
26 #define MEMERASE        _IOW('M', 2, struct erase_info_user)
27
28 int mtd_open(const char *name, int flags)
29 {
30         FILE *fp;
31         char dev[80];
32         int i, ret;
33
34         if ((fp = fopen("/proc/mtd", "r"))) {
35                 while (fgets(dev, sizeof(dev), fp)) {
36                         if (sscanf(dev, "mtd%d:", &i) && strstr(dev, name)) {
37                                 snprintf(dev, sizeof(dev), "/dev/mtd/%d", i);
38                                 if ((ret = open(dev, flags)) < 0) {
39                                         snprintf(dev, sizeof(dev), "/dev/mtd%d", i);
40                                         ret = open(dev, flags);
41                                 }
42                                 fclose(fp);
43                                 return ret;
44                         }
45                 }
46                 fclose(fp);
47         }
48         return -1;
49 }
50
51 int flash_read_mac(char *buf)
52 {
53         int fd, ret;
54
55         if (!buf)
56                 return -1;
57         fd = mtd_open("Factory", O_RDONLY);
58         if (fd < 0) {
59                 fprintf(stderr, "Could not open mtd device\n");
60                 return -1;
61         }
62         lseek(fd, 0x2E, SEEK_SET);
63         ret = read(fd, buf, 6);
64         close(fd);
65         return ret;
66 }
67
68 int flash_read_NicConf(char *buf)
69 {
70         int fd, ret;
71
72         if (!buf)
73                 return -1;
74         fd = mtd_open("Factory", O_RDONLY);
75         if (fd < 0) {
76                 fprintf(stderr, "Could not open mtd device\n");
77                 return -1;
78         }
79         lseek(fd, 0x34, SEEK_SET);
80         ret = read(fd, buf, 6);
81         close(fd);
82         return ret;
83 }
84
85 int flash_read(char *buf, off_t from, size_t len)
86 {
87         int fd, ret;
88         struct mtd_info_user info;
89
90         fd = mtd_open("Config", O_RDONLY);
91         if (fd < 0) {
92                 fprintf(stderr, "Could not open mtd device\n");
93                 return -1;
94         }
95
96         if (ioctl(fd, MEMGETINFO, &info)) {
97                 fprintf(stderr, "Could not get mtd device info\n");
98                 close(fd);
99                 return -1;
100         }
101         if (len > info.size) {
102                 fprintf(stderr, "Too many bytes - %d > %d bytes\n", len, info.erasesize);
103                 close(fd);
104                 return -1;
105         }
106
107         close(fd);
108         fd = mtd_open("Config", O_RDONLY);
109         if (fd < 0) {
110                 fprintf(stderr, "Could not open mtd block device\n");
111                 return -1;
112         }
113
114         lseek(fd, from, SEEK_SET);
115         ret = read(fd, buf, len);
116         if (ret == -1) {
117                 fprintf(stderr, "Reading from mtd failed\n");
118                 close(fd);
119                 return -1;
120         }
121
122         close(fd);
123         return ret;
124 }
125
126 #define min(x,y) ({ typeof(x) _x = (x); typeof(y) _y = (y); (void) (&_x == &_y); _x < _y ? _x : _y; })
127
128 int flash_write(char *buf, off_t to, size_t len)
129 {
130         int fd, ret = 0;
131         char *bak = NULL;
132         struct mtd_info_user info;
133         struct erase_info_user ei;
134
135         fd = mtd_open("Config", O_RDWR | O_SYNC);
136         if (fd < 0) {
137                 fprintf(stderr, "Could not open mtd device\n");
138                 return -1;
139         }
140
141         if (ioctl(fd, MEMGETINFO, &info)) {
142                 fprintf(stderr, "Could not get mtd device info\n");
143                 close(fd);
144                 return -1;
145         }
146         if (len > info.size) {
147                 fprintf(stderr, "Too many bytes: %d > %d bytes\n", len, info.erasesize);
148                 close(fd);
149                 return -1;
150         }
151
152         while (len > 0) {
153                 if ((len & (info.erasesize-1)) || (len < info.erasesize)) {
154                         int piece_size;
155                         unsigned int piece, bakaddr;
156
157                         bak = (char *)malloc(info.erasesize);
158                         if (bak == NULL) {
159                                 fprintf(stderr, "Not enough memory\n");
160                                 close(fd);
161                                 return -1;
162                         }
163
164                         bakaddr = to & ~(info.erasesize - 1);
165                         lseek(fd, bakaddr, SEEK_SET);
166
167                         ret = read(fd, bak, info.erasesize);
168                         if (ret == -1) {
169                                 fprintf(stderr, "Reading from mtd failed\n");
170                                 close(fd);
171                                 free(bak);
172                                 return -1;
173                         }
174
175                         piece = to & (info.erasesize - 1);
176                         piece_size = min(len, info.erasesize - piece);
177                         memcpy(bak + piece, buf, piece_size);
178
179                         ei.start = bakaddr;
180                         ei.length = info.erasesize;
181                         if (ioctl(fd, MEMERASE, &ei) < 0) {
182                                 fprintf(stderr, "Erasing mtd failed\n");
183                                 close(fd);
184                                 free(bak);
185                                 return -1;
186                         }
187
188                         lseek(fd, bakaddr, SEEK_SET);
189                         ret = write(fd, bak, info.erasesize);
190                         if (ret == -1) {
191                                 fprintf(stderr, "Writing to mtd failed\n");
192                                 close(fd);
193                                 free(bak);
194                                 return -1;
195                         }
196
197                         free(bak);
198                         buf += piece_size;
199                         to += piece_size;
200                         len -= piece_size;
201                 }
202                 else {
203                         ei.start = to;
204                         ei.length = info.erasesize;
205                         if (ioctl(fd, MEMERASE, &ei) < 0) {
206                                 fprintf(stderr, "Erasing mtd failed\n");
207                                 close(fd);
208                                 return -1;
209                         }
210
211                         ret = write(fd, buf, info.erasesize);
212                         if (ret == -1) {
213                                 fprintf(stderr, "Writing to mtd failed\n");
214                                 close(fd);
215                                 free(bak);
216                                 return -1;
217                         }
218
219                         buf += info.erasesize;
220                         to += info.erasesize;
221                         len -= info.erasesize;
222                 }
223         }
224
225         close(fd);
226         return ret;
227 }
228