| Joachim Foerster | a9f00d8 | 2007-11-05 16:06:01 +0100 | [diff] [blame] | 1 | /* | 
 | 2 |  * ALSA driver for Xilinx ML403 AC97 Controller Reference | 
 | 3 |  *   IP: opb_ac97_controller_ref_v1_00_a (EDK 8.1i) | 
 | 4 |  *   IP: opb_ac97_controller_ref_v1_00_a (EDK 9.1i) | 
 | 5 |  * | 
 | 6 |  *  Copyright (c) by 2007  Joachim Foerster <JOFT@gmx.de> | 
 | 7 |  * | 
 | 8 |  *   This program is free software; you can redistribute it and/or modify | 
 | 9 |  *   it under the terms of the GNU General Public License as published by | 
 | 10 |  *   the Free Software Foundation; either version 2 of the License, or | 
 | 11 |  *   (at your option) any later version. | 
 | 12 |  * | 
 | 13 |  *   This program is distributed in the hope that it will be useful, | 
 | 14 |  *   but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 | 15 |  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 | 16 |  *   GNU General Public License for more details. | 
 | 17 |  * | 
 | 18 |  *   You should have received a copy of the GNU General Public License | 
 | 19 |  *   along with this program; if not, write to the Free Software | 
 | 20 |  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA | 
 | 21 |  * | 
 | 22 |  */ | 
 | 23 |  | 
 | 24 | /* Some notes / status of this driver: | 
 | 25 |  * | 
 | 26 |  * - Don't wonder about some strange implementations of things - especially the | 
 | 27 |  * (heavy) shadowing of codec registers, with which I tried to reduce read | 
 | 28 |  * accesses to a minimum, because after a variable amount of accesses, the AC97 | 
 | 29 |  * controller doesn't raise the register access finished bit anymore ... | 
 | 30 |  * | 
| Joachim Foerster | a9f00d8 | 2007-11-05 16:06:01 +0100 | [diff] [blame] | 31 |  * - Playback support seems to be pretty stable - no issues here. | 
| Joachim Foerster | dddefd0 | 2007-11-05 15:48:36 +0100 | [diff] [blame] | 32 |  * - Capture support "works" now, too. Overruns don't happen any longer so often. | 
 | 33 |  *   But there might still be some ... | 
| Joachim Foerster | a9f00d8 | 2007-11-05 16:06:01 +0100 | [diff] [blame] | 34 |  */ | 
 | 35 |  | 
| Joachim Foerster | a9f00d8 | 2007-11-05 16:06:01 +0100 | [diff] [blame] | 36 | #include <linux/init.h> | 
 | 37 | #include <linux/moduleparam.h> | 
 | 38 |  | 
 | 39 | #include <linux/platform_device.h> | 
 | 40 |  | 
 | 41 | #include <linux/ioport.h> | 
