~mefrio-g/+junk/indicator-session-pantheon-shutdown

« back to all changes in this revision

Viewing changes to src/udev-mgr.c

  • Committer: cody at elementaryos
  • Date: 2012-12-10 00:13:38 UTC
  • Revision ID: cody@elementaryos.org-20121210001338-379sxx4jo6r003d6
Initial import, version 0.3.96-0ubuntu1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
Copyright 2011 Canonical Ltd.
 
3
 
 
4
Authors:
 
5
    Conor Curran <conor.curran@canonical.com>
 
6
 
 
7
This program is free software: you can redistribute it and/or modify it 
 
8
under the terms of the GNU General Public License version 3, as published 
 
9
by the Free Software Foundation.
 
10
 
 
11
This program is distributed in the hope that it will be useful, but 
 
12
WITHOUT ANY WARRANTY; without even the implied warranties of 
 
13
MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR 
 
14
PURPOSE.  See the GNU General Public License for more details.
 
15
 
 
16
You should have received a copy of the GNU General Public License along 
 
17
with this program.  If not, see <http://www.gnu.org/licenses/>.
 
18
*/
 
19
 
 
20
#include <gudev/gudev.h>
 
21
 
 
22
#include <glib/gi18n.h>
 
23
 
 
24
#include "udev-mgr.h"
 
25
#include "sane-rules.h"
 
26
 
 
27
static void udevice_mgr_device_list_iterator (gpointer data,
 
28
                                              gpointer userdata);
 
29
static void udev_mgr_uevent_cb  (GUdevClient *client,
 
30
                                 gchar       *action,
 
31
                                 GUdevDevice *device,
 
32
                                 gpointer     user_data);   
 
33
static void udev_mgr_update_menuitems (UdevMgr* self);
 
34
static void udev_mgr_check_if_usb_device_is_supported (UdevMgr* self, 
 
35
                                                        GUdevDevice *device,
 
36
                                                        UdevMgrDeviceAction action);                                                                                                                                               
 
37
static void udev_mgr_handle_webcam (UdevMgr* self,
 
38
                                    GUdevDevice* device,
 
39
                                    UdevMgrDeviceAction action);                                                      
 
40
static void udev_mgr_handle_scsi_device (UdevMgr* self,
 
41
                                         GUdevDevice* device,
 
42
                                         UdevMgrDeviceAction action);
 
43
 
 
44
static void udev_mgr_cleanup_lists(gpointer data, gpointer self);
 
45
static void udev_mgr_cleanup_entries(gpointer data, gpointer self);
 
46
 
 
47
 
 
48
static void debug_device (UdevMgr* self,
 
49
                          GUdevDevice* device,
 
50
                          UdevMgrDeviceAction action);
 
51
                          
 
52
static gchar* format_device_name (UdevMgr* self,
 
53
                                  const gchar* brand,
 
54
                                  const gchar* generic,
 
55
                                  const gchar* branded) G_GNUC_WARN_UNUSED_RESULT;
 
56
struct _UdevMgr
 
57
{
 
58
        GObject parent_instance;
 
59
  DbusmenuMenuitem* scanner_item;
 
60
  DbusmenuMenuitem* webcam_item;  
 
61
  GUdevClient* client;  
 
62
  GHashTable* supported_usb_scanners;
 
63
  GHashTable* supported_scsi_scanners;
 
64
  GHashTable* scanners_present;
 
65
  GHashTable* webcams_present;
 
66
};
 
67
 
 
68
const char *subsystems[3] = {"usb", "scsi", "video4linux"};
 
69
const gchar* usb_subsystem = "usb";
 
70
const gchar* scsi_subsystem = "scsi";
 
71
const gchar* video4linux_subsystem = "video4linux";
 
72
 
 
73
 
 
74
G_DEFINE_TYPE (UdevMgr, udev_mgr, G_TYPE_OBJECT);
 
75
 
 
76
static void
 
77
udev_mgr_init (UdevMgr* self)
 
