[install] Update driver version to match package version
[sanbootconf.git] / installer / setupdi.c
1 /*
2  * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <windows.h>
23 #include <setupapi.h>
24 #include <cfgmgr32.h>
25 #include <objbase.h>
26 #include <newdev.h>
27 #include "setupdi.h"
28
29 #define eprintf(...) fprintf ( stderr, __VA_ARGS__ )
30 #define array_size(x) ( sizeof ( (x) ) / sizeof ( (x)[0] ) )
31
32 /*****************************************************************************
33  *
34  * Generic routines for installing non-PnP drivers
35  *
36  *****************************************************************************
37  */
38
39 /**
40  * Count device nodes
41  *
42  * @v inf_path          Path to .INF file
43  * @v hw_id             Hardware ID
44  * @v count             Number of device nodes
45  * @ret rc              Return status code
46  */
47 static int count_device_nodes ( LPWSTR inf_path, LPWSTR hw_id, DWORD *count ) {
48         GUID class_guid;
49         WCHAR class_name[MAX_CLASS_NAME_LEN];
50         HDEVINFO dev_info_list;
51         DWORD dev_index;
52         SP_DEVINFO_DATA dev_info;
53         WCHAR hw_ids[256];
54         DWORD hw_ids_len;
55         DWORD rc;
56
57         /* Initialise count */
58         *count = 0;
59
60         /* Get class GUID and name */
61         if ( ! SetupDiGetINFClassW ( inf_path, &class_guid, class_name,
62                                      array_size ( class_name ), NULL ) ) {
63                 rc = GetLastError();
64                 eprintf ( "Could not fetch class GUID from %S: %x\n",
65                           inf_path, rc );
66                 goto err_setupdigetinfclass;
67         }
68
69         /* Get device list */
70         dev_info_list = SetupDiGetClassDevsW ( &class_guid, NULL, NULL, 0 );
71         if ( dev_info_list == INVALID_HANDLE_VALUE ) {
72                 rc = GetLastError();
73                 eprintf ( "Could not get device list: %x\n", rc );
74                 goto err_setupdigetclassdevs;
75         }
76
77         /* Enumerate devices */
78         for ( dev_index = 0 ; ; dev_index++ ) {
79                 dev_info.cbSize = sizeof ( dev_info );
80                 if ( ! SetupDiEnumDeviceInfo ( dev_info_list, dev_index,
81                                                &dev_info ) ) {
82                         rc = GetLastError();
83                         if ( rc == ERROR_NO_MORE_ITEMS )
84                                 break;
85                         eprintf ( "Could not enumerate devices: %x\n", rc );
86                         goto err_setupdienumdeviceinfo;
87                 }
88
89                 /* Fetch hardare IDs */
90                 if ( ! SetupDiGetDeviceRegistryPropertyW ( dev_info_list,
91                                                            &dev_info,
92                                                            SPDRP_HARDWAREID,
93                                                            NULL,
94                                                            ( (PBYTE) hw_ids ),
95                                                            sizeof ( hw_ids ),
96                                                            &hw_ids_len ) ){
97                         rc = GetLastError();
98                         eprintf ( "Could not get hardware ID: %x\n", rc );
99                         goto err_setupdigetdeviceregistryproperty;
100                 }
101
102                 /* Compare hardware IDs */
103                 if ( _wcsicmp ( hw_id, hw_ids ) == 0 ) {
104                         /* Increment count of matching devices */
105                         (*count)++;
106                 }
107         }
108
109         /* Success */
110         rc = 0;
111
112  err_setupdigetdeviceregistryproperty:
113  err_setupdienumdeviceinfo:
114         SetupDiDestroyDeviceInfoList ( dev_info_list );
115  err_setupdigetclassdevs:
116  err_setupdigetinfclass:
117         return rc;
118 }
119
120 /**
121  * Install a device node
122  *
123  * @v inf_path          Path to .INF file
124  * @v hw_id             Hardware ID
125  * @ret rc              Return status code
126  */
127 static int install_device_node ( LPWSTR inf_path, LPWSTR hw_id ) {
128         GUID class_guid;
129         WCHAR class_name[MAX_CLASS_NAME_LEN];
130         HDEVINFO dev_info_list;
131         SP_DEVINFO_DATA dev_info;
132         WCHAR dev_instance[256];
133         WCHAR hw_ids[256];
134         DWORD hw_ids_len;
135         DWORD rc;
136
137         printf ( "Installing device node for hardware ID \"%S\"\n", hw_id );
138
139         /* Get class GUID and name */
140         if ( ! SetupDiGetINFClassW ( inf_path, &class_guid, class_name,
141                                      array_size ( class_name ), NULL ) ) {
142                 rc = GetLastError();
143                 eprintf ( "Could not fetch class GUID from %S: %x\n",
144                           inf_path, rc );
145                 goto err_setupdigetinfclass;
146         }
147
148         /* Create empty device information list */
149         dev_info_list = SetupDiCreateDeviceInfoList ( &class_guid, 0 );
150         if ( dev_info_list == INVALID_HANDLE_VALUE ) {
151                 rc = GetLastError();
152                 eprintf ( "Could not create device info list: %x\n", rc );
153                 goto err_setupdicreatedeviceinfolist;
154         }
155
156         /* Create device information element */
157         dev_info.cbSize = sizeof ( dev_info );
158         if ( ! SetupDiCreateDeviceInfoW ( dev_info_list, class_name,
159                                           &class_guid, NULL, 0,
160                                           DICD_GENERATE_ID, &dev_info ) ) {
161                 rc = GetLastError();
162                 eprintf ( "Could not create device info: %x\n", rc );
163                 goto err_setupdicreatedeviceinfo;
164         }
165
166         /* Fetch device instance ID */
167         if ( ! SetupDiGetDeviceInstanceIdW ( dev_info_list, &dev_info,
168                                              dev_instance,
169                                              array_size ( dev_instance ),
170                                              NULL ) ) {
171                 rc = GetLastError();
172                 eprintf ( "Could not get device instance ID: %x\n", rc );
173                 goto err_setupdigetdeviceinstanceid;
174         }
175         printf ( "Device instance ID is \"%S\"\n", dev_instance );
176
177         /* Add the hardware ID */
178         hw_ids_len = _snwprintf ( hw_ids, array_size ( hw_ids ),
179                                   L"%s%c", hw_id, 0 );
180         if ( ! SetupDiSetDeviceRegistryPropertyW ( dev_info_list, &dev_info,
181                                                    SPDRP_HARDWAREID,
182                                                    ( ( LPBYTE ) hw_ids ),
183                                                    ( ( hw_ids_len + 1 ) *
184                                                      sizeof ( hw_ids[0] ) ) )){
185                 rc = GetLastError();
186                 eprintf ( "Could not set hardware ID: %x\n", rc );
187                 goto err_setupdisetdeviceregistryproperty;
188         }
189
190         /* Install the device node */
191         if ( ! SetupDiCallClassInstaller ( DIF_REGISTERDEVICE, dev_info_list,
192                                            &dev_info ) ) {
193                 rc = GetLastError();
194                 eprintf ( "Could not install device node: %x\n", rc );
195                 goto err_setupdicallclassinstaller;
196         }
197
198         /* Success */
199         rc = 0;
200
201  err_setupdicallclassinstaller:
202  err_setupdisetdeviceregistryproperty:
203  err_setupdigetdeviceinstanceid:
204  err_setupdicreatedeviceinfo:
205         SetupDiDestroyDeviceInfoList ( dev_info_list );
206  err_setupdicreatedeviceinfolist:
207  err_setupdigetinfclass:
208         return rc;
209 }
210
211 /**
212  * Update driver
213  *
214  * @v inf_path          Path to .INF file
215  * @v hw_id             Hardware ID
216  * @ret rc              Return status code
217  */
218 static int update_driver ( LPWSTR inf_path, LPWSTR hw_id ) {
219         BOOL reboot_required;
220         int rc;
221
222         printf ( "Updating driver for hardware ID \"%S\"\n", hw_id );
223
224         /* Update driver */
225         if ( ! UpdateDriverForPlugAndPlayDevicesW ( NULL, hw_id, inf_path,
226                                                     0, &reboot_required ) ) {
227                 rc = GetLastError();
228                 eprintf ( "Could not update driver: %x\n", rc );
229                 goto err_updatedriverforplugandplaydevices;
230         }
231
232         /* Success */
233         rc = 0;
234
235  err_updatedriverforplugandplaydevices:
236         return rc;
237 }
238
239 /**
240  * Install (or update) driver
241  *
242  * @v inf_path          Path to .INF file
243  * @v hw_id             Hardware ID
244  * @ret rc              Return status code
245  */
246 int install_or_update_driver ( LPWSTR inf_path, LPWSTR hw_id ) {
247         DWORD existing_devices;
248         int rc;
249
250         /* See if device node exists */
251         if ( ( rc = count_device_nodes ( inf_path, hw_id,
252                                          &existing_devices ) ) != 0 )
253                 return rc;
254
255         /* Install device node (if necessary) */
256         if ( ( existing_devices == 0 ) &&
257              ( ( rc = install_device_node ( inf_path, hw_id ) ) != 0 ) )
258                 return rc;
259              
260         /* Update driver */
261         if ( ( rc = update_driver ( inf_path, hw_id ) ) != 0 )
262                 return rc;
263
264         return 0;
265 }