| Tejun Heo | 5a0e3ad | 2010-03-24 17:04:11 +0900 | [diff] [blame] | 42 | #include <linux/slab.h> | 
| Joachim Foerster | a9f00d8 | 2007-11-05 16:06:01 +0100 | [diff] [blame] | 43 | #include <linux/io.h> | 
 | 44 | #include <linux/interrupt.h> | 
 | 45 |  | 
 | 46 | /* HZ */ | 
 | 47 | #include <linux/param.h> | 
 | 48 | /* jiffies, time_*() */ | 
 | 49 | #include <linux/jiffies.h> | 
 | 50 | /* schedule_timeout*() */ | 
 | 51 | #include <linux/sched.h> | 
 | 52 | /* spin_lock*() */ | 
 | 53 | #include <linux/spinlock.h> | 
 | 54 | /* struct mutex, mutex_init(), mutex_*lock() */ | 
 | 55 | #include <linux/mutex.h> | 
 | 56 |  | 
 | 57 | /* snd_printk(), snd_printd() */ | 
 | 58 | #include <sound/core.h> | 
 | 59 | #include <sound/pcm.h> | 
 | 60 | #include <sound/pcm_params.h> | 
 | 61 | #include <sound/initval.h> | 
 | 62 | #include <sound/ac97_codec.h> | 
 | 63 |  | 
 | 64 | #include "pcm-indirect2.h" | 
 | 65 |  | 
 | 66 |  | 
 | 67 | #define SND_ML403_AC97CR_DRIVER "ml403-ac97cr" | 
 | 68 |  | 
 | 69 | MODULE_AUTHOR("Joachim Foerster <JOFT@gmx.de>"); | 
 | 70 | MODULE_DESCRIPTION("Xilinx ML403 AC97 Controller Reference"); | 
 | 71 | MODULE_LICENSE("GPL"); | 
 | 72 | MODULE_SUPPORTED_DEVICE("{{Xilinx,ML403 AC97 Controller Reference}}"); | 
 | 73 |  | 
 | 74 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; | 
 | 75 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; | 
 | 76 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; | 
 | 77 |  | 
 | 78 | module_param_array(index, int, NULL, 0444); | 
 | 79 | MODULE_PARM_DESC(index, "Index value for ML403 AC97 Controller Reference."); | 
 | 80 | module_param_array(id, charp, NULL, 0444); | 
 | 81 | MODULE_PARM_DESC(id, "ID string for ML403 AC97 Controller Reference."); | 
 | 82 | module_param_array(enable, bool, NULL, 0444); | 
 | 83 | MODULE_PARM_DESC(enable, "Enable this ML403 AC97 Controller Reference."); | 
 | 84 |  | 
 | 85 | /* Special feature options */ | 
 | 86 | /*#define CODEC_WRITE_CHECK_RAF*/ /* don't return after a write to a codec | 
 | 87 | 				   * register, while RAF bit is not set | 
 | 88 | 				   */ | 
 | 89 | /* Debug options for code which may be removed completely in a final version */ | 
 | 90 | #ifdef CONFIG_SND_DEBUG | 
 | 91 | /*#define CODEC_STAT*/            /* turn on some minimal "statistics" | 
 | 92 | 				   * about codec register usage | 
 | 93 | 				   */ | 
 | 94 | #define SND_PCM_INDIRECT2_STAT    /* turn on some "statistics" about the | 
 | 95 | 				   * process of copying bytes from the | 
 | 96 | 				   * intermediate buffer to the hardware | 
 | 97 | 				   * fifo and the other way round | 
 | 98 | 				   */ | 
 | 99 | #endif | 
 | 100 |  | 
 | 101 | /* Definition of a "level/facility dependent" printk(); may be removed | 
 | 102 |  * completely in a final version | 
 | 103 |  */ | 
 | 104 | #undef PDEBUG | 
 | 105 | #ifdef CONFIG_SND_DEBUG | 
 | 106 | /* "facilities" for PDEBUG */ | 
 | 107 | #define UNKNOWN       (1<<0) | 
 | 108 | #define CODEC_SUCCESS (1<<1) | 
 | 109 | #define CODEC_FAKE    (1<<2) | 
 | 110 | #define INIT_INFO     (1<<3) | 
 | 111 | #define INIT_FAILURE  (1<<4) | 
 | 112 | #define WORK_INFO     (1<<5) | 
 | 113 | #define WORK_FAILURE  (1<<6) | 
 | 114 |  | 
 | 115 | #define PDEBUG_FACILITIES (UNKNOWN | INIT_FAILURE | WORK_FAILURE) | 
 | 116 |  | 
 | 117 | #define PDEBUG(fac, fmt, args...) do { \ | 
 | 118 | 		if (fac & PDEBUG_FACILITIES) \ | 
 | 119 | 			snd_printd(KERN_DEBUG SND_ML403_AC97CR_DRIVER ": " \ | 
 | 120 | 				   fmt, ##args); \ | 
 | 121 | 	} while (0) | 
 | 122 | #else | 
 | 123 | #define PDEBUG(fac, fmt, args...) /* nothing */ | 
 | 124 | #endif | 
 | 125 |  | 
 | 126 |  | 
 | 127 |  | 
 | 128 | /* Defines for "waits"/timeouts (portions of HZ=250 on arch/ppc by default) */ | 
 | 129 | #define CODEC_TIMEOUT_ON_INIT       5	/* timeout for checking for codec | 
 | 130 | 					 * readiness (after insmod) | 
 | 131 | 					 */ | 
 | 132 | #ifndef CODEC_WRITE_CHECK_RAF | 
 | 133 | #define CODEC_WAIT_AFTER_WRITE    100	/* general, static wait after a write | 
 | 134 | 					 * access to a codec register, may be | 
 | 135 | 					 * 0 to completely remove wait | 
 | 136 | 					 */ | 
 | 137 | #else | 
 | 138 | #define CODEC_TIMEOUT_AFTER_WRITE   5	/* timeout after a write access to a | 
 | 139 | 					 * codec register, if RAF bit is used | 
 | 140 | 					 */ | 
 | 141 | #endif | 
 | 142 | #define CODEC_TIMEOUT_AFTER_READ    5	/* timeout after a read access to a | 
 | 143 | 					 * codec register (checking RAF bit) | 
 | 144 | 					 */ | 
 | 145 |  | 
 | 146 | /* Infrastructure for codec register shadowing */ | 
 | 147 | #define LM4550_REG_OK        (1<<0)   /* register exists */ | 
 | 148 | #define LM4550_REG_DONEREAD  (1<<1)   /* read register once, value should be | 
 | 149 | 				       * the same currently in the register | 
 | 150 | 				       */ | 
 | 151 | #define LM4550_REG_NOSAVE    (1<<2)   /* values written to this register will | 
 | 152 | 				       * not be saved in the register | 
 | 153 | 				       */ | 
 | 154 | #define LM4550_REG_NOSHADOW  (1<<3)   /* don't do register shadowing, use plain | 
 | 155 | 				       * hardware access | 
 | 156 | 				       */ | 
 | 157 | #define LM4550_REG_READONLY  (1<<4)   /* register is read only */ | 
 | 158 | #define LM4550_REG_FAKEPROBE (1<<5)   /* fake write _and_ read actions during | 
 | 159 | 				       * probe() correctly | 
 | 160 | 				       */ | 
 | 161 | #define LM4550_REG_FAKEREAD  (1<<6)   /* fake read access, always return | 
 | 162 | 				       * default value | 
 | 163 | 				       */ | 
 | 164 | #define LM4550_REG_ALLFAKE   (LM4550_REG_FAKEREAD | LM4550_REG_FAKEPROBE) | 
 | 165 |  | 
 | 166 | struct lm4550_reg { | 
 | 167 | 	u16 value; | 
 | 168 | 	u16 flag; | 
 | 169 | 	u16 wmask; | 
 | 170 | 	u16 def; | 
 | 171 | }; | 
 | 172 |  | 
 | 173 | struct lm4550_reg lm4550_regfile[64] = { | 
 | 174 | 	[AC97_RESET / 2]              = {.flag = LM4550_REG_OK \ | 
 | 175 | 						| LM4550_REG_NOSAVE \ | 
 | 176 | 						| LM4550_REG_FAKEREAD, | 
 | 177 | 					 .def = 0x0D50}, | 
 | 178 | 	[AC97_MASTER / 2]             = {.flag = LM4550_REG_OK | 
 | 179 | 						| LM4550_REG_FAKEPROBE, | 
 | 180 | 					 .wmask = 0x9F1F, | 
 | 181 | 					 .def = 0x8000}, | 
 | 182 | 	[AC97_HEADPHONE / 2]          = {.flag = LM4550_REG_OK \ | 
 | 183 | 						| LM4550_REG_FAKEPROBE, | 
 | 184 | 					 .wmask = 0x9F1F, | 
 | 185 | 					 .def = 0x8000}, | 
 | 186 | 	[AC97_MASTER_MONO / 2]        = {.flag = LM4550_REG_OK \ | 
 | 187 | 						| LM4550_REG_FAKEPROBE, | 
 | 188 | 					 .wmask = 0x801F, | 
 | 189 | 					 .def = 0x8000}, | 
 | 190 | 	[AC97_PC_BEEP / 2]            = {.flag = LM4550_REG_OK \ | 
 | 191 | 						| LM4550_REG_FAKEPROBE, | 
 | 192 | 					 .wmask = 0x801E, | 
 | 193 | 					 .def = 0x0}, | 
 | 194 | 	[AC97_PHONE / 2]              = {.flag = LM4550_REG_OK \ | 
 | 195 | 						| LM4550_REG_FAKEPROBE, | 
 | 196 | 					 .wmask = 0x801F, | 
 | 197 | 					 .def = 0x8008}, | 
 | 198 | 	[AC97_MIC / 2]                = {.flag = LM4550_REG_OK \ | 
 | 199 | 						| LM4550_REG_FAKEPROBE, | 
 | 200 | 					 .wmask = 0x805F, | 
 | 201 | 					 .def = 0x8008}, | 
 | 202 | 	[AC97_LINE / 2]               = {.flag = LM4550_REG_OK \ | 
 | 203 | 						| LM4550_REG_FAKEPROBE, | 
 | 204 | 					 .wmask = 0x9F1F, | 
 | 205 | 					 .def = 0x8808}, | 
 | 206 | 	[AC97_CD / 2]                 = {.flag = LM4550_REG_OK \ | 
 | 207 | 						| LM4550_REG_FAKEPROBE, | 
 | 208 | 					 .wmask = 0x9F1F, | 
 | 209 | 					 .def = 0x8808}, | 
 | 210 | 	[AC97_VIDEO / 2]              = {.flag = LM4550_REG_OK \ | 
 | 211 | 						| LM4550_REG_FAKEPROBE, | 
 | 212 | 					 .wmask = 0x9F1F, | 
 | 213 | 					 .def = 0x8808}, | 
 | 214 | 	[AC97_AUX / 2]                = {.flag = LM4550_REG_OK \ | 
 | 215 | 						| LM4550_REG_FAKEPROBE, | 
 | 216 | 					 .wmask = 0x9F1F, | 
 | 217 | 					 .def = 0x8808}, | 
 | 218 | 	[AC97_PCM / 2]                = {.flag = LM4550_REG_OK \ | 
 | 219 | 						| LM4550_REG_FAKEPROBE, | 
 | 220 | 					 .wmask = 0x9F1F, | 
 | 221 | 					 .def = 0x8008}, | 
 | 222 | 	[AC97_REC_SEL / 2]            = {.flag = LM4550_REG_OK \ | 
 | 223 | 						| LM4550_REG_FAKEPROBE, | 
 | 224 | 					 .wmask = 0x707, | 
 | 225 | 					 .def = 0x0}, | 
 | 226 | 	[AC97_REC_GAIN / 2]           = {.flag = LM4550_REG_OK \ | 
 | 227 | 						| LM4550_REG_FAKEPROBE, | 
 | 228 | 					 .wmask = 0x8F0F, | 
 | 229 | 					 .def = 0x8000}, | 
 | 230 | 	[AC97_GENERAL_PURPOSE / 2]    = {.flag = LM4550_REG_OK \ | 
 | 231 | 						| LM4550_REG_FAKEPROBE, | 
 | 232 | 					 .def = 0x0, | 
 | 233 | 					 .wmask = 0xA380}, | 
 | 234 | 	[AC97_3D_CONTROL / 2]         = {.flag = LM4550_REG_OK \ | 
 | 235 | 						| LM4550_REG_FAKEREAD \ | 
 | 236 | 						| LM4550_REG_READONLY, | 
 | 237 | 					 .def = 0x0101}, | 
 | 238 | 	[AC97_POWERDOWN / 2]          = {.flag = LM4550_REG_OK \ | 
 | 239 | 						| LM4550_REG_NOSHADOW \ | 
 | 240 | 						| LM4550_REG_NOSAVE, | 
 | 241 | 					 .wmask = 0xFF00}, | 
 | 242 | 					/* may not write ones to | 
 | 243 | 					 * REF/ANL/DAC/ADC bits | 
 | 244 | 					 * FIXME: Is this ok? | 
 | 245 | 					 */ | 
 | 246 | 	[AC97_EXTENDED_ID / 2]        = {.flag = LM4550_REG_OK \ | 
 | 247 | 						| LM4550_REG_FAKEREAD \ | 
 | 248 | 						| LM4550_REG_READONLY, | 
 | 249 | 					 .def = 0x0201}, /* primary codec */ | 
 | 250 | 	[AC97_EXTENDED_STATUS / 2]    = {.flag = LM4550_REG_OK \ | 
 | 251 | 						| LM4550_REG_NOSHADOW \ | 
 | 252 | 						| LM4550_REG_NOSAVE, | 
 | 253 | 					 .wmask = 0x1}, | 
 | 254 | 	[AC97_PCM_FRONT_DAC_RATE / 2] = {.flag = LM4550_REG_OK \ | 
 | 255 | 						| LM4550_REG_FAKEPROBE, | 
 | 256 | 					 .def = 0xBB80, | 
 | 257 | 					 .wmask = 0xFFFF}, | 
 | 258 | 	[AC97_PCM_LR_ADC_RATE / 2]    = {.flag = LM4550_REG_OK \ | 
 | 259 | 						| LM4550_REG_FAKEPROBE, | 
 | 260 | 					 .def = 0xBB80, | 
 | 261 | 					 .wmask = 0xFFFF}, | 
 | 262 | 	[AC97_VENDOR_ID1 / 2]         = {.flag = LM4550_REG_OK \ | 
 | 263 | 						| LM4550_REG_READONLY \ | 
 | 264 | 						| LM4550_REG_FAKEREAD, | 
 | 265 | 					 .def = 0x4E53}, | 
 | 266 | 	[AC97_VENDOR_ID2 / 2]         = {.flag = LM4550_REG_OK \ | 
 | 267 | 						| LM4550_REG_READONLY \ | 
 | 268 | 						| LM4550_REG_FAKEREAD, | 
 | 269 | 					 .def = 0x4350} | 
 | 270 | }; | 
 | 271 |  | 
 | 272 | #define LM4550_RF_OK(reg)    (lm4550_regfile[reg / 2].flag & LM4550_REG_OK) | 
 | 273 |  | 
 | 274 | static void lm4550_regfile_init(void) | 
 | 275 | { | 
 | 276 | 	int i; | 
 | 277 | 	for (i = 0; i < 64; i++) | 
 | 278 | 		if (lm4550_regfile[i].flag & LM4550_REG_FAKEPROBE) | 
 | 279 | 			lm4550_regfile[i].value = lm4550_regfile[i].def; | 
 | 280 | } | 
 | 281 |  | 
 | 282 | static void lm4550_regfile_write_values_after_init(struct snd_ac97 *ac97) | 
 | 283 | { | 
 | 284 | 	int i; | 
 | 285 | 	for (i = 0; i < 64; i++) | 
 | 286 | 		if ((lm4550_regfile[i].flag & LM4550_REG_FAKEPROBE) && | 
 | 287 | 		    (lm4550_regfile[i].value != lm4550_regfile[i].def)) { | 
 | 288 | 			PDEBUG(CODEC_FAKE, "lm4550_regfile_write_values_after_" | 
 | 289 | 			       "init(): reg=0x%x value=0x%x / %d is different " | 
 | 290 | 			       "from def=0x%x / %d\n", | 
 | 291 | 			       i, lm4550_regfile[i].value, | 
 | 292 | 			       lm4550_regfile[i].value, lm4550_regfile[i].def, | 
 | 293 | 			       lm4550_regfile[i].def); | 
 | 294 | 			snd_ac97_write(ac97, i * 2, lm4550_regfile[i].value); | 
 | 295 | 			lm4550_regfile[i].flag |= LM4550_REG_DONEREAD; | 
 | 296 | 		} | 
 | 297 | } | 
 | 298 |  | 
 | 299 |  | 
 | 300 | /* direct registers */ | 
 | 301 | #define CR_REG(ml403_ac97cr, x) ((ml403_ac97cr)->port + CR_REG_##x) | 
 | 302 |  | 
 | 303 | #define CR_REG_PLAYFIFO         0x00 | 
 | 304 | #define   CR_PLAYDATA(a)        ((a) & 0xFFFF) | 
 | 305 |  | 
 | 306 | #define CR_REG_RECFIFO          0x04 | 
 | 307 | #define   CR_RECDATA(a)         ((a) & 0xFFFF) | 
 | 308 |  | 
 | 309 | #define CR_REG_STATUS           0x08 | 
 | 310 | #define   CR_RECOVER            (1<<7) | 
 | 311 | #define   CR_PLAYUNDER          (1<<6) | 
 | 312 | #define   CR_CODECREADY         (1<<5) | 
 | 313 | #define   CR_RAF                (1<<4) | 
 | 314 | #define   CR_RECEMPTY           (1<<3) | 
 | 315 | #define   CR_RECFULL            (1<<2) | 
 | 316 | #define   CR_PLAYHALF           (1<<1) | 
 | 317 | #define   CR_PLAYFULL           (1<<0) | 
 | 318 |  | 
 | 319 | #define CR_REG_RESETFIFO        0x0C | 
 | 320 | #define   CR_RECRESET           (1<<1) | 
 | 321 | #define   CR_PLAYRESET          (1<<0) | 
 | 322 |  | 
 | 323 | #define CR_REG_CODEC_ADDR       0x10 | 
 | 324 | /* UG082 says: | 
 | 325 |  * #define   CR_CODEC_ADDR(a)  ((a) << 1) | 
 | 326 |  * #define   CR_CODEC_READ     (1<<0) | 
 | 327 |  * #define   CR_CODEC_WRITE    (0<<0) | 
 | 328 |  */ | 
 | 329 | /* RefDesign example says: */ | 
 | 330 | #define   CR_CODEC_ADDR(a)      ((a) << 0) | 
 | 331 | #define   CR_CODEC_READ         (1<<7) | 
 | 332 | #define   CR_CODEC_WRITE        (0<<7) | 
 | 333 |  | 
 | 334 | #define CR_REG_CODEC_DATAREAD   0x14 | 
 | 335 | #define   CR_CODEC_DATAREAD(v)  ((v) & 0xFFFF) | 
 | 336 |  | 
 | 337 | #define CR_REG_CODEC_DATAWRITE  0x18 | 
 | 338 | #define   CR_CODEC_DATAWRITE(v) ((v) & 0xFFFF) | 
 | 339 |  | 
 | 340 | #define CR_FIFO_SIZE            32 | 
 | 341 |  | 
 | 342 | struct snd_ml403_ac97cr { | 
 | 343 | 	/* lock for access to (controller) registers */ | 
 | 344 | 	spinlock_t reg_lock; | 
 | 345 | 	/* mutex for the whole sequence of accesses to (controller) registers | 
 | 346 | 	 * which affect codec registers | 
 | 347 | 	 */ | 
 | 348 | 	struct mutex cdc_mutex; | 
 | 349 |  | 
 | 350 | 	int irq; /* for playback */ | 
 | 351 | 	int enable_irq;	/* for playback */ | 
 | 352 |  | 
 | 353 | 	int capture_irq; | 
 | 354 | 	int enable_capture_irq; | 
 | 355 |  | 
 | 356 | 	struct resource *res_port; | 
 | 357 | 	void *port; | 
 | 358 |  | 
 | 359 | 	struct snd_ac97 *ac97; | 
 | 360 | 	int ac97_fake; | 
 | 361 | #ifdef CODEC_STAT | 
 | 362 | 	int ac97_read; | 
 | 363 | 	int ac97_write; | 
 | 364 | #endif | 
 | 365 |  | 
 | 366 | 	struct platform_device *pfdev; | 
 | 367 | 	struct snd_card *card; | 
 | 368 | 	struct snd_pcm *pcm; | 
 | 369 | 	struct snd_pcm_substream *playback_substream; | 
 | 370 | 	struct snd_pcm_substream *capture_substream; | 
 | 371 |  | 
 | 372 | 	struct snd_pcm_indirect2 ind_rec; /* for playback */ | 
 | 373 | 	struct snd_pcm_indirect2 capture_ind2_rec; | 
 | 374 | }; | 
 | 375 |  | 
 | 376 | static struct snd_pcm_hardware snd_ml403_ac97cr_playback = { | 
 | 377 | 	.info =	            (SNDRV_PCM_INFO_MMAP | | 
 | 378 | 			     SNDRV_PCM_INFO_INTERLEAVED | | 
 | 379 | 			     SNDRV_PCM_INFO_MMAP_VALID), | 
 | 380 | 	.formats =          SNDRV_PCM_FMTBIT_S16_BE, | 
 | 381 | 	.rates =	    (SNDRV_PCM_RATE_CONTINUOUS | | 
 | 382 | 			     SNDRV_PCM_RATE_8000_48000), | 
 | 383 | 	.rate_min =	    4000, | 
 | 384 | 	.rate_max =	    48000, | 
 | 385 | 	.channels_min =     2, | 
 | 386 | 	.channels_max =     2, | 
 | 387 | 	.buffer_bytes_max = (128*1024), | 
 | 388 | 	.period_bytes_min = CR_FIFO_SIZE/2, | 
 | 389 | 	.period_bytes_max = (64*1024), | 
 | 390 | 	.periods_min =      2, | 
 | 391 | 	.periods_max =      (128*1024)/(CR_FIFO_SIZE/2), | 
 | 392 | 	.fifo_size =	    0, | 
 | 393 | }; | 
 | 394 |  | 
 | 395 | static struct snd_pcm_hardware snd_ml403_ac97cr_capture = { | 
 | 396 | 	.info =	            (SNDRV_PCM_INFO_MMAP | | 
 | 397 | 			     SNDRV_PCM_INFO_INTERLEAVED | | 
 | 398 | 			     SNDRV_PCM_INFO_MMAP_VALID), | 
 | 399 | 	.formats =          SNDRV_PCM_FMTBIT_S16_BE, | 
 | 400 | 	.rates =            (SNDRV_PCM_RATE_CONTINUOUS | | 
 | 401 | 			     SNDRV_PCM_RATE_8000_48000), | 
 | 402 | 	.rate_min =         4000, | 
 | 403 | 	.rate_max =         48000, | 
 | 404 | 	.channels_min =     2, | 
 | 405 | 	.channels_max =     2, | 
 | 406 | 	.buffer_bytes_max = (128*1024), | 
 | 407 | 	.period_bytes_min = CR_FIFO_SIZE/2, | 
 | 408 | 	.period_bytes_max = (64*1024), | 
 | 409 | 	.periods_min =      2, | 
 | 410 | 	.periods_max =      (128*1024)/(CR_FIFO_SIZE/2), | 
 | 411 | 	.fifo_size =	    0, | 
 | 412 | }; | 
 | 413 |  | 
 | 414 | static size_t | 
 | 415 | snd_ml403_ac97cr_playback_ind2_zero(struct snd_pcm_substream *substream, | 
 | 416 | 				    struct snd_pcm_indirect2 *rec) | 
 | 417 | { | 
 | 418 | 	struct snd_ml403_ac97cr *ml403_ac97cr; | 
 | 419 | 	int copied_words = 0; | 
 | 420 | 	u32 full = 0; | 
 | 421 |  | 
 | 422 | 	ml403_ac97cr = snd_pcm_substream_chip(substream); | 
 | 423 |  | 
 | 424 | 	spin_lock(&ml403_ac97cr->reg_lock); | 
 | 425 | 	while ((full = (in_be32(CR_REG(ml403_ac97cr, STATUS)) & | 
 | 426 | 			CR_PLAYFULL)) != CR_PLAYFULL) { | 
 | 427 | 		out_be32(CR_REG(ml403_ac97cr, PLAYFIFO), 0); | 
 | 428 | 		copied_words++; | 
 | 429 | 	} | 
 | 430 | 	rec->hw_ready = 0; | 
 | 431 | 	spin_unlock(&ml403_ac97cr->reg_lock); | 
 | 432 |  | 
 | 433 | 	return (size_t) (copied_words * 2); | 
 | 434 | } | 
 | 435 |  | 
 | 436 | static size_t | 
 | 437 | snd_ml403_ac97cr_playback_ind2_copy(struct snd_pcm_substream *substream, | 
 | 438 | 				    struct snd_pcm_indirect2 *rec, | 
 | 439 | 				    size_t bytes) | 
 | 440 | { | 
 | 441 | 	struct snd_ml403_ac97cr *ml403_ac97cr; | 
 | 442 | 	u16 *src; | 
 | 443 | 	int copied_words = 0; | 
 | 444 | 	u32 full = 0; | 
 | 445 |  | 
 | 446 | 	ml403_ac97cr = snd_pcm_substream_chip(substream); | 
 | 447 | 	src = (u16 *)(substream->runtime->dma_area + rec->sw_data); | 
 | 448 |  | 
 | 449 | 	spin_lock(&ml403_ac97cr->reg_lock); | 
 | 450 | 	while (((full = (in_be32(CR_REG(ml403_ac97cr, STATUS)) & | 
 | 451 | 			 CR_PLAYFULL)) != CR_PLAYFULL) && (bytes > 1)) { | 
 | 452 | 		out_be32(CR_REG(ml403_ac97cr, PLAYFIFO), | 
 | 453 | 			 CR_PLAYDATA(src[copied_words])); | 
 | 454 | 		copied_words++; | 
 | 455 | 		bytes = bytes - 2; | 
 | 456 | 	} | 
 | 457 | 	if (full != CR_PLAYFULL) | 
 | 458 | 		rec->hw_ready = 1; | 
 | 459 | 	else | 
 | 460 | 		rec->hw_ready = 0; | 
 | 461 | 	spin_unlock(&ml403_ac97cr->reg_lock); | 
 | 462 |  | 
 | 463 | 	return (size_t) (copied_words * 2); | 
 | 464 | } | 
 | 465 |  | 
 | 466 | static size_t | 
 | 467 | snd_ml403_ac97cr_capture_ind2_null(struct snd_pcm_substream *substream, | 
 | 468 | 				   struct snd_pcm_indirect2 *rec) | 
 | 469 | { | 
 | 470 | 	struct snd_ml403_ac97cr *ml403_ac97cr; | 
 | 471 | 	int copied_words = 0; | 
 | 472 | 	u32 empty = 0; | 
 | 473 |  | 
 | 474 | 	ml403_ac97cr = snd_pcm_substream_chip(substream); | 
 | 475 |  | 
 | 476 | 	spin_lock(&ml403_ac97cr->reg_lock); | 
 | 477 | 	while ((empty = (in_be32(CR_REG(ml403_ac97cr, STATUS)) & | 
 | 478 | 			 CR_RECEMPTY)) != CR_RECEMPTY) { | 
 | 479 | 		volatile u32 trash; | 
 | 480 |  | 
 | 481 | 		trash = CR_RECDATA(in_be32(CR_REG(ml403_ac97cr, RECFIFO))); | 
 | 482 | 		/* Hmmmm, really necessary? Don't want call to in_be32() | 
 | 483 | 		 * to be optimised away! | 
 | 484 | 		 */ | 
 | 485 | 		trash++; | 
 | 486 | 		copied_words++; | 
 | 487 | 	} | 
 | 488 | 	rec->hw_ready = 0; | 
 | 489 | 	spin_unlock(&ml403_ac97cr->reg_lock); | 
 | 490 |  | 
 | 491 | 	return (size_t) (copied_words * 2); | 
 | 492 | } | 
 | 493 |  | 
 | 494 | static size_t | 
 | 495 | snd_ml403_ac97cr_capture_ind2_copy(struct snd_pcm_substream *substream, | 
 | 496 | 				   struct snd_pcm_indirect2 *rec, size_t bytes) | 
 | 497 | { | 
 | 498 | 	struct snd_ml403_ac97cr *ml403_ac97cr; | 
 | 499 | 	u16 *dst; | 
 | 500 | 	int copied_words = 0; | 
 | 501 | 	u32 empty = 0; | 
 | 502 |  | 
 | 503 | 	ml403_ac97cr = snd_pcm_substream_chip(substream); | 
 | 504 | 	dst = (u16 *)(substream->runtime->dma_area + rec->sw_data); | 
 | 505 |  | 
 | 506 | 	spin_lock(&ml403_ac97cr->reg_lock); | 
 | 507 | 	while (((empty = (in_be32(CR_REG(ml403_ac97cr, STATUS)) & | 
 | 508 | 			  CR_RECEMPTY)) != CR_RECEMPTY) && (bytes > 1)) { | 
 | 509 | 		dst[copied_words] = CR_RECDATA(in_be32(CR_REG(ml403_ac97cr, | 
 | 510 | 							      RECFIFO))); | 
 | 511 | 		copied_words++; | 
 | 512 | 		bytes = bytes - 2; | 
 | 513 | 	} | 
 | 514 | 	if (empty != CR_RECEMPTY) | 
 | 515 | 		rec->hw_ready = 1; | 
 | 516 | 	else | 
 | 517 | 		rec->hw_ready = 0; | 
 | 518 | 	spin_unlock(&ml403_ac97cr->reg_lock); | 
 | 519 |  | 
 | 520 | 	return (size_t) (copied_words * 2); | 
 | 521 | } | 
 | 522 |  | 
 | 523 | static snd_pcm_uframes_t | 
 | 524 | snd_ml403_ac97cr_pcm_pointer(struct snd_pcm_substream *substream) | 
 | 525 | { | 
 | 526 | 	struct snd_ml403_ac97cr *ml403_ac97cr; | 
 | 527 | 	struct snd_pcm_indirect2 *ind2_rec = NULL; | 
 | 528 |  | 
 | 529 | 	ml403_ac97cr = snd_pcm_substream_chip(substream); | 
 | 530 |  | 
 | 531 | 	if (substream == ml403_ac97cr->playback_substream) | 
 | 532 | 		ind2_rec = &ml403_ac97cr->ind_rec; | 
 | 533 | 	if (substream == ml403_ac97cr->capture_substream) | 
 | 534 | 		ind2_rec = &ml403_ac97cr->capture_ind2_rec; | 
 | 535 |  | 
 | 536 | 	if (ind2_rec != NULL) | 
 | 537 | 		return snd_pcm_indirect2_pointer(substream, ind2_rec); | 
 | 538 | 	return (snd_pcm_uframes_t) 0; | 
 | 539 | } | 
 | 540 |  | 
 | 541 | static int | 
 | 542 | snd_ml403_ac97cr_pcm_playback_trigger(struct snd_pcm_substream *substream, | 
 | 543 | 				      int cmd) | 
 | 544 | { | 
 | 545 | 	struct snd_ml403_ac97cr *ml403_ac97cr; | 
 | 546 | 	int err = 0; | 
 | 547 |  | 
 | 548 | 	ml403_ac97cr = snd_pcm_substream_chip(substream); | 
 | 549 |  | 
 | 550 | 	switch (cmd) { | 
 | 551 | 	case SNDRV_PCM_TRIGGER_START: | 
 | 552 | 		PDEBUG(WORK_INFO, "trigger(playback): START\n"); | 
 | 553 | 		ml403_ac97cr->ind_rec.hw_ready = 1; | 
 | 554 |  | 
 | 555 | 		/* clear play FIFO */ | 
 | 556 | 		out_be32(CR_REG(ml403_ac97cr, RESETFIFO), CR_PLAYRESET); | 
 | 557 |  | 
 | 558 | 		/* enable play irq */ | 
 | 559 | 		ml403_ac97cr->enable_irq = 1; | 
 | 560 | 		enable_irq(ml403_ac97cr->irq); | 
 | 561 | 		break; | 
 | 562 | 	case SNDRV_PCM_TRIGGER_STOP: | 
 | 563 | 		PDEBUG(WORK_INFO, "trigger(playback): STOP\n"); | 
 | 564 | 		ml403_ac97cr->ind_rec.hw_ready = 0; | 
 | 565 | #ifdef SND_PCM_INDIRECT2_STAT | 
 | 566 | 		snd_pcm_indirect2_stat(substream, &ml403_ac97cr->ind_rec); | 
 | 567 | #endif | 
 | 568 | 		/* disable play irq */ | 
 | 569 | 		disable_irq_nosync(ml403_ac97cr->irq); | 
 | 570 | 		ml403_ac97cr->enable_irq = 0; | 
 | 571 | 		break; | 
 | 572 | 	default: | 
 | 573 | 		err = -EINVAL; | 
 | 574 | 		break; | 
 | 575 | 	} | 
 | 576 | 	PDEBUG(WORK_INFO, "trigger(playback): (done)\n"); | 
 | 577 | 	return err; | 
 | 578 | } | 
 | 579 |  | 
 | 580 | static int | 
 | 581 | snd_ml403_ac97cr_pcm_capture_trigger(struct snd_pcm_substream *substream, | 
 | 582 | 				      int cmd) | 
 | 583 | { | 
 | 584 | 	struct snd_ml403_ac97cr *ml403_ac97cr; | 
 | 585 | 	int err = 0; | 
 | 586 |  | 
 | 587 | 	ml403_ac97cr = snd_pcm_substream_chip(substream); | 
 | 588 |  | 
 | 589 | 	switch (cmd) { | 
 | 590 | 	case SNDRV_PCM_TRIGGER_START: | 
 | 591 | 		PDEBUG(WORK_INFO, "trigger(capture): START\n"); | 
 | 592 | 		ml403_ac97cr->capture_ind2_rec.hw_ready = 0; | 
 | 593 |  | 
 | 594 | 		/* clear record FIFO */ | 
 | 595 | 		out_be32(CR_REG(ml403_ac97cr, RESETFIFO), CR_RECRESET); | 
 | 596 |  | 
 | 597 | 		/* enable record irq */ | 
 | 598 | 		ml403_ac97cr->enable_capture_irq = 1; | 
 | 599 | 		enable_irq(ml403_ac97cr->capture_irq); | 
 | 600 | 		break; | 
 | 601 | 	case SNDRV_PCM_TRIGGER_STOP: | 
 | 602 | 		PDEBUG(WORK_INFO, "trigger(capture): STOP\n"); | 
 | 603 | 		ml403_ac97cr->capture_ind2_rec.hw_ready = 0; | 
 | 604 | #ifdef SND_PCM_INDIRECT2_STAT | 
 | 605 | 		snd_pcm_indirect2_stat(substream, | 
 | 606 | 				       &ml403_ac97cr->capture_ind2_rec); | 
 | 607 | #endif | 
 | 608 | 		/* disable capture irq */ | 
 | 609 | 		disable_irq_nosync(ml403_ac97cr->capture_irq); | 
 | 610 | 		ml403_ac97cr->enable_capture_irq = 0; | 
 | 611 | 		break; | 
 | 612 | 	default: | 
 | 613 | 		err = -EINVAL; | 
 | 614 | 		break; | 
 | 615 | 	} | 
 | 616 | 	PDEBUG(WORK_INFO, "trigger(capture): (done)\n"); | 
 | 617 | 	return err; | 
 | 618 | } | 
 | 619 |  | 
 | 620 | static int | 
 | 621 | snd_ml403_ac97cr_pcm_playback_prepare(struct snd_pcm_substream *substream) | 
 | 622 | { | 
 | 623 | 	struct snd_ml403_ac97cr *ml403_ac97cr; | 
 | 624 | 	struct snd_pcm_runtime *runtime; | 
 | 625 |  | 
 | 626 | 	ml403_ac97cr = snd_pcm_substream_chip(substream); | 
 | 627 | 	runtime = substream->runtime; | 
 | 628 |  | 
 | 629 | 	PDEBUG(WORK_INFO, | 
 | 630 | 	       "prepare(): period_bytes=%d, minperiod_bytes=%d\n", | 
 | 631 | 	       snd_pcm_lib_period_bytes(substream), CR_FIFO_SIZE / 2); | 
 | 632 |  | 
 | 633 | 	/* set sampling rate */ | 
 | 634 | 	snd_ac97_set_rate(ml403_ac97cr->ac97, AC97_PCM_FRONT_DAC_RATE, | 
 | 635 | 			  runtime->rate); | 
 | 636 | 	PDEBUG(WORK_INFO, "prepare(): rate=%d\n", runtime->rate); | 
 | 637 |  | 
 | 638 | 	/* init struct for intermediate buffer */ | 
 | 639 | 	memset(&ml403_ac97cr->ind_rec, 0, | 
 | 640 | 	       sizeof(struct snd_pcm_indirect2)); | 
 | 641 | 	ml403_ac97cr->ind_rec.hw_buffer_size = CR_FIFO_SIZE; | 
 | 642 | 	ml403_ac97cr->ind_rec.sw_buffer_size = | 
 | 643 | 		snd_pcm_lib_buffer_bytes(substream); | 
 | 644 | 	ml403_ac97cr->ind_rec.min_periods = -1; | 
 | 645 | 	ml403_ac97cr->ind_rec.min_multiple = | 
 | 646 | 		snd_pcm_lib_period_bytes(substream) / (CR_FIFO_SIZE / 2); | 
 | 647 | 	PDEBUG(WORK_INFO, "prepare(): hw_buffer_size=%d, " | 
 | 648 | 	       "sw_buffer_size=%d, min_multiple=%d\n", | 
 | 649 | 	       CR_FIFO_SIZE, ml403_ac97cr->ind_rec.sw_buffer_size, | 
 | 650 | 	       ml403_ac97cr->ind_rec.min_multiple); | 
 | 651 | 	return 0; | 
 | 652 | } | 
 | 653 |  | 
 | 654 | static int | 
 | 655 | snd_ml403_ac97cr_pcm_capture_prepare(struct snd_pcm_substream *substream) | 
 | 656 | { | 
 | 657 | 	struct snd_ml403_ac97cr *ml403_ac97cr; | 
 | 658 | 	struct snd_pcm_runtime *runtime; | 
 | 659 |  | 
 | 660 | 	ml403_ac97cr = snd_pcm_substream_chip(substream); | 
 | 661 | 	runtime = substream->runtime; | 
 | 662 |  | 
 | 663 | 	PDEBUG(WORK_INFO, | 
 | 664 | 	       "prepare(capture): period_bytes=%d, minperiod_bytes=%d\n", | 
 | 665 | 	       snd_pcm_lib_period_bytes(substream), CR_FIFO_SIZE / 2); | 
 | 666 |  | 
 | 667 | 	/* set sampling rate */ | 
 | 668 | 	snd_ac97_set_rate(ml403_ac97cr->ac97, AC97_PCM_LR_ADC_RATE, | 
 | 669 | 			  runtime->rate); | 
 | 670 | 	PDEBUG(WORK_INFO, "prepare(capture): rate=%d\n", runtime->rate); | 
 | 671 |  | 
 | 672 | 	/* init struct for intermediate buffer */ | 
 | 673 | 	memset(&ml403_ac97cr->capture_ind2_rec, 0, | 
 | 674 | 	       sizeof(struct snd_pcm_indirect2)); | 
 | 675 | 	ml403_ac97cr->capture_ind2_rec.hw_buffer_size = CR_FIFO_SIZE; | 
 | 676 | 	ml403_ac97cr->capture_ind2_rec.sw_buffer_size = | 
 | 677 | 		snd_pcm_lib_buffer_bytes(substream); | 
 | 678 | 	ml403_ac97cr->capture_ind2_rec.min_multiple = | 
 | 679 | 		snd_pcm_lib_period_bytes(substream) / (CR_FIFO_SIZE / 2); | 
 | 680 | 	PDEBUG(WORK_INFO, "prepare(capture): hw_buffer_size=%d, " | 
 | 681 | 	       "sw_buffer_size=%d, min_multiple=%d\n", CR_FIFO_SIZE, | 
 | 682 | 	       ml403_ac97cr->capture_ind2_rec.sw_buffer_size, | 
 | 683 | 	       ml403_ac97cr->capture_ind2_rec.min_multiple); | 
 | 684 | 	return 0; | 
 | 685 | } | 
 | 686 |  | 
 | 687 | static int snd_ml403_ac97cr_hw_free(struct snd_pcm_substream *substream) | 
 | 688 | { | 
 | 689 | 	PDEBUG(WORK_INFO, "hw_free()\n"); | 
 | 690 | 	return snd_pcm_lib_free_pages(substream); | 
 | 691 | } | 
 | 692 |  | 
 | 693 | static int | 
 | 694 | snd_ml403_ac97cr_hw_params(struct snd_pcm_substream *substream, | 
 | 695 | 			   struct snd_pcm_hw_params *hw_params) | 
 | 696 | { | 
 | 697 | 	PDEBUG(WORK_INFO, "hw_params(): desired buffer bytes=%d, desired " | 
 | 698 | 	       "period bytes=%d\n", | 
 | 699 | 	       params_buffer_bytes(hw_params), params_period_bytes(hw_params)); | 
 | 700 | 	return snd_pcm_lib_malloc_pages(substream, | 
 | 701 | 					params_buffer_bytes(hw_params)); | 
 | 702 | } | 
 | 703 |  | 
 | 704 | static int snd_ml403_ac97cr_playback_open(struct snd_pcm_substream *substream) | 
 | 705 | { | 
 | 706 | 	struct snd_ml403_ac97cr *ml403_ac97cr; | 
 | 707 | 	struct snd_pcm_runtime *runtime; | 
 | 708 |  | 
 | 709 | 	ml403_ac97cr = snd_pcm_substream_chip(substream); | 
 | 710 | 	runtime = substream->runtime; | 
 | 711 |  | 
 | 712 | 	PDEBUG(WORK_INFO, "open(playback)\n"); | 
 | 713 | 	ml403_ac97cr->playback_substream = substream; | 
 | 714 | 	runtime->hw = snd_ml403_ac97cr_playback; | 
 | 715 |  | 
 | 716 | 	snd_pcm_hw_constraint_step(runtime, 0, | 
 | 717 | 				   SNDRV_PCM_HW_PARAM_PERIOD_BYTES, | 
 | 718 | 				   CR_FIFO_SIZE / 2); | 
 | 719 | 	return 0; | 
 | 720 | } | 
 | 721 |  | 
 | 722 | static int snd_ml403_ac97cr_capture_open(struct snd_pcm_substream *substream) | 
 | 723 | { | 
 | 724 | 	struct snd_ml403_ac97cr *ml403_ac97cr; | 
 | 725 | 	struct snd_pcm_runtime *runtime; | 
 | 726 |  | 
 | 727 | 	ml403_ac97cr = snd_pcm_substream_chip(substream); | 
 | 728 | 	runtime = substream->runtime; | 
 | 729 |  | 
 | 730 | 	PDEBUG(WORK_INFO, "open(capture)\n"); | 
 | 731 | 	ml403_ac97cr->capture_substream = substream; | 
 | 732 | 	runtime->hw = snd_ml403_ac97cr_capture; | 
 | 733 |  | 
 | 734 | 	snd_pcm_hw_constraint_step(runtime, 0, | 
 | 735 | 				   SNDRV_PCM_HW_PARAM_PERIOD_BYTES, | 
 | 736 | 				   CR_FIFO_SIZE / 2); | 
 | 737 | 	return 0; | 
 | 738 | } | 
 | 739 |  | 
 | 740 | static int snd_ml403_ac97cr_playback_close(struct snd_pcm_substream *substream) | 
 | 741 | { | 
 | 742 | 	struct snd_ml403_ac97cr *ml403_ac97cr; | 
 | 743 |  | 
 | 744 | 	ml403_ac97cr = snd_pcm_substream_chip(substream); | 
 | 745 |  | 
 | 746 | 	PDEBUG(WORK_INFO, "close(playback)\n"); | 
 | 747 | 	ml403_ac97cr->playback_substream = NULL; | 
 | 748 | 	return 0; | 
 | 749 | } | 
 | 750 |  | 
 | 751 | static int snd_ml403_ac97cr_capture_close(struct snd_pcm_substream *substream) | 
 | 752 | { | 
 | 753 | 	struct snd_ml403_ac97cr *ml403_ac97cr; | 
 | 754 |  | 
 | 755 | 	ml403_ac97cr = snd_pcm_substream_chip(substream); | 
 | 756 |  | 
 | 757 | 	PDEBUG(WORK_INFO, "close(capture)\n"); | 
 | 758 | 	ml403_ac97cr->capture_substream = NULL; | 
 | 759 | 	return 0; | 
 | 760 | } | 
 | 761 |  | 
 | 762 | static struct snd_pcm_ops snd_ml403_ac97cr_playback_ops = { | 
 | 763 | 	.open = snd_ml403_ac97cr_playback_open, | 
 | 764 | 	.close = snd_ml403_ac97cr_playback_close, | 
 | 765 | 	.ioctl = snd_pcm_lib_ioctl, | 
 | 766 | 	.hw_params = snd_ml403_ac97cr_hw_params, | 
 | 767 | 	.hw_free = snd_ml403_ac97cr_hw_free, | 
 | 768 | 	.prepare = snd_ml403_ac97cr_pcm_playback_prepare, | 
 | 769 | 	.trigger = snd_ml403_ac97cr_pcm_playback_trigger, | 
 | 770 | 	.pointer = snd_ml403_ac97cr_pcm_pointer, | 
 | 771 | }; | 
 | 772 |  | 
 | 773 | static struct snd_pcm_ops snd_ml403_ac97cr_capture_ops = { | 
 | 774 | 	.open = snd_ml403_ac97cr_capture_open, | 
 | 775 | 	.close = snd_ml403_ac97cr_capture_close, | 
 | 776 | 	.ioctl = snd_pcm_lib_ioctl, | 
 | 777 | 	.hw_params = snd_ml403_ac97cr_hw_params, | 
 | 778 | 	.hw_free = snd_ml403_ac97cr_hw_free, | 
 | 779 | 	.prepare = snd_ml403_ac97cr_pcm_capture_prepare, | 
 | 780 | 	.trigger = snd_ml403_ac97cr_pcm_capture_trigger, | 
 | 781 | 	.pointer = snd_ml403_ac97cr_pcm_pointer, | 
 | 782 | }; | 
 | 783 |  | 
 | 784 | static irqreturn_t snd_ml403_ac97cr_irq(int irq, void *dev_id) | 
 | 785 | { | 
 | 786 | 	struct snd_ml403_ac97cr *ml403_ac97cr; | 
 | 787 | 	struct platform_device *pfdev; | 
 | 788 | 	int cmp_irq; | 
 | 789 |  | 
 | 790 | 	ml403_ac97cr = (struct snd_ml403_ac97cr *)dev_id; | 
 | 791 | 	if (ml403_ac97cr == NULL) | 
 | 792 | 		return IRQ_NONE; | 
 | 793 |  | 
 | 794 | 	pfdev = ml403_ac97cr->pfdev; | 
 | 795 |  | 
 | 796 | 	/* playback interrupt */ | 
 | 797 | 	cmp_irq = platform_get_irq(pfdev, 0); | 
 | 798 | 	if (irq == cmp_irq) { | 
 | 799 | 		if (ml403_ac97cr->enable_irq) | 
 | 800 | 			snd_pcm_indirect2_playback_interrupt( | 
 | 801 | 				ml403_ac97cr->playback_substream, | 
 | 802 | 				&ml403_ac97cr->ind_rec, | 
 | 803 | 				snd_ml403_ac97cr_playback_ind2_copy, | 
 | 804 | 				snd_ml403_ac97cr_playback_ind2_zero); | 
 | 805 | 		else | 
 | 806 | 			goto __disable_irq; | 
 | 807 | 	} else { | 
 | 808 | 		/* record interrupt */ | 
 | 809 | 		cmp_irq = platform_get_irq(pfdev, 1); | 
 | 810 | 		if (irq == cmp_irq) { | 
 | 811 | 			if (ml403_ac97cr->enable_capture_irq) | 
 | 812 | 				snd_pcm_indirect2_capture_interrupt( | 
 | 813 | 					ml403_ac97cr->capture_substream, | 
 | 814 | 					&ml403_ac97cr->capture_ind2_rec, | 
 | 815 | 					snd_ml403_ac97cr_capture_ind2_copy, | 
 | 816 | 					snd_ml403_ac97cr_capture_ind2_null); | 
 | 817 | 			else | 
 | 818 | 				goto __disable_irq; | 
 | 819 | 		} else | 
 | 820 | 			return IRQ_NONE; | 
 | 821 | 	} | 
 | 822 | 	return IRQ_HANDLED; | 
 | 823 |  | 
 | 824 | __disable_irq: | 
 | 825 | 	PDEBUG(INIT_INFO, "irq(): irq %d is meant to be disabled! So, now try " | 
 | 826 | 	       "to disable it _really_!\n", irq); | 
 | 827 | 	disable_irq_nosync(irq); | 
 | 828 | 	return IRQ_HANDLED; | 
 | 829 | } | 
 | 830 |  | 
 | 831 | static unsigned short | 
 | 832 | snd_ml403_ac97cr_codec_read(struct snd_ac97 *ac97, unsigned short reg) | 
 | 833 | { | 
 | 834 | 	struct snd_ml403_ac97cr *ml403_ac97cr = ac97->private_data; | 
 | 835 | #ifdef CODEC_STAT | 
 | 836 | 	u32 stat; | 
 | 837 | 	u32 rafaccess = 0; | 
 | 838 | #endif | 
 | 839 | 	unsigned long end_time; | 
 | 840 | 	u16 value = 0; | 
 | 841 |  | 
 | 842 | 	if (!LM4550_RF_OK(reg)) { | 
 | 843 | 		snd_printk(KERN_WARNING SND_ML403_AC97CR_DRIVER ": " | 
 | 844 | 			   "access to unknown/unused codec register 0x%x " | 
 | 845 | 			   "ignored!\n", reg); | 
 | 846 | 		return 0; | 
 | 847 | 	} | 
 | 848 | 	/* check if we can fake/answer this access from our shadow register */ | 
 | 849 | 	if ((lm4550_regfile[reg / 2].flag & | 
 | 850 | 	     (LM4550_REG_DONEREAD | LM4550_REG_ALLFAKE)) && | 
 | 851 | 	    !(lm4550_regfile[reg / 2].flag & LM4550_REG_NOSHADOW)) { | 
 | 852 | 		if (lm4550_regfile[reg / 2].flag & LM4550_REG_FAKEREAD) { | 
 | 853 | 			PDEBUG(CODEC_FAKE, "codec_read(): faking read from " | 
 | 854 | 			       "reg=0x%x, val=0x%x / %d\n", | 
 | 855 | 			       reg, lm4550_regfile[reg / 2].def, | 
 | 856 | 			       lm4550_regfile[reg / 2].def); | 
 | 857 | 			return lm4550_regfile[reg / 2].def; | 
 | 858 | 		} else if ((lm4550_regfile[reg / 2].flag & | 
 | 859 | 			    LM4550_REG_FAKEPROBE) && | 
 | 860 | 			   ml403_ac97cr->ac97_fake) { | 
 | 861 | 			PDEBUG(CODEC_FAKE, "codec_read(): faking read from " | 
 | 862 | 			       "reg=0x%x, val=0x%x / %d (probe)\n", | 
 | 863 | 			       reg, lm4550_regfile[reg / 2].value, | 
 | 864 | 			       lm4550_regfile[reg / 2].value); | 
 | 865 | 			return lm4550_regfile[reg / 2].value; | 
 | 866 | 		} else { | 
 | 867 | #ifdef CODEC_STAT | 
 | 868 | 			PDEBUG(CODEC_FAKE, "codec_read(): read access " | 
 | 869 | 			       "answered by shadow register 0x%x (value=0x%x " | 
 | 870 | 			       "/ %d) (cw=%d cr=%d)\n", | 
 | 871 | 			       reg, lm4550_regfile[reg / 2].value, | 
 | 872 | 			       lm4550_regfile[reg / 2].value, | 
 | 873 | 			       ml403_ac97cr->ac97_write, | 
 | 874 | 			       ml403_ac97cr->ac97_read); | 
 | 875 | #else | 
 | 876 | 			PDEBUG(CODEC_FAKE, "codec_read(): read access " | 
 | 877 | 			       "answered by shadow register 0x%x (value=0x%x " | 
 | 878 | 			       "/ %d)\n", | 
 | 879 | 			       reg, lm4550_regfile[reg / 2].value, | 
 | 880 | 			       lm4550_regfile[reg / 2].value); | 
 | 881 | #endif | 
 | 882 | 			return lm4550_regfile[reg / 2].value; | 
 | 883 | 		} | 
 | 884 | 	} | 
 | 885 | 	/* if we are here, we _have_ to access the codec really, no faking */ | 
 | 886 | 	if (mutex_lock_interruptible(&ml403_ac97cr->cdc_mutex) != 0) | 
 | 887 | 		return 0; | 
 | 888 | #ifdef CODEC_STAT | 
 | 889 | 	ml403_ac97cr->ac97_read++; | 
 | 890 | #endif | 
 | 891 | 	spin_lock(&ml403_ac97cr->reg_lock); | 
 | 892 | 	out_be32(CR_REG(ml403_ac97cr, CODEC_ADDR), | 
 | 893 | 		 CR_CODEC_ADDR(reg) | CR_CODEC_READ); | 
 | 894 | 	spin_unlock(&ml403_ac97cr->reg_lock); | 
 | 895 | 	end_time = jiffies + (HZ / CODEC_TIMEOUT_AFTER_READ); | 
 | 896 | 	do { | 
 | 897 | 		spin_lock(&ml403_ac97cr->reg_lock); | 
 | 898 | #ifdef CODEC_STAT | 
 | 899 | 		rafaccess++; | 
 | 900 | 		stat = in_be32(CR_REG(ml403_ac97cr, STATUS)); | 
 | 901 | 		if ((stat & CR_RAF) == CR_RAF) { | 
 | 902 | 			value = CR_CODEC_DATAREAD( | 
 | 903 | 				in_be32(CR_REG(ml403_ac97cr, CODEC_DATAREAD))); | 
 | 904 | 			PDEBUG(CODEC_SUCCESS, "codec_read(): (done) reg=0x%x, " | 
 | 905 | 			       "value=0x%x / %d (STATUS=0x%x)\n", | 
 | 906 | 			       reg, value, value, stat); | 
 | 907 | #else | 
 | 908 | 		if ((in_be32(CR_REG(ml403_ac97cr, STATUS)) & | 
 | 909 | 		     CR_RAF) == CR_RAF) { | 
 | 910 | 			value = CR_CODEC_DATAREAD( | 
 | 911 | 				in_be32(CR_REG(ml403_ac97cr, CODEC_DATAREAD))); | 
 | 912 | 			PDEBUG(CODEC_SUCCESS, "codec_read(): (done) " | 
 | 913 | 			       "reg=0x%x, value=0x%x / %d\n", | 
 | 914 | 			       reg, value, value); | 
 | 915 | #endif | 
 | 916 | 			lm4550_regfile[reg / 2].value = value; | 
 | 917 | 			lm4550_regfile[reg / 2].flag |= LM4550_REG_DONEREAD; | 
 | 918 | 			spin_unlock(&ml403_ac97cr->reg_lock); | 
 | 919 | 			mutex_unlock(&ml403_ac97cr->cdc_mutex); | 
 | 920 | 			return value; | 
 | 921 | 		} | 
 | 922 | 		spin_unlock(&ml403_ac97cr->reg_lock); | 
 | 923 | 		schedule_timeout_uninterruptible(1); | 
 | 924 | 	} while (time_after(end_time, jiffies)); | 
 | 925 | 	/* read the DATAREAD register anyway, see comment below */ | 
 | 926 | 	spin_lock(&ml403_ac97cr->reg_lock); | 
 | 927 | 	value = | 
 | 928 | 	    CR_CODEC_DATAREAD(in_be32(CR_REG(ml403_ac97cr, CODEC_DATAREAD))); | 
 | 929 | 	spin_unlock(&ml403_ac97cr->reg_lock); | 
 | 930 | #ifdef CODEC_STAT | 
 | 931 | 	snd_printk(KERN_WARNING SND_ML403_AC97CR_DRIVER ": " | 
 | 932 | 		   "timeout while codec read! " | 
 | 933 | 		   "(reg=0x%x, last STATUS=0x%x, DATAREAD=0x%x / %d, %d) " | 
 | 934 | 		   "(cw=%d, cr=%d)\n", | 
 | 935 | 		   reg, stat, value, value, rafaccess, | 
 | 936 | 		   ml403_ac97cr->ac97_write, ml403_ac97cr->ac97_read); | 
 | 937 | #else | 
 | 938 | 	snd_printk(KERN_WARNING SND_ML403_AC97CR_DRIVER ": " | 
 | 939 | 		   "timeout while codec read! " | 
 | 940 | 		   "(reg=0x%x, DATAREAD=0x%x / %d)\n", | 
 | 941 | 		   reg, value, value); | 
 | 942 | #endif | 
 | 943 | 	/* BUG: This is PURE speculation! But after _most_ read timeouts the | 
 | 944 | 	 * value in the register is ok! | 
 | 945 | 	 */ | 
 | 946 | 	lm4550_regfile[reg / 2].value = value; | 
 | 947 | 	lm4550_regfile[reg / 2].flag |= LM4550_REG_DONEREAD; | 
 | 948 | 	mutex_unlock(&ml403_ac97cr->cdc_mutex); | 
 | 949 | 	return value; | 
 | 950 | } | 
 | 951 |  | 
 | 952 | static void | 
 | 953 | snd_ml403_ac97cr_codec_write(struct snd_ac97 *ac97, unsigned short reg, | 
 | 954 | 			     unsigned short val) | 
 | 955 | { | 
 | 956 | 	struct snd_ml403_ac97cr *ml403_ac97cr = ac97->private_data; | 
 | 957 |  | 
 | 958 | #ifdef CODEC_STAT | 
 | 959 | 	u32 stat; | 
 | 960 | 	u32 rafaccess = 0; | 
 | 961 | #endif | 
 | 962 | #ifdef CODEC_WRITE_CHECK_RAF | 
 | 963 | 	unsigned long end_time; | 
 | 964 | #endif | 
 | 965 |  | 
 | 966 | 	if (!LM4550_RF_OK(reg)) { | 
 | 967 | 		snd_printk(KERN_WARNING SND_ML403_AC97CR_DRIVER ": " | 
 | 968 | 			   "access to unknown/unused codec register 0x%x " | 
 | 969 | 			   "ignored!\n", reg); | 
 | 970 | 		return; | 
 | 971 | 	} | 
 | 972 | 	if (lm4550_regfile[reg / 2].flag & LM4550_REG_READONLY) { | 
 | 973 | 		snd_printk(KERN_WARNING SND_ML403_AC97CR_DRIVER ": " | 
 | 974 | 			   "write access to read only codec register 0x%x " | 
 | 975 | 			   "ignored!\n", reg); | 
 | 976 | 		return; | 
 | 977 | 	} | 
 | 978 | 	if ((val & lm4550_regfile[reg / 2].wmask) != val) { | 
 | 979 | 		snd_printk(KERN_WARNING SND_ML403_AC97CR_DRIVER ": " | 
 | 980 | 			   "write access to codec register 0x%x " | 
 | 981 | 			   "with bad value 0x%x / %d!\n", | 
 | 982 | 			   reg, val, val); | 
 | 983 | 		val = val & lm4550_regfile[reg / 2].wmask; | 
 | 984 | 	} | 
 | 985 | 	if (((lm4550_regfile[reg / 2].flag & LM4550_REG_FAKEPROBE) && | 
 | 986 | 	     ml403_ac97cr->ac97_fake) && | 
 | 987 | 	    !(lm4550_regfile[reg / 2].flag & LM4550_REG_NOSHADOW)) { | 
 | 988 | 		PDEBUG(CODEC_FAKE, "codec_write(): faking write to reg=0x%x, " | 
 | 989 | 		       "val=0x%x / %d\n", reg, val, val); | 
 | 990 | 		lm4550_regfile[reg / 2].value = (val & | 
 | 991 | 						lm4550_regfile[reg / 2].wmask); | 
 | 992 | 		return; | 
 | 993 | 	} | 
 | 994 | 	if (mutex_lock_interruptible(&ml403_ac97cr->cdc_mutex) != 0) | 
 | 995 | 		return; | 
 | 996 | #ifdef CODEC_STAT | 
 | 997 | 	ml403_ac97cr->ac97_write++; | 
 | 998 | #endif | 
 | 999 | 	spin_lock(&ml403_ac97cr->reg_lock); | 
 | 1000 | 	out_be32(CR_REG(ml403_ac97cr, CODEC_DATAWRITE), | 
 | 1001 | 		 CR_CODEC_DATAWRITE(val)); | 
 | 1002 | 	out_be32(CR_REG(ml403_ac97cr, CODEC_ADDR), | 
 | 1003 | 		 CR_CODEC_ADDR(reg) | CR_CODEC_WRITE); | 
 | 1004 | 	spin_unlock(&ml403_ac97cr->reg_lock); | 
 | 1005 | #ifdef CODEC_WRITE_CHECK_RAF | 
 | 1006 | 	/* check CR_CODEC_RAF bit to see if write access to register is done; | 
 | 1007 | 	 * loop until bit is set or timeout happens | 
 | 1008 | 	 */ | 
 | 1009 | 	end_time = jiffies + HZ / CODEC_TIMEOUT_AFTER_WRITE; | 
 | 1010 | 	do { | 
 | 1011 | 		spin_lock(&ml403_ac97cr->reg_lock); | 
 | 1012 | #ifdef CODEC_STAT | 
 | 1013 | 		rafaccess++; | 
 | 1014 | 		stat = in_be32(CR_REG(ml403_ac97cr, STATUS)) | 
 | 1015 | 		if ((stat & CR_RAF) == CR_RAF) { | 
 | 1016 | #else | 
 | 1017 | 		if ((in_be32(CR_REG(ml403_ac97cr, STATUS)) & | 
 | 1018 | 		     CR_RAF) == CR_RAF) { | 
 | 1019 | #endif | 
 | 1020 | 			PDEBUG(CODEC_SUCCESS, "codec_write(): (done) " | 
 | 1021 | 			       "reg=0x%x, value=%d / 0x%x\n", | 
 | 1022 | 			       reg, val, val); | 
 | 1023 | 			if (!(lm4550_regfile[reg / 2].flag & | 
 | 1024 | 			      LM4550_REG_NOSHADOW) && | 
 | 1025 | 			    !(lm4550_regfile[reg / 2].flag & | 
 | 1026 | 			      LM4550_REG_NOSAVE)) | 
 | 1027 | 				lm4550_regfile[reg / 2].value = val; | 
 | 1028 | 			lm4550_regfile[reg / 2].flag |= LM4550_REG_DONEREAD; | 
 | 1029 | 			spin_unlock(&ml403_ac97cr->reg_lock); | 
 | 1030 | 			mutex_unlock(&ml403_ac97cr->cdc_mutex); | 
 | 1031 | 			return; | 
 | 1032 | 		} | 
 | 1033 | 		spin_unlock(&ml403_ac97cr->reg_lock); | 
 | 1034 | 		schedule_timeout_uninterruptible(1); | 
 | 1035 | 	} while (time_after(end_time, jiffies)); | 
 | 1036 | #ifdef CODEC_STAT | 
 | 1037 | 	snd_printk(KERN_WARNING SND_ML403_AC97CR_DRIVER ": " | 
 | 1038 | 		   "timeout while codec write " | 
 | 1039 | 		   "(reg=0x%x, val=0x%x / %d, last STATUS=0x%x, %d) " | 
 | 1040 | 		   "(cw=%d, cr=%d)\n", | 
 | 1041 | 		   reg, val, val, stat, rafaccess, ml403_ac97cr->ac97_write, | 
 | 1042 | 		   ml403_ac97cr->ac97_read); | 
 | 1043 | #else | 
 | 1044 | 	snd_printk(KERN_WARNING SND_ML403_AC97CR_DRIVER ": " | 
 | 1045 | 		   "timeout while codec write (reg=0x%x, val=0x%x / %d)\n", | 
 | 1046 | 		   reg, val, val); | 
 | 1047 | #endif | 
 | 1048 | #else /* CODEC_WRITE_CHECK_RAF */ | 
 | 1049 | #if CODEC_WAIT_AFTER_WRITE > 0 | 
 | 1050 | 	/* officially, in AC97 spec there is no possibility for a AC97 | 
 | 1051 | 	 * controller to determine, if write access is done or not - so: How | 
 | 1052 | 	 * is Xilinx able to provide a RAF bit for write access? | 
 | 1053 | 	 * => very strange, thus just don't check RAF bit (compare with | 
 | 1054 | 	 * Xilinx's example app in EDK 8.1i) and wait | 
 | 1055 | 	 */ | 
 | 1056 | 	schedule_timeout_uninterruptible(HZ / CODEC_WAIT_AFTER_WRITE); | 
 | 1057 | #endif | 
 | 1058 | 	PDEBUG(CODEC_SUCCESS, "codec_write(): (done) " | 
 | 1059 | 	       "reg=0x%x, value=%d / 0x%x (no RAF check)\n", | 
 | 1060 | 	       reg, val, val); | 
 | 1061 | #endif | 
 | 1062 | 	mutex_unlock(&ml403_ac97cr->cdc_mutex); | 
 | 1063 | 	return; | 
 | 1064 | } | 
 | 1065 |  | 
 | 1066 | static int __devinit | 
 | 1067 | snd_ml403_ac97cr_chip_init(struct snd_ml403_ac97cr *ml403_ac97cr) | 
 | 1068 | { | 
 | 1069 | 	unsigned long end_time; | 
 | 1070 | 	PDEBUG(INIT_INFO, "chip_init():\n"); | 
 | 1071 | 	end_time = jiffies + HZ / CODEC_TIMEOUT_ON_INIT; | 
 | 1072 | 	do { | 
 | 1073 | 		if (in_be32(CR_REG(ml403_ac97cr, STATUS)) & CR_CODECREADY) { | 
 | 1074 | 			/* clear both hardware FIFOs */ | 
 | 1075 | 			out_be32(CR_REG(ml403_ac97cr, RESETFIFO), | 
 | 1076 | 				 CR_RECRESET | CR_PLAYRESET); | 
 | 1077 | 			PDEBUG(INIT_INFO, "chip_init(): (done)\n"); | 
 | 1078 | 			return 0; | 
 | 1079 | 		} | 
 | 1080 | 		schedule_timeout_uninterruptible(1); | 
 | 1081 | 	} while (time_after(end_time, jiffies)); | 
 | 1082 | 	snd_printk(KERN_ERR SND_ML403_AC97CR_DRIVER ": " | 
 | 1083 | 		   "timeout while waiting for codec, " | 
 | 1084 | 		   "not ready!\n"); | 
 | 1085 | 	return -EBUSY; | 
 | 1086 | } | 
 | 1087 |  | 
 | 1088 | static int snd_ml403_ac97cr_free(struct snd_ml403_ac97cr *ml403_ac97cr) | 
 | 1089 | { | 
 | 1090 | 	PDEBUG(INIT_INFO, "free():\n"); | 
 | 1091 | 	/* irq release */ | 
 | 1092 | 	if (ml403_ac97cr->irq >= 0) | 
 | 1093 | 		free_irq(ml403_ac97cr->irq, ml403_ac97cr); | 
 | 1094 | 	if (ml403_ac97cr->capture_irq >= 0) | 
 | 1095 | 		free_irq(ml403_ac97cr->capture_irq, ml403_ac97cr); | 
 | 1096 | 	/* give back "port" */ | 
 | 1097 | 	if (ml403_ac97cr->port != NULL) | 
 | 1098 | 		iounmap(ml403_ac97cr->port); | 
 | 1099 | 	kfree(ml403_ac97cr); | 
 | 1100 | 	PDEBUG(INIT_INFO, "free(): (done)\n"); | 
 | 1101 | 	return 0; | 
 | 1102 | } | 
 | 1103 |  | 
 | 1104 | static int snd_ml403_ac97cr_dev_free(struct snd_device *snddev) | 
 | 1105 | { | 
 | 1106 | 	struct snd_ml403_ac97cr *ml403_ac97cr = snddev->device_data; | 
 | 1107 | 	PDEBUG(INIT_INFO, "dev_free():\n"); | 
 | 1108 | 	return snd_ml403_ac97cr_free(ml403_ac97cr); | 
 | 1109 | } | 
 | 1110 |  | 
 | 1111 | static int __devinit | 
 | 1112 | snd_ml403_ac97cr_create(struct snd_card *card, struct platform_device *pfdev, | 
 | 1113 | 			struct snd_ml403_ac97cr **rml403_ac97cr) | 
 | 1114 | { | 
 | 1115 | 	struct snd_ml403_ac97cr *ml403_ac97cr; | 
 | 1116 | 	int err; | 
 | 1117 | 	static struct snd_device_ops ops = { | 
 | 1118 | 		.dev_free = snd_ml403_ac97cr_dev_free, | 
 | 1119 | 	}; | 
 | 1120 | 	struct resource *resource; | 
 | 1121 | 	int irq; | 
 | 1122 |  | 
 | 1123 | 	*rml403_ac97cr = NULL; | 
 | 1124 | 	ml403_ac97cr = kzalloc(sizeof(*ml403_ac97cr), GFP_KERNEL); | 
 | 1125 | 	if (ml403_ac97cr == NULL) | 
 | 1126 | 		return -ENOMEM; | 
 | 1127 | 	spin_lock_init(&ml403_ac97cr->reg_lock); | 
 | 1128 | 	mutex_init(&ml403_ac97cr->cdc_mutex); | 
 | 1129 | 	ml403_ac97cr->card = card; | 
 | 1130 | 	ml403_ac97cr->pfdev = pfdev; | 
 | 1131 | 	ml403_ac97cr->irq = -1; | 
 | 1132 | 	ml403_ac97cr->enable_irq = 0; | 
 | 1133 | 	ml403_ac97cr->capture_irq = -1; | 
 | 1134 | 	ml403_ac97cr->enable_capture_irq = 0; | 
 | 1135 | 	ml403_ac97cr->port = NULL; | 
 | 1136 | 	ml403_ac97cr->res_port = NULL; | 
 | 1137 |  | 
 | 1138 | 	PDEBUG(INIT_INFO, "Trying to reserve resources now ...\n"); | 
 | 1139 | 	resource = platform_get_resource(pfdev, IORESOURCE_MEM, 0); | 
 | 1140 | 	/* get "port" */ | 
 | 1141 | 	ml403_ac97cr->port = ioremap_nocache(resource->start, | 
 | 1142 | 					     (resource->end) - | 
 | 1143 | 					     (resource->start) + 1); | 
 | 1144 | 	if (ml403_ac97cr->port == NULL) { | 
 | 1145 | 		snd_printk(KERN_ERR SND_ML403_AC97CR_DRIVER ": " | 
| Joe Perches | a8cc0f4 | 2010-12-13 13:42:22 -0800 | [diff] [blame] | 1146 | 			   "unable to remap memory region (%pR)\n", | 
 | 1147 | 			   resource); | 
| Joachim Foerster | a9f00d8 | 2007-11-05 16:06:01 +0100 | [diff] [blame] | 1148 | 		snd_ml403_ac97cr_free(ml403_ac97cr); | 
 | 1149 | 		return -EBUSY; | 
 | 1150 | 	} | 
 | 1151 | 	snd_printk(KERN_INFO SND_ML403_AC97CR_DRIVER ": " | 
 | 1152 | 		   "remap controller memory region to " | 
 | 1153 | 		   "0x%x done\n", (unsigned int)ml403_ac97cr->port); | 
 | 1154 | 	/* get irq */ | 
 | 1155 | 	irq = platform_get_irq(pfdev, 0); | 
 | 1156 | 	if (request_irq(irq, snd_ml403_ac97cr_irq, IRQF_DISABLED, | 
| Kay Sievers | bb072bf | 2008-11-02 03:50:35 +0100 | [diff] [blame] | 1157 | 			dev_name(&pfdev->dev), (void *)ml403_ac97cr)) { | 
| Joachim Foerster | a9f00d8 | 2007-11-05 16:06:01 +0100 | [diff] [blame] | 1158 | 		snd_printk(KERN_ERR SND_ML403_AC97CR_DRIVER ": " | 
 | 1159 | 			   "unable to grab IRQ %d\n", | 
 | 1160 | 			   irq); | 
 | 1161 | 		snd_ml403_ac97cr_free(ml403_ac97cr); | 
 | 1162 | 		return -EBUSY; | 
 | 1163 | 	} | 
 | 1164 | 	ml403_ac97cr->irq = irq; | 
 | 1165 | 	snd_printk(KERN_INFO SND_ML403_AC97CR_DRIVER ": " | 
 | 1166 | 		   "request (playback) irq %d done\n", | 
 | 1167 | 		   ml403_ac97cr->irq); | 
 | 1168 | 	irq = platform_get_irq(pfdev, 1); | 
 | 1169 | 	if (request_irq(irq, snd_ml403_ac97cr_irq, IRQF_DISABLED, | 
| Kay Sievers | bb072bf | 2008-11-02 03:50:35 +0100 | [diff] [blame] | 1170 | 			dev_name(&pfdev->dev), (void *)ml403_ac97cr)) { | 
| Joachim Foerster | a9f00d8 | 2007-11-05 16:06:01 +0100 | [diff] [blame] | 1171 | 		snd_printk(KERN_ERR SND_ML403_AC97CR_DRIVER ": " | 
 | 1172 | 			   "unable to grab IRQ %d\n", | 
 | 1173 | 			   irq); | 
 | 1174 | 		snd_ml403_ac97cr_free(ml403_ac97cr); | 
 | 1175 | 		return -EBUSY; | 
 | 1176 | 	} | 
 | 1177 | 	ml403_ac97cr->capture_irq = irq; | 
 | 1178 | 	snd_printk(KERN_INFO SND_ML403_AC97CR_DRIVER ": " | 
 | 1179 | 		   "request (capture) irq %d done\n", | 
 | 1180 | 		   ml403_ac97cr->capture_irq); | 
 | 1181 |  | 
 | 1182 | 	err = snd_ml403_ac97cr_chip_init(ml403_ac97cr); | 
 | 1183 | 	if (err < 0) { | 
 | 1184 | 		snd_ml403_ac97cr_free(ml403_ac97cr); | 
 | 1185 | 		return err; | 
 | 1186 | 	} | 
 | 1187 |  | 
 | 1188 | 	err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, ml403_ac97cr, &ops); | 
 | 1189 | 	if (err < 0) { | 
 | 1190 | 		PDEBUG(INIT_FAILURE, "probe(): snd_device_new() failed!\n"); | 
 | 1191 | 		snd_ml403_ac97cr_free(ml403_ac97cr); | 
 | 1192 | 		return err; | 
 | 1193 | 	} | 
 | 1194 |  | 
| Joachim Foerster | a9f00d8 | 2007-11-05 16:06:01 +0100 | [diff] [blame] | 1195 | 	*rml403_ac97cr = ml403_ac97cr; | 
 | 1196 | 	return 0; | 
 | 1197 | } | 
 | 1198 |  | 
 | 1199 | static void snd_ml403_ac97cr_mixer_free(struct snd_ac97 *ac97) | 
 | 1200 | { | 
 | 1201 | 	struct snd_ml403_ac97cr *ml403_ac97cr = ac97->private_data; | 
 | 1202 | 	PDEBUG(INIT_INFO, "mixer_free():\n"); | 
 | 1203 | 	ml403_ac97cr->ac97 = NULL; | 
 | 1204 | 	PDEBUG(INIT_INFO, "mixer_free(): (done)\n"); | 
 | 1205 | } | 
 | 1206 |  | 
 | 1207 | static int __devinit | 
 | 1208 | snd_ml403_ac97cr_mixer(struct snd_ml403_ac97cr *ml403_ac97cr) | 
 | 1209 | { | 
 | 1210 | 	struct snd_ac97_bus *bus; | 
 | 1211 | 	struct snd_ac97_template ac97; | 
 | 1212 | 	int err; | 
 | 1213 | 	static struct snd_ac97_bus_ops ops = { | 
 | 1214 | 		.write = snd_ml403_ac97cr_codec_write, | 
 | 1215 | 		.read = snd_ml403_ac97cr_codec_read, | 
 | 1216 | 	}; | 
 | 1217 | 	PDEBUG(INIT_INFO, "mixer():\n"); | 
 | 1218 | 	err = snd_ac97_bus(ml403_ac97cr->card, 0, &ops, NULL, &bus); | 
 | 1219 | 	if (err < 0) | 
 | 1220 | 		return err; | 
 | 1221 |  | 
 | 1222 | 	memset(&ac97, 0, sizeof(ac97)); | 
 | 1223 | 	ml403_ac97cr->ac97_fake = 1; | 
 | 1224 | 	lm4550_regfile_init(); | 
 | 1225 | #ifdef CODEC_STAT | 
 | 1226 | 	ml403_ac97cr->ac97_read = 0; | 
 | 1227 | 	ml403_ac97cr->ac97_write = 0; | 
 | 1228 | #endif | 
 | 1229 | 	ac97.private_data = ml403_ac97cr; | 
 | 1230 | 	ac97.private_free = snd_ml403_ac97cr_mixer_free; | 
 | 1231 | 	ac97.scaps = AC97_SCAP_AUDIO | AC97_SCAP_SKIP_MODEM | | 
 | 1232 | 	    AC97_SCAP_NO_SPDIF; | 
 | 1233 | 	err = snd_ac97_mixer(bus, &ac97, &ml403_ac97cr->ac97); | 
 | 1234 | 	ml403_ac97cr->ac97_fake = 0; | 
 | 1235 | 	lm4550_regfile_write_values_after_init(ml403_ac97cr->ac97); | 
 | 1236 | 	PDEBUG(INIT_INFO, "mixer(): (done) snd_ac97_mixer()=%d\n", err); | 
 | 1237 | 	return err; | 
 | 1238 | } | 
 | 1239 |  | 
 | 1240 | static int __devinit | 
 | 1241 | snd_ml403_ac97cr_pcm(struct snd_ml403_ac97cr *ml403_ac97cr, int device, | 
 | 1242 | 		     struct snd_pcm **rpcm) | 
 | 1243 | { | 
 | 1244 | 	struct snd_pcm *pcm; | 
 | 1245 | 	int err; | 
 | 1246 |  | 
 | 1247 | 	if (rpcm) | 
 | 1248 | 		*rpcm = NULL; | 
 | 1249 | 	err = snd_pcm_new(ml403_ac97cr->card, "ML403AC97CR/1", device, 1, 1, | 
 | 1250 | 			  &pcm); | 
 | 1251 | 	if (err < 0) | 
 | 1252 | 		return err; | 
 | 1253 | 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, | 
 | 1254 | 			&snd_ml403_ac97cr_playback_ops); | 
 | 1255 | 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, | 
 | 1256 | 			&snd_ml403_ac97cr_capture_ops); | 
 | 1257 | 	pcm->private_data = ml403_ac97cr; | 
 | 1258 | 	pcm->info_flags = 0; | 
 | 1259 | 	strcpy(pcm->name, "ML403AC97CR DAC/ADC"); | 
 | 1260 | 	ml403_ac97cr->pcm = pcm; | 
 | 1261 |  | 
 | 1262 | 	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, | 
 | 1263 | 					  snd_dma_continuous_data(GFP_KERNEL), | 
 | 1264 | 					  64 * 1024, | 
 | 1265 | 					  128 * 1024); | 
 | 1266 | 	if (rpcm) | 
 | 1267 | 		*rpcm = pcm; | 
 | 1268 | 	return 0; | 
 | 1269 | } | 
 | 1270 |  | 
 | 1271 | static int __devinit snd_ml403_ac97cr_probe(struct platform_device *pfdev) | 
 | 1272 | { | 
 | 1273 | 	struct snd_card *card; | 
 | 1274 | 	struct snd_ml403_ac97cr *ml403_ac97cr = NULL; | 
 | 1275 | 	int err; | 
 | 1276 | 	int dev = pfdev->id; | 
 | 1277 |  | 
 | 1278 | 	if (dev >= SNDRV_CARDS) | 
 | 1279 | 		return -ENODEV; | 
 | 1280 | 	if (!enable[dev]) | 
 | 1281 | 		return -ENOENT; | 
 | 1282 |  | 
| Takashi Iwai | bd7dd77 | 2008-12-28 16:45:02 +0100 | [diff] [blame] | 1283 | 	err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); | 
 | 1284 | 	if (err < 0) | 
 | 1285 | 		return err; | 
