1/*======================================================================
2
3    PCMCIA card configuration register dump
4
5    dump_cisreg.c 1.31 2001/11/30 23:10:17
6
7    The contents of this file are subject to the Mozilla Public
8    License Version 1.1 (the "License"); you may not use this file
9    except in compliance with the License. You may obtain a copy of
10    the License at http://www.mozilla.org/MPL/
11
12    Software distributed under the License is distributed on an "AS
13    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14    implied. See the License for the specific language governing
15    rights and limitations under the License.
16
17    The initial developer of the original code is David A. Hinds
18    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
19    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
20
21    Alternatively, the contents of this file may be used under the
22    terms of the GNU General Public License version 2 (the "GPL"), in
23    which case the provisions of the GPL are applicable instead of the
24    above.  If you wish to allow the use of your version of this file
25    only under the terms of the GPL and not to allow others to use
26    your version of this file under the MPL, indicate your decision
27    by deleting the provisions above and replace them with the notice
28    and other provisions required by the GPL.  If you do not delete
29    the provisions above, a recipient may use your version of this
30    file under either the MPL or the GPL.
31
32======================================================================*/
33#if (defined(__BEOS__) || defined(__HAIKU__))
34#include <OS.h>
35#endif
36#include <sys/types.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
40#include <unistd.h>
41#include <fcntl.h>
42#include <errno.h>
43#include <sys/time.h>
44#include <sys/ioctl.h>
45#include <sys/stat.h>
46
47#include <pcmcia/cs_types.h>
48#include <pcmcia/cs.h>
49#include <pcmcia/cistpl.h>
50#include <pcmcia/cisreg.h>
51#include <pcmcia/ds.h>
52
53/*====================================================================*/
54#if (!defined(__BEOS__) && !defined(__HAIKU__))
55static int major = 0;
56
57static int lookup_dev(char *name)
58{
59    FILE *f;
60    int n;
61    char s[32], t[32];
62
63    f = fopen("/proc/devices", "r");
64    if (f == NULL)
65	return -1;
66    while (fgets(s, 32, f) != NULL) {
67	if (sscanf(s, "%d %s", &n, t) == 2)
68	    if (strcmp(name, t) == 0)
69		break;
70    }
71    fclose(f);
72    if (strcmp(name, t) == 0)
73	return n;
74    else
75	return -1;
76}
77#endif
78
79/*====================================================================*/
80
81static int open_sock(int sock)
82{
83#if (defined(__BEOS__) || defined(__HAIKU__))
84    char fn[B_OS_NAME_LENGTH];
85    sprintf(fn, "/dev/bus/pcmcia/sock/%d", sock);
86    return open(fn, O_RDONLY);
87#else
88    static char *paths[] = {
89	"/var/lib/pcmcia", "/var/run", "/dev", "/tmp", NULL
90    };
91    int fd;
92    char **p, fn[64];
93    dev_t dev = (major<<8) + sock;
94
95    for (p = paths; *p; p++) {
96	sprintf(fn, "%s/dc%d", *p, getpid());
97	if (mknod(fn, (S_IFCHR|S_IREAD|S_IWRITE), dev) == 0) {
98	    fd = open(fn, O_RDONLY);
99	    unlink(fn);
100	    if (fd >= 0)
101		return fd;
102	    if (errno == ENODEV) break;
103	}
104    }
105    return -1;
106#endif
107} /* open_sock */
108
109/*====================================================================*/
110
111static int get_reg(int fd, int fn, off_t off)
112{
113    ds_ioctl_arg_t arg;
114    int ret;
115
116    arg.conf_reg.Function = fn;
117    arg.conf_reg.Action = CS_READ;
118    arg.conf_reg.Offset = off;
119    ret = ioctl(fd, DS_ACCESS_CONFIGURATION_REGISTER, &arg);
120    if (ret != 0) {
121	printf("  read config register: %s\n\n", strerror(errno));
122	return -1;
123    }
124    return arg.conf_reg.Value;
125}
126
127static int dump_option(int fd, int fn, int mfc)
128{
129    int v = get_reg(fd, fn, CISREG_COR);
130
131    if (v == -1) return -1;
132    printf("  Configuration option register = %#2.2x\n", v);
133    printf("   ");
134    if (v & COR_LEVEL_REQ) printf(" [level_req]");
135    if (v & COR_SOFT_RESET) printf(" [soft_reset]");
136    if (mfc) {
137	if (v & COR_FUNC_ENA) printf(" [func_ena]");
138	if (v & COR_ADDR_DECODE) printf(" [addr_decode]");
139	if (v & COR_IREQ_ENA) printf(" [ireq_ena]");
140	printf(" [index = %#2.2x]\n", v & COR_MFC_CONFIG_MASK);
141    } else
142	printf(" [index = %#2.2x]\n", v & COR_CONFIG_MASK);
143    return 0;
144}
145
146static void dump_status(int fd, int fn)
147{
148    int v = get_reg(fd, fn, CISREG_CCSR);
149
150    printf("  Card configuration and status register = %#2.2x\n", v);
151    printf("   ");
152    if (v & CCSR_INTR_ACK) printf(" [intr_ack]");
153    if (v & CCSR_INTR_PENDING) printf(" [intr_pending]");
154    if (v & CCSR_POWER_DOWN) printf(" [power_down]");
155    if (v & CCSR_AUDIO_ENA) printf(" [audio]");
156    if (v & CCSR_IOIS8) printf(" [IOis8]");
157    if (v & CCSR_SIGCHG_ENA) printf(" [sigchg]");
158    if (v & CCSR_CHANGED) printf(" [changed]");
159    printf("\n");
160}
161
162static void dump_pin(int fd, int fn)
163{
164    int v = get_reg(fd, fn, CISREG_PRR);
165
166    printf("  Pin replacement register = %#2.2x\n", v);
167    printf("   ");
168    if (v & PRR_WP_STATUS) printf(" [wp]");
169    if (v & PRR_READY_STATUS) printf(" [ready]");
170    if (v & PRR_BVD2_STATUS) printf(" [bvd2]");
171    if (v & PRR_BVD1_STATUS) printf(" [bvd1]");
172    if (v & PRR_WP_EVENT) printf(" [wp_event]");
173    if (v & PRR_READY_EVENT) printf(" [ready_event]");
174    if (v & PRR_BVD2_EVENT) printf(" [bvd2_event]");
175    if (v & PRR_BVD1_EVENT) printf(" [bvd1_event]");
176    printf("\n");
177}
178
179static void dump_copy(int fd, int fn)
180{
181    int v = get_reg(fd, fn, CISREG_SCR);
182
183    printf("  Socket and copy register = %#2.2x\n", v);
184    printf("    [socket = %d] [copy = %d]\n",
185	   v & SCR_SOCKET_NUM,
186	   (v & SCR_COPY_NUM) >> 4);
187}
188
189static void dump_ext_status(int fd, int fn)
190{
191    int v = get_reg(fd, fn, CISREG_ESR);
192    printf("  Extended status register = %#2.2x\n", v);
193    printf("   ");
194    if (v & ESR_REQ_ATTN_ENA) printf(" [req_attn_ena]");
195    if (v & ESR_REQ_ATTN) printf(" [req_attn]");
196    printf("\n");
197}
198
199/*====================================================================*/
200
201static void dump_all(int fd, int fn, int mfc, u_int mask)
202{
203    int addr;
204    if (mask & PRESENT_OPTION) {
205	if (dump_option(fd, fn, mfc) != 0)
206	    return;
207    }
208    if (mask & PRESENT_STATUS)
209	dump_status(fd, fn);
210    if (mask & PRESENT_PIN_REPLACE)
211	dump_pin(fd, fn);
212    if (mask & PRESENT_COPY)
213	dump_copy(fd, fn);
214    if (mask & PRESENT_EXT_STATUS)
215	dump_ext_status(fd, fn);
216    if (mask & PRESENT_IOBASE_0) {
217	addr = get_reg(fd, fn, CISREG_IOBASE_0);
218	addr += get_reg(fd, fn, CISREG_IOBASE_1) << 8;
219	printf("  IO base = 0x%04x\n", addr);
220    }
221    if (mask & PRESENT_IOSIZE)
222	printf("  IO size = %d\n", get_reg(fd, fn, CISREG_IOSIZE));
223    if (mask == 0)
224	printf("  no config registers\n\n");
225    else
226	printf("\n");
227}
228
229/*====================================================================*/
230
231#define MAX_SOCKS 8
232
233int main(int argc, char *argv[])
234{
235    int i, j, nfn, fd, ret;
236    u_int mask;
237    ds_ioctl_arg_t arg;
238
239#if (!defined(__BEOS__) && !defined(__HAIKU__))
240    major = lookup_dev("pcmcia");
241    if (major < 0) {
242	fprintf(stderr, "no pcmcia driver in /proc/devices\n");
243	exit(EXIT_FAILURE);
244    }
245#endif
246
247    for (i = 0; i < MAX_SOCKS; i++) {
248	fd = open_sock(i);
249	if (fd < 0) break;
250
251	arg.tuple.TupleDataMax = sizeof(arg.tuple_parse.data);
252	arg.tuple.Attributes = TUPLE_RETURN_COMMON;
253	arg.tuple.DesiredTuple = CISTPL_LONGLINK_MFC;
254	arg.tuple.TupleOffset = 0;
255	if (ioctl(fd, DS_GET_FIRST_TUPLE, &arg) == 0) {
256	    ioctl(fd, DS_GET_TUPLE_DATA, &arg);
257	    ioctl(fd, DS_PARSE_TUPLE, &arg);
258	    nfn = arg.tuple_parse.parse.longlink_mfc.nfn;
259	} else {
260	    nfn = 1;
261	    arg.tuple.DesiredTuple = CISTPL_DEVICE;
262	    ret = ioctl(fd, DS_GET_FIRST_TUPLE, &arg);
263	    if (ret != 0) {
264		if (errno != ENODEV) perror("ioctl()");
265		continue;
266	    }
267	}
268
269	arg.tuple.DesiredTuple = CISTPL_CONFIG;
270
271	for (j = 0; j < nfn; j++) {
272	    printf("Socket %d function %d:\n", i, j);
273	    if (ioctl(fd, DS_GET_NEXT_TUPLE, &arg) != 0) {
274		printf("  no config tuple: %s\n\n", strerror(errno));
275		continue;
276	    }
277	    ioctl(fd, DS_GET_TUPLE_DATA, &arg);
278	    ioctl(fd, DS_PARSE_TUPLE, &arg);
279	    printf("  Config register base = %#4.4x, mask = %#4.4x\n",
280		   arg.tuple_parse.parse.config.base,
281		   arg.tuple_parse.parse.config.rmask[0]);
282	    mask = arg.tuple_parse.parse.config.rmask[0];
283	    dump_all(fd, j, (nfn > 1), mask);
284	}
285
286    }
287    return 0;
288}
289