1/*
2 * Thomas Horsten <thh@lasat.com>
3 * Copyright (C) 2000 LASAT Networks A/S.
4 *
5 *  This program is free software; you can distribute it and/or modify it
6 *  under the terms of the GNU General Public License (Version 2) as
7 *  published by the Free Software Foundation.
8 *
9 *  This program is distributed in the hope it will be useful, but WITHOUT
10 *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 *  for more details.
13 *
14 *  You should have received a copy of the GNU General Public License along
15 *  with this program; if not, write to the Free Software Foundation, Inc.,
16 *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
17 *
18 * Routines specific to the LASAT boards
19 */
20#include <linux/types.h>
21#include <asm/lasat/lasat.h>
22
23#include <linux/module.h>
24#include <linux/sysctl.h>
25#include <linux/stddef.h>
26#include <linux/init.h>
27#include <linux/fs.h>
28#include <linux/ctype.h>
29#include <linux/string.h>
30#include <linux/net.h>
31#include <linux/inet.h>
32#include <linux/mutex.h>
33#include <asm/uaccess.h>
34
35#include "sysctl.h"
36#include "ds1603.h"
37
38static DEFINE_MUTEX(lasat_info_mutex);
39
40/* Strategy function to write EEPROM after changing string entry */
41int sysctl_lasatstring(ctl_table *table, int *name, int nlen,
42		void *oldval, size_t *oldlenp,
43		void *newval, size_t newlen)
44{
45	int r;
46	mutex_lock(&lasat_info_mutex);
47	r = sysctl_string(table, name,
48			  nlen, oldval, oldlenp, newval, newlen);
49	if (r < 0) {
50		mutex_unlock(&lasat_info_mutex);
51		return r;
52	}
53	if (newval && newlen) {
54		lasat_write_eeprom_info();
55	}
56	mutex_unlock(&lasat_info_mutex);
57	return 1;
58}
59
60
61/* And the same for proc */
62int proc_dolasatstring(ctl_table *table, int write, struct file *filp,
63		       void *buffer, size_t *lenp, loff_t *ppos)
64{
65	int r;
66	mutex_lock(&lasat_info_mutex);
67	r = proc_dostring(table, write, filp, buffer, lenp, ppos);
68	if ( (!write) || r) {
69		mutex_unlock(&lasat_info_mutex);
70		return r;
71	}
72	lasat_write_eeprom_info();
73	mutex_unlock(&lasat_info_mutex);
74	return 0;
75}
76
77/* proc function to write EEPROM after changing int entry */
78int proc_dolasatint(ctl_table *table, int write, struct file *filp,
79		       void *buffer, size_t *lenp, loff_t *ppos)
80{
81	int r;
82	mutex_lock(&lasat_info_mutex);
83	r = proc_dointvec(table, write, filp, buffer, lenp, ppos);
84	if ( (!write) || r) {
85		mutex_unlock(&lasat_info_mutex);
86		return r;
87	}
88	lasat_write_eeprom_info();
89	mutex_unlock(&lasat_info_mutex);
90	return 0;
91}
92
93static int rtctmp;
94
95#ifdef CONFIG_DS1603
96/* proc function to read/write RealTime Clock */
97int proc_dolasatrtc(ctl_table *table, int write, struct file *filp,
98		       void *buffer, size_t *lenp, loff_t *ppos)
99{
100	int r;
101	mutex_lock(&lasat_info_mutex);
102	if (!write) {
103		rtctmp = ds1603_read();
104		/* check for time < 0 and set to 0 */
105		if (rtctmp < 0)
106			rtctmp = 0;
107	}
108	r = proc_dointvec(table, write, filp, buffer, lenp, ppos);
109	if ( (!write) || r) {
110		mutex_unlock(&lasat_info_mutex);
111		return r;
112	}
113	ds1603_set(rtctmp);
114	mutex_unlock(&lasat_info_mutex);
115	return 0;
116}
117#endif
118
119/* Sysctl for setting the IP addresses */
120int sysctl_lasat_intvec(ctl_table *table, int *name, int nlen,
121		    void *oldval, size_t *oldlenp,
122		    void *newval, size_t newlen)
123{
124	int r;
125	mutex_lock(&lasat_info_mutex);
126	r = sysctl_intvec(table, name, nlen, oldval, oldlenp, newval, newlen);
127	if (r < 0) {
128		mutex_unlock(&lasat_info_mutex);
129		return r;
130	}
131	if (newval && newlen) {
132		lasat_write_eeprom_info();
133	}
134	mutex_unlock(&lasat_info_mutex);
135	return 1;
136}
137
138#ifdef CONFIG_DS1603
139/* Same for RTC */
140int sysctl_lasat_rtc(ctl_table *table, int *name, int nlen,
141		    void *oldval, size_t *oldlenp,
142		    void *newval, size_t newlen)
143{
144	int r;
145	mutex_lock(&lasat_info_mutex);
146	rtctmp = ds1603_read();
147	if (rtctmp < 0)
148		rtctmp = 0;
149	r = sysctl_intvec(table, name, nlen, oldval, oldlenp, newval, newlen);
150	if (r < 0) {
151		mutex_unlock(&lasat_info_mutex);
152		return r;
153	}
154	if (newval && newlen) {
155		ds1603_set(rtctmp);
156	}
157	mutex_unlock(&lasat_info_mutex);
158	return 1;
159}
160#endif
161
162#ifdef CONFIG_INET
163static char lasat_bcastaddr[16];
164
165void update_bcastaddr(void)
166{
167	unsigned int ip;
168
169	ip = (lasat_board_info.li_eeprom_info.ipaddr &
170		lasat_board_info.li_eeprom_info.netmask) |
171		~lasat_board_info.li_eeprom_info.netmask;
172
173	sprintf(lasat_bcastaddr, "%d.%d.%d.%d",
174			(ip      ) & 0xff,
175			(ip >>  8) & 0xff,
176			(ip >> 16) & 0xff,
177			(ip >> 24) & 0xff);
178}
179
180static char proc_lasat_ipbuf[32];
181/* Parsing of IP address */
182int proc_lasat_ip(ctl_table *table, int write, struct file *filp,
183		       void *buffer, size_t *lenp, loff_t *ppos)
184{
185	int len;
186        unsigned int ip;
187	char *p, c;
188
189	if (!table->data || !table->maxlen || !*lenp ||
190	    (*ppos && !write)) {
191		*lenp = 0;
192		return 0;
193	}
194
195	mutex_lock(&lasat_info_mutex);
196	if (write) {
197		len = 0;
198		p = buffer;
199		while (len < *lenp) {
200			if(get_user(c, p++)) {
201				mutex_unlock(&lasat_info_mutex);
202				return -EFAULT;
203			}
204			if (c == 0 || c == '\n')
205				break;
206			len++;
207		}
208		if (len >= sizeof(proc_lasat_ipbuf)-1)
209			len = sizeof(proc_lasat_ipbuf) - 1;
210		if (copy_from_user(proc_lasat_ipbuf, buffer, len))
211		{
212			mutex_unlock(&lasat_info_mutex);
213			return -EFAULT;
214		}
215		proc_lasat_ipbuf[len] = 0;
216		*ppos += *lenp;
217		/* Now see if we can convert it to a valid IP */
218		ip = in_aton(proc_lasat_ipbuf);
219		*(unsigned int *)(table->data) = ip;
220		lasat_write_eeprom_info();
221	} else {
222		ip = *(unsigned int *)(table->data);
223		sprintf(proc_lasat_ipbuf, "%d.%d.%d.%d",
224			(ip      ) & 0xff,
225			(ip >>  8) & 0xff,
226			(ip >> 16) & 0xff,
227			(ip >> 24) & 0xff);
228		len = strlen(proc_lasat_ipbuf);
229		if (len > *lenp)
230			len = *lenp;
231		if (len)
232			if(copy_to_user(buffer, proc_lasat_ipbuf, len)) {
233				mutex_unlock(&lasat_info_mutex);
234				return -EFAULT;
235			}
236		if (len < *lenp) {
237			if(put_user('\n', ((char *) buffer) + len)) {
238				mutex_unlock(&lasat_info_mutex);
239				return -EFAULT;
240			}
241			len++;
242		}
243		*lenp = len;
244		*ppos += len;
245	}
246	update_bcastaddr();
247	mutex_unlock(&lasat_info_mutex);
248	return 0;
249}
250#endif /* defined(CONFIG_INET) */
251
252static int sysctl_lasat_eeprom_value(ctl_table *table, int *name, int nlen,
253				     void *oldval, size_t *oldlenp,
254				     void *newval, size_t newlen)
255{
256	int r;
257
258	mutex_lock(&lasat_info_mutex);
259	r = sysctl_intvec(table, name, nlen, oldval, oldlenp, newval, newlen);
260	if (r < 0) {
261		mutex_unlock(&lasat_info_mutex);
262		return r;
263	}
264
265	if (newval && newlen)
266	{
267		if (name && *name == LASAT_PRID)
268			lasat_board_info.li_eeprom_info.prid = *(int*)newval;
269
270		lasat_write_eeprom_info();
271		lasat_init_board_info();
272	}
273	mutex_unlock(&lasat_info_mutex);
274
275	return 0;
276}
277
278int proc_lasat_eeprom_value(ctl_table *table, int write, struct file *filp,
279		       void *buffer, size_t *lenp, loff_t *ppos)
280{
281	int r;
282	mutex_lock(&lasat_info_mutex);
283	r = proc_dointvec(table, write, filp, buffer, lenp, ppos);
284	if ( (!write) || r) {
285		mutex_unlock(&lasat_info_mutex);
286		return r;
287	}
288	if (filp && filp->f_path.dentry)
289	{
290		if (!strcmp(filp->f_path.dentry->d_name.name, "prid"))
291			lasat_board_info.li_eeprom_info.prid = lasat_board_info.li_prid;
292		if (!strcmp(filp->f_path.dentry->d_name.name, "debugaccess"))
293			lasat_board_info.li_eeprom_info.debugaccess = lasat_board_info.li_debugaccess;
294	}
295	lasat_write_eeprom_info();
296	mutex_unlock(&lasat_info_mutex);
297	return 0;
298}
299
300extern int lasat_boot_to_service;
301
302#ifdef CONFIG_SYSCTL
303
304static ctl_table lasat_table[] = {
305	{
306		.ctl_name	= CTL_UNNUMBERED,
307		.procname	= "cpu-hz",
308		.data		= &lasat_board_info.li_cpu_hz,
309		.maxlen		= sizeof(int),
310		.mode		= 0444,
311		.proc_handler	= &proc_dointvec,
312		.strategy	= &sysctl_intvec
313	},
314	{
315		.ctl_name	= CTL_UNNUMBERED,
316		.procname	= "bus-hz",
317		.data		= &lasat_board_info.li_bus_hz,
318		.maxlen		= sizeof(int),
319		.mode		= 0444,
320		.proc_handler	= &proc_dointvec,
321		.strategy	= &sysctl_intvec
322	},
323	{
324		.ctl_name	= CTL_UNNUMBERED,
325		.procname	= "bmid",
326		.data		= &lasat_board_info.li_bmid,
327		.maxlen		= sizeof(int),
328		.mode		= 0444,
329		.proc_handler	= &proc_dointvec,
330		.strategy	= &sysctl_intvec
331	},
332	{
333		.ctl_name	= CTL_UNNUMBERED,
334		.procname	= "prid",
335		.data		= &lasat_board_info.li_prid,
336		.maxlen		= sizeof(int),
337		.mode		= 0644,
338		.proc_handler	= &proc_lasat_eeprom_value,
339		.strategy	= &sysctl_lasat_eeprom_value
340	},
341#ifdef CONFIG_INET
342	{
343		.ctl_name	= CTL_UNNUMBERED,
344		.procname	= "ipaddr",
345		.data		= &lasat_board_info.li_eeprom_info.ipaddr,
346		.maxlen		= sizeof(int),
347		.mode		= 0644,
348		.proc_handler	= &proc_lasat_ip,
349		.strategy	= &sysctl_lasat_intvec
350	},
351	{
352		.ctl_name	= LASAT_NETMASK,
353		.procname	= "netmask",
354		.data		= &lasat_board_info.li_eeprom_info.netmask,
355		.maxlen		= sizeof(int),
356		.mode		= 0644,
357		.proc_handler	= &proc_lasat_ip,
358		.strategy	= &sysctl_lasat_intvec
359	},
360	{
361		.ctl_name	= CTL_UNNUMBERED,
362		.procname	= "bcastaddr",
363		.data		= &lasat_bcastaddr,
364		.maxlen		= sizeof(lasat_bcastaddr),
365		.mode		= 0600,
366		.proc_handler	= &proc_dostring,
367		.strategy	= &sysctl_string
368	},
369#endif
370	{
371		.ctl_name	= CTL_UNNUMBERED,
372		.procname	= "passwd_hash",
373		.data		= &lasat_board_info.li_eeprom_info.passwd_hash,
374		.maxlen		= sizeof(lasat_board_info.li_eeprom_info.passwd_hash),
375		.mode		= 0600,
376		.proc_handler	= &proc_dolasatstring,
377		.strategy	= &sysctl_lasatstring
378	},
379	{
380		.ctl_name	= CTL_UNNUMBERED,
381		.procname	= "boot-service",
382		.data		= &lasat_boot_to_service,
383		.maxlen		= sizeof(int),
384		.mode		= 0644,
385		.proc_handler	= &proc_dointvec,
386		.strategy	= &sysctl_intvec
387	},
388#ifdef CONFIG_DS1603
389	{
390		.ctl_name	= CTL_UNNUMBERED,
391		.procname	= "rtc",
392		.data		= &rtctmp,
393		.maxlen		= sizeof(int),
394		.mode		= 0644,
395		.proc_handler	= &proc_dolasatrtc,
396		.strategy	= &sysctl_lasat_rtc
397	},
398#endif
399	{
400		.ctl_name	= CTL_UNNUMBERED,
401		.procname	= "namestr",
402		.data		= &lasat_board_info.li_namestr,
403		.maxlen		= sizeof(lasat_board_info.li_namestr),
404		.mode		= 0444,
405		.proc_handler	=  &proc_dostring,
406		.strategy	= &sysctl_string
407	},
408	{
409		.ctl_name	= CTL_UNNUMBERED,
410		.procname	= "typestr",
411		.data		= &lasat_board_info.li_typestr,
412		.maxlen		= sizeof(lasat_board_info.li_typestr),
413		.mode		= 0444,
414		.proc_handler	= &proc_dostring,
415		.strategy	= &sysctl_string
416	},
417	{}
418};
419
420static ctl_table lasat_root_table[] = {
421	{
422		.ctl_name	= CTL_UNNUMBERED,
423		.procname	= "lasat",
424		.mode		=  0555,
425		.child		= lasat_table
426	},
427	{}
428};
429
430static int __init lasat_register_sysctl(void)
431{
432	struct ctl_table_header *lasat_table_header;
433
434	lasat_table_header =
435		register_sysctl_table(lasat_root_table);
436
437	return 0;
438}
439
440__initcall(lasat_register_sysctl);
441#endif /* CONFIG_SYSCTL */
442