78
{
 
79
  self->client = NULL;
 
80
  self->supported_usb_scanners = NULL;
 
81
  self->scanners_present = NULL;
 
82
  self->webcams_present = NULL;
 
83
  self->client = g_udev_client_new (subsystems);  
 
84
  self->supported_usb_scanners = g_hash_table_new_full (g_str_hash,
 
85
                                                        g_str_equal,
 
86
                                                        g_free,
 
87
                                                        (GDestroyNotify)udev_mgr_cleanup_lists);
 
88
  self->supported_scsi_scanners = g_hash_table_new_full (g_str_hash,
 
89
                                                         g_str_equal,
 
90
                                                         g_free,
 
91
                                                         (GDestroyNotify)udev_mgr_cleanup_lists);
 
92
  self->scanners_present = g_hash_table_new_full (g_str_hash,
 
93
                                                  g_str_equal,
 
94
                                                  g_free,
 
95
                                                  g_free);
 
96
  self->webcams_present = g_hash_table_new_full (g_str_hash,
 
97
                                                 g_str_equal,
 
98
                                                 g_free,
 
99
                                                 g_free);
 
100
  
 
101
  // load into memory all supported scanners ...
 
102
  populate_usb_scanners (self->supported_usb_scanners);
 
103
  populate_scsi_scanners (self->supported_scsi_scanners);
 
104
  g_signal_connect (G_OBJECT (self->client),
 
105
                   "uevent",
 
106
                    G_CALLBACK (udev_mgr_uevent_cb),
 
107
                    self);
 
108
}
 
109
 
 
110
static void
 
111
udev_mgr_cleanup_lists(gpointer data, gpointer self)
 
112
{
 
113
  GList* scanners = (GList*)data;
 
114
  g_list_foreach (scanners, udev_mgr_cleanup_entries, NULL);  
 
115
  g_list_free(scanners);
 
116
}
 
117
 
 
118
static void
 
119
udev_mgr_cleanup_entries(gpointer data, gpointer self)
 
120
{
 
121
  gchar* entry = (gchar*)data;
 
122
  g_free(entry);
 
123
}
 
124
 
 
125
static void
 
126
udev_mgr_finalize (GObject *object)
 
127
{
 
128
  UdevMgr* self = UDEV_MGR (object);
 
129
  g_hash_table_destroy (self->supported_scsi_scanners);  
 
130
  g_hash_table_destroy (self->supported_usb_scanners);  
 
131
  g_hash_table_destroy (self->scanners_present);  
 
132
  g_hash_table_destroy (self->webcams_present);  
 
133
        G_OBJECT_CLASS (udev_mgr_parent_class)->finalize (object);
 
134
}
 
135
 
 
136
static void
 
137
udev_mgr_class_init (UdevMgrClass *klass)
 
138
{
 
139
        GObjectClass* object_class = G_OBJECT_CLASS (klass);
 
140
        object_class->finalize = udev_mgr_finalize;
 
141
}
 
142
 
 
143
static void
 
144
udevice_mgr_device_list_iterator (gpointer data, gpointer userdata)
 
145
{
 
146
  g_return_if_fail (G_UDEV_IS_DEVICE (data));
 
147
  g_return_if_fail (UDEV_IS_MGR (userdata));
 
148
  
 
149
  UdevMgr* self = UDEV_MGR (userdata);
 
150
  
 
151
  GUdevDevice* device = G_UDEV_DEVICE (data);
 
152
 
 
153
  const gchar* subsystem = NULL; 
 
154
  subsystem = g_udev_device_get_subsystem (device);
 
155
 
 
156
  if (g_strcmp0 (subsystem, "usb") == 0){
 
157
    udev_mgr_check_if_usb_device_is_supported (self, device, ADD);
 
158
  }
 
159
  else if (g_strcmp0 (subsystem, "video4linux") == 0){
 
160
    udev_mgr_handle_webcam (self, device, ADD);    
 
161
  }
 
162
  else if (g_strcmp0 (subsystem, "scsi") == 0){
 
163
    udev_mgr_handle_scsi_device (self, device, ADD);    
 
164
  }
 
165
  
 
166
  g_object_unref (device);
 
167
}
 
168
 
 
169
 
 
170
static void udev_mgr_update_menuitems (UdevMgr* self)
 
