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

📄 mcd.c.txt

📁 Linux块设备驱动分析与模拟实现
💻 TXT
📖 第 1 页 / 共 3 页
字号:
  1 /*
  2         linux/kernel/blk_drv/mcd.c - Mitsumi CDROM driver
  3 
  4         Copyright (C) 1992  Martin Harriss
  5 
  6         martin@bdsi.com
  7 
  8         This program is free software; you can redistribute it and/or modify
  9         it under the terms of the GNU General Public License as published by
 10         the Free Software Foundation; either version 2, or (at your option)
 11         any later version.
 12 
 13         This program is distributed in the hope that it will be useful,
 14         but WITHOUT ANY WARRANTY; without even the implied warranty of
 15         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 16         GNU General Public License for more details.
 17 
 18         You should have received a copy of the GNU General Public License
 19         along with this program; if not, write to the Free Software
 20         Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 21 
 22         HISTORY
 23 
 24         0.1     First attempt - internal use only
 25         0.2     Cleaned up delays and use of timer - alpha release
 26         0.3     Audio support added
 27         0.3.1 Changes for mitsumi CRMC LU005S march version
 28                    (stud11@cc4.kuleuven.ac.be)
 29         0.3.2 bug fixes to the ioclts and merged with ALPHA0.99-pl12
 30                    (Jon Tombs <jon@robots.ox.ac.uk>)
 31         0.3.3 Added more #defines and mcd_setup()
 32                    (Jon Tombs <jon@gtex02.us.es>)
 33 */
 34 
 35 
 36 #include <linux/errno.h>
 37 #include <linux/signal.h>
 38 #include <linux/sched.h>
 39 #include <linux/timer.h>
 40 #include <linux/fs.h>
 41 #include <linux/kernel.h>
 42 #include <linux/cdrom.h>
 43 #include <linux/ioport.h>
 44 
 45 /* #define REALLY_SLOW_IO  */
 46 #include <asm/system.h>
 47 #include <asm/io.h>
 48 #include <asm/segment.h>
 49 
 50 #define MAJOR_NR MITSUMI_CDROM_MAJOR
 51 #include "blk.h"
 52 #include <linux/mcd.h>
 53 
 54 #if 0
 55 static int mcd_sizes[] = { 0 };
 56 #endif
 57 
 58 static int mcdPresent = 0;
 59 
 60 static char mcd_buf[2048];      /* buffer for block size conversion */
 61 static int   mcd_bn   = -1;
 62 static short mcd_port = MCD_BASE_ADDR;
 63 static int   mcd_irq  = MCD_INTR_NR;
 64 
 65 static int McdTimeout, McdTries;
 66 static struct wait_queue *mcd_waitq = NULL;
 67 
 68 static struct mcd_DiskInfo DiskInfo;
 69 static struct mcd_Toc Toc[MAX_TRACKS];
 70 static struct mcd_Play_msf mcd_Play;
 71 
 72 static int audioStatus;
 73 static char mcdDiskChanged;
 74 static char tocUpToDate;
 75 static char mcdVersion;
 76 
 77 static void mcd_transfer(void);
 78 static void mcd_start(void);
 79 static void mcd_status(void);
 80 static void mcd_read_cmd(void);
 81 static void mcd_data(void);
 82 static void do_mcd_request(void);
 83 static void hsg2msf(long hsg, struct msf *msf);
 84 static void bin2bcd(unsigned char *p);
 85 static int bcd2bin(unsigned char bcd);
 86 static int mcdStatus(void);
 87 static void sendMcdCmd(int cmd, struct mcd_Play_msf *params);
 88 static int getMcdStatus(int timeout);
 89 static int GetQChannelInfo(struct mcd_Toc *qp);
 90 static int updateToc(void);
 91 static int GetDiskInfo(void);
 92 static int GetToc(void);
 93 static int getValue(unsigned char *result);
 94 
 95 
 96 void mcd_setup(char *str, int *ints)
 97 {
 98    if (ints[0] > 0)
 99       mcd_port = ints[1];
100    if (ints[0] > 1)      
101       mcd_irq  = ints[2];
102 }
103 
104  
105 int
106 check_mcd_media_change(int full_dev, int flag)
107 {
108    int retval, target;
109 
110 
111 #if 1    /* the below is not reliable */
112    return 0;
113 #endif  
114    target = MINOR(full_dev);
115 
116    if (target > 0) {
117       printk("mcd: Mitsumi CD-ROM request error: invalid device.\n");
118       return 0;
119    }
120 
121    retval = mcdDiskChanged;
122    if (!flag)
123    {
124       mcdDiskChanged = 0;
125    }
126 
127    return retval;
128 }
129 
130 
131 /*
132  * Do a 'get status' command and get the result.  Only use from the top half
133  * because it calls 'getMcdStatus' which sleeps.
134  */
135 
136 static int
137 statusCmd(void)
138 {
139         int st, retry;
140 
141         for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
142         {
143 
144                 outb(MCMD_GET_STATUS, MCDPORT(0));      /* send get-status cmd */
145                 st = getMcdStatus(MCD_STATUS_DELAY);
146                 if (st != -1)
147                         break;
148         }
149 
150         return st;
151 }
152 
153 
154 /*
155  * Send a 'Play' command and get the status.  Use only from the top half.
156  */
157 
158 static int
159 mcdPlay(struct mcd_Play_msf *arg)
160 {
161         int retry, st;
162 
163         for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
164         {
165                 sendMcdCmd(MCMD_PLAY_READ, arg);
166                 st = getMcdStatus(2 * MCD_STATUS_DELAY);
167                 if (st != -1)
168                         break;
169         }
170 
171         return st;
172 }
173 
174 
175 long
176 msf2hsg(struct msf *mp)
177 {
178         return bcd2bin(mp -> frame)
179                 + bcd2bin(mp -> sec) * 75
180                 + bcd2bin(mp -> min) * 4500
181                 - 150;
182 }
183 
184 
185 static int
186 mcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd,
187                                                 unsigned long arg)
188 {
189         int i, st;
190         struct mcd_Toc qInfo;
191         struct cdrom_ti ti;
192         struct cdrom_tochdr tocHdr;
193         struct cdrom_msf msf;
194         struct cdrom_tocentry entry;
195         struct mcd_Toc *tocPtr;
196         struct cdrom_subchnl subchnl;
197 #if 0
198         struct cdrom_volctrl volctrl;
199 #endif
200 
201         if (!ip)
202                 return -EINVAL;
203 
204         st = statusCmd();
205         if (st < 0)
206                 return -EIO;
207 
208         if (!tocUpToDate)
209         {
210                 i = updateToc();
211                 if (i < 0)
212                         return i;       /* error reading TOC */
213         }
214 
215         switch (cmd)
216         {
217         case CDROMSTART:     /* Spin up the drive */
218                 /* Don't think we can do this.  Even if we could,
219                  * I think the drive times out and stops after a while
220                  * anyway.  For now, ignore it.
221                  */
222 
223                 return 0;
224 
225         case CDROMSTOP:      /* Spin down the drive */
226                 outb(MCMD_STOP, MCDPORT(0));
227                 i = getMcdStatus(MCD_STATUS_DELAY);
228 
229                 /* should we do anything if it fails? */
230 
231                 audioStatus = CDROM_AUDIO_NO_STATUS;
232                 return 0;
233 
234         case CDROMPAUSE:     /* Pause the drive */
235                 if (audioStatus != CDROM_AUDIO_PLAY)
236                         return -EINVAL;
237 
238                 outb(MCMD_STOP, MCDPORT(0));
239                 i = getMcdStatus(MCD_STATUS_DELAY);
240 
241                 if (GetQChannelInfo(&qInfo) < 0)
242                 {
243                         /* didn't get q channel info */
244 
245                         audioStatus = CDROM_AUDIO_NO_STATUS;
246                         return 0;
247                 }
248 
249                 mcd_Play.start = qInfo.diskTime;        /* remember restart point */
250 
251                 audioStatus = CDROM_AUDIO_PAUSED;
252                 return 0;
253 
254         case CDROMRESUME:    /* Play it again, Sam */
255                 if (audioStatus != CDROM_AUDIO_PAUSED)
256                         return -EINVAL;
257 
258                 /* restart the drive at the saved position. */
259 
260                 i = mcdPlay(&mcd_Play);
261                 if (i < 0)
262                 {
263                         audioStatus = CDROM_AUDIO_ERROR;
264                         return -EIO;
265                 }
266 
267                 audioStatus = CDROM_AUDIO_PLAY;
268                 return 0;
269 
270         case CDROMPLAYTRKIND:     /* Play a track.  This currently ignores index. */
271 
272                 st = verify_area(VERIFY_READ, (void *) arg, sizeof ti);
273                 if (st)
274                         return st;
275 
276                 memcpy_fromfs(&ti, (void *) arg, sizeof ti);
277 
278                 if (ti.cdti_trk0 < DiskInfo.first
279                         || ti.cdti_trk0 > DiskInfo.last
280                         || ti.cdti_trk1 < ti.cdti_trk0)
281                 {
282                         return -EINVAL;
283                 }
284 
285                 if (ti.cdti_trk1 > DiskInfo.last)
286                         ti. cdti_trk1 = DiskInfo.last;
287 
288                 mcd_Play.start = Toc[ti.cdti_trk0].diskTime;
289                 mcd_Play.end = Toc[ti.cdti_trk1 + 1].diskTime;
290 
291 #ifdef MCD_DEBUG
292 printk("play: %02x:%02x.%02x to %02x:%02x.%02x\n",
293         mcd_Play.start.min, mcd_Play.start.sec, mcd_Play.start.frame,
294         mcd_Play.end.min, mcd_Play.end.sec, mcd_Play.end.frame);
295 #endif
296 
297                 i = mcdPlay(&mcd_Play);
298                 if (i < 0)
299                 {
300                         audioStatus = CDROM_AUDIO_ERROR;
301                         return -EIO;
302                 }
303 
304                 audioStatus = CDROM_AUDIO_PLAY;
305                 return 0;
306 
307         case CDROMPLAYMSF:   /* Play starting at the given MSF address. */
308 
309                 if (audioStatus == CDROM_AUDIO_PLAY) {
310                   outb(MCMD_STOP, MCDPORT(0));
311                   i = getMcdStatus(MCD_STATUS_DELAY);
312                   audioStatus = CDROM_AUDIO_NO_STATUS;
313                 }
314 
315                 st = verify_area(VERIFY_READ, (void *) arg, sizeof msf);
316                 if (st)
317                         return st;
318 
319                 memcpy_fromfs(&msf, (void *) arg, sizeof msf);
320 
321                 /* convert to bcd */
322 
323                 bin2bcd(&msf.cdmsf_min0);
324                 bin2bcd(&msf.cdmsf_sec0);
325                 bin2bcd(&msf.cdmsf_frame0);
326                 bin2bcd(&msf.cdmsf_min1);
327                 bin2bcd(&msf.cdmsf_sec1);
328                 bin2bcd(&msf.cdmsf_frame1);
329 
330                 mcd_Play.start.min = msf.cdmsf_min0;
331                 mcd_Play.start.sec = msf.cdmsf_sec0;
332                 mcd_Play.start.frame = msf.cdmsf_frame0;
333                 mcd_Play.end.min = msf.cdmsf_min1;
334                 mcd_Play.end.sec = msf.cdmsf_sec1;
335                 mcd_Play.end.frame = msf.cdmsf_frame1;
336 
337 #ifdef MCD_DEBUG
338 printk("play: %02x:%02x.%02x to %02x:%02x.%02x\n",
339 mcd_Play.start.min, mcd_Play.start.sec, mcd_Play.start.frame,
340 mcd_Play.end.min, mcd_Play.end.sec, mcd_Play.end.frame);
341 #endif
342 
343                 i = mcdPlay(&mcd_Play);
344                 if (i < 0)
345                 {
346                         audioStatus = CDROM_AUDIO_ERROR;
347                         return -EIO;
348                 }
349 
350                 audioStatus = CDROM_AUDIO_PLAY;
351                 return 0;
352 
353         case CDROMREADTOCHDR:        /* Read the table of contents header */
354                 st = verify_area(VERIFY_WRITE, (void *) arg, sizeof tocHdr);
355                 if (st)
356                         return st;
357 
358                 tocHdr.cdth_trk0 = DiskInfo.first;
359                 tocHdr.cdth_trk1 = DiskInfo.last;
360                 memcpy_tofs((void *) arg, &tocHdr, sizeof tocHdr);
361                 return 0;
362 
363         case CDROMREADTOCENTRY:      /* Read an entry in the table of contents */
364 
365                 st = verify_area(VERIFY_WRITE, (void *) arg, sizeof entry);
366                 if (st)
367                         return st;
368 
369                 memcpy_fromfs(&entry, (void *) arg, sizeof entry);
370                 if (entry.cdte_track == CDROM_LEADOUT)
371                         /* XXX */
372                         tocPtr = &Toc[DiskInfo.last + 1];
373 
374                 else if (entry.cdte_track > DiskInfo.last
375                                 || entry.cdte_track < DiskInfo.first)
376                         return -EINVAL;
377 
378                 else
379                         tocPtr = &Toc[entry.cdte_track];
380 
381                 entry.cdte_adr = tocPtr -> ctrl_addr;
382                 entry.cdte_ctrl = tocPtr -> ctrl_addr >> 4;
383 
384                 if (entry.cdte_format == CDROM_LBA)
385                         entry.cdte_addr.lba = msf2hsg(&tocPtr -> diskTime);
386 
387                 else if (entry.cdte_format == CDROM_MSF)
388                 {
389                         entry.cdte_addr.msf.minute = bcd2bin(tocPtr -> diskTime.min);
390                         entry.cdte_addr.msf.second = bcd2bin(tocPtr -> diskTime.sec);
391                         entry.cdte_addr.msf.frame = bcd2bin(tocPtr -> diskTime.frame);
392                 }
393 
394                 else
395                         return -EINVAL;
396 
397                 memcpy_tofs((void *) arg, &entry, sizeof entry);
398                 return 0;
399 
400         case CDROMSUBCHNL:   /* Get subchannel info */
401 
402                 st = verify_area(VERIFY_WRITE, (void *) arg, sizeof subchnl);
403                 if (st)
404                         return st;
405 
406                 memcpy_fromfs(&subchnl, (void *) arg, sizeof subchnl);
407 
408                 if (GetQChannelInfo(&qInfo) < 0)
409                         return -EIO;
410 

⌨️ 快捷键说明

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