+#include <asm/types.h>
+#include <linux/list.h>
+#include <malloc.h>
+#include <net.h>
+
+/* local debug macro */
+#define MII_DEBUG
+#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);
+}
+