171
{
 
172
  dbusmenu_menuitem_property_set_bool (self->scanner_item,
 
173
                                       DBUSMENU_MENUITEM_PROP_VISIBLE,
 
174
                                       g_hash_table_size (self->scanners_present) > 0);
 
175
 
 
176
  dbusmenu_menuitem_property_set_bool (self->webcam_item,
 
177
                                       DBUSMENU_MENUITEM_PROP_VISIBLE,
 
178
                                       g_hash_table_size (self->webcams_present) > 0);
 
179
 
 
180
}
 
181
 
 
182
static void udev_mgr_uevent_cb (GUdevClient *client,
 
183
                                gchar       *action,
 
184
                                GUdevDevice *device,
 
185
                                gpointer     user_data)   
 
186
{
 
187
  g_return_if_fail (UDEV_IS_MGR (user_data));
 
188
  UdevMgr* self = UDEV_MGR (user_data);
 
189
  g_return_if_fail (device != NULL);
 
190
  
 
191
  g_debug ("just received a UEVENT with an action :  %s", action);
 
192
 
 
193
  UdevMgrDeviceAction udev_mgr_action = ADD;
 
194
 
 
195
  if (g_strcmp0 (action, "remove") == 0){
 
196
    udev_mgr_action = REMOVE;
 
197
  }
 
198
  
 
199
  const gchar* subsystem = NULL;  
 
200
  subsystem = g_udev_device_get_subsystem (device);
 
201
 
 
202
  if (g_strcmp0 (subsystem, "usb") == 0){
 
203
    udev_mgr_check_if_usb_device_is_supported (self,
 
204
                                               device,
 
205
                                               udev_mgr_action);
 
206
  }
 
207
  else if (g_strcmp0 (subsystem, "video4linux") == 0){
 
208
    udev_mgr_handle_webcam (self, device, udev_mgr_action);
 
209
  }
 
210
  else if (g_strcmp0 (subsystem, "scsi") == 0){
 
211
    udev_mgr_handle_scsi_device (self, device, udev_mgr_action);    
 
212
  }
 
213
}
 
214
 
 
215
 
 
216
static void
 
217
udev_mgr_handle_webcam (UdevMgr* self,
 
218
                        GUdevDevice* device,
 
219
                        UdevMgrDeviceAction action)
 
220
{
 
221
  if (FALSE)
 
222
    debug_device (self, device, action);    
 
223
  
 
224
  const gchar* vendor;
 
225
  const gchar* product;
 
226
  
 
227
  vendor = g_udev_device_get_property (device, "ID_VENDOR_ID");
 
228
  product = g_udev_device_get_property (device, "ID_MODEL_ID");
 
229
 
 
230
  if (!vendor || !product) {
 
231
    return;
 
232
  }  
 
233
 
 
234
  if (action == REMOVE){
 
235
    if (g_hash_table_lookup (self->webcams_present, product) == NULL){
 
236
      g_warning ("Got a remove event on a webcam device but we don't have that device in our webcam cache");
 
237
      return;                     
 
238
    }
 
239
    g_hash_table_remove (self->webcams_present,
 
240
                         product);
 
241
    dbusmenu_menuitem_property_set (self->webcam_item,
 
242
                                    DBUSMENU_MENUITEM_PROP_LABEL,
 
243
                                    _("Webcam"));                            
 
244
  }
 
245
  else {
 
246
    if (g_hash_table_lookup (self->webcams_present, product) != NULL){
 
247
      g_warning ("Got an ADD event on a webcam device but we already have that device in our webcam cache");
 
248
      return;                     
 
249
    }
 
250
    
 
251
    const gchar* manufacturer = NULL;        
 
252
    manufacturer = g_udev_device_get_property (device, "ID_VENDOR");
 
253
    
 
254
    if (manufacturer != NULL){
 
255
          gchar * label = format_device_name(self, manufacturer, _("Webcam"), _("%s Webcam"));
 
256
      dbusmenu_menuitem_property_set (self->webcam_item,
 
257
                                      DBUSMENU_MENUITEM_PROP_LABEL,
 
258
                                      label);
 
259
          g_free(label);
 
260
    }
 
261
    
 
262
    g_hash_table_insert (self->webcams_present,
 
263
                         g_strdup (product),
 
264
                         g_strdup (vendor));                               
 
265
  }
 
266
  udev_mgr_update_menuitems (self);  
 
267
}                        
 