| Joachim Foerster | a9f00d8 | 2007-11-05 16:06:01 +0100 | [diff] [blame] | 1286 | 	err = snd_ml403_ac97cr_create(card, pfdev, &ml403_ac97cr); | 
 | 1287 | 	if (err < 0) { | 
 | 1288 | 		PDEBUG(INIT_FAILURE, "probe(): create failed!\n"); | 
 | 1289 | 		snd_card_free(card); | 
 | 1290 | 		return err; | 
 | 1291 | 	} | 
 | 1292 | 	PDEBUG(INIT_INFO, "probe(): create done\n"); | 
 | 1293 | 	card->private_data = ml403_ac97cr; | 
 | 1294 | 	err = snd_ml403_ac97cr_mixer(ml403_ac97cr); | 
 | 1295 | 	if (err < 0) { | 
 | 1296 | 		snd_card_free(card); | 
 | 1297 | 		return err; | 
 | 1298 | 	} | 
 | 1299 | 	PDEBUG(INIT_INFO, "probe(): mixer done\n"); | 
 | 1300 | 	err = snd_ml403_ac97cr_pcm(ml403_ac97cr, 0, NULL); | 
 | 1301 | 	if (err < 0) { | 
 | 1302 | 		snd_card_free(card); | 
 | 1303 | 		return err; | 
 | 1304 | 	} | 
 | 1305 | 	PDEBUG(INIT_INFO, "probe(): PCM done\n"); | 
 | 1306 | 	strcpy(card->driver, SND_ML403_AC97CR_DRIVER); | 
 | 1307 | 	strcpy(card->shortname, "ML403 AC97 Controller Reference"); | 
 | 1308 | 	sprintf(card->longname, "%s %s at 0x%lx, irq %i & %i, device %i", | 
 | 1309 | 		card->shortname, card->driver, | 
 | 1310 | 		(unsigned long)ml403_ac97cr->port, ml403_ac97cr->irq, | 
 | 1311 | 		ml403_ac97cr->capture_irq, dev + 1); | 
 | 1312 |  | 
