1 /*
2  * natfeat.c - ARAnyM hardware support via Native Features (natfeats)
3  *
4  * Copyright (c) 2005 Petr Stehlik of ARAnyM dev team
5  *
6  * This software may be used and distributed according to the terms of
7  * the GNU General Public License (GPL), incorporated herein by reference.
8  */
9 
10 #include <linux/config.h>
11 #include <linux/types.h>
12 #include <linux/string.h> // strncpy()
13 #include <linux/kernel.h> // snprintf()
14 #include <asm/io.h> // virt_to_phys()
15 
16 #include "natfeat.h"
17 
18 #ifdef CONFIG_ATARI_NFETH
19 #include "natfeat_ethernet_nfapi.h"
20 #endif
21 
22 #ifndef TRUE
23 #define TRUE 1
24 #endif
25 
26 #ifndef FALSE
27 #define FALSE 0
28 #endif
29 
30 static unsigned long nf_get_id_instr = 0x73004e75UL;
31 static unsigned long nf_call_instr = 0x73014e75UL;
32 
33 static struct nf_ops _nf_ops = { &nf_get_id_instr, &nf_call_instr };
34 static const struct nf_ops *nf_ops;
35 
36 #define NF_GETID(a)		nf_ops->get_id(virt_to_phys(a))
37 
detect_native_features(void)38 int detect_native_features(void)
39 {
40     int		ret;
41     long	save_sp, save_vbr;
42     static long tmp_vectors[5];
43     static char *nf_version = "NF_VERSION";
44 
45     __asm__ __volatile__
46 	(	"movec	%/vbr,%2\n\t"	/* save vbr value            */
47 		"movel	#Liierr,%3@(0x10)\n\t" /* set Illegal Insn vec */
48  		"movec	%3,%/vbr\n\t"	/* set up temporary vectors  */
49 		"movel	%/sp,%1\n\t"	/* save sp                   */
50 		"moveq	#0,%0\n\t"		/* assume no NatFeats        */
51 		"clrl	%/d0\n\t"		/* clear ID value register   */
52 		"movel	%4,%/sp@\n\t"
53 		"subql	#4,%/sp\n\t"
54 		"dc	0x7300\n\t"			/* call NatFeat GetID        */
55 		"tstl	%/d0\n\t"		/* check ID value register   */
56 		"sne	%0\n\t"			/* if non-zero NatFeats work */
57 		"Liierr:\n\t"
58 		"movel	%1,%/sp\n\t"	/* restore sp                */
59 		"movec	%2,%/vbr"		/* restore vbr               */
60 		: "=&d" (ret), "=&r" (save_sp), "=&r" (save_vbr)
61 		: "a" (tmp_vectors), "a" (virt_to_phys(nf_version))
62 		: "d0"					/* reg d0 used by NatFeats   */
63         );
64 
65     return( ret );
66 }
67 
nf_init(void)68 const struct nf_ops * nf_init(void)
69 {
70 	if (detect_native_features()) {
71 		nf_ops = &_nf_ops;
72 		nf_debug("NatFeats found\n");
73 		return nf_ops;
74 	}
75 
76 	return NULL;
77 }
78 
79 /****************/
80 /* NF Basic Set */
nf_name1(char * buf,int bufsize)81 int nf_name1(char *buf, int bufsize)
82 {
83 	if (nf_ops) {
84 		static long nfid_name = 0;
85 		if (nfid_name == 0) {
86 			nfid_name = NF_GETID("NF_NAME");
87 		}
88 
89 		if (nfid_name) {
90 			nf_ops->call(nfid_name+1, virt_to_phys(buf), bufsize); // TODO: lock buf to prevent swap out
91 			return TRUE;
92 		}
93 	}
94 
95 	return FALSE;
96 }
97 
nf_debug(const char * msg)98 int nf_debug(const char *msg)
99 {
100 	if (nf_ops) {
101 		static long nfid_stderr = 0;
102 		if (nfid_stderr == 0) {
103 			nfid_stderr = NF_GETID("NF_STDERR");
104 		}
105 
106 		if (nfid_stderr) {
107 			nf_ops->call(nfid_stderr, virt_to_phys(msg)); // TODO: lock msg to prevent swap out
108 			return TRUE;
109 		}
110 	}
111 
112 	return FALSE;
113 }
114 
nf_shutdown(void)115 int nf_shutdown(void)
116 {
117 	if (nf_ops) {
118 		long shutdown_id = NF_GETID("NF_SHUTDOWN");
119 
120 		if (shutdown_id) {
121 			nf_ops->call(shutdown_id);
122 			return TRUE; /* never returns actually */
123 		}
124 	}
125 
126 	return FALSE;
127 }
128 
129 #ifdef CONFIG_ATARI_NFETH
130 
131 /****************************/
132 /* NatFeat Ethernet support */
133 static long nfEtherID = 0;
134 
is_nf_eth(void)135 static int is_nf_eth(void)
136 {
137 	if (nf_ops) {
138 		if (nfEtherID == 0) {
139 			nfEtherID = NF_GETID("ETHERNET");
140 		}
141 	}
142 	return (nfEtherID != 0);
143 }
144 
nf_ethernet_check_version(char * errmsg,int errmsglen)145 int nf_ethernet_check_version(char *errmsg, int errmsglen)
146 {
147 	if (is_nf_eth()) {
148 		static unsigned long host_ver = 0;
149 		if (host_ver == 0) {
150 			host_ver = nf_ops->call(ETH(GET_VERSION));
151 		}
152 		if (host_ver == ARAETHER_NFAPI_VERSION) {
153 			return TRUE;
154 		}
155 		else {
156 			// API version mismatch
157 			if (errmsg != NULL) {
158 				snprintf(errmsg, errmsglen,
159 					"NatFeat Ethernet API: expected %d, got %ld",
160 					ARAETHER_NFAPI_VERSION, host_ver);
161 			}
162 			return FALSE;
163 		}
164 	}
165 	if (errmsg != NULL) {
166 		strncpy(errmsg, "NatFeat Ethernet support not found", errmsglen);
167 	}
168 	return FALSE;
169 }
170 
nf_ethernet_get_irq(void)171 int nf_ethernet_get_irq(void)
172 {
173 	return is_nf_eth() ? nf_ops->call(ETH(XIF_INTLEVEL)) : 0;
174 }
175 
nf_ethernet_get_hw_addr(int ethX,char * buffer,int bufsize)176 int nf_ethernet_get_hw_addr(int ethX, char *buffer, int bufsize)
177 {
178 	if (is_nf_eth()) {
179 		return nf_ops->call(ETH(XIF_GET_MAC), (unsigned long)ethX, virt_to_phys(buffer), (unsigned long)bufsize); // TODO: lock buffer to prevent swap out
180 	}
181 	return FALSE;
182 }
183 
nf_ethernet_interrupt(int bit)184 int nf_ethernet_interrupt(int bit)
185 {
186 	if (is_nf_eth()) {
187 		return nf_ops->call(ETH(XIF_IRQ), (unsigned long)bit);
188 	}
189 	return 0;
190 }
191 
nf_ethernet_read_packet_len(int ethX)192 int nf_ethernet_read_packet_len(int ethX)
193 {
194 	if (is_nf_eth()) {
195 		return nf_ops->call(ETH(XIF_READLENGTH), (unsigned long)ethX);
196 	}
197 	return 0;
198 }
199 
nf_ethernet_read_block(int ethX,char * buffer,int len)200 void nf_ethernet_read_block(int ethX, char *buffer, int len)
201 {
202 	if (is_nf_eth()) {
203 		nf_ops->call(ETH(XIF_READBLOCK), (unsigned long)ethX, virt_to_phys(buffer), (unsigned long)len); // TODO: lock buffer to prevent swap out
204 	}
205 }
206 
nf_ethernet_write_block(int ethX,char * buffer,int len)207 void nf_ethernet_write_block(int ethX, char *buffer, int len)
208 {
209 	if (is_nf_eth()) {
210 		nf_ops->call(ETH(XIF_WRITEBLOCK), (unsigned long)ethX, virt_to_phys(buffer), (unsigned long)len); // TODO: lock buffer to prevent swap out
211 	}
212 }
213 
nf_ethernet_xif_start(int ethX)214 void nf_ethernet_xif_start(int ethX)
215 {
216 	if (is_nf_eth()) {
217 		nf_ops->call(ETH(XIF_START), (unsigned long)ethX);
218 	}
219 }
220 
nf_ethernet_xif_stop(int ethX)221 void nf_ethernet_xif_stop(int ethX)
222 {
223 	if (is_nf_eth()) {
224 		nf_ops->call(ETH(XIF_STOP), (unsigned long)ethX);
225 	}
226 }
227 #endif // CONFIG_ATARI_NFETH
228 
229 /*
230 vim:ts=4:sw=4:
231 */
232