268
 
 
269
static void
 
270
debug_device (UdevMgr* self,
 
271
              GUdevDevice* device,
 
272
              UdevMgrDeviceAction action)
 
273
{
 
274
  const gchar* vendor;
 
275
  const gchar* product;
 
276
  const gchar* number;
 
277
  const gchar* name;
 
278
  const gchar* manufacturer;
 
279
  
 
280
        vendor = g_udev_device_get_property (device, "ID_VENDOR_ID");
 
281
        manufacturer = g_udev_device_get_property (device, "ID_VENDOR");
 
282
        product = g_udev_device_get_property (device, "ID_MODEL_ID");
 
283
  number = g_udev_device_get_number (device);
 
284
  name = g_udev_device_get_name (device);
 
285
  
 
286
  g_debug ("%s device vendor id %s , product id of %s , number of %s and name of %s",
 
287
           g_strdup(manufacturer),
 
288
           g_strdup(vendor),
 
289
           g_strdup(product),
 
290
           g_strdup(number),
 
291
           g_strdup(name));
 
292
         
 
293
  /*const gchar *const *list;
 
294
  const gchar *const *iter;  
 
295
  char propstr[500];
 
296
  guint32 namelen = 0, i;  
 
297
  
 
298
  list = g_udev_device_get_property_keys(device);
 
299
  
 
300
  for (iter = list; iter && *iter; iter++) {
 
301
    if (strlen(*iter) > namelen)
 
302
      namelen = strlen(*iter);
 
303
  }
 
304
  namelen++;
 
305
 
 
306
  for (iter = list; iter && *iter; iter++) {
 
307
    strcpy(propstr, *iter);
 
308
    strcat(propstr, ":");
 
309
    for (i = 0; i < namelen - strlen(*iter); i++)
 
310
           strcat(propstr, " ");
 
311
    strcat(propstr, g_udev_device_get_property(device, *iter));
 
312
    g_debug("%s", propstr);
 
313
  }*/ 
 
314
}
 
315
// TODO SCSI is not dynamic right ?
 
316
// i.e. just need to handle startup scan.
 
317
static void udev_mgr_handle_scsi_device (UdevMgr* self,
 
318
                                         GUdevDevice* device,
 
319
                                         UdevMgrDeviceAction action)
 
