ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/BeOS/ether_beos.cpp
Revision: 1.5
Committed: 2005-07-03T08:23:42Z (19 years, 4 months ago) by gbeauche
Branch: MAIN
Changes since 1.4: +8 -6 lines
Log Message:
First round of patches to increase ethernet code portability.

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * ether_beos.cpp - SheepShaver Ethernet Device Driver (DLPI), BeOS specific stuff
3     *
4 gbeauche 1.4 * SheepShaver (C) 1997-2005 Marc Hellwig and Christian Bauer
5 cebix 1.1 *
6     * This program is free software; you can redistribute it and/or modify
7     * it under the terms of the GNU General Public License as published by
8     * the Free Software Foundation; either version 2 of the License, or
9     * (at your option) any later version.
10     *
11     * This program is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with this program; if not, write to the Free Software
18     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19     */
20    
21     #include "sysdeps.h"
22     #include "ether.h"
23     #include "ether_defs.h"
24     #include "prefs.h"
25     #include "xlowmem.h"
26     #include "main.h"
27     #include "user_strings.h"
28     #include "sheep_net.h"
29    
30     #define DEBUG 0
31     #include "debug.h"
32    
33     #define STATISTICS 0
34     #define MONITOR 0
35    
36    
37     // Global variables
38     static thread_id read_thread; // Packet receiver thread
39     static bool ether_thread_active = true; // Flag for quitting the receiver thread
40    
41     static area_id buffer_area; // Packet buffer area
42     static net_buffer *net_buffer_ptr; // Pointer to packet buffer
43     static sem_id read_sem, write_sem; // Semaphores to trigger packet reading/writing
44     static uint32 rd_pos; // Current read position in packet buffer
45     static uint32 wr_pos; // Current write position in packet buffer
46    
47     static bool net_open = false; // Flag: initialization succeeded, network device open
48    
49    
50     // Prototypes
51     static status_t AO_receive_thread(void *data);
52    
53    
54     /*
55     * Initialize ethernet
56     */
57    
58     void EtherInit(void)
59     {
60     // Do nothing if the user disabled the network
61     if (PrefsFindBool("nonet"))
62     return;
63    
64     // find net-server team
65     i_wanna_try_that_again:
66     bool found_add_on = false;
67     team_info t_info;
68     int32 t_cookie = 0;
69     image_info i_info;
70     int32 i_cookie = 0;
71     while (get_next_team_info(&t_cookie, &t_info) == B_NO_ERROR) {
72     if (strstr(t_info.args,"net_server")!=NULL) {
73     // check if sheep_net add-on is loaded
74     while (get_next_image_info(t_info.team,&i_cookie,&i_info) == B_NO_ERROR) {
75     if (strstr(i_info.name,"sheep_net")!=NULL) {
76     found_add_on = true;
77     break;
78     }
79     }
80     }
81     if (found_add_on) break;
82     }
83     if (!found_add_on) {
84    
85     // Search for sheep_net in network config file
86     char str[1024];
87     bool sheep_net_found = false;
88     FILE *fin = fopen("/boot/home/config/settings/network", "r");
89     while (!feof(fin)) {
90     fgets(str, 1024, fin);
91     if (strstr(str, "PROTOCOLS"))
92     if (strstr(str, "sheep_net"))
93     sheep_net_found = true;
94     }
95     fclose(fin);
96    
97     // It was found, so something else must be wrong
98     if (sheep_net_found) {
99     WarningAlert(GetString(STR_NO_NET_ADDON_WARN));
100     return;
101     }
102    
103     // Not found, inform the user
104     if (!ChoiceAlert(GetString(STR_NET_CONFIG_MODIFY_WARN), GetString(STR_OK_BUTTON), GetString(STR_CANCEL_BUTTON)))
105     return;
106    
107     // Change the network config file and restart the network
108     fin = fopen("/boot/home/config/settings/network", "r");
109     FILE *fout = fopen("/boot/home/config/settings/network.2", "w");
110     bool global_found = false;
111     bool modified = false;
112     while (!feof(fin)) {
113     str[0] = 0;
114     fgets(str, 1024, fin);
115     if (!global_found && strstr(str, "GLOBAL:")) {
116     global_found = true;
117     } else if (global_found && !modified && strstr(str, "PROTOCOLS")) {
118     str[strlen(str)-1] = 0;
119     strcat(str, " sheep_net\n");
120     modified = true;
121     } else if (global_found && !modified && strlen(str) > 2 && str[strlen(str) - 2] == ':') {
122     fputs("\tPROTOCOLS = sheep_net\n", fout);
123     modified = true;
124     }
125     fputs(str, fout);
126     }
127     if (!modified)
128     fputs("\tPROTOCOLS = sheep_net\n", fout);
129     fclose(fout);
130     fclose(fin);
131     remove("/boot/home/config/settings/network.orig");
132     rename("/boot/home/config/settings/network", "/boot/home/config/settings/network.orig");
133     rename("/boot/home/config/settings/network.2", "/boot/home/config/settings/network");
134    
135     app_info ai;
136     if (be_roster->GetAppInfo("application/x-vnd.Be-NETS", &ai) == B_OK) {
137     BMessenger msg(NULL, ai.team);
138     if (msg.IsValid()) {
139     while (be_roster->IsRunning("application/x-vnd.Be-NETS")) {
140     msg.SendMessage(B_QUIT_REQUESTED);
141     snooze(500000);
142     }
143     }
144     }
145     BPath path;
146     find_directory(B_BEOS_BOOT_DIRECTORY, &path);
147     path.Append("Netscript");
148     char *argv[3] = {"/bin/sh", (char *)path.Path(), NULL};
149     thread_id net_server = load_image(2, argv, environ);
150     resume_thread(net_server);
151     status_t l;
152     wait_for_thread(net_server, &l);
153     goto i_wanna_try_that_again;
154     }
155    
156     // Set up communications with add-on
157     area_id handler_buffer;
158     if ((handler_buffer = find_area("packet buffer")) < B_NO_ERROR) {
159     WarningAlert(GetString(STR_NET_ADDON_INIT_FAILED));
160     return;
161     }
162     if ((buffer_area = clone_area("local packet buffer", &net_buffer_ptr, B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, handler_buffer)) < B_NO_ERROR) {
163     D(bug("EtherInit: couldn't clone packet area\n"));
164     WarningAlert(GetString(STR_NET_ADDON_CLONE_FAILED));
165     return;
166     }
167     if ((read_sem = create_sem(0, "ether read")) < B_NO_ERROR) {
168     printf("FATAL: can't create Ethernet semaphore\n");
169     return;
170     }
171     net_buffer_ptr->read_sem = read_sem;
172     write_sem = net_buffer_ptr->write_sem;
173     read_thread = spawn_thread(AO_receive_thread, "ether read", B_URGENT_DISPLAY_PRIORITY, NULL);
174     resume_thread(read_thread);
175     for (int i=0; i<WRITE_PACKET_COUNT; i++)
176     net_buffer_ptr->write[i].cmd = IN_USE | (ACTIVATE_SHEEP_NET << 8);
177     rd_pos = wr_pos = 0;
178     release_sem(write_sem);
179    
180     // Everything OK
181     net_open = true;
182     }
183    
184    
185     /*
186     * Exit ethernet
187     */
188    
189     void EtherExit(void)
190     {
191     if (net_open) {
192    
193     // Close communications with add-on
194     for (int i=0; i<WRITE_PACKET_COUNT; i++)
195     net_buffer_ptr->write[i].cmd = IN_USE | (DEACTIVATE_SHEEP_NET << 8);
196     release_sem(write_sem);
197    
198     // Quit receiver thread
199     ether_thread_active = false;
200     status_t result;
201     release_sem(read_sem);
202     while (wait_for_thread(read_thread, &result) == B_INTERRUPTED) ;
203    
204     delete_sem(read_sem);
205     delete_area(buffer_area);
206     }
207    
208     #if STATISTICS
209     // Show statistics
210     printf("%ld messages put on write queue\n", num_wput);
211     printf("%ld error acks\n", num_error_acks);
212     printf("%ld packets transmitted (%ld raw, %ld normal)\n", num_tx_packets, num_tx_raw_packets, num_tx_normal_packets);
213     printf("%ld tx packets dropped because buffer full\n", num_tx_buffer_full);
214     printf("%ld packets received\n", num_rx_packets);
215     printf("%ld packets passed upstream (%ld Fast Path, %ld normal)\n", num_rx_fastpath + num_unitdata_ind, num_rx_fastpath, num_unitdata_ind);
216     printf("EtherIRQ called %ld times\n", num_ether_irq);
217     printf("%ld rx packets dropped due to low memory\n", num_rx_no_mem);
218     printf("%ld rx packets dropped because no stream found\n", num_rx_dropped);
219     printf("%ld rx packets dropped because stream not ready\n", num_rx_stream_not_ready);
220     printf("%ld rx packets dropped because no memory for unitdata_ind\n", num_rx_no_unitdata_mem);
221     #endif
222     }
223    
224    
225     /*
226     * Ask add-on for ethernet hardware address
227     */
228    
229 gbeauche 1.5 void AO_get_ethernet_address(uint32 arg)
230 cebix 1.1 {
231 gbeauche 1.5 uint8 *addr = Mac2HostAddr(arg);
232 cebix 1.1 if (net_open) {
233     OTCopy48BitAddress(net_buffer_ptr->ether_addr, addr);
234     } else {
235     addr[0] = 0x12;
236     addr[1] = 0x34;
237     addr[2] = 0x56;
238     addr[3] = 0x78;
239     addr[4] = 0x9a;
240     addr[5] = 0xbc;
241     }
242     D(bug("AO_get_ethernet_address: got address %02x%02x%02x%02x%02x%02x\n", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]));
243     }
244    
245    
246     /*
247     * Tell add-on to enable multicast address
248     */
249    
250 gbeauche 1.5 void AO_enable_multicast(uint32 addr)
251 cebix 1.1 {
252     D(bug("AO_enable_multicast\n"));
253     if (net_open) {
254     net_packet *p = &net_buffer_ptr->write[wr_pos];
255     if (p->cmd & IN_USE) {
256     D(bug("WARNING: couldn't enable multicast address\n"));
257     } else {
258 gbeauche 1.5 Mac2host_memcpy(p->data, addr, 6);
259 cebix 1.1 p->length = 6;
260     p->cmd = IN_USE | (ADD_MULTICAST << 8);
261     wr_pos = (wr_pos + 1) % WRITE_PACKET_COUNT;
262     release_sem(write_sem);
263     }
264     }
265     }
266    
267    
268     /*
269     * Tell add-on to disable multicast address
270     */
271    
272 gbeauche 1.5 void AO_disable_multicast(uint32 addr)
273 cebix 1.1 {
274     D(bug("AO_disable_multicast\n"));
275     if (net_open) {
276     net_packet *p = &net_buffer_ptr->write[wr_pos];
277     if (p->cmd & IN_USE) {
278     D(bug("WARNING: couldn't enable multicast address\n"));
279     } else {
280 gbeauche 1.5 Mac2host_memcpy(p->data, addr, 6);
281 cebix 1.1 p->length = 6;
282     p->cmd = IN_USE | (REMOVE_MULTICAST << 8);
283     wr_pos = (wr_pos + 1) % WRITE_PACKET_COUNT;
284     release_sem(write_sem);
285     }
286     D(bug("WARNING: couldn't disable multicast address\n"));
287     }
288     }
289    
290    
291     /*
292     * Tell add-on to transmit one packet
293     */
294    
295 gbeauche 1.5 void AO_transmit_packet(uint32 mp_arg)
296 cebix 1.1 {
297     D(bug("AO_transmit_packet\n"));
298     if (net_open) {
299     net_packet *p = &net_buffer_ptr->write[wr_pos];
300     if (p->cmd & IN_USE) {
301     D(bug("WARNING: couldn't transmit packet (buffer full)\n"));
302     num_tx_buffer_full++;
303     } else {
304     D(bug(" write packet pos %d\n", i));
305     num_tx_packets++;
306    
307     // Copy packet to buffer
308     uint8 *start;
309     uint8 *bp = start = p->data;
310 gbeauche 1.5 mblk_t *mp = Mac2HostAddr(mp_arg);
311 cebix 1.1 while (mp) {
312     uint32 size = mp->b_wptr - mp->b_rptr;
313     memcpy(bp, mp->b_rptr, size);
314     bp += size;
315     mp = mp->b_cont;
316     }
317    
318     #if MONITOR
319     bug("Sending Ethernet packet:\n");
320     for (int i=0; i<(uint32)(bp - start); i++) {
321     bug("%02lx ", start[i]);
322     }
323     bug("\n");
324     #endif
325    
326     // Notify add-on
327     p->length = (uint32)(bp - start);
328     p->cmd = IN_USE | (SHEEP_PACKET << 8);
329     wr_pos = (wr_pos + 1) % WRITE_PACKET_COUNT;
330     release_sem(write_sem);
331     }
332     }
333     }
334    
335    
336     /*
337     * Packet reception thread
338     */
339    
340     static status_t AO_receive_thread(void *data)
341     {
342     while (ether_thread_active) {
343     if (net_buffer_ptr->read[rd_pos].cmd & IN_USE) {
344     if (ether_driver_opened) {
345     D(bug(" packet received, triggering Ethernet interrupt\n"));
346     SetInterruptFlag(INTFLAG_ETHER);
347     TriggerInterrupt();
348     }
349     }
350     acquire_sem_etc(read_sem, 1, B_TIMEOUT, 25000);
351     }
352     return 0;
353     }
354    
355    
356     /*
357     * Ethernet interrupt
358     */
359    
360     void EtherIRQ(void)
361     {
362     D(bug("EtherIRQ\n"));
363     num_ether_irq++;
364     OTEnterInterrupt();
365    
366     // Send received packets to OpenTransport
367     net_packet *p = &net_buffer_ptr->read[rd_pos];
368     while (p->cmd & IN_USE) {
369     if ((p->cmd >> 8) == SHEEP_PACKET) {
370     num_rx_packets++;
371     D(bug(" read packet pos %d\n", i));
372     uint32 size = p->length;
373    
374     #if MONITOR
375     bug("Receiving Ethernet packet:\n");
376     for (int i=0; i<size; i++) {
377     bug("%02lx ", p->data[i]);
378     }
379     bug("\n");
380     #endif
381    
382     // Wrap packet in message block
383     //!! maybe use esballoc()
384     mblk_t *mp;
385     if ((mp = allocb(size, 0)) != NULL) {
386 gbeauche 1.3 D(bug(" packet data at %p\n", (void *)mp->b_rptr));
387 cebix 1.1 memcpy(mp->b_rptr, p->data, size);
388     mp->b_wptr += size;
389     ether_packet_received(mp);
390     } else {
391     D(bug("WARNING: Cannot allocate mblk for received packet\n"));
392     num_rx_no_mem++;
393     }
394     }
395     p->cmd = 0; // Free packet
396     rd_pos = (rd_pos + 1) % READ_PACKET_COUNT;
397     p = &net_buffer_ptr->read[rd_pos];
398     }
399     OTLeaveInterrupt();
400     }