3f59d59e3b5ff0940779617c09a107a904f41ff9
[packages.git] / utils / retutahvo / files / src / retutahvo.c
1 /*
2  *   Copyright (C) 2010 Michael Buesch <mb@bu3sch.de>
3  *
4  *   This program is free software; you can redistribute it and/or
5  *   modify it under the terms of the GNU General Public License
6  *   as published by the Free Software Foundation; either version 2
7  *   of the License, or (at your option) any later version.
8  *
9  *   This program is distributed in the hope that it will be useful,
10  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *   GNU General Public License for more details.
13  */
14
15 #include <stdio.h>
16 #include <stdint.h>
17 #include <string.h>
18 #include <errno.h>
19 #include <unistd.h>
20 #include <fcntl.h>
21 #include <sys/ioctl.h>
22
23 typedef uint8_t u8;
24 typedef uint16_t u16;
25 typedef uint32_t u32;
26
27 #include "user_retu_tahvo.h"
28
29
30 static const char * chip2str(int chip)
31 {
32         switch (chip) {
33         case CHIP_RETU:
34                 return "Retu";
35         case CHIP_TAHVO:
36                 return "Tahvo";
37         }
38         return "UNKNOWN";
39 }
40
41 static int str2uint(const char *str, unsigned int *value)
42 {
43         char *tail;
44
45         *value = strtoul(str, &tail, 0);
46         if (*tail != '\0')
47                 return -1;
48
49         return 0;
50 }
51
52 static int open_dev(int chip)
53 {
54         const char *path;
55         int fd;
56
57         switch (chip) {
58         case CHIP_RETU:
59                 path = "/dev/retu";
60                 break;
61         case CHIP_TAHVO:
62                 path = "/dev/tahvo";
63                 break;
64         default:
65                 return -1;
66         }
67
68         fd = open(path, O_RDWR);
69         if (fd < 0) {
70                 fprintf(stderr, "Failed to open %d: %s\n",
71                         path, strerror(errno));
72         }
73
74         return fd;
75 }
76
77 #define MASKREG(mask, reg)      ((mask) | (((reg) & 0x3F) << 16))
78
79 static unsigned int encrapify_value(unsigned int value, unsigned int mask)
80 {
81         if (!mask)
82                 return 0;
83         while (!(mask & 1)) {
84                 value >>= 1;
85                 mask >>= 1;
86         }
87
88         return value;
89 }
90
91 static unsigned int decrapify_value(unsigned int value, unsigned int mask)
92 {
93         if (!mask)
94                 return 0;
95         while (!(mask & 1)) {
96                 value <<= 1;
97                 mask >>= 1;
98         }
99
100         return value;
101 }
102
103 static int do_read(int chip, int fd, unsigned int mask, unsigned int reg, unsigned int *value)
104 {
105         unsigned int command;
106         int res;
107
108         switch (chip) {
109         case CHIP_RETU:
110                 command = RETU_IOCH_READ;
111                 break;
112         case CHIP_TAHVO:
113                 command = TAHVO_IOCH_READ;
114                 break;
115         default:
116                 return -1;
117         }
118         res = ioctl(fd, command, MASKREG(mask, reg));
119         if (res < 0)
120                 return -1;
121         *value = decrapify_value(res, mask);
122
123         return 0;
124 }
125
126 static int task_read(int chip, unsigned int reg, unsigned int *value)
127 {
128         int fd, err;
129
130         fd = open_dev(chip);
131         if (fd < 0)
132                 return -1;
133         err = do_read(chip, fd, 0xFFFF, reg, value);
134         close(fd);
135
136         return err;
137 }
138
139 static int do_write(int chip, int fd, unsigned int mask, unsigned int reg, unsigned int value)
140 {
141         struct retu_tahvo_write_parms p;
142         unsigned int command;
143         int err;
144
145         switch (chip) {
146         case CHIP_RETU:
147                 command = RETU_IOCX_WRITE;
148                 break;
149         case CHIP_TAHVO:
150                 command = TAHVO_IOCX_WRITE;
151                 break;
152         default:
153                 return -1;
154         }
155
156         memset(&p, 0, sizeof(p));
157         p.field = MASKREG(mask, reg);
158         p.value = encrapify_value(value, mask);
159
160         err = ioctl(fd, command, &p);
161         if (err) {
162                 fprintf(stderr, "Write ioctl failed\n");
163                 return -1;
164         }
165         if (p.result != 0) {
166                 fprintf(stderr, "Failed to write\n");
167                 return -1;
168         }
169
170         return 0;
171 }
172
173 static int task_maskset(int chip, unsigned int reg, unsigned int mask, unsigned int set)
174 {
175         int fd, err;
176         unsigned int value;
177
178         mask &= 0xFFFF;
179         set &= 0xFFFF;
180
181         fd = open_dev(chip);
182         if (fd < 0)
183                 return -1;
184         err = do_write(chip, fd, mask, reg, set);
185         close(fd);
186
187         return err;
188 }
189
190 static int task_write(int chip, unsigned int reg, unsigned int value)
191 {
192         return task_maskset(chip, reg, 0xFFFF, value);
193 }
194
195 static void usage(FILE *fd, int argc, char **argv)
196 {
197         fprintf(fd, "Usage: %s CHIP TASK REG [VALUE...]\n", argv[0]);
198         fprintf(fd, "  CHIP is one of RETU or TAHVO\n");
199         fprintf(fd, "  TASK is one of READ, WRITE or MASKSET\n");
200         fprintf(fd, "  VALUE are values, depending on TASK\n");
201 }
202
203 int main(int argc, char **argv)
204 {
205         const char *chip_str, *task, *reg_str;
206         int chip;
207         unsigned int reg, mask, set, value;
208         int err;
209
210         if (argc != 4 && argc != 5 && argc != 6)
211                 goto err_usage;
212         chip_str = argv[1];
213         task = argv[2];
214         reg_str = argv[3];
215
216         if (strcasecmp(chip_str, "retu") == 0)
217                 chip = CHIP_RETU;
218         else if (strcasecmp(chip_str, "tahvo") == 0)
219                 chip = CHIP_TAHVO;
220         else
221                 goto err_usage;
222
223         err = str2uint(reg_str, &reg);
224         if (err)
225                 goto err_usage;
226
227         if (strcasecmp(task, "read") == 0) {
228                 if (argc != 4)
229                         goto err_usage;
230                 err = task_read(chip, reg, &value);
231                 if (err) {
232                         fprintf(stderr, "Failed to read %s register 0x%02X\n",
233                                 chip2str(chip), reg);
234                         return 1;
235                 }
236                 printf("0x%04X\n", value);
237         } else if (strcasecmp(task, "write") == 0) {
238                 if (argc != 5)
239                         goto err_usage;
240                 err = str2uint(argv[4], &value);
241                 if (err)
242                         goto err_usage;
243                 err = task_write(chip, reg, value);
244                 if (err) {
245                         fprintf(stderr, "Failed to write %s register 0x%02X\n",
246                                 chip2str(chip), reg);
247                         return 1;
248                 }
249         } else if (strcasecmp(task, "maskset") == 0) {
250                 if (argc != 6)
251                         goto err_usage;
252                 err = str2uint(argv[4], &mask);
253                 err |= str2uint(argv[5], &set);
254                 if (err)
255                         goto err_usage;
256                 err = task_maskset(chip, reg, mask, set);
257                 if (err) {
258                         fprintf(stderr, "Failed to maskset %s register 0x%02X\n",
259                                 chip2str(chip), reg);
260                         return 1;
261                 }
262         } else
263                 goto err_usage;
264
265         return 0;
266
267 err_usage:
268         usage(stderr, argc, argv);
269         return 1;
270 }