320
{
 
321
  const gchar* type = NULL;
 
322
        type = g_udev_device_get_property (device, "TYPE");
 
323
  
 
324
  if (!type) {
 
325
    return;
 
326
  }  
 
327
  
 
328
  // apparently anything thats type 6 and SCSI is a Scanner
 
329
  if (g_strcmp0 (type, "6") == 0 && action == ADD){
 
330
    
 
331
    const gchar* manufacturer = NULL;        
 
332
    manufacturer = g_udev_device_get_property (device, "ID_VENDOR");
 
333
    
 
334
    if (manufacturer != NULL){
 
335
            gchar * label = format_device_name(self, manufacturer, _("Scanner"), _("%s Scanner"));
 
336
      dbusmenu_menuitem_property_set (self->scanner_item,
 
337
                                      DBUSMENU_MENUITEM_PROP_LABEL,
 
338
                                      label);
 
339
            g_free(label);
 
340
    }
 
341
    
 
342
    gchar* random_scanner_name =        g_strdup_printf("%p--scanner", self);
 
343
    g_hash_table_insert (self->scanners_present,
 
344
                         random_scanner_name,
 
345
                         g_strdup("Scanner")); 
 
346
    udev_mgr_update_menuitems (self);    
 
347
    return;                         
 
348
  }
 
349
 
 
350
  // We only care about type 3 for the special cases below
 
351
  if (g_strcmp0 (type, "3") != 0){
 
352
    return;
 
353
  }
 
354
 
 
355
  const gchar* vendor = NULL;
 
356
        vendor = g_udev_device_get_property (device, "VENDOR");
 
357
  
 
358
  if (vendor == NULL)
 
359
    return;
 
360
 
 
361
  GList* vendor_list = NULL;
 
362
  vendor_list = g_hash_table_lookup (self->supported_scsi_scanners,
 
363
                                     (gpointer)vendor);
 
364
  if (vendor_list == NULL)
 
365
    return;
 
366
 
 
367
  const gchar* model_id = NULL;
 
368
        model_id = g_udev_device_get_property (device, "MODEL");
 
369
  
 
370
  if (model_id == NULL)
 
371
    return;
 
372
 
 
373
  GList* model_entry = NULL;
 
374
  model_entry = g_list_find_custom (vendor_list,
 
375
                                    model_id,
 
376
                                    (GCompareFunc)g_strcmp0);
 
377
    
 
378
  if (model_entry != NULL){
 
379
    if (action == REMOVE){
 
380
      if (g_hash_table_lookup (self->scanners_present, g_strdup(vendor)) == NULL){
 
381
        g_warning ("Got an REMOVE event on a scanner device but we dont have that device in our scanners cache");
 
382
      }
 
383
      else{
 
384
        g_hash_table_remove (self->scanners_present, vendor);
 
385
        dbusmenu_menuitem_property_set (self->scanner_item,
 
386
                                        DBUSMENU_MENUITEM_PROP_LABEL,
 
387
                                        _("Scanner"));
 
388
        
 
389
      }
 
390
    }
 
391
    else{      
 
392
      if (g_hash_table_lookup (self->scanners_present, g_strdup(vendor)) != NULL){
 
393
        g_warning ("Got an ADD event on a scanner device but we already have that device in our scanners cache");
 
394
      }
 
395
      else{
 
396
        const gchar* manufacturer = NULL;        
 
397
        manufacturer = g_udev_device_get_property (device, "ID_VENDOR");
 
398
        
 
399
        if (manufacturer != NULL){
 
400
          gchar * label = format_device_name(self, manufacturer, _("Scanner"), _("%s Scanner"));
 
401
          dbusmenu_menuitem_property_set (self->scanner_item,
 
402
                                          DBUSMENU_MENUITEM_PROP_LABEL,
 
403
                                          label);
 
404
          g_free(label);
 
405
        }
 
406
        g_hash_table_insert (self->scanners_present,
 
407
                             g_strdup(vendor),
 
408
                             g_strdup(model_id)); 
 
409
      }
 
410
    }
 
411
    udev_mgr_update_menuitems (self);
 
412
  }
 
413
}                                         
 
414
 
 
415
static void
 
416
udev_mgr_check_if_usb_device_is_supported (UdevMgr* self, 
 
417
                                           GUdevDevice *device,
 
418
                                           UdevMgrDeviceAction action)
 
419
{
 
420
  const gchar* vendor = NULL;
 
421
  //debug_device (self, device, action);    
 
422
  
 
423
        vendor = g_udev_device_get_property (device, "ID_VENDOR_ID");
 
424
  
 
425
  if (vendor == NULL)
 
426
    return;
 
427
 
 
428
  //g_debug ("vendor = %s", vendor);
 
429
  
 
430
  GList* vendor_list = NULL;
 
431
  vendor_list = g_hash_table_lookup (self->supported_usb_scanners,
 
432
                                     (gpointer)vendor);
 
433
  if (vendor_list == NULL)
 
434
    return;
 
435
 
 
436
  const gchar* model_id = NULL;
 
437
        model_id = g_udev_device_get_property (device, "ID_MODEL_ID");
 
438
  
 
439
  if (model_id == NULL)
 
440
    return;
 
441
  
 
442
  GList* model_entry = NULL;
 
443
  model_entry = g_list_find_custom(vendor_list, model_id, (GCompareFunc)g_strcmp0);
 
444
    
 
445
  if (model_entry != NULL){
 
446
    if (action == REMOVE){
 
447
      if (g_hash_table_lookup (self->scanners_present, g_strdup(vendor)) == NULL){
 
448
        g_warning ("Got an REMOVE event on a scanner device but we dont have that device in our scanners cache");
 
449
      }
 
450
      else{
 
451
        g_hash_table_remove (self->scanners_present, vendor);
 
452
        dbusmenu_menuitem_property_set (self->scanner_item, 
 
453
                                        DBUSMENU_MENUITEM_PROP_LABEL,
 
454
                                        _("Scanner"));        
 
455
      }
 
456
    }
 
457
    else{      
 
458
      if (g_hash_table_lookup (self->scanners_present, g_strdup(vendor)) != NULL){
 
459
        g_warning ("Got an ADD event on a scanner device but we already have that device in our scanners cache");
 
460
      }
 
461
      else{
 
462
        const gchar* manufacturer = NULL;
 
463
        
 
464
        manufacturer = g_udev_device_get_property (device, "ID_VENDOR");
 
465
        if (manufacturer != NULL){
 
466
          gchar * label = format_device_name(self, manufacturer, _("Scanner"), _("%s Scanner"));
 
467
          dbusmenu_menuitem_property_set (self->scanner_item, 
 
468
                                          DBUSMENU_MENUITEM_PROP_LABEL,
 
469
                                          label);
 
470
          g_free(label);
 
471
        }
 
472
                                        
 
473
        g_hash_table_insert (self->scanners_present,
 
474
                             g_strdup(vendor),
 
475
                             g_strdup(model_id)); 
 
476
      }
 
477
    }
 
478
    udev_mgr_update_menuitems (self);
 
479
  }
 
480
}
 