| Takashi Iwai | d47ac43 | 2007-11-26 08:58:48 +0100 | [diff] [blame] | 1313 | 	snd_card_set_dev(card, &pfdev->dev); | 
 | 1314 |  | 
| Joachim Foerster | a9f00d8 | 2007-11-05 16:06:01 +0100 | [diff] [blame] | 1315 | 	err = snd_card_register(card); | 
 | 1316 | 	if (err < 0) { | 
 | 1317 | 		snd_card_free(card); | 
 | 1318 | 		return err; | 
 | 1319 | 	} | 
 | 1320 | 	platform_set_drvdata(pfdev, card); | 
 | 1321 | 	PDEBUG(INIT_INFO, "probe(): (done)\n"); | 
 | 1322 | 	return 0; | 
 | 1323 | } | 
 | 1324 |  | 
 | 1325 | static int snd_ml403_ac97cr_remove(struct platform_device *pfdev) | 
 | 1326 | { | 
 | 1327 | 	snd_card_free(platform_get_drvdata(pfdev)); | 
 | 1328 | 	platform_set_drvdata(pfdev, NULL); | 
 | 1329 | 	return 0; | 
 | 1330 | } | 
 | 1331 |  | 
| Kay Sievers | 8b45a20 | 2008-04-14 13:33:36 +0200 | [diff] [blame] | 1332 | /* work with hotplug and coldplug */ | 
 | 1333 | MODULE_ALIAS("platform:" SND_ML403_AC97CR_DRIVER); | 
 | 1334 |  | 
