fakedevice hotplug Demo with sourcecode
Wallace William
avalonwallace at gmail.com
Sat May 6 11:21:37 UTC 2006
hello ,everyone .
i have write a demo module to demostrate the hotplug of a pci
device under freeBSD 5.3 . when kldload the module ,the fakedevice will be
"plug "into the pci architechure,when kldunload ,the device will be removed.
pciconf -l ,and devinfo -v will be the tool to show this change : a new
device called wallace is added ,this device comes from the info in LINE97 of
the fakeBSC.c:
*dinfo=* ((struct pci_devinfo *) device_get_ivars(devlist[6]) );
maybe u need to change the '6' according to ur need .
there r 4 file in this package :pci_hotplug_core.c fakeBSD.c pci_hotplug.h
and the Makefile .
way to RUN:
1 unzip the package
2 make
3 kldload ./fakeBSD.ko
4 pciconf -l ,and devinfo -v to see the change
5 kldunload fakeBSD.ko
welcome for ur feedback,next i will do my best to write the driver for real
pci device hotplug, as what cardbus has done
////////////////pci_hotplug_core.c//////////////////////////////////
/////////////from PCIexample////////////////
#include <sys/param.h> /* defines used in kernel.h */
#include <sys/module.h>
#include <sys/systm.h>
#include <sys/errno.h>
#include <sys/kernel.h> /* types used in module initialization */
#include <sys/conf.h> /* cdevsw struct */
#include <sys/uio.h> /* uio struct */
#include <sys/malloc.h>
#include <sys/bus.h> /* structs, prototypes for pci bus stuff */
#include <machine/bus.h>
#include <sys/rman.h>
#include <machine/resource.h>
#include <dev/pci/pcivar.h> /* For get_pci macros! */
#include <dev/pci/pcireg.h>
////////////////////////////////////
#include<dev/drm/drm_linux_list.h>
#include "pci_hotplug.h"
//WB//
#define MY_NAME "pci_hotplug"
//simplified//WB//
#define dbg(fmt, arg...) do { if (debug) printf( fmt , ## arg); } while (0)
#define err(format, arg...) printf( format, MY_NAME , ## arg)
#define info(format, arg...) printf(format, MY_NAME , ## arg)
#define warn(format, arg...) printf(format , MY_NAME, ## arg)
/* local variables */
static int debug;
//////////////////////////////////////////////////////////////////
static LIST_HEAD(pci_hotplug_slot_list);
/* these strings match up with the values in pci_bus_speed */
static char *pci_bus_speed_strings[] = {
"33 MHz PCI", /* 0x00 */
"66 MHz PCI", /* 0x01 */
"66 MHz PCIX", /* 0x02 */
"100 MHz PCIX", /* 0x03 */
"133 MHz PCIX", /* 0x04 */
NULL, /* 0x05 */
NULL, /* 0x06 */
NULL, /* 0x07 */
NULL, /* 0x08 */
"66 MHz PCIX 266", /* 0x09 */
"100 MHz PCIX 266", /* 0x0a */
"133 MHz PCIX 266", /* 0x0b */
NULL, /* 0x0c */
NULL, /* 0x0d */
NULL, /* 0x0e */
NULL, /* 0x0f */
NULL, /* 0x10 */
"66 MHz PCIX 533", /* 0x11 */
"100 MHz PCIX 533", /* 0x12 */
"133 MHz PCIX 533", /* 0x13 */
"25 GBps PCI-E", /* 0x14 */
};
///////////////////fakeBSD.c
/////////////////////////////////////////////////
////////change of the header/////////////
/////////////from PCIexample////////////////
#include <sys/param.h> /* defines used in kernel.h */
#include <sys/module.h>
#include <sys/systm.h>
#include <sys/errno.h>
#include <sys/kernel.h> /* types used in module initialization */
#include <sys/conf.h> /* cdevsw struct */
#include <sys/uio.h> /* uio struct */
#include <sys/malloc.h>
#include <sys/bus.h> /* structs, prototypes for pci bus stuff */
//for TAILQ_FOREACH
//#include <sys/queue.h>
//
#include <sys/bus.h> //1129
#include <machine/bus.h>
#include <sys/rman.h>
#include <machine/resource.h>
#include <sys/pciio.h>//1129 sizeof
#include <dev/pci/pcivar.h> /* For get_pci macros! */
#include <dev/pci/pcireg.h>
#include <dev/pci/pci_private.h>//1129
////////////////////////////////////
#include<dev/drm/drm_linux_list.h> //for list_head
//#include "pci_hotplug.h" put the unrealated functions out
//#include "../pci.h"
//this is created on compiling.so leave it to makefile
//#include "pcib_if.h" //#include "pci_if.h"
/*
//COMMENT
//devinfo struct for devinfo
//addtodevice_list for pciconf
COPY the NIC device content to the wallace0 fake device
*/
#define MY_NAME "fakephp"
#define dbg(fmt, arg...) do { if (debug) printf( fmt , ## arg); } while (0)
#define err(format, arg...) printf( format, MY_NAME , ## arg)
#define info(format, arg...) printf(format, MY_NAME , ## arg)
#define DRIVER_AUTHOR "Wallace <avalonwallace at gmail.com>"
#define DRIVER_DESC "Fake PCI Hot Plug Controller Driver"
/*
* This function is called by the kld[un]load(2) system calls to
* determine what actions to take when a module is loaded or unloaded.
*/
/* vars */
static struct pci_devinfo *dinfo;
static device_t bus; //refer to pci bus
size_t dinfo_size;
static int
fake_loader(struct module *m, int what, void *arg)
{
int erro=0;
device_t *devlist;
int count=0; int numdevs;
devclass_t class1;
char * Dtarget="pci",Dname="wallace";
struct devlist *devlist_head;
devlist_head = &pci_devq;
switch (what) {
case MOD_LOAD: /* kldload */
printf("Module loaded.\n,with bootverbose=%i",bootverbose);
//find pci devclass and device
if ((class1 = devclass_find(Dtarget)) == NULL) {
printf("unable to get the class");
return ENXIO;
}
printf("\n//////////////my name is
%s////////////\n",devclass_get_name(class1));
// show the nameof the device,or store them into another TAILQ
printf("maxunit under class pci
is%i\n",devclass_get_maxunit(class1)); //WB does unit == count
if((bus = devclass_get_device(class1,count))!=NULL)//WB why not use the
loop over count?
{
printf("my device name is %s,my unit is %i, DESC: %s,with number:%i\n",
device_get_name(bus),device_get_unit(bus),device_get_desc(bus),pcib_get_bus(bus));
}
//else? return (NULL)
dinfo_size=sizeof(struct pci_devinfo);
dinfo=NULL; //initialized
dinfo= malloc(dinfo_size, M_DEVBUF, M_WAITOK | M_ZERO);
if (dinfo == NULL)
return (NULL);
if (device_get_children(bus, &devlist, &numdevs)==0)
//get ivar from de0,thus 6 of devlist ,hardcoded ,this need specific
platform characteristic , waiting for modification
*dinfo=* ((struct pci_devinfo *) device_get_ivars(devlist[6]) );
if ((dinfo->cfg.dev = device_add_child(bus, "wallace", -1)) == NULL)
{//change the name
device_printf(device_get_parent(bus), "couldn't attach pci bus\n");
}
device_sysctl_init(dinfo->cfg.dev);
strncpy ((dinfo->conf.pd_name),device_get_name(dinfo->cfg.dev
),8);//sizeof(device_get_name(dinfo->cfg.dev)));
STAILQ_INSERT_TAIL(devlist_head, dinfo, pci_links);
pci_numdevs++;
pci_generation++;
device_set_ivars(dinfo->cfg.dev, dinfo);
//show result
if (device_get_children(bus, &devlist, &numdevs)==0)
while (numdevs--){
printf("%i",numdevs);
device_print_prettyname(devlist[numdevs]);
if (device_get_devclass(devlist[numdevs])!=NULL )
printf("devclass=%s\n",devclass_get_name(device_get_devclass(devlist[numdevs])
));
}
break;
case MOD_UNLOAD:
printf("Module unloaded.\n");
//still dinfo point to the fake device i point to . it is static !!!:)
if (dinfo->cfg.dev != NULL) {
printf("dinfo->cfg.dev exist,deleting it.\n");
device_delete_child(device_get_parent(dinfo->cfg.dev), dinfo->cfg.dev);
printf("dinfo->cfg.dev exist,deleted .\n");
}else printf("dinfo->cfg.dev=NULL\n");
if (device_get_children(bus, &devlist, &numdevs)==0)
//demostrating the result
while (numdevs--){
printf("%i",numdevs);
device_print_prettyname(devlist[numdevs]);
if (device_get_devclass(devlist[numdevs])!=NULL )
printf("devclass=%s\n",devclass_get_name(device_get_devclass(devlist[numdevs])
));
}
printf("freeing(dinfo,M_DEVBUF)\n");
//1
device_sysctl_fini(dinfo->cfg.dev);//WB finish sysctl structure
devlist_head = &pci_devq;
STAILQ_REMOVE(devlist_head, dinfo, pci_devinfo, pci_links);
free(dinfo, M_DEVBUF);
/* increment the generation count */
//WB inrease or decreas?
pci_generation++;
/* we're losing one device */
pci_numdevs--;
dinfo=NULL;
//2
printf("freed dinfo,\n"); //WB ,n->,/n
//erro=0;
break;
default:
printf("Module default.\n");
erro = EINVAL;
break;
}
return(erro);
}
//DEV_MODULE(echo,echo_loader,NULL);
//#define DEV_MODULE(name, evh, arg)
static moduledata_t fake_mod = {
"fakeBSD",
fake_loader,
NULL
};
DECLARE_MODULE(fake, fake_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
//////////////////////pci_hotplug.h ///////////////////////
#include <sys/types.h> //WB//
#ifndef _PCI_HOTPLUG_H
#define _PCI_HOTPLUG_H
/* These values come from the PCI Hotplug Spec */
enum pci_bus_speed {
PCI_SPEED_33MHz = 0x00,
PCI_SPEED_66MHz = 0x01,
PCI_SPEED_66MHz_PCIX = 0x02,
PCI_SPEED_100MHz_PCIX = 0x03,
PCI_SPEED_133MHz_PCIX = 0x04,
PCI_SPEED_66MHz_PCIX_ECC = 0x05,
PCI_SPEED_100MHz_PCIX_ECC = 0x06,
PCI_SPEED_133MHz_PCIX_ECC = 0x07,
PCI_SPEED_66MHz_PCIX_266 = 0x09,
PCI_SPEED_100MHz_PCIX_266 = 0x0a,
PCI_SPEED_133MHz_PCIX_266 = 0x0b,
PCI_SPEED_66MHz_PCIX_533 = 0x11,
PCI_SPEED_100MHz_PCIX_533 = 0x12,
PCI_SPEED_133MHz_PCIX_533 = 0x13,
PCI_SPEED_UNKNOWN = 0xff,
};
/* These values come from the PCI Express Spec */
enum pcie_link_width {
PCIE_LNK_WIDTH_RESRV = 0x00,
PCIE_LNK_X1 = 0x01,
PCIE_LNK_X2 = 0x02,
PCIE_LNK_X4 = 0x04,
PCIE_LNK_X8 = 0x08,
PCIE_LNK_X12 = 0x0C,
PCIE_LNK_X16 = 0x10,
PCIE_LNK_X32 = 0x20,
PCIE_LNK_WIDTH_UNKNOWN = 0xFF,
};
enum pcie_link_speed {
PCIE_2PT5GB = 0x14,
PCIE_LNK_SPEED_UNKNOWN = 0xFF,
};
struct hotplug_slot;
/*//WB//
struct hotplug_slot_attribute {
struct attribute attr;
ssize_t (*show)(struct hotplug_slot *, char *);
ssize_t (*store)(struct hotplug_slot *, const char *, size_t);
};
//WB//
#define to_hotplug_attr(n) container_of(n, struct hotplug_slot_attribute,
attr);
* struct hotplug_slot_ops -the callbacks that the hotplug pci core can use
* @owner: The module owner of this structure
* @enable_slot: Called when the user wants to enable a specific pci slot
* @disable_slot: Called when the user wants to disable a specific pci slot
* @set_attention_status: Called to set the specific slot's attention LED to
* the specified value
* @hardware_test: Called to run a specified hardware test on the specified
* slot.
* @get_power_status: Called to get the current power status of a slot.
* If this field is NULL, the value passed in the struct hotplug_slot_info
* will be used when this value is requested by a user.
* @get_attention_status: Called to get the current attention status of a
slot.
* If this field is NULL, the value passed in the struct hotplug_slot_info
* will be used when this value is requested by a user.
* @get_latch_status: Called to get the current latch status of a slot.
* If this field is NULL, the value passed in the struct hotplug_slot_info
* will be used when this value is requested by a user.
* @get_adapter_status: Called to get see if an adapter is present in the
slot or not.
* If this field is NULL, the value passed in the struct hotplug_slot_info
* will be used when this value is requested by a user.
* @get_address: Called to get pci address of a slot.
* If this field is NULL, the value passed in the struct hotplug_slot_info
* will be used when this value is requested by a user.
* @get_max_bus_speed: Called to get the max bus speed for a slot.
* If this field is NULL, the value passed in the struct hotplug_slot_info
* will be used when this value is requested by a user.
* @get_cur_bus_speed: Called to get the current bus speed for a slot.
* If this field is NULL, the value passed in the struct hotplug_slot_info
* will be used when this value is requested by a user.
*
* The table of function pointers that is passed to the hotplug pci core by
a
* hotplug pci driver. These functions are called by the hotplug pci core
when
* the user wants to do something to a specific slot (query it for
information,
* set an LED, enable / disable power, etc.)
*/
//the freebsd WAY of function call back
typedef int enable_slot_t (struct hotplug_slot *slot);
typedef int disable_slot_t (struct hotplug_slot *slot);
typedef int set_attention_status_t (struct hotplug_slot *slot, u_int8_t
value);
typedef int hardware_test_t (struct hotplug_slot *slot, u_int32_t value);
typedef int get_power_status_t (struct hotplug_slot *slot, u_int8_t
*value);
typedef int get_attention_status_t (struct hotplug_slot *slot, u_int8_t
*value);
typedef int get_latch_status_t (struct hotplug_slot *slot, u_int8_t
*value);
typedef int get_adapter_status_t (struct hotplug_slot *slot, u_int8_t
*value);
typedef int get_address_t (struct hotplug_slot *slot, u_int32_t *value);
typedef int get_max_bus_speed_t (struct hotplug_slot *slot, enum
pci_bus_speed *value);
typedef int get_cur_bus_speed_t (struct hotplug_slot *slot, enum
pci_bus_speed *value);
struct hotplug_slot_ops {
//struct module *owner;
enable_slot_t * enable_slot;
disable_slot_t *disable_slot;
set_attention_status_t *set_attention_status;
hardware_test_t *hardware_test;
get_power_status_t *get_power_status;
get_attention_status_t *get_attention_status;
get_latch_status_t *get_latch_status;
get_adapter_status_t *get_adapter_status;
get_address_t *get_address;
get_max_bus_speed_t *get_max_bus_speed;
get_cur_bus_speed_t *get_cur_bus_speed;
};
/**
* struct hotplug_slot_info - used to notify the hotplug pci core of the
state of the slot
* @power: if power is enabled or not (1/0)
* @attention_status: if the attention light is enabled or not (1/0)
* @latch_status: if the latch (if any) is open or closed (1/0)
* @adapter_present: if there is a pci board present in the slot or not
(1/0)
* @address: (domain << 16 | bus << 8 | dev)
*
* Used to notify the hotplug pci core of the status of a specific slot.
*/
struct hotplug_slot_info {
u_int8_t power_status;
u_int8_t attention_status;
u_int8_t latch_status;
u_int8_t adapter_status;
u_int32_t address;
enum pci_bus_speed max_bus_speed;
enum pci_bus_speed cur_bus_speed;
};
/**
* struct hotplug_slot - used to register a physical slot with the hotplug
pci core
* @name: the name of the slot being registered. This string must
* be unique amoung slots registered on this system.
* @ops: pointer to the &struct hotplug_slot_ops to be used for this slot
* @info: pointer to the &struct hotplug_slot_info for the inital values for
* this slot.
* @private: used by the hotplug pci controller driver to store whatever it
* needs.
*/
typedef void release_t (struct hotplug_slot *slot);
struct hotplug_slot {
char *name;
int unit;
struct hotplug_slot_ops *ops;
struct hotplug_slot_info *info;
release_t * release;
void *private;
/* Variables below this are for use only by the hotplug pci core.
for example :pci_hotplug_slot_list
*/
struct list_head slot_list;
//WB//struct kobject kobj;
};
//WB//#define to_hotplug_slot(n) container_of(n, struct hotplug_slot, kobj)
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name)
/* list_entry - get the struct for this entry
* @ptr: the &struct list_head pointer.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_struct within the struct.
entry2 inorder to differ from the vm one
*/
#define list_entry2(ptr, type, member) \
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
/**
* list_for_each_safe - iterate over a list safe against removal of list
entry
* @pos: the &struct list_head to use as a loop counter.
* @n: another &struct list_head to use as temporary storage
* @head: the head for your list.
*/
#define list_for_each_safe2(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, n = pos->next)
extern int pci_hp_register (struct hotplug_slot *slot);
extern int pci_hp_deregister (struct hotplug_slot *slot);
extern int pci_hp_change_slot_info (struct hotplug_slot *slot,
struct hotplug_slot_info *info);
//WB//extern struct subsystem pci_hotplug_slots_subsys;
#endif
///////////////////Makefile/////////////////////////////
.PATH: /usr/src/devdrv/
KMOD= fakeBSD
SRCS= fakeBSD.c pci_hotplug_core.c
SRCS+= device_if.h bus_if.h pci_if.h
.include <bsd.kmod.mk>
More information about the freebsd-arch
mailing list