COMPLETE.TXT
上传用户:jnzhq888
上传日期:2007-01-18
资源大小:51694k
文件大小:2624k
源码类别:

操作系统开发

开发平台:

WINDOWS

  1. 22076 #define MCD_DISK_IN             0x40    /* Disk is in */
  2. 22077 #define MCD_DOOR_OPEN           0x80    /* Door is open */
  3. 22078
  4. 22079 /* Flag bits */
  5. 22080 #define MCD_DATA_AVAILABLE      0x02    /* Data available */
  6. 22081 #define MCD_BUSY                0x04    /* Drive is busy */
  7. 22082
  8. 22083 /* Function prototypes */
  9. 22084 FORWARD _PROTOTYPE ( int mcd_init, (void));
  10. 22085 FORWARD _PROTOTYPE ( int c_handler, (int irq));
  11. 22086 FORWARD _PROTOTYPE ( int mcd_play_mss, (struct cd_play_mss));
  12. 22087 FORWARD _PROTOTYPE ( int mcd_play_tracks, (struct cd_play_track tracks));
  13. 22088 FORWARD _PROTOTYPE ( int mcd_stop, (void));
  14. 22089 FORWARD _PROTOTYPE ( int mcd_eject, (void));
  15. 22090 FORWARD _PROTOTYPE ( int mcd_pause, (void));
  16. 22091 FORWARD _PROTOTYPE ( int mcd_resume, (void));
  17. 22092 FORWARD _PROTOTYPE ( u8_t bin2bcd, (u8_t b));
  18. 22093 FORWARD _PROTOTYPE ( void bcd2bin, (u8_t *bcd));
  19. 22094 FORWARD _PROTOTYPE ( long mss2block, (u8_t *mss));
  20. 22095 FORWARD _PROTOTYPE ( void block2mss, (long block, u8_t *mss));
  21. 22096 FORWARD _PROTOTYPE ( int mcd_get_reply, (u8_t *reply, int delay));
  22. 22097 FORWARD _PROTOTYPE ( int mcd_get_status, (int f));
  23. 22098 FORWARD _PROTOTYPE ( int mcd_ready, (int delay));
  24. 22099 FORWARD _PROTOTYPE ( int mcd_data_ready, (int delay));
  25. 22100 FORWARD _PROTOTYPE ( int mcd_set_mode, (int mode));
  26. 22101 FORWARD _PROTOTYPE ( int mcd_send_command, (int command));
  27. 22102 FORWARD _PROTOTYPE ( int mcd_get_disk_info, (void));
  28. 22103 FORWARD _PROTOTYPE ( int mcd_read_q_channel, (struct cd_toc_entry *qc));
  29. 22104 FORWARD _PROTOTYPE ( int mcd_read_toc, (void));
  30. 22105 FORWARD _PROTOTYPE ( int ioctl_read_toc, (message *m_ptr));
  31. 22106 FORWARD _PROTOTYPE ( int ioctl_disk_info, (message *m_ptr));
  32. 22107 FORWARD _PROTOTYPE ( int ioctl_read_sub, (message *m_ptr));
  33. 22108 FORWARD _PROTOTYPE ( int ioctl_disk_info, (message *m_ptr));
  34. 22109 FORWARD _PROTOTYPE ( int ioctl_play_mss, (message *m_ptr));
  35. 22110 FORWARD _PROTOTYPE ( int ioctl_play_ti, (message *m_ptr));
  36. 22111 FORWARD _PROTOTYPE ( int mcd_open, (struct driver *dp, message *m_ptr));
  37. 22112 FORWARD _PROTOTYPE ( int mcd_close, (struct driver *dp, message *m_ptr));
  38. 22113 FORWARD _PROTOTYPE ( int mcd_ioctl, (struct driver *dp, message *m_ptr));
  39. 22114 FORWARD _PROTOTYPE ( char *mcd_name, (void));
  40. 22115 FORWARD _PROTOTYPE ( struct device *mcd_prepare, (int dev));
  41. 22116 FORWARD _PROTOTYPE ( int mcd_schedule, (int proc_nr, struct iorequest_s *iop));
  42. 22117 FORWARD _PROTOTYPE ( int mcd_finish, (void));
  43. 22118 FORWARD _PROTOTYPE ( void mcd_geometry, (struct partition *entry));
  44. 22119
  45. 22120
  46. 22121 /* Flags displaying current status of cdrom, used with the McdStatus variable */
  47. 22122 #define TOC_UPTODATE   0x001     /* Table of contents is up to date */
  48. 22123 #define INFO_UPTODATE  0x002     /* Disk info is up to date */
  49. 22124 #define DISK_CHANGED   0x004     /* Disk has changed */
  50. 22125 #define AUDIO_PLAYING  0x008     /* Cdrom is playing audio */
  51. 22126 #define AUDIO_PAUSED   0x010     /* Cdrom is paused (only audio) */
  52. 22127 #define AUDIO_DISK     0x020     /* Disk contains audio */
  53. 22128 #define DISK_ERROR     0x040     /* An error occured */
  54. 22129 #define NO_DISK        0x080     /* No disk in device */
  55. 22130
  56. 22131 /* Entry points to this driver. */
  57. 22132 PRIVATE struct driver mcd_dtab = 
  58. 22133 {
  59. 22134 #if __minix_vmd
  60. 22135   NULL,         /* No private request buffer */
  61. 22136 #endif
  62. 22137   mcd_name,     /* Current device's name */
  63. 22138   mcd_open,     /* Open request read table of contents */
  64. 22139   mcd_close,    /* Release device */
  65. 22140   mcd_ioctl,    /* Do cdrom ioctls */
  66. 22141   mcd_prepare,  /* Prepare for I/O */
  67. 22142   mcd_schedule, /* Precompute blocks */
  68. 22143   mcd_finish,   /* Do the I/O */
  69. 22144   nop_cleanup,  /* No cleanup to do */
  70. 22145   mcd_geometry  /* Tell geometry */
  71. 22146 };
  72. 22147
  73. 22148
  74. 22149 PRIVATE struct trans 
  75. 22150 {
  76. 22151   struct iorequest_s *tr_iop;   /* Belongs to this I/O request */
  77. 22152   unsigned long tr_pos;         /* Byte position to transfer from */
  78. 22153   int tr_count;                 /* Byte count */
  79. 22154   phys_bytes tr_phys;           /* User physical address */
  80. 22155 } mcd_trans[NR_IOREQS];
  81. 22156
  82. 22157
  83. 22158 /* Globals */
  84. 22159 #if __minix_vmd
  85. 22160 PRIVATE int mcd_tasknr = ANY;
  86. 22161 #endif
  87. 22162 PRIVATE int mcd_avail;                  /* Set if Mitsumi device exists */
  88. 22163 PRIVATE int mcd_irq;                    /* Interrupt request line */
  89. 22164 PRIVATE int mcd_io_base;                /* I/O base register */
  90. 22165 PRIVATE struct device *mcd_dv;          /* Active partition */
  91. 22166 PRIVATE struct trans *mcd_tp;           /* Pointer to add transfer requests */
  92. 22167 PRIVATE unsigned mcd_count;             /* Number of bytes to transfer */
  93. 22168 PRIVATE unsigned long mcd_nextpos;      /* Next consecutive position on disk */
  94. 22169 PRIVATE struct device mcd_part[DEV_PER_DRIVE];
  95. 22170                                         /* Primary partitions: cd[0-4] */
  96. 22171 PRIVATE struct device mcd_subpart[SUB_PER_DRIVE];
  97. 22172                                         /* Subpartitions: cd[1-4][a-d] */
  98. 22173 PRIVATE int mcd_open_ct;                /* in-use count */
  99. 22174 PRIVATE int McdStatus = NO_DISK;        /* A new (or no) disk is inserted */ 
  100. 22175 PRIVATE struct cd_play_mss PlayMss;     /* Keep track of where we are if we
  101. 22176                                            pause, used by resume */ 
  102. 22177 PRIVATE struct cd_disk_info DiskInfo;   /* Contains toc header */  
  103. 22178 PRIVATE struct cd_toc_entry Toc[MAX_TRACKS];  /* Buffer for toc */
  104. 22179
  105. 22180
  106. 22181
  107. 22182 /*=========================================================================*
  108. 22183  *                              mcd_task                                   *
  109. 22184  *=========================================================================*/
  110. 22185 PUBLIC void mcd_task()
  111. 22186 {
  112. 22187   long v;
  113. 22188   static char var[] = "MCD";
  114. 22189   static char fmt[] = "x:d";
  115. 22190
  116. 22191 #if __minix_vmd
  117. 22192   mcd_tasknr = proc_number(proc_ptr);
  118. 22193 #endif
  119. 22194
  120. 22195   /* Configure I/O base and IRQ. */
  121. 22196   v = MCD_IO_BASE_ADDRESS;
  122. 22197   (void) env_parse(var, fmt, 0, &v, 0x000L, 0x3FFL);
  123. 22198   mcd_io_base = v;
  124. 22199
  125. 22200   v = MCD_IRQ;
  126. 22201   (void) env_parse(var, fmt, 0, &v, 0L, (long) NR_IRQ_VECTORS - 1);
  127. 22202   mcd_irq = v;
  128. 22203
  129. 22204   driver_task(&mcd_dtab);       /* Start driver task for cdrom */
  130. 22205 }
  131. 22208 /*=========================================================================*
  132. 22209  *                              mcd_open                                   *    
  133. 22210  *=========================================================================*/
  134. 22211 PRIVATE int mcd_open(dp, m_ptr)
  135. 22212 struct driver *dp;      /* pointer to this drive */
  136. 22213 message *m_ptr;         /* OPEN */
  137. 22214 {
  138. 22215   int i, status;
  139. 22216
  140. 22217   if (!mcd_avail && mcd_init() != OK) return EIO;
  141. 22218
  142. 22219   if (mcd_prepare(m_ptr->DEVICE) == NIL_DEV) return ENXIO;
  143. 22220
  144. 22221   /* A CD-ROM is read-only by definition. */
  145. 22222   if (m_ptr->COUNT & W_BIT) return EACCES;
  146. 22223
  147. 22224   if (mcd_open_ct == 0)
  148. 22225   {
  149. 22226     i = 20;
  150. 22227     for (;;) {
  151. 22228       if (mcd_get_status(1) == -1) return EIO;   /* set McdStatus flags */
  152. 22229       if (!(McdStatus & NO_DISK)) break;
  153. 22230       if (--i == 0) return EIO;
  154. 22231       milli_delay(100);
  155. 22232     }
  156. 22233
  157. 22234     /* Try to read the table of contents of the CD currently inserted */
  158. 22235     if ((status = mcd_read_toc()) != OK)  
  159. 22236       return status;
  160. 22237
  161. 22238     mcd_open_ct++;
  162. 22239
  163. 22240     /* fill in size of device (= nr. of bytes on the disk) */
  164. 22241     mcd_part[0].dv_base = 0;
  165. 22242     mcd_part[0].dv_size = 
  166. 22243      ((((unsigned long)DiskInfo.disk_length_mss[MINUTES] * SECONDS_PER_MINUTE
  167. 22244       + (unsigned long)DiskInfo.disk_length_mss[SECONDS]) * SECTORS_PER_SECOND)
  168. 22245       + (unsigned long)DiskInfo.disk_length_mss[SECTOR]) * BYTES_PER_SECTOR; 
  169. 22246
  170. 22247 #if MCD_DEBUG >= 1
  171. 22248     printf("cd size: %lun", mcd_part[0].dv_size);
  172. 22249 #endif
  173. 22250
  174. 22251     /* Partition the disk. */
  175. 22252     partition(&mcd_dtab, 0, P_PRIMARY);
  176. 22253   }
  177. 22254   return OK;
  178. 22255 }
  179. 22258 /*=========================================================================*
  180. 22259  *                              mcd_close                                  *    
  181. 22260  *=========================================================================*/
  182. 22261 PRIVATE int mcd_close(dp, m_ptr)
  183. 22262 struct driver *dp;      /* pointer to this drive */
  184. 22263 message *m_ptr;         /* CLOSE */
  185. 22264 {
  186. 22265   /* One less reference to the device */
  187. 22266
  188. 22267   mcd_open_ct--;
  189. 22268   return OK;
  190. 22269 }
  191. 22272 /*=========================================================================*
  192. 22273  *                              mcd_name                                   *    
  193. 22274  *=========================================================================*/
  194. 22275 PRIVATE char *mcd_name()
  195. 22276 {
  196. 22277   /* Return a name for the device */
  197. 22278
  198. 22279   return "cd0";
  199. 22280 }
  200. 22283 /*=========================================================================*
  201. 22284  *                              mcd_ioctl                                  *    
  202. 22285  *=========================================================================*/
  203. 22286 PRIVATE int mcd_ioctl(dp, m_ptr)
  204. 22287 struct driver *dp;      /* pointer to the drive */
  205. 22288 message *m_ptr;         /* contains ioctl command */
  206. 22289 {
  207. 22290   /* Perform the ioctl request */
  208. 22291
  209. 22292   int status;
  210. 22293
  211. 22294   if (mcd_prepare(m_ptr->DEVICE) == NIL_DEV) return(ENXIO);
  212. 22295
  213. 22296   mcd_get_status(1);    /* Update the status flags */
  214. 22297   if ((McdStatus & NO_DISK) && m_ptr->REQUEST != CDIOEJECT)
  215. 22298     return EIO;
  216. 22299
  217. 22300   switch(m_ptr->REQUEST)
  218. 22301   {
  219. 22302     case CDIOPLAYMSS:     status = ioctl_play_mss(m_ptr);break;
  220. 22303     case CDIOPLAYTI:      status = ioctl_play_ti(m_ptr);break;
  221. 22304     case CDIOREADTOCHDR:  status = ioctl_disk_info(m_ptr);break;
  222. 22305     case CDIOREADTOC:     status = ioctl_read_toc(m_ptr);break;
  223. 22306     case CDIOREADSUBCH:   status = ioctl_read_sub(m_ptr);break;
  224. 22307     case CDIOSTOP:        status = mcd_stop();break;
  225. 22308     case CDIOPAUSE:       status = mcd_pause();break;
  226. 22309     case CDIORESUME:      status = mcd_resume();break;
  227. 22310     case CDIOEJECT:       status = mcd_eject();break;
  228. 22311     default:              status = do_diocntl(dp, m_ptr);
  229. 22312   }
  230. 22313   return status;
  231. 22314 }
  232. 22317 /*=========================================================================*
  233. 22318  *                              mcd_get_reply                              *    
  234. 22319  *=========================================================================*/
  235. 22320 PRIVATE int mcd_get_reply(reply, delay)
  236. 22321 u8_t *reply;            /* variable to put reply in */
  237. 22322 int delay;              /* count to wait for the reply */
  238. 22323 {
  239. 22324   /* Get a reply from the drive */
  240. 22325
  241. 22326   if (mcd_ready(delay) != OK) return EIO;           /* wait for drive to 
  242. 22327                                                        become available */
  243. 22328   *reply = in_byte(MCD_DATA_PORT);      /* get the reply */
  244. 22329   return OK;
  245. 22330 }
  246. 22333 /*=========================================================================*
  247. 22334  *                              mcd_ready                                  *    
  248. 22335  *=========================================================================*/
  249. 22336 PRIVATE int mcd_ready(delay)
  250. 22337 int delay;   /* count to wait for drive to become available again */
  251. 22338 {
  252. 22339   /* Wait for drive to become available */
  253. 22340
  254. 22341   struct milli_state ms;
  255. 22342
  256. 22343   milli_start(&ms);
  257. 22344   do
  258. 22345   {
  259. 22346     if (!(in_byte(MCD_FLAG_PORT) & MCD_BUSY)) return OK; /* OK, drive ready */
  260. 22347   } while(milli_elapsed(&ms) < delay);
  261. 22348
  262. 22349   return EIO; /* Timeout */
  263. 22350 }
  264. 22353 /*=========================================================================*
  265. 22354  *                              mcd_data_ready                             *    
  266. 22355  *=========================================================================*/
  267. 22356 PRIVATE int mcd_data_ready(delay)
  268. 22357 int delay;      /* count to wait for the data */
  269. 22358 {
  270. 22359   /* Wait for the drive to get the data */
  271. 22360
  272. 22361   struct milli_state ms;
  273. 22362
  274. 22363   milli_start(&ms);
  275. 22364   do
  276. 22365   {
  277. 22366     if (!(in_byte(MCD_FLAG_PORT) & 2)) return OK; /* OK, data is there */
  278. 22367   } while(milli_elapsed(&ms) < delay);
  279. 22368
  280. 22369   return EIO;  /* Timeout */
  281. 22370 }
  282. 22373 /*=========================================================================*
  283. 22374  *                              mcd_get_status                             *    
  284. 22375  *=========================================================================*/
  285. 22376 PRIVATE int mcd_get_status(f)
  286. 22377 int f;          /* flag */
  287. 22378 {
  288. 22379   /* Return status info from the drive and update the global McdStatus */
  289. 22380
  290. 22381   u8_t status;
  291. 22382
  292. 22383   /* If f = 1, we first send a get_status command, otherwise we just get
  293. 22384      the status info from the drive */ 
  294. 22385
  295. 22386   if (f) out_byte(MCD_DATA_PORT, MCD_GET_STATUS);        /* Try to get status */
  296. 22387   if (mcd_get_reply(&status,REPLY_DELAY) != OK) return -1; 
  297. 22388
  298. 22389   McdStatus &= ~(NO_DISK | DISK_CHANGED | DISK_ERROR);
  299. 22390
  300. 22391   /* Fill in the McdStatus variable */
  301. 22392   if (status & MCD_DOOR_OPEN ||
  302. 22393      !(status & MCD_DISK_IN))         McdStatus = NO_DISK;  
  303. 22394   else if (status & MCD_DISK_CHANGED) McdStatus = DISK_CHANGED; 
  304. 22395   else if (status & MCD_READ_ERROR ||
  305. 22396            status & MCD_CMD_ERROR)    McdStatus = DISK_ERROR; 
  306. 22397   else 
  307. 22398   {
  308. 22399     if (status & MCD_AUDIO_DISK) 
  309. 22400     {
  310. 22401       McdStatus |= AUDIO_DISK;
  311. 22402       if (!(status & MCD_AUDIO_BUSY)) McdStatus &= ~(AUDIO_PLAYING); 
  312. 22403       else McdStatus |= AUDIO_PLAYING;
  313. 22404     }
  314. 22405   }
  315. 22406 #if MCD_DEBUG >= 3
  316. 22407   printf("mcd_get_status(%d) = %02x, McdStatus = %02xn",
  317. 22408         f, status, McdStatus);
  318. 22409 #endif
  319. 22410   return status;        /* Return status */
  320. 22411 }
  321. 22414 /*=========================================================================*
  322. 22415  *                              mcd_set_mode                               *    
  323. 22416  *=========================================================================*/
  324. 22417 PRIVATE int mcd_set_mode(mode)
  325. 22418 int mode; /* new drive mode */
  326. 22419 {
  327. 22420   /* Set drive mode */
  328. 22421
  329. 22422   int i;
  330. 22423
  331. 22424   for (i = 0; i < MCD_RETRIES; i++)
  332. 22425   {
  333. 22426     out_byte(MCD_DATA_PORT, MCD_SET_MODE); /* Send set mode command */
  334. 22427     out_byte(MCD_DATA_PORT, mode);         /* Send which mode */
  335. 22428     if (mcd_get_status(0) != -1 &&
  336. 22429          !(McdStatus & DISK_ERROR)) break; 
  337. 22430   }
  338. 22431   if (i == MCD_RETRIES) return EIO;        /* Operation failed */
  339. 22432
  340. 22433   return OK; /* Operation succeeded */
  341. 22434 }
  342. 22437 /*=========================================================================*
  343. 22438  *                              mcd_send_command                           *    
  344. 22439  *=========================================================================*/
  345. 22440 PRIVATE int mcd_send_command(command)
  346. 22441 int command;    /* command to send */
  347. 22442 {
  348. 22443   int i;
  349. 22444
  350. 22445   for (i = 0; i < MCD_RETRIES; i++)
  351. 22446   {
  352. 22447     out_byte(MCD_DATA_PORT, command);      /* send command */
  353. 22448     if (mcd_get_status(0) != -1 && 
  354. 22449          !(McdStatus & DISK_ERROR)) break; 
  355. 22450   }
  356. 22451   if (i == MCD_RETRIES) return EIO;        /* operation failed */
  357. 22452
  358. 22453   return OK;
  359. 22454 }
  360. 22457 /*=========================================================================*
  361. 22458  *                              mcd_init                                   *    
  362. 22459  *=========================================================================*/
  363. 22460 PRIVATE int mcd_init()
  364. 22461 {
  365. 22462   /* Initialize the drive and get the version bytes, this is done only
  366. 22463      once when the system gets up. We can't use mcd_ready because
  367. 22464      the clock task is not available yet.
  368. 22465    */
  369. 22466
  370. 22467   u8_t version[3];
  371. 22468   int i;
  372. 22469   u32_t n;
  373. 22470   struct milli_state ms;
  374. 22471
  375. 22472   /* Reset the flag port and remove all pending data, if we do
  376. 22473    * not do this properly the drive won't cooperate.
  377. 22474    */
  378. 22475   out_byte(MCD_FLAG_PORT, 0x00);        
  379. 22476   for (n = 0; n < 1000000; n++)
  380. 22477     (void) in_byte(MCD_FLAG_PORT);
  381. 22478
  382. 22479   /* Now see if the drive will report its status */
  383. 22480   if (mcd_get_status(1) == -1)
  384. 22481   {
  385. 22482     /* Too bad, drive will not listen */
  386. 22483     printf("%s: init failed, no Mitsumi cdrom presentn", mcd_name());
  387. 22484     return -1; 
  388. 22485   }
  389. 22486
  390. 22487   /* Find out drive version */
  391. 22488   out_byte(MCD_DATA_PORT, MCD_GET_VERSION);
  392. 22489   milli_start(&ms);
  393. 22490   for (i = 0; i < 3; i++)
  394. 22491   {
  395. 22492     while (in_byte(MCD_FLAG_PORT) & MCD_BUSY)
  396. 22493     {
  397. 22494       if (milli_elapsed(&ms) >= 1000) 
  398. 22495       {
  399. 22496         printf("%s: can't get version of Mitsumi cdromn", mcd_name());
  400. 22497         return -1;
  401. 22498       }
  402. 22499     }
  403. 22500     version[i] = in_byte(MCD_DATA_PORT);
  404. 22501   }
  405. 22502  
  406. 22503   if (version[1] == 'D')
  407. 22504     printf("%s: Mitsumi FX001D CD-ROMn", mcd_name());
  408. 22505   else 
  409. 22506     printf("%s: Mitsumi CD-ROM version %02x%02x%02xn", mcd_name(), 
  410. 22507             version[0], version[1], version[2]);
  411. 22508
  412. 22509   /* Newer drive models need this */
  413. 22510   if (version[1] >= 4) out_byte(MCD_CONTROL_PORT, MCD_PICKLE);
  414. 22511
  415. 22512   /* Register interrupt vector and enable interrupt 
  416. 22513    * currently the interrupt is not used because
  417. 22514    * the controller isn't set up to do dma.  XXX
  418. 22515    */
  419. 22516   put_irq_handler(mcd_irq, c_handler);
  420. 22517   enable_irq(mcd_irq);
  421. 22518
  422. 22519   mcd_avail = 1;
  423. 22520   return OK;
  424. 22521 }
  425. 22524 /*=========================================================================*
  426. 22525  *                              c_handler                                  *    
  427. 22526  *=========================================================================*/
  428. 22527 PRIVATE int c_handler(irq)
  429. 22528 int irq;        /* irq number */
  430. 22529 {
  431. 22530   /* The interrupt handler, I never got an interrupt but its here just
  432. 22531    * in case...
  433. 22532    */
  434. 22533
  435. 22534   /* Send interrupt message to cdrom task */
  436. 22535 #if XXX
  437. 22536 #if __minix_vmd
  438. 22537   interrupt(mcd_tasknr);
  439. 22538 #else
  440. 22539   interrupt(CDROM);
  441. 22540 #endif
  442. 22541 #endif
  443. 22542
  444. 22543   return 1;
  445. 22544 }
  446. 22547 /*=========================================================================*
  447. 22548  *                              mcd_play_mss                               *    
  448. 22549  *=========================================================================*/
  449. 22550 PRIVATE int mcd_play_mss(mss)
  450. 22551 struct cd_play_mss mss;  /* from where to play minute:second.sector */
  451. 22552 {
  452. 22553   /* Command the drive to start playing at min:sec.sector */
  453. 22554
  454. 22555   int i;
  455. 22556
  456. 22557 #if MCD_DEBUG >= 1
  457. 22558   printf("Play_mss: begin: %02d:%02d.%02d  end: %02d:%02d.%02dn",
  458. 22559           mss.begin_mss[MINUTES], mss.begin_mss[SECONDS],
  459. 22560           mss.begin_mss[SECTOR], mss.end_mss[MINUTES], 
  460. 22561           mss.end_mss[SECONDS], mss.end_mss[SECTOR]); 
  461. 22562 #endif
  462. 22563
  463. 22564   for (i=0; i < MCD_RETRIES; i++)     /* Try it more than once */
  464. 22565   {
  465. 22566     lock();        /* No interrupts when we issue this command */
  466. 22567
  467. 22568     /* Send command with paramters to drive */
  468. 22569     out_byte(MCD_DATA_PORT, MCD_READ_FROM_TO);
  469. 22570     out_byte(MCD_DATA_PORT, bin2bcd(mss.begin_mss[MINUTES]));
  470. 22571     out_byte(MCD_DATA_PORT, bin2bcd(mss.begin_mss[SECONDS]));
  471. 22572     out_byte(MCD_DATA_PORT, bin2bcd(mss.begin_mss[SECTOR]));
  472. 22573     out_byte(MCD_DATA_PORT, bin2bcd(mss.end_mss[MINUTES]));
  473. 22574     out_byte(MCD_DATA_PORT, bin2bcd(mss.end_mss[SECONDS]));
  474. 22575     out_byte(MCD_DATA_PORT, bin2bcd(mss.end_mss[SECTOR]));
  475. 22576
  476. 22577     unlock();      /* Enable interrupts again */
  477. 22578
  478. 22579     mcd_get_status(0);                    /* See if all went well */
  479. 22580     if (McdStatus & AUDIO_PLAYING) break; /* Ok, we're playing */
  480. 22581   }
  481. 22582
  482. 22583   if (i == MCD_RETRIES) return EIO;       /* Command failed */
  483. 22584
  484. 22585   /* keep in mind where we going in case of a future resume */
  485. 22586   PlayMss.end_mss[MINUTES] = mss.end_mss[MINUTES];
  486. 22587   PlayMss.end_mss[SECONDS] = mss.end_mss[SECONDS];
  487. 22588   PlayMss.end_mss[SECTOR] = mss.end_mss[SECTOR];
  488. 22589
  489. 22590   McdStatus &= ~(AUDIO_PAUSED);
  490. 22591
  491. 22592   return(OK);
  492. 22593 }
  493. 22596 /*=========================================================================*
  494. 22597  *                              mcd_play_tracks                            *    
  495. 22598  *=========================================================================*/
  496. 22599 PRIVATE int mcd_play_tracks(tracks)
  497. 22600 struct cd_play_track tracks;     /* which tracks to play */
  498. 22601 {
  499. 22602   /* Command the drive to play tracks */
  500. 22603   
  501. 22604   int i, err;
  502. 22605   struct cd_play_mss mss;
  503. 22606
  504. 22607 #if MCD_DEBUG >= 1
  505. 22608   printf("Play tracks: begin: %02d end: %02dn",
  506. 22609            tracks.begin_track, tracks.end_track);
  507. 22610 #endif
  508. 22611
  509. 22612   /* First read the table of contents */
  510. 22613   if ((err = mcd_read_toc()) != OK) return err; 
  511. 22614  
  512. 22615   /* Check if parameters are valid */
  513. 22616   if (tracks.begin_track < DiskInfo.first_track ||
  514. 22617       tracks.end_track > DiskInfo.last_track ||
  515. 22618       tracks.begin_track > tracks.end_track)
  516. 22619     return EINVAL;
  517. 22620
  518. 22621
  519. 22622   /* Convert the track numbers to min:sec.sector */
  520. 22623   for (i=0; i<3; i++)
  521. 22624   {
  522. 22625     mss.begin_mss[i] = Toc[tracks.begin_track].position_mss[i]; 
  523. 22626     mss.end_mss[i] = Toc[tracks.end_track+1].position_mss[i]; 
  524. 22627   }
  525. 22628
  526. 22629   return(mcd_play_mss(mss));     /* Start playing */
  527. 22630 }
  528. 22633 /*=========================================================================*
  529. 22634  *                              mcd_get_disk_info                          *    
  530. 22635  *=========================================================================*/
  531. 22636 PRIVATE int mcd_get_disk_info()
  532. 22637 {
  533. 22638   /* Get disk info */
  534. 22639
  535. 22640   int i, err;
  536. 22641
  537. 22642   if (McdStatus & INFO_UPTODATE) return OK; /* No need to read info again */
  538. 22643
  539. 22644   /* Issue the get volume info command */
  540. 22645   if ((err = mcd_send_command(MCD_GET_VOL_INFO)) != OK) return err;
  541. 22646
  542. 22647   /* Fill global DiskInfo */
  543. 22648   for (i=0; i < sizeof(DiskInfo); i++) 
  544. 22649   {
  545. 22650     if ((err = mcd_get_reply((u8_t *)(&DiskInfo) + i, REPLY_DELAY)) !=OK)
  546. 22651       return err;
  547. 22652     bcd2bin((u8_t *)(&DiskInfo) + i);  
  548. 22653   }
  549. 22654
  550. 22655 #if MCD_DEBUG >= 1
  551. 22656   printf("Mitsumi disk info: first: %d last: %d first %02d:%02d.%02d length: %02d:%02d.%02dn",
  552. 22657       DiskInfo.first_track,
  553. 22658       DiskInfo.last_track,
  554. 22659       DiskInfo.first_track_mss[MINUTES],
  555. 22660       DiskInfo.first_track_mss[SECONDS],
  556. 22661       DiskInfo.first_track_mss[SECTOR],
  557. 22662       DiskInfo.disk_length_mss[MINUTES],        
  558. 22663       DiskInfo.disk_length_mss[SECONDS],        
  559. 22664       DiskInfo.disk_length_mss[SECTOR]);        
  560. 22665 #endif
  561. 22666
  562. 22667   /* Update global status info */
  563. 22668   McdStatus |= INFO_UPTODATE; /* toc header has been read */
  564. 22669   McdStatus &= ~TOC_UPTODATE; /* toc has not been read yet */
  565. 22670
  566. 22671   return OK;
  567. 22672 }
  568. 22676 /*=========================================================================*
  569. 22677  *                              mcd_read_q_channel                         *    
  570. 22678  *=========================================================================*/
  571. 22679 PRIVATE int mcd_read_q_channel(qc)
  572. 22680 struct cd_toc_entry *qc;  /* struct to return q-channel info in */
  573. 22681 {
  574. 22682   /* Read the qchannel info, if we we're already playing this returns
  575. 22683    * the relative position and the absolute position of where we are
  576. 22684    * in min:sec.sector. If we're not playing, this returns an entry
  577. 22685    * from the table of contents
  578. 22686    */
  579. 22687  
  580. 22688   int i, err; 
  581. 22689
  582. 22690   /* Issue the command */
  583. 22691   if ((err = mcd_send_command(MCD_GET_Q_CHANNEL)) != OK) return err;
  584. 22692
  585. 22693   /* Read the info */
  586. 22694   for (i=0; i < sizeof(struct cd_toc_entry); i++)
  587. 22695   {
  588. 22696     /* Return error on timeout */
  589. 22697     if ((err = mcd_get_reply((u8_t *)qc + i, REPLY_DELAY)) != OK) 
  590. 22698       return err;
  591. 22699
  592. 22700     bcd2bin((u8_t *)qc + i);  /* Convert value to binary */
  593. 22701   }
  594. 22702  
  595. 22703 #if MCD_DEBUG >= 2
  596. 22704   printf("qchannel info: ctl_addr: %d track: %d index: %d length %02d:%02d.%02d pos: %02d:%02d.%02dn",
  597. 22705       qc->control_address,
  598. 22706       qc->track_nr,
  599. 22707       qc->index_nr,
  600. 22708       qc->track_time_mss[MINUTES],      
  601. 22709       qc->track_time_mss[SECONDS],      
  602. 22710       qc->track_time_mss[SECTOR],
  603. 22711       qc->position_mss[MINUTES],        
  604. 22712       qc->position_mss[SECONDS],        
  605. 22713       qc->position_mss[SECTOR]);
  606. 22714 #endif
  607. 22715
  608. 22716   return OK;  /* All done */
  609. 22717 }
  610. 22720 /*=========================================================================*
  611. 22721  *                              mcd_read_toc                               *    
  612. 22722  *=========================================================================*/
  613. 22723 PRIVATE int mcd_read_toc()
  614. 22724 {
  615. 22725   /* Read the table of contents (TOC) */
  616. 22726
  617. 22727   struct cd_toc_entry q_info;
  618. 22728   int current_track, current_index;
  619. 22729   int err,i;
  620. 22730
  621. 22731
  622. 22732   if (McdStatus & TOC_UPTODATE) return OK; /* No need to read toc again */
  623. 22733         
  624. 22734   /* Clear toc table */
  625. 22735   for (i = 0; i < MAX_TRACKS; i++) Toc[i].index_nr = 0;                 
  626. 22736
  627. 22737   /* Read disk info */
  628. 22738   if ((err = mcd_get_disk_info()) != OK) return err;
  629. 22739
  630. 22740   /* Calculate track to start with */ 
  631. 22741   current_track = DiskInfo.last_track - DiskInfo.first_track + 1;
  632. 22742
  633. 22743   /* Set read toc mode */
  634. 22744   if ((err = mcd_set_mode(MCD_TOC)) != OK) return err;
  635. 22745
  636. 22746   /* Read the complete TOC, on every read-q-channel command we get a random
  637. 22747    * TOC entry depending on how far we are in the q-channel, collect entries
  638. 22748    * as long as we don't have the complete TOC. There's a limit of 600 here,
  639. 22749    * if we don't have the complete TOC after 600 reads we quit with an error
  640. 22750    */
  641. 22751   for (i = 0; (i < 600 && current_track > 0); i++)
  642. 22752   {
  643. 22753     /* Try to read a TOC entry */
  644. 22754     if ((err = mcd_read_q_channel(&q_info)) != OK) break;       
  645. 22755
  646. 22756     /* Is this a valid track number and didn't we have it yet ? */
  647. 22757     current_index = q_info.index_nr;    
  648. 22758     if (current_index >= DiskInfo.first_track &&
  649. 22759         current_index <= DiskInfo.last_track &&
  650. 22760         q_info.track_nr == 0)
  651. 22761     {
  652. 22762       /* Copy entry into toc table */
  653. 22763       if (Toc[current_index].index_nr == 0)
  654. 22764       {
  655. 22765         Toc[current_index].control_address = q_info.control_address;
  656. 22766         Toc[current_index].track_nr = current_index;
  657. 22767         Toc[current_index].index_nr = 1;
  658. 22768         Toc[current_index].track_time_mss[MINUTES] = q_info.track_time_mss[MINUTES];
  659. 22769         Toc[current_index].track_time_mss[SECONDS] = q_info.track_time_mss[SECONDS];
  660. 22770         Toc[current_index].track_time_mss[SECTOR] = q_info.track_time_mss[SECTOR];
  661. 22771         Toc[current_index].position_mss[MINUTES] = q_info.position_mss[MINUTES];
  662. 22772         Toc[current_index].position_mss[SECONDS] = q_info.position_mss[SECONDS];
  663. 22773         Toc[current_index].position_mss[SECTOR] = q_info.position_mss[SECTOR];
  664. 22774         current_track--;
  665. 22775       }
  666. 22776     }
  667. 22777   }
  668. 22778   if (err) return err;   /* Do we have all toc entries? */
  669. 22779
  670. 22780   /* Fill in lead out */
  671. 22781   current_index = DiskInfo.last_track + 1;
  672. 22782   Toc[current_index].control_address = 
  673. 22783                                   Toc[current_index-1].control_address;
  674. 22784   Toc[current_index].track_nr = 0;
  675. 22785   Toc[current_index].index_nr = LEAD_OUT;
  676. 22786   Toc[current_index].position_mss[MINUTES] = DiskInfo.disk_length_mss[MINUTES];
  677. 22787   Toc[current_index].position_mss[SECONDS] = DiskInfo.disk_length_mss[SECONDS];
  678. 22788   Toc[current_index].position_mss[SECTOR] = DiskInfo.disk_length_mss[SECTOR];
  679. 22789
  680. 22790   /* Return to cooked mode */
  681. 22791   if ((err = mcd_set_mode(MCD_COOKED)) != OK) return err; 
  682. 22792
  683. 22793   /* Update global status */
  684. 22794   McdStatus |= TOC_UPTODATE;
  685. 22795
  686. 22796 #if MCD_DEBUG >= 1
  687. 22797   for (i = DiskInfo.first_track; i <= current_index; i++)
  688. 22798   {
  689. 22799     printf("Mitsumi toc %d: trk %d  index %d  time %02d:%02d.%02d  pos: %02d:%02d.%02dn",
  690. 22800         i,
  691. 22801         Toc[i].track_nr,
  692. 22802         Toc[i].index_nr,
  693. 22803         Toc[i].track_time_mss[MINUTES],
  694. 22804         Toc[i].track_time_mss[SECONDS],
  695. 22805         Toc[i].track_time_mss[SECTOR],
  696. 22806         Toc[i].position_mss[MINUTES],
  697. 22807         Toc[i].position_mss[SECONDS],
  698. 22808         Toc[i].position_mss[SECTOR]);
  699. 22809   }
  700. 22810 #endif
  701. 22811
  702. 22812   return OK;
  703. 22813 }
  704. 22816 /*=========================================================================*
  705. 22817  *                              mcd_stop                                   *    
  706. 22818  *=========================================================================*/
  707. 22819 PRIVATE int mcd_stop()
  708. 22820 {
  709. 22821   int err;
  710. 22822
  711. 22823   if ((err = mcd_send_command(MCD_STOP)) != OK ) return err;
  712. 22824
  713. 22825   McdStatus &= ~(AUDIO_PAUSED);
  714. 22826
  715. 22827   return OK;
  716. 22828 } 
  717. 22829
  718. 22830
  719. 22831 /*=========================================================================*
  720. 22832  *                              mcd_eject                                  *    
  721. 22833  *=========================================================================*/
  722. 22834 PRIVATE int mcd_eject()
  723. 22835 {
  724. 22836   int err;
  725. 22837
  726. 22838   if ((err = mcd_send_command(MCD_EJECT)) != OK) return err;
  727. 22839   return OK;
  728. 22840 } 
  729. 22841
  730. 22842
  731. 22843 /*=========================================================================*
  732. 22844  *                              mcd_pause                                  *    
  733. 22845  *=========================================================================*/
  734. 22846 PRIVATE int mcd_pause()
  735. 22847 {
  736. 22848   int err;
  737. 22849   struct cd_toc_entry qc;
  738. 22850
  739. 22851   /* We can only pause when we are playing audio */
  740. 22852   if (!(McdStatus & AUDIO_PLAYING)) return EINVAL;
  741. 22853
  742. 22854   /* Look where we are */
  743. 22855   if ((err = mcd_read_q_channel(&qc)) != OK) return err;
  744. 22856
  745. 22857   /* Stop playing */
  746. 22858   if ((err = mcd_send_command(MCD_STOP_AUDIO)) != OK) return err;
  747. 22859
  748. 22860   /* Keep in mind were we have to start again */
  749. 22861   PlayMss.begin_mss[MINUTES] = qc.position_mss[MINUTES];
  750. 22862   PlayMss.begin_mss[SECONDS] = qc.position_mss[SECONDS];
  751. 22863   PlayMss.begin_mss[SECTOR] = qc.position_mss[SECTOR];
  752. 22864
  753. 22865   /* Update McdStatus */
  754. 22866   McdStatus |= AUDIO_PAUSED;
  755. 22867
  756. 22868 #if MCD_DEBUG >= 1
  757. 22869   printf("Mcd_paused at: %02d:%02d.%02dn",
  758. 22870       PlayMss.begin_mss[MINUTES],
  759. 22871       PlayMss.begin_mss[SECONDS],
  760. 22872       PlayMss.begin_mss[SECTOR]);
  761. 22873 #endif
  762. 22874
  763. 22875   return OK;
  764. 22876 } 
  765. 22877
  766. 22878
  767. 22879 /*=========================================================================*
  768. 22880  *                              mcd_resume                                 *    
  769. 22881  *=========================================================================*/
  770. 22882 PRIVATE int mcd_resume()
  771. 22883 {
  772. 22884   int err;
  773. 22885
  774. 22886   /* we can only resume if we are in a pause state */
  775. 22887   if (!(McdStatus & AUDIO_PAUSED)) return EINVAL;
  776. 22888
  777. 22889   /* start playing where we left off */
  778. 22890   if ((err = mcd_play_mss(PlayMss)) != OK) return err;
  779. 22891
  780. 22892   McdStatus &= ~(AUDIO_PAUSED);
  781. 22893
  782. 22894 #if MCD_DEBUG >= 1
  783. 22895   printf("Mcd resumed at: %02d:%02d.%02dn",
  784. 22896       PlayMss.begin_mss[MINUTES],
  785. 22897       PlayMss.begin_mss[SECONDS],
  786. 22898       PlayMss.begin_mss[SECTOR]);
  787. 22899 #endif
  788. 22900
  789. 22901   return OK;
  790. 22902 } 
  791. 22903
  792. 22904
  793. 22905 /*=========================================================================*
  794. 22906  *                              ioctl_read_sub                             *    
  795. 22907  *=========================================================================*/
  796. 22908 PRIVATE int ioctl_read_sub(m_ptr)
  797. 22909 message *m_ptr;
  798. 22910 {
  799. 22911   phys_bytes user_phys;
  800. 22912   struct cd_toc_entry sub;
  801. 22913   int err;
  802. 22914
  803. 22915   /* We can only read a sub channel when we are playing audio */
  804. 22916   if (!(McdStatus & AUDIO_PLAYING)) return EINVAL; 
  805. 22917
  806. 22918   /* Read the sub channel */
  807. 22919   if ((err = mcd_read_q_channel(&sub)) != OK) return err;
  808. 22920
  809. 22921   /* Copy info to user */
  810. 22922   user_phys = numap(m_ptr->PROC_NR, (vir_bytes) m_ptr->ADDRESS, sizeof(sub));
  811. 22923   if (user_phys == 0) return(EFAULT);
  812. 22924   phys_copy(vir2phys(&sub), user_phys, (phys_bytes) sizeof(sub));
  813. 22925
  814. 22926   return OK;
  815. 22927 }  
  816. 22928
  817. 22929
  818. 22930
  819. 22931 /*=========================================================================*
  820. 22932  *                              ioctl_read_toc                             *    
  821. 22933  *=========================================================================*/
  822. 22934 PRIVATE int ioctl_read_toc(m_ptr)
  823. 22935 message *m_ptr;
  824. 22936 {
  825. 22937   phys_bytes user_phys;
  826. 22938   int err, toc_size;
  827. 22939
  828. 22940   /* Try to read the table of contents */
  829. 22941   if ((err = mcd_read_toc()) != OK) return err;
  830. 22942
  831. 22943   /* Get size of toc */
  832. 22944   toc_size = (DiskInfo.last_track + 1) * sizeof(struct cd_toc_entry);
  833. 22945
  834. 22946   /* Copy to user */
  835. 22947   user_phys = numap(m_ptr->PROC_NR, (vir_bytes) m_ptr->ADDRESS, toc_size);
  836. 22948   if (user_phys == 0) return(EFAULT);
  837. 22949   phys_copy(vir2phys(&Toc), user_phys, (phys_bytes) toc_size);
  838. 22950
  839. 22951   return OK;
  840. 22952 }  
  841. 22953
  842. 22954
  843. 22955 /*=========================================================================*
  844. 22956  *                              ioctl_disk_info                            *    
  845. 22957  *=========================================================================*/
  846. 22958 PRIVATE int ioctl_disk_info(m_ptr)
  847. 22959 message *m_ptr;
  848. 22960 {
  849. 22961   phys_bytes user_phys;
  850. 22962   int err;
  851. 22963
  852. 22964   /* Try to read the toc header */
  853. 22965   if ((err = mcd_get_disk_info()) != OK) return err;
  854. 22966
  855. 22967   /* Copy info to user */
  856. 22968   user_phys = numap(m_ptr->PROC_NR, (vir_bytes) m_ptr->ADDRESS, sizeof(DiskInfo));
  857. 22969   if (user_phys == 0) return(EFAULT);
  858. 22970   phys_copy(vir2phys(&DiskInfo), user_phys, (phys_bytes) sizeof(DiskInfo));
  859. 22971
  860. 22972   return OK;
  861. 22973 }
  862. 22976 /*=========================================================================*
  863. 22977  *                              ioctl_play_mss                             *    
  864. 22978  *=========================================================================*/
  865. 22979 PRIVATE int ioctl_play_mss(m_ptr)
  866. 22980 message *m_ptr;
  867. 22981 {
  868. 22982   phys_bytes user_phys;
  869. 22983   struct cd_play_mss mss;
  870. 22984
  871. 22985   /* Get user data */
  872. 22986   user_phys = numap(m_ptr->PROC_NR, (vir_bytes) m_ptr->ADDRESS, sizeof(mss));
  873. 22987   if (user_phys == 0) return(EFAULT);
  874. 22988   phys_copy(user_phys, vir2phys(&mss), (phys_bytes) sizeof(mss));
  875. 22989
  876. 22990   /* Try to play */
  877. 22991   return mcd_play_mss(mss);
  878. 22992 }
  879. 22995 /*=========================================================================*
  880. 22996  *                              ioctl_play_ti                              *    
  881. 22997  *=========================================================================*/
  882. 22998 PRIVATE int ioctl_play_ti(m_ptr)
  883. 22999 message *m_ptr;
  884. 23000 {
  885. 23001   phys_bytes user_phys;
  886. 23002   struct cd_play_track tracks;
  887. 23003
  888. 23004   /* Get user data */
  889. 23005   user_phys = numap(m_ptr->PROC_NR, (vir_bytes) m_ptr->ADDRESS, sizeof(tracks));
  890. 23006   if (user_phys == 0) return(EFAULT);
  891. 23007   phys_copy(user_phys, vir2phys(&tracks), (phys_bytes) sizeof(tracks));
  892. 23008
  893. 23009   /* Try to play */
  894. 23010   return mcd_play_tracks(tracks);
  895. 23011 }
  896. 23014 /*===========================================================================*
  897. 23015  *                              mcd_prepare                                  *
  898. 23016  *===========================================================================*/
  899. 23017 PRIVATE struct device *mcd_prepare(device)
  900. 23018 int device;
  901. 23019 {
  902. 23020   /* Nothing to transfer as yet. */
  903. 23021   mcd_count = 0;
  904. 23022
  905. 23023   /* Select partition. */
  906. 23024   if (device < DEV_PER_DRIVE) {                 /* cd0, cd1, ... */
  907. 23025     mcd_dv = &mcd_part[device];
  908. 23026   } else
  909. 23027   if ((unsigned) (device -= MINOR_hd1a) < SUB_PER_DRIVE) { /* cd1a, cd1b, ... */
  910. 23028     mcd_dv = &mcd_subpart[device];
  911. 23029   } else {
  912. 23030     return NIL_DEV;
  913. 23031   }
  914. 23032
  915. 23033   return mcd_dv;
  916. 23034 }
  917. 23037 /*===========================================================================*
  918. 23038  *                              mcd_schedule                                 *
  919. 23039  *===========================================================================*/
  920. 23040 PRIVATE int mcd_schedule(proc_nr, iop)
  921. 23041 int proc_nr;                    /* process doing the request */
  922. 23042 struct iorequest_s *iop;        /* pointer to read or write request */
  923. 23043 {
  924. 23044 /* Gather I/O requests on consecutive blocks so they may be read/written
  925. 23045  * in one controller command.  (There is enough time to compute the next
  926. 23046  * consecutive request while an unwanted block passes by.)
  927. 23047  */
  928. 23048   int r, opcode;
  929. 23049   unsigned long pos;
  930. 23050   unsigned nbytes;
  931. 23051   phys_bytes user_phys;
  932. 23052
  933. 23053   /* This many bytes to read */
  934. 23054   nbytes = iop->io_nbytes;
  935. 23055
  936. 23056   /* From/to this position on the device */
  937. 23057   pos = iop->io_position;
  938. 23058
  939. 23059   /* To/from this user address */
  940. 23060   user_phys = numap(proc_nr, (vir_bytes) iop->io_buf, nbytes);
  941. 23061   if (user_phys == 0) return(iop->io_nbytes = EINVAL);
  942. 23062
  943. 23063   /* Read or write? */
  944. 23064   opcode = iop->io_request & ~OPTIONAL_IO;
  945. 23065
  946. 23066   /* Only read permitted on cdrom */
  947. 23067   if (opcode != DEV_READ) return EIO;
  948. 23068
  949. 23069   /* What position on disk and how close to EOF? */
  950. 23070   if (pos >= mcd_dv->dv_size) return(OK);       /* At EOF */
  951. 23071   if (pos + nbytes > mcd_dv->dv_size) nbytes = mcd_dv->dv_size - pos;
  952. 23072   pos += mcd_dv->dv_base;
  953. 23073
  954. 23074   if (mcd_count > 0 && pos != mcd_nextpos) {
  955. 23075         /* This new request can't be chained to the job being built */
  956. 23076         if ((r = mcd_finish()) != OK) return(r);
  957. 23077   }
  958. 23078
  959. 23079   /* Next consecutive position. */
  960. 23080   mcd_nextpos = pos + nbytes;
  961. 23081
  962. 23082   if (mcd_count == 0) 
  963. 23083   {
  964. 23084     /* The first request in a row, initialize. */
  965. 23085     mcd_tp = mcd_trans;
  966. 23086   }
  967. 23087
  968. 23088   /* Store I/O parameters */
  969. 23089   mcd_tp->tr_iop = iop;
  970. 23090   mcd_tp->tr_pos = pos;
  971. 23091   mcd_tp->tr_count = nbytes;
  972. 23092   mcd_tp->tr_phys = user_phys;
  973. 23093
  974. 23094   /* Update counters */
  975. 23095   mcd_tp++;
  976. 23096   mcd_count += nbytes;
  977. 23097   return(OK);
  978. 23098 }
  979. 23101 /*===========================================================================*
  980. 23102  *                              mcd_finish                                   *
  981. 23103  *===========================================================================*/
  982. 23104 PRIVATE int mcd_finish()
  983. 23105 {
  984. 23106 /* Carry out the I/O requests gathered in mcd_trans[]. */
  985. 23107
  986. 23108   struct trans *tp = mcd_trans;
  987. 23109   int err, errors;
  988. 23110   u8_t mss[3];
  989. 23111   unsigned long pos;
  990. 23112   unsigned count, n;
  991. 23113
  992. 23114   if (mcd_count == 0) return(OK);       /* we're already done */
  993. 23115
  994. 23116   /* Update status */
  995. 23117   mcd_get_status(1);
  996. 23118   if (McdStatus & (AUDIO_DISK | NO_DISK))
  997. 23119     return(tp->tr_iop->io_nbytes = EIO);
  998. 23120                                                           
  999. 23121   /* Set cooked mode */
  1000. 23122   if ((err = mcd_set_mode(MCD_COOKED)) != OK)
  1001. 23123     return(tp->tr_iop->io_nbytes = err);
  1002. 23124
  1003. 23125   while (mcd_count > 0)
  1004. 23126   {
  1005. 23127     /* Position on the CD rounded down to the CD block size */
  1006. 23128     pos = tp->tr_pos & ~MCD_BLOCK_MASK;
  1007. 23129
  1008. 23130     /* Byte count rounded up. */
  1009. 23131     count = (pos - tp->tr_pos) + mcd_count;
  1010. 23132     count = (count + MCD_BLOCK_SIZE - 1) & ~MCD_BLOCK_MASK;
  1011. 23133
  1012. 23134     /* XXX transfer size limits? */
  1013. 23135     if (count > MCD_BLOCK_SIZE) count = MCD_BLOCK_SIZE;
  1014. 23136
  1015. 23137     /* Compute disk position in min:sec:sector */
  1016. 23138     block2mss(pos >> MCD_BLOCK_SHIFT, mss);
  1017. 23139
  1018. 23140     /* Now try to read a block */
  1019. 23141     errors = 0;
  1020. 23142     while (errors < MCD_RETRIES) 
  1021. 23143     {
  1022. 23144       lock();
  1023. 23145       out_byte(MCD_DATA_PORT, MCD_READ_FROM_TO);
  1024. 23146       out_byte(MCD_DATA_PORT, bin2bcd(mss[MINUTES])); 
  1025. 23147       out_byte(MCD_DATA_PORT, bin2bcd(mss[SECONDS])); 
  1026. 23148       out_byte(MCD_DATA_PORT, bin2bcd(mss[SECTOR])); 
  1027. 23149       out_byte(MCD_DATA_PORT, 0); 
  1028. 23150       out_byte(MCD_DATA_PORT, 0); 
  1029. 23151       out_byte(MCD_DATA_PORT, 1);       /* XXX count in mss form? */
  1030. 23152       unlock();
  1031. 23153
  1032. 23154       /* Wait for data */
  1033. 23155       if (mcd_data_ready(REPLY_DELAY) == OK) break;
  1034. 23156       printf("Mcd: data time outn");
  1035. 23157       errors++;
  1036. 23158     }
  1037. 23159     if (errors == MCD_RETRIES) return(tp->tr_iop->io_nbytes = EIO);
  1038. 23160
  1039. 23161     /* Prepare reading data. */
  1040. 23162     out_byte(MCD_CONTROL_PORT, 0x04);
  1041. 23163
  1042. 23164     while (pos < tp->tr_pos)
  1043. 23165     {
  1044. 23166       /* Discard bytes before the position we are really interested in. */
  1045. 23167       n = tp->tr_pos - pos;
  1046. 23168       if (n > DMA_BUF_SIZE) n = DMA_BUF_SIZE;
  1047. 23169       port_read_byte(MCD_DATA_PORT, tmp_phys, n);
  1048. 23170 #if XXX
  1049. 23171 printf("count = %u, n = %u, tr_pos = %lu, io_nbytes = %u, tr_count = %u, mcd_count = %un",
  1050. 23172 count, n, 0, 0, 0, mcd_count);
  1051. 23173 #endif
  1052. 23174       pos += n;
  1053. 23175       count -= n;
  1054. 23176     }
  1055. 23177
  1056. 23178     while (mcd_count > 0 && count > 0)
  1057. 23179     {
  1058. 23180       /* Transfer bytes into the user buffers. */
  1059. 23181       n = tp->tr_count;
  1060. 23182       if (n > count) n = count;
  1061. 23183       port_read_byte(MCD_DATA_PORT, tp->tr_phys, n);
  1062. 23184 #if XXX
  1063. 23185 printf("count = %u, n = %u, tr_pos = %lu, io_nbytes = %u, tr_count = %u, mcd_count = %un",
  1064. 23186 count, n, tp->tr_pos, tp->tr_iop->io_nbytes, tp->tr_count, mcd_count);
  1065. 23187 #endif
  1066. 23188       tp->tr_phys += n;
  1067. 23189       tp->tr_pos += n;
  1068. 23190       tp->tr_iop->io_nbytes -= n;
  1069. 23191       if ((tp->tr_count -= n) == 0) tp++;
  1070. 23192       count -= n;
  1071. 23193       mcd_count -= n;
  1072. 23194     }
  1073. 23195
  1074. 23196     while (count > 0)
  1075. 23197     {
  1076. 23198       /* Discard excess bytes. */
  1077. 23199       n = count;
  1078. 23200       if (n > DMA_BUF_SIZE) n = DMA_BUF_SIZE;
  1079. 23201       port_read_byte(MCD_DATA_PORT, tmp_phys, n);
  1080. 23202 #if XXX
  1081. 23203 printf("count = %u, n = %u, tr_pos = %lu, io_nbytes = %u, tr_count = %u, mcd_count = %un",
  1082. 23204 count, n, 0, 0, 0, mcd_count);
  1083. 23205 #endif
  1084. 23206       count -= n;
  1085. 23207     }
  1086. 23208
  1087. 23209     /* Finish reading data. */
  1088. 23210     out_byte(MCD_CONTROL_PORT, 0x0c);
  1089. 23211 #if 0 /*XXX*/
  1090. 23212     mcd_get_status(1);
  1091. 23213     if (!(McdStatus & DISK_ERROR)) done = 1; /* OK, no errors */
  1092. 23214 #endif
  1093. 23215   }
  1094. 23216  
  1095. 23217   return OK; 
  1096. 23218 }
  1097. 23221 /*============================================================================*
  1098. 23222  *                              mcd_geometry                                  *
  1099. 23223  *============================================================================*/
  1100. 23224 PRIVATE void mcd_geometry(entry)
  1101. 23225 struct partition *entry;                
  1102. 23226 {
  1103. 23227 /* The geometry of a cdrom doesn't look like the geometry of a regular disk,
  1104. 23228  * so we invent a geometry to keep external programs happy.
  1105. 23229  */ 
  1106. 23230   entry->cylinders = (mcd_part[0].dv_size >> SECTOR_SHIFT) / (64 * 32);
  1107. 23231   entry->heads = 64;
  1108. 23232   entry->sectors = 32;
  1109. 23233 }
  1110. 23236 /*============================================================================*
  1111. 23237  *                              misc functions                                *
  1112. 23238  *============================================================================*/
  1113. 23239 PRIVATE u8_t bin2bcd(u8_t b)
  1114. 23240 {
  1115. 23241   /* Convert a number to binary-coded-decimal */
  1116. 23242   int u,t;
  1117. 23243
  1118. 23244   u = b%10;
  1119. 23245   t = b/10;
  1120. 23246   return (u8_t)(u | (t << 4));
  1121. 23247 }
  1122. 23250 PRIVATE void bcd2bin(u8_t *bcd)
  1123. 23251 {
  1124. 23252   /* Convert binary-coded-decimal to binary :-) */
  1125. 23253
  1126. 23254   *bcd = (*bcd >> 4) * 10 + (*bcd & 0xf);
  1127. 23255 }
  1128. 23258 PRIVATE void block2mss(block, mss)
  1129. 23259 long block;
  1130. 23260 u8_t *mss;
  1131. 23261 {
  1132. 23262   /* Compute disk position of a block in min:sec:sector */
  1133. 23263
  1134. 23264   block += MCD_SKIP;
  1135. 23265   mss[MINUTES] = block/(SECONDS_PER_MINUTE * SECTORS_PER_SECOND);
  1136. 23266   block %= (SECONDS_PER_MINUTE * SECTORS_PER_SECOND);
  1137. 23267   mss[SECONDS] = block/(SECTORS_PER_SECOND);
  1138. 23268   mss[SECTOR] = block%(SECTORS_PER_SECOND);
  1139. 23269 }
  1140. 23272 PRIVATE long mss2block(u8_t *mss)
  1141. 23273 {
  1142. 23274   /* Compute block number belonging to 
  1143. 23275    * disk position min:sec:sector 
  1144. 23276    */
  1145. 23277
  1146. 23278   return ((((unsigned long) mss[MINUTES] * SECONDS_PER_MINUTE
  1147. 23279         + (unsigned long) mss[SECONDS]) * SECTORS_PER_SECOND)
  1148. 23280         + (unsigned long) mss[SECTOR]) - MCD_SKIP;
  1149. 23281 }
  1150. 23282 #endif /* ENABLE_MITSUMI_CDROM */
  1151. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1152. src/kernel/memory.c    
  1153. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1154. 23300 /* This file contains the device dependent part of the drivers for the
  1155. 23301  * following special files:
  1156. 23302  *     /dev/null        - null device (data sink)
  1157. 23303  *     /dev/mem         - absolute memory
  1158. 23304  *     /dev/kmem        - kernel virtual memory
  1159. 23305  *     /dev/ram         - RAM disk
  1160. 23306  *
  1161. 23307  * The file contains one entry point:
  1162. 23308  *
  1163. 23309  *   mem_task:  main entry when system is brought up
  1164. 23310  *
  1165. 23311  *  Changes:
  1166. 23312  *      20 Apr  1992 by Kees J. Bot: device dependent/independent split
  1167. 23313  */
  1168. 23314
  1169. 23315 #include "kernel.h"
  1170. 23316 #include "driver.h"
  1171. 23317 #include <sys/ioctl.h>
  1172. 23318
  1173. 23319 #define NR_RAMS            4    /* number of RAM-type devices */
  1174. 23320
  1175. 23321 PRIVATE struct device m_geom[NR_RAMS];  /* Base and size of each RAM disk */
  1176. 23322 PRIVATE int m_device;           /* current device */
  1177. 23323
  1178. 23324 FORWARD _PROTOTYPE( struct device *m_prepare, (int device) );
  1179. 23325 FORWARD _PROTOTYPE( int m_schedule, (int proc_nr, struct iorequest_s *iop) );
  1180. 23326 FORWARD _PROTOTYPE( int m_do_open, (struct driver *dp, message *m_ptr) );
  1181. 23327 FORWARD _PROTOTYPE( void m_init, (void) );
  1182. 23328 FORWARD _PROTOTYPE( int m_ioctl, (struct driver *dp, message *m_ptr) );
  1183. 23329 FORWARD _PROTOTYPE( void m_geometry, (struct partition *entry) );
  1184. 23330
  1185. 23331
  1186. 23332 /* Entry points to this driver. */
  1187. 23333 PRIVATE struct driver m_dtab = {
  1188. 23334   no_name,      /* current device's name */
  1189. 23335   m_do_open,    /* open or mount */
  1190. 23336   do_nop,       /* nothing on a close */
  1191. 23337   m_ioctl,      /* specify ram disk geometry */
  1192. 23338   m_prepare,    /* prepare for I/O on a given minor device */
  1193. 23339   m_schedule,   /* do the I/O */
  1194. 23340   nop_finish,   /* schedule does the work, no need to be smart */
  1195. 23341   nop_cleanup,  /* nothing's dirty */
  1196. 23342   m_geometry,   /* memory device "geometry" */
  1197. 23343 };
  1198. 23344
  1199. 23345
  1200. 23346 /*===========================================================================*
  1201. 23347  *                              mem_task                                     *
  1202. 23348  *===========================================================================*/
  1203. 23349 PUBLIC void mem_task()
  1204. 23350 {
  1205. 23351   m_init();
  1206. 23352   driver_task(&m_dtab);
  1207. 23353 }
  1208. 23356 /*===========================================================================*
  1209. 23357  *                              m_prepare                                    *
  1210. 23358  *===========================================================================*/
  1211. 23359 PRIVATE struct device *m_prepare(device)
  1212. 23360 int device;
  1213. 23361 {
  1214. 23362 /* Prepare for I/O on a device. */
  1215. 23363
  1216. 23364   if (device < 0 || device >= NR_RAMS) return(NIL_DEV);
  1217. 23365   m_device = device;
  1218. 23366
  1219. 23367   return(&m_geom[device]);
  1220. 23368 }
  1221. 23371 /*===========================================================================*
  1222. 23372  *                              m_schedule                                   *
  1223. 23373  *===========================================================================*/
  1224. 23374 PRIVATE int m_schedule(proc_nr, iop)
  1225. 23375 int proc_nr;                    /* process doing the request */
  1226. 23376 struct iorequest_s *iop;        /* pointer to read or write request */
  1227. 23377 {
  1228. 23378 /* Read or write /dev/null, /dev/mem, /dev/kmem, or /dev/ram. */
  1229. 23379
  1230. 23380   int device, count, opcode;
  1231. 23381   phys_bytes mem_phys, user_phys;
  1232. 23382   struct device *dv;
  1233. 23383
  1234. 23384   /* Type of request */
  1235. 23385   opcode = iop->io_request & ~OPTIONAL_IO;
  1236. 23386
  1237. 23387   /* Get minor device number and check for /dev/null. */
  1238. 23388   device = m_device;
  1239. 23389   dv = &m_geom[device];
  1240. 23390
  1241. 23391   /* Determine address where data is to go or to come from. */
  1242. 23392   user_phys = numap(proc_nr, (vir_bytes) iop->io_buf,
  1243. 23393                                                 (vir_bytes) iop->io_nbytes);
  1244. 23394   if (user_phys == 0) return(iop->io_nbytes = EINVAL);
  1245. 23395
  1246. 23396   if (device == NULL_DEV) {
  1247. 23397         /* /dev/null: Black hole. */
  1248. 23398         if (opcode == DEV_WRITE) iop->io_nbytes = 0;
  1249. 23399         count = 0;
  1250. 23400   } else {
  1251. 23401         /* /dev/mem, /dev/kmem, or /dev/ram: Check for EOF */
  1252. 23402         if (iop->io_position >= dv->dv_size) return(OK);
  1253. 23403         count = iop->io_nbytes;
  1254. 23404         if (iop->io_position + count > dv->dv_size)
  1255. 23405                 count = dv->dv_size - iop->io_position;
  1256. 23406   }
  1257. 23407
  1258. 23408   /* Set up 'mem_phys' for /dev/mem, /dev/kmem, or /dev/ram */
  1259. 23409   mem_phys = dv->dv_base + iop->io_position;
  1260. 23410
  1261. 23411   /* Book the number of bytes to be transferred in advance. */
  1262. 23412   iop->io_nbytes -= count;
  1263. 23413
  1264. 23414   if (count == 0) return(OK);
  1265. 23415
  1266. 23416   /* Copy the data. */
  1267. 23417   if (opcode == DEV_READ)
  1268. 23418         phys_copy(mem_phys, user_phys, (phys_bytes) count);
  1269. 23419   else
  1270. 23420         phys_copy(user_phys, mem_phys, (phys_bytes) count);
  1271. 23421
  1272. 23422   return(OK);
  1273. 23423 }
  1274. 23426 /*============================================================================*
  1275. 23427  *                              m_do_open                                     *
  1276. 23428  *============================================================================*/
  1277. 23429 PRIVATE int m_do_open(dp, m_ptr)
  1278. 23430 struct driver *dp;
  1279. 23431 message *m_ptr;
  1280. 23432 {
  1281. 23433 /* Check device number on open.  Give I/O privileges to a process opening
  1282. 23434  * /dev/mem or /dev/kmem.
  1283. 23435  */
  1284. 23436
  1285. 23437   if (m_prepare(m_ptr->DEVICE) == NIL_DEV) return(ENXIO);
  1286. 23438
  1287. 23439 #if (CHIP == INTEL)
  1288. 23440   if (m_device == MEM_DEV || m_device == KMEM_DEV)
  1289. 23441         enable_iop(proc_addr(m_ptr->PROC_NR));
  1290. 23442 #endif
  1291. 23443
  1292. 23444   return(OK);
  1293. 23445 }
  1294. 23448 /*===========================================================================*
  1295. 23449  *                              m_init                                       *
  1296. 23450  *===========================================================================*/
  1297. 23451 PRIVATE void m_init()
  1298. 23452 {
  1299. 23453   /* Initialize this task. */
  1300. 23454   extern int _end;
  1301. 23455
  1302. 23456   m_geom[KMEM_DEV].dv_base = vir2phys(0);
  1303. 23457   m_geom[KMEM_DEV].dv_size = vir2phys(&_end);
  1304. 23458
  1305. 23459 #if (CHIP == INTEL)
  1306. 23460   if (!protected_mode) {
  1307. 23461         m_geom[MEM_DEV].dv_size =   0x100000;   /* 1M for 8086 systems */
  1308. 23462   } else {
  1309. 23463 #if _WORD_SIZE == 2
  1310. 23464         m_geom[MEM_DEV].dv_size =  0x1000000;   /* 16M for 286 systems */
  1311. 23465 #else
  1312. 23466         m_geom[MEM_DEV].dv_size = 0xFFFFFFFF;   /* 4G-1 for 386 systems */
  1313. 23467 #endif
  1314. 23468   }
  1315. 23469 #else /* !(CHIP == INTEL) */
  1316. 23470 #if (CHIP == M68000)
  1317. 23471   m_geom[MEM_DEV].dv_size = MEM_BYTES;
  1318. 23472 #else /* !(CHIP == M68000) */
  1319. 23473 #error /* memory limit not set up */
  1320. 23474 #endif /* !(CHIP == M68000) */
  1321. 23475 #endif /* !(CHIP == INTEL) */
  1322. 23476 }
  1323. 23479 /*===========================================================================*
  1324. 23480  *                              m_ioctl                                      *
  1325. 23481  *===========================================================================*/
  1326. 23482 PRIVATE int m_ioctl(dp, m_ptr)
  1327. 23483 struct driver *dp;
  1328. 23484 message *m_ptr;                 /* pointer to read or write message */
  1329. 23485 {
  1330. 23486 /* Set parameters for one of the RAM disks. */
  1331. 23487
  1332. 23488   unsigned long bytesize;
  1333. 23489   unsigned base, size;
  1334. 23490   struct memory *memp;
  1335. 23491   static struct psinfo psinfo = { NR_TASKS, NR_PROCS, (vir_bytes) proc, 0, 0 };
  1336. 23492   phys_bytes psinfo_phys;
  1337. 23493
  1338. 23494   switch (m_ptr->REQUEST) {
  1339. 23495   case MIOCRAMSIZE:
  1340. 23496         /* FS sets the RAM disk size. */
  1341. 23497         if (m_ptr->PROC_NR != FS_PROC_NR) return(EPERM);
  1342. 23498
  1343. 23499         bytesize = m_ptr->POSITION * BLOCK_SIZE;
  1344. 23500         size = (bytesize + CLICK_SHIFT-1) >> CLICK_SHIFT;
  1345. 23501
  1346. 23502         /* Find a memory chunk big enough for the RAM disk. */
  1347. 23503         memp= &mem[NR_MEMS];
  1348. 23504         while ((--memp)->size < size) {
  1349. 23505                 if (memp == mem) panic("RAM disk is too big", NO_NUM);
  1350. 23506         }
  1351. 23507         base = memp->base;
  1352. 23508         memp->base += size;
  1353. 23509         memp->size -= size;
  1354. 23510
  1355. 23511         m_geom[RAM_DEV].dv_base = (unsigned long) base << CLICK_SHIFT;
  1356. 23512         m_geom[RAM_DEV].dv_size = bytesize;
  1357. 23513         break;
  1358. 23514   case MIOCSPSINFO:
  1359. 23515         /* MM or FS set the address of their process table. */
  1360. 23516         if (m_ptr->PROC_NR == MM_PROC_NR) {
  1361. 23517                 psinfo.mproc = (vir_bytes) m_ptr->ADDRESS;
  1362. 23518         } else
  1363. 23519         if (m_ptr->PROC_NR == FS_PROC_NR) {
  1364. 23520                 psinfo.fproc = (vir_bytes) m_ptr->ADDRESS;
  1365. 23521         } else {
  1366. 23522                 return(EPERM);
  1367. 23523         }
  1368. 23524         break;
  1369. 23525   case MIOCGPSINFO:
  1370. 23526         /* The ps program wants the process table addresses. */
  1371. 23527         psinfo_phys = numap(m_ptr->PROC_NR, (vir_bytes) m_ptr->ADDRESS,
  1372. 23528                                                         sizeof(psinfo));
  1373. 23529         if (psinfo_phys == 0) return(EFAULT);
  1374. 23530         phys_copy(vir2phys(&psinfo), psinfo_phys, (phys_bytes) sizeof(psinfo));
  1375. 23531         break;
  1376. 23532   default:
  1377. 23533         return(do_diocntl(&m_dtab, m_ptr));
  1378. 23534   }
  1379. 23535   return(OK);
  1380. 23536 }
  1381. 23539 /*============================================================================*
  1382. 23540  *                              m_geometry                                    *
  1383. 23541  *============================================================================*/
  1384. 23542 PRIVATE void m_geometry(entry)
  1385. 23543 struct partition *entry;
  1386. 23544 {
  1387. 23545   /* Memory devices don't have a geometry, but the outside world insists. */
  1388. 23546   entry->cylinders = (m_geom[m_device].dv_size >> SECTOR_SHIFT) / (64 * 32);
  1389. 23547   entry->heads = 64;
  1390. 23548   entry->sectors = 32;
  1391. 23549 }
  1392. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1393. src/kernel/misc.c    
  1394. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1395. 23600 /* This file contains a collection of miscellaneous procedures:
  1396. 23601  *      mem_init:       initialize memory tables.  Some memory is reported
  1397. 23602  *                      by the BIOS, some is guesstimated and checked later
  1398. 23603  *      env_parse       parse environment variable.
  1399. 23604  *      bad_assertion   for debugging
  1400. 23605  *      bad_compare     for debugging
  1401. 23606  */
  1402. 23607
  1403. 23608 #include "kernel.h"
  1404. 23609 #include "assert.h"
  1405. 23610 #include <stdlib.h>
  1406. 23611 #include <minix/com.h>
  1407. 23612
  1408. 23613 #if (CHIP == INTEL)
  1409. 23614
  1410. 23615 #define EM_BASE     0x100000L   /* base of extended memory on AT's */
  1411. 23616 #define SHADOW_BASE 0xFA0000L   /* base of RAM shadowing ROM on some AT's */
  1412. 23617 #define SHADOW_MAX  0x060000L   /* maximum usable shadow memory (16M limit) */
  1413. 23618
  1414. 23619 /*=========================================================================*
  1415. 23620  *                              mem_init                                   *
  1416. 23621  *=========================================================================*/
  1417. 23622 PUBLIC void mem_init()
  1418. 23623 {
  1419. 23624 /* Initialize the memory size tables.  This is complicated by fragmentation
  1420. 23625  * and different access strategies for protected mode.  There must be a
  1421. 23626  * chunk at 0 big enough to hold Minix proper.  For 286 and 386 processors,
  1422. 23627  * there can be extended memory (memory above 1MB).  This usually starts at
  1423. 23628  * 1MB, but there may be another chunk just below 16MB, reserved under DOS
  1424. 23629  * for shadowing ROM, but available to Minix if the hardware can be re-mapped.
  1425. 23630  * In protected mode, extended memory is accessible assuming CLICK_SIZE is
  1426. 23631  * large enough, and is treated as ordinary memory.
  1427. 23632  */
  1428. 23633
  1429. 23634   u32_t ext_clicks;
  1430. 23635   phys_clicks max_clicks;
  1431. 23636
  1432. 23637   /* Get the size of ordinary memory from the BIOS. */
  1433. 23638   mem[0].size = k_to_click(low_memsize);        /* base = 0 */
  1434. 23639
  1435. 23640   if (pc_at && protected_mode) {
  1436. 23641         /* Get the size of extended memory from the BIOS.  This is special
  1437. 23642          * except in protected mode, but protected mode is now normal.
  1438. 23643          * Note that no more than 16M can be addressed in 286 mode, so make
  1439. 23644          * sure that the highest memory address fits in a short when counted
  1440. 23645          * in clicks.
  1441. 23646          */
  1442. 23647         ext_clicks = k_to_click((u32_t) ext_memsize);
  1443. 23648         max_clicks = USHRT_MAX - (EM_BASE >> CLICK_SHIFT);
  1444. 23649         mem[1].size = MIN(ext_clicks, max_clicks);
  1445. 23650         mem[1].base = EM_BASE >> CLICK_SHIFT;
  1446. 23651
  1447. 23652         if (ext_memsize <= (unsigned) ((SHADOW_BASE - EM_BASE) / 1024)
  1448. 23653                         && check_mem(SHADOW_BASE, SHADOW_MAX) == SHADOW_MAX) {
  1449. 23654                 /* Shadow ROM memory. */
  1450. 23655                 mem[2].size = SHADOW_MAX >> CLICK_SHIFT;
  1451. 23656                 mem[2].base = SHADOW_BASE >> CLICK_SHIFT;
  1452. 23657         }
  1453. 23658   }
  1454. 23659
  1455. 23660   /* Total system memory. */
  1456. 23661   tot_mem_size = mem[0].size + mem[1].size + mem[2].size;
  1457. 23662 }
  1458. 23663 #endif /* (CHIP == INTEL) */
  1459. 23664
  1460. 23665 /*=========================================================================*
  1461. 23666  *                              env_parse                                  *
  1462. 23667  *=========================================================================*/
  1463. 23668 PUBLIC int env_parse(env, fmt, field, param, min, max)
  1464. 23669 char *env;              /* environment variable to inspect */
  1465. 23670 char *fmt;              /* template to parse it with */
  1466. 23671 int field;              /* field number of value to return */
  1467. 23672 long *param;            /* address of parameter to get */
  1468. 23673 long min, max;          /* minimum and maximum values for the parameter */
  1469. 23674 {
  1470. 23675 /* Parse an environment variable setting, something like "DPETH0=300:3".
  1471. 23676  * Panic if the parsing fails.  Return EP_UNSET if the environment variable
  1472. 23677  * is not set, EP_OFF if it is set to "off", EP_ON if set to "on" or a
  1473. 23678  * field is left blank, or EP_SET if a field is given (return value through
  1474. 23679  * *param).  Commas and colons may be used in the environment and format
  1475. 23680  * string, fields in the environment string may be empty, and punctuation
  1476. 23681  * may be missing to skip fields.  The format string contains characters
  1477. 23682  * 'd', 'o', 'x' and 'c' to indicate that 10, 8, 16, or 0 is used as the
  1478. 23683  * last argument to strtol.
  1479. 23684  */
  1480. 23685
  1481. 23686   char *val, *end;
  1482. 23687   long newpar;
  1483. 23688   int i = 0, radix, r;
  1484. 23689
  1485. 23690   if ((val = k_getenv(env)) == NIL_PTR) return(EP_UNSET);
  1486. 23691   if (strcmp(val, "off") == 0) return(EP_OFF);
  1487. 23692   if (strcmp(val, "on") == 0) return(EP_ON);
  1488. 23693
  1489. 23694   r = EP_ON;
  1490. 23695   for (;;) {
  1491. 23696         while (*val == ' ') val++;
  1492. 23697
  1493. 23698         if (*val == 0) return(r);       /* the proper exit point */
  1494. 23699
  1495. 23700         if (*fmt == 0) break;           /* too many values */
  1496. 23701
  1497. 23702         if (*val == ',' || *val == ':') {
  1498. 23703                 /* Time to go to the next field. */
  1499. 23704                 if (*fmt == ',' || *fmt == ':') i++;
  1500. 23705                 if (*fmt++ == *val) val++;
  1501. 23706         } else {
  1502. 23707                 /* Environment contains a value, get it. */
  1503. 23708                 switch (*fmt) {
  1504. 23709                 case 'd':       radix =   10;   break;
  1505. 23710                 case 'o':       radix =  010;   break;
  1506. 23711                 case 'x':       radix = 0x10;   break;
  1507. 23712                 case 'c':       radix =    0;   break;
  1508. 23713                 default:        goto badenv;
  1509. 23714                 }
  1510. 23715                 newpar = strtol(val, &end, radix);
  1511. 23716
  1512. 23717                 if (end == val) break;  /* not a number */
  1513. 23718                 val = end;
  1514. 23719
  1515. 23720                 if (i == field) {
  1516. 23721                         /* The field requested. */
  1517. 23722                         if (newpar < min || newpar > max) break;
  1518. 23723                         *param = newpar;
  1519. 23724                         r = EP_SET;
  1520. 23725                 }
  1521. 23726         }
  1522. 23727   }
  1523. 23728 badenv:
  1524. 23729   printf("Bad environment setting: '%s = %s'n", env, k_getenv(env));
  1525. 23730   panic("", NO_NUM);
  1526. 23731   /*NOTREACHED*/
  1527. 23732 }
  1528. 23734 #if DEBUG
  1529. 23735 /*=========================================================================*
  1530. 23736  *                              bad_assertion                              *
  1531. 23737  *=========================================================================*/
  1532. 23738 PUBLIC void bad_assertion(file, line, what)
  1533. 23739 char *file;
  1534. 23740 int line;
  1535. 23741 char *what;
  1536. 23742 {
  1537. 23743   printf("panic at %s(%d): assertion "%s" failedn", file, line, what);
  1538. 23744   panic(NULL, NO_NUM);
  1539. 23745 }
  1540. 23747 /*=========================================================================*
  1541. 23748  *                              bad_compare                                *
  1542. 23749  *=========================================================================*/
  1543. 23750 PUBLIC void bad_compare(file, line, lhs, what, rhs)
  1544. 23751 char *file;
  1545. 23752 int line;
  1546. 23753 int lhs;
  1547. 23754 char *what;
  1548. 23755 int rhs;
  1549. 23756 {
  1550. 23757   printf("panic at %s(%d): compare (%d) %s (%d) failedn",
  1551. 23758         file, line, lhs, what, rhs);
  1552. 23759   panic(NULL, NO_NUM);
  1553. 23760 }
  1554. 23761 #endif /* DEBUG */
  1555. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1556. src/kernel/ne2000.c    
  1557. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1558. 23800 /*
  1559. 23801 ne2000.c
  1560. 23802
  1561. 23803 Driver for the ne2000 ethernet cards. This file contains only the ne2000
  1562. 23804 specific code, the rest is in dp8390.c
  1563. 23805
  1564. 23806 Created:        March 15, 1994 by Philip Homburg <philip@cs.vu.nl>
  1565. 23807 */
  1566. 23808
  1567. 23809 #include "kernel.h"
  1568. 23810 #include <net/gen/ether.h>
  1569. 23811 #include <net/gen/eth_io.h>
  1570. 23812 #include "dp8390.h"
  1571. 23813 #include "ne2000.h"
  1572. 23814
  1573. 23815 #if ENABLE_NETWORKING
  1574. 23816
  1575. 23817 #if !__minix_vmd
  1576. 23818 #define debug           0
  1577. 23819 #endif
  1578. 23820
  1579. 23821 #define N 100
  1580. 23822
  1581. 23823 _PROTOTYPE( typedef int (*testf_t), (dpeth_t *dep, int pos, u8_t *pat)  );
  1582. 23824
  1583. 23825 u8_t    pat0[]= { 0x00, 0x00, 0x00, 0x00 };
  1584. 23826 u8_t    pat1[]= { 0xFF, 0xFF, 0xFF, 0xFF };
  1585. 23827 u8_t    pat2[]= { 0xA5, 0x5A, 0x69, 0x96 };
  1586. 23828 u8_t    pat3[]= { 0x96, 0x69, 0x5A, 0xA5 };
  1587. 23829
  1588. 23830 _PROTOTYPE( static int test_8, (dpeth_t *dep, int pos, u8_t *pat)       );
  1589. 23831 _PROTOTYPE( static int test_16, (dpeth_t *dep, int pos, u8_t *pat)      );
  1590. 23832 _PROTOTYPE( static void ne_init, (dpeth_t *dep)                         );
  1591. 23833 _PROTOTYPE( static void ne_stop, (dpeth_t *dep)                         );
  1592. 23834
  1593. 23835 /*===========================================================================*
  1594. 23836  *                              ne_probe                                     *
  1595. 23837  *===========================================================================*/
  1596. 23838 int ne_probe(dep)
  1597. 23839 dpeth_t *dep;
  1598. 23840 {
  1599. 23841         int byte;
  1600. 23842         int i;
  1601. 23843         int loc1, loc2;
  1602. 23844         testf_t f;
  1603. 23845
  1604. 23846         dep->de_dp8390_port= dep->de_base_port + NE_DP8390;
  1605. 23847
  1606. 23848         /* We probe for an ne1000 or an ne2000 by testing whether the
  1607. 23849          * on board is reachable through the dp8390. Note that the
  1608. 23850          * ne1000 is an 8bit card and has a memory region distict from
  1609. 23851          * the 16bit ne2000
  1610. 23852          */
  1611. 23853
  1612. 23854         for (dep->de_16bit= 0; dep->de_16bit < 2; dep->de_16bit++)
  1613. 23855         {
  1614. 23856                 /* Reset the ethernet card */
  1615. 23857                 byte= inb_ne(dep, NE_RESET);
  1616. 23858                 milli_delay(2);
  1617. 23859                 outb_ne(dep, NE_RESET, byte);
  1618. 23860                 milli_delay(2);
  1619. 23861
  1620. 23862                 /* Reset the dp8390 */
  1621. 23863                 outb_reg0(dep, DP_CR, CR_STP | CR_DM_ABORT);
  1622. 23864                 for (i= 0; i < 0x1000 && ((inb_reg0(dep, DP_ISR) & ISR_RST) == 0); i++)
  1623. 23865                         ; /* Do nothing */
  1624. 23866
  1625. 23867                 /* Check if the dp8390 is really there */
  1626. 23868                 if ((inb_reg0(dep, DP_CR) & (CR_STP|CR_DM_ABORT)) !=
  1627. 23869                         (CR_STP|CR_DM_ABORT))
  1628. 23870                 {
  1629. 23871                         return 0;
  1630. 23872                 }
  1631. 23873
  1632. 23874                 /* Put it in loop-back mode */
  1633. 23875                 outb_reg0(dep, DP_RCR, RCR_MON);
  1634. 23876                 outb_reg0(dep, DP_TCR, TCR_NORMAL);
  1635. 23877                 if (dep->de_16bit)
  1636. 23878                 {
  1637. 23879                         outb_reg0(dep, DP_DCR, DCR_WORDWIDE | DCR_8BYTES |
  1638. 23880                                 DCR_BMS);
  1639. 23881                 }
  1640. 23882                 else
  1641. 23883                 {
  1642. 23884                         outb_reg0(dep, DP_DCR, DCR_BYTEWIDE | DCR_8BYTES |
  1643. 23885                                 DCR_BMS);
  1644. 23886                 }
  1645. 23887
  1646. 23888                 if (dep->de_16bit)
  1647. 23889                 {
  1648. 23890                         loc1= NE2000_START;
  1649. 23891                         loc2= NE2000_START + NE2000_SIZE - 4;
  1650. 23892                         f= test_16;
  1651. 23893                 }
  1652. 23894                 else
  1653. 23895                 {
  1654. 23896                         loc1= NE1000_START;
  1655. 23897                         loc2= NE1000_START + NE1000_SIZE - 4;
  1656. 23898                         f= test_8;
  1657. 23899                 }
  1658. 23900                 if (f(dep, loc1, pat0) && f(dep, loc1, pat1) &&
  1659. 23901                         f(dep, loc1, pat2) && f(dep, loc1, pat3) &&
  1660. 23902                         f(dep, loc2, pat0) && f(dep, loc2, pat1) &&
  1661. 23903                         f(dep, loc2, pat2) && f(dep, loc2, pat3))
  1662. 23904                 {
  1663. 23905                         /* We don't need a memory segment */
  1664. 23906                         dep->de_linmem= 0;
  1665. 23907                         dep->de_initf= ne_init;
  1666. 23908                         dep->de_stopf= ne_stop;
  1667. 23909                         dep->de_prog_IO= 1;
  1668. 23910                         return 1;
  1669. 23911                 }
  1670. 23912         }
  1671. 23913         return 0;
  1672. 23914 }
  1673. 23917 /*===========================================================================*
  1674. 23918  *                              test_8                                       *
  1675. 23919  *===========================================================================*/
  1676. 23920 static int test_8(dep, pos, pat)
  1677. 23921 dpeth_t *dep;
  1678. 23922 int pos;
  1679. 23923 u8_t *pat;
  1680. 23924 {
  1681. 23925         u8_t buf[4];
  1682. 23926         int i;
  1683. 23927         int r;
  1684. 23928
  1685. 23929         outb_reg0(dep, DP_ISR, 0xFF);
  1686. 23930
  1687. 23931         /* Setup a transfer to put the pattern. */
  1688. 23932         outb_reg0(dep, DP_RBCR0, 4);
  1689. 23933         outb_reg0(dep, DP_RBCR1, 0);
  1690. 23934         outb_reg0(dep, DP_RSAR0, pos & 0xFF);
  1691. 23935         outb_reg0(dep, DP_RSAR1, pos >> 8);
  1692. 23936         outb_reg0(dep, DP_CR, CR_DM_RW | CR_PS_P0 | CR_STA);
  1693. 23937
  1694. 23938         for (i= 0; i<4; i++)
  1695. 23939                 outb_ne(dep, NE_DATA, pat[i]);
  1696. 23940
  1697. 23941         for (i= 0; i<N; i++)
  1698. 23942         {
  1699. 23943                 if (inb_reg0(dep, DP_ISR) & ISR_RDC)
  1700. 23944                         break;
  1701. 23945         }
  1702. 23946         if (i == N)
  1703. 23947         {
  1704. 23948                 printf("ne2000, test_8: remote dma failed to completen");
  1705. 23949                 return 0;
  1706. 23950         }
  1707. 23951
  1708. 23952         outb_reg0(dep, DP_RBCR0, 4);
  1709. 23953         outb_reg0(dep, DP_RBCR1, 0);
  1710. 23954         outb_reg0(dep, DP_RSAR0, pos & 0xFF);
  1711. 23955         outb_reg0(dep, DP_RSAR1, pos >> 8);
  1712. 23956         outb_reg0(dep, DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
  1713. 23957
  1714. 23958         for (i= 0; i<4; i++)
  1715. 23959                 buf[i]= inb_ne(dep, NE_DATA);
  1716. 23960
  1717. 23961         r= (memcmp(buf, pat, 4) == 0);
  1718. 23962         return r;
  1719. 23963 }
  1720. 23966 /*===========================================================================*
  1721. 23967  *                              test_16                                      *
  1722. 23968  *===========================================================================*/
  1723. 23969 static int test_16(dep, pos, pat)
  1724. 23970 dpeth_t *dep;
  1725. 23971 int pos;
  1726. 23972 u8_t *pat;
  1727. 23973 {
  1728. 23974         u8_t buf[4];
  1729. 23975         int i;
  1730. 23976         int r;
  1731. 23977
  1732. 23978         outb_reg0(dep, DP_ISR, 0xFF);
  1733. 23979
  1734. 23980         /* Setup a transfer to put the pattern. */
  1735. 23981         outb_reg0(dep, DP_RBCR0, 4);
  1736. 23982         outb_reg0(dep, DP_RBCR1, 0);
  1737. 23983         outb_reg0(dep, DP_RSAR0, pos & 0xFF);
  1738. 23984         outb_reg0(dep, DP_RSAR1, pos >> 8);
  1739. 23985         outb_reg0(dep, DP_CR, CR_DM_RW | CR_PS_P0 | CR_STA);
  1740. 23986
  1741. 23987         for (i= 0; i<4; i += 2)
  1742. 23988         {
  1743. 23989                 outw_ne(dep, NE_DATA, *(u16_t *)(pat+i));
  1744. 23990         }
  1745. 23991
  1746. 23992         for (i= 0; i<N; i++)
  1747. 23993         {
  1748. 23994                 if (inb_reg0(dep, DP_ISR) & ISR_RDC)
  1749. 23995                         break;
  1750. 23996         }
  1751. 23997         if (i == N)
  1752. 23998         {
  1753. 23999                 printf("ne2000, test_16: remote dma failed to completen");
  1754. 24000                 return 0;
  1755. 24001         }
  1756. 24002
  1757. 24003         outb_reg0(dep, DP_RBCR0, 4);
  1758. 24004         outb_reg0(dep, DP_RBCR1, 0);
  1759. 24005         outb_reg0(dep, DP_RSAR0, pos & 0xFF);
  1760. 24006         outb_reg0(dep, DP_RSAR1, pos >> 8);
  1761. 24007         outb_reg0(dep, DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
  1762. 24008
  1763. 24009         for (i= 0; i<4; i += 2)
  1764. 24010         {
  1765. 24011                 *(u16_t *)(buf+i)= inw_ne(dep, NE_DATA);
  1766. 24012         }
  1767. 24013
  1768. 24014         r= (memcmp(buf, pat, 4) == 0);
  1769. 24015         return r;
  1770. 24016 }
  1771. 24019 /*===========================================================================*
  1772. 24020  *                              ne_init                                      *
  1773. 24021  *===========================================================================*/
  1774. 24022 static void ne_init(dep)
  1775. 24023 dpeth_t *dep;
  1776. 24024 {
  1777. 24025         int i;
  1778. 24026         int word, sendq_nr;
  1779. 24027
  1780. 24028         /* Setup a transfer to get the ethernet address. */
  1781. 24029         if (dep->de_16bit)
  1782. 24030                 outb_reg0(dep, DP_RBCR0, 6*2);
  1783. 24031         else
  1784. 24032                 outb_reg0(dep, DP_RBCR0, 6);
  1785. 24033         outb_reg0(dep, DP_RBCR1, 0);
  1786. 24034         outb_reg0(dep, DP_RSAR0, 0);
  1787. 24035         outb_reg0(dep, DP_RSAR1, 0);
  1788. 24036         outb_reg0(dep, DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
  1789. 24037
  1790. 24038         for (i= 0; i<6; i++)
  1791. 24039         {
  1792. 24040                 if (dep->de_16bit)
  1793. 24041                 {
  1794. 24042                         word= inw_ne(dep, NE_DATA);
  1795. 24043                         dep->de_address.ea_addr[i]= word;
  1796. 24044                 }
  1797. 24045                 else
  1798. 24046                 {
  1799. 24047                         dep->de_address.ea_addr[i] = inb_ne(dep, NE_DATA);
  1800. 24048                 }
  1801. 24049         }
  1802. 24050         dep->de_data_port= dep->de_base_port + NE_DATA;
  1803. 24051         if (dep->de_16bit)
  1804. 24052         {
  1805. 24053                 dep->de_ramsize= NE2000_SIZE;
  1806. 24054                 dep->de_offset_page= NE2000_START / DP_PAGESIZE;
  1807. 24055         }
  1808. 24056         else
  1809. 24057         {
  1810. 24058                 dep->de_ramsize= NE1000_SIZE;
  1811. 24059                 dep->de_offset_page= NE1000_START / DP_PAGESIZE;
  1812. 24060         }
  1813. 24061
  1814. 24062         /* Allocate one send buffer (1.5KB) per 8KB of on board memory. */
  1815. 24063         sendq_nr= dep->de_ramsize / 0x2000;
  1816. 24064         if (sendq_nr < 1)
  1817. 24065                 sendq_nr= 1;
  1818. 24066         else if (sendq_nr > SENDQ_NR)
  1819. 24067                 sendq_nr= SENDQ_NR;
  1820. 24068         dep->de_sendq_nr= sendq_nr;
  1821. 24069         for (i= 0; i<sendq_nr; i++)
  1822. 24070         {
  1823. 24071                 dep->de_sendq[i].sq_sendpage= dep->de_offset_page +
  1824. 24072                         i*SENDQ_PAGES;  
  1825. 24073         }
  1826. 24074
  1827. 24075         dep->de_startpage= dep->de_offset_page + i*SENDQ_PAGES;
  1828. 24076         dep->de_stoppage= dep->de_offset_page + dep->de_ramsize / DP_PAGESIZE;
  1829. 24077
  1830. 24078         /* Can't override the default IRQ. */
  1831. 24079         dep->de_irq &= ~DEI_DEFAULT;
  1832. 24080
  1833. 24081         if (!debug)
  1834. 24082         {
  1835. 24083                 printf("ne2000: NE%d000 at %X:%dn",
  1836. 24084                         dep->de_16bit ? 2 : 1,
  1837. 24085                         dep->de_base_port, dep->de_irq);
  1838. 24086         }
  1839. 24087         else
  1840. 24088         {
  1841. 24089                 printf("ne2000: Novell %s ethernet card ", 
  1842. 24090                         dep->de_16bit ? "16-bit (ne2000)" : "8-bit (ne1000)");
  1843. 24091                 printf("at I/O address 0x%X, memory size 0x%X, irq %dn",
  1844. 24092                         dep->de_base_port, dep->de_ramsize, dep->de_irq);
  1845. 24093         }
  1846. 24094 }
  1847. 24097 /*===========================================================================*
  1848. 24098  *                              ne_stop                                      *
  1849. 24099  *===========================================================================*/
  1850. 24100 static void ne_stop(dep)
  1851. 24101 dpeth_t *dep;
  1852. 24102 {
  1853. 24103         int byte;
  1854. 24104
  1855. 24105         /* Reset the ethernet card */
  1856. 24106         byte= inb_ne(dep, NE_RESET);
  1857. 24107         milli_delay(2);
  1858. 24108         outb_ne(dep, NE_RESET, byte);
  1859. 24109 }
  1860. 24111 #endif /* ENABLE_NETWORKING */
  1861. 24112
  1862. 24113 /*
  1863. 24114  * $PchHeader: /mount/hd2/minix/sys/kernel/ibm/RCS/ne2000.c,v 1.2 1995/01/12 21:48:53 philip Exp $
  1864. 24115  */
  1865. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1866. src/kernel/printer.c    
  1867. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1868. 24200 /* This file contains the printer driver. It is a fairly simple driver,
  1869. 24201  * supporting only one printer.  Characters that are written to the driver
  1870. 24202  * are written to the printer without any changes at all.
  1871. 24203  *
  1872. 24204  * The valid messages and their parameters are:
  1873. 24205  *
  1874. 24206  *   HARD_INT:     interrupt handler has finished current chunk of output
  1875. 24207  *   DEV_WRITE:    a process wants to write on a terminal
  1876. 24208  *   CANCEL:       terminate a previous incomplete system call immediately
  1877. 24209  *
  1878. 24210  *    m_type      TTY_LINE   PROC_NR    COUNT    ADDRESS
  1879. 24211  * -------------------------------------------------------
  1880. 24212  * | HARD_INT    |         |         |         |         |
  1881. 24213  * |-------------+---------+---------+---------+---------|
  1882. 24214  * | DEV_WRITE   |minor dev| proc nr |  count  | buf ptr |
  1883. 24215  * |-------------+---------+---------+---------+---------|
  1884. 24216  * | CANCEL      |minor dev| proc nr |         |         |
  1885. 24217  * -------------------------------------------------------
  1886. 24218  * 
  1887. 24219  * Note: since only 1 printer is supported, minor dev is not used at present.
  1888. 24220  */
  1889. 24221
  1890. 24222 #include "kernel.h"
  1891. 24223 #include <minix/callnr.h>
  1892. 24224 #include <minix/com.h>
  1893. 24225 #include "proc.h"
  1894. 24226
  1895. 24227 /* Control bits (in port_base + 2).  "+" means positive logic and "-" means
  1896. 24228  * negative logic.  Most of the signals are negative logic on the pins but
  1897. 24229  * many are converted to positive logic in the ports.  Some manuals are
  1898. 24230  * misleading because they only document the pin logic.
  1899. 24231  *
  1900. 24232  *      +0x01   Pin 1   -Strobe
  1901. 24233  *      +0x02   Pin 14  -Auto Feed
  1902. 24234  *      -0x04   Pin 16  -Initialize Printer
  1903. 24235  *      +0x08   Pin 17  -Select Printer
  1904. 24236  *      +0x10   IRQ7 Enable
  1905. 24237  *
  1906. 24238  * Auto Feed and Select Printer are always enabled. Strobe is enabled briefly
  1907. 24239  * when characters are output.  Initialize Printer is enabled briefly when
  1908. 24240  * the task is started.  IRQ7 is enabled when the first character is output
  1909. 24241  * and left enabled until output is completed (or later after certain
  1910. 24242  * abnormal completions).
  1911. 24243  */
  1912. 24244 #define ASSERT_STROBE   0x1D    /* strobe a character to the interface */
  1913. 24245 #define NEGATE_STROBE   0x1C    /* enable interrupt on interface */
  1914. 24246 #define SELECT          0x0C    /* select printer bit */
  1915. 24247 #define INIT_PRINTER    0x08    /* init printer bits */
  1916. 24248
  1917. 24249 /* Status bits (in port_base + 2).
  1918. 24250  *
  1919. 24251  *      -0x08   Pin 15  -Error
  1920. 24252  *      +0x10   Pin 13  +Select Status
  1921. 24253  *      +0x20   Pin 12  +Out of Paper
  1922. 24254  *      -0x40   Pin 10  -Acknowledge
  1923. 24255  *      -0x80   Pin 11  +Busy
  1924. 24256  */
  1925. 24257 #define BUSY_STATUS     0x10    /* printer gives this status when busy */
  1926. 24258 #define NO_PAPER        0x20    /* status bit saying that paper is out */
  1927. 24259 #define NORMAL_STATUS   0x90    /* printer gives this status when idle */
  1928. 24260 #define ON_LINE         0x10    /* status bit saying that printer is online */
  1929. 24261 #define STATUS_MASK     0xB0    /* mask to filter out status bits */ 
  1930. 24262
  1931. 24263 /* Centronics interface timing that must be met by software (in microsec).
  1932. 24264  *
  1933. 24265  * Strobe length:       0.5u to 100u (not sure about the upper limit).
  1934. 24266  * Data set up:         0.5u before strobe.
  1935. 24267  * Data hold:                   0.5u after strobe.
  1936. 24268  * Init pulse length:      over 200u (not sure).
  1937. 24269  *
  1938. 24270  * The strobe length is about 50u with the code here and function calls for
  1939. 24271  * out_byte() - not much to spare.  The 0.5u minimums may be violated if
  1940. 24272  * out_byte() is generated in-line on a fast machine.  Some printer boards
  1941. 24273  * are slower than 0.5u anyway.
  1942. 24274  */
  1943. 24275
  1944. 24276 PRIVATE int caller;             /* process to tell when printing done (FS) */
  1945. 24277 PRIVATE int done_status;        /* status of last output completion */
  1946. 24278 PRIVATE int oleft;              /* bytes of output left in obuf */
  1947. 24279 PRIVATE char obuf[128];         /* output buffer */
  1948. 24280 PRIVATE int opending;           /* nonzero while expected printing not done */
  1949. 24281 PRIVATE char *optr;             /* ptr to next char in obuf to print */
  1950. 24282 PRIVATE int orig_count;         /* original byte count */
  1951. 24283 PRIVATE int port_base;          /* I/O port for printer */
  1952. 24284 PRIVATE int proc_nr;            /* user requesting the printing */
  1953. 24285 PRIVATE int user_left;          /* bytes of output left in user buf */
  1954. 24286 PRIVATE vir_bytes user_vir;     /* address of remainder of user buf */
  1955. 24287 PRIVATE int writing;            /* nonzero while write is in progress */
  1956. 24288
  1957. 24289 FORWARD _PROTOTYPE( void do_cancel, (message *m_ptr) );
  1958. 24290 FORWARD _PROTOTYPE( void do_done, (void) );
  1959. 24291 FORWARD _PROTOTYPE( void do_write, (message *m_ptr) );
  1960. 24292 FORWARD _PROTOTYPE( void pr_start, (void) );
  1961. 24293 FORWARD _PROTOTYPE( void print_init, (void) );
  1962. 24294 FORWARD _PROTOTYPE( void reply, (int code, int replyee, int process,
  1963. 24295                 int status) );
  1964. 24296 FORWARD _PROTOTYPE( int pr_handler, (int irq) );
  1965. 24297
  1966. 24298 /*===========================================================================*
  1967. 24299  *                              printer_task                                 *
  1968. 24300  *===========================================================================*/
  1969. 24301 PUBLIC void printer_task()
  1970. 24302 {
  1971. 24303 /* Main routine of the printer task. */
  1972. 24304
  1973. 24305   message pr_mess;              /* buffer for all incoming messages */
  1974. 24306
  1975. 24307   print_init();                 /* initialize */
  1976. 24308
  1977. 24309   while (TRUE) {
  1978. 24310         receive(ANY, &pr_mess);
  1979. 24311         switch(pr_mess.m_type) {
  1980. 24312             case DEV_OPEN:
  1981. 24313             case DEV_CLOSE:
  1982. 24314                 reply(TASK_REPLY, pr_mess.m_source, pr_mess.PROC_NR, OK);
  1983. 24315                 break;
  1984. 24316             case DEV_WRITE:     do_write(&pr_mess);     break;
  1985. 24317             case CANCEL   :     do_cancel(&pr_mess);    break;
  1986. 24318             case HARD_INT :     do_done();              break;
  1987. 24319             default:
  1988. 24320                 reply(TASK_REPLY, pr_mess.m_source, pr_mess.PROC_NR, EINVAL);
  1989. 24321         }
  1990. 24322   }
  1991. 24323 }
  1992. 24326 /*===========================================================================*
  1993. 24327  *                              do_write                                     *
  1994. 24328  *===========================================================================*/
  1995. 24329 PRIVATE void do_write(m_ptr)
  1996. 24330 register message *m_ptr;        /* pointer to the newly arrived message */
  1997. 24331 {
  1998. 24332 /* The printer is used by sending DEV_WRITE messages to it. Process one. */
  1999. 24333
  2000. 24334   register int r;
  2001. 24335
  2002. 24336   /* Reject command if last write is not finished, count not positive, or
  2003. 24337    * user address bad.
  2004. 24338    */
  2005. 24339   if (writing) {
  2006. 24340         r = EIO;
  2007. 24341   } else
  2008. 24342   if (m_ptr->COUNT <= 0) {
  2009. 24343         r = EINVAL;
  2010. 24344   } else
  2011. 24345   if (numap(m_ptr->PROC_NR, (vir_bytes) m_ptr->ADDRESS, m_ptr->COUNT) == 0) {
  2012. 24346         r = EFAULT;
  2013. 24347   } else {
  2014. 24348         /* Save information needed later. */
  2015. 24349         caller = m_ptr->m_source;
  2016. 24350         proc_nr = m_ptr->PROC_NR;
  2017. 24351         user_left = m_ptr->COUNT;
  2018. 24352         orig_count = m_ptr->COUNT;
  2019. 24353         user_vir = (vir_bytes) m_ptr->ADDRESS;
  2020. 24354         pr_start();
  2021. 24355         writing = TRUE;
  2022. 24356         r = SUSPEND;
  2023. 24357   }
  2024. 24358
  2025. 24359   /* Reply to FS, no matter what happened. */
  2026. 24360   reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, r);
  2027. 24361 }
  2028. 24364 /*===========================================================================*
  2029. 24365  *                              do_done                                      *
  2030. 24366  *===========================================================================*/
  2031. 24367 PRIVATE void do_done()
  2032. 24368 {
  2033. 24369 /* Previous chunk of printing is finished.  Continue if OK and more.
  2034. 24370  * Otherwise, reply to caller (FS).
  2035. 24371  */
  2036. 24372
  2037. 24373   register int status;
  2038. 24374
  2039. 24375   if (!writing) return;         /* interrupt while canceling */
  2040. 24376   if (done_status != OK) {
  2041. 24377         /* Printer error. */
  2042. 24378         status = EIO;
  2043. 24379         if ((done_status & ON_LINE) == 0) {
  2044. 24380                 printf("Printer is not on linen");
  2045. 24381         } else
  2046. 24382         if (done_status & NO_PAPER) {
  2047. 24383                 status = EAGAIN;        /* out of paper */
  2048. 24384         } else {
  2049. 24385                 printf("Printer error, status is 0x%02Xn", done_status);
  2050. 24386         }
  2051. 24387         if (status == EAGAIN && user_left < orig_count) {
  2052. 24388                 /* Some characters have been printed, tell how many. */
  2053. 24389                 status = orig_count - user_left;
  2054. 24390         }
  2055. 24391         oleft = 0;              /* cancel output by interrupt handler */
  2056. 24392   } else if (user_left != 0) {
  2057. 24393         pr_start();
  2058. 24394         return;
  2059. 24395   } else {
  2060. 24396         status = orig_count;
  2061. 24397   }
  2062. 24398   reply(REVIVE, caller, proc_nr, status);
  2063. 24399   writing = FALSE;
  2064. 24400 }
  2065. 24403 /*===========================================================================*
  2066. 24404  *                              do_cancel                                    *
  2067. 24405  *===========================================================================*/
  2068. 24406 PRIVATE void do_cancel(m_ptr)
  2069. 24407 register message *m_ptr;        /* pointer to the newly arrived message */
  2070. 24408 {
  2071. 24409 /* Cancel a print request that has already started.  Usually this means that
  2072. 24410  * the process doing the printing has been killed by a signal.  It is not
  2073. 24411  * clear if there are race conditions.  Try not to cancel the wrong process,
  2074. 24412  * but rely on FS to handle the EINTR reply and de-suspension properly.
  2075. 24413  */
  2076. 24414
  2077. 24415   if (writing && m_ptr->PROC_NR == proc_nr) {
  2078. 24416         oleft = 0;              /* cancel output by interrupt handler */
  2079. 24417         writing = FALSE;
  2080. 24418   }
  2081. 24419   reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, EINTR);
  2082. 24420 }
  2083. 24423 /*===========================================================================*
  2084. 24424  *                              reply                                        *
  2085. 24425  *===========================================================================*/
  2086. 24426 PRIVATE void reply(code, replyee, process, status)
  2087. 24427 int code;                       /* TASK_REPLY or REVIVE */
  2088. 24428 int replyee;                    /* destination for message (normally FS) */
  2089. 24429 int process;                    /* which user requested the printing */
  2090. 24430 int status;                     /* number of  chars printed or error code */
  2091. 24431 {
  2092. 24432 /* Send a reply telling FS that printing has started or stopped. */
  2093. 24433
  2094. 24434   message pr_mess;
  2095. 24435
  2096. 24436   pr_mess.m_type = code;        /* TASK_REPLY or REVIVE */
  2097. 24437   pr_mess.REP_STATUS = status;  /* count or EIO */
  2098. 24438   pr_mess.REP_PROC_NR = process;        /* which user does this pertain to */
  2099. 24439   send(replyee, &pr_mess);      /* send the message */
  2100. 24440 }
  2101. 24443 /*===========================================================================*
  2102. 24444  *                              print_init                                   *
  2103. 24445  *===========================================================================*/
  2104. 24446 PRIVATE void print_init()
  2105. 24447 {
  2106. 24448 /* Set global variables.  Get the port base for the first printer from the
  2107. 24449  * BIOS and initialize the printer.
  2108. 24450  */
  2109. 24451
  2110. 24452   phys_copy(0x408L, vir2phys(&port_base), 2L);
  2111. 24453   out_byte(port_base + 2, INIT_PRINTER);
  2112. 24454   milli_delay(2);               /* easily satisfies Centronics minimum */
  2113. 24455   out_byte(port_base + 2, SELECT);
  2114. 24456   put_irq_handler(PRINTER_IRQ, pr_handler);
  2115. 24457   enable_irq(PRINTER_IRQ);              /* ready for printer interrupts */
  2116. 24458 }
  2117. 24461 /*==========================================================================*
  2118. 24462  *                              pr_start                                    *
  2119. 24463  *==========================================================================*/
  2120. 24464 PRIVATE void pr_start()
  2121. 24465 {
  2122. 24466 /* Start next chunk of printer output. */
  2123. 24467
  2124. 24468   register int chunk;
  2125. 24469   phys_bytes user_phys;
  2126. 24470
  2127. 24471   if ( (chunk = user_left) > sizeof obuf) chunk = sizeof obuf;
  2128. 24472   user_phys = proc_vir2phys(proc_addr(proc_nr), user_vir);
  2129. 24473   phys_copy(user_phys, vir2phys(obuf), (phys_bytes) chunk);
  2130. 24474   optr = obuf;
  2131. 24475   opending = TRUE;
  2132. 24476   oleft = chunk;                /* now interrupt handler is enabled */
  2133. 24477 }
  2134. 24480 /*===========================================================================*
  2135. 24481  *                              pr_handler                                   *
  2136. 24482  *===========================================================================*/
  2137. 24483 PRIVATE int pr_handler(irq)
  2138. 24484 int irq;
  2139. 24485 {
  2140. 24486 /* This is the interrupt handler.  When a character has been printed, an
  2141. 24487  * interrupt occurs, and the assembly code routine trapped to calls
  2142. 24488  * pr_handler().
  2143. 24489  *
  2144. 24490  * One problem is that the 8259A controller generates spurious interrupts to
  2145. 24491  * IRQ7 when it gets confused by mistimed interrupts on any line.  (IRQ7 for
  2146. 24492  * the first controller happens to be the printer IRQ.)  Such an interrupt is
  2147. 24493  * ignored as a side-affect of the method of checking the busy status.  This
  2148. 24494  * is harmless for the printer task but probably fatal to the task that missed
  2149. 24495  * the interrupt.  It may be possible to recover by doing more work here.
  2150. 24496  */
  2151. 24497
  2152. 24498   register int status;
  2153. 24499
  2154. 24500   if (oleft == 0) {
  2155. 24501         /* Nothing more to print.  Turn off printer interrupts in case they
  2156. 24502          * are level-sensitive as on the PS/2.  This should be safe even
  2157. 24503          * when the printer is busy with a previous character, because the
  2158. 24504          * interrupt status does not affect the printer.
  2159. 24505          */
  2160. 24506         out_byte(port_base + 2, SELECT);
  2161. 24507         return 1;
  2162. 24508   }
  2163. 24509
  2164. 24510   do {
  2165. 24511         /* Loop to handle fast (buffered) printers.  It is important that
  2166. 24512          * processor interrupts are not disabled here, just printer interrupts.
  2167. 24513          */
  2168. 24514         status = in_byte(port_base + 1);
  2169. 24515         if ((status & STATUS_MASK) == BUSY_STATUS) {
  2170. 24516                 /* Still busy with last output.  This normally happens
  2171. 24517                  * immediately after doing output to an unbuffered or slow
  2172. 24518                  * printer.  It may happen after a call from pr_start or
  2173. 24519                  * pr_restart, since they are not synchronized with printer
  2174. 24520                  * interrupts.  It may happen after a spurious interrupt.
  2175. 24521                  */
  2176. 24522                 return 1;
  2177. 24523         }
  2178. 24524         if ((status & STATUS_MASK) == NORMAL_STATUS) {
  2179. 24525                 /* Everything is all right.  Output another character. */
  2180. 24526                 out_byte(port_base, *optr++);   /* output character */
  2181. 24527                 lock();         /* ensure strobe is not too long */
  2182. 24528                 out_byte(port_base + 2, ASSERT_STROBE);
  2183. 24529                 out_byte(port_base + 2, NEGATE_STROBE);
  2184. 24530                 unlock();
  2185. 24531                 opending = FALSE;       /* show interrupt is working */
  2186. 24532
  2187. 24533                 user_vir++;
  2188. 24534                 user_left--;
  2189. 24535         } else {
  2190. 24536                 /* Error.  This would be better ignored (treat as busy). */
  2191. 24537                 done_status = status;
  2192. 24538                 interrupt(PRINTER);
  2193. 24539                 return 1;
  2194. 24540         }
  2195. 24541   }
  2196. 24542   while (--oleft != 0);
  2197. 24543
  2198. 24544   /* Finished printing chunk OK. */
  2199. 24545   done_status = OK;
  2200. 24546   interrupt(PRINTER);
  2201. 24547   return 1;     /* Reenable printer interrupt */
  2202. 24548 }
  2203. 24551 /*==========================================================================*
  2204. 24552  *                              pr_restart                                  *
  2205. 24553  *==========================================================================*/
  2206. 24554 PUBLIC void pr_restart()
  2207. 24555 {
  2208. 24556 /* Check if printer is hung up, and if so, restart it.
  2209. 24557  * Disable_irq() returns true if the irq could be disabled, so that
  2210. 24558  * pr_restart() is not reentered.
  2211. 24559  */
  2212. 24560
  2213. 24561   if (oleft != 0) {
  2214. 24562         if (opending && disable_irq(PRINTER_IRQ)) {
  2215. 24563                 (void) pr_handler(PRINTER_IRQ);
  2216. 24564
  2217. 24565                 /* ready for printer interrupts again */
  2218. 24566                 enable_irq(PRINTER_IRQ);
  2219. 24567         }
  2220. 24568         opending = TRUE;        /* expect some printing before next call */
  2221. 24569   }
  2222. 24570 }
  2223. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2224. src/kernel/proc.c    
  2225. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2226. 24600 /* This file contains essentially all of the process and message handling.
  2227. 24601  * It has two main entry points from the outside:
  2228. 24602  *
  2229. 24603  *   sys_call:   called when a process or task does SEND, RECEIVE or SENDREC
  2230. 24604  *   interrupt: called by interrupt routines to send a message to task
  2231. 24605  *
  2232. 24606  * It also has several minor entry points:
  2233. 24607  *
  2234. 24608  *   lock_ready:      put a process on one of the ready queues so it can be run
  2235. 24609  *   lock_unready:    remove a process from the ready queues
  2236. 24610  *   lock_sched:      a process has run too long; schedule another one
  2237. 24611  *   lock_mini_send:  send a message (used by interrupt signals, etc.)
  2238. 24612  *   lock_pick_proc:  pick a process to run (used by system initialization)
  2239. 24613  *   unhold:          repeat all held-up interrupts
  2240. 24614  */
  2241. 24615
  2242. 24616 #include "kernel.h"
  2243. 24617 #include <minix/callnr.h>
  2244. 24618 #include <minix/com.h>
  2245. 24619 #include "proc.h"
  2246. 24620
  2247. 24621 PRIVATE unsigned char switching;        /* nonzero to inhibit interrupt() */
  2248. 24622
  2249. 24623 FORWARD _PROTOTYPE( int mini_send, (struct proc *caller_ptr, int dest,
  2250. 24624                 message *m_ptr) );
  2251. 24625 FORWARD _PROTOTYPE( int mini_rec, (struct proc *caller_ptr, int src,
  2252. 24626                 message *m_ptr) );
  2253. 24627 FORWARD _PROTOTYPE( void ready, (struct proc *rp) );
  2254. 24628 FORWARD _PROTOTYPE( void sched, (void) );
  2255. 24629 FORWARD _PROTOTYPE( void unready, (struct proc *rp) );
  2256. 24630 FORWARD _PROTOTYPE( void pick_proc, (void) );
  2257. 24631
  2258. 24632 #if (CHIP == M68000)
  2259. 24633 FORWARD _PROTOTYPE( void cp_mess, (int src, struct proc *src_p, message *src_m,
  2260. 24634                 struct proc *dst_p, message *dst_m) );
  2261. 24635 #endif
  2262. 24636
  2263. 24637 #if (CHIP == INTEL)
  2264. 24638 #define CopyMess(s,sp,sm,dp,dm) 
  2265. 24639         cp_mess(s, (sp)->p_map[D].mem_phys, (vir_bytes)sm, (dp)->p_map[D].mem_phys, (vir_bytes)dm)
  2266. 24640 #endif
  2267. 24641
  2268. 24642 #if (CHIP == M68000)
  2269. 24643 #define CopyMess(s,sp,sm,dp,dm) 
  2270. 24644         cp_mess(s,sp,sm,dp,dm)
  2271. 24645 #endif
  2272. 24646
  2273. 24647 /*===========================================================================*
  2274. 24648  *                              interrupt                                    * 
  2275. 24649  *===========================================================================*/
  2276. 24650 PUBLIC void interrupt(task)
  2277. 24651 int task;                       /* number of task to be started */
  2278. 24652 {
  2279. 24653 /* An interrupt has occurred.  Schedule the task that handles it. */
  2280. 24654
  2281. 24655   register struct proc *rp;     /* pointer to task's proc entry */
  2282. 24656
  2283. 24657   rp = proc_addr(task);
  2284. 24658
  2285. 24659   /* If this call would compete with other process-switching functions, put
  2286. 24660    * it on the 'held' queue to be flushed at the next non-competing restart().
  2287. 24661    * The competing conditions are:
  2288. 24662    * (1) k_reenter == (typeof k_reenter) -1:
  2289. 24663    *     Call from the task level, typically from an output interrupt
  2290. 24664    *     routine.  An interrupt handler might reenter interrupt().  Rare,
  2291. 24665    *     so not worth special treatment.
  2292. 24666    * (2) k_reenter > 0:
  2293. 24667    *     Call from a nested interrupt handler.  A previous interrupt handler
  2294. 24668    *     might be inside interrupt() or sys_call().
  2295. 24669    * (3) switching != 0:
  2296. 24670    *     Some process-switching function other than interrupt() is being
  2297. 24671    *     called from the task level, typically sched() from CLOCK.  An
  2298. 24672    *     interrupt handler might call interrupt and pass the k_reenter test.
  2299. 24673    */
  2300. 24674   if (k_reenter != 0 || switching) {
  2301. 24675         lock();
  2302. 24676         if (!rp->p_int_held) {
  2303. 24677                 rp->p_int_held = TRUE;
  2304. 24678                 if (held_head != NIL_PROC)
  2305. 24679                         held_tail->p_nextheld = rp;
  2306. 24680                 else
  2307. 24681                         held_head = rp;
  2308. 24682                 held_tail = rp;
  2309. 24683                 rp->p_nextheld = NIL_PROC;
  2310. 24684         }
  2311. 24685         unlock();
  2312. 24686         return;
  2313. 24687   }
  2314. 24688
  2315. 24689   /* If task is not waiting for an interrupt, record the blockage. */
  2316. 24690   if ( (rp->p_flags & (RECEIVING | SENDING)) != RECEIVING ||
  2317. 24691       !isrxhardware(rp->p_getfrom)) {
  2318. 24692         rp->p_int_blocked = TRUE;
  2319. 24693         return;
  2320. 24694   }
  2321. 24695
  2322. 24696   /* Destination is waiting for an interrupt.
  2323. 24697    * Send it a message with source HARDWARE and type HARD_INT.
  2324. 24698    * No more information can be reliably provided since interrupt messages
  2325. 24699    * are not queued.
  2326. 24700    */
  2327. 24701   rp->p_messbuf->m_source = HARDWARE;
  2328. 24702   rp->p_messbuf->m_type = HARD_INT;
  2329. 24703   rp->p_flags &= ~RECEIVING;
  2330. 24704   rp->p_int_blocked = FALSE;
  2331. 24705
  2332. 24706    /* Make rp ready and run it unless a task is already running.  This is
  2333. 24707     * ready(rp) in-line for speed.
  2334. 24708     */
  2335. 24709   if (rdy_head[TASK_Q] != NIL_PROC)
  2336. 24710         rdy_tail[TASK_Q]->p_nextready = rp;
  2337. 24711   else
  2338. 24712         proc_ptr = rdy_head[TASK_Q] = rp;
  2339. 24713   rdy_tail[TASK_Q] = rp;
  2340. 24714   rp->p_nextready = NIL_PROC;
  2341. 24715 }
  2342. 24717 /*===========================================================================*
  2343. 24718  *                              sys_call                                     * 
  2344. 24719  *===========================================================================*/
  2345. 24720 PUBLIC int sys_call(function, src_dest, m_ptr)
  2346. 24721 int function;                   /* SEND, RECEIVE, or BOTH */
  2347. 24722 int src_dest;                   /* source to receive from or dest to send to */
  2348. 24723 message *m_ptr;                 /* pointer to message */
  2349. 24724 {
  2350. 24725 /* The only system calls that exist in MINIX are sending and receiving
  2351. 24726  * messages.  These are done by trapping to the kernel with an INT instruction.
  2352. 24727  * The trap is caught and sys_call() is called to send or receive a message
  2353. 24728  * (or both). The caller is always given by proc_ptr.
  2354. 24729  */
  2355. 24730
  2356. 24731   register struct proc *rp;
  2357. 24732   int n;
  2358. 24733
  2359. 24734   /* Check for bad system call parameters. */
  2360. 24735   if (!isoksrc_dest(src_dest)) return(E_BAD_SRC);
  2361. 24736   rp = proc_ptr;
  2362. 24737
  2363. 24738   if (isuserp(rp) && function != BOTH) return(E_NO_PERM);
  2364. 24739   
  2365. 24740   /* The parameters are ok. Do the call. */
  2366. 24741   if (function & SEND) {
  2367. 24742         /* Function = SEND or BOTH. */
  2368. 24743         n = mini_send(rp, src_dest, m_ptr);
  2369. 24744         if (function == SEND || n != OK)
  2370. 24745                 return(n);      /* done, or SEND failed */
  2371. 24746   }
  2372. 24747
  2373. 24748   /* Function = RECEIVE or BOTH.
  2374. 24749    * We have checked user calls are BOTH, and trust 'function' otherwise.
  2375. 24750    */
  2376. 24751   return(mini_rec(rp, src_dest, m_ptr));
  2377. 24752 }
  2378. 24754 /*===========================================================================*
  2379. 24755  *                              mini_send                                    * 
  2380. 24756  *===========================================================================*/
  2381. 24757 PRIVATE int mini_send(caller_ptr, dest, m_ptr)
  2382. 24758 register struct proc *caller_ptr;       /* who is trying to send a message? */
  2383. 24759 int dest;                       /* to whom is message being sent? */
  2384. 24760 message *m_ptr;                 /* pointer to message buffer */
  2385. 24761 {
  2386. 24762 /* Send a message from 'caller_ptr' to 'dest'. If 'dest' is blocked waiting
  2387. 24763  * for this message, copy the message to it and unblock 'dest'. If 'dest' is
  2388. 24764  * not waiting at all, or is waiting for another source, queue 'caller_ptr'.
  2389. 24765  */
  2390. 24766
  2391. 24767   register struct proc *dest_ptr, *next_ptr;
  2392. 24768   vir_bytes vb;                 /* message buffer pointer as vir_bytes */
  2393. 24769   vir_clicks vlo, vhi;          /* virtual clicks containing message to send */
  2394. 24770
  2395. 24771   /* User processes are only allowed to send to FS and MM.  Check for this. */
  2396. 24772   if (isuserp(caller_ptr) && !issysentn(dest)) return(E_BAD_DEST);
  2397. 24773   dest_ptr = proc_addr(dest);   /* pointer to destination's proc entry */
  2398. 24774   if (dest_ptr->p_flags & P_SLOT_FREE) return(E_BAD_DEST);      /* dead dest */
  2399. 24775
  2400. 24776 #if ALLOW_GAP_MESSAGES
  2401. 24777   /* This check allows a message to be anywhere in data or stack or gap. 
  2402. 24778    * It will have to be made more elaborate later for machines which
  2403. 24779    * don't have the gap mapped.
  2404. 24780    */
  2405. 24781   vb = (vir_bytes) m_ptr;
  2406. 24782   vlo = vb >> CLICK_SHIFT;      /* vir click for bottom of message */
  2407. 24783   vhi = (vb + MESS_SIZE - 1) >> CLICK_SHIFT;    /* vir click for top of msg */
  2408. 24784   if (vlo < caller_ptr->p_map[D].mem_vir || vlo > vhi ||
  2409. 24785       vhi >= caller_ptr->p_map[S].mem_vir + caller_ptr->p_map[S].mem_len)
  2410. 24786         return(EFAULT); 
  2411. 24787 #else
  2412. 24788   /* Check for messages wrapping around top of memory or outside data seg. */
  2413. 24789   vb = (vir_bytes) m_ptr;
  2414. 24790   vlo = vb >> CLICK_SHIFT;      /* vir click for bottom of message */
  2415. 24791   vhi = (vb + MESS_SIZE - 1) >> CLICK_SHIFT;    /* vir click for top of msg */
  2416. 24792   if (vhi < vlo ||
  2417. 24793       vhi - caller_ptr->p_map[D].mem_vir >= caller_ptr->p_map[D].mem_len)
  2418. 24794         return(EFAULT);
  2419. 24795 #endif
  2420. 24796
  2421. 24797   /* Check for deadlock by 'caller_ptr' and 'dest' sending to each other. */
  2422. 24798   if (dest_ptr->p_flags & SENDING) {
  2423. 24799         next_ptr = proc_addr(dest_ptr->p_sendto);
  2424. 24800         while (TRUE) {
  2425. 24801                 if (next_ptr == caller_ptr) return(ELOCKED);
  2426. 24802                 if (next_ptr->p_flags & SENDING)
  2427. 24803                         next_ptr = proc_addr(next_ptr->p_sendto);
  2428. 24804                 else
  2429. 24805                         break;
  2430. 24806         }
  2431. 24807   }
  2432. 24808
  2433. 24809   /* Check to see if 'dest' is blocked waiting for this message. */
  2434. 24810   if ( (dest_ptr->p_flags & (RECEIVING | SENDING)) == RECEIVING &&
  2435. 24811        (dest_ptr->p_getfrom == ANY ||
  2436. 24812         dest_ptr->p_getfrom == proc_number(caller_ptr))) {
  2437. 24813         /* Destination is indeed waiting for this message. */
  2438. 24814         CopyMess(proc_number(caller_ptr), caller_ptr, m_ptr, dest_ptr,
  2439. 24815                  dest_ptr->p_messbuf);
  2440. 24816         dest_ptr->p_flags &= ~RECEIVING;        /* deblock destination */
  2441. 24817         if (dest_ptr->p_flags == 0) ready(dest_ptr);
  2442. 24818   } else {
  2443. 24819         /* Destination is not waiting.  Block and queue caller. */
  2444. 24820         caller_ptr->p_messbuf = m_ptr;
  2445. 24821         if (caller_ptr->p_flags == 0) unready(caller_ptr);
  2446. 24822         caller_ptr->p_flags |= SENDING;
  2447. 24823         caller_ptr->p_sendto= dest;
  2448. 24824
  2449. 24825         /* Process is now blocked.  Put in on the destination's queue. */
  2450. 24826         if ( (next_ptr = dest_ptr->p_callerq) == NIL_PROC)
  2451. 24827                 dest_ptr->p_callerq = caller_ptr;
  2452. 24828         else {
  2453. 24829                 while (next_ptr->p_sendlink != NIL_PROC)
  2454. 24830                         next_ptr = next_ptr->p_sendlink;
  2455. 24831                 next_ptr->p_sendlink = caller_ptr;
  2456. 24832         }
  2457. 24833         caller_ptr->p_sendlink = NIL_PROC;
  2458. 24834   }
  2459. 24835   return(OK);
  2460. 24836 }
  2461. 24838 /*===========================================================================*
  2462. 24839  *                              mini_rec                                     * 
  2463. 24840  *===========================================================================*/
  2464. 24841 PRIVATE int mini_rec(caller_ptr, src, m_ptr)
  2465. 24842 register struct proc *caller_ptr;       /* process trying to get message */
  2466. 24843 int src;                        /* which message source is wanted (or ANY) */
  2467. 24844 message *m_ptr;                 /* pointer to message buffer */
  2468. 24845 {
  2469. 24846 /* A process or task wants to get a message.  If one is already queued,
  2470. 24847  * acquire it and deblock the sender.  If no message from the desired source
  2471. 24848  * is available, block the caller.  No need to check parameters for validity.
  2472. 24849  * Users calls are always sendrec(), and mini_send() has checked already.  
  2473. 24850  * Calls from the tasks, MM, and FS are trusted.
  2474. 24851  */
  2475. 24852
  2476. 24853   register struct proc *sender_ptr;
  2477. 24854   register struct proc *previous_ptr;
  2478. 24855
  2479. 24856   /* Check to see if a message from desired source is already available. */
  2480. 24857   if (!(caller_ptr->p_flags & SENDING)) {
  2481. 24858         /* Check caller queue. */
  2482. 24859     for (sender_ptr = caller_ptr->p_callerq; sender_ptr != NIL_PROC;
  2483. 24860          previous_ptr = sender_ptr, sender_ptr = sender_ptr->p_sendlink) {
  2484. 24861         if (src == ANY || src == proc_number(sender_ptr)) {
  2485. 24862                 /* An acceptable message has been found. */
  2486. 24863                 CopyMess(proc_number(sender_ptr), sender_ptr,
  2487. 24864                          sender_ptr->p_messbuf, caller_ptr, m_ptr);
  2488. 24865                 if (sender_ptr == caller_ptr->p_callerq)
  2489. 24866                         caller_ptr->p_callerq = sender_ptr->p_sendlink;
  2490. 24867                 else
  2491. 24868                         previous_ptr->p_sendlink = sender_ptr->p_sendlink;
  2492. 24869                 if ((sender_ptr->p_flags &= ~SENDING) == 0)
  2493. 24870                         ready(sender_ptr);      /* deblock sender */
  2494. 24871                 return(OK);
  2495. 24872         }
  2496. 24873     }
  2497. 24874
  2498. 24875     /* Check for blocked interrupt. */
  2499. 24876     if (caller_ptr->p_int_blocked && isrxhardware(src)) {
  2500. 24877         m_ptr->m_source = HARDWARE;
  2501. 24878         m_ptr->m_type = HARD_INT;
  2502. 24879         caller_ptr->p_int_blocked = FALSE;
  2503. 24880         return(OK);
  2504. 24881     }
  2505. 24882   }
  2506. 24883
  2507. 24884   /* No suitable message is available.  Block the process trying to receive. */
  2508. 24885   caller_ptr->p_getfrom = src;
  2509. 24886   caller_ptr->p_messbuf = m_ptr;
  2510. 24887   if (caller_ptr->p_flags == 0) unready(caller_ptr);
  2511. 24888   caller_ptr->p_flags |= RECEIVING;
  2512. 24889
  2513. 24890   /* If MM has just blocked and there are kernel signals pending, now is the
  2514. 24891    * time to tell MM about them, since it will be able to accept the message.
  2515. 24892    */
  2516. 24893   if (sig_procs > 0 && proc_number(caller_ptr) == MM_PROC_NR && src == ANY)
  2517. 24894         inform();
  2518. 24895   return(OK);
  2519. 24896 }
  2520. 24898 /*===========================================================================*
  2521. 24899  *                              pick_proc                                    * 
  2522. 24900  *===========================================================================*/
  2523. 24901 PRIVATE void pick_proc()
  2524. 24902 {
  2525. 24903 /* Decide who to run now.  A new process is selected by setting 'proc_ptr'.
  2526. 24904  * When a fresh user (or idle) process is selected, record it in 'bill_ptr',
  2527. 24905  * so the clock task can tell who to bill for system time.
  2528. 24906  */
  2529. 24907
  2530. 24908   register struct proc *rp;     /* process to run */
  2531. 24909
  2532. 24910   if ( (rp = rdy_head[TASK_Q]) != NIL_PROC) {
  2533. 24911         proc_ptr = rp;
  2534. 24912         return;
  2535. 24913   }
  2536. 24914   if ( (rp = rdy_head[SERVER_Q]) != NIL_PROC) {
  2537. 24915         proc_ptr = rp;
  2538. 24916         return;
  2539. 24917   }
  2540. 24918   if ( (rp = rdy_head[USER_Q]) != NIL_PROC) {
  2541. 24919         proc_ptr = rp;
  2542. 24920         bill_ptr = rp;
  2543. 24921         return;
  2544. 24922   }
  2545. 24923   /* No one is ready.  Run the idle task.  The idle task might be made an
  2546. 24924    * always-ready user task to avoid this special case.
  2547. 24925    */
  2548. 24926   bill_ptr = proc_ptr = proc_addr(IDLE);
  2549. 24927 }
  2550. 24929 /*===========================================================================*
  2551. 24930  *                              ready                                        * 
  2552. 24931  *===========================================================================*/
  2553. 24932 PRIVATE void ready(rp)
  2554. 24933 register struct proc *rp;       /* this process is now runnable */
  2555. 24934 {
  2556. 24935 /* Add 'rp' to the end of one of the queues of runnable processes. Three
  2557. 24936  * queues are maintained:
  2558. 24937  *   TASK_Q   - (highest priority) for runnable tasks
  2559. 24938  *   SERVER_Q - (middle priority) for MM and FS only
  2560. 24939  *   USER_Q   - (lowest priority) for user processes
  2561. 24940  */
  2562. 24941
  2563. 24942   if (istaskp(rp)) {
  2564. 24943         if (rdy_head[TASK_Q] != NIL_PROC)
  2565. 24944                 /* Add to tail of nonempty queue. */
  2566. 24945                 rdy_tail[TASK_Q]->p_nextready = rp;
  2567. 24946         else {
  2568. 24947                 proc_ptr =              /* run fresh task next */
  2569. 24948                 rdy_head[TASK_Q] = rp;  /* add to empty queue */
  2570. 24949         }
  2571. 24950         rdy_tail[TASK_Q] = rp;
  2572. 24951         rp->p_nextready = NIL_PROC;     /* new entry has no successor */
  2573. 24952         return;
  2574. 24953   }
  2575. 24954   if (!isuserp(rp)) {           /* others are similar */
  2576. 24955         if (rdy_head[SERVER_Q] != NIL_PROC)
  2577. 24956                 rdy_tail[SERVER_Q]->p_nextready = rp;
  2578. 24957         else
  2579. 24958                 rdy_head[SERVER_Q] = rp;
  2580. 24959         rdy_tail[SERVER_Q] = rp;
  2581. 24960         rp->p_nextready = NIL_PROC;
  2582. 24961         return;
  2583. 24962   }
  2584. 24963 #if (SHADOWING == 1)
  2585. 24964   if (isshadowp(rp)) {          /* others are similar */
  2586. 24965         if (rdy_head[SHADOW_Q] != NIL_PROC)
  2587. 24966                 rdy_tail[SHADOW_Q]->p_nextready = rp;
  2588. 24967         else
  2589. 24968                 rdy_head[SHADOW_Q] = rp;
  2590. 24969         rdy_tail[SHADOW_Q] = rp;
  2591. 24970         rp->p_nextready = NIL_PROC;
  2592. 24971         return;
  2593. 24972   }
  2594. 24973 #endif
  2595. 24974   if (rdy_head[USER_Q] == NIL_PROC)
  2596. 24975         rdy_tail[USER_Q] = rp;
  2597. 24976   rp->p_nextready = rdy_head[USER_Q];
  2598. 24977   rdy_head[USER_Q] = rp;
  2599. 24978 /*
  2600. 24979   if (rdy_head[USER_Q] != NIL_PROC)
  2601. 24980         rdy_tail[USER_Q]->p_nextready = rp;
  2602. 24981   else
  2603. 24982         rdy_head[USER_Q] = rp;
  2604. 24983   rdy_tail[USER_Q] = rp;
  2605. 24984   rp->p_nextready = NIL_PROC;
  2606. 24985 */
  2607. 24986 }
  2608. 24988 /*===========================================================================*
  2609. 24989  *                              unready                                      * 
  2610. 24990  *===========================================================================*/
  2611. 24991 PRIVATE void unready(rp)
  2612. 24992 register struct proc *rp;       /* this process is no longer runnable */
  2613. 24993 {
  2614. 24994 /* A process has blocked. */
  2615. 24995
  2616. 24996   register struct proc *xp;
  2617. 24997   register struct proc **qtail;  /* TASK_Q, SERVER_Q, or USER_Q rdy_tail */
  2618. 24998
  2619. 24999   if (istaskp(rp)) {
  2620. 25000         /* task stack still ok? */
  2621. 25001         if (*rp->p_stguard != STACK_GUARD)
  2622. 25002                 panic("stack overrun by task", proc_number(rp));
  2623. 25003
  2624. 25004         if ( (xp = rdy_head[TASK_Q]) == NIL_PROC) return;
  2625. 25005         if (xp == rp) {
  2626. 25006                 /* Remove head of queue */
  2627. 25007                 rdy_head[TASK_Q] = xp->p_nextready;
  2628. 25008                 if (rp == proc_ptr) pick_proc();
  2629. 25009                 return;
  2630. 25010         }
  2631. 25011         qtail = &rdy_tail[TASK_Q];
  2632. 25012   }
  2633. 25013   else if (!isuserp(rp)) {
  2634. 25014         if ( (xp = rdy_head[SERVER_Q]) == NIL_PROC) return;
  2635. 25015         if (xp == rp) {
  2636. 25016                 rdy_head[SERVER_Q] = xp->p_nextready;
  2637. 25017 #if (CHIP == M68000)
  2638. 25018                 if (rp == proc_ptr)
  2639. 25019 #endif
  2640. 25020                 pick_proc();
  2641. 25021                 return;
  2642. 25022         }
  2643. 25023         qtail = &rdy_tail[SERVER_Q];
  2644. 25024   } else
  2645. 25025 #if (SHADOWING == 1)
  2646. 25026   if (isshadowp(rp)) {
  2647. 25027         if ( (xp = rdy_head[SHADOW_Q]) == NIL_PROC) return;
  2648. 25028         if (xp == rp) {
  2649. 25029                 rdy_head[SHADOW_Q] = xp->p_nextready;
  2650. 25030                 if (rp == proc_ptr)
  2651. 25031                         pick_proc();
  2652. 25032                 return;
  2653. 25033         }
  2654. 25034         qtail = &rdy_tail[SHADOW_Q];
  2655. 25035   } else
  2656. 25036 #endif
  2657. 25037   {
  2658. 25038         if ( (xp = rdy_head[USER_Q]) == NIL_PROC) return;
  2659. 25039         if (xp == rp) {
  2660. 25040                 rdy_head[USER_Q] = xp->p_nextready;
  2661. 25041 #if (CHIP == M68000)
  2662. 25042                 if (rp == proc_ptr)
  2663. 25043 #endif
  2664. 25044                 pick_proc();
  2665. 25045                 return;
  2666. 25046         }
  2667. 25047         qtail = &rdy_tail[USER_Q];
  2668. 25048   }
  2669. 25049
  2670. 25050   /* Search body of queue.  A process can be made unready even if it is
  2671. 25051    * not running by being sent a signal that kills it.
  2672. 25052    */
  2673. 25053   while (xp->p_nextready != rp)
  2674. 25054         if ( (xp = xp->p_nextready) == NIL_PROC) return;
  2675. 25055   xp->p_nextready = xp->p_nextready->p_nextready;
  2676. 25056   if (*qtail == rp) *qtail = xp;
  2677. 25057 }
  2678. 25059 /*===========================================================================*
  2679. 25060  *                              sched                                        * 
  2680. 25061  *===========================================================================*/
  2681. 25062 PRIVATE void sched()
  2682. 25063 {
  2683. 25064 /* The current process has run too long.  If another low priority (user)
  2684. 25065  * process is runnable, put the current process on the end of the user queue,
  2685. 25066  * possibly promoting another user to head of the queue.
  2686. 25067  */
  2687. 25068
  2688. 25069   if (rdy_head[USER_Q] == NIL_PROC) return;
  2689. 25070
  2690. 25071   /* One or more user processes queued. */
  2691. 25072   rdy_tail[USER_Q]->p_nextready = rdy_head[USER_Q];
  2692. 25073   rdy_tail[USER_Q] = rdy_head[USER_Q];
  2693. 25074   rdy_head[USER_Q] = rdy_head[USER_Q]->p_nextready;
  2694. 25075   rdy_tail[USER_Q]->p_nextready = NIL_PROC;
  2695. 25076   pick_proc();
  2696. 25077 }
  2697. 25079 /*==========================================================================*
  2698. 25080  *                              lock_mini_send                              *
  2699. 25081  *==========================================================================*/
  2700. 25082 PUBLIC int lock_mini_send(caller_ptr, dest, m_ptr)
  2701. 25083 struct proc *caller_ptr;        /* who is trying to send a message? */
  2702. 25084 int dest;                       /* to whom is message being sent? */
  2703. 25085 message *m_ptr;                 /* pointer to message buffer */
  2704. 25086 {
  2705. 25087 /* Safe gateway to mini_send() for tasks. */
  2706. 25088
  2707. 25089   int result;
  2708. 25090
  2709. 25091   switching = TRUE;
  2710. 25092   result = mini_send(caller_ptr, dest, m_ptr);
  2711. 25093   switching = FALSE;
  2712. 25094   return(result);
  2713. 25095 }
  2714. 25097 /*==========================================================================*
  2715. 25098  *                              lock_pick_proc                              *
  2716. 25099  *==========================================================================*/
  2717. 25100 PUBLIC void lock_pick_proc()
  2718. 25101 {
  2719. 25102 /* Safe gateway to pick_proc() for tasks. */
  2720. 25103
  2721. 25104   switching = TRUE;
  2722. 25105   pick_proc();
  2723. 25106   switching = FALSE;
  2724. 25107 }
  2725. 25109 /*==========================================================================*
  2726. 25110  *                              lock_ready                                  *
  2727. 25111  *==========================================================================*/
  2728. 25112 PUBLIC void lock_ready(rp)
  2729. 25113 struct proc *rp;                /* this process is now runnable */
  2730. 25114 {
  2731. 25115 /* Safe gateway to ready() for tasks. */
  2732. 25116
  2733. 25117   switching = TRUE;
  2734. 25118   ready(rp);
  2735. 25119   switching = FALSE;
  2736. 25120 }
  2737. 25122 /*==========================================================================*
  2738. 25123  *                              lock_unready                                *
  2739. 25124  *==========================================================================*/
  2740. 25125 PUBLIC void lock_unready(rp)
  2741. 25126 struct proc *rp;                /* this process is no longer runnable */
  2742. 25127 {
  2743. 25128 /* Safe gateway to unready() for tasks. */
  2744. 25129
  2745. 25130   switching = TRUE;
  2746. 25131   unready(rp);
  2747. 25132   switching = FALSE;
  2748. 25133 }
  2749. 25135 /*==========================================================================*
  2750. 25136  *                              lock_sched                                  *
  2751. 25137  *==========================================================================*/
  2752. 25138 PUBLIC void lock_sched()
  2753. 25139 {
  2754. 25140 /* Safe gateway to sched() for tasks. */
  2755. 25141
  2756. 25142   switching = TRUE;
  2757. 25143   sched();
  2758. 25144   switching = FALSE;
  2759. 25145 }
  2760. 25147 /*==========================================================================*
  2761. 25148  *                              unhold                                      *
  2762. 25149  *==========================================================================*/
  2763. 25150 PUBLIC void unhold()
  2764. 25151 {
  2765. 25152 /* Flush any held-up interrupts.  k_reenter must be 0.  held_head must not
  2766. 25153  * be NIL_PROC.  Interrupts must be disabled.  They will be enabled but will
  2767. 25154  * be disabled when this returns.
  2768. 25155  */
  2769. 25156