diff options
author | Uwe Stuehler <uwe@cvs.openbsd.org> | 2007-05-26 19:19:48 +0000 |
---|---|---|
committer | Uwe Stuehler <uwe@cvs.openbsd.org> | 2007-05-26 19:19:48 +0000 |
commit | c38ff95999be32f68ae6d64861823add79aac35c (patch) | |
tree | c473fb07381f83b60928851d35720ccc0076181e /usr.sbin/sdio | |
parent | 44455e01ff2ab5a0d447eb8fdfc5711641219b9d (diff) |
Rewrite the sdio(8) tool so that it can send arbitrary MMC commands.
Diffstat (limited to 'usr.sbin/sdio')
-rw-r--r-- | usr.sbin/sdio/Makefile | 4 | ||||
-rw-r--r-- | usr.sbin/sdio/sdio.8 | 25 | ||||
-rw-r--r-- | usr.sbin/sdio/sdio.c | 266 |
3 files changed, 134 insertions, 161 deletions
diff --git a/usr.sbin/sdio/Makefile b/usr.sbin/sdio/Makefile index fb4fb6a52ff..54eee98e12c 100644 --- a/usr.sbin/sdio/Makefile +++ b/usr.sbin/sdio/Makefile @@ -1,6 +1,8 @@ -# $OpenBSD: Makefile,v 1.1 2006/11/28 20:26:31 uwe Exp $ +# $OpenBSD: Makefile,v 1.2 2007/05/26 19:19:47 uwe Exp $ PROG= sdio MAN= sdio.8 +CPPFLAGS+= -I${.CURDIR}/../../sys + .include <bsd.prog.mk> diff --git a/usr.sbin/sdio/sdio.8 b/usr.sbin/sdio/sdio.8 index c0979fba0dc..719cdb6a1c6 100644 --- a/usr.sbin/sdio/sdio.8 +++ b/usr.sbin/sdio/sdio.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: sdio.8,v 1.1 2006/11/28 20:26:31 uwe Exp $ +.\" $OpenBSD: sdio.8,v 1.2 2007/05/26 19:19:47 uwe Exp $ .\" .\" Uwe Stuehler, 2006. Public Domain. .\" @@ -10,10 +10,33 @@ .Nd SD/MMC/SDIO interface .Sh SYNOPSIS .Nm sdio +.Fl d Ar debug_flags +.Nm sdio +.Fl c Ar index Ar argument Ar response_type +.Op Ar data ... .Sh DESCRIPTION The .Nm program provides command-level access to SD/MMC and SDIO cards. +.Pp +The options are as follows: +.Bl -tag -width Ds +The +.Fl c +option sends arbitrary commands to the card. +.It Fl d Ar debug_flags +The +.Fl d +option sets the debug level for the SD/MMC subsystem and +.Ar debug_flags +is a 16-bit value. +The low byte sets the debug level for +.Xr sdmmc 4 , +the high byte sets the debug level for +.Xr sdhc 4 +or other host controller drivers. +.El +.\" .Sh MMC/SD/SDIO COMMANDS .Sh SEE ALSO .Xr intro 8 .Sh HISTORY diff --git a/usr.sbin/sdio/sdio.c b/usr.sbin/sdio/sdio.c index 80e7b2d5c81..48f2904d6af 100644 --- a/usr.sbin/sdio/sdio.c +++ b/usr.sbin/sdio/sdio.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sdio.c,v 1.2 2006/11/29 01:03:45 uwe Exp $ */ +/* $OpenBSD: sdio.c,v 1.3 2007/05/26 19:19:47 uwe Exp $ */ /* * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org> @@ -21,10 +21,12 @@ #include <fcntl.h> #include <stdlib.h> #include <stdio.h> +#include <string.h> #include <unistd.h> #include <sys/ioctl.h> #include <sys/limits.h> +#include <sys/param.h> #include <dev/biovar.h> @@ -46,13 +48,10 @@ static int sdio_open(const char *, struct sdio_hdl **); static void sdio_close(struct sdio_hdl *); static int sdio_debug(struct sdio_hdl *, int); static int sdio_exec(struct sdio_hdl *, struct sdmmc_command *); -static int sdio_cmd52(struct sdio_hdl *, int, int, u_int8_t *, int); -static int sdio_cmd53(struct sdio_hdl *, int, int, u_char *, size_t, - int); +static int sdio_command(struct sdio_hdl *, int, int, char *[]); -int sdio_read(struct sdio_hdl *, int, int, int *, int); -int sdio_write(struct sdio_hdl *, int, int, int, int); static int strtoint(const char *, const char **); +static int strtorsp(const char *, const char **); static void usage(void) __dead; static int @@ -106,8 +105,8 @@ sdio_exec(struct sdio_hdl *hdl, struct sdmmc_command *cmd) struct bio_sdmmc_command bcmd; bcopy(cmd, &bcmd.cmd, sizeof *cmd); - bcmd.cookie = hdl->cookie; + if (ioctl(hdl->bio, SDIOCEXECMMC, &bcmd) == -1) err(1, "ioctl"); @@ -120,102 +119,79 @@ sdio_exec(struct sdio_hdl *hdl, struct sdmmc_command *cmd) } static int -sdio_cmd52(struct sdio_hdl *hdl, int fnum, int reg, u_int8_t *data, int arg) +sdio_command(struct sdio_hdl *hdl, int datalen, int argc, char *argv[]) { struct sdmmc_command cmd; - int function; + const char *errstr; + u_char *buf = NULL; int error; + int i; - arg &= SD_ARG_CMD52_READ | SD_ARG_CMD52_WRITE; - - arg |= (fnum & SD_ARG_CMD52_FUNC_MASK) << - SD_ARG_CMD52_FUNC_SHIFT; - arg |= (reg & SD_ARG_CMD52_REG_MASK) << - SD_ARG_CMD52_REG_SHIFT; - arg |= (*data & SD_ARG_CMD52_DATA_MASK) << - SD_ARG_CMD52_DATA_SHIFT; + if (argc < 3) + errx(1, "sdio_command: wrong # args\n"); bzero(&cmd, sizeof cmd); - cmd.c_opcode = SD_IO_RW_DIRECT; - cmd.c_arg = arg; - cmd.c_flags = SCF_CMD_BC/* XXX */ | SCF_RSP_R5; - if (sdio_exec(hdl, &cmd) != 0) - return -1; + cmd.c_opcode = strtoint(argv[0], &errstr); + if (!errstr && cmd.c_opcode > 63) + errstr = "out of range"; + if (errstr) + errx(1, "command index is %s: %s", argv[0]); - *data = SD_R5_DATA(cmd.c_resp); - return 0; -} + cmd.c_arg = strtoint(argv[1], &errstr); + if (errstr) + errx(1, "command argument is %s: %s", argv[1]); -static int -sdio_cmd53(struct sdio_hdl *hdl, int fnum, int reg, u_char *data, - size_t datalen, int arg) -{ - struct sdmmc_command cmd; - int function; - int error; + cmd.c_flags = strtorsp(argv[2], &errstr); + if (errstr) + errx(1, "response type is %s: %s", argv[2]); - arg &= SD_ARG_CMD53_READ | SD_ARG_CMD53_WRITE | - SD_ARG_CMD53_INCREMENT; + argc -= 3; + argv += 3; - arg |= (fnum & SD_ARG_CMD53_FUNC_MASK) << - SD_ARG_CMD53_FUNC_SHIFT; - arg |= (reg & SD_ARG_CMD53_REG_MASK) << - SD_ARG_CMD53_REG_SHIFT; - arg |= (datalen & SD_ARG_CMD53_LENGTH_MASK) << - SD_ARG_CMD53_LENGTH_SHIFT; + if (datalen > 0) { + if (argc == 0) + cmd.c_flags |= SCF_CMD_READ; - bzero(&cmd, sizeof cmd); - cmd.c_opcode = SD_IO_RW_EXTENDED; - cmd.c_arg = arg; - cmd.c_flags = SCF_CMD_ADTC/* XXX */ | SCF_RSP_R5; - cmd.c_data = data; - cmd.c_datalen = datalen; - cmd.c_blklen = datalen; + if (argc > 0 && argc < datalen) + errx(2, "expected %d more argument(s)", + datalen - argc); - if (!(arg & SD_ARG_CMD53_WRITE)) - cmd.c_flags |= SCF_CMD_READ; + buf = (u_char *)malloc(datalen); + if (buf == NULL) + err(1, NULL); - return sdio_exec(hdl, &cmd); -} - -int -sdio_read(struct sdio_hdl *hdl, int fnum, int addr, int *ival, int width) -{ - u_int16_t v2 = 0; - u_int8_t v1 = 0; - int error; + for (i = 0; argc > 0 && i < datalen; i++) { + int ival = (u_int8_t)strtoint(argv[i], &errstr); + if (!errstr && (ival < 0 || ival > UCHAR_MAX)) + errstr = "out of range"; + if (errstr) + errx(1, "data byte at offset %d is %s: %s", + i, errstr, argv[i]); + buf[i] = (u_int8_t)ival; + } - switch (width) { - case 2: - error = sdio_cmd53(hdl, fnum, addr, (u_char *)&v2, 2, - SD_ARG_CMD53_READ | SD_ARG_CMD53_INCREMENT); - if (!error) - *ival = (int)v2; - return error; - default: - error = sdio_cmd52(hdl, fnum, addr, &v1, SD_ARG_CMD52_READ); - if (!error) - *ival = (int)v1; - return error; + cmd.c_datalen = datalen; + cmd.c_data = (void *)buf; + /* XXX cmd.c_blklen = ??? */ + cmd.c_blklen = MIN(cmd.c_datalen, 512); } -} -int -sdio_write(struct sdio_hdl *hdl, int fnum, int addr, int ival, int width) -{ - u_int16_t v2 = 0; - u_int8_t v1 = 0; - - switch (width) { - case 2: - v2 = (u_int16_t)ival; - return sdio_cmd53(hdl, fnum, addr, (u_char *)&v2, - sizeof v2, SD_ARG_CMD53_WRITE | SD_ARG_CMD53_INCREMENT); - default: - v1 = (u_int8_t)ival; - return sdio_cmd52(hdl, fnum, addr, &v1, SD_ARG_CMD52_WRITE); + error = sdio_exec(hdl, &cmd); + if (error) + err(1, "sdio_exec"); + + printf("0x%08x 0x%08x 0x%08x 0x%08x\n", (u_int)cmd.c_resp[0], + (u_int)cmd.c_resp[1], (u_int)cmd.c_resp[2], + (u_int)cmd.c_resp[3]); + + if (datalen > 0) { + for (i = 0; argc == 0 && i < datalen; i++) + printf("0x%02x\n", buf[i]); + free(buf); } + + return 0; } int @@ -223,40 +199,25 @@ main(int argc, char *argv[]) { struct sdio_hdl *hdl; const char *errstr; - int dflag = 0, debug; - int rflag = 0; - int wflag = 0; - int fnum = 0; - int width = 1; + int datalen = 0; + int dflag = 0; + int cflag = 0; int c; - while ((c = getopt(argc, argv, "2d:f:rw")) != -1) { + while ((c = getopt(argc, argv, "cdl:")) != -1) { switch (c) { - case '2': - width = 2; + case 'c': + cflag = 1; break; case 'd': dflag = 1; - debug = strtoint(optarg, &errstr); - if (errstr) - errx(2, "argument is %s: %s", - errstr, optarg); break; - case 'f': - fnum = strtonum(optarg, 0, 7, &errstr); + case 'l': + datalen = strtoint(optarg, &errstr); if (errstr) - errx(2, "function number is %s: %s", - errstr, optarg); - break; - - case 'r': - rflag = 1; - break; - - case 'w': - wflag = 1; + errx(2, "data length is %s: %s", optarg); break; default: @@ -267,62 +228,24 @@ main(int argc, char *argv[]) argc -= optind; argv += optind; - if (rflag && wflag) - errx(2, "only one of -r or -w may be specified"); - - if ((rflag || wflag) && argc < 1) - errx(2, "address required for -r or -w"); - - if (wflag && argc < 2) - errx(2, "value required for -w"); - - if ((rflag && argc != 1) || (wflag && argc != 2) || - ((rflag|wflag) == 0 && argc > 0) || - (rflag|wflag|dflag) == 0) + if ((cflag + dflag) != 1 || + (cflag && argc < 3) || + (dflag && argc != 1)) usage(); if (sdio_open(DEVNAME, &hdl)) return 1; - if (dflag && sdio_debug(hdl, debug)) - err(1, "unable to set debug flags"); - - if (rflag) { - int addr; - int val; - - addr = strtoint(argv[0], &errstr); - if (!errstr && addr < 0 || addr > SDIO_ADDR_MAX) - errstr = "out of range"; + if (dflag) { + int debug = strtoint(argv[0], &errstr); if (errstr) - errx(1, "address is %s: %s", errstr, argv[0]); - - if (sdio_read(hdl, fnum, addr, &val, width)) - err(1, "unable to read"); - printf("%u\n", (unsigned)val); + errx(2, "argument is %s: %s", errstr, argv[0]); + if (sdio_debug(hdl, debug)) + err(1, "unable to set debug flags"); } - if (wflag) { - int addr; - int val; - - addr = strtoint(argv[0], &errstr); - if (!errstr && addr < 0 || addr > SDIO_ADDR_MAX) - errstr = "out of range"; - if (errstr) - errx(1, "address is %s: %s", errstr, argv[0]); - - val = strtoint(argv[1], &errstr); - if (!errstr && - ((width == 1 && (val < 0 || val > UCHAR_MAX)) || - (width == 2 && (val < 0 || val > USHRT_MAX)))) - errstr = "out of range"; - if (errstr) - errx(1, "value is %s: %s", errstr, argv[1]); - - if (sdio_write(hdl, fnum, addr, val, width)) - err(1, "unable to write"); - } + if (cflag && sdio_command(hdl, datalen, argc, argv)) + errx(1, "unable to send command"); sdio_close(hdl); return 0; @@ -348,12 +271,37 @@ strtoint(const char *str, const char **errstr) return (int)val; } +static int +strtorsp(const char *str, const char **errstr) +{ + *errstr = NULL; + if (!strcasecmp(str, "R1")) + return SCF_RSP_R1; + else if (!strcasecmp(str, "R1b")) + return SCF_RSP_R1B; + else if (!strcasecmp(str, "R2")) + return SCF_RSP_R2; + else if (!strcasecmp(str, "R3")) + return SCF_RSP_R3; + else if (!strcasecmp(str, "R4")) + return SCF_RSP_R4; + else if (!strcasecmp(str, "R5")) + return SCF_RSP_R5; + else if (!strcasecmp(str, "R5b")) + return SCF_RSP_R5B; + else if (!strcasecmp(str, "R6")) + return SCF_RSP_R6; + + *errstr = "not valid"; + return 0; +} + __dead static void usage(void) { extern char *__progname; - fprintf(stderr, "usage: %s [-d flags] [-f fnum] " - "[-r|-w addr [value]]\n", __progname); + fprintf(stderr, "usage:\t%s -d debug_flags\n", __progname); + fprintf(stderr, "\t%s -c index arg resp_type [data ...]\n", __progname); exit(2); } |