File indexing completed on 2024-04-28 08:46:54

0001 /*
0002  * This file is part of WorkMan, the civilized CD player library
0003  * Copyright (C) 1991-1997 by Steven Grimm (original author)
0004  * Copyright (C) by Dirk Försterling <milliByte@DeathsDoor.com>
0005  * Copyright (C) 2004-2006 Alexander Kern <alex.kern@gmx.de>
0006  *
0007  * This library is free software; you can redistribute it and/or
0008  * modify it under the terms of the GNU Library General Public
0009  * License as published by the Free Software Foundation; either
0010  * version 2 of the License, or (at your option) any later version.
0011  *
0012  * This library is distributed in the hope that it will be useful,
0013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0015  * Library General Public License for more details.
0016  *
0017  * You should have received a copy of the GNU Library General Public
0018  * License along with this library; if not, write to the Free
0019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
0020  *
0021  *
0022  * Vendor-specific drive control routines for Sony CDU-8012 series.
0023  */
0024 
0025 #include <stdio.h>
0026 #include <errno.h>
0027 #include "include/wm_config.h"
0028 #include "include/wm_struct.h"
0029 #include "include/wm_scsi.h"
0030 
0031 #define PAGE_AUDIO 0x0e
0032 
0033 static int max_volume = 255;
0034 
0035 /*
0036  * On the Sony CDU-8012 drive, the amount of sound coming out the jack
0037  * increases much faster toward the top end of the volume scale than it
0038  * does at the bottom.  To make up for this, we make the volume scale look
0039  * sort of logarithmic (actually an upside-down inverse square curve) so
0040  * that the volume value passed to the drive changes less and less as you
0041  * approach the maximum slider setting.  Additionally, only the top half
0042  * of the volume scale is valid; the bottom half is all silent.  The actual
0043  * formula looks like
0044  *
0045  *     max^2 - (max - vol)^2   max
0046  * v = --------------------- + ---
0047  *            max * 2           2
0048  *
0049  * Where "max" is the maximum value of the volume scale, usually 100.
0050  */
0051 static int scale_volume(int vol, int max)
0052 {
0053     vol = (max*max - (max - vol) * (max - vol)) / max;
0054     return ((vol + max) / 2);
0055 }
0056 
0057 /*
0058  * Given a value between min_volume and max_volume, return the standard-scale
0059  * volume value needed to achieve that hardware value.
0060  *
0061  * Rather than perform floating-point calculations to reverse the above
0062  * formula, we simply do a binary search of scale_volume()'s return values.
0063  */
0064 static int unscale_volume(int vol, int max)
0065 {
0066     int ret_vol = 0, top = max, bot = 0, scaled = 0;
0067 
0068     vol = (vol * 100 + (max_volume - 1)) / max_volume;
0069 
0070     while (bot <= top)
0071     {
0072         ret_vol = (top + bot) / 2;
0073         scaled = scale_volume(ret_vol, max);
0074         if (vol <= scaled)
0075             top = ret_vol - 1;
0076         else
0077             bot = ret_vol + 1;
0078     }
0079 
0080     /* Might have looked down too far for repeated scaled values */
0081     if (vol < scaled)
0082         ret_vol++;
0083 
0084     if (ret_vol < 0)
0085         ret_vol = 0;
0086     else if (ret_vol > max)
0087         ret_vol = max;
0088 
0089     return ret_vol;
0090 }
0091 
0092 /*
0093  * Set the volume using the wacky scale outlined above.  The Sony drive
0094  * responds to the standard set-volume command.
0095  *
0096  * Get the volume.  Sun's CD-ROM driver doesn't support this operation, even
0097  * though their drive does.  Dumb.
0098  */
0099 static int sony_get_volume( struct wm_drive *d, int *left, int *right )
0100 {
0101     unsigned char mode[16];
0102 
0103     /* Get the current audio parameters first. */
0104     if (wm_scsi_mode_sense(d, PAGE_AUDIO, mode))
0105         return -1;
0106 
0107     *left = mode[9];
0108     *right = mode[11];
0109 
0110     return 0;
0111 }
0112 
0113 static int sony_scale_volume(int *left, int *right)
0114 {
0115     *left = scale_volume(*left, 100);
0116     *right = scale_volume(*right, 100);
0117 
0118     return 0;
0119 }
0120 
0121 static int sony_unscale_volume(int *left, int *right)
0122 {
0123     *left = unscale_volume(*left, 100);
0124     *right = unscale_volume(*right, 100);
0125 
0126     return 0;
0127 }
0128 
0129 int sony_fixup(struct wm_drive *d)
0130 {
0131     d->proto.get_volume = sony_get_volume;
0132     d->proto.scale_volume = sony_scale_volume;
0133     d->proto.unscale_volume = sony_unscale_volume;
0134 
0135     return 0;
0136 }