Logo Search packages:      
Sourcecode: pcmcia-cs version File versions  Download package

dlport.c

/*======================================================================

    Utility to select the transceiver type for some D-Link (and also
    Linksys) ethernet adapters

    Compile with: cc -O2 -o dlport dlport.c
    
    Written by David Hinds, dhinds@hyper.stanford.edu
    This program is in the public domain.

    dlport.c 1.3 1997/04/30 05:10:58
    
======================================================================*/

#ifdef __KERNEL__

#include <linux/types.h>
#include <linux/delay.h>
#include <asm/io.h>

#else

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <asm/io.h>

#define udelay(n) usleep(n)

char *if_names[] = { "10base2", "10baseT" };

#endif

/*====================================================================*/

#define ioaddr_t  u_short
#define OP_ADRCNT 11
#define OP_READ         0x0600
#define OP_WRITE  0x0500
#define OP_EWEN         0x04c0
#define OP_ERASE  0x0700
#define OP_EWDS         0x0400

/* Mapping of EEPROM pins to register bits */
#define E_REFCLK  0x80
#define E_EEROM         0x40
#define E_RECALL  0x20
#define E_ASIC          0x10
#define E_CS            0x08
#define E_CLK           0x04
#define E_DIN           0x02
#define E_DOUT          0x01

#ifdef OLD

static void slow_12_8us(ioaddr_t port)
{
    u_char a, b, i;
    for (i = b = 0; (i < 16) && (b < 3); i++) {
      inb(port); inb(port);
      a = inb(port) & E_REFCLK;
      if ((b & 1) ? (a) : (!a)) b++;
    }
#ifndef __KERNEL__
    if (i == 16) printf("slow_12_8us() timed out!\n");
#endif
}

#else
#define slow_12_8us(p) udelay(10)
#endif

static void send_list(const u_char *v, ioaddr_t port)
{
    u_char n;
    for (n = *v++; n; n--, v++) {
      outb(*v | E_EEROM, port);
      slow_12_8us(port);
    }
}

static void set_send_state(ioaddr_t port)
{
    static const u_char cmd[] =
    { 3, 0x01, 0x09, 0x0d };
    send_list(cmd, port);
}

static void reset_send_state(ioaddr_t port)
{
    static const u_char cmd[] =
    { 8, 0x09, 0x01, 0x05, 0x01, 0x05, 0x01, 0x05, 0x01 };
    send_list(cmd, port);
}

void send_bits(u_int v, u_char bits, ioaddr_t port)
{
    static const u_char send_0[] = { 2, 0x09, 0x0d };
    static const u_char send_1[] = { 2, 0x0b, 0x0f };
    u_short i;
    for (i = 1<<(bits-1); i != 0; i >>= 1)
      send_list(((v & i) ? send_1 : send_0), port);
}

static void simple_cmd(u_int cmd, ioaddr_t port)
{
    set_send_state(port);
    send_bits(cmd, OP_ADRCNT, port);
    reset_send_state(port);
}

static u_short read_eeprom(ioaddr_t port, u_short addr)
{
    u_short i, v;
    set_send_state(port);
    send_bits(OP_READ|addr, OP_ADRCNT, port);
    for (i = v = 0; i < 16; i++) {
      send_bits(0, 1, port);
      v = (v<<1) | (inb(port) & E_DOUT);
    }
    reset_send_state(port);
    return v;
}

static void write_wait(ioaddr_t port)
{
    int i;
    set_send_state(port);
    /* The datasheet is unclear... but 15ms should cover it */
    for (i = 0; i < 150; i++) {
      udelay(100);
      if (inb(port) & E_DOUT) break;
    }
#ifndef __KERNEL__
    if (i == 150) printf("write_wait() timed out!\n");
#endif
    reset_send_state(port);
}

static void write_eeprom(ioaddr_t port, u_short addr, u_short val)
{
    simple_cmd(OP_EWEN, port);
    simple_cmd(OP_ERASE|addr, port);
    write_wait(port);
    set_send_state(port);
    send_bits(OP_WRITE|addr, OP_ADRCNT, port);
    send_bits(val, 16, port);
    reset_send_state(port);
    write_wait(port);
    simple_cmd(OP_EWDS, port);
}

static inline void reload(ioaddr_t port)
{
    int i;
    static const u_char cmd[] = { 4, 0x00, 0x00, 0x20, 0x00 };
    send_list(cmd, port);
    for (i = 0; i < 200; i++) {
      udelay(100);
      if (!(inb(port) & E_EEROM)) break;
    }
#ifndef __KERNEL__
    if (i == 200) printf("reload() timed out!\n");
#endif
}

void change_media(ioaddr_t base, u_char if_port)
{
    u_short w;
    w = read_eeprom(base+0x1e, 4);
    /* BNC is 0, UTP is 1 */
    if ((w & 2) != (if_port << 1)) {
      w = (w & (~2)) | (if_port << 1);
      write_eeprom(base+0x1e, 4, w);
      reload(base+0x1e);
    }
}

/*====================================================================*/

#ifndef __KERNEL__
static int sockets_open(void)
{
    int sock;
    if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) != -1)
      return sock;
    else if ((sock = socket(AF_IPX, SOCK_DGRAM, 0)) != -1)
      return sock;
    else if ((sock = socket(AF_AX25, SOCK_DGRAM, 0)) != -1)
      return sock;
    else
      return socket(AF_APPLETALK, SOCK_DGRAM, 0);
}

void usage(char *s)
{
    fprintf(stderr, "usage: %s interface [10baseT|10base2]\n", s);
    exit(1);
}

void main(int argc, char **argv)
{
    struct ifreq ifr;
    int i, skfd;

    if ((argc < 2) || (argc > 3))
      usage(argv[0]);
    skfd = sockets_open();
    if (skfd == -1) {
      perror("socket");
      exit(1);
    }
    strcpy(ifr.ifr_name, argv[1]);
    if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0)
      fprintf(stderr, "%s: unknown interface.\n", argv[1]);
    else {
      ioperm(0x80, 1, 1);
      ioperm(ifr.ifr_map.base_addr+0x1e, 1, 1);
      if (argc == 2) {
          i = read_eeprom(ifr.ifr_map.base_addr+0x1e, 4);
          printf("%s\t%s\n", argv[1], if_names[(i >> 1) & 1]);
      } else {
          for (i = 0; i < 2; i++)
            if (strcasecmp(argv[2], if_names[i]) == 0)
                break;
          if (i < 2) {
            change_media(ifr.ifr_map.base_addr, i);
          } else
            perror("ioctl");
      }
    }
    close(skfd);
    exit(0);
}
#endif

Generated by  Doxygen 1.6.0   Back to index