1/*	$NetBSD: nvram.c,v 1.18 2010/04/13 09:51:07 tsutsui Exp $	*/
2
3/*
4 * Copyright (c) 1995 Leo Weppelman.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28/*
29 * Nvram driver
30 */
31
32#include <sys/cdefs.h>
33__KERNEL_RCSID(0, "$NetBSD: nvram.c,v 1.18 2010/04/13 09:51:07 tsutsui Exp $");
34
35#include <sys/param.h>
36#include <sys/conf.h>
37#include <sys/kernel.h>
38#include <sys/proc.h>
39#include <sys/systm.h>
40#include <sys/device.h>
41#include <sys/buf.h>
42#include <sys/uio.h>
43
44#include <machine/iomap.h>
45#include <machine/cpu.h>
46
47#include <atari/dev/clockreg.h>
48#include <atari/dev/nvramvar.h>
49
50#include "ioconf.h"
51
52#include "nvr.h"
53
54#define	MC_NVRAM_CSUM	(MC_NVRAM_START + MC_NVRAM_SIZE - 2)
55
56#if NNVR > 0
57static void	nvram_set_csum(u_char csum);
58static int	nvram_csum_valid(u_char csum);
59static u_char	nvram_csum(void);
60
61/*
62 * Auto config stuff....
63 */
64static void	nvr_attach(device_t, device_t, void *);
65static int	nvr_match(device_t, cfdata_t, void *);
66
67CFATTACH_DECL_NEW(nvr, sizeof(struct nvr_softc),
68    nvr_match, nvr_attach, NULL, NULL);
69
70/*ARGSUSED*/
71static	int
72nvr_match(device_t parent, cfdata_t cf, void *aux)
73{
74	if (!strcmp((char *)aux, "nvr"))
75		return (1);
76	return (0);
77}
78
79/*ARGSUSED*/
80static void
81nvr_attach(device_t parent, device_t self, void *aux)
82{
83	struct nvr_softc	*sc;
84	int			nreg;
85
86	/*
87	 * Check the validity of the NVram contents
88	 */
89	if (!nvram_csum_valid(nvram_csum())) {
90		printf(": Invalid checksum - re-initialized");
91		for (nreg = MC_NVRAM_START; nreg < MC_NVRAM_CSUM; nreg++)
92			mc146818_write(RTC, nreg, 0);
93		nvram_set_csum(nvram_csum());
94	}
95	sc = device_private(self);
96	sc->sc_dev = self;
97	sc->sc_flags = NVR_CONFIGURED;
98	printf("\n");
99}
100/*
101 * End of auto config stuff....
102 */
103#endif /* NNVR > 0 */
104
105/*
106 * Kernel internal interface
107 */
108int
109nvr_get_byte(int byteno)
110{
111#if NNVR > 0
112	struct nvr_softc	*sc;
113
114	sc = device_lookup_private(&nvr_cd, 0);
115	if (!(sc->sc_flags & NVR_CONFIGURED))
116		return(NVR_INVALID);
117	return (mc146818_read(RTC, byteno + MC_NVRAM_START) & 0xff);
118#else
119	return(NVR_INVALID);
120#endif /* NNVR > 0 */
121}
122
123#if NNVR > 0
124
125int
126nvram_uio(struct uio *uio)
127{
128	int			i;
129	off_t			offset;
130	int			nleft;
131	u_char			buf[MC_NVRAM_CSUM - MC_NVRAM_START + 1];
132	u_char			*p;
133	struct nvr_softc	*sc;
134
135	sc = device_lookup_private(&nvr_cd,0);
136	if (!(sc->sc_flags & NVR_CONFIGURED))
137		return ENXIO;
138
139#ifdef NV_DEBUG
140	printf("Request to transfer %d bytes offset: %d, %s nvram\n",
141				(long)uio->uio_resid, (long)uio->uio_offset,
142				(uio->uio_rw == UIO_READ) ? "from" : "to");
143#endif /* NV_DEBUG */
144
145	offset = uio->uio_offset + MC_NVRAM_START;
146	nleft  = uio->uio_resid;
147	if (offset + nleft >= MC_NVRAM_CSUM) {
148		if (offset == MC_NVRAM_CSUM)
149			return (0);
150		nleft = MC_NVRAM_CSUM - offset;
151		if (nleft <= 0)
152			return (EINVAL);
153	}
154#ifdef NV_DEBUG
155	printf("Translated: offset = %d, bytes: %d\n", (long)offset, nleft);
156#endif /* NV_DEBUG */
157
158	if (uio->uio_rw == UIO_READ) {
159		for (i = 0, p = buf; i < nleft; i++, p++)
160			*p =  mc146818_read(RTC, offset + i);
161	}
162	if ((i = uiomove(buf, nleft, uio)) != 0)
163		return (i);
164	if (uio->uio_rw == UIO_WRITE) {
165		for (i = 0, p = buf; i < nleft; i++, p++)
166			mc146818_write(RTC, offset + i, *p);
167		nvram_set_csum(nvram_csum());
168	}
169	return(0);
170}
171
172static u_char
173nvram_csum(void)
174{
175	u_char	csum;
176	int	nreg;
177
178	for (csum = 0, nreg = MC_NVRAM_START; nreg < MC_NVRAM_CSUM; nreg++)
179		csum += mc146818_read(RTC, nreg);
180	return(csum);
181}
182
183static int
184nvram_csum_valid(u_char csum)
185{
186	if (((~csum & 0xff) != mc146818_read(RTC, MC_NVRAM_CSUM))
187		|| (csum != mc146818_read(RTC, MC_NVRAM_CSUM + 1)))
188		return 0;
189	return 1;
190}
191
192static void
193nvram_set_csum(u_char csum)
194{
195	mc146818_write(RTC, MC_NVRAM_CSUM,    ~csum);
196	mc146818_write(RTC, MC_NVRAM_CSUM + 1, csum);
197}
198#endif /* NNVR > 0 */
199