2
Copyright 2011 Canonical Ltd.
5
Conor Curran <conor.curran@canonical.com>
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.
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.
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/>.
20
#include <gudev/gudev.h>
22
#include <glib/gi18n.h>
25
#include "sane-rules.h"
27
static void udevice_mgr_device_list_iterator (gpointer data,
29
static void udev_mgr_uevent_cb (GUdevClient *client,
33
static void udev_mgr_update_menuitems (UdevMgr* self);
34
static void udev_mgr_check_if_usb_device_is_supported (UdevMgr* self,
36
UdevMgrDeviceAction action);
37
static void udev_mgr_handle_webcam (UdevMgr* self,
39
UdevMgrDeviceAction action);
40
static void udev_mgr_handle_scsi_device (UdevMgr* self,
42
UdevMgrDeviceAction action);
44
static void udev_mgr_cleanup_lists(gpointer data, gpointer self);
45
static void udev_mgr_cleanup_entries(gpointer data, gpointer self);
48
static void debug_device (UdevMgr* self,
50
UdevMgrDeviceAction action);
52
static gchar* format_device_name (UdevMgr* self,
55
const gchar* branded) G_GNUC_WARN_UNUSED_RESULT;
58
GObject parent_instance;
59
DbusmenuMenuitem* scanner_item;
60
DbusmenuMenuitem* webcam_item;
62
GHashTable* supported_usb_scanners;
63
GHashTable* supported_scsi_scanners;
64
GHashTable* scanners_present;
65
GHashTable* webcams_present;
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";
74
G_DEFINE_TYPE (UdevMgr, udev_mgr, G_TYPE_OBJECT);
77
udev_mgr_init (UdevMgr* self)
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,
87
(GDestroyNotify)udev_mgr_cleanup_lists);
88
self->supported_scsi_scanners = g_hash_table_new_full (g_str_hash,
91
(GDestroyNotify)udev_mgr_cleanup_lists);
92
self->scanners_present = g_hash_table_new_full (g_str_hash,
96
self->webcams_present = g_hash_table_new_full (g_str_hash,
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),
106
G_CALLBACK (udev_mgr_uevent_cb),
111
udev_mgr_cleanup_lists(gpointer data, gpointer self)
113
GList* scanners = (GList*)data;
114
g_list_foreach (scanners, udev_mgr_cleanup_entries, NULL);
115
g_list_free(scanners);
119
udev_mgr_cleanup_entries(gpointer data, gpointer self)
121
gchar* entry = (gchar*)data;
126
udev_mgr_finalize (GObject *object)
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);
137
udev_mgr_class_init (UdevMgrClass *klass)
139
GObjectClass* object_class = G_OBJECT_CLASS (klass);
140
object_class->finalize = udev_mgr_finalize;
144
udevice_mgr_device_list_iterator (gpointer data, gpointer userdata)
146
g_return_if_fail (G_UDEV_IS_DEVICE (data));
147
g_return_if_fail (UDEV_IS_MGR (userdata));
149
UdevMgr* self = UDEV_MGR (userdata);
151
GUdevDevice* device = G_UDEV_DEVICE (data);
153
const gchar* subsystem = NULL;
154
subsystem = g_udev_device_get_subsystem (device);
156
if (g_strcmp0 (subsystem, "usb") == 0){
157
udev_mgr_check_if_usb_device_is_supported (self, device, ADD);
159
else if (g_strcmp0 (subsystem, "video4linux") == 0){
160
udev_mgr_handle_webcam (self, device, ADD);
162
else if (g_strcmp0 (subsystem, "scsi") == 0){
163
udev_mgr_handle_scsi_device (self, device, ADD);
166
g_object_unref (device);
170
static void udev_mgr_update_menuitems (UdevMgr* self)
172
dbusmenu_menuitem_property_set_bool (self->scanner_item,
173
DBUSMENU_MENUITEM_PROP_VISIBLE,
174
g_hash_table_size (self->scanners_present) > 0);
176
dbusmenu_menuitem_property_set_bool (self->webcam_item,
177
DBUSMENU_MENUITEM_PROP_VISIBLE,
178
g_hash_table_size (self->webcams_present) > 0);
182
static void udev_mgr_uevent_cb (GUdevClient *client,
187
g_return_if_fail (UDEV_IS_MGR (user_data));
188
UdevMgr* self = UDEV_MGR (user_data);
189
g_return_if_fail (device != NULL);
191
g_debug ("just received a UEVENT with an action : %s", action);
193
UdevMgrDeviceAction udev_mgr_action = ADD;
195
if (g_strcmp0 (action, "remove") == 0){
196
udev_mgr_action = REMOVE;
199
const gchar* subsystem = NULL;
200
subsystem = g_udev_device_get_subsystem (device);
202
if (g_strcmp0 (subsystem, "usb") == 0){
203
udev_mgr_check_if_usb_device_is_supported (self,
207
else if (g_strcmp0 (subsystem, "video4linux") == 0){
208
udev_mgr_handle_webcam (self, device, udev_mgr_action);
210
else if (g_strcmp0 (subsystem, "scsi") == 0){
211
udev_mgr_handle_scsi_device (self, device, udev_mgr_action);
217
udev_mgr_handle_webcam (UdevMgr* self,
219
UdevMgrDeviceAction action)
222
debug_device (self, device, action);
225
const gchar* product;
227
vendor = g_udev_device_get_property (device, "ID_VENDOR_ID");
228
product = g_udev_device_get_property (device, "ID_MODEL_ID");
230
if (!vendor || !product) {
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");
239
g_hash_table_remove (self->webcams_present,
241
dbusmenu_menuitem_property_set (self->webcam_item,
242
DBUSMENU_MENUITEM_PROP_LABEL,
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");
251
const gchar* manufacturer = NULL;
252
manufacturer = g_udev_device_get_property (device, "ID_VENDOR");
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,
262
g_hash_table_insert (self->webcams_present,
266
udev_mgr_update_menuitems (self);
270
debug_device (UdevMgr* self,
272
UdevMgrDeviceAction action)
275
const gchar* product;
278
const gchar* manufacturer;
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);
286
g_debug ("%s device vendor id %s , product id of %s , number of %s and name of %s",
287
g_strdup(manufacturer),
293
/*const gchar *const *list;
294
const gchar *const *iter;
296
guint32 namelen = 0, i;
298
list = g_udev_device_get_property_keys(device);
300
for (iter = list; iter && *iter; iter++) {
301
if (strlen(*iter) > namelen)
302
namelen = strlen(*iter);
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);
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,
319
UdevMgrDeviceAction action)
321
const gchar* type = NULL;
322
type = g_udev_device_get_property (device, "TYPE");
328
// apparently anything thats type 6 and SCSI is a Scanner
329
if (g_strcmp0 (type, "6") == 0 && action == ADD){
331
const gchar* manufacturer = NULL;
332
manufacturer = g_udev_device_get_property (device, "ID_VENDOR");
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,
342
gchar* random_scanner_name = g_strdup_printf("%p--scanner", self);
343
g_hash_table_insert (self->scanners_present,
345
g_strdup("Scanner"));
346
udev_mgr_update_menuitems (self);
350
// We only care about type 3 for the special cases below
351
if (g_strcmp0 (type, "3") != 0){
355
const gchar* vendor = NULL;
356
vendor = g_udev_device_get_property (device, "VENDOR");
361
GList* vendor_list = NULL;
362
vendor_list = g_hash_table_lookup (self->supported_scsi_scanners,
364
if (vendor_list == NULL)
367
const gchar* model_id = NULL;
368
model_id = g_udev_device_get_property (device, "MODEL");
370
if (model_id == NULL)
373
GList* model_entry = NULL;
374
model_entry = g_list_find_custom (vendor_list,
376
(GCompareFunc)g_strcmp0);
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");
384
g_hash_table_remove (self->scanners_present, vendor);
385
dbusmenu_menuitem_property_set (self->scanner_item,
386
DBUSMENU_MENUITEM_PROP_LABEL,
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");
396
const gchar* manufacturer = NULL;
397
manufacturer = g_udev_device_get_property (device, "ID_VENDOR");
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,
406
g_hash_table_insert (self->scanners_present,
411
udev_mgr_update_menuitems (self);
416
udev_mgr_check_if_usb_device_is_supported (UdevMgr* self,
418
UdevMgrDeviceAction action)
420
const gchar* vendor = NULL;
421
//debug_device (self, device, action);
423
vendor = g_udev_device_get_property (device, "ID_VENDOR_ID");
428
//g_debug ("vendor = %s", vendor);
430
GList* vendor_list = NULL;
431
vendor_list = g_hash_table_lookup (self->supported_usb_scanners,
433
if (vendor_list == NULL)
436
const gchar* model_id = NULL;
437
model_id = g_udev_device_get_property (device, "ID_MODEL_ID");
439
if (model_id == NULL)
442
GList* model_entry = NULL;
443
model_entry = g_list_find_custom(vendor_list, model_id, (GCompareFunc)g_strcmp0);
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");
451
g_hash_table_remove (self->scanners_present, vendor);
452
dbusmenu_menuitem_property_set (self->scanner_item,
453
DBUSMENU_MENUITEM_PROP_LABEL,
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");
462
const gchar* manufacturer = NULL;
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,
473
g_hash_table_insert (self->scanners_present,
478
udev_mgr_update_menuitems (self);
482
UdevMgr* udev_mgr_new (DbusmenuMenuitem* scanner,
483
DbusmenuMenuitem* webcam)
485
UdevMgr* mgr = g_object_new (UDEV_TYPE_MGR, NULL);
486
mgr->scanner_item = scanner;
487
mgr->webcam_item = webcam;
489
// Check for USB devices
490
GList* usb_devices_available = NULL;
491
usb_devices_available = g_udev_client_query_by_subsystem (mgr->client,
493
if (usb_devices_available != NULL){
494
g_list_foreach (usb_devices_available,
495
udevice_mgr_device_list_iterator,
498
g_list_free (usb_devices_available);
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,
509
g_list_free (video_devices_available);
511
// Check for SCSI devices
512
GList* scsi_devices_available = NULL;
513
scsi_devices_available = g_udev_client_query_by_subsystem (mgr->client,
515
if (scsi_devices_available != NULL){
516
g_list_foreach (scsi_devices_available,
517
udevice_mgr_device_list_iterator,
519
g_list_free (scsi_devices_available);
524
static gchar* format_device_name (UdevMgr* self,
526
const gchar* generic,
527
const gchar* branded)
529
// We don't want to accommodate long names
530
if (strlen(brand) > 7)
531
return g_strdup(generic);
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);
541
gchar* lowered = g_ascii_strdown (brand, -1);
542
lowered[0] = g_ascii_toupper (lowered[0]);
543
gchar* label = g_strdup_printf(branded, lowered);