+#include <asm/types.h>
+#include <linux/list.h>
+#include <malloc.h>
+#include <net.h>
+
+/* local debug macro */
+#undef MII_DEBUG
+
+#undef debug
+#ifdef MII_DEBUG
+#define debug(fmt,args...) printf (fmt ,##args)
+#else
+#define debug(fmt,args...)
+#endif /* MII_DEBUG */
+
+struct mii_dev {
+ struct list_head link;
+ char *name;
+ int (*read) (char *devname, unsigned char addr,
+ unsigned char reg, unsigned short *value);
+ int (*write) (char *devname, unsigned char addr,
+ unsigned char reg, unsigned short value);
+};
+
+static struct list_head mii_devs;
+static struct mii_dev *current_mii;
+
+/*****************************************************************************
+ *
+ * Initialize global data. Need to be called before any other miiphy routine.
+ */
+void miiphy_init ()
+{
+ INIT_LIST_HEAD (&mii_devs);
+ current_mii = NULL;
+}
+
+/*****************************************************************************
+ *
+ * Register read and write MII access routines for the device <name>.
+ */
+void miiphy_register (char *name,
+ int (*read) (char *devname, unsigned char addr,
+ unsigned char reg, unsigned short *value),
+ int (*write) (char *devname, unsigned char addr,
+ unsigned char reg, unsigned short value))
+{
+ struct list_head *entry;
+ struct mii_dev *new_dev;
+ struct mii_dev *miidev;
+ unsigned int name_len;
+
+ /* check if we have unique name */
+ list_for_each (entry, &mii_devs) {
+ miidev = list_entry (entry, struct mii_dev, link);
+ if (strcmp (miidev->name, name) == 0) {
+ printf ("miiphy_register: non unique device name "
+ "'%s'\n", name);
+ return;
+ }
+ }
+
+ /* allocate memory */
+ name_len = strlen (name);
+ new_dev =
+ (struct mii_dev *)malloc (sizeof (struct mii_dev) + name_len + 1);
+
+ if (new_dev == NULL) {
+ printf ("miiphy_register: cannot allocate memory for '%s'\n",
+ name);
+ return;
+ }
+ memset (new_dev, 0, sizeof (struct mii_dev) + name_len);
+
+ /* initalize mii_dev struct fields */
+ INIT_LIST_HEAD (&new_dev->link);
+ new_dev->read = read;
+ new_dev->write = write;
+ new_dev->name = (char *)(new_dev + 1);
+ strncpy (new_dev->name, name, name_len);
+ new_dev->name[name_len] = '\0';
+
+ debug ("miiphy_register: added '%s', read=0x%08lx, write=0x%08lx\n",
+ new_dev->name, new_dev->read, new_dev->write);
+
+ /* add it to the list */
+ list_add_tail (&new_dev->link, &mii_devs);
+
+ if (!current_mii)
+ current_mii = new_dev;
+}
+
+int miiphy_set_current_dev (char *devname)
+{
+ struct list_head *entry;
+ struct mii_dev *dev;
+
+ list_for_each (entry, &mii_devs) {
+ dev = list_entry (entry, struct mii_dev, link);
+
+ if (strcmp (devname, dev->name) == 0) {
+ current_mii = dev;
+ return 0;
+ }
+ }
+
+ printf ("No such device: %s\n", devname);
+ return 1;
+}
+
+char *miiphy_get_current_dev ()
+{
+ if (current_mii)
+ return current_mii->name;
+
+ return NULL;
+}
+
+/*****************************************************************************
+ *
+ * Read to variable <value> from the PHY attached to device <devname>,
+ * use PHY address <addr> and register <reg>.
+ *
+ * Returns:
+ * 0 on success
+ */
+int miiphy_read (char *devname, unsigned char addr, unsigned char reg,
+ unsigned short *value)
+{
+ struct list_head *entry;
+ struct mii_dev *dev;
+ int found_dev = 0;
+ int read_ret = 0;
+
+ if (!devname) {
+ printf ("NULL device name!\n");
+ return 1;
+ }
+
+ list_for_each (entry, &mii_devs) {
+ dev = list_entry (entry, struct mii_dev, link);
+
+ if (strcmp (devname, dev->name) == 0) {
+ found_dev = 1;
+ read_ret = dev->read (devname, addr, reg, value);
+ break;
+ }
+ }
+
+ if (found_dev == 0)
+ printf ("No such device: %s\n", devname);
+
+ return ((found_dev) ? read_ret : 1);
+}
+
+/*****************************************************************************
+ *
+ * Write <value> to the PHY attached to device <devname>,
+ * use PHY address <addr> and register <reg>.
+ *
+ * Returns:
+ * 0 on success
+ */
+int miiphy_write (char *devname, unsigned char addr, unsigned char reg,
+ unsigned short value)
+{
+ struct list_head *entry;
+ struct mii_dev *dev;
+ int found_dev = 0;
+ int write_ret = 0;
+
+ if (!devname) {
+ printf ("NULL device name!\n");
+ return 1;
+ }
+
+ list_for_each (entry, &mii_devs) {
+ dev = list_entry (entry, struct mii_dev, link);
+
+ if (strcmp (devname, dev->name) == 0) {
+ found_dev = 1;
+ write_ret = dev->write (devname, addr, reg, value);
+ break;
+ }
+ }
+
+ if (found_dev == 0)
+ printf ("No such device: %s\n", devname);
+
+ return ((found_dev) ? write_ret : 1);
+}
+
+/*****************************************************************************
+ *
+ * Print out list of registered MII capable devices.
+ */
+void miiphy_listdev (void)
+{
+ struct list_head *entry;
+ struct mii_dev *dev;
+
+ puts ("MII devices: ");
+ list_for_each (entry, &mii_devs) {
+ dev = list_entry (entry, struct mii_dev, link);
+ printf ("'%s' ", dev->name);
+ }
+ puts ("\n");
+
+ if (current_mii)
+ printf ("Current device: '%s'\n", current_mii->name);
+}