@@ -99,6 +99,52 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count)
9999}
100100static DRIVER_ATTR (new_id , S_IWUSR , NULL, store_new_id ) ;
101101
102+ /**
103+ * store_remove_id - remove a PCI device ID from this driver
104+ * @driver: target device driver
105+ * @buf: buffer for scanning device ID data
106+ * @count: input size
107+ *
108+ * Removes a dynamic pci device ID to this driver.
109+ */
110+ static ssize_t
111+ store_remove_id (struct device_driver * driver , const char * buf , size_t count )
112+ {
113+ struct pci_dynid * dynid , * n ;
114+ struct pci_driver * pdrv = to_pci_driver (driver );
115+ __u32 vendor , device , subvendor = PCI_ANY_ID ,
116+ subdevice = PCI_ANY_ID , class = 0 , class_mask = 0 ;
117+ int fields = 0 ;
118+ int retval = - ENODEV ;
119+
120+ fields = sscanf (buf , "%x %x %x %x %x %x" ,
121+ & vendor , & device , & subvendor , & subdevice ,
122+ & class , & class_mask );
123+ if (fields < 2 )
124+ return - EINVAL ;
125+
126+ spin_lock (& pdrv -> dynids .lock );
127+ list_for_each_entry_safe (dynid , n , & pdrv -> dynids .list , node ) {
128+ struct pci_device_id * id = & dynid -> id ;
129+ if ((id -> vendor == vendor ) &&
130+ (id -> device == device ) &&
131+ (subvendor == PCI_ANY_ID || id -> subvendor == subvendor ) &&
132+ (subdevice == PCI_ANY_ID || id -> subdevice == subdevice ) &&
133+ !((id -> class ^ class ) & class_mask )) {
134+ list_del (& dynid -> node );
135+ kfree (dynid );
136+ retval = 0 ;
137+ break ;
138+ }
139+ }
140+ spin_unlock (& pdrv -> dynids .lock );
141+
142+ if (retval )
143+ return retval ;
144+ return count ;
145+ }
146+ static DRIVER_ATTR (remove_id , S_IWUSR , NULL, store_remove_id ) ;
147+
102148static void
103149pci_free_dynids (struct pci_driver * drv )
104150{
@@ -125,13 +171,32 @@ static void pci_remove_newid_file(struct pci_driver *drv)
125171{
126172 driver_remove_file (& drv -> driver , & driver_attr_new_id );
127173}
174+
175+ static int
176+ pci_create_removeid_file (struct pci_driver * drv )
177+ {
178+ int error = 0 ;
179+ if (drv -> probe != NULL )
180+ error = driver_create_file (& drv -> driver ,& driver_attr_remove_id );
181+ return error ;
182+ }
183+
184+ static void pci_remove_removeid_file (struct pci_driver * drv )
185+ {
186+ driver_remove_file (& drv -> driver , & driver_attr_remove_id );
187+ }
128188#else /* !CONFIG_HOTPLUG */
129189static inline void pci_free_dynids (struct pci_driver * drv ) {}
130190static inline int pci_create_newid_file (struct pci_driver * drv )
131191{
132192 return 0 ;
133193}
134194static inline void pci_remove_newid_file (struct pci_driver * drv ) {}
195+ static inline int pci_create_removeid_file (struct pci_driver * drv )
196+ {
197+ return 0 ;
198+ }
199+ static inline void pci_remove_removeid_file (struct pci_driver * drv ) {}
135200#endif
136201
137202/**
@@ -852,13 +917,23 @@ int __pci_register_driver(struct pci_driver *drv, struct module *owner,
852917 /* register with core */
853918 error = driver_register (& drv -> driver );
854919 if (error )
855- return error ;
920+ goto out ;
856921
857922 error = pci_create_newid_file (drv );
858923 if (error )
859- driver_unregister ( & drv -> driver ) ;
924+ goto out_newid ;
860925
926+ error = pci_create_removeid_file (drv );
927+ if (error )
928+ goto out_removeid ;
929+ out :
861930 return error ;
931+
932+ out_removeid :
933+ pci_remove_newid_file (drv );
934+ out_newid :
935+ driver_unregister (& drv -> driver );
936+ goto out ;
862937}
863938
864939/**
@@ -874,6 +949,7 @@ int __pci_register_driver(struct pci_driver *drv, struct module *owner,
874949void
875950pci_unregister_driver (struct pci_driver * drv )
876951{
952+ pci_remove_removeid_file (drv );
877953 pci_remove_newid_file (drv );
878954 driver_unregister (& drv -> driver );
879955 pci_free_dynids (drv );
0 commit comments