]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/sdiotool/cam_sdio.c
Remove spurious newline
[FreeBSD/FreeBSD.git] / usr.bin / sdiotool / cam_sdio.c
1 /*-
2  * Copyright (c) 2017 Ilya Bakulin
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include "cam_sdio.h"
33
34 /* Use CMD52 to read or write a single byte */
35 int
36 sdio_rw_direct(struct cam_device *dev,
37                uint8_t func_number,
38                uint32_t addr,
39                uint8_t is_write,
40                uint8_t *data, uint8_t *resp) {
41         union ccb *ccb;
42         uint32_t flags;
43         uint32_t arg;
44         int retval = 0;
45
46         ccb = cam_getccb(dev);
47         if (ccb == NULL) {
48                 warnx("%s: error allocating CCB", __func__);
49                 return (-1);
50         }
51         bzero(&(&ccb->ccb_h)[1],
52               sizeof(union ccb) - sizeof(struct ccb_hdr));
53
54         flags = MMC_RSP_R5 | MMC_CMD_AC;
55         arg = SD_IO_RW_FUNC(func_number) | SD_IO_RW_ADR(addr);
56         if (is_write)
57                 arg |= SD_IO_RW_WR | SD_IO_RW_RAW | SD_IO_RW_DAT(*data);
58
59         cam_fill_mmcio(&ccb->mmcio,
60                        /*retries*/ 0,
61                        /*cbfcnp*/ NULL,
62                        /*flags*/ CAM_DIR_NONE,
63                        /*mmc_opcode*/ SD_IO_RW_DIRECT,
64                        /*mmc_arg*/ arg,
65                        /*mmc_flags*/ flags,
66                        /*mmc_data*/ 0,
67                        /*timeout*/ 5000);
68
69         if (((retval = cam_send_ccb(dev, ccb)) < 0)
70             || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
71                 const char warnstr[] = "error sending command";
72
73                 if (retval < 0)
74                         warn(warnstr);
75                 else
76                         warnx(warnstr);
77                 return (-1);
78         }
79
80         *resp = ccb->mmcio.cmd.resp[0] & 0xFF;
81         cam_freeccb(ccb);
82         return (retval);
83 }
84
85 /*
86  * CMD53 -- IO_RW_EXTENDED
87  * Use to read or write memory blocks
88  *
89  * is_increment=1: FIFO mode
90  * blk_count > 0: block mode
91  */
92 int
93 sdio_rw_extended(struct cam_device *dev,
94                  uint8_t func_number,
95                  uint32_t addr,
96                  uint8_t is_write,
97                  caddr_t data, size_t datalen,
98                  uint8_t is_increment,
99                  uint16_t blk_count) {
100         union ccb *ccb;
101         uint32_t flags;
102         uint32_t arg;
103         uint32_t cam_flags;
104         uint8_t resp;
105         struct mmc_data mmcd;
106         int retval = 0;
107
108         if (blk_count != 0) {
109                 warnx("%s: block mode is not supported yet", __func__);
110                 return (-1);
111         }
112
113         ccb = cam_getccb(dev);
114         if (ccb == NULL) {
115                 warnx("%s: error allocating CCB", __func__);
116                 return (-1);
117         }
118         bzero(&(&ccb->ccb_h)[1],
119               sizeof(union ccb) - sizeof(struct ccb_hdr));
120
121         flags = MMC_RSP_R5 | MMC_CMD_ADTC;
122         arg = SD_IO_RW_FUNC(func_number) | SD_IO_RW_ADR(addr) |
123                 SD_IOE_RW_LEN(datalen);
124
125         if (is_increment)
126                 arg |= SD_IO_RW_INCR;
127
128         mmcd.data = data;
129         mmcd.len = datalen;
130         mmcd.xfer_len = 0; /* not used by MMCCAM */
131         mmcd.mrq = NULL; /* not used by MMCCAM */
132
133         if (is_write) {
134                 arg |= SD_IO_RW_WR;
135                 cam_flags = CAM_DIR_OUT;
136                 mmcd.flags = MMC_DATA_WRITE;
137         } else {
138                 cam_flags = CAM_DIR_IN;
139                 mmcd.flags = MMC_DATA_READ;
140         }
141         cam_fill_mmcio(&ccb->mmcio,
142                        /*retries*/ 0,
143                        /*cbfcnp*/ NULL,
144                        /*flags*/ cam_flags,
145                        /*mmc_opcode*/ SD_IO_RW_EXTENDED,
146                        /*mmc_arg*/ arg,
147                        /*mmc_flags*/ flags,
148                        /*mmc_data*/ &mmcd,
149                        /*timeout*/ 5000);
150
151         if (((retval = cam_send_ccb(dev, ccb)) < 0)
152             || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
153                 const char warnstr[] = "error sending command";
154
155                 if (retval < 0)
156                         warn(warnstr);
157                 else
158                         warnx(warnstr);
159                 return (-1);
160         }
161
162         resp = ccb->mmcio.cmd.resp[0] & 0xFF;
163         if (resp != 0)
164                 warn("Response from CMD53 is not 0?!");
165         cam_freeccb(ccb);
166         return (retval);
167 }
168
169
170 int
171 sdio_read_bool_for_func(struct cam_device *dev, uint32_t addr, uint8_t func_number, uint8_t *is_enab) {
172         uint8_t resp;
173         int ret;
174
175         ret = sdio_rw_direct(dev, 0, addr, 0, NULL, &resp);
176         if (ret < 0)
177                 return ret;
178
179         *is_enab = (resp & (1 << func_number)) > 0 ? 1 : 0;
180
181         return (0);
182 }
183
184 int
185 sdio_set_bool_for_func(struct cam_device *dev, uint32_t addr, uint8_t func_number, int enable) {
186         uint8_t resp;
187         int ret;
188         uint8_t is_enabled;
189
190         ret = sdio_rw_direct(dev, 0, addr, 0, NULL, &resp);
191         if (ret != 0)
192                 return ret;
193
194         is_enabled = resp & (1 << func_number);
195         if ((is_enabled !=0 && enable == 1) || (is_enabled == 0 && enable == 0))
196                 return 0;
197
198         if (enable)
199                 resp |= 1 << func_number;
200         else
201                 resp &= ~ (1 << func_number);
202
203         ret = sdio_rw_direct(dev, 0, addr, 1, &resp, &resp);
204
205         return ret;
206 }
207
208 /* Conventional I/O functions */
209 uint8_t
210 sdio_read_1(struct cam_device *dev, uint8_t func_number, uint32_t addr, int *ret) {
211         uint8_t val;
212         *ret = sdio_rw_direct(dev, func_number, addr, 0, NULL, &val);
213         return val;
214 }
215
216 int
217 sdio_write_1(struct cam_device *dev, uint8_t func_number, uint32_t addr, uint8_t val) {
218         uint8_t _val;
219         return sdio_rw_direct(dev, func_number, addr, 0, &val, &_val);
220 }
221
222 uint16_t
223 sdio_read_2(struct cam_device *dev, uint8_t func_number, uint32_t addr, int *ret) {
224         uint16_t val;
225         *ret = sdio_rw_extended(dev, func_number, addr,
226                                 /* is_write */ 0,
227                                 /* data */ (caddr_t) &val,
228                                 /* datalen */ sizeof(val),
229                                 /* is_increment */ 1,
230                                 /* blk_count */ 0
231                 );
232         return val;
233 }
234
235
236 int
237 sdio_write_2(struct cam_device *dev, uint8_t func_number, uint32_t addr, uint16_t val) {
238         return sdio_rw_extended(dev, func_number, addr,
239                                 /* is_write */ 1,
240                                 /* data */ (caddr_t) &val,
241                                 /* datalen */ sizeof(val),
242                                 /* is_increment */ 1,
243                                 /* blk_count */ 0
244                 );
245 }
246
247 uint32_t
248 sdio_read_4(struct cam_device *dev, uint8_t func_number, uint32_t addr, int *ret) {
249         uint32_t val;
250         *ret = sdio_rw_extended(dev, func_number, addr,
251                                 /* is_write */ 0,
252                                 /* data */ (caddr_t) &val,
253                                 /* datalen */ sizeof(val),
254                                 /* is_increment */ 1,
255                                 /* blk_count */ 0
256                 );
257         return val;
258 }
259
260
261 int
262 sdio_write_4(struct cam_device *dev, uint8_t func_number, uint32_t addr, uint32_t val) {
263         return sdio_rw_extended(dev, func_number, addr,
264                                 /* is_write */ 1,
265                                 /* data */ (caddr_t) &val,
266                                 /* datalen */ sizeof(val),
267                                 /* is_increment */ 1,
268                                 /* blk_count */ 0
269                 );
270 }
271
272 /* Higher-level wrappers for certain management operations */
273 int
274 sdio_is_func_ready(struct cam_device *dev, uint8_t func_number, uint8_t *is_enab) {
275         return sdio_read_bool_for_func(dev, SD_IO_CCCR_FN_READY, func_number, is_enab);
276 }
277
278 int
279 sdio_is_func_enabled(struct cam_device *dev, uint8_t func_number, uint8_t *is_enab) {
280         return sdio_read_bool_for_func(dev, SD_IO_CCCR_FN_ENABLE, func_number, is_enab);
281 }
282
283 int
284 sdio_func_enable(struct cam_device *dev, uint8_t func_number, int enable) {
285         return sdio_set_bool_for_func(dev, SD_IO_CCCR_FN_ENABLE, func_number, enable);
286 }
287
288 int
289 sdio_is_func_intr_enabled(struct cam_device *dev, uint8_t func_number, uint8_t *is_enab) {
290         return sdio_read_bool_for_func(dev, SD_IO_CCCR_INT_ENABLE, func_number, is_enab);
291 }
292
293 int
294 sdio_func_intr_enable(struct cam_device *dev, uint8_t func_number, int enable) {
295         return sdio_set_bool_for_func(dev, SD_IO_CCCR_INT_ENABLE, func_number, enable);
296 }
297
298 int
299 sdio_card_set_bus_width(struct cam_device *dev, enum mmc_bus_width bw) {
300         int ret;
301         uint8_t ctl_val;
302         ret = sdio_rw_direct(dev, 0, SD_IO_CCCR_BUS_WIDTH, 0, NULL, &ctl_val);
303         if (ret < 0) {
304                 warn("Error getting CCCR_BUS_WIDTH value");
305                 return ret;
306         }
307         ctl_val &= ~0x3;
308         switch (bw) {
309         case bus_width_1:
310                 /* Already set to 1-bit */
311                 break;
312         case bus_width_4:
313                 ctl_val |= CCCR_BUS_WIDTH_4;
314                 break;
315         case bus_width_8:
316                 warn("Cannot do 8-bit on SDIO yet");
317                 return -1;
318                 break;
319         }
320         ret = sdio_rw_direct(dev, 0, SD_IO_CCCR_BUS_WIDTH, 1, &ctl_val, &ctl_val);
321         if (ret < 0) {
322                 warn("Error setting CCCR_BUS_WIDTH value");
323                 return ret;
324         }
325         return ret;
326 }
327
328 int
329 sdio_func_read_cis(struct cam_device *dev, uint8_t func_number,
330                    uint32_t cis_addr, struct cis_info *info) {
331         uint8_t tuple_id, tuple_len, tuple_count;
332         uint32_t addr;
333
334         char *cis1_info[4];
335         int start, i, ch, count, ret;
336         char cis1_info_buf[256];
337
338         tuple_count = 0; /* Use to prevent infinite loop in case of parse errors */
339         memset(cis1_info_buf, 0, 256);
340         do {
341                 addr = cis_addr;
342                 tuple_id = sdio_read_1(dev, 0, addr++, &ret);
343                 if (tuple_id == SD_IO_CISTPL_END)
344                         break;
345                 if (tuple_id == 0) {
346                         cis_addr++;
347                         continue;
348                 }
349                 tuple_len = sdio_read_1(dev, 0, addr++, &ret);
350                 if (tuple_len == 0 && tuple_id != 0x00) {
351                         warn("Parse error: 0-length tuple %02X\n", tuple_id);
352                         return -1;
353                 }
354
355                 switch (tuple_id) {
356                 case SD_IO_CISTPL_VERS_1:
357                         addr += 2;
358                         for (count = 0, start = 0, i = 0;
359                              (count < 4) && ((i + 4) < 256); i++) {
360                                 ch = sdio_read_1(dev, 0, addr + i, &ret);
361                                 printf("count=%d, start=%d, i=%d, Got %c (0x%02x)\n", count, start, i, ch, ch);
362                                 if (ch == 0xff)
363                                         break;
364                                 cis1_info_buf[i] = ch;
365                                 if (ch == 0) {
366                                         cis1_info[count] =
367                                                 cis1_info_buf + start;
368                                         start = i + 1;
369                                         count++;
370                                 }
371                         }
372                         printf("Card info:");
373                         for (i=0; i<4; i++)
374                                 if (cis1_info[i])
375                                         printf(" %s", cis1_info[i]);
376                         printf("\n");
377                         break;
378                 case SD_IO_CISTPL_MANFID:
379                         info->man_id =  sdio_read_1(dev, 0, addr++, &ret);
380                         info->man_id |= sdio_read_1(dev, 0, addr++, &ret) << 8;
381
382                         info->prod_id =  sdio_read_1(dev, 0, addr++, &ret);
383                         info->prod_id |= sdio_read_1(dev, 0, addr++, &ret) << 8;
384                         break;
385                 case SD_IO_CISTPL_FUNCID:
386                         /* not sure if we need to parse it? */
387                         break;
388                 case SD_IO_CISTPL_FUNCE:
389                         if (tuple_len < 4) {
390                                 printf("FUNCE is too short: %d\n", tuple_len);
391                                 break;
392                         }
393                         if (func_number == 0) {
394                                 /* skip extended_data */
395                                 addr++;
396                                 info->max_block_size  = sdio_read_1(dev, 0, addr++, &ret);
397                                 info->max_block_size |= sdio_read_1(dev, 0, addr++, &ret) << 8;
398                         } else {
399                                 info->max_block_size  = sdio_read_1(dev, 0, addr + 0xC, &ret);
400                                 info->max_block_size |= sdio_read_1(dev, 0, addr + 0xD, &ret) << 8;
401                         }
402                         break;
403                 default:
404                         warnx("Skipping tuple ID %02X len %02X\n", tuple_id, tuple_len);
405                 }
406                 cis_addr += tuple_len + 2;
407                 tuple_count++;
408         } while (tuple_count < 20);
409
410         return 0;
411 }
412
413 uint32_t
414 sdio_get_common_cis_addr(struct cam_device *dev) {
415         uint32_t addr;
416         int ret;
417
418         addr =  sdio_read_1(dev, 0, SD_IO_CCCR_CISPTR, &ret);
419         addr |= sdio_read_1(dev, 0, SD_IO_CCCR_CISPTR + 1, &ret) << 8;
420         addr |= sdio_read_1(dev, 0, SD_IO_CCCR_CISPTR + 2, &ret) << 16;
421
422         if (addr < SD_IO_CIS_START || addr > SD_IO_CIS_START + SD_IO_CIS_SIZE) {
423                 warn("Bad CIS address: %04X\n", addr);
424                 addr = 0;
425         }
426
427         return addr;
428 }
429
430 void sdio_card_reset(struct cam_device *dev) {
431         int ret;
432         uint8_t ctl_val;
433         ret = sdio_rw_direct(dev, 0, SD_IO_CCCR_CTL, 0, NULL, &ctl_val);
434         if (ret < 0)
435                 errx(1, "Error getting CCCR_CTL value");
436         ctl_val |= CCCR_CTL_RES;
437         ret = sdio_rw_direct(dev, 0, SD_IO_CCCR_CTL, 1, &ctl_val, &ctl_val);
438         if (ret < 0)
439                 errx(1, "Error setting CCCR_CTL value");
440 }