481
 
 
482
UdevMgr* udev_mgr_new (DbusmenuMenuitem* scanner, 
 
483
                       DbusmenuMenuitem* webcam)
 
484
{
 
485
  UdevMgr* mgr = g_object_new (UDEV_TYPE_MGR, NULL);
 
486
  mgr->scanner_item = scanner;
 
487
  mgr->webcam_item = webcam;
 
488
  
 
489
  // Check for USB devices
 
490
  GList* usb_devices_available = NULL;
 
491
  usb_devices_available  = g_udev_client_query_by_subsystem (mgr->client,
 
492
                                                             usb_subsystem);
 
493
  if (usb_devices_available != NULL){
 
494
    g_list_foreach (usb_devices_available,
 
495
                    udevice_mgr_device_list_iterator,
 
496
                    mgr);
 
497
                    
 
498
    g_list_free (usb_devices_available);
 
499
  }  
 
500
  // Check for webcams
 
501
  GList* video_devices_available  = NULL;
 
502
  video_devices_available  = g_udev_client_query_by_subsystem (mgr->client,
 
503
                                                               video4linux_subsystem);
 
504
  if (video_devices_available != NULL){
 
505
    g_list_foreach (video_devices_available,
 
506
                    udevice_mgr_device_list_iterator,
 
507
                    mgr);
 
508
    
 
509
    g_list_free (video_devices_available);
 
510
  }  
 
511
  // Check for SCSI devices
 
512
  GList* scsi_devices_available = NULL;
 
513
  scsi_devices_available  = g_udev_client_query_by_subsystem (mgr->client,
 
514
                                                              scsi_subsystem);
 
515
  if (scsi_devices_available != NULL){
 
516
    g_list_foreach (scsi_devices_available,
 
517
                    udevice_mgr_device_list_iterator,
 
518
                    mgr);                    
 
519
    g_list_free (scsi_devices_available);
 
520
  }
 
521
  return mgr;
 
522
}
 
523
 
 
524
static gchar* format_device_name (UdevMgr* self,
 
525
                                  const gchar* brand,
 
526
                                  const gchar* generic,
 
527
                                  const gchar* branded)
 
528
{
 
529
  // We don't want to accommodate long names
 
530
  if (strlen(brand) > 7)
 
531
    return g_strdup(generic);
 
532
 
 
533
  gint i = 0;
 
534
 
 
535
  // If it contains something other than an alphabetic entry ignore it.
 
536
  for(i = 0; i < sizeof(brand); i++){
 
537
    if ( !g_ascii_isalpha (brand[i]) )
 
538
      return g_strdup(generic);
 
539
  }
 
540
 
 
541
  gchar* lowered = g_ascii_strdown (brand, -1);
 
542
  lowered[0] = g_ascii_toupper (lowered[0]);
 
543
  gchar* label = g_strdup_printf(branded, lowered);
 
544
  g_free (lowered);  
 
545
  return label;
 
546
}