1 /*
2 * Copyright (C) 2009 David Mohr <david@mcbf.net>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Library 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 *
18 */
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif /* !HAVE_CONFIG_H */
23
24 #include <libxfce4util/libxfce4util.h>
25 #include <unistd.h>
26
27 #include "xfburn-device.h"
28 #include "xfburn-udev-manager.h"
29
30 /*- globals -*/
31
32 enum {
33 PROP_0,
34 PROP_NAME,
35 PROP_ADDRESS,
36 PROP_REVISION,
37 PROP_ACCESSIBLE,
38 PROP_SUPPORTED_SPEEDS,
39 PROP_DISC_STATUS,
40 PROP_PROFILE_NO,
41 PROP_PROFILE_NAME,
42 PROP_ERASABLE,
43 PROP_CDR,
44 PROP_CDRW,
45 PROP_DVDR,
46 PROP_DVDPLUSR,
47 PROP_DVDRAM,
48 PROP_BD,
49 PROP_TAO_BLOCK_TYPES,
50 PROP_SAO_BLOCK_TYPES,
51 PROP_RAW_BLOCK_TYPES,
52 PROP_PACKET_BLOCK_TYPES,
53 };
54
55 /*- private prototypes -*/
56
57 #define CAN_BURN(priv) ((priv)->cdr || (priv)->cdrw || (priv)->dvdr || (priv)->dvdram)
58 #define DEVICE_INFO_PRINTF(device) "%s can burn: %d [cdr: %d, cdrw: %d, dvdr: %d, dvdram: %d]", (device)->name, CAN_BURN (device), (device)->cdr, (device)->cdrw, (device)->dvdr, (device)->dvdram
59
60
61 /*****************/
62 /*- class setup -*/
63 /*****************/
64 typedef struct _XfburnDevicePrivate XfburnDevicePrivate;
65
66 struct _XfburnDevicePrivate {
67 gchar *name;
68 gchar *addr;
69 gchar *rev;
70 gboolean details_known;
71
72 gint buffer_size;
73 gboolean dummy_write;
74
75 gboolean cdr;
76 gboolean cdrw;
77 gboolean dvdr;
78 gboolean dvdplusr;
79 gboolean dvdram;
80 gboolean bd;
81
82 GSList *supported_speeds;
83
84 gint tao_block_types;
85 gint sao_block_types;
86 gint raw_block_types;
87 gint packet_block_types;
88
89 enum burn_disc_status disc_status;
90 int profile_no;
91 char profile_name[80];
92 int is_erasable;
93 };
94
G_DEFINE_TYPE_WITH_PRIVATE(XfburnDevice,xfburn_device,G_TYPE_OBJECT)95 G_DEFINE_TYPE_WITH_PRIVATE (XfburnDevice, xfburn_device, G_TYPE_OBJECT)
96
97 #define GET_PRIVATE(o) \
98 (xfburn_device_get_instance_private (o))
99
100 static void
101 xfburn_device_get_property (GObject *object, guint property_id,
102 GValue *value, GParamSpec *pspec)
103 {
104 XfburnDevicePrivate *priv = GET_PRIVATE (XFBURN_DEVICE (object));
105
106 switch (property_id) {
107 case PROP_NAME:
108 g_value_set_string (value, priv->name);
109 break;
110 case PROP_ADDRESS:
111 g_value_set_string (value, priv->addr);
112 break;
113 case PROP_REVISION:
114 g_value_set_string (value, priv->rev);
115 break;
116 case PROP_SUPPORTED_SPEEDS:
117 g_value_set_pointer (value, priv->supported_speeds);
118 break;
119 case PROP_DISC_STATUS:
120 g_value_set_int (value, priv->disc_status);
121 break;
122 case PROP_PROFILE_NO:
123 g_value_set_int (value, priv->profile_no);
124 break;
125 case PROP_PROFILE_NAME:
126 g_value_set_string (value, priv->profile_name);
127 break;
128 case PROP_ERASABLE:
129 g_value_set_boolean (value, priv->is_erasable);
130 break;
131 case PROP_CDR:
132 g_value_set_boolean (value, priv->cdr);
133 break;
134 case PROP_CDRW:
135 g_value_set_boolean (value, priv->cdrw);
136 break;
137 case PROP_DVDR:
138 g_value_set_boolean (value, priv->dvdr);
139 break;
140 case PROP_DVDPLUSR:
141 g_value_set_boolean (value, priv->dvdplusr);
142 break;
143 case PROP_DVDRAM:
144 g_value_set_boolean (value, priv->dvdram);
145 break;
146 case PROP_BD:
147 g_value_set_boolean (value, priv->bd);
148 break;
149 case PROP_TAO_BLOCK_TYPES:
150 g_value_set_int (value, priv->tao_block_types);
151 break;
152 case PROP_SAO_BLOCK_TYPES:
153 g_value_set_int (value, priv->sao_block_types);
154 break;
155 case PROP_RAW_BLOCK_TYPES:
156 g_value_set_int (value, priv->raw_block_types);
157 break;
158 case PROP_PACKET_BLOCK_TYPES:
159 g_value_set_int (value, priv->packet_block_types);
160 break;
161 default:
162 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
163 }
164 }
165
166 static void
xfburn_device_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)167 xfburn_device_set_property (GObject *object, guint property_id,
168 const GValue *value, GParamSpec *pspec)
169 {
170 XfburnDevicePrivate *priv = GET_PRIVATE (XFBURN_DEVICE (object));
171
172 switch (property_id) {
173 case PROP_NAME:
174 priv->name = g_value_dup_string (value);
175 break;
176 case PROP_ADDRESS:
177 priv->addr = g_value_dup_string (value);
178 break;
179 case PROP_REVISION:
180 priv->rev = g_value_dup_string (value);
181 break;
182 case PROP_SUPPORTED_SPEEDS:
183 priv->supported_speeds = g_value_get_pointer (value);
184 break;
185 case PROP_DISC_STATUS:
186 priv->disc_status = g_value_get_int (value);
187 break;
188 case PROP_PROFILE_NO:
189 priv->profile_no = g_value_get_int (value);
190 break;
191 case PROP_PROFILE_NAME:
192 strncpy (priv->profile_name, g_value_get_string(value), 80);
193 break;
194 case PROP_ERASABLE:
195 priv->is_erasable = g_value_get_boolean (value);
196 break;
197 case PROP_CDR:
198 priv->cdr = g_value_get_boolean (value);
199 break;
200 case PROP_CDRW:
201 priv->cdrw = g_value_get_boolean (value);
202 break;
203 case PROP_DVDR:
204 priv->dvdr = g_value_get_boolean (value);
205 break;
206 case PROP_DVDPLUSR:
207 priv->dvdplusr = g_value_get_boolean (value);
208 break;
209 case PROP_DVDRAM:
210 priv->dvdram = g_value_get_boolean (value);
211 break;
212 case PROP_BD:
213 priv->bd = g_value_get_boolean (value);
214 break;
215 case PROP_TAO_BLOCK_TYPES:
216 priv->tao_block_types = g_value_get_int (value);
217 break;
218 case PROP_SAO_BLOCK_TYPES:
219 priv->sao_block_types = g_value_get_int (value);
220 break;
221 case PROP_RAW_BLOCK_TYPES:
222 priv->raw_block_types = g_value_get_int (value);
223 break;
224 case PROP_PACKET_BLOCK_TYPES:
225 priv->packet_block_types = g_value_get_int (value);
226 break;
227 default:
228 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
229 }
230 }
231
232 static void
xfburn_device_finalize(GObject * object)233 xfburn_device_finalize (GObject *object)
234 {
235 XfburnDevice *dev = XFBURN_DEVICE (object);
236 XfburnDevicePrivate *priv = GET_PRIVATE (dev);
237
238 g_free (priv->name);
239
240 g_slist_free (priv->supported_speeds);
241
242 G_OBJECT_CLASS (xfburn_device_parent_class)->finalize (object);
243 }
244
245 static void
xfburn_device_class_init(XfburnDeviceClass * klass)246 xfburn_device_class_init (XfburnDeviceClass *klass)
247 {
248 GObjectClass *object_class = G_OBJECT_CLASS (klass);
249
250 object_class->get_property = xfburn_device_get_property;
251 object_class->set_property = xfburn_device_set_property;
252 object_class->finalize = xfburn_device_finalize;
253
254 g_object_class_install_property (object_class, PROP_NAME,
255 g_param_spec_string ("name", _("Display name"),
256 _("Display name"), NULL, G_PARAM_READABLE));
257 g_object_class_install_property (object_class, PROP_ADDRESS,
258 g_param_spec_string ("address", _("Device address"),
259 _("Device address"), "", G_PARAM_READWRITE));
260 g_object_class_install_property (object_class, PROP_REVISION,
261 g_param_spec_string ("revision", _("Device revision"),
262 _("Device Revision"), "", G_PARAM_READWRITE));
263 g_object_class_install_property (object_class, PROP_SUPPORTED_SPEEDS,
264 g_param_spec_pointer ("supported-speeds", _("Burn speeds supported by the device"),
265 _("Burn speeds supported by the device"), G_PARAM_READABLE));
266 g_object_class_install_property (object_class, PROP_DISC_STATUS,
267 g_param_spec_int ("disc-status", _("Disc status"),
268 _("Disc status"), 0, 6, 0, G_PARAM_READABLE));
269 g_object_class_install_property (object_class, PROP_PROFILE_NO,
270 g_param_spec_int ("profile-no", _("Profile no. as reported by libburn"),
271 _("Profile no. as reported by libburn"), 0, 0xffff, 0, G_PARAM_READABLE));
272 g_object_class_install_property (object_class, PROP_PROFILE_NAME,
273 g_param_spec_string ("profile-name", _("Profile name as reported by libburn"),
274 _("Profile name as reported by libburn"), "", G_PARAM_READABLE));
275 g_object_class_install_property (object_class, PROP_ERASABLE,
276 g_param_spec_boolean ("erasable", _("Is the disc erasable"),
277 _("Is the disc erasable"), FALSE, G_PARAM_READABLE));
278 g_object_class_install_property (object_class, PROP_CDR,
279 g_param_spec_boolean ("cdr", _("Can burn CDR"),
280 _("Can burn CDR"), FALSE, G_PARAM_READWRITE));
281 g_object_class_install_property (object_class, PROP_CDRW,
282 g_param_spec_boolean ("cdrw", _("Can burn CDRW"),
283 _("Can burn CDRW"), FALSE, G_PARAM_READWRITE));
284 g_object_class_install_property (object_class, PROP_DVDR,
285 g_param_spec_boolean ("dvdr", _("Can burn DVDR"),
286 _("Can burn DVDR"), FALSE, G_PARAM_READWRITE));
287 g_object_class_install_property (object_class, PROP_DVDPLUSR,
288 g_param_spec_boolean ("dvdplusr", _("Can burn DVDPLUSR"),
289 _("Can burn DVDPLUSR"), FALSE, G_PARAM_READWRITE));
290 g_object_class_install_property (object_class, PROP_DVDRAM,
291 g_param_spec_boolean ("dvdram", _("Can burn DVDRAM"),
292 _("Can burn DVDRAM"), FALSE, G_PARAM_READWRITE));
293 g_object_class_install_property (object_class, PROP_BD,
294 g_param_spec_boolean ("bd", _("Can burn Blu-ray"),
295 _("Can burn Blu-ray"), FALSE, G_PARAM_READWRITE));
296 g_object_class_install_property (object_class, PROP_TAO_BLOCK_TYPES,
297 g_param_spec_int ("tao-block-types", _("libburn TAO block types"),
298 _("libburn TAO block types"), 0, G_MAXINT, 0, G_PARAM_READABLE));
299 g_object_class_install_property (object_class, PROP_SAO_BLOCK_TYPES,
300 g_param_spec_int ("sao-block-types", _("libburn SAO block types"),
301 _("libburn SAO block types"), 0, G_MAXINT, 0, G_PARAM_READABLE));
302 g_object_class_install_property (object_class, PROP_RAW_BLOCK_TYPES,
303 g_param_spec_int ("raw-block-types", _("libburn RAW block types"),
304 _("libburn RAW block types"), 0, G_MAXINT, 0, G_PARAM_READABLE));
305 g_object_class_install_property (object_class, PROP_PACKET_BLOCK_TYPES,
306 g_param_spec_int ("packet-block-types", _("libburn PACKET block types"),
307 _("libburn PACKET block types"), 0, G_MAXINT, 0, G_PARAM_READABLE));
308 }
309
310 static void
xfburn_device_init(XfburnDevice * self)311 xfburn_device_init (XfburnDevice *self)
312 {
313 /* FIXME: initialize profile_name, or is that handled by the property? */
314 }
315
316
317 /***************/
318 /*- internals -*/
319 /***************/
320
321 static gboolean
no_speed_duplicate(GSList * speed_list,gint speed)322 no_speed_duplicate (GSList *speed_list, gint speed)
323 {
324 GSList *el = speed_list;
325
326 while (el) {
327 gint el_speed = GPOINTER_TO_INT (el->data);
328
329 if (el_speed == speed)
330 return FALSE;
331
332 el = g_slist_next (el);
333 }
334
335 return TRUE;
336 }
337
338 /* sort the speed list in ascending order */
339 static gint
cmp_ints(gconstpointer a,gconstpointer b)340 cmp_ints (gconstpointer a, gconstpointer b)
341 {
342 return GPOINTER_TO_INT(a) - GPOINTER_TO_INT(b);
343 }
344
345 static void
refresh_disc(XfburnDevice * device,struct burn_drive_info * drive_info)346 refresh_disc (XfburnDevice * device, struct burn_drive_info *drive_info)
347 {
348 XfburnDevicePrivate *priv = GET_PRIVATE (device);
349 gint ret;
350
351 /* check if there is a disc in the drive */
352 while ((priv->disc_status = burn_disc_get_status (drive_info->drive)) == BURN_DISC_UNREADY)
353 usleep(100001);
354
355 DBG ("disc_status = %d", priv->disc_status);
356
357 if ((ret = burn_disc_get_profile(drive_info->drive, &(priv->profile_no), priv->profile_name)) != 1) {
358 g_warning ("no profile could be retrieved");
359 }
360 priv->is_erasable = burn_disc_erasable (drive_info->drive);
361 DBG ("profile_no = 0x%x (%s), %s erasable", priv->profile_no, priv->profile_name, (priv->is_erasable ? "" : "NOT"));
362
363 #if 0 /* this doesn't seem to work */
364 if (burn_disc_read_atip (drive_info->drive) == 1) {
365 int start, end;
366
367 if (burn_drive_get_start_end_lba (drive_info->drive, &start, &end, 0) == 1) {
368 DBG ("lba start = %d, end = %d", start, end);
369 } else
370 DBG ("Getting start/end lba failed");
371 } else
372 DBG ("Reading ATIP failed");
373 #endif
374 }
375
376 static void
refresh_speed_list(XfburnDevice * device,struct burn_drive_info * drive_info)377 refresh_speed_list (XfburnDevice * device, struct burn_drive_info *drive_info)
378 {
379 XfburnDevicePrivate *priv = GET_PRIVATE (device);
380
381 struct burn_speed_descriptor *speed_list = NULL;
382 gint ret;
383
384 /* fill new list */
385 ret = burn_drive_get_speedlist (drive_info->drive, &speed_list);
386 /* speed_list = NULL; DEBUG */
387
388 if (ret > 0 && speed_list != NULL) {
389 struct burn_speed_descriptor *el = speed_list;
390
391 while (el) {
392 gint speed = el->write_speed;
393
394 /* FIXME: why do we need no_speed_duplicate? */
395 if (speed > 0 && no_speed_duplicate (priv->supported_speeds, speed)) {
396 priv->supported_speeds = g_slist_prepend (priv->supported_speeds, GINT_TO_POINTER (speed));
397 }
398
399 el = el->next;
400 }
401
402 burn_drive_free_speedlist (&speed_list);
403 priv->supported_speeds = g_slist_sort (priv->supported_speeds, &cmp_ints);
404 } else if (ret == 0 || speed_list == NULL) {
405 g_warning ("reported speed list is empty for device:");
406 // FIXME
407 //g_warning (DEVICE_INFO_PRINTF (priv));
408 g_warning ("%s can burn: %d [cdr: %d, cdrw: %d, dvdr: %d, dvdram: %d]", (priv)->name, ((priv)->cdr || (priv)->cdrw || (priv)->dvdr || (priv)->dvdram), (priv)->cdr, (priv)->cdrw, (priv)->dvdr, (priv)->dvdram);
409 } else {
410 /* ret < 0 */
411 g_error ("severe error while retrieving speed list");
412 }
413 }
414
415 /*******************/
416 /*- public methods-*/
417 /*******************/
418
419 void
xfburn_device_fillin_libburn_info(XfburnDevice * device,struct burn_drive_info * drive)420 xfburn_device_fillin_libburn_info (XfburnDevice *device, struct burn_drive_info *drive)
421 {
422 XfburnDevicePrivate *priv = GET_PRIVATE (device);
423
424 priv->details_known = TRUE;
425
426 priv->cdr = drive->write_cdr;
427 priv->cdrw = drive->write_cdrw;
428
429 priv->dvdr = drive->write_dvdr;
430 priv->dvdram = drive->write_dvdram;
431
432 priv->buffer_size = drive->buffer_size;
433 priv->dummy_write = drive->write_simulate;
434
435 DBG ("libburn will determine BD support based on the disk in the drive");
436
437 /* write modes */
438 priv->tao_block_types = drive->tao_block_types;
439 priv->sao_block_types = drive->sao_block_types;
440 priv->raw_block_types = drive->raw_block_types;
441 priv->packet_block_types = drive->packet_block_types;
442
443 DBG (DEVICE_INFO_PRINTF (priv));
444 }
445
446 gboolean
xfburn_device_grab(XfburnDevice * device,struct burn_drive_info ** drive_info)447 xfburn_device_grab (XfburnDevice * device, struct burn_drive_info **drive_info)
448 {
449 XfburnDevicePrivate *priv = GET_PRIVATE (device);
450 int ret = 0;
451 gchar drive_addr[BURN_DRIVE_ADR_LEN];
452 int i;
453 const int max_checks = 4;
454 #ifdef HAVE_GUDEV
455 XfburnUdevManager *udevman = xfburn_udev_manager_get_global ();
456 #endif
457
458 ret = burn_drive_convert_fs_adr (priv->addr, drive_addr);
459 if (ret <= 0) {
460 g_error ("Device address does not lead to a burner '%s' (ret=%d).", priv->addr, ret);
461 return FALSE;
462 }
463
464 /* we need to try to grab several times, because
465 * the drive might be busy detecting the disc */
466 for (i=1; i<=max_checks; i++) {
467 ret = burn_drive_scan_and_grab (drive_info, drive_addr, 0);
468 //DBG ("grab (%s)-> %d", drive_addr, ret);
469 if (ret > 0)
470 break;
471 else if (i < max_checks) {
472 #ifdef HAVE_GUDEV
473 if (!xfburn_udev_manager_check_ask_umount (udevman, device))
474 usleep(i*100001);
475 #else
476 usleep(i*100001);
477 #endif
478 }
479 }
480
481 if (ret <= 0) {
482 g_warning ("Unable to grab the drive at path '%s' (ret=%d).", priv->addr, ret);
483 return FALSE;
484 }
485
486 return TRUE;
487 }
488
489 gboolean
xfburn_device_refresh_info(XfburnDevice * device,gboolean get_speed_info)490 xfburn_device_refresh_info (XfburnDevice * device, gboolean get_speed_info)
491 {
492 XfburnDevicePrivate *priv = GET_PRIVATE (device);
493
494 struct burn_drive_info *drive_info = NULL;
495 gboolean ret;
496
497 if (G_UNLIKELY (device == NULL)) {
498 g_warning ("Hmm, why can we refresh when there is no drive?");
499 return FALSE;
500 }
501
502 /* reset other internal structures */
503 priv->profile_no = 0;
504 *(priv->profile_name) = '\0';
505 priv->is_erasable = 0;
506
507 /* empty previous speed list */
508 g_slist_free (priv->supported_speeds);
509 priv->supported_speeds = NULL;
510
511 if (!xfburn_device_grab (device, &drive_info)) {
512 ret = FALSE;
513 g_warning ("Couldn't grab drive in order to update speed list.");
514 priv->disc_status = BURN_DISC_UNGRABBED;
515 } else {
516 if (!priv->details_known)
517 xfburn_device_fillin_libburn_info (device, drive_info);
518
519 ret = TRUE;
520 refresh_disc (device, drive_info);
521 if (get_speed_info)
522 refresh_speed_list (device, drive_info);
523
524 xfburn_device_release (drive_info, 0);
525 }
526
527 return ret;
528 }
529
530 gboolean
xfburn_device_release(struct burn_drive_info * drive_info,gboolean eject)531 xfburn_device_release (struct burn_drive_info *drive_info, gboolean eject)
532 {
533 int ret;
534
535 burn_drive_snooze (drive_info->drive, 0);
536 burn_drive_release (drive_info->drive, eject);
537
538 ret = burn_drive_info_forget (drive_info, 0);
539
540 if (G_LIKELY (ret == 1))
541 return TRUE;
542 else if (ret == 2) {
543 DBG ("drive_info already forgotten");
544 return TRUE;
545 } else if (ret == 0) {
546 DBG ("could not forget drive_info");
547 return FALSE;
548 } else if (ret < 0) {
549 DBG ("some other failure while forgetting drive_info");
550 return FALSE;
551 }
552
553 /* we should never reach this */
554 return FALSE;
555 }
556
557 const gchar *
xfburn_device_set_name(XfburnDevice * device,const gchar * vendor,const gchar * product)558 xfburn_device_set_name (XfburnDevice *device, const gchar *vendor, const gchar *product)
559 {
560 XfburnDevicePrivate *priv = GET_PRIVATE (device);
561
562 priv->name = g_strconcat (vendor, " ", product, NULL);
563
564 return priv->name;
565 }
566
567 gboolean
xfburn_device_can_burn(XfburnDevice * device)568 xfburn_device_can_burn (XfburnDevice *device)
569 {
570 XfburnDevicePrivate *priv = GET_PRIVATE (device);
571
572 return CAN_BURN (priv);
573 }
574
575 gboolean
xfburn_device_can_dummy_write(XfburnDevice * device)576 xfburn_device_can_dummy_write (XfburnDevice *device)
577 {
578 XfburnDevicePrivate *priv = GET_PRIVATE (device);
579
580 return priv->dummy_write;
581 }
582
583 XfburnDevice*
xfburn_device_new(void)584 xfburn_device_new (void)
585 {
586 return g_object_new (XFBURN_TYPE_DEVICE, NULL);
587 }
588
589
590