⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cdu31a.c.txt

📁 Linux块设备驱动分析与模拟实现
💻 TXT
📖 第 1 页 / 共 4 页
字号:
929 {
930    log = log + LOG_START_OFFSET;
931    msf[0] = int_to_bcd(log / 4500);
932    log = log % 4500;
933    msf[1] = int_to_bcd(log / 75);
934    msf[2] = int_to_bcd(log % 75);
935 }
936 
937 
938 /*
939  * Convert an MSF format to a logical sector.
940  */
941 static unsigned int
942 msf_to_log(unsigned char *msf)
943 {
944    unsigned int log;
945 
946 
947    log = bcd_to_int(msf[2]);
948    log += bcd_to_int(msf[1]) * 75;
949    log += bcd_to_int(msf[0]) * 4500;
950    log = log - LOG_START_OFFSET;
951 
952    return log;
953 }
954 
955 
956 /*
957  * Take in integer size value and put it into a buffer like
958  * the drive would want to see a number-of-sector value.
959  */
960 static void
961 size_to_buf(unsigned int size,
962             unsigned char *buf)
963 {
964    buf[0] = size / 65536;
965    size = size % 65536;
966    buf[1] = size / 256;
967    buf[2] = size % 256;
968 }
969 
970 
971 /*
972  * The OS calls this to perform a read or write operation to the drive.
973  * Write obviously fail.  Reads to a read ahead of sony_buffer_size
974  * bytes to help speed operations.  This especially helps since the OS
975  * uses 1024 byte blocks and the drive uses 2048 byte blocks.  Since most
976  * data access on a CD is done sequentially, this saves a lot of operations.
977  */
978 static void
979 do_cdu31a_request(void)
980 {
981    int block;
982    unsigned int dev;
983    int nsect;
984    unsigned char params[10];
985    unsigned char res_reg[2];
986    unsigned int res_size;
987    int copyoff;
988    int spin_up_retry;
989    unsigned int read_size;
990 
991 
992    if (!sony_spun_up)
993    {
994       scd_open (NULL,NULL);
995    }
996 
997    while (1)
998    {
999 cdu31a_request_startover:
1000       /*
1001        * The beginning here is stolen from the hard disk driver.  I hope
1002        * its right.
1003        */
1004       if (!(CURRENT) || CURRENT->dev < 0)
1005       {
1006          return;
1007       }
1008 
1009       INIT_REQUEST;
1010       dev = MINOR(CURRENT->dev);
1011       block = CURRENT->sector;
1012       nsect = CURRENT->nr_sectors;
1013       if (dev != 0)
1014       {
1015          end_request(0);
1016          goto cdu31a_request_startover;
1017       }
1018 
1019       switch(CURRENT->cmd)
1020       {
1021       case READ:
1022          /*
1023           * If the block address is invalid or the request goes beyond the end of
1024           * the media, return an error.
1025           */
1026          if ((block / 4) >= sony_toc->lead_out_start_lba)
1027          {
1028             end_request(0);
1029             goto cdu31a_request_startover;
1030          }
1031          if (((block + nsect) / 4) >= sony_toc->lead_out_start_lba)
1032          {
1033             end_request(0);
1034             goto cdu31a_request_startover;
1035          }
1036 
1037          while (nsect > 0)
1038          {
1039             /*
1040              * If the requested sector is not currently in the read-ahead buffer,
1041              * it must be read in.
1042              */
1043             if ((block < sony_first_block) || (block > sony_last_block))
1044             {
1045                sony_first_block = (block / 4) * 4;
1046                log_to_msf(block/4, params);
1047 
1048                /*
1049                 * If the full read-ahead would go beyond the end of the media, trim
1050                 * it back to read just till the end of the media.
1051                 */
1052                if (((block / 4) + sony_buffer_sectors) >= sony_toc->lead_out_start_lba)
1053                {
1054                   read_size = sony_toc->lead_out_start_lba - (block / 4);
1055                }
1056                else
1057                {
1058                   read_size = sony_buffer_sectors;
1059                }
1060                size_to_buf(read_size, &params[3]);
1061 
1062                /*
1063                 * Read the data.  If the drive was not spinning, spin it up and try
1064                 * once more.  I know, the goto is ugly, but I am too lazy to fix it.
1065                 */
1066                spin_up_retry = 0;
1067 try_read_again:
1068                sony_last_block =   sony_first_block
1069                                  + (get_data(sony_buffer,
1070                                              params,
1071                                              (read_size * 2048),
1072                                              res_reg,
1073                                              &res_size) * 4) - 1;
1074                if ((res_size < 2) || (res_reg[0] != 0))
1075                {
1076                   if ((res_reg[1] == SONY_NOT_SPIN_ERR) && (!spin_up_retry))
1077                   {
1078                      do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, &res_size);
1079                      spin_up_retry = 1;
1080                      goto try_read_again;
1081                   }
1082 
1083                   printk("Sony CDROM Read error: 0x%2.2x\n", res_reg[1]);
1084                   sony_first_block = -1;
1085                   sony_last_block = -1;
1086                   end_request(0);
1087                   goto cdu31a_request_startover;
1088                }
1089             }
1090    
1091             /*
1092              * The data is in memory now, copy it to the buffer and advance to the
1093              * next block to read.
1094              */
1095             copyoff = (block - sony_first_block) * 512;
1096             memcpy(CURRENT->buffer, sony_buffer+copyoff, 512);
1097                
1098             block += 1;
1099             nsect -= 1;
1100             CURRENT->buffer += 512;
1101          }
1102                
1103          end_request(1);
1104          break;
1105             
1106       case WRITE:
1107          end_request(0);
1108          break;
1109             
1110       default:
1111          panic("Unkown SONY CD cmd");
1112       }
1113    }
1114 }
1115 
1116 
1117 /*
1118  * Read the table of contents from the drive and set sony_toc_read if
1119  * successful.
1120  */
1121 static void
1122 sony_get_toc(void)
1123 {
1124    unsigned int res_size;
1125 
1126 
1127    if (!sony_toc_read)
1128    {
1129       do_sony_cd_cmd(SONY_REQ_TOC_DATA_CMD,
1130                      NULL,
1131                      0, 
1132                      (unsigned char *) sony_toc, 
1133                      &res_size);
1134       if ((res_size < 2) || ((sony_toc->exec_status[0] & 0x20) == 0x20))
1135       {
1136          return;
1137       }
1138       sony_toc->lead_out_start_lba = msf_to_log(sony_toc->lead_out_start_msf);
1139       sony_toc_read = 1;
1140    }
1141 }
1142 
1143 
1144 /*
1145  * Search for a specific track in the table of contents.
1146  */
1147 static int
1148 find_track(int track)
1149 {
1150    int i;
1151    int num_tracks;
1152 
1153 
1154    num_tracks = sony_toc->last_track_num + sony_toc->first_track_num + 1;
1155    for (i = 0; i < num_tracks; i++)
1156    {
1157       if (sony_toc->tracks[i].track == track)
1158       {
1159          return i;
1160       }
1161    }
1162 
1163    return -1;
1164 }
1165 
1166 
1167 /*
1168  * Read the subcode and put it int last_sony_subcode for future use.
1169  */
1170 static int
1171 read_subcode(void)
1172 {
1173    unsigned int res_size;
1174 
1175 
1176    do_sony_cd_cmd(SONY_REQ_SUBCODE_ADDRESS_CMD,
1177                   NULL,
1178                   0, 
1179                   (unsigned char *) last_sony_subcode, 
1180                   &res_size);
1181    if ((res_size < 2) || ((last_sony_subcode->exec_status[0] & 0x20) == 0x20))
1182    {
1183       printk("Sony CDROM error 0x%2.2x (read_subcode)\n",
1184              last_sony_subcode->exec_status[1]);
1185       return -EIO;
1186    }
1187 
1188    return 0;
1189 }
1190 
1191 
1192 /*
1193  * Get the subchannel info like the CDROMSUBCHNL command wants to see it.  If
1194  * the drive is playing, the subchannel needs to be read (since it would be
1195  * changing).  If the drive is paused or completed, the subcode information has
1196  * already been stored, just use that.  The ioctl call wants things in decimal
1197  * (not BCD), so all the conversions are done.
1198  */
1199 static int
1200 sony_get_subchnl_info(long arg)
1201 {
1202    struct cdrom_subchnl schi;
1203 
1204 
1205    /* Get attention stuff */
1206    while (handle_sony_cd_attention())
1207       ;
1208 
1209    sony_get_toc();
1210    if (!sony_toc_read)
1211    {
1212       return -EIO;
1213    }
1214 
1215    verify_area(VERIFY_READ, (char *) arg, sizeof(schi));
1216    verify_area(VERIFY_WRITE, (char *) arg, sizeof(schi));
1217 
1218    memcpy_fromfs(&schi, (char *) arg, sizeof(schi));
1219    
1220    switch (sony_audio_status)
1221    {
1222    case CDROM_AUDIO_PLAY:
1223       if (read_subcode() < 0)
1224       {
1225          return -EIO;
1226       }
1227       break;
1228 
1229    case CDROM_AUDIO_PAUSED:
1230    case CDROM_AUDIO_COMPLETED:
1231       break;
1232 
1233    case CDROM_AUDIO_NO_STATUS:
1234       schi.cdsc_audiostatus = sony_audio_status;
1235       memcpy_tofs((char *) arg, &schi, sizeof(schi));
1236       return 0;
1237       break;
1238 
1239    case CDROM_AUDIO_INVALID:
1240    case CDROM_AUDIO_ERROR:
1241    default:
1242       return -EIO;
1243    }
1244 
1245    schi.cdsc_audiostatus = sony_audio_status;
1246    schi.cdsc_adr = last_sony_subcode->address;
1247    schi.cdsc_ctrl = last_sony_subcode->control;
1248    schi.cdsc_trk = bcd_to_int(last_sony_subcode->track_num);
1249    schi.cdsc_ind = bcd_to_int(last_sony_subcode->index_num);
1250    if (schi.cdsc_format == CDROM_MSF)
1251    {
1252       schi.cdsc_absaddr.msf.minute = bcd_to_int(last_sony_subcode->abs_msf[0]);
1253       schi.cdsc_absaddr.msf.second = bcd_to_int(last_sony_subcode->abs_msf[1]);
1254       schi.cdsc_absaddr.msf.frame = bcd_to_int(last_sony_subcode->abs_msf[2]);
1255 
1256       schi.cdsc_reladdr.msf.minute = bcd_to_int(last_sony_subcode->rel_msf[0]);
1257       schi.cdsc_reladdr.msf.second = bcd_to_int(last_sony_subcode->rel_msf[1]);
1258       schi.cdsc_reladdr.msf.frame = bcd_to_int(last_sony_subcode->rel_msf[2]);
1259    }
1260    else if (schi.cdsc_format == CDROM_LBA)
1261    {
1262       schi.cdsc_absaddr.lba = msf_to_log(last_sony_subcode->abs_msf);
1263       schi.cdsc_reladdr.lba = msf_to_log(last_sony_subcode->rel_msf);
1264    }
1265    
1266    memcpy_tofs((char *) arg, &schi, sizeof(schi));
1267    return 0;
1268 }
1269 
1270 
1271 /*
1272  * The big ugly ioctl handler.
1273  */
1274 static int
1275 scd_ioctl(struct inode *inode,
1276           struct file  *file,
1277           unsigned int  cmd,
1278           unsigned long arg)
1279 {
1280    unsigned int dev;
1281    unsigned char res_reg[2];
1282    unsigned int res_size;
1283    unsigned char params[7];
1284    int i;
1285 
1286 
1287    if (!inode)
1288    {
1289       return -EINVAL;
1290    }
1291    dev = MINOR(inode->i_rdev) >> 6;
1292    if (dev != 0)
1293    {
1294       return -EINVAL;
1295    }
1296 
1297    switch (cmd)
1298    {
1299    case CDROMSTART:     /* Spin up the drive */
1300       do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, &res_size);
1301       if ((res_size < 2) || ((res_reg[0] & 0x20) == 0x20))
1302       {
1303          printk("Sony CDROM error 0x%2.2x (CDROMSTART)\n", res_reg[1]);
1304          return -EIO;
1305       }
1306       return 0;
1307       break;
1308       
1309    case CDROMSTOP:      /* Spin down the drive */
1310       do_sony_cd_cmd(SONY_AUDIO_STOP_CMD, NULL, 0, res_reg, &res_size);
1311 
1312       /*
1313        * Spin the drive down, ignoring the error if the disk was
1314        * already not spinning.
1315        */
1316       sony_audio_status = CDROM_AUDIO_NO_STATUS;
1317       do_sony_cd_cmd(SONY_SPIN_DOWN_CMD, NULL, 0, res_reg, &res_size);
1318       if (   ((res_size < 2) || ((res_reg[0] & 0x20) == 0x20))
1319           && (res_reg[1] != SONY_NOT_SPIN_ERR))
1320       {
1321          printk("Sony CDROM error 0x%2.2x (CDROMSTOP)\n", res_reg[1]);
1322          return -EIO;
1323       }
1324       
1325       return 0;
1326       break;
1327 
1328    case CDROMPAUSE:     /* Pause the drive */
1329       do_sony_cd_cmd(SONY_AUDIO_STOP_CMD, NULL, 0, res_reg, &res_size);
1330       if ((res_size < 2) || ((res_reg[0] & 0x20) == 0x20))
1331       {
1332          printk("Sony CDROM error 0x%2.2x (CDROMPAUSE)\n", res_reg[1]);
1333          return -EIO;
1334       }
1335 
1336       /* Get the current position and save it for resuming */
1337       if (read_subcode() < 0)
1338       {
1339          return -EIO;
1340       }
1341       cur_pos_msf[0] = last_sony_subcode->abs_msf[0];
1342       cur_pos_msf[1] = last_sony_subcode->abs_msf[1];
1343       cur_pos_msf[2] = last_sony_subcode->abs_msf[2];
1344       sony_audio_status = CDROM_AUDIO_PAUSED;
1345       return 0;
1346       break;
1347 
1348    case CDROMRESUME:    /* Start the drive after being paused */
1349       if (sony_audio_status != CDROM_AUDIO_PAUSED)
1350       {
1351          return -EINVAL;
1352       }
1353       
1354       do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, &res_size);
1355       
1356       /* Start the drive at the saved position. */
1357       params[1] = cur_pos_msf[0];
1358       params[2] = cur_pos_msf[1];
1359       params[3] = cur_pos_msf[2];
1360       params[4] = final_pos_msf[0];
1361       params[5] = final_pos_msf[1];
1362       params[6] = final_pos_msf[2];
1363       params[0] = 0x03;
1364       do_sony_cd_cmd(SONY_AUDIO_PLAYBACK_CMD, params, 7, res_reg, &res_size);
1365       if ((res_size < 2) || ((res_reg[0] & 0x20) == 0x20))
1366       {
1367          printk("Sony CDROM error 0x%2.2x (CDROMRESUME)\n", res_reg[1]);
1368          return -EIO;
1369       }
1370       sony_audio_status = CDROM_AUDIO_PLAY;
1371       return 0;
1372       break;
1373 
1374    case CDROMPLAYMSF:   /* Play starting at the given MSF address. */
1375       verify_area(VERIFY_READ, (char *) arg, 6);
1376       do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, &res_size);
1377       memcpy_fromfs(&(params[1]), (void *) arg, 6);
1378       
1379       /* The parameters are given in int, must be converted */
1380       for (i=1; i<7; i++)
1381       {
1382          params[i] = int_to_bcd(params[i]);
1383       }
1384       params[0] = 0x03;
1385       do_sony_cd_cmd(SONY_AUDIO_PLAYBACK_CMD, params, 7, res_reg, &res_size);
1386       if ((res_size < 2) || ((res_reg[0] & 0x20) == 0x20))
1387       {
1388          printk("Sony CDROM error 0x%2.2x (CDROMPLAYMSF)\n", res_reg[1]);
1389          return -EIO;
1390       }
1391       
1392       /* Save the final position for pauses and resumes */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -