File indexing completed on 2024-03-24 04:57:15
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 }