Merge branch 'master' into 'master'
[brasero.git] / libbrasero-media / scsi-mode-sense.c
blob99635f44f2fea831b8428db698d21f65db77d469
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /*
3 * Libbrasero-media
4 * Copyright (C) Philippe Rouquier 2005-2009 <bonfire-app@wanadoo.fr>
6 * Libbrasero-media is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * The Libbrasero-media authors hereby grant permission for non-GPL compatible
12 * GStreamer plugins to be used and distributed together with GStreamer
13 * and Libbrasero-media. This permission is above and beyond the permissions granted
14 * by the GPL license by which Libbrasero-media is covered. If you modify this code
15 * you may extend this exception to your version of the code, but you are not
16 * obligated to do so. If you do not wish to do so, delete this exception
17 * statement from your version.
19 * Libbrasero-media is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Library General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to:
26 * The Free Software Foundation, Inc.,
27 * 51 Franklin Street, Fifth Floor
28 * Boston, MA 02110-1301, USA.
31 #ifdef HAVE_CONFIG_H
32 # include <config.h>
33 #endif
35 #include <glib.h>
37 #include "brasero-media-private.h"
39 #include "scsi-spc1.h"
41 #include "scsi-error.h"
42 #include "scsi-utils.h"
43 #include "scsi-base.h"
44 #include "scsi-command.h"
45 #include "scsi-opcodes.h"
46 #include "scsi-mode-pages.h"
48 /**
49 * MODE SENSE command description (defined in SPC, Scsi Primary Commands)
52 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
54 struct _BraseroModeSenseCDB {
55 uchar opcode :8;
57 uchar reserved1 :3;
58 uchar dbd :1;
59 uchar llbaa :1;
60 uchar reserved0 :3;
62 uchar page_code :8;
63 uchar subpage_code :8;
65 uchar reserved2 [3];
67 uchar alloc_len [2];
68 uchar ctl;
71 #else
73 struct _BraseroModeSenseCDB {
74 uchar opcode :8;
76 uchar reserved0 :3;
77 uchar llbaa :1;
78 uchar dbd :1;
79 uchar reserved1 :3;
81 uchar page_code :8;
82 uchar subpage_code :8;
84 uchar reserved2 [3];
86 uchar alloc_len [2];
87 uchar ctl;
90 #endif
92 typedef struct _BraseroModeSenseCDB BraseroModeSenseCDB;
94 BRASERO_SCSI_COMMAND_DEFINE (BraseroModeSenseCDB,
95 MODE_SENSE,
96 BRASERO_SCSI_READ);
98 #define BRASERO_MODE_DATA(data) ((BraseroScsiModeData *) (data))
100 BraseroScsiResult
101 brasero_spc1_mode_sense_get_page (BraseroDeviceHandle *handle,
102 BraseroSPCPageType num,
103 BraseroScsiModeData **data,
104 int *data_size,
105 BraseroScsiErrCode *error)
107 int page_size;
108 int buffer_size;
109 int request_size;
110 BraseroScsiResult res;
111 BraseroModeSenseCDB *cdb;
112 BraseroScsiModeData header;
113 BraseroScsiModeData *buffer;
115 g_return_val_if_fail (handle != NULL, BRASERO_SCSI_FAILURE);
117 if (!data || !data_size) {
118 BRASERO_SCSI_SET_ERRCODE (error, BRASERO_SCSI_BAD_ARGUMENT);
119 return BRASERO_SCSI_FAILURE;
122 /* issue a first command to get the size of the page ... */
123 cdb = brasero_scsi_command_new (&info, handle);
124 cdb->dbd = 1;
125 cdb->page_code = num;
126 BRASERO_SET_16 (cdb->alloc_len, sizeof (header));
127 bzero (&header, sizeof (header));
129 BRASERO_MEDIA_LOG ("Getting page size");
130 res = brasero_scsi_command_issue_sync (cdb, &header, sizeof (header), error);
131 if (res)
132 goto end;
134 if (!header.hdr.len) {
135 BRASERO_SCSI_SET_ERRCODE (error, BRASERO_SCSI_SIZE_MISMATCH);
136 res = BRASERO_SCSI_FAILURE;
137 goto end;
140 /* Paranoïa, make sure:
141 * - the size given in header, the one of the page returned are coherent
142 * - the block descriptors are actually disabled */
143 if (BRASERO_GET_16 (header.hdr.bdlen)) {
144 BRASERO_SCSI_SET_ERRCODE (error, BRASERO_SCSI_BAD_ARGUMENT);
145 BRASERO_MEDIA_LOG ("Block descriptors not disabled %i", BRASERO_GET_16 (header.hdr.bdlen));
146 res = BRASERO_SCSI_FAILURE;
147 goto end;
150 request_size = BRASERO_GET_16 (header.hdr.len) +
151 G_STRUCT_OFFSET (BraseroScsiModeHdr, len) +
152 sizeof (header.hdr.len);
154 page_size = header.page.len +
155 G_STRUCT_OFFSET (BraseroScsiModePage, len) +
156 sizeof (header.page.len);
158 if (request_size != page_size + sizeof (BraseroScsiModeHdr)) {
159 BRASERO_SCSI_SET_ERRCODE (error, BRASERO_SCSI_SIZE_MISMATCH);
160 BRASERO_MEDIA_LOG ("Incoherent answer sizes: request %i, page %i", request_size, page_size);
161 res = BRASERO_SCSI_FAILURE;
162 goto end;
165 /* ... allocate an appropriate buffer ... */
166 buffer = (BraseroScsiModeData *) g_new0 (uchar, request_size);
168 /* ... re-issue the command */
169 BRASERO_MEDIA_LOG("Getting page (size = %i)", request_size);
171 BRASERO_SET_16 (cdb->alloc_len, request_size);
172 res = brasero_scsi_command_issue_sync (cdb, buffer, request_size, error);
173 if (res) {
174 g_free (buffer);
175 goto end;
178 /* Paranoïa, some more checks:
179 * - the size of the page returned is the one we requested
180 * - block descriptors are actually disabled
181 * - header claimed size == buffer size
182 * - header claimed size == sizeof (header) + sizeof (page) */
183 buffer_size = BRASERO_GET_16 (buffer->hdr.len) +
184 G_STRUCT_OFFSET (BraseroScsiModeHdr, len) +
185 sizeof (buffer->hdr.len);
187 page_size = buffer->page.len +
188 G_STRUCT_OFFSET (BraseroScsiModePage, len) +
189 sizeof (buffer->page.len);
191 if (request_size != buffer_size
192 || BRASERO_GET_16 (buffer->hdr.bdlen)
193 || buffer_size != page_size + sizeof (BraseroScsiModeHdr)) {
194 g_free (buffer);
196 BRASERO_SCSI_SET_ERRCODE (error, BRASERO_SCSI_SIZE_MISMATCH);
197 res = BRASERO_SCSI_FAILURE;
198 goto end;
201 *data = buffer;
202 *data_size = request_size;
204 end:
205 brasero_scsi_command_free (cdb);
206 return res;