Imported Upstream version 1.1.11
[platform/upstream/cdrkit.git] / wodim / scsi_mmc.c
1 /*
2  * This file has been modified for the cdrkit suite.
3  *
4  * The behaviour and appearence of the program code below can differ to a major
5  * extent from the version distributed by the original author(s).
6  *
7  * For details, see Changelog file distributed with the cdrkit package. If you
8  * received this file from another source then ask the distributing person for
9  * a log of modifications.
10  *
11  */
12
13 /* @(#)scsi_mmc.c       1.13 05/05/16 Copyright 2002-2005 J. Schilling */
14 /*
15  *      SCSI command functions for cdrecord
16  *      covering MMC-3 level and above
17  *
18  *      Copyright (c) 2002-2005 J. Schilling
19  */
20 /*
21  * This program is free software; you can redistribute it and/or modify
22  * it under the terms of the GNU General Public License version 2
23  * as published by the Free Software Foundation.
24  *
25  * This program is distributed in the hope that it will be useful,
26  * but WITHOUT ANY WARRANTY; without even the implied warranty of
27  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
28  * GNU General Public License for more details.
29  *
30  * You should have received a copy of the GNU General Public License along with
31  * this program; see the file COPYING.  If not, write to the Free Software
32  * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
33  */
34
35 /*
36 Includes code from http://libburnia.pykix.org/browser/libburn/trunk/libburn/mmc.c?format=txt 
37 */
38
39 /*#define       DEBUG*/
40
41 #include <mconfig.h>
42
43 #include <stdio.h>
44 #include <standard.h>
45 #include <stdxlib.h>
46 #include <unixstd.h>
47 #include <fctldefs.h>
48 #include <errno.h>
49 #include <strdefs.h>
50 #include <timedefs.h>
51
52 #include <utypes.h>
53 #include <btorder.h>
54 #include <intcvt.h>
55 #include <schily.h>
56
57 #include <usal/usalcmd.h>
58 #include <usal/scsidefs.h>
59 #include <usal/scsireg.h>
60 #include <usal/scsitransp.h>
61
62 #include "scsimmc.h"
63 #include "wodim.h"
64
65 extern  int     xdebug;
66
67
68
69 int     get_configuration(SCSI *usalp, caddr_t bp, int cnt, int st_feature, 
70                                                                 int rt);
71 static  int     get_conflen(SCSI *usalp, int st_feature, int rt);
72 int     get_curprofile(SCSI *usalp);
73 static  int     get_profiles(SCSI *usalp, caddr_t bp, int cnt);
74 int     print_profiles(SCSI *usalp);
75 int     get_proflist(SCSI *usalp, BOOL *wp, BOOL *cdp, BOOL *dvdp, BOOL *dvdplusp,
76                                                  BOOL *ddcdp);
77 int     get_wproflist(SCSI *usalp, BOOL *cdp, BOOL *dvdp, BOOL *dvdplusp, 
78                                                   BOOL *ddcdp);
79
80 /*
81  * Get feature codes
82  */
83 int
84 get_configuration(SCSI *usalp, caddr_t bp, int cnt, int st_feature, int rt)
85 {
86         register struct usal_cmd        *scmd = usalp->scmd;
87
88         fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
89         scmd->addr = bp;
90         scmd->size = cnt;
91         scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
92         scmd->cdb_len = SC_G1_CDBLEN;
93         scmd->sense_len = CCS_SENSE_LEN;
94         scmd->cdb.g1_cdb.cmd = 0x46;
95         scmd->cdb.g1_cdb.lun = usal_lun(usalp);
96         if (rt & 1)
97                 scmd->cdb.g1_cdb.reladr  = 1;
98         if (rt & 2)
99                 scmd->cdb.g1_cdb.res  = 1;
100
101         i_to_2_byte(scmd->cdb.g1_cdb.addr, st_feature);
102         g1_cdblen(&scmd->cdb.g1_cdb, cnt);
103
104         usalp->cmdname = "get_configuration";
105
106         return (usal_cmd(usalp));
107 }
108
109 /*
110  * Retrieve feature code list length
111  */
112 static int
113 get_conflen(SCSI *usalp, int st_feature, int rt)
114 {
115         Uchar   cbuf[8];
116         int     flen;
117         int     i;
118
119         fillbytes(cbuf, sizeof (cbuf), '\0');
120         usalp->silent++;
121         i = get_configuration(usalp, (char *)cbuf, sizeof (cbuf), st_feature, rt);
122         usalp->silent--;
123         if (i < 0)
124                 return (-1);
125         i = sizeof (cbuf) - usal_getresid(usalp);
126         if (i < 4)
127                 return (-1);
128
129         flen = a_to_u_4_byte(cbuf);
130         if (flen < 4)
131                 return (-1);
132         return (flen);
133 }
134
135 int
136 get_curprofile(SCSI *usalp)
137 {
138         Uchar   cbuf[8];
139         int     amt;
140         int     flen;
141         int     profile;
142         int     i;
143
144         fillbytes(cbuf, sizeof (cbuf), '\0');
145         usalp->silent++;
146         i = get_configuration(usalp, (char *)cbuf, sizeof (cbuf), 0, 0);
147         usalp->silent--;
148         if (i < 0)
149                 return (-1);
150
151         amt = sizeof (cbuf) - usal_getresid(usalp);
152         if (amt < 8)
153                 return (-1);
154         flen = a_to_u_4_byte(cbuf);
155         if (flen < 4)
156                 return (-1);
157
158         profile = a_to_u_2_byte(&cbuf[6]);
159
160         if (xdebug > 1)
161                 usal_prbytes("Features: ", cbuf, amt);
162
163         if (xdebug > 0)
164                 printf("feature len: %d current profile 0x%04X (%s) len %d\n",
165                                 flen, profile,
166                                 mmc_obtain_profile_name(profile), amt);
167
168         return (profile);
169 }
170
171 static int
172 get_profiles(SCSI *usalp, caddr_t bp, int cnt)
173 {
174         int     amt;
175         int     flen;
176         int     i;
177
178         flen = get_conflen(usalp, 0, 0);
179         if (flen < 0)
180                 return (-1);
181         if (cnt < flen)
182                 flen = cnt;
183
184         fillbytes(bp, cnt, '\0');
185         usalp->silent++;
186         i = get_configuration(usalp, (char *)bp, flen, 0, 0);
187         usalp->silent--;
188         if (i < 0)
189                 return (-1);
190         amt = flen - usal_getresid(usalp);
191
192         flen = a_to_u_4_byte(bp);
193         if ((flen+4) < amt)
194                 amt = flen+4;
195
196         return (amt);
197 }
198
199 int
200 print_profiles(SCSI *usalp)
201 {
202         Uchar   cbuf[1024];
203         Uchar   *p;
204         int     flen;
205         int     curprofile;
206         int     profile;
207         int     i;
208         int     n;
209
210         flen = get_profiles(usalp, (caddr_t)cbuf, sizeof (cbuf));
211         if (flen < 0)
212                 return (-1);
213
214         p = cbuf;
215         if (xdebug > 1)
216                 usal_prbytes("Features: ", cbuf, flen);
217
218         curprofile = a_to_u_2_byte(&p[6]);
219         if (xdebug > 0)
220                 printf("feature len: %d current profile 0x%04X (%s)\n",
221                                 flen, curprofile,
222                                 mmc_obtain_profile_name(curprofile));
223
224         printf("Current: 0x%04X (%s)\n", curprofile,
225                         mmc_obtain_profile_name(curprofile));
226
227         p += 8;         /* Skip feature header  */
228         n = p[3];       /* Additional length    */
229         n /= 4;
230         p += 4;
231
232         for (i = 0; i < n; i++) {
233                 profile = a_to_u_2_byte(p);
234                 if (xdebug > 0)
235                         printf("Profile: 0x%04X (%s)", profile,
236                                         mmc_obtain_profile_name(profile));
237                 else
238                         printf("Profile: ");
239                 printf("0x%04X (%s) %s\n", profile,
240                                 mmc_obtain_profile_name(profile), 
241                                 p[2] & 1 ? "(current)":"");
242                 p += 4;
243         }
244         return (curprofile);
245 }
246
247 int
248 get_proflist(SCSI *usalp, BOOL *wp, BOOL *cdp, BOOL *dvdp, BOOL *dvdplusp, 
249              BOOL *ddcdp)
250 {
251         Uchar   cbuf[1024];
252         Uchar   *p;
253         int     flen;
254         int     curprofile;
255         int     profile;
256         int     i;
257         int     n;
258         BOOL    wr      = FALSE;
259         BOOL    cd      = FALSE;
260         BOOL    dvd     = FALSE;
261         BOOL    dvdplus = FALSE;
262         BOOL    ddcd    = FALSE;
263
264         flen = get_profiles(usalp, (caddr_t)cbuf, sizeof (cbuf));
265         if (flen < 0)
266                 return (-1);
267
268         p = cbuf;
269         if (xdebug > 1)
270                 usal_prbytes("Features: ", cbuf, flen);
271
272         curprofile = a_to_u_2_byte(&p[6]);
273         if (xdebug > 0)
274                 printf("feature len: %d current profile 0x%04X (%s)\n",
275                                 flen, curprofile, 
276                                 mmc_obtain_profile_name(curprofile));
277
278         p += 8;         /* Skip feature header  */
279         n = p[3];       /* Additional length    */
280         n /= 4;
281         p += 4;
282
283         for (i = 0; i < n; i++) {
284                 profile = a_to_u_2_byte(p);
285                 p += 4;
286                 if (profile >= 0x0008 && profile < 0x0010)
287                         cd = TRUE;
288                 if (profile > 0x0008 && profile < 0x0010)
289                         wr = TRUE;
290
291                 if (profile >= 0x0010 && profile < 0x0018)
292                         dvd = TRUE;
293                 if (profile > 0x0010 && profile < 0x0018)
294                         wr = TRUE;
295
296                 if (profile >= 0x0018 && profile < 0x0020)
297                         dvdplus = TRUE;
298                 if (profile > 0x0018 && profile < 0x0020)
299                         wr = TRUE;
300
301                 if (profile >= 0x0020 && profile < 0x0028)
302                         ddcd = TRUE;
303                 if (profile > 0x0020 && profile < 0x0028)
304                         wr = TRUE;
305         }
306         if (wp)
307                 *wp     = wr;
308         if (cdp)
309                 *cdp    = cd;
310         if (dvdp)
311                 *dvdp   = dvd;
312         if (dvdplusp)
313                 *dvdplusp = dvdplus;
314         if (ddcdp)
315                 *ddcdp  = ddcd;
316
317         return (curprofile);
318 }
319
320 int
321 get_wproflist(SCSI *usalp, BOOL *cdp, BOOL *dvdp, BOOL *dvdplusp, BOOL *ddcdp)
322 {
323         Uchar   cbuf[1024];
324         Uchar   *p;
325         int     flen;
326         int     curprofile;
327         int     profile;
328         int     i;
329         int     n;
330         BOOL    cd      = FALSE;
331         BOOL    dvd     = FALSE;
332         BOOL    dvdplus = FALSE;
333         BOOL    ddcd    = FALSE;
334
335         flen = get_profiles(usalp, (caddr_t)cbuf, sizeof (cbuf));
336         if (flen < 0)
337                 return (-1);
338         p = cbuf;
339         curprofile = a_to_u_2_byte(&p[6]);
340
341         p += 8;         /* Skip feature header  */
342         n = p[3];       /* Additional length    */
343         n /= 4;
344         p += 4;
345
346         for (i = 0; i < n; i++) {
347                 profile = a_to_u_2_byte(p);
348                 p += 4;
349                 if (profile > 0x0008 && profile < 0x0010)
350                         cd = TRUE;
351                 if (profile > 0x0010 && profile < 0x0018)
352                         dvd = TRUE;
353                 if (profile > 0x0018 && profile < 0x0020)
354                         dvdplus = TRUE;
355                 if (profile > 0x0020 && profile < 0x0028)
356                         ddcd = TRUE;
357         }
358         if (cdp)
359                 *cdp    = cd;
360         if (dvdp)
361                 *dvdp   = dvd;
362         if (dvdplusp)
363                 *dvdplusp = dvdplus;
364         if (ddcdp)
365                 *ddcdp  = ddcd;
366
367         return (curprofile);
368 }
369
370
371 char *mmc_obtain_profile_name(int profile_number) {
372   static char *texts[0x53] = {NULL};
373   static char *reserved="Reserved/Unknown";
374   int i, max_pno = 0x53;
375   
376   if (texts[0] == NULL) {
377     for (i = 0; i<max_pno; i++)
378       texts[i] = reserved;
379     /* mmc5r04c.pdf , Table 88, human readable profile names */
380     texts[0x01] = "Non-removable disk";
381     texts[0x02] = "Removable disk";
382     texts[0x03] = "MO erasable";
383     texts[0x04] = "Optical write once";
384     texts[0x05] = "AS-MO";
385     texts[0x08] = "CD-ROM";
386     texts[0x09] = "CD-R";
387     texts[0x0a] = "CD-RW";
388     texts[0x10] = "DVD-ROM";
389     texts[0x11] = "DVD-R sequential recording";
390     texts[0x12] = "DVD-RAM";
391     texts[0x13] = "DVD-RW restricted overwrite";
392     texts[0x14] = "DVD-RW sequential recording";
393     texts[0x15] = "DVD-R/DL sequential recording";
394     texts[0x16] = "DVD-R/DL layer jump recording";
395     texts[0x1a] = "DVD+RW";
396     texts[0x1b] = "DVD+R";
397     texts[0x2a] = "DVD+RW/DL";
398     texts[0x2b] = "DVD+R/DL";
399     texts[0x40] = "BD-ROM";
400     texts[0x41] = "BD-R sequential recording";
401     texts[0x42] = "BD-R random recording";
402     texts[0x43] = "BD-RE";
403     texts[0x50] = "HD-DVD-ROM";
404     texts[0x51] = "HD-DVD-R";
405     texts[0x52] = "HD-DVD-RAM";
406   }
407   if (profile_number<0 || profile_number>=max_pno)
408     return "";
409   return texts[profile_number];
410 }
411