diff options
Diffstat (limited to 'drivers/net/atari_pamsnet.c')
| -rw-r--r-- | drivers/net/atari_pamsnet.c | 878 |
1 files changed, 0 insertions, 878 deletions
diff --git a/drivers/net/atari_pamsnet.c b/drivers/net/atari_pamsnet.c deleted file mode 100644 index f7356374a2e7..000000000000 --- a/drivers/net/atari_pamsnet.c +++ /dev/null | |||
| @@ -1,878 +0,0 @@ | |||
| 1 | /* atari_pamsnet.c PAMsNet device driver for linux68k. | ||
| 2 | * | ||
| 3 | * Version: @(#)PAMsNet.c 0.2ß 03/31/96 | ||
| 4 | * | ||
| 5 | * Author: Torsten Lang <Torsten.Lang@ap.physik.uni-giessen.de> | ||
| 6 | * <Torsten.Lang@jung.de> | ||
| 7 | * | ||
| 8 | * This driver is based on my driver PAMSDMA.c for MiNT-Net and | ||
| 9 | * on the driver bionet.c written by | ||
| 10 | * Hartmut Laue <laue@ifk-mp.uni-kiel.de> | ||
| 11 | * and Torsten Narjes <narjes@ifk-mp.uni-kiel.de> | ||
| 12 | * | ||
| 13 | * Little adaptions for integration into pl7 by Roman Hodek | ||
| 14 | * | ||
| 15 | What is it ? | ||
| 16 | ------------ | ||
| 17 | This driver controls the PAMsNet LAN-Adapter which connects | ||
| 18 | an ATARI ST/TT via the ACSI-port to an Ethernet-based network. | ||
| 19 | |||
| 20 | This version can be compiled as a loadable module (See the | ||
| 21 | compile command at the bottom of this file). | ||
| 22 | At load time, you can optionally set the debugging level and the | ||
| 23 | fastest response time on the command line of 'insmod'. | ||
| 24 | |||
| 25 | 'pamsnet_debug' | ||
| 26 | controls the amount of diagnostic messages: | ||
| 27 | 0 : no messages | ||
| 28 | >0 : see code for meaning of printed messages | ||
| 29 | |||
| 30 | 'pamsnet_min_poll_time' (always >=1) | ||
| 31 | gives the time (in jiffies) between polls. Low values | ||
| 32 | increase the system load (beware!) | ||
| 33 | |||
| 34 | When loaded, a net device with the name 'eth?' becomes available, | ||
| 35 | which can be controlled with the usual 'ifconfig' command. | ||
| 36 | |||
| 37 | It is possible to compile this driver into the kernel like other | ||
| 38 | (net) drivers. For this purpose, some source files (e.g. config-files | ||
| 39 | makefiles, Space.c) must be changed accordingly. (You may refer to | ||
| 40 | other drivers how to do it.) In this case, the device will be detected | ||
| 41 | at boot time and (probably) appear as 'eth0'. | ||
| 42 | |||
| 43 | Theory of Operation | ||
| 44 | ------------------- | ||
| 45 | Because the ATARI DMA port is usually shared between several | ||
| 46 | devices (eg. harddisk, floppy) we cannot block the ACSI bus | ||
| 47 | while waiting for interrupts. Therefore we use a polling mechanism | ||
| 48 | to fetch packets from the adapter. For the same reason, we send | ||
| 49 | packets without checking that the previous packet has been sent to | ||
| 50 | the LAN. We rely on the higher levels of the networking code to detect | ||
| 51 | missing packets and resend them. | ||
| 52 | |||
| 53 | Before we access the ATARI DMA controller, we check if another | ||
| 54 | process is using the DMA. If not, we lock the DMA, perform one or | ||
| 55 | more packet transfers and unlock the DMA before returning. | ||
| 56 | We do not use 'stdma_lock' unconditionally because it is unclear | ||
| 57 | if the networking code can be set to sleep, which will happen if | ||
| 58 | another (possibly slow) device is using the DMA controller. | ||
| 59 | |||
| 60 | The polling is done via timer interrupts which periodically | ||
| 61 | 'simulate' an interrupt from the Ethernet adapter. The time (in jiffies) | ||
| 62 | between polls varies depending on an estimate of the net activity. | ||
| 63 | The allowed range is given by the variable 'bionet_min_poll_time' | ||
| 64 | for the lower (fastest) limit and the constant 'MAX_POLL_TIME' | ||
| 65 | for the higher (slowest) limit. | ||
| 66 | |||
| 67 | Whenever a packet arrives, we switch to fastest response by setting | ||
| 68 | the polling time to its lowest limit. If the following poll fails, | ||
| 69 | because no packets have arrived, we increase the time for the next | ||
| 70 | poll. When the net activity is low, the polling time effectively | ||
| 71 | stays at its maximum value, resulting in the lowest load for the | ||
| 72 | machine. | ||
| 73 | */ | ||
| 74 | |||
| 75 | #define MAX_POLL_TIME 10 | ||
| 76 | |||
| 77 | static char *version = | ||
| 78 | "pamsnet.c:v0.2beta 30-mar-96 (c) Torsten Lang.\n"; | ||
| 79 | |||
| 80 | #include <linux/module.h> | ||
| 81 | |||
| 82 | #include <linux/kernel.h> | ||
| 83 | #include <linux/jiffies.h> | ||
| 84 | #include <linux/types.h> | ||
| 85 | #include <linux/fcntl.h> | ||
| 86 | #include <linux/interrupt.h> | ||
| 87 | #include <linux/ioport.h> | ||
| 88 | #include <linux/in.h> | ||
| 89 | #include <linux/slab.h> | ||
| 90 | #include <linux/string.h> | ||
| 91 | #include <linux/bitops.h> | ||
| 92 | #include <asm/system.h> | ||
| 93 | #include <asm/pgtable.h> | ||
| 94 | #include <asm/io.h> | ||
| 95 | #include <asm/dma.h> | ||
| 96 | #include <linux/errno.h> | ||
| 97 | #include <asm/atarihw.h> | ||
| 98 | #include <asm/atariints.h> | ||
| 99 | #include <asm/atari_stdma.h> | ||
| 100 | #include <asm/atari_acsi.h> | ||
| 101 | |||
| 102 | #include <linux/delay.h> | ||
| 103 | #include <linux/timer.h> | ||
| 104 | #include <linux/init.h> | ||
| 105 | |||
| 106 | #include <linux/netdevice.h> | ||
| 107 | #include <linux/etherdevice.h> | ||
| 108 | #include <linux/skbuff.h> | ||
| 109 | |||
| 110 | #undef READ | ||
| 111 | #undef WRITE | ||
| 112 | |||
| 113 | /* use 0 for production, 1 for verification, >2 for debug | ||
| 114 | */ | ||
| 115 | #ifndef NET_DEBUG | ||
| 116 | #define NET_DEBUG 0 | ||
| 117 | #endif | ||
| 118 | /* | ||
| 119 | * Global variable 'pamsnet_debug'. Can be set at load time by 'insmod' | ||
| 120 | */ | ||
| 121 | unsigned int pamsnet_debug = NET_DEBUG; | ||
| 122 | module_param(pamsnet_debug, int, 0); | ||
| 123 | MODULE_PARM_DESC(pamsnet_debug, "pamsnet debug enable (0-1)"); | ||
| 124 | MODULE_LICENSE("GPL"); | ||
| 125 | |||
| 126 | static unsigned int pamsnet_min_poll_time = 2; | ||
| 127 | |||
| 128 | |||
| 129 | /* Information that need to be kept for each board. | ||
| 130 | */ | ||
| 131 | struct net_local { | ||
| 132 | struct net_device_stats stats; | ||
| 133 | long open_time; /* for debugging */ | ||
| 134 | int poll_time; /* polling time varies with net load */ | ||
| 135 | }; | ||
| 136 | |||
| 137 | static struct nic_pkt_s { /* packet format */ | ||
| 138 | unsigned char buffer[2048]; | ||
| 139 | } *nic_packet = 0; | ||
| 140 | unsigned char *phys_nic_packet; | ||
| 141 | |||
| 142 | typedef unsigned char HADDR[6]; /* 6-byte hardware address of lance */ | ||
| 143 | |||
| 144 | /* Index to functions, as function prototypes. | ||
| 145 | */ | ||
| 146 | static void start (int target); | ||
| 147 | static int stop (int target); | ||
| 148 | static int testpkt (int target); | ||
| 149 | static int sendpkt (int target, unsigned char *buffer, int length); | ||
| 150 | static int receivepkt (int target, unsigned char *buffer); | ||
| 151 | static int inquiry (int target, unsigned char *buffer); | ||
| 152 | static HADDR *read_hw_addr(int target, unsigned char *buffer); | ||
| 153 | static void setup_dma (void *address, unsigned rw_flag, int num_blocks); | ||
| 154 | static int send_first (int target, unsigned char byte); | ||
| 155 | static int send_1_5 (int lun, unsigned char *command, int dma); | ||
| 156 | static int get_status (void); | ||
| 157 | static int calc_received (void *start_address); | ||
| 158 | |||
| 159 | static int pamsnet_open(struct net_device *dev); | ||
| 160 | static int pamsnet_send_packet(struct sk_buff *skb, struct net_device *dev); | ||
| 161 | static void pamsnet_poll_rx(struct net_device *); | ||
| 162 | static int pamsnet_close(struct net_device *dev); | ||
| 163 | static struct net_device_stats *net_get_stats(struct net_device *dev); | ||
| 164 | static void pamsnet_tick(unsigned long); | ||
| 165 | |||
| 166 | static irqreturn_t pamsnet_intr(int irq, void *data); | ||
| 167 | |||
| 168 | static DEFINE_TIMER(pamsnet_timer, pamsnet_tick, 0, 0); | ||
| 169 | |||
| 170 | #define STRAM_ADDR(a) (((a) & 0xff000000) == 0) | ||
| 171 | |||
| 172 | typedef struct | ||
| 173 | { | ||
| 174 | unsigned char reserved1[0x38]; | ||
| 175 | HADDR hwaddr; | ||
| 176 | unsigned char reserved2[0x1c2]; | ||
| 177 | } DMAHWADDR; | ||
| 178 | |||
| 179 | /* | ||
| 180 | * Definitions of commands understood by the PAMs DMA adaptor. | ||
| 181 | * | ||
| 182 | * In general the DMA adaptor uses LUN 0, 5, 6 and 7 on one ID changeable | ||
| 183 | * by the PAM's Net software. | ||
| 184 | * | ||
| 185 | * LUN 0 works as a harddisk. You can boot the PAM's Net driver there. | ||
| 186 | * LUN 5 works as a harddisk and lets you access the RAM and some I/O HW | ||
| 187 | * area. In sector 0, bytes 0x38-0x3d you find the ethernet HW address | ||
| 188 | * of the adaptor. | ||
| 189 | * LUN 6 works as a harddisk and lets you access the firmware ROM. | ||
| 190 | * LUN 7 lets you send and receive packets. | ||
| 191 | * | ||
| 192 | * Some commands like the INQUIRY command work identical on all used LUNs. | ||
| 193 | * | ||
| 194 | * UNKNOWN1 seems to read some data. | ||
| 195 | * Command length is 6 bytes. | ||
| 196 | * UNKNOWN2 seems to read some data (command byte 1 must be !=0). The | ||
| 197 | * following bytes seem to be something like an allocation length. | ||
| 198 | * Command length is 6 bytes. | ||
| 199 | * READPKT reads a packet received by the DMA adaptor. | ||
| 200 | * Command length is 6 bytes. | ||
| 201 | * WRITEPKT sends a packet transferred by the following DMA phase. The length | ||
| 202 | * of the packet is transferred in command bytes 3 and 4. | ||
| 203 | * The adaptor automatically replaces the src hw address in an ethernet | ||
| 204 | * packet by its own hw address. | ||
| 205 | * Command length is 6 bytes. | ||
| 206 | * INQUIRY has the same function as the INQUIRY command supported by harddisks | ||
| 207 | * and other SCSI devices. It lets you detect which device you found | ||
| 208 | * at a given address. | ||
| 209 | * Command length is 6 bytes. | ||
| 210 | * START initializes the DMA adaptor. After this command it is able to send | ||
| 211 | * and receive packets. There is no status byte returned! | ||
| 212 | * Command length is 1 byte. | ||
| 213 | * NUMPKTS gives back the number of received packets waiting in the queue in | ||
| 214 | * the status byte. | ||
| 215 | * Command length is 1 byte. | ||
| 216 | * UNKNOWN3 | ||
| 217 | * UNKNOWN4 Function of these three commands is unknown. | ||
| 218 | * UNKNOWN5 The command length of these three commands is 1 byte. | ||
| 219 | * DESELECT immediately deselects the DMA adaptor. May important with interrupt | ||
| 220 | * driven operation. | ||
| 221 | * Command length is 1 byte. | ||
| 222 | * STOP resets the DMA adaptor. After this command packets can no longer | ||
| 223 | * be received or transferred. | ||
| 224 | * Command length is 6 byte. | ||
| 225 | */ | ||
| 226 | |||
| 227 | enum {UNKNOWN1=3, READPKT=8, UNKNOWN2, WRITEPKT=10, INQUIRY=18, START, | ||
| 228 | NUMPKTS=22, UNKNOWN3, UNKNOWN4, UNKNOWN5, DESELECT, STOP}; | ||
| 229 | |||
| 230 | #define READSECTOR READPKT | ||
| 231 | #define WRITESECTOR WRITEPKT | ||
| 232 | |||
| 233 | u_char *inquire8="MV PAM's NET/GK"; | ||
| 234 | |||
| 235 | #define DMALOW dma_wd.dma_lo | ||
| 236 | #define DMAMID dma_wd.dma_md | ||
| 237 | #define DMAHIGH dma_wd.dma_hi | ||
| 238 | #define DACCESS dma_wd.fdc_acces_seccount | ||
| 239 | |||
| 240 | #define MFP_GPIP mfp.par_dt_reg | ||
| 241 | |||
| 242 | /* Some useful functions */ | ||
| 243 | |||
| 244 | #define INT (!(MFP_GPIP & 0x20)) | ||
| 245 | #define DELAY ({MFP_GPIP; MFP_GPIP; MFP_GPIP;}) | ||
| 246 | #define WRITEMODE(value) \ | ||
| 247 | ({ u_short dummy = value; \ | ||
| 248 | __asm__ volatile("movew %0, 0xFFFF8606" : : "d"(dummy)); \ | ||
| 249 | DELAY; \ | ||
| 250 | }) | ||
| 251 | #define WRITEBOTH(value1, value2) \ | ||
| 252 | ({ u_long dummy = (u_long)(value1)<<16 | (u_short)(value2); \ | ||
| 253 | __asm__ volatile("movel %0, 0xFFFF8604" : : "d"(dummy)); \ | ||
| 254 | DELAY; \ | ||
| 255 | }) | ||
| 256 | |||
| 257 | /* Definitions for DMODE */ | ||
| 258 | |||
| 259 | #define READ 0x000 | ||
| 260 | #define WRITE 0x100 | ||
| 261 | |||
| 262 | #define DMA_FDC 0x080 | ||
| 263 | #define DMA_ACSI 0x000 | ||
| 264 | |||
| 265 | #define DMA_DISABLE 0x040 | ||
| 266 | |||
| 267 | #define SEC_COUNT 0x010 | ||
| 268 | #define DMA_WINDOW 0x000 | ||
| 269 | |||
| 270 | #define REG_ACSI 0x008 | ||
| 271 | #define REG_FDC 0x000 | ||
| 272 | |||
| 273 | #define A1 0x002 | ||
| 274 | |||
| 275 | /* Timeout constants */ | ||
| 276 | |||
| 277 | #define TIMEOUTCMD HZ/2 /* ca. 500ms */ | ||
| 278 | #define TIMEOUTDMA HZ /* ca. 1s */ | ||
| 279 | #define COMMAND_DELAY 500 /* ca. 0.5ms */ | ||
| 280 | |||
| 281 | unsigned rw; | ||
| 282 | int lance_target = -1; | ||
| 283 | int if_up = 0; | ||
| 284 | |||
| 285 | /* The following routines access the ethernet board connected to the | ||
| 286 | * ACSI port via the st_dma chip. | ||
| 287 | */ | ||
| 288 | |||
| 289 | /* The following lowlevel routines work on physical addresses only and assume | ||
| 290 | * that eventually needed buffers are | ||
| 291 | * - completely located in ST RAM | ||
| 292 | * - are contigous in the physical address space | ||
| 293 | */ | ||
| 294 | |||
| 295 | /* Setup the DMA counter */ | ||
| 296 | |||
| 297 | static void | ||
| 298 | setup_dma (void *address, unsigned rw_flag, int num_blocks) | ||
| 299 | { | ||
| 300 | WRITEMODE((unsigned) rw_flag | DMA_FDC | SEC_COUNT | REG_ACSI | | ||
| 301 | A1); | ||
| 302 | WRITEMODE((unsigned)(rw_flag ^ WRITE) | DMA_FDC | SEC_COUNT | REG_ACSI | | ||
| 303 | A1); | ||
| 304 | WRITEMODE((unsigned) rw_flag | DMA_FDC | SEC_COUNT | REG_ACSI | | ||
| 305 | A1); | ||
| 306 | DMALOW = (unsigned char)((unsigned long)address & 0xFF); | ||
| 307 | DMAMID = (unsigned char)(((unsigned long)address >> 8) & 0xFF); | ||
| 308 | DMAHIGH = (unsigned char)(((unsigned long)address >> 16) & 0xFF); | ||
| 309 | WRITEBOTH((unsigned)num_blocks & 0xFF, | ||
| 310 | rw_flag | DMA_FDC | DMA_WINDOW | REG_ACSI | A1); | ||
| 311 | rw = rw_flag; | ||
| 312 | } | ||
| 313 | |||
| 314 | /* Send the first byte of an command block */ | ||
| 315 | |||
| 316 | static int | ||
| 317 | send_first (int target, unsigned char byte) | ||
| 318 | { | ||
| 319 | rw = READ; | ||
| 320 | acsi_delay_end(COMMAND_DELAY); | ||
| 321 | /* | ||
| 322 | * wake up ACSI | ||
| 323 | */ | ||
| 324 | WRITEMODE(DMA_FDC | DMA_WINDOW | REG_ACSI); | ||
| 325 | /* | ||
| 326 | * write command byte | ||
| 327 | */ | ||
| 328 | WRITEBOTH((target << 5) | (byte & 0x1F), DMA_FDC | | ||
| 329 | DMA_WINDOW | REG_ACSI | A1); | ||
| 330 | return (!acsi_wait_for_IRQ(TIMEOUTCMD)); | ||
| 331 | } | ||
| 332 | |||
| 333 | /* Send the rest of an command block */ | ||
| 334 | |||
| 335 | static int | ||
| 336 | send_1_5 (int lun, unsigned char *command, int dma) | ||
| 337 | { | ||
| 338 | int i, j; | ||
| 339 | |||
| 340 | for (i=0; i<5; i++) { | ||
| 341 | WRITEBOTH((!i ? (((lun & 0x7) << 5) | (command[i] & 0x1F)) | ||
| 342 | : command[i]), | ||
| 343 | rw | REG_ACSI | DMA_WINDOW | | ||
| 344 | ((i < 4) ? DMA_FDC | ||
| 345 | : (dma ? DMA_ACSI | ||
| 346 | : DMA_FDC)) | A1); | ||
| 347 | if (i < 4 && (j = !acsi_wait_for_IRQ(TIMEOUTCMD))) | ||
| 348 | return (j); | ||
| 349 | } | ||
| 350 | return (0); | ||
| 351 | } | ||
| 352 | |||
| 353 | /* Read a status byte */ | ||
| 354 | |||
| 355 | static int | ||
| 356 | get_status (void) | ||
| 357 | { | ||
| 358 | WRITEMODE(DMA_FDC | DMA_WINDOW | REG_ACSI | A1); | ||
| 359 | acsi_delay_start(); | ||
| 360 | return ((int)(DACCESS & 0xFF)); | ||
| 361 | } | ||
| 362 | |||
| 363 | /* Calculate the number of received bytes */ | ||
| 364 | |||
| 365 | static int | ||
| 366 | calc_received (void *start_address) | ||
| 367 | { | ||
| 368 | return (int)( | ||
| 369 | (((unsigned long)DMAHIGH << 16) | ((unsigned)DMAMID << 8) | DMALOW) | ||
| 370 | - (unsigned long)start_address); | ||
| 371 | } | ||
| 372 | |||
| 373 | /* The following midlevel routines still work on physical addresses ... */ | ||
| 374 | |||
| 375 | /* start() starts the PAM's DMA adaptor */ | ||
| 376 | |||
| 377 | static void | ||
| 378 | start (int target) | ||
| 379 | { | ||
| 380 | send_first(target, START); | ||
| 381 | } | ||
| 382 | |||
| 383 | /* stop() stops the PAM's DMA adaptor and returns a value of zero in case of success */ | ||
| 384 | |||
| 385 | static int | ||
| 386 | stop (int target) | ||
| 387 | { | ||
| 388 | int ret = -1; | ||
| 389 | unsigned char cmd_buffer[5]; | ||
| 390 | |||
| 391 | if (send_first(target, STOP)) | ||
| 392 | goto bad; | ||
| 393 | cmd_buffer[0] = cmd_buffer[1] = cmd_buffer[2] = | ||
| 394 | cmd_buffer[3] = cmd_buffer[4] = 0; | ||
| 395 | if (send_1_5(7, cmd_buffer, 0) || | ||
| 396 | !acsi_wait_for_IRQ(TIMEOUTDMA) || | ||
| 397 | get_status()) | ||
| 398 | goto bad; | ||
| 399 | ret = 0; | ||
| 400 | bad: | ||
| 401 | return (ret); | ||
| 402 | } | ||
| 403 | |||
| 404 | /* testpkt() returns the number of received packets waiting in the queue */ | ||
| 405 | |||
| 406 | static int | ||
| 407 | testpkt(int target) | ||
| 408 | { | ||
| 409 | int ret = -1; | ||
| 410 | |||
| 411 | if (send_first(target, NUMPKTS)) | ||
| 412 | goto bad; | ||
| 413 | ret = get_status(); | ||
| 414 | bad: | ||
| 415 | return (ret); | ||
| 416 | } | ||
| 417 | |||
| 418 | /* inquiry() returns 0 when PAM's DMA found, -1 when timeout, -2 otherwise */ | ||
| 419 | /* Please note: The buffer is for internal use only but must be defined! */ | ||
| 420 | |||
| 421 | static int | ||
| 422 | inquiry (int target, unsigned char *buffer) | ||
| 423 | { | ||
| 424 | int ret = -1; | ||
| 425 | unsigned char *vbuffer = phys_to_virt((unsigned long)buffer); | ||
| 426 | unsigned char cmd_buffer[5]; | ||
| 427 | |||
| 428 | if (send_first(target, INQUIRY)) | ||
| 429 | goto bad; | ||
| 430 | setup_dma(buffer, READ, 1); | ||
| 431 | vbuffer[8] = vbuffer[27] = 0; /* Avoid confusion with previous read data */ | ||
| 432 | cmd_buffer[0] = cmd_buffer[1] = cmd_buffer[2] = cmd_buffer[4] = 0; | ||
| 433 | cmd_buffer[3] = 48; | ||
| 434 | if (send_1_5(5, cmd_buffer, 1) || | ||
| 435 | !acsi_wait_for_IRQ(TIMEOUTDMA) || | ||
| 436 | get_status() || | ||
| 437 | (calc_received(buffer) < 32)) | ||
| 438 | goto bad; | ||
| 439 | dma_cache_maintenance((unsigned long)(buffer+8), 20, 0); | ||
| 440 | if (memcmp(inquire8, vbuffer+8, 20)) | ||
| 441 | goto bad; | ||
| 442 | ret = 0; | ||
| 443 | bad: | ||
| 444 | if (!!NET_DEBUG) { | ||
| 445 | vbuffer[8+20]=0; | ||
| 446 | printk("inquiry of target %d: %s\n", target, vbuffer+8); | ||
| 447 | } | ||
| 448 | return (ret); | ||
| 449 | } | ||
| 450 | |||
| 451 | /* | ||
| 452 | * read_hw_addr() reads the sector containing the hwaddr and returns | ||
| 453 | * a pointer to it (virtual address!) or 0 in case of an error | ||
| 454 | */ | ||
| 455 | |||
| 456 | static HADDR | ||
| 457 | *read_hw_addr(int target, unsigned char *buffer) | ||
| 458 | { | ||
| 459 | HADDR *ret = 0; | ||
| 460 | unsigned char cmd_buffer[5]; | ||
| 461 | |||
| 462 | if (send_first(target, READSECTOR)) | ||
| 463 | goto bad; | ||
| 464 | setup_dma(buffer, READ, 1); | ||
| 465 | cmd_buffer[0] = cmd_buffer[1] = cmd_buffer[2] = cmd_buffer[4] = 0; | ||
| 466 | cmd_buffer[3] = 1; | ||
| 467 | if (send_1_5(5, cmd_buffer, 1) || | ||
| 468 | !acsi_wait_for_IRQ(TIMEOUTDMA) || | ||
| 469 | get_status()) | ||
| 470 | goto bad; | ||
| 471 | ret = phys_to_virt((unsigned long)&(((DMAHWADDR *)buffer)->hwaddr)); | ||
| 472 | dma_cache_maintenance((unsigned long)buffer, 512, 0); | ||
| 473 | bad: | ||
| 474 | return (ret); | ||
| 475 | } | ||
| 476 | |||
| 477 | static irqreturn_t | ||
| 478 | pamsnet_intr(int irq, void *data) | ||
| 479 | { | ||
| 480 | return IRQ_HANDLED; | ||
| 481 | } | ||
| 482 | |||
| 483 | /* receivepkt() loads a packet to a given buffer and returns its length */ | ||
| 484 | |||
| 485 | static int | ||
| 486 | receivepkt (int target, unsigned char *buffer) | ||
| 487 | { | ||
| 488 | int ret = -1; | ||
| 489 | unsigned char cmd_buffer[5]; | ||
| 490 | |||
| 491 | if (send_first(target, READPKT)) | ||
| 492 | goto bad; | ||
| 493 | setup_dma(buffer, READ, 3); | ||
| 494 | cmd_buffer[0] = cmd_buffer[1] = cmd_buffer[2] = cmd_buffer[4] = 0; | ||
| 495 | cmd_buffer[3] = 3; | ||
| 496 | if (send_1_5(7, cmd_buffer, 1) || | ||
| 497 | !acsi_wait_for_IRQ(TIMEOUTDMA) || | ||
| 498 | get_status()) | ||
| 499 | goto bad; | ||
| 500 | ret = calc_received(buffer); | ||
| 501 | bad: | ||
| 502 | return (ret); | ||
| 503 | } | ||
| 504 | |||
| 505 | /* sendpkt() sends a packet and returns a value of zero when the packet was sent | ||
| 506 | successfully */ | ||
| 507 | |||
| 508 | static int | ||
| 509 | sendpkt (int target, unsigned char *buffer, int length) | ||
| 510 | { | ||
| 511 | int ret = -1; | ||
| 512 | unsigned char cmd_buffer[5]; | ||
| 513 | |||
| 514 | if (send_first(target, WRITEPKT)) | ||
| 515 | goto bad; | ||
| 516 | setup_dma(buffer, WRITE, 3); | ||
| 517 | cmd_buffer[0] = cmd_buffer[1] = cmd_buffer[4] = 0; | ||
| 518 | cmd_buffer[2] = length >> 8; | ||
| 519 | cmd_buffer[3] = length & 0xFF; | ||
| 520 | if (send_1_5(7, cmd_buffer, 1) || | ||
| 521 | !acsi_wait_for_IRQ(TIMEOUTDMA) || | ||
| 522 | get_status()) | ||
| 523 | goto bad; | ||
| 524 | ret = 0; | ||
| 525 | bad: | ||
| 526 | return (ret); | ||
| 527 | } | ||
| 528 | |||
| 529 | /* The following higher level routines work on virtual addresses and convert them to | ||
| 530 | * physical addresses when passed to the lowlevel routines. It's up to the higher level | ||
| 531 | * routines to copy data from Alternate RAM to ST RAM if neccesary! | ||
| 532 | */ | ||
| 533 | |||
| 534 | /* Check for a network adaptor of this type, and return '0' if one exists. | ||
| 535 | */ | ||
| 536 | |||
| 537 | struct net_device * __init pamsnet_probe (int unit) | ||
| 538 | { | ||
| 539 | struct net_device *dev; | ||
| 540 | int i; | ||
| 541 | HADDR *hwaddr; | ||
| 542 | int err; | ||
| 543 | |||
| 544 | unsigned char station_addr[6]; | ||
| 545 | static unsigned version_printed; | ||
| 546 | /* avoid "Probing for..." printed 4 times - the driver is supporting only one adapter now! */ | ||
| 547 | static int no_more_found; | ||
| 548 | |||
| 549 | if (no_more_found) | ||
| 550 | return ERR_PTR(-ENODEV); | ||
| 551 | no_more_found = 1; | ||
| 552 | |||
| 553 | dev = alloc_etherdev(sizeof(struct net_local)); | ||
| 554 | if (!dev) | ||
| 555 | return ERR_PTR(-ENOMEM); | ||
| 556 | if (unit >= 0) { | ||
| 557 | sprintf(dev->name, "eth%d", unit); | ||
| 558 | netdev_boot_setup_check(dev); | ||
| 559 | } | ||
| 560 | SET_MODULE_OWNER(dev); | ||
| 561 | |||
| 562 | printk("Probing for PAM's Net/GK Adapter...\n"); | ||
| 563 | |||
| 564 | /* Allocate the DMA buffer here since we need it for probing! */ | ||
| 565 | |||
| 566 | nic_packet = (struct nic_pkt_s *)acsi_buffer; | ||
| 567 | phys_nic_packet = (unsigned char *)phys_acsi_buffer; | ||
| 568 | if (pamsnet_debug > 0) { | ||
| 569 | printk("nic_packet at 0x%p, phys at 0x%p\n", | ||
| 570 | nic_packet, phys_nic_packet ); | ||
| 571 | } | ||
| 572 | |||
| 573 | stdma_lock(pamsnet_intr, NULL); | ||
| 574 | DISABLE_IRQ(); | ||
| 575 | |||
| 576 | for (i=0; i<8; i++) { | ||
| 577 | /* Do two inquiries to cover cases with strange equipment on previous ID */ | ||
| 578 | /* blocking the ACSI bus (like the SLMC804 laser printer controller... */ | ||
| 579 | inquiry(i, phys_nic_packet); | ||
| 580 | if (!inquiry(i, phys_nic_packet)) { | ||
| 581 | lance_target = i; | ||
| 582 | break; | ||
| 583 | } | ||
| 584 | } | ||
| 585 | |||
| 586 | if (!!NET_DEBUG) | ||
| 587 | printk("ID: %d\n",i); | ||
| 588 | |||
| 589 | if (lance_target >= 0) { | ||
| 590 | if (!(hwaddr = read_hw_addr(lance_target, phys_nic_packet))) | ||
| 591 | lance_target = -1; | ||
| 592 | else | ||
| 593 | memcpy (station_addr, hwaddr, ETH_ALEN); | ||
| 594 | } | ||
| 595 | |||
| 596 | ENABLE_IRQ(); | ||
| 597 | stdma_release(); | ||
| 598 | |||
| 599 | if (lance_target < 0) { | ||
| 600 | printk("No PAM's Net/GK found.\n"); | ||
| 601 | free_netdev(dev); | ||
| 602 | return ERR_PTR(-ENODEV); | ||
| 603 | } | ||
| 604 | |||
| 605 | if (pamsnet_debug > 0 && version_printed++ == 0) | ||
| 606 | printk(version); | ||
| 607 | |||
| 608 | printk("%s: %s found on target %01d, eth-addr: %02x:%02x:%02x:%02x:%02x:%02x.\n", | ||
| 609 | dev->name, "PAM's Net/GK", lance_target, | ||
| 610 | station_addr[0], station_addr[1], station_addr[2], | ||
| 611 | station_addr[3], station_addr[4], station_addr[5]); | ||
| 612 | |||
| 613 | /* Initialize the device structure. */ | ||
| 614 | dev->open = pamsnet_open; | ||
| 615 | dev->stop = pamsnet_close; | ||
| 616 | dev->hard_start_xmit = pamsnet_send_packet; | ||
| 617 | dev->get_stats = net_get_stats; | ||
| 618 | |||
| 619 | /* Fill in the fields of the device structure with ethernet-generic | ||
| 620 | * values. This should be in a common file instead of per-driver. | ||
| 621 | */ | ||
| 622 | |||
| 623 | for (i = 0; i < ETH_ALEN; i++) { | ||
| 624 | #if 0 | ||
| 625 | dev->broadcast[i] = 0xff; | ||
| 626 | #endif | ||
| 627 | dev->dev_addr[i] = station_addr[i]; | ||
| 628 | } | ||
| 629 | err = register_netdev(dev); | ||
| 630 | if (!err) | ||
| 631 | return dev; | ||
| 632 | |||
| 633 | free_netdev(dev); | ||
| 634 | return ERR_PTR(err); | ||
| 635 | } | ||
| 636 | |||
| 637 | /* Open/initialize the board. This is called (in the current kernel) | ||
| 638 | sometime after booting when the 'ifconfig' program is run. | ||
| 639 | |||
| 640 | This routine should set everything up anew at each open, even | ||
| 641 | registers that "should" only need to be set once at boot, so that | ||
| 642 | there is non-reboot way to recover if something goes wrong. | ||
| 643 | */ | ||
| 644 | static int | ||
| 645 | pamsnet_open(struct net_device *dev) | ||
| 646 | { | ||
| 647 | struct net_local *lp = netdev_priv(dev); | ||
| 648 | |||
| 649 | if (pamsnet_debug > 0) | ||
| 650 | printk("pamsnet_open\n"); | ||
| 651 | stdma_lock(pamsnet_intr, NULL); | ||
| 652 | DISABLE_IRQ(); | ||
| 653 | |||
| 654 | /* Reset the hardware here. | ||
| 655 | */ | ||
| 656 | if (!if_up) | ||
| 657 | start(lance_target); | ||
| 658 | if_up = 1; | ||
| 659 | lp->open_time = 0; /*jiffies*/ | ||
| 660 | lp->poll_time = MAX_POLL_TIME; | ||
| 661 | |||
| 662 | dev->tbusy = 0; | ||
| 663 | dev->interrupt = 0; | ||
| 664 | dev->start = 1; | ||
| 665 | |||
| 666 | ENABLE_IRQ(); | ||
| 667 | stdma_release(); | ||
| 668 | pamsnet_timer.data = (long)dev; | ||
| 669 | pamsnet_timer.expires = jiffies + lp->poll_time; | ||
| 670 | add_timer(&pamsnet_timer); | ||
| 671 | return 0; | ||
| 672 | } | ||
| 673 | |||
| 674 | static int | ||
| 675 | pamsnet_send_packet(struct sk_buff *skb, struct net_device *dev) | ||
| 676 | { | ||
| 677 | struct net_local *lp = netdev_priv(dev); | ||
| 678 | unsigned long flags; | ||
| 679 | |||
| 680 | /* Block a timer-based transmit from overlapping. This could better be | ||
| 681 | * done with atomic_swap(1, dev->tbusy), but set_bit() works as well. | ||
| 682 | */ | ||
| 683 | local_irq_save(flags); | ||
| 684 | |||
| 685 | if (stdma_islocked()) { | ||
| 686 | local_irq_restore(flags); | ||
| 687 | lp->stats.tx_errors++; | ||
| 688 | } | ||
| 689 | else { | ||
| 690 | int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; | ||
| 691 | unsigned long buf = virt_to_phys(skb->data); | ||
| 692 | int stat; | ||
| 693 | |||
| 694 | stdma_lock(pamsnet_intr, NULL); | ||
| 695 | DISABLE_IRQ(); | ||
| 696 | |||
| 697 | local_irq_restore(flags); | ||
| 698 | if( !STRAM_ADDR(buf+length-1) ) { | ||
| 699 | skb_copy_from_linear_data(skb, nic_packet->buffer, | ||
| 700 | length); | ||
| 701 | buf = (unsigned long)phys_nic_packet; | ||
| 702 | } | ||
| 703 | |||
| 704 | dma_cache_maintenance(buf, length, 1); | ||
| 705 | |||
| 706 | stat = sendpkt(lance_target, (unsigned char *)buf, length); | ||
| 707 | ENABLE_IRQ(); | ||
| 708 | stdma_release(); | ||
| 709 | |||
| 710 | dev->trans_start = jiffies; | ||
| 711 | dev->tbusy = 0; | ||
| 712 | lp->stats.tx_packets++; | ||
| 713 | lp->stats.tx_bytes+=length; | ||
| 714 | } | ||
| 715 | dev_kfree_skb(skb); | ||
| 716 | |||
| 717 | return 0; | ||
| 718 | } | ||
| 719 | |||
| 720 | /* We have a good packet(s), get it/them out of the buffers. | ||
| 721 | */ | ||
| 722 | static void | ||
| 723 | pamsnet_poll_rx(struct net_device *dev) | ||
| 724 | { | ||
| 725 | struct net_local *lp = netdev_priv(dev); | ||
| 726 | int boguscount; | ||
| 727 | int pkt_len; | ||
| 728 | struct sk_buff *skb; | ||
| 729 | unsigned long flags; | ||
| 730 | |||
| 731 | local_irq_save(flags); | ||
| 732 | /* ++roman: Take care at locking the ST-DMA... This must be done with ints | ||
| 733 | * off, since otherwise an int could slip in between the question and the | ||
| 734 | * locking itself, and then we'd go to sleep... And locking itself is | ||
| 735 | * necessary to keep the floppy_change timer from working with ST-DMA | ||
| 736 | * registers. */ | ||
| 737 | if (stdma_islocked()) { | ||
| 738 | local_irq_restore(flags); | ||
| 739 | return; | ||
| 740 | } | ||
| 741 | stdma_lock(pamsnet_intr, NULL); | ||
| 742 | DISABLE_IRQ(); | ||
| 743 | local_irq_restore(flags); | ||
| 744 | |||
| 745 | boguscount = testpkt(lance_target); | ||
| 746 | if( lp->poll_time < MAX_POLL_TIME ) lp->poll_time++; | ||
| 747 | |||
| 748 | while(boguscount--) { | ||
| 749 | pkt_len = receivepkt(lance_target, phys_nic_packet); | ||
| 750 | |||
| 751 | if( pkt_len < 60 ) break; | ||
| 752 | |||
| 753 | /* Good packet... */ | ||
| 754 | |||
| 755 | dma_cache_maintenance((unsigned long)phys_nic_packet, pkt_len, 0); | ||
| 756 | |||
| 757 | lp->poll_time = pamsnet_min_poll_time; /* fast poll */ | ||
| 758 | if( pkt_len >= 60 && pkt_len <= 2048 ) { | ||
| 759 | if (pkt_len > 1514) | ||
| 760 | pkt_len = 1514; | ||
| 761 | |||
| 762 | /* Malloc up new buffer. | ||
| 763 | */ | ||
| 764 | skb = alloc_skb(pkt_len, GFP_ATOMIC); | ||
| 765 | if (skb == NULL) { | ||
| 766 | printk("%s: Memory squeeze, dropping packet.\n", | ||
| 767 | dev->name); | ||
| 768 | lp->stats.rx_dropped++; | ||
| 769 | break; | ||
| 770 | } | ||
| 771 | skb->len = pkt_len; | ||
| 772 | skb->dev = dev; | ||
| 773 | |||
| 774 | /* 'skb->data' points to the start of sk_buff data area. | ||
| 775 | */ | ||
| 776 | skb_copy_to_linear_data(skb, nic_packet->buffer, | ||
| 777 | pkt_len); | ||
| 778 | netif_rx(skb); | ||
| 779 | dev->last_rx = jiffies; | ||
| 780 | lp->stats.rx_packets++; | ||
| 781 | lp->stats.rx_bytes+=pkt_len; | ||
| 782 | } | ||
| 783 | } | ||
| 784 | |||
| 785 | /* If any worth-while packets have been received, dev_rint() | ||
| 786 | has done a mark_bh(INET_BH) for us and will work on them | ||
| 787 | when we get to the bottom-half routine. | ||
| 788 | */ | ||
| 789 | |||
| 790 | ENABLE_IRQ(); | ||
| 791 | stdma_release(); | ||
| 792 | return; | ||
| 793 | } | ||
| 794 | |||
| 795 | /* pamsnet_tick: called by pamsnet_timer. Reads packets from the adapter, | ||
| 796 | * passes them to the higher layers and restarts the timer. | ||
| 797 | */ | ||
| 798 | static void | ||
| 799 | pamsnet_tick(unsigned long data) | ||
| 800 | { | ||
| 801 | struct net_device *dev = (struct net_device *)data; | ||
| 802 | struct net_local *lp = netdev_priv(dev); | ||
| 803 | |||
| 804 | if( pamsnet_debug > 0 && (lp->open_time++ & 7) == 8 ) | ||
| 805 | printk("pamsnet_tick: %ld\n", lp->open_time); | ||
| 806 | |||
| 807 | pamsnet_poll_rx(dev); | ||
| 808 | |||
| 809 | pamsnet_timer.expires = jiffies + lp->poll_time; | ||
| 810 | add_timer(&pamsnet_timer); | ||
| 811 | } | ||
| 812 | |||
| 813 | /* The inverse routine to pamsnet_open(). | ||
| 814 | */ | ||
| 815 | static int | ||
| 816 | pamsnet_close(struct net_device *dev) | ||
| 817 | { | ||
| 818 | struct net_local *lp = netdev_priv(dev); | ||
| 819 | |||
| 820 | if (pamsnet_debug > 0) | ||
| 821 | printk("pamsnet_close, open_time=%ld\n", lp->open_time); | ||
| 822 | del_timer(&pamsnet_timer); | ||
| 823 | stdma_lock(pamsnet_intr, NULL); | ||
| 824 | DISABLE_IRQ(); | ||
| 825 | |||
| 826 | if (if_up) | ||
| 827 | stop(lance_target); | ||
| 828 | if_up = 0; | ||
| 829 | |||
| 830 | lp->open_time = 0; | ||
| 831 | |||
| 832 | dev->tbusy = 1; | ||
| 833 | dev->start = 0; | ||
| 834 | |||
| 835 | ENABLE_IRQ(); | ||
| 836 | stdma_release(); | ||
| 837 | return 0; | ||
| 838 | } | ||
| 839 | |||
| 840 | /* Get the current statistics. | ||
| 841 | This may be called with the card open or closed. | ||
| 842 | */ | ||
| 843 | static struct net_device_stats *net_get_stats(struct net_device *dev) | ||
| 844 | { | ||
| 845 | struct net_local *lp = netdev_priv(dev); | ||
| 846 | return &lp->stats; | ||
| 847 | } | ||
| 848 | |||
| 849 | |||
| 850 | #ifdef MODULE | ||
| 851 | |||
| 852 | static struct net_device *pam_dev; | ||
| 853 | |||
| 854 | int init_module(void) | ||
| 855 | { | ||
| 856 | pam_dev = pamsnet_probe(-1); | ||
| 857 | if (IS_ERR(pam_dev)) | ||
| 858 | return PTR_ERR(pam_dev); | ||
| 859 | return 0; | ||
| 860 | } | ||
| 861 | |||
| 862 | void cleanup_module(void) | ||
| 863 | { | ||
| 864 | unregister_netdev(pam_dev); | ||
| 865 | free_netdev(pam_dev); | ||
| 866 | } | ||
| 867 | |||
| 868 | #endif /* MODULE */ | ||
| 869 | |||
| 870 | /* Local variables: | ||
| 871 | * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include | ||
| 872 | -b m68k-linuxaout -Wall -Wstrict-prototypes -O2 | ||
| 873 | -fomit-frame-pointer -pipe -DMODULE -I../../net/inet -c atari_pamsnet.c" | ||
| 874 | * version-control: t | ||
| 875 | * kept-new-versions: 5 | ||
| 876 | * tab-width: 8 | ||
| 877 | * End: | ||
| 878 | */ | ||