| Joachim Foerster | a9f00d8 | 2007-11-05 16:06:01 +0100 | [diff] [blame] | 1335 | static struct platform_driver snd_ml403_ac97cr_driver = { | 
 | 1336 | 	.probe = snd_ml403_ac97cr_probe, | 
 | 1337 | 	.remove = snd_ml403_ac97cr_remove, | 
 | 1338 | 	.driver = { | 
 | 1339 | 		.name = SND_ML403_AC97CR_DRIVER, | 
| Kay Sievers | 8b45a20 | 2008-04-14 13:33:36 +0200 | [diff] [blame] | 1340 | 		.owner = THIS_MODULE, | 
| Joachim Foerster | a9f00d8 | 2007-11-05 16:06:01 +0100 | [diff] [blame] | 1341 | 	}, | 
 | 1342 | }; | 
 | 1343 |  | 
 | 1344 | static int __init alsa_card_ml403_ac97cr_init(void) | 
 | 1345 | { | 
 | 1346 | 	return platform_driver_register(&snd_ml403_ac97cr_driver); | 
 | 1347 | } | 
 | 1348 |  | 
 | 1349 | static void __exit alsa_card_ml403_ac97cr_exit(void) | 
 | 1350 | { | 
 | 1351 | 	platform_driver_unregister(&snd_ml403_ac97cr_driver); | 
 | 1352 | } | 
 | 1353 |  | 
 | 1354 | module_init(alsa_card_ml403_ac97cr_init) | 
 | 1355 | module_exit(alsa_card_ml403_ac97cr_exit) |