Drivers for the MNT ZZ9000 graphics and ARM coprocessor card for classic Amigas.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

734 lines
20 KiB

  1. /*
  2. * MNT ZZ9000 Network Driver (ZZ9000Net.device)
  3. * Copyright (C) 2016-2019, Lukas F. Hartmann <lukas@mntre.com>
  4. * MNT Research GmbH, Berlin
  5. * https://mntre.com
  6. *
  7. * Based on code copyright (C) 2018 Henryk Richter <henryk.richter@gmx.net>
  8. * Released under GPLv3+ with permission.
  9. *
  10. * More Info: https://mntre.com/zz9000
  11. *
  12. * SPDX-License-Identifier: GPL-3.0-or-later
  13. * GNU General Public License v3.0 or later
  14. *
  15. * https://spdx.org/licenses/GPL-3.0-or-later.html
  16. */
  17. #define DEVICE_MAIN
  18. #include <proto/exec.h>
  19. #include <proto/utility.h>
  20. #include <proto/dos.h>
  21. #include <proto/expansion.h>
  22. #include <clib/exec_protos.h>
  23. #include <clib/alib_protos.h>
  24. #include <dos/dostags.h>
  25. #include <utility/tagitem.h>
  26. #include <exec/lists.h>
  27. #include <exec/errors.h>
  28. #include <exec/interrupts.h>
  29. #include <exec/tasks.h>
  30. #include <hardware/intbits.h>
  31. #include <string.h>
  32. #ifdef HAVE_VERSION_H
  33. #include "version.h"
  34. #endif
  35. /* NSD support is optional */
  36. #ifdef NEWSTYLE
  37. #include <devices/newstyle.h>
  38. #endif /* NEWSTYLE */
  39. #ifdef DEVICES_NEWSTYLE_H
  40. const UWORD dev_supportedcmds[] = {
  41. NSCMD_DEVICEQUERY,
  42. CMD_READ,
  43. CMD_WRITE,
  44. /* ... add all cmds here that are supported by BeginIO */
  45. 0
  46. };
  47. const struct NSDeviceQueryResult NSDQueryAnswer = {
  48. 0,
  49. 16, /* up to SupportedCommands (inclusive) TODO: correct number */
  50. NSDEVTYPE_SANA2, /* TODO: proper device type */
  51. 0, /* subtype */
  52. (UWORD*)dev_supportedcmds
  53. };
  54. #endif /* DEVICES_NEWSTYLE_H */
  55. #include "device.h"
  56. #include "macros.h"
  57. static ULONG ZZ9K_REGS = 0;
  58. #define ZZ9K_RX 0x2000
  59. #define ZZ9K_TX 0x8000
  60. __saveds void frame_proc();
  61. char *frame_proc_name = "ZZ9000NetFramer";
  62. // ZZ9000 Interrupt Handler (INT6)
  63. __saveds void dev_isr(__reg("a1") struct devbase* db) {
  64. // signal main process that a packet is available
  65. if (db->db_Proc) {
  66. Signal((struct Task*)db->db_Proc, SIGBREAKF_CTRL_F);
  67. }
  68. }
  69. static UBYTE HW_MAC[] = {0x00,0x00,0x00,0x00,0x00,0x00};
  70. void set_mac_from_string(UBYTE* buf) {
  71. int k=0;
  72. for (int i=0; i<6; i++) {
  73. int c = buf[k];
  74. int v = 0;
  75. if (c>='0' && c<='9') c-='0';
  76. else if (c>='a' && c<='f') c=c+10-'a';
  77. else if (c>='A' && c<='F') c=c+10-'A';
  78. v = c<<4;
  79. c = buf[k+1];
  80. if (c>='0' && c<='9') c-='0';
  81. else if (c>='a' && c<='f') c=c+10-'a';
  82. else if (c>='A' && c<='F') c=c+10-'A';
  83. HW_MAC[i] = v+c;
  84. k+=3;
  85. }
  86. }
  87. struct ProcInit
  88. {
  89. struct Message msg;
  90. struct devbase *db;
  91. BOOL error;
  92. UBYTE pad[2];
  93. };
  94. __saveds struct Device *DevInit( ASMR(d0) DEVBASEP ASMREG(d0),
  95. ASMR(a0) BPTR seglist ASMREG(a0),
  96. ASMR(a6) struct Library *_SysBase ASMREG(a6) )
  97. {
  98. UBYTE*p;
  99. ULONG i;
  100. LONG ok;
  101. p = ((UBYTE*)db) + sizeof(struct Library);
  102. i = sizeof(DEVBASETYPE)-sizeof(struct Library);
  103. while( i-- )
  104. *p++ = 0;
  105. db->db_SysBase = _SysBase;
  106. db->db_SegList = seglist;
  107. db->db_Flags = 0;
  108. ok = 0;
  109. if( (DOSBase = OpenLibrary("dos.library", 36)) ) {
  110. if( (UtilityBase = OpenLibrary("utility.library", 37)) ) {
  111. ok = 0;
  112. struct ConfigDev* cd = NULL;
  113. USHORT fwrev = 0;
  114. if ((ExpansionBase = OpenLibrary("expansion.library", 0)) ) {
  115. // Find Z2 or Z3 model of MNT ZZ9000
  116. if ((cd = (struct ConfigDev*)FindConfigDev(cd,0x6d6e,0x4)) || (cd = (struct ConfigDev*)FindConfigDev(cd,0x6d6e,0x3))) {
  117. BPTR fh;
  118. D(("ZZ9000Net: MNT ZZ9000 found.\n"));
  119. ZZ9K_REGS = (ULONG)cd->cd_BoardAddr;
  120. // Thanks to https://grandcentrix.team
  121. HW_MAC[0]=0x68;
  122. HW_MAC[1]=0x82;
  123. HW_MAC[2]=0xF2;
  124. HW_MAC[3]=0x00;
  125. HW_MAC[4]=0x01;
  126. HW_MAC[5]=0x00;
  127. if ((fh=Open("ENV:ZZ9K_MAC",MODE_OLDFILE))) {
  128. UBYTE char_buf[32];
  129. char* res = FGets(fh,char_buf,18);
  130. if (!res || strlen(char_buf)<17) {
  131. D(("ZZ9000Net: MAC address in ENV:ZZ9K_MAC has invalid syntax.\n"));
  132. } else {
  133. D(("ZZ9000Net: Setting MAC address from ENV:ZZ9K_MAC.\n"));
  134. set_mac_from_string(char_buf);
  135. }
  136. Close(fh);
  137. }
  138. // FIXME
  139. *(USHORT*)(ZZ9K_REGS+0x84) = (HW_MAC[0]<<8)|HW_MAC[1];
  140. *(USHORT*)(ZZ9K_REGS+0x84) = (HW_MAC[0]<<8)|HW_MAC[1];
  141. *(USHORT*)(ZZ9K_REGS+0x86) = (HW_MAC[2]<<8)|HW_MAC[3];
  142. *(USHORT*)(ZZ9K_REGS+0x86) = (HW_MAC[2]<<8)|HW_MAC[3];
  143. *(USHORT*)(ZZ9K_REGS+0x88) = (HW_MAC[4]<<8)|HW_MAC[5];
  144. ok = 1;
  145. } else {
  146. D(("ZZ9000Net: MNT ZZ9000 not found!\n"));
  147. }
  148. CloseLibrary(ExpansionBase);
  149. } else {
  150. D(("ZZ9000Net: failed to open expansion.library!\n"));
  151. }
  152. if (!ok) {
  153. CloseLibrary(DOSBase);
  154. CloseLibrary(UtilityBase);
  155. }
  156. }
  157. else {
  158. D(("ZZ9000Net: Could not open utility.library.\n"));
  159. CloseLibrary(DOSBase);
  160. }
  161. }
  162. else {
  163. D(("ZZ9000Net: Could not open dos.library.\n"));
  164. }
  165. {
  166. BPTR fh;
  167. if ((fh=Open("ENV:ZZ9K_INT2",MODE_OLDFILE))) {
  168. D(("ZZ9000Net: Using INT2 mode.\n"));
  169. Close(fh);
  170. db->db_Flags |= DEVF_INT2MODE;
  171. } else {
  172. D(("ZZ9000Net: Using INT6 mode (default).\n"));
  173. }
  174. }
  175. /* no hardware found, reject init */
  176. return (ok > 0) ? (struct Device*)db : (0);
  177. }
  178. __saveds LONG DevOpen( ASMR(a1) struct IOSana2Req *ioreq ASMREG(a1),
  179. ASMR(d0) ULONG unit ASMREG(d0),
  180. ASMR(d1) ULONG flags ASMREG(d1),
  181. ASMR(a6) DEVBASEP ASMREG(a6) )
  182. {
  183. LONG ok = 0,ret = IOERR_OPENFAIL;
  184. struct BufferManagement *bm;
  185. D(("ZZ9000Net: DevOpen for %ld\n",unit));
  186. db->db_Lib.lib_OpenCnt++; /* avoid Expunge, see below for separate "unit" open count */
  187. if (unit==0 && db->db_Lib.lib_OpenCnt==1) {
  188. if ((bm = (struct BufferManagement*)AllocVec(sizeof(struct BufferManagement), MEMF_CLEAR|MEMF_PUBLIC))) {
  189. bm->bm_CopyToBuffer = (BMFunc)GetTagData(S2_CopyToBuff, 0, (struct TagItem *)ioreq->ios2_BufferManagement);
  190. bm->bm_CopyFromBuffer = (BMFunc)GetTagData(S2_CopyFromBuff, 0, (struct TagItem *)ioreq->ios2_BufferManagement);
  191. ioreq->ios2_BufferManagement = (VOID *)bm;
  192. ioreq->ios2_Req.io_Error = 0;
  193. ioreq->ios2_Req.io_Unit = (struct Unit *)unit; // not a real pointer, but id integer
  194. ioreq->ios2_Req.io_Device = (struct Device *)db;
  195. NewList(&db->db_ReadList);
  196. InitSemaphore(&db->db_ReadListSem);
  197. struct ProcInit init;
  198. struct MsgPort *port;
  199. if (port = CreateMsgPort()) {
  200. D(("ZZ9000Net: Starting Process\n"));
  201. if (db->db_Proc = CreateNewProcTags(NP_Entry, frame_proc, NP_Name,
  202. frame_proc_name, TAG_DONE)) {
  203. InitSemaphore(&db->db_ProcExitSem);
  204. init.error = 1;
  205. init.db = db;
  206. init.msg.mn_Length = sizeof(init);
  207. init.msg.mn_ReplyPort = port;
  208. D(("ZZ9000Net: handover db: %lx\n",init.db));
  209. PutMsg(&db->db_Proc->pr_MsgPort, (struct Message*)&init);
  210. WaitPort(port);
  211. if (!init.error) {
  212. ok = 1;
  213. // Register Interrupt server
  214. if (db->db_interrupt = AllocMem(sizeof(struct Interrupt), MEMF_PUBLIC|MEMF_CLEAR)) {
  215. db->db_interrupt->is_Node.ln_Type = NT_INTERRUPT;
  216. db->db_interrupt->is_Node.ln_Pri = -60;
  217. db->db_interrupt->is_Node.ln_Name = "ZZ9000Net";
  218. db->db_interrupt->is_Data = (APTR)db;
  219. db->db_interrupt->is_Code = dev_isr;
  220. Disable();
  221. AddIntServer((db->db_Flags & DEVF_INT2MODE) ? INTB_PORTS : INTB_EXTER, db->db_interrupt);
  222. Enable();
  223. D(("ZZ9000Net: Interrupt server registered, using INT%ld\n",(db->db_Flags & DEVF_INT2MODE) ? 2L : 6L));
  224. ret = 0;
  225. ok = 1;
  226. // enable HW interrupt
  227. USHORT hw_config = *(USHORT*)(ZZ9K_REGS+0x04);
  228. hw_config |= 1;
  229. *(volatile USHORT*)(ZZ9K_REGS+0x04) = hw_config;
  230. D(("ZZ9000Net: ZZ interrupt enabled\n"));
  231. } else {
  232. D(("ZZ9000Net: failed to alloc struct Interrupt\n"));
  233. ret = IOERR_OPENFAIL;
  234. ok = 0;
  235. Signal((struct Task*)db->db_Proc, SIGBREAKF_CTRL_C);
  236. // this will block until the process has really quit and released the semaphore
  237. ObtainSemaphore(&db->db_ProcExitSem);
  238. ReleaseSemaphore(&db->db_ProcExitSem);
  239. }
  240. } else {
  241. D(("ZZ9000Net:process startup error\n"));
  242. ret = IOERR_OPENFAIL;
  243. ok = 0;
  244. }
  245. } else {
  246. D(("ZZ9000Net:couldn't create process\n"));
  247. ret = IOERR_OPENFAIL;
  248. ok = 0;
  249. }
  250. DeleteMsgPort(port);
  251. }
  252. }
  253. } else {
  254. ret = IOERR_OPENFAIL;
  255. ok = 0;
  256. }
  257. if (ok) {
  258. ret = 0;
  259. db->db_Lib.lib_Flags &= ~LIBF_DELEXP;
  260. }
  261. if (ret == IOERR_OPENFAIL) {
  262. ioreq->ios2_Req.io_Unit = (0);
  263. ioreq->ios2_Req.io_Device = (0);
  264. ioreq->ios2_Req.io_Error = ret;
  265. db->db_Lib.lib_OpenCnt--;
  266. }
  267. ioreq->ios2_Req.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
  268. D(("ZZ9000Net: DevOpen return code %ld\n",ret));
  269. return ret;
  270. }
  271. __saveds BPTR DevClose( ASMR(a1) struct IORequest *ioreq ASMREG(a1),
  272. ASMR(a6) DEVBASEP ASMREG(a6) )
  273. {
  274. /* ULONG unit; */
  275. BPTR ret = (0);
  276. D(("ZZ9000Net: DevClose open count %ld\n",db->db_Lib.lib_OpenCnt));
  277. if( !ioreq )
  278. return ret;
  279. db->db_Lib.lib_OpenCnt--;
  280. if (db->db_Lib.lib_OpenCnt == 0) {
  281. // disable HW interrupt
  282. USHORT hw_config = *(USHORT*)(ZZ9K_REGS+0x04);
  283. hw_config &= 0xfffe;
  284. *(volatile USHORT*)(ZZ9K_REGS+0x04) = hw_config;
  285. D(("ZZ9000Net: ZZ interrupt disabled\n"));
  286. if (db->db_interrupt) {
  287. D(("ZZ9000Net: Remove IntServer...\n"));
  288. Forbid();
  289. RemIntServer((db->db_Flags & DEVF_INT2MODE) ? INTB_PORTS : INTB_EXTER, db->db_interrupt);
  290. db->db_interrupt = 0;
  291. Permit();
  292. }
  293. if (db->db_Proc) {
  294. D(("ZZ9000Net: End Proc...\n"));
  295. Signal((struct Task*)db->db_Proc, SIGBREAKF_CTRL_C);
  296. db->db_Proc = 0;
  297. ObtainSemaphore(&db->db_ProcExitSem);
  298. ReleaseSemaphore(&db->db_ProcExitSem);
  299. }
  300. }
  301. ioreq->io_Device = (0);
  302. ioreq->io_Unit = (struct Unit *)(-1);
  303. if (db->db_Lib.lib_Flags & LIBF_DELEXP)
  304. ret = DevExpunge(db);
  305. return ret;
  306. }
  307. __saveds BPTR DevExpunge( ASMR(a6) DEVBASEP ASMREG(a6) )
  308. {
  309. BPTR seglist = db->db_SegList;
  310. if( db->db_Lib.lib_OpenCnt )
  311. {
  312. db->db_Lib.lib_Flags |= LIBF_DELEXP;
  313. return (0);
  314. }
  315. D(("ZZ9000Net: Remove Device Node...\n"));
  316. Remove((struct Node*)db);
  317. CloseLibrary(DOSBase);
  318. CloseLibrary(UtilityBase);
  319. FreeMem( ((BYTE*)db)-db->db_Lib.lib_NegSize,(ULONG)(db->db_Lib.lib_PosSize + db->db_Lib.lib_NegSize));
  320. return seglist;
  321. }
  322. ULONG read_frame(struct IOSana2Req *req, volatile UBYTE *frame);
  323. ULONG write_frame(struct IOSana2Req *req, UBYTE *frame);
  324. __saveds VOID DevBeginIO( ASMR(a1) struct IOSana2Req *ioreq ASMREG(a1),
  325. ASMR(a6) DEVBASEP ASMREG(a6) )
  326. {
  327. ULONG unit = (ULONG)ioreq->ios2_Req.io_Unit;
  328. int mtu;
  329. ioreq->ios2_Req.io_Message.mn_Node.ln_Type = NT_MESSAGE;
  330. ioreq->ios2_Req.io_Error = S2ERR_NO_ERROR;
  331. ioreq->ios2_WireError = S2WERR_GENERIC_ERROR;
  332. //D(("BeginIO command %ld unit %ld\n",(LONG)ioreq->ios2_Req.io_Command,unit));
  333. switch( ioreq->ios2_Req.io_Command ) {
  334. case CMD_READ:
  335. if (ioreq->ios2_BufferManagement == NULL) {
  336. ioreq->ios2_Req.io_Error = S2ERR_BAD_ARGUMENT;
  337. ioreq->ios2_WireError = S2WERR_BUFF_ERROR;
  338. }
  339. else {
  340. // not quick, add request to reader list
  341. // will be handled on interrupts by frame_proc
  342. ioreq->ios2_Req.io_Flags &= ~SANA2IOF_QUICK;
  343. ObtainSemaphore(&db->db_ReadListSem);
  344. AddHead((struct List*)&db->db_ReadList, (struct Node*)ioreq);
  345. ReleaseSemaphore(&db->db_ReadListSem);
  346. ioreq = NULL;
  347. }
  348. break;
  349. case S2_BROADCAST:
  350. /* set broadcast addr: ff:ff:ff:ff:ff:ff */
  351. if (ioreq->ios2_DstAddr) {
  352. memset(ioreq->ios2_DstAddr, 0xff, HW_ADDRFIELDSIZE);
  353. } else {
  354. D(("bcast: invalid dst addr\n"));
  355. }
  356. /* fall through */
  357. case CMD_WRITE: {
  358. ULONG res = write_frame(ioreq, (UBYTE*)(ZZ9K_REGS+ZZ9K_TX));
  359. if (res!=0) {
  360. ioreq->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
  361. ioreq->ios2_WireError = S2WERR_GENERIC_ERROR;
  362. } else {
  363. ioreq->ios2_Req.io_Error = 0;
  364. }
  365. break;
  366. }
  367. case S2_READORPHAN:
  368. if( !ioreq->ios2_BufferManagement )
  369. {
  370. ioreq->ios2_Req.io_Error = S2ERR_BAD_ARGUMENT;
  371. ioreq->ios2_WireError = S2WERR_BUFF_ERROR;
  372. }
  373. else
  374. {
  375. ioreq->ios2_Req.io_Flags &= ~SANA2IOF_QUICK;
  376. // FIXME do we need this list?
  377. //ObtainSemaphore(&db->db_Units[unit].du_Sem);
  378. //AddHead((struct List*)&db->db_ReadOrphans,(struct Node*)ioreq);
  379. //ReleaseSemaphore(&db->db_Units[unit].du_Sem);
  380. ioreq = NULL;
  381. }
  382. break;
  383. case S2_ONLINE:
  384. case S2_OFFLINE:
  385. case S2_CONFIGINTERFACE: /* forward request */
  386. break;
  387. case S2_GETSTATIONADDRESS:
  388. memcpy(ioreq->ios2_SrcAddr, HW_MAC, HW_ADDRFIELDSIZE); /* current */
  389. memcpy(ioreq->ios2_DstAddr, HW_MAC, HW_ADDRFIELDSIZE); /* default */
  390. break;
  391. case S2_DEVICEQUERY:
  392. {
  393. struct Sana2DeviceQuery *devquery;
  394. devquery = ioreq->ios2_StatData;
  395. devquery->DevQueryFormat = 0; /* "this is format 0" */
  396. devquery->DeviceLevel = 0; /* "this spec defines level 0" */
  397. if (devquery->SizeAvailable >= 18) devquery->AddrFieldSize = HW_ADDRFIELDSIZE * 8; /* Bits! */
  398. if (devquery->SizeAvailable >= 22) devquery->MTU = 1500;
  399. if (devquery->SizeAvailable >= 26) devquery->BPS = 1000*1000*100;
  400. if (devquery->SizeAvailable >= 30) devquery->HardwareType = S2WireType_Ethernet;
  401. devquery->SizeSupplied = (devquery->SizeAvailable<30?devquery->SizeAvailable:30);
  402. }
  403. break;
  404. case S2_GETSPECIALSTATS:
  405. {
  406. struct Sana2SpecialStatHeader *s2ssh = (struct Sana2SpecialStatHeader *)ioreq->ios2_StatData;
  407. s2ssh->RecordCountSupplied = 0;
  408. }
  409. break;
  410. default:
  411. {
  412. ioreq->ios2_Req.io_Error = S2ERR_NOT_SUPPORTED;
  413. ioreq->ios2_WireError = S2WERR_GENERIC_ERROR;
  414. break;
  415. }
  416. }
  417. if (ioreq) {
  418. DevTermIO(db, (struct IORequest*)ioreq);
  419. }
  420. }
  421. __saveds LONG DevAbortIO( ASMR(a1) struct IORequest *ioreq ASMREG(a1),
  422. ASMR(a6) DEVBASEP ASMREG(a6) )
  423. {
  424. LONG ret = 0;
  425. struct IOSana2Req* ios2 = (struct IOSana2Req*)ioreq;
  426. D(("ZZ9000Net: AbortIO on %lx\n",(ULONG)ioreq));
  427. Remove((struct Node*)ioreq);
  428. ioreq->io_Error = IOERR_ABORTED;
  429. ios2->ios2_WireError = 0;
  430. ReplyMsg((struct Message*)ioreq);
  431. return ret;
  432. }
  433. void DevTermIO( DEVBASEP, struct IORequest *ioreq )
  434. {
  435. struct IOSana2Req* ios2 = (struct IOSana2Req*)ioreq;
  436. if (!(ios2->ios2_Req.io_Flags & SANA2IOF_QUICK)) {
  437. ReplyMsg((struct Message *)ioreq);
  438. } else {
  439. ioreq->io_Message.mn_Node.ln_Type = NT_REPLYMSG;
  440. }
  441. }
  442. ULONG get_frame_serial(UBYTE* frame) {
  443. UBYTE* frm = (UBYTE*)frame;
  444. ULONG ser = ((ULONG)frm[2]<<8)|((ULONG)frm[3]);
  445. return ser;
  446. }
  447. ULONG read_frame(struct IOSana2Req *req, volatile UBYTE *frame)
  448. {
  449. ULONG datasize;
  450. BYTE *frame_ptr;
  451. BOOL broadcast;
  452. ULONG err = 0;
  453. struct BufferManagement *bm;
  454. UBYTE* frm = (UBYTE*)frame;
  455. ULONG sz = ((ULONG)frm[0]<<8)|((ULONG)frm[1]);
  456. ULONG ser = ((ULONG)frm[2]<<8)|((ULONG)frm[3]);
  457. USHORT tp = ((USHORT)frm[16]<<8)|((USHORT)frm[17]);
  458. if (req->ios2_Req.io_Flags & SANA2IOF_RAW) {
  459. frame_ptr = frm+4;
  460. datasize = sz;
  461. req->ios2_Req.io_Flags = SANA2IOF_RAW;
  462. }
  463. else {
  464. frame_ptr = frm+4+HW_ETH_HDR_SIZE;
  465. datasize = sz-HW_ETH_HDR_SIZE;
  466. req->ios2_Req.io_Flags = 0;
  467. }
  468. req->ios2_DataLength = datasize;
  469. //D(("datasize: %lx\n",datasize));
  470. //D(("frame_ptr: %lx\n",frame_ptr));
  471. //D(("ios2_Data: %lx\n",req->ios2_Data));
  472. //D(("bufmgmt: %lx\n",req->ios2_BufferManagement));
  473. // copy frame to device user (probably tcp/ip system)
  474. bm = (struct BufferManagement *)req->ios2_BufferManagement;
  475. if (!(*bm->bm_CopyToBuffer)(req->ios2_Data, frame_ptr, datasize)) {
  476. //D(("rx copybuf error\n"));
  477. req->ios2_Req.io_Error = S2ERR_SOFTWARE;
  478. req->ios2_WireError = S2WERR_BUFF_ERROR;
  479. err = 1;
  480. }
  481. else {
  482. req->ios2_Req.io_Error = req->ios2_WireError = 0;
  483. err = 0;
  484. }
  485. memcpy(req->ios2_SrcAddr, frame+4+6, HW_ADDRFIELDSIZE);
  486. memcpy(req->ios2_DstAddr, frame+4, HW_ADDRFIELDSIZE);
  487. //D(("RXSZ %ld\n",(LONG)sz));
  488. //D(("RXPT %ld\n",(LONG)tp));
  489. //D(("RXSER %ld\n",(LONG)ser));
  490. //D(("RXDST %lx...\n",*((ULONG*)(req->ios2_DstAddr))));
  491. //D(("RXSRC %lx\n",*((ULONG*)(req->ios2_SrcAddr))));
  492. //D(("RXSRC %lx\n",*((ULONG*)(frame_ptr))));
  493. broadcast = TRUE;
  494. for (int i=0; i<HW_ADDRFIELDSIZE; i++) {
  495. if (frame[i+4] != 0xff) {
  496. broadcast = FALSE;
  497. break;
  498. }
  499. }
  500. if (broadcast) {
  501. req->ios2_Req.io_Flags |= SANA2IOF_BCAST;
  502. }
  503. req->ios2_PacketType = tp;
  504. return err;
  505. }
  506. ULONG write_frame(struct IOSana2Req *req, UBYTE *frame)
  507. {
  508. ULONG rc=0;
  509. struct BufferManagement *bm;
  510. USHORT sz=0;
  511. if (req->ios2_Req.io_Flags & SANA2IOF_RAW) {
  512. sz = req->ios2_DataLength;
  513. } else {
  514. sz = req->ios2_DataLength + HW_ETH_HDR_SIZE;
  515. *((USHORT*)(frame+6+6)) = (USHORT)req->ios2_PacketType;
  516. memcpy(frame, req->ios2_DstAddr, HW_ADDRFIELDSIZE);
  517. memcpy(frame+6, HW_MAC, HW_ADDRFIELDSIZE);
  518. frame+=HW_ETH_HDR_SIZE;
  519. }
  520. if (sz>0) {
  521. bm = (struct BufferManagement *)req->ios2_BufferManagement;
  522. if (!(*bm->bm_CopyFromBuffer)(frame, req->ios2_Data, req->ios2_DataLength)) {
  523. rc = 1; // FIXME error code
  524. //D(("tx copybuf err\n"));
  525. }
  526. else {
  527. // buffer was copied to zz9000, send it
  528. volatile USHORT* reg = (volatile USHORT*)(ZZ9K_REGS+0x80); // FIXME send_frame reg
  529. *reg = sz;
  530. // get feedback
  531. rc = *reg;
  532. if (rc!=0) {
  533. D(("tx err: %d\n",rc));
  534. }
  535. }
  536. }
  537. return rc;
  538. }
  539. __saveds void frame_proc() {
  540. ULONG wmask;
  541. D(("ZZ9000Net: frame_proc()\n"));
  542. struct ProcInit* init;
  543. {
  544. struct { void *db_SysBase; } *db = (void*)0x4;
  545. struct Process* proc;
  546. proc = (struct Process*)FindTask(NULL);
  547. WaitPort(&proc->pr_MsgPort);
  548. init = (struct ProcInit*)GetMsg(&proc->pr_MsgPort);
  549. }
  550. struct devbase* db = init->db;
  551. init->error = 0;
  552. db = init->db;
  553. ObtainSemaphore(&db->db_ProcExitSem);
  554. ReplyMsg((struct Message*)init);
  555. wmask = SIGBREAKF_CTRL_F | SIGBREAKF_CTRL_C;
  556. ULONG old_serial = 0;
  557. ULONG recv = 0;
  558. // wait for the first packet
  559. recv = Wait(wmask);
  560. while (1) {
  561. struct IOSana2Req *ior;
  562. BOOL receiver_found = 0;
  563. // wait for signal from our interrupt handler
  564. // remove this to use polled-IO
  565. if (recv & SIGBREAKF_CTRL_C) {
  566. D(("ZZ9000Net: process end\n"));
  567. break;
  568. }
  569. volatile UBYTE* frm = (volatile UBYTE*)(ZZ9K_REGS+ZZ9K_RX);
  570. ULONG serial = get_frame_serial(frm);
  571. //D(("FTI %ld\n", serial));
  572. if (serial != old_serial) {
  573. int processed = 0;
  574. USHORT packet_type = ((USHORT)frm[16]<<8)|((USHORT)frm[17]);
  575. old_serial = serial;
  576. ObtainSemaphore(&db->db_ReadListSem);
  577. for (ior = (struct IOSana2Req *)db->db_ReadList.lh_Head;
  578. ior->ios2_Req.io_Message.mn_Node.ln_Succ;
  579. ior = (struct IOSana2Req *)ior->ios2_Req.io_Message.mn_Node.ln_Succ) {
  580. if (ior->ios2_PacketType == packet_type) {
  581. ULONG res = read_frame(ior, frm);
  582. if (res==0) {
  583. Remove((struct Node*)ior);
  584. ReplyMsg((struct Message *)ior);
  585. processed = 1;
  586. } else {
  587. D(("RERR %ld\n",res));
  588. }
  589. break;
  590. }
  591. }
  592. ReleaseSemaphore(&db->db_ReadListSem);
  593. if (!processed) {
  594. //D(("UNPR %ld\n",(LONG)packet_type));
  595. }
  596. // mark this frame as accepted
  597. volatile USHORT* reg = (volatile USHORT*)(ZZ9K_REGS+0x82); // FIXME receive_frame reg
  598. *reg = 1;
  599. } else {
  600. // if there are no more new packets, idle until the next interrupt
  601. recv = Wait(wmask);
  602. }
  603. }
  604. Forbid();
  605. ReleaseSemaphore(&db->db_ProcExitSem);
  606. }