summaryrefslogtreecommitdiffstats
path: root/sys/i386/isa/matcd/audio.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/i386/isa/matcd/audio.c')
-rw-r--r--sys/i386/isa/matcd/audio.c514
1 files changed, 514 insertions, 0 deletions
diff --git a/sys/i386/isa/matcd/audio.c b/sys/i386/isa/matcd/audio.c
new file mode 100644
index 0000000..837689a
--- /dev/null
+++ b/sys/i386/isa/matcd/audio.c
@@ -0,0 +1,514 @@
+/*audio.c--------------------------------------------------------------------
+
+ Matsushita(Panasonic) / Creative CD-ROM Driver (matcd)
+ Authored by Frank Durda IV
+
+ Copyright 1994, 1995 Frank Durda IV. All rights reserved.
+ "FDIV" is a trademark of Frank Durda IV.
+
+
+ Redistribution and use in source and binary forms, with or
+ without modification, are permitted provided that the following
+ conditions are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice positioned at the very beginning of this file without
+ modification, all copyright strings, all related programming
+ codes that display the copyright strings, this list of
+ conditions and the following disclaimer.
+ 2. Redistributions in binary form must contain all copyright strings
+ and related programming code that display the copyright strings.
+ 3. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ 4. All advertising materials mentioning features or use of this
+ software must display the following acknowledgement:
+ "The Matsushita/Panasonic CD-ROM driver was developed
+ by Frank Durda IV for use with "FreeBSD" and similar
+ operating systems."
+ "Similar operating systems" includes mainly non-profit oriented
+ systems for research and education, including but not restricted
+ to "NetBSD", "386BSD", and "Mach" (by CMU). The wording of the
+ acknowledgement (in electronic form or printed text) may not be
+ changed without permission from the author.
+ 5. Absolutely no warranty of function, fitness or purpose is made
+ by the author Frank Durda IV.
+ 6. Neither the name of the author nor the name "FreeBSD" may
+ be used to endorse or promote products derived from this software
+ without specific prior written permission.
+ (The author can be reached at bsdmail@nemesis.lonestar.org)
+ 7. The product containing this software must meet all of these
+ conditions even if it is unsupported, not a complete system
+ and/or does not contain compiled code.
+ 8. These conditions will be in force for the full life of the
+ copyright.
+ 9. If all the above conditions are met, modifications to other
+ parts of this file may be freely made, although any person
+ or persons making changes do not receive the right to add their
+ name or names to the copyright strings and notices in this
+ software. Persons making changes are encouraged to insert edit
+ history in matcd.c and to put your name and details of the
+ change there.
+ 10. You must have prior written permission from the author to
+ deviate from these terms.
+
+ Vendors who produce product(s) containing this code are encouraged
+ (but not required) to provide copies of the finished product(s) to
+ the author and to correspond with the author about development
+ activity relating to this code. Donations of development hardware
+ and/or software are also welcome. (This is one of the faster ways
+ to get a driver developed for a device.)
+
+ THIS SOFTWARE IS PROVIDED BY THE DEVELOPER(S) ``AS IS'' AND ANY
+ EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPER(S) BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+-----No changes are allowed above this line------------------------------------
+
+ The following functions are related to the audio playback
+ capabilities of the drive. They can be omitted from the
+ finished driver using the FULLDRIVER conditional.
+
+ The full set of features the drive is capable of are currently
+ not implemented but will be added in upcoming releases.
+-----------------------------------------------------------------------------*/
+/*-----------------------------------------------------------------------------
+ matcd_playtracks - Plays one or more audio tracks
+-----------------------------------------------------------------------------*/
+
+static int matcd_playtracks(int ldrive, int cdrive, int controller,
+ struct ioc_play_track *pt)
+{
+ struct matcd_data *cd;
+ int start,end;
+ int i,port;
+ unsigned char cmd[MAXCMDSIZ];
+
+ cd=&matcd_data[ldrive];
+ port=cd->iobase;
+
+ if ((cd->flags & MATCDLABEL)==0)
+ return(EIO); /*Refuse after chg error*/
+
+ start=pt->start_track;
+ end=pt->end_track;
+
+ if (start < 1 || /*Starting track valid?*/
+ end < 1 || /*Ending track valid?*/
+ start > end || /*Start higher than end?*/
+ end > cd->volinfo.trk_high) /*End track higher than disc size?*/
+ return(ESPIPE); /*Track out of range*/
+
+ lockbus(controller, ldrive); /*<16>Request bus*/
+ i=matcd_setmode(ldrive, MODE_DA);/*Force drive into audio mode*/
+ unlockbus(controller, ldrive); /*<16>Release bus*/
+ if (i!=0) {
+ return(i); /*Not legal for this media?*/
+ }
+ zero_cmd(cmd);
+ cmd[0]=PLAYTRKS; /*Play Audio Track/Index*/
+ cmd[1]=start;
+ cmd[2]=pt->start_index;
+ cmd[3]=end;
+ cmd[4]=pt->end_index;
+ i=docmd(cmd,ldrive,cdrive,controller,port); /*Issue command*/
+#ifdef DEBUGIOCTL
+ printf("matcd%d: Play track results %d \n",ldrive,i);
+#endif /*DEBUGIOCTL*/
+ if (i==0) cd->status=CD_AS_PLAY_IN_PROGRESS; /*<14>*/
+ return(i);
+}
+
+
+/*-----------------------------------------------------------------------------
+ matcd_playmsf - Plays between a range of blocks
+-----------------------------------------------------------------------------*/
+
+static int matcd_playmsf(int ldrive, int cdrive, int controller,
+ struct ioc_play_msf *pt)
+{
+ struct matcd_data *cd;
+ int i,port;
+ unsigned char cmd[MAXCMDSIZ];
+
+ cd=&matcd_data[ldrive];
+ port=cd->iobase;
+
+#ifdef DEBUGIOCTL
+ printf("matcd%d: playmsf %2x %2x %2x -> %2x %2x %2x\n",
+ ldrive,pt->start_m, pt->start_s, pt->start_f, pt->end_m,
+ pt->end_s,pt->end_f);
+#endif /*DEBUGIOCTL*/
+
+ if ((cd->flags & MATCDLABEL)==0)
+ return(EIO); /*Refuse after chg error*/
+
+ if ((cd->volinfo.vol_msf[0]==0 &&
+ cd->volinfo.vol_msf[1]<2) || /*Must be after 0'1"75F*/
+ msf_to_blk((char *)&pt->start_m) >
+ msf_to_blk((char *)&cd->volinfo.vol_msf)) {
+#ifdef DEBUGIOCTL
+ printf("matcd%d: Invalid block combination\n",ldrive);
+#endif /*DEBUGIOCTL*/
+ return(ESPIPE); /*Track out of range*/
+ }
+
+
+ lockbus(controller, ldrive); /*<16>Request bus*/
+ i=matcd_setmode(ldrive, MODE_DA);/*Force drive into audio mode*/
+ unlockbus(controller, ldrive); /*<16>Release bus*/
+ if (i!=0) {
+ return(i); /*Not legal for this media?*/
+ }
+ zero_cmd(cmd);
+ cmd[0]=PLAYBLOCKS; /*Play Audio Blocks*/
+ cmd[1]=pt->start_m;
+ cmd[2]=pt->start_s;
+ cmd[3]=pt->start_f;
+ cmd[4]=pt->end_m;
+ cmd[5]=pt->end_s;
+ cmd[6]=pt->end_f;
+ i=docmd(cmd,ldrive,cdrive,controller,port); /*Issue command*/
+ if (i==0) cd->status=CD_AS_PLAY_IN_PROGRESS; /*<14>*/
+ return(i);
+}
+
+
+/*-----------------------------------------------------------------------------
+ matcd_pause - Pause or Resume audio playback
+-----------------------------------------------------------------------------*/
+
+static int matcd_pause(int ldrive, int cdrive, int controller, int action)
+{
+ struct matcd_data *cd;
+ int i,z,port;
+ unsigned char cmd[MAXCMDSIZ];
+
+ cd=&matcd_data[ldrive];
+ port=cd->iobase;
+
+ if ((cd->flags & MATCDLABEL)==0)
+ return(EIO); /*Refuse after chg error*/
+
+ zero_cmd(cmd);
+ cmd[0]=NOP; /*<14>Just find out whats going on*/
+
+ lockbus(controller, ldrive); /*<16>Request bus*/
+ matcd_slowcmd(port,ldrive,cdrive,cmd); /*<14>*/
+ i=waitforit(10*TICKRES,DTEN,port,"sense"); /*<14>*/
+ z=get_stat(port,ldrive); /*<14>Read status byte*/
+ if ((z & MATCD_ST_ERROR)) { /*<14>Something went wrong*/
+ i=get_error(port, ldrive, cdrive); /*<14>*/
+ unlockbus(controller, ldrive); /*<16>Release bus*/
+ return(EIO); /*<14>*/
+ } /*<14>*/
+ unlockbus(controller, ldrive); /*<16>Release bus*/
+
+ if (z & MATCD_ST_AUDIOBSY==0 && /*<14>If drive is idle*/
+ cd->status==CD_AS_PLAY_IN_PROGRESS) { /*<14>but was playing*/
+ cd->status=CD_AS_PLAY_COMPLETED; /*<14>then its done*/
+ return(0);
+ }
+
+ if (action) { /*<14>Set state for subq ioctl*/
+#ifndef KRYTEN
+ if (cd->status==CD_AS_PLAY_IN_PROGRESS) {/*<14>Don't resume*/
+ return(0); /*<14>if already playing*/
+ } /*<14>Max Headroom sound occurs*/
+#endif /*KRYTEN*/
+ cd->status=CD_AS_PLAY_IN_PROGRESS; /*<14>to read*/
+ } else { /*<14>There is no way to ask the*/
+ cd->status=CD_AS_PLAY_PAUSED;/*<14>drive if it is paused*/
+ } /*<14>*/
+
+ cmd[0]=PAUSE; /*Pause or Resume playing audio*/
+ cmd[1]=action;
+ i=docmd(cmd,ldrive,cdrive,controller,port); /*Issue command*/
+#ifdef DEBUGIOCTL
+ printf("matcd%d: Pause / Resume results %d \n",ldrive,i);
+#endif /*DEBUGIOCTL*/
+ return(i);
+}
+
+
+
+/*-----------------------------------------------------------------------------
+ matcd_stop - Stop audio playback
+-----------------------------------------------------------------------------*/
+
+static int matcd_stop(int ldrive, int cdrive, int controller)
+{
+ struct matcd_data *cd;
+ int i,port;
+ unsigned char cmd[MAXCMDSIZ];
+
+ cd=&matcd_data[ldrive];
+ port=cd->iobase;
+
+ if ((cd->flags & MATCDLABEL)==0)
+ return(EIO); /*Refuse after chg error*/
+
+ zero_cmd(cmd);
+ cmd[0]=ABORT; /*Abort playing audio*/
+ i=docmd(cmd,ldrive,cdrive,controller,port); /*Issue command*/
+#ifdef DEBUGIOCTL
+ printf("matcd%d: Abort results %d \n",ldrive,i);
+#endif /*DEBUGIOCTL*/
+ cd->status=CD_AS_PLAY_COMPLETED;/*<14>the drive if it is paused*/
+ return(i);
+}
+
+
+/*-----------------------------------------------------------------------------
+ matcd_level - Read or set the audio levels
+<12> New for Edit 12
+-----------------------------------------------------------------------------*/
+
+static int matcd_level(int ldrive, int cdrive, int controller,
+ struct ioc_vol * level, int action)
+{
+ struct matcd_data *cd;
+ int i,z,port;
+ unsigned char c;
+ unsigned char cmd[MAXCMDSIZ];
+ unsigned char data[5];
+
+ cd=&matcd_data[ldrive];
+ port=cd->iobase;
+
+ zero_cmd(cmd);
+ if (action==CDIOCSETVOL) { /*We are setting new volume settings*/
+
+/* Here we set the volume levels. Note that the same command
+ also sets the patching (routing) of audio, so we have to rely
+ on previously-stored settings to fill in these fields.
+*/
+ cmd[0]=MODESELECT; /*Write drive settings*/
+ cmd[1]=AUDIOPARM; /*Audio/routing settings*/
+
+/* Although the drive allows a left and right channel volume to be
+ specified separately, the drive refuses the settings if the
+ values are different.
+*/
+ c=level->vol[0] | level->vol[1]; /*Or them together*/
+
+ cmd[4]=cd->volume[0]=c; /*Channel 0 (Left) volume*/
+ cmd[6]=cd->volume[1]=c; /*Channel 1 (Right) volume*/
+ cmd[3]=cd->patch[0]; /*Channel 0 (Left) patching*/
+ cmd[5]=cd->patch[1]; /*Channel 1 (Right) patching*/
+ i=docmd(cmd,ldrive,cdrive,controller,port);/*Issue cmd*/
+#ifdef DEBUGIOCTL
+ printf("matcd%d: Volume set %d\n",ldrive,i);
+#endif /*DEBUGIOCTL*/
+ return(i);
+ } else { /*Read existing settings*/
+
+
+/* This code reads the settings for the drive back - note that
+ volume and patching are both returned so we have to keep
+ both internally.
+*/
+ cmd[0]=MODESENSE; /*Read drive settings*/
+ cmd[1]=AUDIOPARM; /*Audio/routing settings*/
+ lockbus(controller, ldrive); /*<16>Request bus*/
+ matcd_slowcmd(port,ldrive,cdrive,cmd);
+ i=waitforit(10*TICKRES,DTEN,port,"sense");
+ matcd_pread(port, 5, data); /*Read data returned*/
+ z=get_stat(port,ldrive);/*Read status byte*/
+ unlockbus(controller, ldrive); /*<16>Release bus*/
+#ifdef DEBUGIOCTL
+ printf("matcd%d: Data got was %x %x %x %x %x ",ldrive,
+ data[0],data[1],data[2], data[3],data[4]);
+ printf("status byte %x\n",z);
+#endif /*DEBUGIOCTL*/
+ cd->volume[0]=level->vol[0]= /*Channel 0 (Left) volume*/
+ data[2];
+ cd->volume[1]=level->vol[1]= /*Channel 1 (Right) volume*/
+ data[4];
+ level->vol[2]=level->vol[3]=0; /*Channel 2 & 3 not avail*/
+
+ cd->patch[0]=data[1]; /*Channel 0 (Left) patching*/
+ cd->patch[1]=data[3]; /*Channel 1 (Right) patching*/
+
+ return(0);
+ }
+
+}
+
+
+/*-----------------------------------------------------------------------------
+ matcd_routing - Set the audio routing (patching)
+<12> New for Edit 12
+-----------------------------------------------------------------------------*/
+
+static int matcd_route(int ldrive, int cdrive, int controller,
+ int command)
+{
+ struct matcd_data *cd;
+ int i,port;
+ unsigned char l,r;
+ unsigned char cmd[MAXCMDSIZ];
+
+ cd=&matcd_data[ldrive];
+ port=cd->iobase;
+
+ zero_cmd(cmd);
+ switch (command) {
+ case CDIOCSETMUTE:
+ l=r=0;
+ break;
+
+ case CDIOCSETLEFT:
+ l=r=OUTLEFT;
+ break;
+
+ case CDIOCSETRIGHT:
+ l=r=OUTRIGHT;
+ break;
+
+ default:
+ case CDIOCSETSTEREO:
+ l=OUTLEFT;
+ r=OUTRIGHT;
+ break;
+ }
+
+/* Here we set the volume levels. Note that the same command
+ also sets the patching (routing) of audio, so we have to rely
+ on previously-stored settings to fill in these fields.
+*/
+ cmd[0]=MODESELECT; /*Write drive settings*/
+ cmd[1]=AUDIOPARM; /*Audio/routing settings*/
+
+
+/* Although the drive allows a left and right channel volume to be
+ specified separately, the drive refuses the settings if the
+ values are different.
+*/
+ cmd[4]=cd->volume[0]; /*Channel 0 (Left) volume*/
+ cmd[6]=cd->volume[1]; /*Channel 1 (Right) volume*/
+ cmd[3]=cd->patch[0]=l; /*Channel 0 (Left) patching*/
+ cmd[5]=cd->patch[1]=r; /*Channel 1 (Right) patching*/
+ i=docmd(cmd,ldrive,cdrive,controller,port);/*Issue cmd*/
+#ifdef DEBUGIOCTL
+ printf("matcd%d: Routing set %d\n",ldrive,i);
+#endif /*DEBUGIOCTL*/
+ return(i);
+
+}
+
+
+/*-----------------------------------------------------------------------------
+ matcd_patch - Set the audio routing (patching)
+<12> New for Edit 12
+-----------------------------------------------------------------------------*/
+
+static int matcd_patch(int ldrive, int cdrive, int controller,
+ struct ioc_patch * routing)
+{
+ struct matcd_data *cd;
+ int i,port;
+ unsigned char cmd[MAXCMDSIZ];
+
+ cd=&matcd_data[ldrive];
+ port=cd->iobase;
+
+ zero_cmd(cmd);
+
+/* Here we set the volume levels. Note that the same command
+ also sets the patching (routing) of audio, so we have to rely
+ on previously-stored settings to fill in these fields.
+*/
+ cmd[0]=MODESELECT; /*Write drive settings*/
+ cmd[1]=AUDIOPARM; /*Audio/routing settings*/
+
+
+/* Although the drive allows a left and right channel volume to be
+ specified separately, the drive refuses the settings if the
+ values are different.
+*/
+ cmd[4]=cd->volume[0]; /*Channel 0 (Left) volume*/
+ cmd[6]=cd->volume[1]; /*Channel 1 (Right) volume*/
+ cmd[3]=cd->patch[0]= /*Channel 0 (Left) patching*/
+ (routing->patch[0] & 0x03);
+ cmd[5]=cd->patch[1]= /*Channel 1 (Right) patching*/
+ (routing->patch[1] & 0x03);
+ i=docmd(cmd,ldrive,cdrive,controller,port);/*Issue cmd*/
+#ifdef DEBUGIOCTL
+ printf("matcd%d: Routing set %d\n",ldrive,i);
+#endif /*DEBUGIOCTL*/
+ return(i);
+
+}
+
+/*-----------------------------------------------------------------------------
+ matcd_pitch - Change audio playback rate
+ Apart from making things sound funny, the only
+ other application might be Karaoke. Ugh.
+<12> New for Edit 12
+-----------------------------------------------------------------------------*/
+
+static int matcd_pitch(int ldrive, int cdrive, int controller,
+ struct ioc_pitch * speed)
+{
+ struct matcd_data *cd;
+ short i;
+ int z,port;
+ unsigned char cmd[MAXCMDSIZ];
+
+ cd=&matcd_data[ldrive];
+ port=cd->iobase;
+
+ zero_cmd(cmd);
+
+/* This function sets the audio playback rate. In SCSI devices this is
+ referred to as the logical block addresses per second parameter.
+ Uh huh. Sounds like they didn't want anyone to find it.
+ Anyway, a study found that no one else has implemented this ioctl
+ but the capability does exist in the SCSI standard so I am following
+ the SCSI scheme even though it really doesn't fit this drive well.
+
+ I define the parameter to this ioctl as -32767 to -1 being
+ "play slower", 0x0000 flat and 1 to 32767 being "play faster"
+ within the scale allowed by the device. The value is scaled to fit
+ the allowed by the device and any excess is treated as being
+ the positive or negative limit. No ioctl input value is considered
+ invalid.
+
+ This device has a +/- 13% playback pitch specified by a range
+ -130 to +130. The drive does a hard enforcement on this.
+
+ SCSI defines a 16 bit LBAS count, and a "multiplier" that
+ is either x1 or x(1/256). The Matsushita drive only provides
+ 10 bits total for indicating pitch so the LSbits are discarded.
+*/
+
+ cmd[0]=MODESELECT; /*Write drive settings*/
+ cmd[1]=SPEEDPARM; /*Audio speed settings*/
+
+ i=speed->speed>>7; /*Scale down to our usable range*/
+
+ if (i!=0) { /*Real pitch value*/
+ if (i < -130) i=-130; /*Force into range we support*/
+ else if (i > 130) i=130;
+ cmd[3]=((i>>8)&0x03) | 0x04; /*Get upper bits*/
+ cmd[4]=(i & 0xff); /*Set lower bits*/
+ }
+ z=docmd(cmd,ldrive,cdrive,controller,port);/*Issue cmd*/
+#ifdef DEBUGIOCTL
+ printf("matcd%d: Pitch set %d\n",ldrive,i);
+#endif /*DEBUGIOCTL*/
+ return(z);
+}
+
+/*End of audio.c*/
+
OpenPOWER on IntegriCloud