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