sr_vendor.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:9k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /* -*-linux-c-*-
  2.  * vendor-specific code for SCSI CD-ROM's goes here.
  3.  *
  4.  * This is needed becauce most of the new features (multisession and
  5.  * the like) are too new to be included into the SCSI-II standard (to
  6.  * be exact: there is'nt anything in my draft copy).
  7.  *
  8.  * Aug 1997: Ha! Got a SCSI-3 cdrom spec across my fingers. SCSI-3 does
  9.  *           multisession using the READ TOC command (like SONY).
  10.  *
  11.  *           Rearranged stuff here: SCSI-3 is included allways, support
  12.  *           for NEC/TOSHIBA/HP commands is optional.
  13.  *
  14.  *   Gerd Knorr <kraxel@cs.tu-berlin.de> 
  15.  *
  16.  * --------------------------------------------------------------------------
  17.  *
  18.  * support for XA/multisession-CD's
  19.  * 
  20.  *   - NEC:     Detection and support of multisession CD's.
  21.  *     
  22.  *   - TOSHIBA: Detection and support of multisession CD's.
  23.  *              Some XA-Sector tweaking, required for older drives.
  24.  *
  25.  *   - SONY:    Detection and support of multisession CD's.
  26.  *              added by Thomas Quinot <thomas@cuivre.freenix.fr>
  27.  *
  28.  *   - PIONEER, HITACHI, PLEXTOR, MATSHITA, TEAC, PHILIPS: known to
  29.  *              work with SONY (SCSI3 now)  code.
  30.  *
  31.  *   - HP:      Much like SONY, but a little different... (Thomas)
  32.  *              HP-Writers only ??? Maybe other CD-Writers work with this too ?
  33.  *              HP 6020 writers now supported.
  34.  */
  35. #include <linux/config.h>
  36. #include <linux/errno.h>
  37. #include <linux/string.h>
  38. #include <linux/blk.h>
  39. #include "scsi.h"
  40. #include "hosts.h"
  41. #include <scsi/scsi_ioctl.h>
  42. #include <linux/cdrom.h>
  43. #include "sr.h"
  44. #if 0
  45. #define DEBUG
  46. #endif
  47. /* here are some constants to sort the vendors into groups */
  48. #define VENDOR_SCSI3           1 /* default: scsi-3 mmc */
  49. #define VENDOR_NEC             2
  50. #define VENDOR_TOSHIBA         3
  51. #define VENDOR_WRITER          4 /* pre-scsi3 writers */
  52. #define VENDOR_ID (scsi_CDs[minor].vendor)
  53. void sr_vendor_init(int minor)
  54. {
  55. #ifndef CONFIG_BLK_DEV_SR_VENDOR
  56. VENDOR_ID = VENDOR_SCSI3;
  57. #else
  58. char *vendor = scsi_CDs[minor].device->vendor;
  59. char *model = scsi_CDs[minor].device->model;
  60. /* default */
  61. VENDOR_ID = VENDOR_SCSI3;
  62. if (scsi_CDs[minor].readcd_known)
  63. /* this is true for scsi3/mmc drives - no more checks */
  64. return;
  65. if (scsi_CDs[minor].device->type == TYPE_WORM) {
  66. VENDOR_ID = VENDOR_WRITER;
  67. } else if (!strncmp(vendor, "NEC", 3)) {
  68. VENDOR_ID = VENDOR_NEC;
  69. if (!strncmp(model, "CD-ROM DRIVE:25", 15) ||
  70.     !strncmp(model, "CD-ROM DRIVE:36", 15) ||
  71.     !strncmp(model, "CD-ROM DRIVE:83", 15) ||
  72.     !strncmp(model, "CD-ROM DRIVE:84 ", 16)
  73. #if 0
  74. /* my NEC 3x returns the read-raw data if a read-raw
  75.    is followed by a read for the same sector - aeb */
  76.     || !strncmp(model, "CD-ROM DRIVE:500", 16)
  77. #endif
  78.     )
  79. /* these can't handle multisession, may hang */
  80. scsi_CDs[minor].cdi.mask |= CDC_MULTI_SESSION;
  81. } else if (!strncmp(vendor, "TOSHIBA", 7)) {
  82. VENDOR_ID = VENDOR_TOSHIBA;
  83. }
  84. #endif
  85. }
  86. /* small handy function for switching block length using MODE SELECT,
  87.  * used by sr_read_sector() */
  88. int sr_set_blocklength(int minor, int blocklength)
  89. {
  90. unsigned char *buffer; /* the buffer for the ioctl */
  91. unsigned char cmd[MAX_COMMAND_SIZE]; /* the scsi-command */
  92. struct ccs_modesel_head *modesel;
  93. int rc, density = 0;
  94. #ifdef CONFIG_BLK_DEV_SR_VENDOR
  95. if (VENDOR_ID == VENDOR_TOSHIBA)
  96. density = (blocklength > 2048) ? 0x81 : 0x83;
  97. #endif
  98. buffer = (unsigned char *) scsi_malloc(512);
  99. if (!buffer)
  100. return -ENOMEM;
  101. #ifdef DEBUG
  102. printk("sr%d: MODE SELECT 0x%x/%dn", minor, density, blocklength);
  103. #endif
  104. memset(cmd, 0, MAX_COMMAND_SIZE);
  105. cmd[0] = MODE_SELECT;
  106. cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ?
  107.          (scsi_CDs[minor].device->lun << 5) : 0;
  108. cmd[1] |= (1 << 4);
  109. cmd[4] = 12;
  110. modesel = (struct ccs_modesel_head *) buffer;
  111. memset(modesel, 0, sizeof(*modesel));
  112. modesel->block_desc_length = 0x08;
  113. modesel->density = density;
  114. modesel->block_length_med = (blocklength >> 8) & 0xff;
  115. modesel->block_length_lo = blocklength & 0xff;
  116. if (0 == (rc = sr_do_ioctl(minor, cmd, buffer, sizeof(*modesel), 0, SCSI_DATA_WRITE, NULL))) {
  117. scsi_CDs[minor].device->sector_size = blocklength;
  118. }
  119. #ifdef DEBUG
  120. else
  121. printk("sr%d: switching blocklength to %d bytes failedn",
  122.        minor, blocklength);
  123. #endif
  124. scsi_free(buffer, 512);
  125. return rc;
  126. }
  127. /* This function gets called after a media change. Checks if the CD is
  128.    multisession, asks for offset etc. */
  129. #define BCD_TO_BIN(x)    ((((int)x & 0xf0) >> 4)*10 + ((int)x & 0x0f))
  130. int sr_cd_check(struct cdrom_device_info *cdi)
  131. {
  132. unsigned long sector;
  133. unsigned char *buffer; /* the buffer for the ioctl */
  134. unsigned char cmd[MAX_COMMAND_SIZE]; /* the scsi-command */
  135. int rc, no_multi, minor;
  136. minor = MINOR(cdi->dev);
  137. if (scsi_CDs[minor].cdi.mask & CDC_MULTI_SESSION)
  138. return 0;
  139. buffer = (unsigned char *) scsi_malloc(512);
  140. if (!buffer)
  141. return -ENOMEM;
  142. sector = 0; /* the multisession sector offset goes here  */
  143. no_multi = 0; /* flag: the drive can't handle multisession */
  144. rc = 0;
  145. switch (VENDOR_ID) {
  146. case VENDOR_SCSI3:
  147. memset(cmd, 0, MAX_COMMAND_SIZE);
  148. cmd[0] = READ_TOC;
  149. cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ?
  150.          (scsi_CDs[minor].device->lun << 5) : 0;
  151. cmd[8] = 12;
  152. cmd[9] = 0x40;
  153. rc = sr_do_ioctl(minor, cmd, buffer, 12, 1, SCSI_DATA_READ, NULL);
  154. if (rc != 0)
  155. break;
  156. if ((buffer[0] << 8) + buffer[1] < 0x0a) {
  157. printk(KERN_INFO "sr%d: Hmm, seems the drive "
  158.    "doesn't support multisession CD'sn", minor);
  159. no_multi = 1;
  160. break;
  161. }
  162. sector = buffer[11] + (buffer[10] << 8) +
  163.     (buffer[9] << 16) + (buffer[8] << 24);
  164. if (buffer[6] <= 1) {
  165. /* ignore sector offsets from first track */
  166. sector = 0;
  167. }
  168. break;
  169. #ifdef CONFIG_BLK_DEV_SR_VENDOR
  170. case VENDOR_NEC:{
  171. unsigned long min, sec, frame;
  172. memset(cmd, 0, MAX_COMMAND_SIZE);
  173. cmd[0] = 0xde;
  174. cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ?
  175.          (scsi_CDs[minor].device->lun << 5) : 0;
  176. cmd[1] |= 0x03;
  177. cmd[2] = 0xb0;
  178. rc = sr_do_ioctl(minor, cmd, buffer, 0x16, 1, SCSI_DATA_READ, NULL);
  179. if (rc != 0)
  180. break;
  181. if (buffer[14] != 0 && buffer[14] != 0xb0) {
  182. printk(KERN_INFO "sr%d: Hmm, seems the cdrom "
  183.        "doesn't support multisession CD'sn", minor);
  184. no_multi = 1;
  185. break;
  186. }
  187. min = BCD_TO_BIN(buffer[15]);
  188. sec = BCD_TO_BIN(buffer[16]);
  189. frame = BCD_TO_BIN(buffer[17]);
  190. sector = min * CD_SECS * CD_FRAMES + sec * CD_FRAMES + frame;
  191. break;
  192. }
  193. case VENDOR_TOSHIBA:{
  194. unsigned long min, sec, frame;
  195. /* we request some disc information (is it a XA-CD ?,
  196.  * where starts the last session ?) */
  197. memset(cmd, 0, MAX_COMMAND_SIZE);
  198. cmd[0] = 0xc7;
  199. cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ?
  200.          (scsi_CDs[minor].device->lun << 5) : 0;
  201. cmd[1] |= 0x03;
  202. rc = sr_do_ioctl(minor, cmd, buffer, 4, 1, SCSI_DATA_READ, NULL);
  203. if (rc == -EINVAL) {
  204. printk(KERN_INFO "sr%d: Hmm, seems the drive "
  205.        "doesn't support multisession CD'sn", minor);
  206. no_multi = 1;
  207. break;
  208. }
  209. if (rc != 0)
  210. break;
  211. min = BCD_TO_BIN(buffer[1]);
  212. sec = BCD_TO_BIN(buffer[2]);
  213. frame = BCD_TO_BIN(buffer[3]);
  214. sector = min * CD_SECS * CD_FRAMES + sec * CD_FRAMES + frame;
  215. if (sector)
  216. sector -= CD_MSF_OFFSET;
  217. sr_set_blocklength(minor, 2048);
  218. break;
  219. }
  220. case VENDOR_WRITER:
  221. memset(cmd, 0, MAX_COMMAND_SIZE);
  222. cmd[0] = READ_TOC;
  223. cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ?
  224.          (scsi_CDs[minor].device->lun << 5) : 0;
  225. cmd[8] = 0x04;
  226. cmd[9] = 0x40;
  227. rc = sr_do_ioctl(minor, cmd, buffer, 0x04, 1, SCSI_DATA_READ, NULL);
  228. if (rc != 0) {
  229. break;
  230. }
  231. if ((rc = buffer[2]) == 0) {
  232. printk(KERN_WARNING
  233.        "sr%d: No finished sessionn", minor);
  234. break;
  235. }
  236. cmd[0] = READ_TOC; /* Read TOC */
  237. cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ?
  238.          (scsi_CDs[minor].device->lun << 5) : 0;
  239. cmd[6] = rc & 0x7f; /* number of last session */
  240. cmd[8] = 0x0c;
  241. cmd[9] = 0x40;
  242. rc = sr_do_ioctl(minor, cmd, buffer, 12, 1, SCSI_DATA_READ, NULL);
  243. if (rc != 0) {
  244. break;
  245. }
  246. sector = buffer[11] + (buffer[10] << 8) +
  247.     (buffer[9] << 16) + (buffer[8] << 24);
  248. break;
  249. #endif /* CONFIG_BLK_DEV_SR_VENDOR */
  250. default:
  251. /* should not happen */
  252. printk(KERN_WARNING
  253.    "sr%d: unknown vendor code (%i), not initialized ?n",
  254.        minor, VENDOR_ID);
  255. sector = 0;
  256. no_multi = 1;
  257. break;
  258. }
  259. scsi_CDs[minor].ms_offset = sector;
  260. scsi_CDs[minor].xa_flag = 0;
  261. if (CDS_AUDIO != sr_disk_status(cdi) && 1 == sr_is_xa(minor))
  262. scsi_CDs[minor].xa_flag = 1;
  263. if (2048 != scsi_CDs[minor].device->sector_size) {
  264. sr_set_blocklength(minor, 2048);
  265. }
  266. if (no_multi)
  267. cdi->mask |= CDC_MULTI_SESSION;
  268. #ifdef DEBUG
  269. if (sector)
  270. printk(KERN_DEBUG "sr%d: multisession offset=%lun",
  271.        minor, sector);
  272. #endif
  273. scsi_free(buffer, 512);
  274. return rc;
  275. }