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 * _at_owner: The module owner of this structure * _at_enable_slot: Called when the user wants to enable a specific pci slot * _at_disable_slot: Called when the user wants to disable a specific pci slot * _at_set_attention_status: Called to set the specific slot's attention LED to * the specified value * _at_hardware_test: Called to run a specified hardware test on the specified * slot. * _at_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. * _at_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. * _at_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. * _at_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. * _at_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. * _at_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. * _at_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 * _at_power: if power is enabled or not (1/0) * _at_attention_status: if the attention light is enabled or not (1/0) * _at_latch_status: if the latch (if any) is open or closed (1/0) * _at_adapter_present: if there is a pci board present in the slot or not (1/0) * _at_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 * _at_name: the name of the slot being registered. This string must * be unique amoung slots registered on this system. * _at_ops: pointer to the &struct hotplug_slot_ops to be used for this slot * _at_info: pointer to the &struct hotplug_slot_info for the inital values for * this slot. * _at_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 * _at_ptr: the &struct list_head pointer. * _at_type: the type of the struct this is embedded in. * _at_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 * _at_pos: the &struct list_head to use as a loop counter. * _at_n: another &struct list_head to use as temporary storage * _at_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>Received on Mon May 08 2006 - 00:11:50 UTC
This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:38:55 UTC