⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fixed.c

📁 linux 内核源代码
💻 C
字号:
/* * drivers/net/phy/fixed.c * * Driver for fixed PHYs, when transceiver is able to operate in one fixed mode. * * Author: Vitaly Bordug * * Copyright (c) 2006 MontaVista Software, Inc. * * This program is free software; you can redistribute  it and/or modify it * under  the terms of  the GNU General  Public License as published by the * Free Software Foundation;  either version 2 of the  License, or (at your * option) any later version. * */#include <linux/kernel.h>#include <linux/string.h>#include <linux/errno.h>#include <linux/unistd.h>#include <linux/slab.h>#include <linux/interrupt.h>#include <linux/init.h>#include <linux/delay.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <linux/spinlock.h>#include <linux/mm.h>#include <linux/module.h>#include <linux/mii.h>#include <linux/ethtool.h>#include <linux/phy.h>#include <linux/phy_fixed.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/uaccess.h>/* we need to track the allocated pointers in order to free them on exit */static struct fixed_info *fixed_phy_ptrs[CONFIG_FIXED_MII_AMNT*MAX_PHY_AMNT];/*----------------------------------------------------------------------------- *  If something weird is required to be done with link/speed, * network driver is able to assign a function to implement this. * May be useful for PHY's that need to be software-driven. *-----------------------------------------------------------------------------*/int fixed_mdio_set_link_update(struct phy_device *phydev,			       int (*link_update) (struct net_device *,						   struct fixed_phy_status *)){	struct fixed_info *fixed;	if (link_update == NULL)		return -EINVAL;	if (phydev) {		if (phydev->bus) {			fixed = phydev->bus->priv;			fixed->link_update = link_update;			return 0;		}	}	return -EINVAL;}EXPORT_SYMBOL(fixed_mdio_set_link_update);struct fixed_info *fixed_mdio_get_phydev (int phydev_ind){	if (phydev_ind >= MAX_PHY_AMNT)		return NULL;	return fixed_phy_ptrs[phydev_ind];}EXPORT_SYMBOL(fixed_mdio_get_phydev);/*----------------------------------------------------------------------------- *  This is used for updating internal mii regs from the status *-----------------------------------------------------------------------------*/#if defined(CONFIG_FIXED_MII_100_FDX) || defined(CONFIG_FIXED_MII_10_FDX) || defined(CONFIG_FIXED_MII_1000_FDX)static int fixed_mdio_update_regs(struct fixed_info *fixed){	u16 *regs = fixed->regs;	u16 bmsr = 0;	u16 bmcr = 0;	if (!regs) {		printk(KERN_ERR "%s: regs not set up", __FUNCTION__);		return -EINVAL;	}	if (fixed->phy_status.link)		bmsr |= BMSR_LSTATUS;	if (fixed->phy_status.duplex) {		bmcr |= BMCR_FULLDPLX;		switch (fixed->phy_status.speed) {		case 100:			bmsr |= BMSR_100FULL;			bmcr |= BMCR_SPEED100;			break;		case 10:			bmsr |= BMSR_10FULL;			break;		}	} else {		switch (fixed->phy_status.speed) {		case 100:			bmsr |= BMSR_100HALF;			bmcr |= BMCR_SPEED100;			break;		case 10:			bmsr |= BMSR_100HALF;			break;		}	}	regs[MII_BMCR] = bmcr;	regs[MII_BMSR] = bmsr | 0x800;	/*we are always capable of 10 hdx */	return 0;}static int fixed_mii_read(struct mii_bus *bus, int phy_id, int location){	struct fixed_info *fixed = bus->priv;	/* if user has registered link update callback, use it */	if (fixed->phydev)		if (fixed->phydev->attached_dev) {			if (fixed->link_update) {				fixed->link_update(fixed->phydev->attached_dev,						   &fixed->phy_status);				fixed_mdio_update_regs(fixed);			}		}	if ((unsigned int)location >= fixed->regs_num)		return -1;	return fixed->regs[location];}static int fixed_mii_write(struct mii_bus *bus, int phy_id, int location,			   u16 val){	/* do nothing for now */	return 0;}static int fixed_mii_reset(struct mii_bus *bus){	/*nothing here - no way/need to reset it */	return 0;}#endifstatic int fixed_config_aneg(struct phy_device *phydev){	/* :TODO:03/13/2006 09:45:37 PM::	   The full autoneg funcionality can be emulated,	   but no need to have anything here for now	 */	return 0;}/*----------------------------------------------------------------------------- * the manual bind will do the magic - with phy_id_mask == 0 * match will never return true... *-----------------------------------------------------------------------------*/static struct phy_driver fixed_mdio_driver = {	.name = "Fixed PHY",#ifdef CONFIG_FIXED_MII_1000_FDX	.features = PHY_GBIT_FEATURES,#else	.features = PHY_BASIC_FEATURES,#endif	.config_aneg = fixed_config_aneg,	.read_status = genphy_read_status,	.driver = { .owner = THIS_MODULE, },};static void fixed_mdio_release(struct device *dev){	struct phy_device *phydev = container_of(dev, struct phy_device, dev);	struct mii_bus *bus = phydev->bus;	struct fixed_info *fixed = bus->priv;	kfree(phydev);	kfree(bus->dev);	kfree(bus);	kfree(fixed->regs);	kfree(fixed);}/*----------------------------------------------------------------------------- *  This func is used to create all the necessary stuff, bind * the fixed phy driver and register all it on the mdio_bus_type. * speed is either 10 or 100 or 1000, duplex is boolean. * number is used to create multiple fixed PHYs, so that several devices can * utilize them simultaneously. * * The device on mdio bus will look like [bus_id]:[phy_id], * bus_id = number * phy_id = speed+duplex. *-----------------------------------------------------------------------------*/#if defined(CONFIG_FIXED_MII_100_FDX) || defined(CONFIG_FIXED_MII_10_FDX) || defined(CONFIG_FIXED_MII_1000_FDX)struct fixed_info *fixed_mdio_register_device(	int bus_id, int speed, int duplex, u8 phy_id){	struct mii_bus *new_bus;	struct fixed_info *fixed;	struct phy_device *phydev;	int err;	struct device *dev = kzalloc(sizeof(struct device), GFP_KERNEL);	if (dev == NULL)		goto err_dev_alloc;	new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL);	if (new_bus == NULL)		goto err_bus_alloc;	fixed = kzalloc(sizeof(struct fixed_info), GFP_KERNEL);	if (fixed == NULL)		goto err_fixed_alloc;	fixed->regs = kzalloc(MII_REGS_NUM * sizeof(int), GFP_KERNEL);	if (NULL == fixed->regs)		goto err_fixed_regs_alloc;	fixed->regs_num = MII_REGS_NUM;	fixed->phy_status.speed = speed;	fixed->phy_status.duplex = duplex;	fixed->phy_status.link = 1;	new_bus->name = "Fixed MII Bus";	new_bus->read = &fixed_mii_read;	new_bus->write = &fixed_mii_write;	new_bus->reset = &fixed_mii_reset;	/*set up workspace */	fixed_mdio_update_regs(fixed);	new_bus->priv = fixed;	new_bus->dev = dev;	dev_set_drvdata(dev, new_bus);	/* create phy_device and register it on the mdio bus */	phydev = phy_device_create(new_bus, 0, 0);	if (phydev == NULL)		goto err_phy_dev_create;	/*	 * Put the phydev pointer into the fixed pack so that bus read/write	 * code could be able to access for instance attached netdev. Well it	 * doesn't have to do so, only in case of utilizing user-specified	 * link-update...	 */	fixed->phydev = phydev;	phydev->speed = speed;	phydev->duplex = duplex;	phydev->irq = PHY_IGNORE_INTERRUPT;	phydev->dev.bus = &mdio_bus_type;	snprintf(phydev->dev.bus_id, BUS_ID_SIZE,		 PHY_ID_FMT, bus_id, phy_id);	phydev->bus = new_bus;	phydev->dev.driver = &fixed_mdio_driver.driver;	phydev->dev.release = fixed_mdio_release;	err = phydev->dev.driver->probe(&phydev->dev);	if (err < 0) {		printk(KERN_ERR "Phy %s: problems with fixed driver\n",		       phydev->dev.bus_id);		goto err_out;	}	err = device_register(&phydev->dev);	if (err) {		printk(KERN_ERR "Phy %s failed to register\n",		       phydev->dev.bus_id);		goto err_out;	}	//phydev->state = PHY_RUNNING; /* make phy go up quick, but in 10Mbit/HDX	return fixed;err_out:	kfree(phydev);err_phy_dev_create:	kfree(fixed->regs);err_fixed_regs_alloc:	kfree(fixed);err_fixed_alloc:	kfree(new_bus);err_bus_alloc:	kfree(dev);err_dev_alloc:	return NULL;}#endifMODULE_DESCRIPTION("Fixed PHY device & driver for PAL");MODULE_AUTHOR("Vitaly Bordug");MODULE_LICENSE("GPL");static int __init fixed_init(void){	int cnt = 0;	int i;/* register on the bus... Not expected to be matched * with anything there... * */	phy_driver_register(&fixed_mdio_driver);/* We will create several mdio devices here, and will bound the upper * driver to them. * * Then the external software can lookup the phy bus by searching * for 0:101, to be connected to the virtual 100M Fdx phy. * * In case several virtual PHYs required, the bus_id will be in form * [num]:[duplex]+[speed], which make it able even to define * driver-specific link control callback, if for instance PHY is * completely SW-driven. */	for (i=1; i <= CONFIG_FIXED_MII_AMNT; i++) {#ifdef CONFIG_FIXED_MII_1000_FDX		fixed_phy_ptrs[cnt++] = fixed_mdio_register_device(0, 1000, 1, i);#endif#ifdef CONFIG_FIXED_MII_100_FDX		fixed_phy_ptrs[cnt++] = fixed_mdio_register_device(1, 100, 1, i);#endif#ifdef CONFIG_FIXED_MII_10_FDX		fixed_phy_ptrs[cnt++] = fixed_mdio_register_device(2, 10, 1, i);#endif	}	return 0;}static void __exit fixed_exit(void){	int i;	phy_driver_unregister(&fixed_mdio_driver);	for (i=0; i < MAX_PHY_AMNT; i++)		if ( fixed_phy_ptrs[i] )			device_unregister(&fixed_phy_ptrs[i]->phydev->dev);}module_init(fixed_init);module_exit(fixed_exit);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -