Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
dbf3cb27
Commit
dbf3cb27
authored
Jul 11, 2003
by
Alan Cox
Committed by
Steve French
Jul 11, 2003
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[PATCH] update ITE audio
parent
8019adb6
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
1637 additions
and
1333 deletions
+1637
-1333
sound/oss/ite8172.c
sound/oss/ite8172.c
+1637
-1333
No files found.
sound/oss/ite8172.c
View file @
dbf3cb27
...
@@ -42,15 +42,17 @@
...
@@ -42,15 +42,17 @@
* * Memory mapping the audio buffers, and the ioctl controls that go
* * Memory mapping the audio buffers, and the ioctl controls that go
* with it.
* with it.
* * S/PDIF output.
* * S/PDIF output.
* * I2S support.
* 3. The following is not supported:
* 3. The following is not supported:
* * I2S input.
* * legacy audio mode.
* * legacy audio mode.
* 4. Support for volume button interrupts is implemented but doesn't
* 4. Support for volume button interrupts is implemented but doesn't
* work yet.
* work yet.
*
*
* Revision history
* Revision history
* 02.08.2001 0.1 Initial release
* 02.08.2001 Initial release
* 06.22.2001 Added I2S support
*/
*/
#include <linux/version.h>
#include <linux/module.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/string.h>
#include <linux/ioport.h>
#include <linux/ioport.h>
...
@@ -80,6 +82,19 @@
...
@@ -80,6 +82,19 @@
#undef IT8172_VERBOSE_DEBUG
#undef IT8172_VERBOSE_DEBUG
#define DBG(x) {}
#define DBG(x) {}
#define IT8172_MODULE_NAME "IT8172 audio"
#define PFX IT8172_MODULE_NAME
#ifdef IT8172_DEBUG
#define dbg(format, arg...) printk(KERN_DEBUG PFX ": " format "\n" , ## arg)
#else
#define dbg(format, arg...) do {} while (0)
#endif
#define err(format, arg...) printk(KERN_ERR PFX ": " format "\n" , ## arg)
#define info(format, arg...) printk(KERN_INFO PFX ": " format "\n" , ## arg)
#define warn(format, arg...) printk(KERN_WARNING PFX ": " format "\n" , ## arg)
static
const
unsigned
sample_shift
[]
=
{
0
,
1
,
1
,
2
};
static
const
unsigned
sample_shift
[]
=
{
0
,
1
,
1
,
2
};
...
@@ -226,75 +241,84 @@ static const unsigned sample_shift[] = { 0, 1, 1, 2 };
...
@@ -226,75 +241,84 @@ static const unsigned sample_shift[] = { 0, 1, 1, 2 };
#define POLL_COUNT 0x5000
#define POLL_COUNT 0x5000
#define IT8172_MODULE_NAME "IT8172 audio"
/* --------------------------------------------------------------------- */
#define PFX IT8172_MODULE_NAME ": "
/*
* Define DIGITAL1 as the I2S channel, since it is not listed in
* soundcard.h.
*/
#define SOUND_MIXER_I2S SOUND_MIXER_DIGITAL1
#define SOUND_MASK_I2S SOUND_MASK_DIGITAL1
#define SOUND_MIXER_READ_I2S MIXER_READ(SOUND_MIXER_I2S)
#define SOUND_MIXER_WRITE_I2S MIXER_WRITE(SOUND_MIXER_I2S)
/* --------------------------------------------------------------------- */
/* --------------------------------------------------------------------- */
struct
it8172_state
{
struct
it8172_state
{
/* list of it8172 devices */
/* list of it8172 devices */
struct
list_head
devs
;
struct
list_head
devs
;
/* the corresponding pci_dev structure */
struct
pci_dev
*
dev
;
/* soundcore stuff
*/
/* the corresponding pci_dev structure
*/
int
dev_audio
;
struct
pci_dev
*
dev
;
/* hardware resources */
/* soundcore stuff */
unsigned
long
io
;
int
dev_audio
;
unsigned
int
irq
;
/* PCI ID's */
/* hardware resources */
u16
vendor
;
unsigned
long
io
;
u16
device
;
unsigned
int
irq
;
u8
rev
;
/* the chip revision */
/* options */
/* PCI ID's */
int
spdif_volume
;
/* S/PDIF output is enabled if != -1 */
u16
vendor
;
u16
device
;
u8
rev
;
/* the chip revision */
/* options */
int
spdif_volume
;
/* S/PDIF output is enabled if != -1 */
int
i2s_volume
;
/* current I2S out volume, in OSS format */
int
i2s_recording
;
/* 1 = recording from I2S, 0 = not */
#ifdef IT8172_DEBUG
#ifdef IT8172_DEBUG
/* debug /proc entry */
/* debug /proc entry */
struct
proc_dir_entry
*
ps
;
struct
proc_dir_entry
*
ps
;
struct
proc_dir_entry
*
ac97_ps
;
struct
proc_dir_entry
*
ac97_ps
;
#endif
/* IT8172_DEBUG */
#endif
/* IT8172_DEBUG */
struct
ac97_codec
codec
;
struct
ac97_codec
*
codec
;
unsigned
short
pcc
,
capcc
;
unsigned
short
pcc
,
capcc
;
unsigned
dacrate
,
adcrate
;
unsigned
dacrate
,
adcrate
;
spinlock_t
lock
;
spinlock_t
lock
;
struct
semaphore
open_sem
;
struct
semaphore
open_sem
;
mode_t
open_mode
;
mode_t
open_mode
;
wait_queue_head_t
open_wait
;
wait_queue_head_t
open_wait
;
struct
dmabuf
{
struct
dmabuf
{
void
*
rawbuf
;
void
*
rawbuf
;
dma_addr_t
dmaaddr
;
dma_addr_t
dmaaddr
;
unsigned
buforder
;
unsigned
buforder
;
unsigned
numfrag
;
unsigned
numfrag
;
unsigned
fragshift
;
unsigned
fragshift
;
void
*
nextIn
;
void
*
nextIn
;
void
*
nextOut
;
void
*
nextOut
;
int
count
;
int
count
;
int
curBufPtr
;
int
curBufPtr
;
unsigned
total_bytes
;
unsigned
total_bytes
;
unsigned
error
;
/* over/underrun */
unsigned
error
;
/* over/underrun */
wait_queue_head_t
wait
;
wait_queue_head_t
wait
;
/* redundant, but makes calculations easier */
/* redundant, but makes calculations easier */
unsigned
fragsize
;
unsigned
fragsize
;
unsigned
dmasize
;
unsigned
dmasize
;
unsigned
fragsamples
;
unsigned
fragsamples
;
/* OSS stuff */
/* OSS stuff */
unsigned
mapped
:
1
;
unsigned
mapped
:
1
;
unsigned
ready
:
1
;
unsigned
ready
:
1
;
unsigned
stopped
:
1
;
unsigned
stopped
:
1
;
unsigned
ossfragshift
;
unsigned
ossfragshift
;
int
ossmaxfrags
;
int
ossmaxfrags
;
unsigned
subdivision
;
unsigned
subdivision
;
}
dma_dac
,
dma_adc
;
}
dma_dac
,
dma_adc
;
};
};
/* --------------------------------------------------------------------- */
/* --------------------------------------------------------------------- */
...
@@ -305,114 +329,114 @@ static LIST_HEAD(devs);
...
@@ -305,114 +329,114 @@ static LIST_HEAD(devs);
static
inline
unsigned
ld2
(
unsigned
int
x
)
static
inline
unsigned
ld2
(
unsigned
int
x
)
{
{
unsigned
r
=
0
;
unsigned
r
=
0
;
if
(
x
>=
0x10000
)
{
if
(
x
>=
0x10000
)
{
x
>>=
16
;
x
>>=
16
;
r
+=
16
;
r
+=
16
;
}
}
if
(
x
>=
0x100
)
{
if
(
x
>=
0x100
)
{
x
>>=
8
;
x
>>=
8
;
r
+=
8
;
r
+=
8
;
}
}
if
(
x
>=
0x10
)
{
if
(
x
>=
0x10
)
{
x
>>=
4
;
x
>>=
4
;
r
+=
4
;
r
+=
4
;
}
}
if
(
x
>=
4
)
{
if
(
x
>=
4
)
{
x
>>=
2
;
x
>>=
2
;
r
+=
2
;
r
+=
2
;
}
}
if
(
x
>=
2
)
if
(
x
>=
2
)
r
++
;
r
++
;
return
r
;
return
r
;
}
}
/* --------------------------------------------------------------------- */
/* --------------------------------------------------------------------- */
static
void
it8172_delay
(
int
msec
)
static
void
it8172_delay
(
int
msec
)
{
{
unsigned
long
tmo
;
unsigned
long
tmo
;
signed
long
tmo2
;
signed
long
tmo2
;
if
(
in_interrupt
())
if
(
in_interrupt
())
return
;
return
;
tmo
=
jiffies
+
(
msec
*
HZ
)
/
1000
;
tmo
=
jiffies
+
(
msec
*
HZ
)
/
1000
;
for
(;;)
{
for
(;;)
{
tmo2
=
tmo
-
jiffies
;
tmo2
=
tmo
-
jiffies
;
if
(
tmo2
<=
0
)
if
(
tmo2
<=
0
)
break
;
break
;
schedule_timeout
(
tmo2
);
schedule_timeout
(
tmo2
);
}
}
}
}
static
unsigned
short
static
unsigned
short
get_compat_rate
(
unsigned
*
rate
)
get_compat_rate
(
unsigned
*
rate
)
{
{
unsigned
rate_out
=
*
rate
;
unsigned
rate_out
=
*
rate
;
unsigned
short
sr
;
unsigned
short
sr
;
if
(
rate_out
>=
46050
)
{
if
(
rate_out
>=
46050
)
{
sr
=
CC_SR_48000
;
rate_out
=
48000
;
sr
=
CC_SR_48000
;
rate_out
=
48000
;
}
else
if
(
rate_out
>=
41250
)
{
}
else
if
(
rate_out
>=
41250
)
{
sr
=
CC_SR_44100
;
rate_out
=
44100
;
sr
=
CC_SR_44100
;
rate_out
=
44100
;
}
else
if
(
rate_out
>=
35200
)
{
}
else
if
(
rate_out
>=
35200
)
{
sr
=
CC_SR_38400
;
rate_out
=
38400
;
sr
=
CC_SR_38400
;
rate_out
=
38400
;
}
else
if
(
rate_out
>=
27025
)
{
}
else
if
(
rate_out
>=
27025
)
{
sr
=
CC_SR_32000
;
rate_out
=
32000
;
sr
=
CC_SR_32000
;
rate_out
=
32000
;
}
else
if
(
rate_out
>=
20625
)
{
}
else
if
(
rate_out
>=
20625
)
{
sr
=
CC_SR_22050
;
rate_out
=
22050
;
sr
=
CC_SR_22050
;
rate_out
=
22050
;
}
else
if
(
rate_out
>=
17600
)
{
}
else
if
(
rate_out
>=
17600
)
{
sr
=
CC_SR_19200
;
rate_out
=
19200
;
sr
=
CC_SR_19200
;
rate_out
=
19200
;
}
else
if
(
rate_out
>=
13513
)
{
}
else
if
(
rate_out
>=
13513
)
{
sr
=
CC_SR_16000
;
rate_out
=
16000
;
sr
=
CC_SR_16000
;
rate_out
=
16000
;
}
else
if
(
rate_out
>=
10313
)
{
}
else
if
(
rate_out
>=
10313
)
{
sr
=
CC_SR_11025
;
rate_out
=
11025
;
sr
=
CC_SR_11025
;
rate_out
=
11025
;
}
else
if
(
rate_out
>=
8800
)
{
}
else
if
(
rate_out
>=
8800
)
{
sr
=
CC_SR_9600
;
rate_out
=
9600
;
sr
=
CC_SR_9600
;
rate_out
=
9600
;
}
else
if
(
rate_out
>=
6750
)
{
}
else
if
(
rate_out
>=
6750
)
{
sr
=
CC_SR_8000
;
rate_out
=
8000
;
sr
=
CC_SR_8000
;
rate_out
=
8000
;
}
else
{
}
else
{
sr
=
CC_SR_5500
;
rate_out
=
5500
;
sr
=
CC_SR_5500
;
rate_out
=
5500
;
}
}
*
rate
=
rate_out
;
*
rate
=
rate_out
;
return
sr
;
return
sr
;
}
}
static
void
set_adc_rate
(
struct
it8172_state
*
s
,
unsigned
rate
)
static
void
set_adc_rate
(
struct
it8172_state
*
s
,
unsigned
rate
)
{
{
unsigned
long
flags
;
unsigned
long
flags
;
unsigned
short
sr
;
unsigned
short
sr
;
sr
=
get_compat_rate
(
&
rate
);
sr
=
get_compat_rate
(
&
rate
);
spin_lock_irqsave
(
&
s
->
lock
,
flags
);
spin_lock_irqsave
(
&
s
->
lock
,
flags
);
s
->
capcc
&=
~
CC_SR_MASK
;
s
->
capcc
&=
~
CC_SR_MASK
;
s
->
capcc
|=
sr
;
s
->
capcc
|=
sr
;
outw
(
s
->
capcc
,
s
->
io
+
IT_AC_CAPCC
);
outw
(
s
->
capcc
,
s
->
io
+
IT_AC_CAPCC
);
spin_unlock_irqrestore
(
&
s
->
lock
,
flags
);
spin_unlock_irqrestore
(
&
s
->
lock
,
flags
);
s
->
adcrate
=
rate
;
s
->
adcrate
=
rate
;
}
}
static
void
set_dac_rate
(
struct
it8172_state
*
s
,
unsigned
rate
)
static
void
set_dac_rate
(
struct
it8172_state
*
s
,
unsigned
rate
)
{
{
unsigned
long
flags
;
unsigned
long
flags
;
unsigned
short
sr
;
unsigned
short
sr
;
sr
=
get_compat_rate
(
&
rate
);
sr
=
get_compat_rate
(
&
rate
);
spin_lock_irqsave
(
&
s
->
lock
,
flags
);
spin_lock_irqsave
(
&
s
->
lock
,
flags
);
s
->
pcc
&=
~
CC_SR_MASK
;
s
->
pcc
&=
~
CC_SR_MASK
;
s
->
pcc
|=
sr
;
s
->
pcc
|=
sr
;
outw
(
s
->
pcc
,
s
->
io
+
IT_AC_PCC
);
outw
(
s
->
pcc
,
s
->
io
+
IT_AC_PCC
);
spin_unlock_irqrestore
(
&
s
->
lock
,
flags
);
spin_unlock_irqrestore
(
&
s
->
lock
,
flags
);
s
->
dacrate
=
rate
;
s
->
dacrate
=
rate
;
}
}
...
@@ -420,89 +444,88 @@ static void set_dac_rate(struct it8172_state *s, unsigned rate)
...
@@ -420,89 +444,88 @@ static void set_dac_rate(struct it8172_state *s, unsigned rate)
static
u16
rdcodec
(
struct
ac97_codec
*
codec
,
u8
addr
)
static
u16
rdcodec
(
struct
ac97_codec
*
codec
,
u8
addr
)
{
{
struct
it8172_state
*
s
=
(
struct
it8172_state
*
)
codec
->
private_data
;
struct
it8172_state
*
s
=
(
struct
it8172_state
*
)
codec
->
private_data
;
unsigned
long
flags
;
unsigned
long
flags
;
unsigned
short
circp
,
data
;
unsigned
short
circp
,
data
;
int
i
;
int
i
;
spin_lock_irqsave
(
&
s
->
lock
,
flags
);
spin_lock_irqsave
(
&
s
->
lock
,
flags
);
for
(
i
=
0
;
i
<
POLL_COUNT
;
i
++
)
for
(
i
=
0
;
i
<
POLL_COUNT
;
i
++
)
if
(
!
(
inw
(
s
->
io
+
IT_AC_CIRCP
)
&
CIRCP_CPS
))
if
(
!
(
inw
(
s
->
io
+
IT_AC_CIRCP
)
&
CIRCP_CPS
))
break
;
break
;
if
(
i
==
POLL_COUNT
)
if
(
i
==
POLL_COUNT
)
printk
(
KERN_INFO
PFX
"rdcodec: codec ready poll expired!
\n
"
);
err
(
"rdcodec: codec ready poll expired!
"
);
circp
=
addr
&
CIRCP_CIA_MASK
;
circp
=
addr
&
CIRCP_CIA_MASK
;
circp
|=
(
codec
->
id
<<
CIRCP_CID_BIT
);
circp
|=
(
codec
->
id
<<
CIRCP_CID_BIT
);
circp
|=
CIRCP_RWC
;
// read command
circp
|=
CIRCP_RWC
;
// read command
outw
(
circp
,
s
->
io
+
IT_AC_CIRCP
);
outw
(
circp
,
s
->
io
+
IT_AC_CIRCP
);
/* now wait for the data */
/* now wait for the data */
for
(
i
=
0
;
i
<
POLL_COUNT
;
i
++
)
for
(
i
=
0
;
i
<
POLL_COUNT
;
i
++
)
if
(
inw
(
s
->
io
+
IT_AC_CIRCP
)
&
CIRCP_DPVF
)
if
(
inw
(
s
->
io
+
IT_AC_CIRCP
)
&
CIRCP_DPVF
)
break
;
break
;
if
(
i
==
POLL_COUNT
)
if
(
i
==
POLL_COUNT
)
printk
(
KERN_INFO
PFX
"rdcodec: read poll expired!
\n
"
);
err
(
"rdcodec: read poll expired!
"
);
data
=
inw
(
s
->
io
+
IT_AC_CIRDP
);
data
=
inw
(
s
->
io
+
IT_AC_CIRDP
);
spin_unlock_irqrestore
(
&
s
->
lock
,
flags
);
spin_unlock_irqrestore
(
&
s
->
lock
,
flags
);
return
data
;
return
data
;
}
}
static
void
wrcodec
(
struct
ac97_codec
*
codec
,
u8
addr
,
u16
data
)
static
void
wrcodec
(
struct
ac97_codec
*
codec
,
u8
addr
,
u16
data
)
{
{
struct
it8172_state
*
s
=
(
struct
it8172_state
*
)
codec
->
private_data
;
struct
it8172_state
*
s
=
(
struct
it8172_state
*
)
codec
->
private_data
;
unsigned
long
flags
;
unsigned
long
flags
;
unsigned
short
circp
;
unsigned
short
circp
;
int
i
;
int
i
;
spin_lock_irqsave
(
&
s
->
lock
,
flags
);
spin_lock_irqsave
(
&
s
->
lock
,
flags
);
for
(
i
=
0
;
i
<
POLL_COUNT
;
i
++
)
for
(
i
=
0
;
i
<
POLL_COUNT
;
i
++
)
if
(
!
(
inw
(
s
->
io
+
IT_AC_CIRCP
)
&
CIRCP_CPS
))
if
(
!
(
inw
(
s
->
io
+
IT_AC_CIRCP
)
&
CIRCP_CPS
))
break
;
break
;
if
(
i
==
POLL_COUNT
)
if
(
i
==
POLL_COUNT
)
printk
(
KERN_INFO
PFX
"wrcodec: codec ready poll expired!
\n
"
);
err
(
"wrcodec: codec ready poll expired!
"
);
circp
=
addr
&
CIRCP_CIA_MASK
;
circp
=
addr
&
CIRCP_CIA_MASK
;
circp
|=
(
codec
->
id
<<
CIRCP_CID_BIT
);
circp
|=
(
codec
->
id
<<
CIRCP_CID_BIT
);
circp
&=
~
CIRCP_RWC
;
// write command
circp
&=
~
CIRCP_RWC
;
// write command
outw
(
data
,
s
->
io
+
IT_AC_CIRDP
);
// send data first
outw
(
data
,
s
->
io
+
IT_AC_CIRDP
);
// send data first
outw
(
circp
,
s
->
io
+
IT_AC_CIRCP
);
outw
(
circp
,
s
->
io
+
IT_AC_CIRCP
);
spin_unlock_irqrestore
(
&
s
->
lock
,
flags
);
spin_unlock_irqrestore
(
&
s
->
lock
,
flags
);
}
}
static
void
waitcodec
(
struct
ac97_codec
*
codec
)
static
void
waitcodec
(
struct
ac97_codec
*
codec
)
{
{
unsigned
short
temp
;
unsigned
short
temp
;
/* codec_wait is used to wait for a ready state after
/* codec_wait is used to wait for a ready state after
an AC97_RESET. */
an AC97_RESET. */
it8172_delay
(
10
);
it8172_delay
(
10
);
temp
=
rdcodec
(
codec
,
0x26
);
// If power down, power up
if
(
temp
&
0x3f00
)
{
// Power on
wrcodec
(
codec
,
0x26
,
0
);
it8172_delay
(
100
);
// Reread
temp
=
rdcodec
(
codec
,
0x26
);
temp
=
rdcodec
(
codec
,
0x26
);
}
// If power down, power up
if
(
temp
&
0x3f00
)
{
// Power on
wrcodec
(
codec
,
0x26
,
0
);
it8172_delay
(
100
);
// Reread
temp
=
rdcodec
(
codec
,
0x26
);
}
// Check if Codec REF,ANL,DAC,ADC ready***/
// Check if Codec REF,ANL,DAC,ADC ready***/
if
((
temp
&
0x3f0f
)
!=
0x000f
)
{
if
((
temp
&
0x3f0f
)
!=
0x000f
)
{
printk
(
KERN_INFO
PFX
"codec reg 26 status (0x%x) not ready!!
\n
"
,
err
(
"codec reg 26 status (0x%x) not ready!!"
,
temp
);
temp
);
return
;
return
;
}
}
}
}
...
@@ -510,120 +533,120 @@ static void waitcodec(struct ac97_codec *codec)
...
@@ -510,120 +533,120 @@ static void waitcodec(struct ac97_codec *codec)
static
inline
void
stop_adc
(
struct
it8172_state
*
s
)
static
inline
void
stop_adc
(
struct
it8172_state
*
s
)
{
{
struct
dmabuf
*
db
=
&
s
->
dma_adc
;
struct
dmabuf
*
db
=
&
s
->
dma_adc
;
unsigned
long
flags
;
unsigned
long
flags
;
unsigned
char
imc
;
unsigned
char
imc
;
if
(
db
->
stopped
)
if
(
db
->
stopped
)
return
;
return
;
spin_lock_irqsave
(
&
s
->
lock
,
flags
);
spin_lock_irqsave
(
&
s
->
lock
,
flags
);
s
->
capcc
&=
~
(
CC_CA
|
CC_CP
|
CC_CB2L
|
CC_CB1L
);
s
->
capcc
&=
~
(
CC_CA
|
CC_CP
|
CC_CB2L
|
CC_CB1L
);
s
->
capcc
|=
CC_CSP
;
s
->
capcc
|=
CC_CSP
;
outw
(
s
->
capcc
,
s
->
io
+
IT_AC_CAPCC
);
outw
(
s
->
capcc
,
s
->
io
+
IT_AC_CAPCC
);
// disable capture interrupt
// disable capture interrupt
imc
=
inb
(
s
->
io
+
IT_AC_IMC
);
imc
=
inb
(
s
->
io
+
IT_AC_IMC
);
outb
(
imc
|
IMC_CCIM
,
s
->
io
+
IT_AC_IMC
);
outb
(
imc
|
IMC_CCIM
,
s
->
io
+
IT_AC_IMC
);
db
->
stopped
=
1
;
db
->
stopped
=
1
;
spin_unlock_irqrestore
(
&
s
->
lock
,
flags
);
spin_unlock_irqrestore
(
&
s
->
lock
,
flags
);
}
}
static
inline
void
stop_dac
(
struct
it8172_state
*
s
)
static
inline
void
stop_dac
(
struct
it8172_state
*
s
)
{
{
struct
dmabuf
*
db
=
&
s
->
dma_dac
;
struct
dmabuf
*
db
=
&
s
->
dma_dac
;
unsigned
long
flags
;
unsigned
long
flags
;
unsigned
char
imc
;
unsigned
char
imc
;
if
(
db
->
stopped
)
if
(
db
->
stopped
)
return
;
return
;
spin_lock_irqsave
(
&
s
->
lock
,
flags
);
spin_lock_irqsave
(
&
s
->
lock
,
flags
);
s
->
pcc
&=
~
(
CC_CA
|
CC_CP
|
CC_CB2L
|
CC_CB1L
);
s
->
pcc
&=
~
(
CC_CA
|
CC_CP
|
CC_CB2L
|
CC_CB1L
);
s
->
pcc
|=
CC_CSP
;
s
->
pcc
|=
CC_CSP
;
outw
(
s
->
pcc
,
s
->
io
+
IT_AC_PCC
);
outw
(
s
->
pcc
,
s
->
io
+
IT_AC_PCC
);
// disable playback interrupt
// disable playback interrupt
imc
=
inb
(
s
->
io
+
IT_AC_IMC
);
imc
=
inb
(
s
->
io
+
IT_AC_IMC
);
outb
(
imc
|
IMC_PCIM
,
s
->
io
+
IT_AC_IMC
);
outb
(
imc
|
IMC_PCIM
,
s
->
io
+
IT_AC_IMC
);
db
->
stopped
=
1
;
db
->
stopped
=
1
;
spin_unlock_irqrestore
(
&
s
->
lock
,
flags
);
spin_unlock_irqrestore
(
&
s
->
lock
,
flags
);
}
}
static
void
start_dac
(
struct
it8172_state
*
s
)
static
void
start_dac
(
struct
it8172_state
*
s
)
{
{
struct
dmabuf
*
db
=
&
s
->
dma_dac
;
struct
dmabuf
*
db
=
&
s
->
dma_dac
;
unsigned
long
flags
;
unsigned
long
flags
;
unsigned
char
imc
;
unsigned
char
imc
;
unsigned
long
buf1
,
buf2
;
unsigned
long
buf1
,
buf2
;
if
(
!
db
->
stopped
)
if
(
!
db
->
stopped
)
return
;
return
;
spin_lock_irqsave
(
&
s
->
lock
,
flags
);
spin_lock_irqsave
(
&
s
->
lock
,
flags
);
// reset Buffer 1 and 2 pointers to nextOut and nextOut+fragsize
// reset Buffer 1 and 2 pointers to nextOut and nextOut+fragsize
buf1
=
virt_to_bus
(
db
->
nextOut
);
buf1
=
virt_to_bus
(
db
->
nextOut
);
buf2
=
buf1
+
db
->
fragsize
;
buf2
=
buf1
+
db
->
fragsize
;
if
(
buf2
>=
db
->
dmaaddr
+
db
->
dmasize
)
if
(
buf2
>=
db
->
dmaaddr
+
db
->
dmasize
)
buf2
-=
db
->
dmasize
;
buf2
-=
db
->
dmasize
;
outl
(
buf1
,
s
->
io
+
IT_AC_PCB1STA
);
outl
(
buf1
,
s
->
io
+
IT_AC_PCB1STA
);
outl
(
buf2
,
s
->
io
+
IT_AC_PCB2STA
);
outl
(
buf2
,
s
->
io
+
IT_AC_PCB2STA
);
db
->
curBufPtr
=
IT_AC_PCB1STA
;
db
->
curBufPtr
=
IT_AC_PCB1STA
;
// enable playback interrupt
// enable playback interrupt
imc
=
inb
(
s
->
io
+
IT_AC_IMC
);
imc
=
inb
(
s
->
io
+
IT_AC_IMC
);
outb
(
imc
&
~
IMC_PCIM
,
s
->
io
+
IT_AC_IMC
);
outb
(
imc
&
~
IMC_PCIM
,
s
->
io
+
IT_AC_IMC
);
s
->
pcc
&=
~
(
CC_CSP
|
CC_CP
|
CC_CB2L
|
CC_CB1L
);
s
->
pcc
&=
~
(
CC_CSP
|
CC_CP
|
CC_CB2L
|
CC_CB1L
);
s
->
pcc
|=
CC_CA
;
s
->
pcc
|=
CC_CA
;
outw
(
s
->
pcc
,
s
->
io
+
IT_AC_PCC
);
outw
(
s
->
pcc
,
s
->
io
+
IT_AC_PCC
);
db
->
stopped
=
0
;
db
->
stopped
=
0
;
spin_unlock_irqrestore
(
&
s
->
lock
,
flags
);
spin_unlock_irqrestore
(
&
s
->
lock
,
flags
);
}
}
static
void
start_adc
(
struct
it8172_state
*
s
)
static
void
start_adc
(
struct
it8172_state
*
s
)
{
{
struct
dmabuf
*
db
=
&
s
->
dma_adc
;
struct
dmabuf
*
db
=
&
s
->
dma_adc
;
unsigned
long
flags
;
unsigned
long
flags
;
unsigned
char
imc
;
unsigned
char
imc
;
unsigned
long
buf1
,
buf2
;
unsigned
long
buf1
,
buf2
;
if
(
!
db
->
stopped
)
if
(
!
db
->
stopped
)
return
;
return
;
spin_lock_irqsave
(
&
s
->
lock
,
flags
);
spin_lock_irqsave
(
&
s
->
lock
,
flags
);
// reset Buffer 1 and 2 pointers to nextIn and nextIn+fragsize
// reset Buffer 1 and 2 pointers to nextIn and nextIn+fragsize
buf1
=
virt_to_bus
(
db
->
nextIn
);
buf1
=
virt_to_bus
(
db
->
nextIn
);
buf2
=
buf1
+
db
->
fragsize
;
buf2
=
buf1
+
db
->
fragsize
;
if
(
buf2
>=
db
->
dmaaddr
+
db
->
dmasize
)
if
(
buf2
>=
db
->
dmaaddr
+
db
->
dmasize
)
buf2
-=
db
->
dmasize
;
buf2
-=
db
->
dmasize
;
outl
(
buf1
,
s
->
io
+
IT_AC_CAPB1STA
);
outl
(
buf1
,
s
->
io
+
IT_AC_CAPB1STA
);
outl
(
buf2
,
s
->
io
+
IT_AC_CAPB2STA
);
outl
(
buf2
,
s
->
io
+
IT_AC_CAPB2STA
);
db
->
curBufPtr
=
IT_AC_CAPB1STA
;
db
->
curBufPtr
=
IT_AC_CAPB1STA
;
// enable capture interrupt
// enable capture interrupt
imc
=
inb
(
s
->
io
+
IT_AC_IMC
);
imc
=
inb
(
s
->
io
+
IT_AC_IMC
);
outb
(
imc
&
~
IMC_CCIM
,
s
->
io
+
IT_AC_IMC
);
outb
(
imc
&
~
IMC_CCIM
,
s
->
io
+
IT_AC_IMC
);
s
->
capcc
&=
~
(
CC_CSP
|
CC_CP
|
CC_CB2L
|
CC_CB1L
);
s
->
capcc
&=
~
(
CC_CSP
|
CC_CP
|
CC_CB2L
|
CC_CB1L
);
s
->
capcc
|=
CC_CA
;
s
->
capcc
|=
CC_CA
;
outw
(
s
->
capcc
,
s
->
io
+
IT_AC_CAPCC
);
outw
(
s
->
capcc
,
s
->
io
+
IT_AC_CAPCC
);
db
->
stopped
=
0
;
db
->
stopped
=
0
;
spin_unlock_irqrestore
(
&
s
->
lock
,
flags
);
spin_unlock_irqrestore
(
&
s
->
lock
,
flags
);
}
}
/* --------------------------------------------------------------------- */
/* --------------------------------------------------------------------- */
...
@@ -633,94 +656,103 @@ static void start_adc(struct it8172_state *s)
...
@@ -633,94 +656,103 @@ static void start_adc(struct it8172_state *s)
static
inline
void
dealloc_dmabuf
(
struct
it8172_state
*
s
,
struct
dmabuf
*
db
)
static
inline
void
dealloc_dmabuf
(
struct
it8172_state
*
s
,
struct
dmabuf
*
db
)
{
{
struct
page
*
page
,
*
pend
;
struct
page
*
page
,
*
pend
;
if
(
db
->
rawbuf
)
{
if
(
db
->
rawbuf
)
{
/* undo marking the pages as reserved */
/* undo marking the pages as reserved */
pend
=
virt_to_page
(
db
->
rawbuf
+
(
PAGE_SIZE
<<
db
->
buforder
)
-
1
);
pend
=
virt_to_page
(
db
->
rawbuf
+
for
(
page
=
virt_to_page
(
db
->
rawbuf
);
page
<=
pend
;
page
++
)
(
PAGE_SIZE
<<
db
->
buforder
)
-
1
);
ClearPageReserved
(
page
);
for
(
page
=
virt_to_page
(
db
->
rawbuf
);
page
<=
pend
;
page
++
)
pci_free_consistent
(
s
->
dev
,
PAGE_SIZE
<<
db
->
buforder
,
mem_map_unreserve
(
page
);
db
->
rawbuf
,
db
->
dmaaddr
);
pci_free_consistent
(
s
->
dev
,
PAGE_SIZE
<<
db
->
buforder
,
}
db
->
rawbuf
,
db
->
dmaaddr
);
db
->
rawbuf
=
db
->
nextIn
=
db
->
nextOut
=
NULL
;
}
db
->
mapped
=
db
->
ready
=
0
;
db
->
rawbuf
=
db
->
nextIn
=
db
->
nextOut
=
NULL
;
db
->
mapped
=
db
->
ready
=
0
;
}
}
static
int
prog_dmabuf
(
struct
it8172_state
*
s
,
struct
dmabuf
*
db
,
static
int
prog_dmabuf
(
struct
it8172_state
*
s
,
struct
dmabuf
*
db
,
unsigned
rate
,
unsigned
fmt
,
unsigned
reg
)
unsigned
rate
,
unsigned
fmt
,
unsigned
reg
)
{
{
int
order
;
int
order
;
unsigned
bytepersec
;
unsigned
bytepersec
;
unsigned
bufs
;
unsigned
bufs
;
struct
page
*
page
,
*
pend
;
struct
page
*
page
,
*
pend
;
if
(
!
db
->
rawbuf
)
{
if
(
!
db
->
rawbuf
)
{
db
->
ready
=
db
->
mapped
=
0
;
db
->
ready
=
db
->
mapped
=
0
;
for
(
order
=
DMABUF_DEFAULTORDER
;
order
>=
DMABUF_MINORDER
;
order
--
)
for
(
order
=
DMABUF_DEFAULTORDER
;
if
((
db
->
rawbuf
=
pci_alloc_consistent
(
s
->
dev
,
order
>=
DMABUF_MINORDER
;
order
--
)
PAGE_SIZE
<<
order
,
if
((
db
->
rawbuf
=
&
db
->
dmaaddr
)))
pci_alloc_consistent
(
s
->
dev
,
break
;
PAGE_SIZE
<<
order
,
if
(
!
db
->
rawbuf
)
&
db
->
dmaaddr
)))
return
-
ENOMEM
;
break
;
db
->
buforder
=
order
;
if
(
!
db
->
rawbuf
)
/* now mark the pages as reserved;
return
-
ENOMEM
;
otherwise remap_page_range doesn't do what we want */
db
->
buforder
=
order
;
pend
=
virt_to_page
(
db
->
rawbuf
+
(
PAGE_SIZE
<<
db
->
buforder
)
-
1
);
/* now mark the pages as reserved;
for
(
page
=
virt_to_page
(
db
->
rawbuf
);
page
<=
pend
;
page
++
)
otherwise remap_page_range doesn't do what we want */
SetPageReserved
(
page
);
pend
=
virt_to_page
(
db
->
rawbuf
+
}
(
PAGE_SIZE
<<
db
->
buforder
)
-
1
);
for
(
page
=
virt_to_page
(
db
->
rawbuf
);
page
<=
pend
;
page
++
)
db
->
count
=
0
;
mem_map_reserve
(
page
);
db
->
nextIn
=
db
->
nextOut
=
db
->
rawbuf
;
}
db
->
count
=
0
;
db
->
nextIn
=
db
->
nextOut
=
db
->
rawbuf
;
bytepersec
=
rate
<<
sample_shift
[
fmt
];
bytepersec
=
rate
<<
sample_shift
[
fmt
];
bufs
=
PAGE_SIZE
<<
db
->
buforder
;
bufs
=
PAGE_SIZE
<<
db
->
buforder
;
if
(
db
->
ossfragshift
)
{
if
(
db
->
ossfragshift
)
{
if
((
1000
<<
db
->
ossfragshift
)
<
bytepersec
)
if
((
1000
<<
db
->
ossfragshift
)
<
bytepersec
)
db
->
fragshift
=
ld2
(
bytepersec
/
1000
);
db
->
fragshift
=
ld2
(
bytepersec
/
1000
);
else
else
db
->
fragshift
=
db
->
ossfragshift
;
db
->
fragshift
=
db
->
ossfragshift
;
}
else
{
}
else
{
db
->
fragshift
=
ld2
(
bytepersec
/
100
/
(
db
->
subdivision
?
db
->
fragshift
=
ld2
(
bytepersec
/
100
/
(
db
->
subdivision
?
db
->
subdivision
:
1
));
db
->
subdivision
:
1
));
if
(
db
->
fragshift
<
3
)
if
(
db
->
fragshift
<
3
)
db
->
fragshift
=
3
;
db
->
fragshift
=
3
;
}
}
db
->
numfrag
=
bufs
>>
db
->
fragshift
;
while
(
db
->
numfrag
<
4
&&
db
->
fragshift
>
3
)
{
db
->
fragshift
--
;
db
->
numfrag
=
bufs
>>
db
->
fragshift
;
db
->
numfrag
=
bufs
>>
db
->
fragshift
;
}
while
(
db
->
numfrag
<
4
&&
db
->
fragshift
>
3
)
{
db
->
fragsize
=
1
<<
db
->
fragshift
;
db
->
fragshift
--
;
if
(
db
->
ossmaxfrags
>=
4
&&
db
->
ossmaxfrags
<
db
->
numfrag
)
db
->
numfrag
=
bufs
>>
db
->
fragshift
;
db
->
numfrag
=
db
->
ossmaxfrags
;
}
db
->
fragsamples
=
db
->
fragsize
>>
sample_shift
[
fmt
];
db
->
fragsize
=
1
<<
db
->
fragshift
;
db
->
dmasize
=
db
->
numfrag
<<
db
->
fragshift
;
if
(
db
->
ossmaxfrags
>=
4
&&
db
->
ossmaxfrags
<
db
->
numfrag
)
memset
(
db
->
rawbuf
,
(
fmt
&
(
CC_DF
>>
CC_FMT_BIT
))
?
0
:
0x80
,
db
->
dmasize
);
db
->
numfrag
=
db
->
ossmaxfrags
;
db
->
fragsamples
=
db
->
fragsize
>>
sample_shift
[
fmt
];
db
->
dmasize
=
db
->
numfrag
<<
db
->
fragshift
;
memset
(
db
->
rawbuf
,
(
fmt
&
(
CC_DF
>>
CC_FMT_BIT
))
?
0
:
0x80
,
bufs
);
// set data length register
#ifdef IT8172_VERBOSE_DEBUG
outw
(
db
->
fragsize
,
s
->
io
+
reg
+
2
);
dbg
(
"rate=%d, fragsize=%d, numfrag=%d, dmasize=%d"
,
db
->
ready
=
1
;
rate
,
db
->
fragsize
,
db
->
numfrag
,
db
->
dmasize
);
#endif
// set data length register
outw
(
db
->
fragsize
,
s
->
io
+
reg
+
2
);
db
->
ready
=
1
;
return
0
;
return
0
;
}
}
static
inline
int
prog_dmabuf_adc
(
struct
it8172_state
*
s
)
static
inline
int
prog_dmabuf_adc
(
struct
it8172_state
*
s
)
{
{
stop_adc
(
s
);
stop_adc
(
s
);
return
prog_dmabuf
(
s
,
&
s
->
dma_adc
,
s
->
adcrate
,
return
prog_dmabuf
(
s
,
&
s
->
dma_adc
,
s
->
adcrate
,
(
s
->
capcc
&
CC_FMT_MASK
)
>>
CC_FMT_BIT
,
(
s
->
capcc
&
CC_FMT_MASK
)
>>
CC_FMT_BIT
,
IT_AC_CAPCC
);
IT_AC_CAPCC
);
}
}
static
inline
int
prog_dmabuf_dac
(
struct
it8172_state
*
s
)
static
inline
int
prog_dmabuf_dac
(
struct
it8172_state
*
s
)
{
{
stop_dac
(
s
);
stop_dac
(
s
);
return
prog_dmabuf
(
s
,
&
s
->
dma_dac
,
s
->
dacrate
,
return
prog_dmabuf
(
s
,
&
s
->
dma_dac
,
s
->
dacrate
,
(
s
->
pcc
&
CC_FMT_MASK
)
>>
CC_FMT_BIT
,
(
s
->
pcc
&
CC_FMT_MASK
)
>>
CC_FMT_BIT
,
IT_AC_PCC
);
IT_AC_PCC
);
}
}
...
@@ -728,918 +760,1127 @@ static inline int prog_dmabuf_dac(struct it8172_state *s)
...
@@ -728,918 +760,1127 @@ static inline int prog_dmabuf_dac(struct it8172_state *s)
static
irqreturn_t
it8172_interrupt
(
int
irq
,
void
*
dev_id
,
struct
pt_regs
*
regs
)
static
irqreturn_t
it8172_interrupt
(
int
irq
,
void
*
dev_id
,
struct
pt_regs
*
regs
)
{
{
struct
it8172_state
*
s
=
(
struct
it8172_state
*
)
dev_id
;
struct
it8172_state
*
s
=
(
struct
it8172_state
*
)
dev_id
;
struct
dmabuf
*
dac
=
&
s
->
dma_dac
;
struct
dmabuf
*
dac
=
&
s
->
dma_dac
;
struct
dmabuf
*
adc
=
&
s
->
dma_adc
;
struct
dmabuf
*
adc
=
&
s
->
dma_adc
;
unsigned
char
isc
,
vs
;
unsigned
char
isc
,
vs
;
unsigned
short
vol
,
mute
;
unsigned
short
vol
,
mute
;
unsigned
long
newptr
;
unsigned
long
newptr
;
spin_lock
(
&
s
->
lock
);
spin_lock
(
&
s
->
lock
);
isc
=
inb
(
s
->
io
+
IT_AC_ISC
);
isc
=
inb
(
s
->
io
+
IT_AC_ISC
);
/* fastpath out, to ease interrupt sharing */
/* fastpath out, to ease interrupt sharing */
if
(
!
(
isc
&
(
ISC_VCI
|
ISC_CCI
|
ISC_PCI
)))
{
if
(
!
(
isc
&
(
ISC_VCI
|
ISC_CCI
|
ISC_PCI
)))
{
spin_unlock
(
&
s
->
lock
);
spin_unlock
(
&
s
->
lock
);
return
IRQ_NONE
;
return
IRQ_NONE
;
}
}
/* clear audio interrupts first */
outb
(
isc
|
ISC_VCI
|
ISC_CCI
|
ISC_PCI
,
s
->
io
+
IT_AC_ISC
);
/* handle volume button events */
/* clear audio interrupts first */
if
(
isc
&
ISC_VCI
)
{
outb
(
isc
|
ISC_VCI
|
ISC_CCI
|
ISC_PCI
,
s
->
io
+
IT_AC_ISC
);
vs
=
inb
(
s
->
io
+
IT_AC_VS
);
outb
(
0
,
s
->
io
+
IT_AC_VS
);
vol
=
inw
(
s
->
io
+
IT_AC_PCMOV
);
mute
=
vol
&
PCMOV_PCMOM
;
vol
&=
PCMOV_PCMLCG_MASK
;
if
((
vs
&
VS_VUP
)
&&
vol
>
0
)
vol
--
;
if
((
vs
&
VS_VDP
)
&&
vol
<
0x1f
)
vol
++
;
vol
|=
(
vol
<<
PCMOV_PCMRCG_BIT
);
if
(
vs
&
VS_VMP
)
vol
|=
(
mute
^
PCMOV_PCMOM
);
outw
(
vol
,
s
->
io
+
IT_AC_PCMOV
);
}
/* update capture pointers */
/* handle volume button events (ignore if S/PDIF enabled) */
if
(
isc
&
ISC_CCI
)
{
if
((
isc
&
ISC_VCI
)
&&
s
->
spdif_volume
==
-
1
)
{
if
(
adc
->
count
>
adc
->
dmasize
-
adc
->
fragsize
)
{
vs
=
inb
(
s
->
io
+
IT_AC_VS
);
// Overrun. Stop ADC and log the error
outb
(
0
,
s
->
io
+
IT_AC_VS
);
stop_adc
(
s
);
vol
=
inw
(
s
->
io
+
IT_AC_PCMOV
);
adc
->
error
++
;
mute
=
vol
&
PCMOV_PCMOM
;
printk
(
KERN_INFO
PFX
"adc overrun
\n
"
);
vol
&=
PCMOV_PCMLCG_MASK
;
}
else
{
if
((
vs
&
VS_VUP
)
&&
vol
>
0
)
newptr
=
virt_to_bus
(
adc
->
nextIn
)
+
2
*
adc
->
fragsize
;
vol
--
;
if
(
newptr
>=
adc
->
dmaaddr
+
adc
->
dmasize
)
if
((
vs
&
VS_VDP
)
&&
vol
<
0x1f
)
newptr
-=
adc
->
dmasize
;
vol
++
;
vol
|=
(
vol
<<
PCMOV_PCMRCG_BIT
);
if
(
vs
&
VS_VMP
)
vol
|=
(
mute
^
PCMOV_PCMOM
);
outw
(
vol
,
s
->
io
+
IT_AC_PCMOV
);
}
/* update capture pointers */
if
(
isc
&
ISC_CCI
)
{
if
(
adc
->
count
>
adc
->
dmasize
-
adc
->
fragsize
)
{
// Overrun. Stop ADC and log the error
stop_adc
(
s
);
adc
->
error
++
;
dbg
(
"adc overrun"
);
}
else
{
newptr
=
virt_to_bus
(
adc
->
nextIn
)
+
2
*
adc
->
fragsize
;
if
(
newptr
>=
adc
->
dmaaddr
+
adc
->
dmasize
)
newptr
-=
adc
->
dmasize
;
outl
(
newptr
,
s
->
io
+
adc
->
curBufPtr
);
outl
(
newptr
,
s
->
io
+
adc
->
curBufPtr
);
adc
->
curBufPtr
=
(
adc
->
curBufPtr
==
IT_AC_CAPB1STA
)
?
adc
->
curBufPtr
=
(
adc
->
curBufPtr
==
IT_AC_CAPB1STA
)
?
IT_AC_CAPB2STA
:
IT_AC_CAPB1STA
;
IT_AC_CAPB2STA
:
IT_AC_CAPB1STA
;
adc
->
nextIn
+=
adc
->
fragsize
;
adc
->
nextIn
+=
adc
->
fragsize
;
if
(
adc
->
nextIn
>=
adc
->
rawbuf
+
adc
->
dmasize
)
if
(
adc
->
nextIn
>=
adc
->
rawbuf
+
adc
->
dmasize
)
adc
->
nextIn
-=
adc
->
dmasize
;
adc
->
nextIn
-=
adc
->
dmasize
;
adc
->
count
+=
adc
->
fragsize
;
adc
->
count
+=
adc
->
fragsize
;
adc
->
total_bytes
+=
adc
->
fragsize
;
adc
->
total_bytes
+=
adc
->
fragsize
;
/* wake up anybody listening */
/* wake up anybody listening */
if
(
waitqueue_active
(
&
adc
->
wait
))
if
(
waitqueue_active
(
&
adc
->
wait
))
wake_up_interruptible
(
&
adc
->
wait
);
wake_up_interruptible
(
&
adc
->
wait
);
}
}
}
}
/* update playback pointers */
/* update playback pointers */
if
(
isc
&
ISC_PCI
)
{
if
(
isc
&
ISC_PCI
)
{
newptr
=
virt_to_bus
(
dac
->
nextOut
)
+
2
*
dac
->
fragsize
;
newptr
=
virt_to_bus
(
dac
->
nextOut
)
+
2
*
dac
->
fragsize
;
if
(
newptr
>=
dac
->
dmaaddr
+
dac
->
dmasize
)
if
(
newptr
>=
dac
->
dmaaddr
+
dac
->
dmasize
)
newptr
-=
dac
->
dmasize
;
newptr
-=
dac
->
dmasize
;
outl
(
newptr
,
s
->
io
+
dac
->
curBufPtr
);
outl
(
newptr
,
s
->
io
+
dac
->
curBufPtr
);
dac
->
curBufPtr
=
(
dac
->
curBufPtr
==
IT_AC_PCB1STA
)
?
dac
->
curBufPtr
=
(
dac
->
curBufPtr
==
IT_AC_PCB1STA
)
?
IT_AC_PCB2STA
:
IT_AC_PCB1STA
;
IT_AC_PCB2STA
:
IT_AC_PCB1STA
;
dac
->
nextOut
+=
dac
->
fragsize
;
dac
->
nextOut
+=
dac
->
fragsize
;
if
(
dac
->
nextOut
>=
dac
->
rawbuf
+
dac
->
dmasize
)
if
(
dac
->
nextOut
>=
dac
->
rawbuf
+
dac
->
dmasize
)
dac
->
nextOut
-=
dac
->
dmasize
;
dac
->
nextOut
-=
dac
->
dmasize
;
dac
->
count
-=
dac
->
fragsize
;
dac
->
count
-=
dac
->
fragsize
;
dac
->
total_bytes
+=
dac
->
fragsize
;
dac
->
total_bytes
+=
dac
->
fragsize
;
/* wake up anybody listening */
/* wake up anybody listening */
if
(
waitqueue_active
(
&
dac
->
wait
))
if
(
waitqueue_active
(
&
dac
->
wait
))
wake_up_interruptible
(
&
dac
->
wait
);
wake_up_interruptible
(
&
dac
->
wait
);
if
(
dac
->
count
<=
0
)
if
(
dac
->
count
<=
0
)
stop_dac
(
s
);
stop_dac
(
s
);
}
}
spin_unlock
(
&
s
->
lock
);
spin_unlock
(
&
s
->
lock
);
return
IRQ_HANDLED
;
return
IRQ_HANDLED
;
}
}
/* --------------------------------------------------------------------- */
/* --------------------------------------------------------------------- */
static
loff_t
it8172_llseek
(
struct
file
*
file
,
loff_t
offset
,
int
origin
)
{
return
-
ESPIPE
;
}
static
int
it8172_open_mixdev
(
struct
inode
*
inode
,
struct
file
*
file
)
static
int
it8172_open_mixdev
(
struct
inode
*
inode
,
struct
file
*
file
)
{
{
int
minor
=
minor
(
inode
->
i_rdev
);
int
minor
=
MINOR
(
inode
->
i_rdev
);
struct
list_head
*
list
;
struct
list_head
*
list
;
struct
it8172_state
*
s
;
struct
it8172_state
*
s
;
for
(
list
=
devs
.
next
;
;
list
=
list
->
next
)
{
for
(
list
=
devs
.
next
;
;
list
=
list
->
next
)
{
if
(
list
==
&
devs
)
if
(
list
==
&
devs
)
return
-
ENODEV
;
return
-
ENODEV
;
s
=
list_entry
(
list
,
struct
it8172_state
,
devs
);
s
=
list_entry
(
list
,
struct
it8172_state
,
devs
);
if
(
s
->
codec
.
dev_mixer
==
minor
)
if
(
s
->
codec
->
dev_mixer
==
minor
)
break
;
break
;
}
}
file
->
private_data
=
s
;
file
->
private_data
=
s
;
return
0
;
return
0
;
}
}
static
int
it8172_release_mixdev
(
struct
inode
*
inode
,
struct
file
*
file
)
static
int
it8172_release_mixdev
(
struct
inode
*
inode
,
struct
file
*
file
)
{
{
return
0
;
return
0
;
}
static
u16
cvt_ossvol
(
unsigned
int
gain
)
{
u16
ret
;
if
(
gain
==
0
)
return
0
;
if
(
gain
>
100
)
gain
=
100
;
ret
=
(
100
-
gain
+
32
)
/
4
;
ret
=
ret
>
31
?
31
:
ret
;
return
ret
;
}
}
static
int
mixdev_ioctl
(
struct
ac97_codec
*
codec
,
unsigned
int
cmd
,
static
int
mixdev_ioctl
(
struct
ac97_codec
*
codec
,
unsigned
int
cmd
,
unsigned
long
arg
)
unsigned
long
arg
)
{
{
return
codec
->
mixer_ioctl
(
codec
,
cmd
,
arg
);
struct
it8172_state
*
s
=
(
struct
it8172_state
*
)
codec
->
private_data
;
unsigned
int
left
,
right
;
unsigned
long
flags
;
int
val
;
u16
vol
;
/*
* When we are in S/PDIF mode, we want to disable any analog output so
* we filter the master/PCM channel volume ioctls.
*
* Also filter I2S channel, which AC'97 knows nothing about.
*/
switch
(
cmd
)
{
case
SOUND_MIXER_WRITE_VOLUME
:
// if not in S/PDIF mode, pass to AC'97
if
(
s
->
spdif_volume
==
-
1
)
break
;
return
0
;
case
SOUND_MIXER_WRITE_PCM
:
// if not in S/PDIF mode, pass to AC'97
if
(
s
->
spdif_volume
==
-
1
)
break
;
if
(
get_user
(
val
,
(
int
*
)
arg
))
return
-
EFAULT
;
right
=
((
val
>>
8
)
&
0xff
);
left
=
(
val
&
0xff
);
if
(
right
>
100
)
right
=
100
;
if
(
left
>
100
)
left
=
100
;
s
->
spdif_volume
=
(
right
<<
8
)
|
left
;
vol
=
cvt_ossvol
(
left
);
vol
|=
(
cvt_ossvol
(
right
)
<<
PCMOV_PCMRCG_BIT
);
if
(
vol
==
0
)
vol
=
PCMOV_PCMOM
;
// mute
spin_lock_irqsave
(
&
s
->
lock
,
flags
);
outw
(
vol
,
s
->
io
+
IT_AC_PCMOV
);
spin_unlock_irqrestore
(
&
s
->
lock
,
flags
);
return
put_user
(
s
->
spdif_volume
,
(
int
*
)
arg
);
case
SOUND_MIXER_READ_PCM
:
// if not in S/PDIF mode, pass to AC'97
if
(
s
->
spdif_volume
==
-
1
)
break
;
return
put_user
(
s
->
spdif_volume
,
(
int
*
)
arg
);
case
SOUND_MIXER_WRITE_I2S
:
if
(
get_user
(
val
,
(
int
*
)
arg
))
return
-
EFAULT
;
right
=
((
val
>>
8
)
&
0xff
);
left
=
(
val
&
0xff
);
if
(
right
>
100
)
right
=
100
;
if
(
left
>
100
)
left
=
100
;
s
->
i2s_volume
=
(
right
<<
8
)
|
left
;
vol
=
cvt_ossvol
(
left
);
vol
|=
(
cvt_ossvol
(
right
)
<<
I2SV_I2SRCG_BIT
);
if
(
vol
==
0
)
vol
=
I2SV_I2SOM
;
// mute
outw
(
vol
,
s
->
io
+
IT_AC_I2SV
);
return
put_user
(
s
->
i2s_volume
,
(
int
*
)
arg
);
case
SOUND_MIXER_READ_I2S
:
return
put_user
(
s
->
i2s_volume
,
(
int
*
)
arg
);
case
SOUND_MIXER_WRITE_RECSRC
:
if
(
get_user
(
val
,
(
int
*
)
arg
))
return
-
EFAULT
;
if
(
val
&
SOUND_MASK_I2S
)
{
s
->
i2s_recording
=
1
;
outb
(
DRSS_I2S
,
s
->
io
+
IT_AC_DRSS
);
return
0
;
}
else
{
s
->
i2s_recording
=
0
;
outb
(
DRSS_AC97_PRIM
,
s
->
io
+
IT_AC_DRSS
);
// now let AC'97 select record source
break
;
}
case
SOUND_MIXER_READ_RECSRC
:
if
(
s
->
i2s_recording
)
return
put_user
(
SOUND_MASK_I2S
,
(
int
*
)
arg
);
else
// let AC'97 report recording source
break
;
}
return
codec
->
mixer_ioctl
(
codec
,
cmd
,
arg
);
}
}
static
int
it8172_ioctl_mixdev
(
struct
inode
*
inode
,
struct
file
*
file
,
static
int
it8172_ioctl_mixdev
(
struct
inode
*
inode
,
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
)
unsigned
int
cmd
,
unsigned
long
arg
)
{
{
struct
it8172_state
*
s
=
(
struct
it8172_state
*
)
file
->
private_data
;
struct
it8172_state
*
s
=
(
struct
it8172_state
*
)
file
->
private_data
;
struct
ac97_codec
*
codec
=
&
s
->
codec
;
struct
ac97_codec
*
codec
=
s
->
codec
;
return
mixdev_ioctl
(
codec
,
cmd
,
arg
);
return
mixdev_ioctl
(
codec
,
cmd
,
arg
);
}
}
static
/*const*/
struct
file_operations
it8172_mixer_fops
=
{
static
/*const*/
struct
file_operations
it8172_mixer_fops
=
{
.
owner
=
THIS_MODULE
,
owner:
THIS_MODULE
,
.
llseek
=
no
_llseek
,
llseek:
it8172
_llseek
,
.
ioctl
=
it8172_ioctl_mixdev
,
ioctl:
it8172_ioctl_mixdev
,
.
open
=
it8172_open_mixdev
,
open:
it8172_open_mixdev
,
.
release
=
it8172_release_mixdev
,
release:
it8172_release_mixdev
,
};
};
/* --------------------------------------------------------------------- */
/* --------------------------------------------------------------------- */
static
int
drain_dac
(
struct
it8172_state
*
s
,
int
nonblock
)
static
int
drain_dac
(
struct
it8172_state
*
s
,
int
nonblock
)
{
{
unsigned
long
flags
;
unsigned
long
flags
;
int
count
,
tmo
;
int
count
,
tmo
;
if
(
s
->
dma_dac
.
mapped
||
!
s
->
dma_dac
.
ready
)
if
(
s
->
dma_dac
.
mapped
||
!
s
->
dma_dac
.
ready
||
s
->
dma_dac
.
stopped
)
return
0
;
return
0
;
for
(;;)
{
for
(;;)
{
spin_lock_irqsave
(
&
s
->
lock
,
flags
);
spin_lock_irqsave
(
&
s
->
lock
,
flags
);
count
=
s
->
dma_dac
.
count
;
count
=
s
->
dma_dac
.
count
;
spin_unlock_irqrestore
(
&
s
->
lock
,
flags
);
spin_unlock_irqrestore
(
&
s
->
lock
,
flags
);
if
(
count
<=
0
)
if
(
count
<=
0
)
break
;
break
;
if
(
signal_pending
(
current
))
break
;
//if (nonblock)
//return -EBUSY;
tmo
=
1000
*
count
/
s
->
dacrate
;
tmo
>>=
sample_shift
[(
s
->
pcc
&
CC_FMT_MASK
)
>>
CC_FMT_BIT
];
it8172_delay
(
tmo
);
}
if
(
signal_pending
(
current
))
if
(
signal_pending
(
current
))
break
;
return
-
ERESTARTSYS
;
if
(
nonblock
)
return
0
;
return
-
EBUSY
;
tmo
=
1000
*
count
/
s
->
dacrate
;
tmo
>>=
sample_shift
[(
s
->
pcc
&
CC_FMT_MASK
)
>>
CC_FMT_BIT
];
it8172_delay
(
tmo
);
}
if
(
signal_pending
(
current
))
return
-
ERESTARTSYS
;
return
0
;
}
}
/* --------------------------------------------------------------------- */
/* --------------------------------------------------------------------- */
static
ssize_t
it8172_read
(
struct
file
*
file
,
char
*
buffer
,
size_t
count
,
loff_t
*
ppos
)
{
struct
it8172_state
*
s
=
(
struct
it8172_state
*
)
file
->
private_data
;
struct
dmabuf
*
db
=
&
s
->
dma_adc
;
ssize_t
ret
;
unsigned
long
flags
;
int
cnt
,
bufcnt
,
avail
;
if
(
ppos
!=
&
file
->
f_pos
)
/*
return
-
ESPIPE
;
* Copy audio data to/from user buffer from/to dma buffer, taking care
if
(
db
->
mapped
)
* that we wrap when reading/writing the dma buffer. Returns actual byte
return
-
ENXIO
;
* count written to or read from the dma buffer.
if
(
!
access_ok
(
VERIFY_WRITE
,
buffer
,
count
))
*/
return
-
EFAULT
;
static
int
copy_dmabuf_user
(
struct
dmabuf
*
db
,
char
*
userbuf
,
ret
=
0
;
int
count
,
int
to_user
)
{
while
(
count
>
0
)
{
char
*
bufptr
=
to_user
?
db
->
nextOut
:
db
->
nextIn
;
// wait for samples in capture buffer
char
*
bufend
=
db
->
rawbuf
+
db
->
dmasize
;
do
{
spin_lock_irqsave
(
&
s
->
lock
,
flags
);
if
(
bufptr
+
count
>
bufend
)
{
if
(
db
->
stopped
)
int
partial
=
(
int
)(
bufend
-
bufptr
);
start_adc
(
s
);
if
(
to_user
)
{
avail
=
db
->
count
;
if
(
copy_to_user
(
userbuf
,
bufptr
,
partial
))
spin_unlock_irqrestore
(
&
s
->
lock
,
flags
);
return
-
EFAULT
;
if
(
avail
<=
0
)
{
if
(
copy_to_user
(
userbuf
+
partial
,
db
->
rawbuf
,
if
(
file
->
f_flags
&
O_NONBLOCK
)
{
count
-
partial
))
if
(
!
ret
)
return
-
EFAULT
;
ret
=
-
EAGAIN
;
}
else
{
return
ret
;
if
(
copy_from_user
(
bufptr
,
userbuf
,
partial
))
return
-
EFAULT
;
if
(
copy_from_user
(
db
->
rawbuf
,
userbuf
+
partial
,
count
-
partial
))
return
-
EFAULT
;
}
}
interruptible_sleep_on
(
&
db
->
wait
);
}
else
{
if
(
signal_pending
(
current
))
{
if
(
to_user
)
{
if
(
!
ret
)
if
(
copy_to_user
(
userbuf
,
bufptr
,
count
))
ret
=
-
ERESTARTSYS
;
return
-
EFAULT
;
return
ret
;
}
else
{
if
(
copy_from_user
(
bufptr
,
userbuf
,
count
))
return
-
EFAULT
;
}
}
}
}
while
(
avail
<=
0
);
cnt
=
count
>
avail
?
avail
:
count
;
bufcnt
=
cnt
;
if
(
cnt
%
db
->
fragsize
)
{
// round count up to nearest fragment
int
newcnt
=
db
->
fragsize
*
((
cnt
+
db
->
fragsize
)
/
db
->
fragsize
);
cnt
=
newcnt
;
}
}
return
count
;
}
// copy from nextOut to user
if
(
copy_to_user
(
buffer
,
db
->
nextOut
,
bufcnt
))
{
if
(
!
ret
)
ret
=
-
EFAULT
;
return
ret
;
}
static
ssize_t
it8172_read
(
struct
file
*
file
,
char
*
buffer
,
size_t
count
,
loff_t
*
ppos
)
{
struct
it8172_state
*
s
=
(
struct
it8172_state
*
)
file
->
private_data
;
struct
dmabuf
*
db
=
&
s
->
dma_adc
;
ssize_t
ret
;
unsigned
long
flags
;
int
cnt
,
remainder
,
avail
;
if
(
ppos
!=
&
file
->
f_pos
)
return
-
ESPIPE
;
if
(
db
->
mapped
)
return
-
ENXIO
;
if
(
!
access_ok
(
VERIFY_WRITE
,
buffer
,
count
))
return
-
EFAULT
;
ret
=
0
;
while
(
count
>
0
)
{
// wait for samples in capture buffer
do
{
spin_lock_irqsave
(
&
s
->
lock
,
flags
);
if
(
db
->
stopped
)
start_adc
(
s
);
avail
=
db
->
count
;
spin_unlock_irqrestore
(
&
s
->
lock
,
flags
);
if
(
avail
<=
0
)
{
if
(
file
->
f_flags
&
O_NONBLOCK
)
{
if
(
!
ret
)
ret
=
-
EAGAIN
;
return
ret
;
}
interruptible_sleep_on
(
&
db
->
wait
);
if
(
signal_pending
(
current
))
{
if
(
!
ret
)
ret
=
-
ERESTARTSYS
;
return
ret
;
}
}
}
while
(
avail
<=
0
);
// copy from nextOut to user
if
((
cnt
=
copy_dmabuf_user
(
db
,
buffer
,
count
>
avail
?
avail
:
count
,
1
))
<
0
)
{
if
(
!
ret
)
ret
=
-
EFAULT
;
return
ret
;
}
spin_lock_irqsave
(
&
s
->
lock
,
flags
);
db
->
count
-=
cnt
;
spin_unlock_irqrestore
(
&
s
->
lock
,
flags
);
db
->
nextOut
+=
cnt
;
if
(
db
->
nextOut
>=
db
->
rawbuf
+
db
->
dmasize
)
db
->
nextOut
-=
db
->
dmasize
;
count
-=
cnt
;
buffer
+=
cnt
;
ret
+=
cnt
;
}
// while (count > 0)
/*
* See if the dma buffer count after this read call is
* aligned on a fragsize boundary. If not, read from
* buffer until we reach a boundary, and let's hope this
* is just the last remainder of an audio record. If not
* it means the user is not reading in fragsize chunks, in
* which case it's his/her fault that there are audio gaps
* in their record.
*/
spin_lock_irqsave
(
&
s
->
lock
,
flags
);
spin_lock_irqsave
(
&
s
->
lock
,
flags
);
db
->
count
-=
cnt
;
remainder
=
db
->
count
%
db
->
fragsize
;
if
(
remainder
)
{
db
->
nextOut
+=
remainder
;
if
(
db
->
nextOut
>=
db
->
rawbuf
+
db
->
dmasize
)
db
->
nextOut
-=
db
->
dmasize
;
db
->
count
-=
remainder
;
}
spin_unlock_irqrestore
(
&
s
->
lock
,
flags
);
spin_unlock_irqrestore
(
&
s
->
lock
,
flags
);
db
->
nextOut
+=
cnt
;
return
ret
;
if
(
db
->
nextOut
>=
db
->
rawbuf
+
db
->
dmasize
)
db
->
nextOut
-=
db
->
dmasize
;
count
-=
bufcnt
;
buffer
+=
bufcnt
;
ret
+=
bufcnt
;
}
// while (count > 0)
return
ret
;
}
}
static
ssize_t
it8172_write
(
struct
file
*
file
,
const
char
*
buffer
,
static
ssize_t
it8172_write
(
struct
file
*
file
,
const
char
*
buffer
,
size_t
count
,
loff_t
*
ppos
)
size_t
count
,
loff_t
*
ppos
)
{
{
struct
it8172_state
*
s
=
(
struct
it8172_state
*
)
file
->
private_data
;
struct
it8172_state
*
s
=
(
struct
it8172_state
*
)
file
->
private_data
;
struct
dmabuf
*
db
=
&
s
->
dma_dac
;
struct
dmabuf
*
db
=
&
s
->
dma_dac
;
ssize_t
ret
;
ssize_t
ret
;
unsigned
long
flags
;
unsigned
long
flags
;
int
cnt
,
bufcnt
,
avail
;
int
cnt
,
remainder
,
avail
;
if
(
ppos
!=
&
file
->
f_pos
)
if
(
ppos
!=
&
file
->
f_pos
)
return
-
ESPIPE
;
return
-
ESPIPE
;
if
(
db
->
mapped
)
if
(
db
->
mapped
)
return
-
ENXIO
;
return
-
ENXIO
;
if
(
!
access_ok
(
VERIFY_READ
,
buffer
,
count
))
if
(
!
access_ok
(
VERIFY_READ
,
buffer
,
count
))
return
-
EFAULT
;
return
-
EFAULT
;
ret
=
0
;
ret
=
0
;
while
(
count
>
0
)
{
while
(
count
>
0
)
{
// wait for space in playback buffer
// wait for space in playback buffer
do
{
do
{
spin_lock_irqsave
(
&
s
->
lock
,
flags
);
spin_lock_irqsave
(
&
s
->
lock
,
flags
);
avail
=
db
->
dmasize
-
db
->
count
;
avail
=
db
->
dmasize
-
db
->
count
;
spin_unlock_irqrestore
(
&
s
->
lock
,
flags
);
spin_unlock_irqrestore
(
&
s
->
lock
,
flags
);
if
(
avail
<=
0
)
{
if
(
avail
<=
0
)
{
if
(
file
->
f_flags
&
O_NONBLOCK
)
{
if
(
file
->
f_flags
&
O_NONBLOCK
)
{
if
(
!
ret
)
if
(
!
ret
)
ret
=
-
EAGAIN
;
ret
=
-
EAGAIN
;
return
ret
;
return
ret
;
}
}
interruptible_sleep_on
(
&
db
->
wait
);
interruptible_sleep_on
(
&
db
->
wait
);
if
(
signal_pending
(
current
))
{
if
(
signal_pending
(
current
))
{
if
(
!
ret
)
if
(
!
ret
)
ret
=
-
ERESTARTSYS
;
ret
=
-
ERESTARTSYS
;
return
ret
;
return
ret
;
}
}
}
}
}
while
(
avail
<=
0
);
}
while
(
avail
<=
0
);
cnt
=
count
>
avail
?
avail
:
count
;
// copy to nextIn
// copy to nextIn
if
((
cnt
=
copy_dmabuf_user
(
db
,
(
char
*
)
buffer
,
if
(
copy_from_user
(
db
->
nextIn
,
buffer
,
cnt
))
{
count
>
avail
?
if
(
!
ret
)
avail
:
count
,
0
))
<
0
)
{
ret
=
-
EFAULT
;
if
(
!
ret
)
return
ret
;
ret
=
-
EFAULT
;
}
return
ret
;
}
bufcnt
=
cnt
;
if
(
cnt
%
db
->
fragsize
)
{
// round count up to nearest fragment, and fill remainder of
// fragment with silence
int
newcnt
=
db
->
fragsize
*
((
cnt
+
db
->
fragsize
)
/
db
->
fragsize
);
memset
(
db
->
nextIn
+
cnt
,
(
s
->
pcc
&
CC_DF
)
?
0
:
0x80
,
newcnt
-
cnt
);
cnt
=
newcnt
;
}
spin_lock_irqsave
(
&
s
->
lock
,
flags
);
spin_lock_irqsave
(
&
s
->
lock
,
flags
);
db
->
count
+=
cnt
;
db
->
count
+=
cnt
;
if
(
db
->
stopped
)
if
(
db
->
stopped
)
start_dac
(
s
);
start_dac
(
s
);
spin_unlock_irqrestore
(
&
s
->
lock
,
flags
);
spin_unlock_irqrestore
(
&
s
->
lock
,
flags
);
db
->
nextIn
+=
cnt
;
db
->
nextIn
+=
cnt
;
if
(
db
->
nextIn
>=
db
->
rawbuf
+
db
->
dmasize
)
if
(
db
->
nextIn
>=
db
->
rawbuf
+
db
->
dmasize
)
db
->
nextIn
-=
db
->
dmasize
;
db
->
nextIn
-=
db
->
dmasize
;
count
-=
buf
cnt
;
count
-=
cnt
;
buffer
+=
buf
cnt
;
buffer
+=
cnt
;
ret
+=
buf
cnt
;
ret
+=
cnt
;
}
// while (count > 0)
}
// while (count > 0)
return
ret
;
/*
* See if the dma buffer count after this write call is
* aligned on a fragsize boundary. If not, fill buffer
* with silence to the next boundary, and let's hope this
* is just the last remainder of an audio playback. If not
* it means the user is not sending us fragsize chunks, in
* which case it's his/her fault that there are audio gaps
* in their playback.
*/
spin_lock_irqsave
(
&
s
->
lock
,
flags
);
remainder
=
db
->
count
%
db
->
fragsize
;
if
(
remainder
)
{
int
fill_cnt
=
db
->
fragsize
-
remainder
;
memset
(
db
->
nextIn
,
0
,
fill_cnt
);
db
->
nextIn
+=
fill_cnt
;
if
(
db
->
nextIn
>=
db
->
rawbuf
+
db
->
dmasize
)
db
->
nextIn
-=
db
->
dmasize
;
db
->
count
+=
fill_cnt
;
}
spin_unlock_irqrestore
(
&
s
->
lock
,
flags
);
return
ret
;
}
}
/* No kernel lock - we have our own spinlock */
/* No kernel lock - we have our own spinlock */
static
unsigned
int
it8172_poll
(
struct
file
*
file
,
static
unsigned
int
it8172_poll
(
struct
file
*
file
,
struct
poll_table_struct
*
wait
)
struct
poll_table_struct
*
wait
)
{
{
struct
it8172_state
*
s
=
(
struct
it8172_state
*
)
file
->
private_data
;
struct
it8172_state
*
s
=
(
struct
it8172_state
*
)
file
->
private_data
;
unsigned
long
flags
;
unsigned
long
flags
;
unsigned
int
mask
=
0
;
unsigned
int
mask
=
0
;
if
(
file
->
f_mode
&
FMODE_WRITE
)
if
(
file
->
f_mode
&
FMODE_WRITE
)
{
poll_wait
(
file
,
&
s
->
dma_dac
.
wait
,
wait
);
if
(
!
s
->
dma_dac
.
ready
)
if
(
file
->
f_mode
&
FMODE_READ
)
return
0
;
poll_wait
(
file
,
&
s
->
dma_adc
.
wait
,
wait
);
poll_wait
(
file
,
&
s
->
dma_dac
.
wait
,
wait
);
spin_lock_irqsave
(
&
s
->
lock
,
flags
);
}
if
(
file
->
f_mode
&
FMODE_READ
)
{
if
(
file
->
f_mode
&
FMODE_READ
)
{
if
(
s
->
dma_adc
.
count
>=
(
signed
)
s
->
dma_adc
.
fragsize
)
if
(
!
s
->
dma_adc
.
ready
)
mask
|=
POLLIN
|
POLLRDNORM
;
return
0
;
}
poll_wait
(
file
,
&
s
->
dma_adc
.
wait
,
wait
);
if
(
file
->
f_mode
&
FMODE_WRITE
)
{
}
if
(
s
->
dma_dac
.
mapped
)
{
if
(
s
->
dma_dac
.
count
>=
(
signed
)
s
->
dma_dac
.
fragsize
)
spin_lock_irqsave
(
&
s
->
lock
,
flags
);
mask
|=
POLLOUT
|
POLLWRNORM
;
if
(
file
->
f_mode
&
FMODE_READ
)
{
}
else
{
if
(
s
->
dma_adc
.
count
>=
(
signed
)
s
->
dma_adc
.
fragsize
)
if
((
signed
)
s
->
dma_dac
.
dmasize
>=
mask
|=
POLLIN
|
POLLRDNORM
;
s
->
dma_dac
.
count
+
(
signed
)
s
->
dma_dac
.
fragsize
)
}
mask
|=
POLLOUT
|
POLLWRNORM
;
if
(
file
->
f_mode
&
FMODE_WRITE
)
{
if
(
s
->
dma_dac
.
mapped
)
{
if
(
s
->
dma_dac
.
count
>=
(
signed
)
s
->
dma_dac
.
fragsize
)
mask
|=
POLLOUT
|
POLLWRNORM
;
}
else
{
if
((
signed
)
s
->
dma_dac
.
dmasize
>=
s
->
dma_dac
.
count
+
(
signed
)
s
->
dma_dac
.
fragsize
)
mask
|=
POLLOUT
|
POLLWRNORM
;
}
}
}
}
spin_unlock_irqrestore
(
&
s
->
lock
,
flags
);
spin_unlock_irqrestore
(
&
s
->
lock
,
flags
);
return
mask
;
return
mask
;
}
}
static
int
it8172_mmap
(
struct
file
*
file
,
struct
vm_area_struct
*
vma
)
static
int
it8172_mmap
(
struct
file
*
file
,
struct
vm_area_struct
*
vma
)
{
{
struct
it8172_state
*
s
=
(
struct
it8172_state
*
)
file
->
private_data
;
struct
it8172_state
*
s
=
(
struct
it8172_state
*
)
file
->
private_data
;
struct
dmabuf
*
db
;
struct
dmabuf
*
db
;
unsigned
long
size
;
unsigned
long
size
;
lock_kernel
();
lock_kernel
();
if
(
vma
->
vm_flags
&
VM_WRITE
)
if
(
vma
->
vm_flags
&
VM_WRITE
)
db
=
&
s
->
dma_dac
;
db
=
&
s
->
dma_dac
;
else
if
(
vma
->
vm_flags
&
VM_READ
)
else
if
(
vma
->
vm_flags
&
VM_READ
)
db
=
&
s
->
dma_adc
;
db
=
&
s
->
dma_adc
;
else
{
else
{
unlock_kernel
();
unlock_kernel
();
return
-
EINVAL
;
return
-
EINVAL
;
}
}
if
(
vma
->
vm_pgoff
!=
0
)
{
if
(
vma
->
vm_pgoff
!=
0
)
{
unlock_kernel
();
unlock_kernel
();
return
-
EINVAL
;
return
-
EINVAL
;
}
}
size
=
vma
->
vm_end
-
vma
->
vm_start
;
size
=
vma
->
vm_end
-
vma
->
vm_start
;
if
(
size
>
(
PAGE_SIZE
<<
db
->
buforder
))
{
if
(
size
>
(
PAGE_SIZE
<<
db
->
buforder
))
{
unlock_kernel
();
unlock_kernel
();
return
-
EINVAL
;
return
-
EINVAL
;
}
}
if
(
remap_page_range
(
vma
,
vma
->
vm_start
,
virt_to_phys
(
db
->
rawbuf
),
if
(
remap_page_range
(
vma
,
vma
->
vm_start
,
virt_to_phys
(
db
->
rawbuf
),
size
,
vma
->
vm_page_prot
))
{
size
,
vma
->
vm_page_prot
))
{
unlock_kernel
();
return
-
EAGAIN
;
}
db
->
mapped
=
1
;
unlock_kernel
();
unlock_kernel
();
return
-
EAGAIN
;
return
0
;
}
db
->
mapped
=
1
;
unlock_kernel
();
return
0
;
}
}
#ifdef IT8172_VERBOSE_DEBUG
#ifdef IT8172_VERBOSE_DEBUG
static
struct
ioctl_str_t
{
static
struct
ioctl_str_t
{
unsigned
int
cmd
;
unsigned
int
cmd
;
const
char
*
str
;
const
char
*
str
;
}
ioctl_str
[]
=
{
}
ioctl_str
[]
=
{
{
SNDCTL_DSP_RESET
,
"SNDCTL_DSP_RESET"
},
{
SNDCTL_DSP_RESET
,
"SNDCTL_DSP_RESET"
},
{
SNDCTL_DSP_SYNC
,
"SNDCTL_DSP_SYNC"
},
{
SNDCTL_DSP_SYNC
,
"SNDCTL_DSP_SYNC"
},
{
SNDCTL_DSP_SPEED
,
"SNDCTL_DSP_SPEED"
},
{
SNDCTL_DSP_SPEED
,
"SNDCTL_DSP_SPEED"
},
{
SNDCTL_DSP_STEREO
,
"SNDCTL_DSP_STEREO"
},
{
SNDCTL_DSP_STEREO
,
"SNDCTL_DSP_STEREO"
},
{
SNDCTL_DSP_GETBLKSIZE
,
"SNDCTL_DSP_GETBLKSIZE"
},
{
SNDCTL_DSP_GETBLKSIZE
,
"SNDCTL_DSP_GETBLKSIZE"
},
{
SNDCTL_DSP_SAMPLESIZE
,
"SNDCTL_DSP_SAMPLESIZE"
},
{
SNDCTL_DSP_SAMPLESIZE
,
"SNDCTL_DSP_SAMPLESIZE"
},
{
SNDCTL_DSP_CHANNELS
,
"SNDCTL_DSP_CHANNELS"
},
{
SNDCTL_DSP_CHANNELS
,
"SNDCTL_DSP_CHANNELS"
},
{
SOUND_PCM_WRITE_CHANNELS
,
"SOUND_PCM_WRITE_CHANNELS"
},
{
SOUND_PCM_WRITE_CHANNELS
,
"SOUND_PCM_WRITE_CHANNELS"
},
{
SOUND_PCM_WRITE_FILTER
,
"SOUND_PCM_WRITE_FILTER"
},
{
SOUND_PCM_WRITE_FILTER
,
"SOUND_PCM_WRITE_FILTER"
},
{
SNDCTL_DSP_POST
,
"SNDCTL_DSP_POST"
},
{
SNDCTL_DSP_POST
,
"SNDCTL_DSP_POST"
},
{
SNDCTL_DSP_SUBDIVIDE
,
"SNDCTL_DSP_SUBDIVIDE"
},
{
SNDCTL_DSP_SUBDIVIDE
,
"SNDCTL_DSP_SUBDIVIDE"
},
{
SNDCTL_DSP_SETFRAGMENT
,
"SNDCTL_DSP_SETFRAGMENT"
},
{
SNDCTL_DSP_SETFRAGMENT
,
"SNDCTL_DSP_SETFRAGMENT"
},
{
SNDCTL_DSP_GETFMTS
,
"SNDCTL_DSP_GETFMTS"
},
{
SNDCTL_DSP_GETFMTS
,
"SNDCTL_DSP_GETFMTS"
},
{
SNDCTL_DSP_SETFMT
,
"SNDCTL_DSP_SETFMT"
},
{
SNDCTL_DSP_SETFMT
,
"SNDCTL_DSP_SETFMT"
},
{
SNDCTL_DSP_GETOSPACE
,
"SNDCTL_DSP_GETOSPACE"
},
{
SNDCTL_DSP_GETOSPACE
,
"SNDCTL_DSP_GETOSPACE"
},
{
SNDCTL_DSP_GETISPACE
,
"SNDCTL_DSP_GETISPACE"
},
{
SNDCTL_DSP_GETISPACE
,
"SNDCTL_DSP_GETISPACE"
},
{
SNDCTL_DSP_NONBLOCK
,
"SNDCTL_DSP_NONBLOCK"
},
{
SNDCTL_DSP_NONBLOCK
,
"SNDCTL_DSP_NONBLOCK"
},
{
SNDCTL_DSP_GETCAPS
,
"SNDCTL_DSP_GETCAPS"
},
{
SNDCTL_DSP_GETCAPS
,
"SNDCTL_DSP_GETCAPS"
},
{
SNDCTL_DSP_GETTRIGGER
,
"SNDCTL_DSP_GETTRIGGER"
},
{
SNDCTL_DSP_GETTRIGGER
,
"SNDCTL_DSP_GETTRIGGER"
},
{
SNDCTL_DSP_SETTRIGGER
,
"SNDCTL_DSP_SETTRIGGER"
},
{
SNDCTL_DSP_SETTRIGGER
,
"SNDCTL_DSP_SETTRIGGER"
},
{
SNDCTL_DSP_GETIPTR
,
"SNDCTL_DSP_GETIPTR"
},
{
SNDCTL_DSP_GETIPTR
,
"SNDCTL_DSP_GETIPTR"
},
{
SNDCTL_DSP_GETOPTR
,
"SNDCTL_DSP_GETOPTR"
},
{
SNDCTL_DSP_GETOPTR
,
"SNDCTL_DSP_GETOPTR"
},
{
SNDCTL_DSP_MAPINBUF
,
"SNDCTL_DSP_MAPINBUF"
},
{
SNDCTL_DSP_MAPINBUF
,
"SNDCTL_DSP_MAPINBUF"
},
{
SNDCTL_DSP_MAPOUTBUF
,
"SNDCTL_DSP_MAPOUTBUF"
},
{
SNDCTL_DSP_MAPOUTBUF
,
"SNDCTL_DSP_MAPOUTBUF"
},
{
SNDCTL_DSP_SETSYNCRO
,
"SNDCTL_DSP_SETSYNCRO"
},
{
SNDCTL_DSP_SETSYNCRO
,
"SNDCTL_DSP_SETSYNCRO"
},
{
SNDCTL_DSP_SETDUPLEX
,
"SNDCTL_DSP_SETDUPLEX"
},
{
SNDCTL_DSP_SETDUPLEX
,
"SNDCTL_DSP_SETDUPLEX"
},
{
SNDCTL_DSP_GETODELAY
,
"SNDCTL_DSP_GETODELAY"
},
{
SNDCTL_DSP_GETODELAY
,
"SNDCTL_DSP_GETODELAY"
},
{
SNDCTL_DSP_GETCHANNELMASK
,
"SNDCTL_DSP_GETCHANNELMASK"
},
{
SNDCTL_DSP_GETCHANNELMASK
,
"SNDCTL_DSP_GETCHANNELMASK"
},
{
SNDCTL_DSP_BIND_CHANNEL
,
"SNDCTL_DSP_BIND_CHANNEL"
},
{
SNDCTL_DSP_BIND_CHANNEL
,
"SNDCTL_DSP_BIND_CHANNEL"
},
{
OSS_GETVERSION
,
"OSS_GETVERSION"
},
{
OSS_GETVERSION
,
"OSS_GETVERSION"
},
{
SOUND_PCM_READ_RATE
,
"SOUND_PCM_READ_RATE"
},
{
SOUND_PCM_READ_RATE
,
"SOUND_PCM_READ_RATE"
},
{
SOUND_PCM_READ_CHANNELS
,
"SOUND_PCM_READ_CHANNELS"
},
{
SOUND_PCM_READ_CHANNELS
,
"SOUND_PCM_READ_CHANNELS"
},
{
SOUND_PCM_READ_BITS
,
"SOUND_PCM_READ_BITS"
},
{
SOUND_PCM_READ_BITS
,
"SOUND_PCM_READ_BITS"
},
{
SOUND_PCM_READ_FILTER
,
"SOUND_PCM_READ_FILTER"
}
{
SOUND_PCM_READ_FILTER
,
"SOUND_PCM_READ_FILTER"
}
};
};
#endif
#endif
static
int
it8172_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
static
int
it8172_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
)
unsigned
int
cmd
,
unsigned
long
arg
)
{
{
struct
it8172_state
*
s
=
(
struct
it8172_state
*
)
file
->
private_data
;
struct
it8172_state
*
s
=
(
struct
it8172_state
*
)
file
->
private_data
;
unsigned
long
flags
;
unsigned
long
flags
;
audio_buf_info
abinfo
;
audio_buf_info
abinfo
;
count_info
cinfo
;
count_info
cinfo
;
int
count
;
int
count
;
int
val
,
mapped
,
ret
,
diff
;
int
val
,
mapped
,
ret
,
diff
;
mapped
=
((
file
->
f_mode
&
FMODE_WRITE
)
&&
s
->
dma_dac
.
mapped
)
||
mapped
=
((
file
->
f_mode
&
FMODE_WRITE
)
&&
s
->
dma_dac
.
mapped
)
||
((
file
->
f_mode
&
FMODE_READ
)
&&
s
->
dma_adc
.
mapped
);
((
file
->
f_mode
&
FMODE_READ
)
&&
s
->
dma_adc
.
mapped
);
#ifdef IT8172_VERBOSE_DEBUG
#ifdef IT8172_VERBOSE_DEBUG
for
(
count
=
0
;
count
<
sizeof
(
ioctl_str
)
/
sizeof
(
ioctl_str
[
0
]);
count
++
)
{
for
(
count
=
0
;
count
<
sizeof
(
ioctl_str
)
/
sizeof
(
ioctl_str
[
0
]);
count
++
)
{
if
(
ioctl_str
[
count
].
cmd
==
cmd
)
if
(
ioctl_str
[
count
].
cmd
==
cmd
)
break
;
break
;
}
}
if
(
count
<
sizeof
(
ioctl_str
)
/
sizeof
(
ioctl_str
[
0
]))
if
(
count
<
sizeof
(
ioctl_str
)
/
sizeof
(
ioctl_str
[
0
]))
printk
(
KERN_INFO
PFX
"ioctl %s
\n
"
,
ioctl_str
[
count
].
str
);
dbg
(
"ioctl %s, arg=0x%08x"
,
else
ioctl_str
[
count
].
str
,
(
unsigned
int
)
arg
);
printk
(
KERN_INFO
PFX
"ioctl unknown, 0x%x
\n
"
,
cmd
);
else
dbg
(
"ioctl unknown, 0x%x"
,
cmd
);
#endif
#endif
switch
(
cmd
)
{
switch
(
cmd
)
{
case
OSS_GETVERSION
:
case
OSS_GETVERSION
:
return
put_user
(
SOUND_VERSION
,
(
int
*
)
arg
);
return
put_user
(
SOUND_VERSION
,
(
int
*
)
arg
);
case
SNDCTL_DSP_SYNC
:
case
SNDCTL_DSP_SYNC
:
if
(
file
->
f_mode
&
FMODE_WRITE
)
if
(
file
->
f_mode
&
FMODE_WRITE
)
return
drain_dac
(
s
,
file
->
f_flags
&
O_NONBLOCK
);
return
drain_dac
(
s
,
file
->
f_flags
&
O_NONBLOCK
);
return
0
;
return
0
;
case
SNDCTL_DSP_SETDUPLEX
:
case
SNDCTL_DSP_SETDUPLEX
:
return
0
;
return
0
;
case
SNDCTL_DSP_GETCAPS
:
case
SNDCTL_DSP_GETCAPS
:
return
put_user
(
DSP_CAP_DUPLEX
|
DSP_CAP_REALTIME
|
return
put_user
(
DSP_CAP_DUPLEX
|
DSP_CAP_REALTIME
|
DSP_CAP_TRIGGER
|
DSP_CAP_MMAP
,
(
int
*
)
arg
);
DSP_CAP_TRIGGER
|
DSP_CAP_MMAP
,
(
int
*
)
arg
);
case
SNDCTL_DSP_RESET
:
case
SNDCTL_DSP_RESET
:
if
(
file
->
f_mode
&
FMODE_WRITE
)
{
if
(
file
->
f_mode
&
FMODE_WRITE
)
{
stop_dac
(
s
);
stop_dac
(
s
);
synchronize_irq
(
s
->
irq
);
synchronize_irq
();
s
->
dma_dac
.
count
=
s
->
dma_dac
.
total_bytes
=
0
;
s
->
dma_dac
.
count
=
s
->
dma_dac
.
total_bytes
=
0
;
s
->
dma_dac
.
nextIn
=
s
->
dma_dac
.
nextOut
=
s
->
dma_dac
.
rawbuf
;
s
->
dma_dac
.
nextIn
=
s
->
dma_dac
.
nextOut
=
}
s
->
dma_dac
.
rawbuf
;
if
(
file
->
f_mode
&
FMODE_READ
)
{
stop_adc
(
s
);
synchronize_irq
(
s
->
irq
);
s
->
dma_adc
.
count
=
s
->
dma_adc
.
total_bytes
=
0
;
s
->
dma_adc
.
nextIn
=
s
->
dma_adc
.
nextOut
=
s
->
dma_adc
.
rawbuf
;
}
return
0
;
case
SNDCTL_DSP_SPEED
:
if
(
get_user
(
val
,
(
int
*
)
arg
))
return
-
EFAULT
;
if
(
val
>=
0
)
{
if
(
file
->
f_mode
&
FMODE_READ
)
{
stop_adc
(
s
);
set_adc_rate
(
s
,
val
);
if
((
ret
=
prog_dmabuf_adc
(
s
)))
return
ret
;
}
if
(
file
->
f_mode
&
FMODE_WRITE
)
{
stop_dac
(
s
);
set_dac_rate
(
s
,
val
);
if
((
ret
=
prog_dmabuf_dac
(
s
)))
return
ret
;
}
}
return
put_user
((
file
->
f_mode
&
FMODE_READ
)
?
s
->
adcrate
:
s
->
dacrate
,
(
int
*
)
arg
);
case
SNDCTL_DSP_STEREO
:
if
(
get_user
(
val
,
(
int
*
)
arg
))
return
-
EFAULT
;
if
(
file
->
f_mode
&
FMODE_READ
)
{
stop_adc
(
s
);
if
(
val
)
s
->
capcc
|=
CC_SM
;
else
s
->
capcc
&=
~
CC_SM
;
outw
(
s
->
capcc
,
s
->
io
+
IT_AC_CAPCC
);
if
((
ret
=
prog_dmabuf_adc
(
s
)))
return
ret
;
}
if
(
file
->
f_mode
&
FMODE_WRITE
)
{
stop_dac
(
s
);
if
(
val
)
s
->
pcc
|=
CC_SM
;
else
s
->
pcc
&=
~
CC_SM
;
outw
(
s
->
pcc
,
s
->
io
+
IT_AC_PCC
);
if
((
ret
=
prog_dmabuf_dac
(
s
)))
return
ret
;
}
return
0
;
case
SNDCTL_DSP_CHANNELS
:
if
(
get_user
(
val
,
(
int
*
)
arg
))
return
-
EFAULT
;
if
(
val
!=
0
)
{
if
(
file
->
f_mode
&
FMODE_READ
)
{
stop_adc
(
s
);
if
(
val
>=
2
)
{
val
=
2
;
s
->
capcc
|=
CC_SM
;
}
}
else
if
(
file
->
f_mode
&
FMODE_READ
)
{
s
->
capcc
&=
~
CC_SM
;
stop_adc
(
s
);
outw
(
s
->
capcc
,
s
->
io
+
IT_AC_CAPCC
);
synchronize_irq
();
if
((
ret
=
prog_dmabuf_adc
(
s
)))
s
->
dma_adc
.
count
=
s
->
dma_adc
.
total_bytes
=
0
;
return
ret
;
s
->
dma_adc
.
nextIn
=
s
->
dma_adc
.
nextOut
=
}
s
->
dma_adc
.
rawbuf
;
if
(
file
->
f_mode
&
FMODE_WRITE
)
{
stop_dac
(
s
);
switch
(
val
)
{
case
1
:
s
->
pcc
&=
~
CC_SM
;
break
;
case
2
:
s
->
pcc
|=
CC_SM
;
break
;
default:
// FIX! support multichannel???
val
=
2
;
s
->
pcc
|=
CC_SM
;
break
;
}
}
outw
(
s
->
pcc
,
s
->
io
+
IT_AC_PCC
);
return
0
;
if
((
ret
=
prog_dmabuf_dac
(
s
)))
return
ret
;
case
SNDCTL_DSP_SPEED
:
}
if
(
get_user
(
val
,
(
int
*
)
arg
))
}
return
-
EFAULT
;
return
put_user
(
val
,
(
int
*
)
arg
);
if
(
val
>=
0
)
{
if
(
file
->
f_mode
&
FMODE_READ
)
{
stop_adc
(
s
);
set_adc_rate
(
s
,
val
);
if
((
ret
=
prog_dmabuf_adc
(
s
)))
return
ret
;
}
if
(
file
->
f_mode
&
FMODE_WRITE
)
{
stop_dac
(
s
);
set_dac_rate
(
s
,
val
);
if
((
ret
=
prog_dmabuf_dac
(
s
)))
return
ret
;
}
}
return
put_user
((
file
->
f_mode
&
FMODE_READ
)
?
s
->
adcrate
:
s
->
dacrate
,
(
int
*
)
arg
);
case
SNDCTL_DSP_STEREO
:
if
(
get_user
(
val
,
(
int
*
)
arg
))
return
-
EFAULT
;
if
(
file
->
f_mode
&
FMODE_READ
)
{
stop_adc
(
s
);
if
(
val
)
s
->
capcc
|=
CC_SM
;
else
s
->
capcc
&=
~
CC_SM
;
outw
(
s
->
capcc
,
s
->
io
+
IT_AC_CAPCC
);
if
((
ret
=
prog_dmabuf_adc
(
s
)))
return
ret
;
}
if
(
file
->
f_mode
&
FMODE_WRITE
)
{
stop_dac
(
s
);
if
(
val
)
s
->
pcc
|=
CC_SM
;
else
s
->
pcc
&=
~
CC_SM
;
outw
(
s
->
pcc
,
s
->
io
+
IT_AC_PCC
);
if
((
ret
=
prog_dmabuf_dac
(
s
)))
return
ret
;
}
return
0
;
case
SNDCTL_DSP_CHANNELS
:
if
(
get_user
(
val
,
(
int
*
)
arg
))
return
-
EFAULT
;
if
(
val
!=
0
)
{
if
(
file
->
f_mode
&
FMODE_READ
)
{
stop_adc
(
s
);
if
(
val
>=
2
)
{
val
=
2
;
s
->
capcc
|=
CC_SM
;
}
else
s
->
capcc
&=
~
CC_SM
;
outw
(
s
->
capcc
,
s
->
io
+
IT_AC_CAPCC
);
if
((
ret
=
prog_dmabuf_adc
(
s
)))
return
ret
;
}
if
(
file
->
f_mode
&
FMODE_WRITE
)
{
stop_dac
(
s
);
switch
(
val
)
{
case
1
:
s
->
pcc
&=
~
CC_SM
;
break
;
case
2
:
s
->
pcc
|=
CC_SM
;
break
;
default:
// FIX! support multichannel???
val
=
2
;
s
->
pcc
|=
CC_SM
;
break
;
}
outw
(
s
->
pcc
,
s
->
io
+
IT_AC_PCC
);
if
((
ret
=
prog_dmabuf_dac
(
s
)))
return
ret
;
}
}
return
put_user
(
val
,
(
int
*
)
arg
);
case
SNDCTL_DSP_GETFMTS
:
/* Returns a mask */
case
SNDCTL_DSP_GETFMTS
:
/* Returns a mask */
return
put_user
(
AFMT_S16_LE
|
AFMT_U8
,
(
int
*
)
arg
);
return
put_user
(
AFMT_S16_LE
|
AFMT_U8
,
(
int
*
)
arg
);
case
SNDCTL_DSP_SETFMT
:
/* Selects ONE fmt*/
case
SNDCTL_DSP_SETFMT
:
/* Selects ONE fmt*/
if
(
get_user
(
val
,
(
int
*
)
arg
))
if
(
get_user
(
val
,
(
int
*
)
arg
))
return
-
EFAULT
;
return
-
EFAULT
;
if
(
val
!=
AFMT_QUERY
)
{
if
(
val
!=
AFMT_QUERY
)
{
if
(
file
->
f_mode
&
FMODE_READ
)
{
if
(
file
->
f_mode
&
FMODE_READ
)
{
stop_adc
(
s
);
stop_adc
(
s
);
if
(
val
==
AFMT_S16_LE
)
if
(
val
==
AFMT_S16_LE
)
s
->
capcc
|=
CC_DF
;
s
->
capcc
|=
CC_DF
;
else
{
else
{
val
=
AFMT_U8
;
val
=
AFMT_U8
;
s
->
capcc
&=
~
CC_DF
;
s
->
capcc
&=
~
CC_DF
;
}
}
outw
(
s
->
capcc
,
s
->
io
+
IT_AC_CAPCC
);
outw
(
s
->
capcc
,
s
->
io
+
IT_AC_CAPCC
);
if
((
ret
=
prog_dmabuf_adc
(
s
)))
if
((
ret
=
prog_dmabuf_adc
(
s
)))
return
ret
;
return
ret
;
}
}
if
(
file
->
f_mode
&
FMODE_WRITE
)
{
if
(
file
->
f_mode
&
FMODE_WRITE
)
{
stop_dac
(
s
);
stop_dac
(
s
);
if
(
val
==
AFMT_S16_LE
)
if
(
val
==
AFMT_S16_LE
)
s
->
pcc
|=
CC_DF
;
s
->
pcc
|=
CC_DF
;
else
{
else
{
val
=
AFMT_U8
;
val
=
AFMT_U8
;
s
->
pcc
&=
~
CC_DF
;
s
->
pcc
&=
~
CC_DF
;
}
outw
(
s
->
pcc
,
s
->
io
+
IT_AC_PCC
);
if
((
ret
=
prog_dmabuf_dac
(
s
)))
return
ret
;
}
}
else
{
if
(
file
->
f_mode
&
FMODE_READ
)
val
=
(
s
->
capcc
&
CC_DF
)
?
AFMT_S16_LE
:
AFMT_U8
;
else
val
=
(
s
->
pcc
&
CC_DF
)
?
AFMT_S16_LE
:
AFMT_U8
;
}
}
outw
(
s
->
pcc
,
s
->
io
+
IT_AC_PCC
);
return
put_user
(
val
,
(
int
*
)
arg
);
if
((
ret
=
prog_dmabuf_dac
(
s
)))
return
ret
;
}
}
else
{
if
(
file
->
f_mode
&
FMODE_READ
)
val
=
(
s
->
capcc
&
CC_DF
)
?
AFMT_S16_LE
:
AFMT_U8
;
else
val
=
(
s
->
pcc
&
CC_DF
)
?
AFMT_S16_LE
:
AFMT_U8
;
}
return
put_user
(
val
,
(
int
*
)
arg
);
case
SNDCTL_DSP_POST
:
case
SNDCTL_DSP_POST
:
return
0
;
return
0
;
case
SNDCTL_DSP_GETTRIGGER
:
case
SNDCTL_DSP_GETTRIGGER
:
val
=
0
;
val
=
0
;
spin_lock_irqsave
(
&
s
->
lock
,
flags
);
spin_lock_irqsave
(
&
s
->
lock
,
flags
);
if
(
file
->
f_mode
&
FMODE_READ
&&
!
s
->
dma_adc
.
stopped
)
if
(
file
->
f_mode
&
FMODE_READ
&&
!
s
->
dma_adc
.
stopped
)
val
|=
PCM_ENABLE_INPUT
;
val
|=
PCM_ENABLE_INPUT
;
if
(
file
->
f_mode
&
FMODE_WRITE
&&
!
s
->
dma_dac
.
stopped
)
if
(
file
->
f_mode
&
FMODE_WRITE
&&
!
s
->
dma_dac
.
stopped
)
val
|=
PCM_ENABLE_OUTPUT
;
val
|=
PCM_ENABLE_OUTPUT
;
spin_unlock_irqrestore
(
&
s
->
lock
,
flags
);
spin_unlock_irqrestore
(
&
s
->
lock
,
flags
);
return
put_user
(
val
,
(
int
*
)
arg
);
return
put_user
(
val
,
(
int
*
)
arg
);
case
SNDCTL_DSP_SETTRIGGER
:
case
SNDCTL_DSP_SETTRIGGER
:
if
(
get_user
(
val
,
(
int
*
)
arg
))
if
(
get_user
(
val
,
(
int
*
)
arg
))
return
-
EFAULT
;
return
-
EFAULT
;
if
(
file
->
f_mode
&
FMODE_READ
)
{
if
(
file
->
f_mode
&
FMODE_READ
)
{
if
(
val
&
PCM_ENABLE_INPUT
)
if
(
val
&
PCM_ENABLE_INPUT
)
start_adc
(
s
);
start_adc
(
s
);
else
else
stop_adc
(
s
);
stop_adc
(
s
);
}
}
if
(
file
->
f_mode
&
FMODE_WRITE
)
{
if
(
file
->
f_mode
&
FMODE_WRITE
)
{
if
(
val
&
PCM_ENABLE_OUTPUT
)
if
(
val
&
PCM_ENABLE_OUTPUT
)
start_dac
(
s
);
start_dac
(
s
);
else
else
stop_dac
(
s
);
stop_dac
(
s
);
}
}
return
0
;
return
0
;
case
SNDCTL_DSP_GETOSPACE
:
case
SNDCTL_DSP_GETOSPACE
:
if
(
!
(
file
->
f_mode
&
FMODE_WRITE
))
if
(
!
(
file
->
f_mode
&
FMODE_WRITE
))
return
-
EINVAL
;
return
-
EINVAL
;
abinfo
.
fragsize
=
s
->
dma_dac
.
fragsize
;
abinfo
.
fragsize
=
s
->
dma_dac
.
fragsize
;
spin_lock_irqsave
(
&
s
->
lock
,
flags
);
spin_lock_irqsave
(
&
s
->
lock
,
flags
);
count
=
s
->
dma_dac
.
count
;
count
=
s
->
dma_dac
.
count
;
if
(
!
s
->
dma_dac
.
stopped
)
if
(
!
s
->
dma_dac
.
stopped
)
count
-=
(
s
->
dma_dac
.
fragsize
-
inw
(
s
->
io
+
IT_AC_PCDL
));
count
-=
(
s
->
dma_dac
.
fragsize
-
spin_unlock_irqrestore
(
&
s
->
lock
,
flags
);
inw
(
s
->
io
+
IT_AC_PCDL
));
if
(
count
<
0
)
spin_unlock_irqrestore
(
&
s
->
lock
,
flags
);
count
=
0
;
if
(
count
<
0
)
abinfo
.
bytes
=
s
->
dma_dac
.
dmasize
-
count
;
count
=
0
;
abinfo
.
fragstotal
=
s
->
dma_dac
.
numfrag
;
abinfo
.
bytes
=
s
->
dma_dac
.
dmasize
-
count
;
abinfo
.
fragments
=
abinfo
.
bytes
>>
s
->
dma_dac
.
fragshift
;
abinfo
.
fragstotal
=
s
->
dma_dac
.
numfrag
;
return
copy_to_user
((
void
*
)
arg
,
&
abinfo
,
sizeof
(
abinfo
))
?
-
EFAULT
:
0
;
abinfo
.
fragments
=
abinfo
.
bytes
>>
s
->
dma_dac
.
fragshift
;
return
copy_to_user
((
void
*
)
arg
,
&
abinfo
,
sizeof
(
abinfo
))
?
case
SNDCTL_DSP_GETISPACE
:
-
EFAULT
:
0
;
if
(
!
(
file
->
f_mode
&
FMODE_READ
))
return
-
EINVAL
;
case
SNDCTL_DSP_GETISPACE
:
abinfo
.
fragsize
=
s
->
dma_adc
.
fragsize
;
if
(
!
(
file
->
f_mode
&
FMODE_READ
))
spin_lock_irqsave
(
&
s
->
lock
,
flags
);
return
-
EINVAL
;
count
=
s
->
dma_adc
.
count
;
abinfo
.
fragsize
=
s
->
dma_adc
.
fragsize
;
if
(
!
s
->
dma_adc
.
stopped
)
spin_lock_irqsave
(
&
s
->
lock
,
flags
);
count
+=
(
s
->
dma_adc
.
fragsize
-
inw
(
s
->
io
+
IT_AC_CAPCDL
));
count
=
s
->
dma_adc
.
count
;
spin_unlock_irqrestore
(
&
s
->
lock
,
flags
);
if
(
!
s
->
dma_adc
.
stopped
)
if
(
count
<
0
)
count
+=
(
s
->
dma_adc
.
fragsize
-
count
=
0
;
inw
(
s
->
io
+
IT_AC_CAPCDL
));
abinfo
.
bytes
=
count
;
spin_unlock_irqrestore
(
&
s
->
lock
,
flags
);
abinfo
.
fragstotal
=
s
->
dma_adc
.
numfrag
;
if
(
count
<
0
)
abinfo
.
fragments
=
abinfo
.
bytes
>>
s
->
dma_adc
.
fragshift
;
count
=
0
;
return
copy_to_user
((
void
*
)
arg
,
&
abinfo
,
sizeof
(
abinfo
))
?
-
EFAULT
:
0
;
abinfo
.
bytes
=
count
;
abinfo
.
fragstotal
=
s
->
dma_adc
.
numfrag
;
abinfo
.
fragments
=
abinfo
.
bytes
>>
s
->
dma_adc
.
fragshift
;
return
copy_to_user
((
void
*
)
arg
,
&
abinfo
,
sizeof
(
abinfo
))
?
-
EFAULT
:
0
;
case
SNDCTL_DSP_NONBLOCK
:
case
SNDCTL_DSP_NONBLOCK
:
file
->
f_flags
|=
O_NONBLOCK
;
file
->
f_flags
|=
O_NONBLOCK
;
return
0
;
return
0
;
case
SNDCTL_DSP_GETODELAY
:
case
SNDCTL_DSP_GETODELAY
:
if
(
!
(
file
->
f_mode
&
FMODE_WRITE
))
if
(
!
(
file
->
f_mode
&
FMODE_WRITE
))
return
-
EINVAL
;
return
-
EINVAL
;
spin_lock_irqsave
(
&
s
->
lock
,
flags
);
spin_lock_irqsave
(
&
s
->
lock
,
flags
);
count
=
s
->
dma_dac
.
count
;
count
=
s
->
dma_dac
.
count
;
if
(
!
s
->
dma_dac
.
stopped
)
if
(
!
s
->
dma_dac
.
stopped
)
count
-=
(
s
->
dma_dac
.
fragsize
-
inw
(
s
->
io
+
IT_AC_PCDL
));
count
-=
(
s
->
dma_dac
.
fragsize
-
spin_unlock_irqrestore
(
&
s
->
lock
,
flags
);
inw
(
s
->
io
+
IT_AC_PCDL
));
if
(
count
<
0
)
spin_unlock_irqrestore
(
&
s
->
lock
,
flags
);
count
=
0
;
if
(
count
<
0
)
return
put_user
(
count
,
(
int
*
)
arg
);
count
=
0
;
return
put_user
(
count
,
(
int
*
)
arg
);
case
SNDCTL_DSP_GETIPTR
:
if
(
!
(
file
->
f_mode
&
FMODE_READ
))
case
SNDCTL_DSP_GETIPTR
:
return
-
EINVAL
;
if
(
!
(
file
->
f_mode
&
FMODE_READ
))
spin_lock_irqsave
(
&
s
->
lock
,
flags
);
return
-
EINVAL
;
cinfo
.
bytes
=
s
->
dma_adc
.
total_bytes
;
spin_lock_irqsave
(
&
s
->
lock
,
flags
);
count
=
s
->
dma_adc
.
count
;
cinfo
.
bytes
=
s
->
dma_adc
.
total_bytes
;
if
(
!
s
->
dma_adc
.
stopped
)
{
count
=
s
->
dma_adc
.
count
;
diff
=
s
->
dma_adc
.
fragsize
-
inw
(
s
->
io
+
IT_AC_CAPCDL
);
if
(
!
s
->
dma_adc
.
stopped
)
{
count
+=
diff
;
diff
=
s
->
dma_adc
.
fragsize
-
inw
(
s
->
io
+
IT_AC_CAPCDL
);
cinfo
.
bytes
+=
diff
;
count
+=
diff
;
cinfo
.
ptr
=
inl
(
s
->
io
+
s
->
dma_adc
.
curBufPtr
)
-
s
->
dma_adc
.
dmaaddr
;
cinfo
.
bytes
+=
diff
;
}
else
cinfo
.
ptr
=
inl
(
s
->
io
+
s
->
dma_adc
.
curBufPtr
)
-
cinfo
.
ptr
=
virt_to_bus
(
s
->
dma_adc
.
nextIn
)
-
s
->
dma_adc
.
dmaaddr
;
s
->
dma_adc
.
dmaaddr
;
if
(
s
->
dma_adc
.
mapped
)
}
else
s
->
dma_adc
.
count
&=
s
->
dma_adc
.
fragsize
-
1
;
cinfo
.
ptr
=
virt_to_bus
(
s
->
dma_adc
.
nextIn
)
-
spin_unlock_irqrestore
(
&
s
->
lock
,
flags
);
s
->
dma_adc
.
dmaaddr
;
if
(
count
<
0
)
if
(
s
->
dma_adc
.
mapped
)
count
=
0
;
s
->
dma_adc
.
count
&=
s
->
dma_adc
.
fragsize
-
1
;
cinfo
.
blocks
=
count
>>
s
->
dma_adc
.
fragshift
;
spin_unlock_irqrestore
(
&
s
->
lock
,
flags
);
if
(
copy_to_user
((
void
*
)
arg
,
&
cinfo
,
sizeof
(
cinfo
)))
if
(
count
<
0
)
return
-
EFAULT
;
count
=
0
;
return
0
;
cinfo
.
blocks
=
count
>>
s
->
dma_adc
.
fragshift
;
return
copy_to_user
((
void
*
)
arg
,
&
cinfo
,
sizeof
(
cinfo
));
case
SNDCTL_DSP_GETOPTR
:
if
(
!
(
file
->
f_mode
&
FMODE_READ
))
case
SNDCTL_DSP_GETOPTR
:
return
-
EINVAL
;
if
(
!
(
file
->
f_mode
&
FMODE_READ
))
spin_lock_irqsave
(
&
s
->
lock
,
flags
);
return
-
EINVAL
;
cinfo
.
bytes
=
s
->
dma_dac
.
total_bytes
;
spin_lock_irqsave
(
&
s
->
lock
,
flags
);
count
=
s
->
dma_dac
.
count
;
cinfo
.
bytes
=
s
->
dma_dac
.
total_bytes
;
if
(
!
s
->
dma_dac
.
stopped
)
{
count
=
s
->
dma_dac
.
count
;
diff
=
s
->
dma_dac
.
fragsize
-
inw
(
s
->
io
+
IT_AC_CAPCDL
);
if
(
!
s
->
dma_dac
.
stopped
)
{
count
-=
diff
;
diff
=
s
->
dma_dac
.
fragsize
-
inw
(
s
->
io
+
IT_AC_CAPCDL
);
cinfo
.
bytes
+=
diff
;
count
-=
diff
;
cinfo
.
ptr
=
inl
(
s
->
io
+
s
->
dma_dac
.
curBufPtr
)
-
s
->
dma_dac
.
dmaaddr
;
cinfo
.
bytes
+=
diff
;
}
else
cinfo
.
ptr
=
inl
(
s
->
io
+
s
->
dma_dac
.
curBufPtr
)
-
cinfo
.
ptr
=
virt_to_bus
(
s
->
dma_dac
.
nextOut
)
-
s
->
dma_dac
.
dmaaddr
;
s
->
dma_dac
.
dmaaddr
;
if
(
s
->
dma_dac
.
mapped
)
}
else
s
->
dma_dac
.
count
&=
s
->
dma_dac
.
fragsize
-
1
;
cinfo
.
ptr
=
virt_to_bus
(
s
->
dma_dac
.
nextOut
)
-
spin_unlock_irqrestore
(
&
s
->
lock
,
flags
);
s
->
dma_dac
.
dmaaddr
;
if
(
count
<
0
)
if
(
s
->
dma_dac
.
mapped
)
count
=
0
;
s
->
dma_dac
.
count
&=
s
->
dma_dac
.
fragsize
-
1
;
cinfo
.
blocks
=
count
>>
s
->
dma_dac
.
fragshift
;
spin_unlock_irqrestore
(
&
s
->
lock
,
flags
);
if
(
copy_to_user
((
void
*
)
arg
,
&
cinfo
,
sizeof
(
cinfo
)))
if
(
count
<
0
)
return
-
EFAULT
;
count
=
0
;
return
0
;
cinfo
.
blocks
=
count
>>
s
->
dma_dac
.
fragshift
;
return
copy_to_user
((
void
*
)
arg
,
&
cinfo
,
sizeof
(
cinfo
));
case
SNDCTL_DSP_GETBLKSIZE
:
if
(
file
->
f_mode
&
FMODE_WRITE
)
case
SNDCTL_DSP_GETBLKSIZE
:
return
put_user
(
s
->
dma_dac
.
fragsize
,
(
int
*
)
arg
);
if
(
file
->
f_mode
&
FMODE_WRITE
)
else
return
put_user
(
s
->
dma_dac
.
fragsize
,
(
int
*
)
arg
);
return
put_user
(
s
->
dma_adc
.
fragsize
,
(
int
*
)
arg
);
else
return
put_user
(
s
->
dma_adc
.
fragsize
,
(
int
*
)
arg
);
case
SNDCTL_DSP_SETFRAGMENT
:
if
(
get_user
(
val
,
(
int
*
)
arg
))
case
SNDCTL_DSP_SETFRAGMENT
:
return
-
EFAULT
;
if
(
get_user
(
val
,
(
int
*
)
arg
))
if
(
file
->
f_mode
&
FMODE_READ
)
{
return
-
EFAULT
;
stop_adc
(
s
);
if
(
file
->
f_mode
&
FMODE_READ
)
{
s
->
dma_adc
.
ossfragshift
=
val
&
0xffff
;
stop_adc
(
s
);
s
->
dma_adc
.
ossmaxfrags
=
(
val
>>
16
)
&
0xffff
;
s
->
dma_adc
.
ossfragshift
=
val
&
0xffff
;
if
(
s
->
dma_adc
.
ossfragshift
<
4
)
s
->
dma_adc
.
ossmaxfrags
=
(
val
>>
16
)
&
0xffff
;
s
->
dma_adc
.
ossfragshift
=
4
;
if
(
s
->
dma_adc
.
ossfragshift
<
4
)
if
(
s
->
dma_adc
.
ossfragshift
>
15
)
s
->
dma_adc
.
ossfragshift
=
4
;
s
->
dma_adc
.
ossfragshift
=
15
;
if
(
s
->
dma_adc
.
ossfragshift
>
15
)
if
(
s
->
dma_adc
.
ossmaxfrags
<
4
)
s
->
dma_adc
.
ossfragshift
=
15
;
s
->
dma_adc
.
ossmaxfrags
=
4
;
if
(
s
->
dma_adc
.
ossmaxfrags
<
4
)
if
((
ret
=
prog_dmabuf_adc
(
s
)))
s
->
dma_adc
.
ossmaxfrags
=
4
;
return
ret
;
if
((
ret
=
prog_dmabuf_adc
(
s
)))
}
return
ret
;
if
(
file
->
f_mode
&
FMODE_WRITE
)
{
}
stop_dac
(
s
);
if
(
file
->
f_mode
&
FMODE_WRITE
)
{
s
->
dma_dac
.
ossfragshift
=
val
&
0xffff
;
stop_dac
(
s
);
s
->
dma_dac
.
ossmaxfrags
=
(
val
>>
16
)
&
0xffff
;
s
->
dma_dac
.
ossfragshift
=
val
&
0xffff
;
if
(
s
->
dma_dac
.
ossfragshift
<
4
)
s
->
dma_dac
.
ossmaxfrags
=
(
val
>>
16
)
&
0xffff
;
s
->
dma_dac
.
ossfragshift
=
4
;
if
(
s
->
dma_dac
.
ossfragshift
<
4
)
if
(
s
->
dma_dac
.
ossfragshift
>
15
)
s
->
dma_dac
.
ossfragshift
=
4
;
s
->
dma_dac
.
ossfragshift
=
15
;
if
(
s
->
dma_dac
.
ossfragshift
>
15
)
if
(
s
->
dma_dac
.
ossmaxfrags
<
4
)
s
->
dma_dac
.
ossfragshift
=
15
;
s
->
dma_dac
.
ossmaxfrags
=
4
;
if
(
s
->
dma_dac
.
ossmaxfrags
<
4
)
if
((
ret
=
prog_dmabuf_dac
(
s
)))
s
->
dma_dac
.
ossmaxfrags
=
4
;
return
ret
;
if
((
ret
=
prog_dmabuf_dac
(
s
)))
}
return
ret
;
return
0
;
}
return
0
;
case
SNDCTL_DSP_SUBDIVIDE
:
if
((
file
->
f_mode
&
FMODE_READ
&&
s
->
dma_adc
.
subdivision
)
||
case
SNDCTL_DSP_SUBDIVIDE
:
(
file
->
f_mode
&
FMODE_WRITE
&&
s
->
dma_dac
.
subdivision
))
if
((
file
->
f_mode
&
FMODE_READ
&&
s
->
dma_adc
.
subdivision
)
||
return
-
EINVAL
;
(
file
->
f_mode
&
FMODE_WRITE
&&
s
->
dma_dac
.
subdivision
))
if
(
get_user
(
val
,
(
int
*
)
arg
))
return
-
EINVAL
;
return
-
EFAULT
;
if
(
get_user
(
val
,
(
int
*
)
arg
))
if
(
val
!=
1
&&
val
!=
2
&&
val
!=
4
)
return
-
EFAULT
;
return
-
EINVAL
;
if
(
val
!=
1
&&
val
!=
2
&&
val
!=
4
)
if
(
file
->
f_mode
&
FMODE_READ
)
{
return
-
EINVAL
;
stop_adc
(
s
);
if
(
file
->
f_mode
&
FMODE_READ
)
{
s
->
dma_adc
.
subdivision
=
val
;
stop_adc
(
s
);
if
((
ret
=
prog_dmabuf_adc
(
s
)))
s
->
dma_adc
.
subdivision
=
val
;
return
ret
;
if
((
ret
=
prog_dmabuf_adc
(
s
)))
}
return
ret
;
if
(
file
->
f_mode
&
FMODE_WRITE
)
{
}
stop_dac
(
s
);
if
(
file
->
f_mode
&
FMODE_WRITE
)
{
s
->
dma_dac
.
subdivision
=
val
;
stop_dac
(
s
);
if
((
ret
=
prog_dmabuf_dac
(
s
)))
s
->
dma_dac
.
subdivision
=
val
;
return
ret
;
if
((
ret
=
prog_dmabuf_dac
(
s
)))
}
return
ret
;
return
0
;
}
return
0
;
case
SOUND_PCM_READ_RATE
:
case
SOUND_PCM_READ_RATE
:
return
put_user
((
file
->
f_mode
&
FMODE_READ
)
?
return
put_user
((
file
->
f_mode
&
FMODE_READ
)
?
s
->
adcrate
:
s
->
dacrate
,
(
int
*
)
arg
);
s
->
adcrate
:
s
->
dacrate
,
(
int
*
)
arg
);
case
SOUND_PCM_READ_CHANNELS
:
case
SOUND_PCM_READ_CHANNELS
:
if
(
file
->
f_mode
&
FMODE_READ
)
if
(
file
->
f_mode
&
FMODE_READ
)
return
put_user
((
s
->
capcc
&
CC_SM
)
?
2
:
1
,
(
int
*
)
arg
);
return
put_user
((
s
->
capcc
&
CC_SM
)
?
2
:
1
,
else
(
int
*
)
arg
);
return
put_user
((
s
->
pcc
&
CC_SM
)
?
2
:
1
,
(
int
*
)
arg
);
else
return
put_user
((
s
->
pcc
&
CC_SM
)
?
2
:
1
,
(
int
*
)
arg
);
case
SOUND_PCM_READ_BITS
:
case
SOUND_PCM_READ_BITS
:
if
(
file
->
f_mode
&
FMODE_READ
)
if
(
file
->
f_mode
&
FMODE_READ
)
return
put_user
((
s
->
capcc
&
CC_DF
)
?
16
:
8
,
(
int
*
)
arg
);
return
put_user
((
s
->
capcc
&
CC_DF
)
?
16
:
8
,
else
(
int
*
)
arg
);
return
put_user
((
s
->
pcc
&
CC_DF
)
?
16
:
8
,
(
int
*
)
arg
);
else
return
put_user
((
s
->
pcc
&
CC_DF
)
?
16
:
8
,
(
int
*
)
arg
);
case
SOUND_PCM_WRITE_FILTER
:
case
SOUND_PCM_WRITE_FILTER
:
case
SNDCTL_DSP_SETSYNCRO
:
case
SNDCTL_DSP_SETSYNCRO
:
case
SOUND_PCM_READ_FILTER
:
case
SOUND_PCM_READ_FILTER
:
return
-
EINVAL
;
return
-
EINVAL
;
}
}
return
mixdev_ioctl
(
&
s
->
codec
,
cmd
,
arg
);
return
mixdev_ioctl
(
s
->
codec
,
cmd
,
arg
);
}
}
static
int
it8172_open
(
struct
inode
*
inode
,
struct
file
*
file
)
static
int
it8172_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
{
int
minor
=
minor
(
inode
->
i_rdev
);
int
minor
=
MINOR
(
inode
->
i_rdev
);
DECLARE_WAITQUEUE
(
wait
,
current
);
DECLARE_WAITQUEUE
(
wait
,
current
);
unsigned
long
flags
;
unsigned
long
flags
;
struct
list_head
*
list
;
struct
list_head
*
list
;
struct
it8172_state
*
s
;
struct
it8172_state
*
s
;
int
ret
;
int
ret
;
for
(
list
=
devs
.
next
;
;
list
=
list
->
next
)
{
#ifdef IT8172_VERBOSE_DEBUG
if
(
list
==
&
devs
)
if
(
file
->
f_flags
&
O_NONBLOCK
)
return
-
ENODEV
;
dbg
(
__FUNCTION__
": non-blocking"
);
s
=
list_entry
(
list
,
struct
it8172_state
,
devs
);
else
if
(
!
((
s
->
dev_audio
^
minor
)
&
~
0xf
))
dbg
(
__FUNCTION__
": blocking"
);
break
;
#endif
}
file
->
private_data
=
s
;
for
(
list
=
devs
.
next
;
;
list
=
list
->
next
)
{
/* wait for device to become free */
if
(
list
==
&
devs
)
down
(
&
s
->
open_sem
);
return
-
ENODEV
;
while
(
s
->
open_mode
&
file
->
f_mode
)
{
s
=
list_entry
(
list
,
struct
it8172_state
,
devs
);
if
(
file
->
f_flags
&
O_NONBLOCK
)
{
if
(
!
((
s
->
dev_audio
^
minor
)
&
~
0xf
))
up
(
&
s
->
open_sem
);
break
;
return
-
EBUSY
;
}
}
add_wait_queue
(
&
s
->
open_wait
,
&
wait
);
file
->
private_data
=
s
;
__set_current_state
(
TASK_INTERRUPTIBLE
);
/* wait for device to become free */
up
(
&
s
->
open_sem
);
schedule
();
remove_wait_queue
(
&
s
->
open_wait
,
&
wait
);
set_current_state
(
TASK_RUNNING
);
if
(
signal_pending
(
current
))
return
-
ERESTARTSYS
;
down
(
&
s
->
open_sem
);
down
(
&
s
->
open_sem
);
}
while
(
s
->
open_mode
&
file
->
f_mode
)
{
if
(
file
->
f_flags
&
O_NONBLOCK
)
{
spin_lock_irqsave
(
&
s
->
lock
,
flags
);
up
(
&
s
->
open_sem
);
return
-
EBUSY
;
}
add_wait_queue
(
&
s
->
open_wait
,
&
wait
);
__set_current_state
(
TASK_INTERRUPTIBLE
);
up
(
&
s
->
open_sem
);
schedule
();
remove_wait_queue
(
&
s
->
open_wait
,
&
wait
);
set_current_state
(
TASK_RUNNING
);
if
(
signal_pending
(
current
))
return
-
ERESTARTSYS
;
down
(
&
s
->
open_sem
);
}
if
(
file
->
f_mode
&
FMODE_READ
)
{
spin_lock_irqsave
(
&
s
->
lock
,
flags
);
s
->
dma_adc
.
ossfragshift
=
s
->
dma_adc
.
ossmaxfrags
=
s
->
dma_adc
.
subdivision
=
s
->
dma_adc
.
total_bytes
=
0
;
s
->
capcc
&=
~
(
CC_SM
|
CC_DF
);
set_adc_rate
(
s
,
8000
);
if
((
minor
&
0xf
)
==
SND_DEV_DSP16
)
s
->
capcc
|=
CC_DF
;
outw
(
s
->
capcc
,
s
->
io
+
IT_AC_CAPCC
);
if
((
ret
=
prog_dmabuf_adc
(
s
)))
return
ret
;
}
if
(
file
->
f_mode
&
FMODE_WRITE
)
{
s
->
dma_dac
.
ossfragshift
=
s
->
dma_dac
.
ossmaxfrags
=
s
->
dma_dac
.
subdivision
=
s
->
dma_dac
.
total_bytes
=
0
;
s
->
pcc
&=
~
(
CC_SM
|
CC_DF
);
set_dac_rate
(
s
,
8000
);
if
((
minor
&
0xf
)
==
SND_DEV_DSP16
)
s
->
pcc
|=
CC_DF
;
outw
(
s
->
pcc
,
s
->
io
+
IT_AC_PCC
);
if
((
ret
=
prog_dmabuf_dac
(
s
)))
return
ret
;
}
spin_unlock_irqrestore
(
&
s
->
lock
,
flags
);
if
(
file
->
f_mode
&
FMODE_READ
)
{
s
->
dma_adc
.
ossfragshift
=
s
->
dma_adc
.
ossmaxfrags
=
s
->
dma_adc
.
subdivision
=
s
->
dma_adc
.
total_bytes
=
0
;
s
->
capcc
&=
~
(
CC_SM
|
CC_DF
);
set_adc_rate
(
s
,
8000
);
if
((
minor
&
0xf
)
==
SND_DEV_DSP16
)
s
->
capcc
|=
CC_DF
;
outw
(
s
->
capcc
,
s
->
io
+
IT_AC_CAPCC
);
if
((
ret
=
prog_dmabuf_adc
(
s
)))
{
spin_unlock_irqrestore
(
&
s
->
lock
,
flags
);
return
ret
;
}
}
if
(
file
->
f_mode
&
FMODE_WRITE
)
{
s
->
dma_dac
.
ossfragshift
=
s
->
dma_dac
.
ossmaxfrags
=
s
->
dma_dac
.
subdivision
=
s
->
dma_dac
.
total_bytes
=
0
;
s
->
pcc
&=
~
(
CC_SM
|
CC_DF
);
set_dac_rate
(
s
,
8000
);
if
((
minor
&
0xf
)
==
SND_DEV_DSP16
)
s
->
pcc
|=
CC_DF
;
outw
(
s
->
pcc
,
s
->
io
+
IT_AC_PCC
);
if
((
ret
=
prog_dmabuf_dac
(
s
)))
{
spin_unlock_irqrestore
(
&
s
->
lock
,
flags
);
return
ret
;
}
}
spin_unlock_irqrestore
(
&
s
->
lock
,
flags
);
s
->
open_mode
|=
file
->
f_mode
&
(
FMODE_READ
|
FMODE_WRITE
);
s
->
open_mode
|=
(
file
->
f_mode
&
(
FMODE_READ
|
FMODE_WRITE
)
);
up
(
&
s
->
open_sem
);
up
(
&
s
->
open_sem
);
return
0
;
return
0
;
}
}
static
int
it8172_release
(
struct
inode
*
inode
,
struct
file
*
file
)
static
int
it8172_release
(
struct
inode
*
inode
,
struct
file
*
file
)
{
{
struct
it8172_state
*
s
=
(
struct
it8172_state
*
)
file
->
private_data
;
struct
it8172_state
*
s
=
(
struct
it8172_state
*
)
file
->
private_data
;
lock_kernel
();
#ifdef IT8172_VERBOSE_DEBUG
if
(
file
->
f_mode
&
FMODE_WRITE
)
dbg
(
__FUNCTION__
);
drain_dac
(
s
,
file
->
f_flags
&
O_NONBLOCK
);
#endif
down
(
&
s
->
open_sem
);
lock_kernel
();
if
(
file
->
f_mode
&
FMODE_WRITE
)
{
if
(
file
->
f_mode
&
FMODE_WRITE
)
stop_dac
(
s
);
drain_dac
(
s
,
file
->
f_flags
&
O_NONBLOCK
);
dealloc_dmabuf
(
s
,
&
s
->
dma_dac
);
down
(
&
s
->
open_sem
);
}
if
(
file
->
f_mode
&
FMODE_WRITE
)
{
if
(
file
->
f_mode
&
FMODE_READ
)
{
stop_dac
(
s
);
stop_adc
(
s
);
dealloc_dmabuf
(
s
,
&
s
->
dma_dac
);
dealloc_dmabuf
(
s
,
&
s
->
dma_adc
);
}
}
if
(
file
->
f_mode
&
FMODE_READ
)
{
s
->
open_mode
&=
(
~
file
->
f_mode
)
&
(
FMODE_READ
|
FMODE_WRITE
);
stop_adc
(
s
);
up
(
&
s
->
open_sem
);
dealloc_dmabuf
(
s
,
&
s
->
dma_adc
);
wake_up
(
&
s
->
open_wait
);
}
unlock_kernel
();
s
->
open_mode
&=
((
~
file
->
f_mode
)
&
(
FMODE_READ
|
FMODE_WRITE
));
return
0
;
up
(
&
s
->
open_sem
);
wake_up
(
&
s
->
open_wait
);
unlock_kernel
();
return
0
;
}
}
static
/*const*/
struct
file_operations
it8172_audio_fops
=
{
static
/*const*/
struct
file_operations
it8172_audio_fops
=
{
.
owner
=
THIS_MODULE
,
owner:
THIS_MODULE
,
.
llseek
=
no
_llseek
,
llseek:
it8172
_llseek
,
.
read
=
it8172_read
,
read:
it8172_read
,
.
write
=
it8172_write
,
write:
it8172_write
,
.
poll
=
it8172_poll
,
poll:
it8172_poll
,
.
ioctl
=
it8172_ioctl
,
ioctl:
it8172_ioctl
,
.
mmap
=
it8172_mmap
,
mmap:
it8172_mmap
,
.
open
=
it8172_open
,
open:
it8172_open
,
.
release
=
it8172_release
,
release:
it8172_release
,
};
};
...
@@ -1657,51 +1898,51 @@ static /*const*/ struct file_operations it8172_audio_fops = {
...
@@ -1657,51 +1898,51 @@ static /*const*/ struct file_operations it8172_audio_fops = {
static
int
proc_it8172_dump
(
char
*
buf
,
char
**
start
,
off_t
fpos
,
static
int
proc_it8172_dump
(
char
*
buf
,
char
**
start
,
off_t
fpos
,
int
length
,
int
*
eof
,
void
*
data
)
int
length
,
int
*
eof
,
void
*
data
)
{
{
struct
it8172_state
*
s
;
struct
it8172_state
*
s
;
int
cnt
,
len
=
0
;
int
cnt
,
len
=
0
;
if
(
list_empty
(
&
devs
))
if
(
list_empty
(
&
devs
))
return
0
;
return
0
;
s
=
list_entry
(
devs
.
next
,
struct
it8172_state
,
devs
);
s
=
list_entry
(
devs
.
next
,
struct
it8172_state
,
devs
);
/* print out header */
/* print out header */
len
+=
sprintf
(
buf
+
len
,
"
\n\t\t
IT8172 Audio Debug
\n\n
"
);
len
+=
sprintf
(
buf
+
len
,
"
\n\t\t
IT8172 Audio Debug
\n\n
"
);
// print out digital controller state
// print out digital controller state
len
+=
sprintf
(
buf
+
len
,
"IT8172 Audio Controller registers
\n
"
);
len
+=
sprintf
(
buf
+
len
,
"IT8172 Audio Controller registers
\n
"
);
len
+=
sprintf
(
buf
+
len
,
"---------------------------------
\n
"
);
len
+=
sprintf
(
buf
+
len
,
"---------------------------------
\n
"
);
cnt
=
0
;
cnt
=
0
;
while
(
cnt
<
0x72
)
{
while
(
cnt
<
0x72
)
{
if
(
cnt
==
IT_AC_PCB1STA
||
cnt
==
IT_AC_PCB2STA
||
if
(
cnt
==
IT_AC_PCB1STA
||
cnt
==
IT_AC_PCB2STA
||
cnt
==
IT_AC_CAPB1STA
||
cnt
==
IT_AC_CAPB2STA
||
cnt
==
IT_AC_CAPB1STA
||
cnt
==
IT_AC_CAPB2STA
||
cnt
==
IT_AC_PFDP
)
{
cnt
==
IT_AC_PFDP
)
{
len
+=
sprintf
(
buf
+
len
,
"reg %02x = %08x
\n
"
,
len
+=
sprintf
(
buf
+
len
,
"reg %02x = %08x
\n
"
,
cnt
,
inl
(
s
->
io
+
cnt
));
cnt
,
inl
(
s
->
io
+
cnt
));
cnt
+=
4
;
cnt
+=
4
;
}
else
{
}
else
{
len
+=
sprintf
(
buf
+
len
,
"reg %02x = %04x
\n
"
,
len
+=
sprintf
(
buf
+
len
,
"reg %02x = %04x
\n
"
,
cnt
,
inw
(
s
->
io
+
cnt
));
cnt
,
inw
(
s
->
io
+
cnt
));
cnt
+=
2
;
cnt
+=
2
;
}
}
}
}
/* print out CODEC state */
/* print out CODEC state */
len
+=
sprintf
(
buf
+
len
,
"
\n
AC97 CODEC registers
\n
"
);
len
+=
sprintf
(
buf
+
len
,
"
\n
AC97 CODEC registers
\n
"
);
len
+=
sprintf
(
buf
+
len
,
"----------------------
\n
"
);
len
+=
sprintf
(
buf
+
len
,
"----------------------
\n
"
);
for
(
cnt
=
0
;
cnt
<=
0x7e
;
cnt
=
cnt
+
2
)
for
(
cnt
=
0
;
cnt
<=
0x7e
;
cnt
=
cnt
+
2
)
len
+=
sprintf
(
buf
+
len
,
"reg %02x = %04x
\n
"
,
len
+=
sprintf
(
buf
+
len
,
"reg %02x = %04x
\n
"
,
cnt
,
rdcodec
(
&
s
->
codec
,
cnt
));
cnt
,
rdcodec
(
s
->
codec
,
cnt
));
if
(
fpos
>=
len
){
if
(
fpos
>=
len
){
*
start
=
buf
;
*
start
=
buf
;
*
eof
=
1
;
return
0
;
}
*
start
=
buf
+
fpos
;
if
((
len
-=
fpos
)
>
length
)
return
length
;
*
eof
=
1
;
*
eof
=
1
;
return
0
;
return
len
;
}
*
start
=
buf
+
fpos
;
if
((
len
-=
fpos
)
>
length
)
return
length
;
*
eof
=
1
;
return
len
;
}
}
#endif
/* IT8172_DEBUG */
#endif
/* IT8172_DEBUG */
...
@@ -1712,244 +1953,307 @@ static int proc_it8172_dump (char *buf, char **start, off_t fpos,
...
@@ -1712,244 +1953,307 @@ static int proc_it8172_dump (char *buf, char **start, off_t fpos,
#define NR_DEVICE 5
#define NR_DEVICE 5
static
int
spdif
[
NR_DEVICE
]
=
{
0
,
};
static
int
spdif
[
NR_DEVICE
]
=
{
0
,
};
static
int
i2s_fmt
[
NR_DEVICE
]
=
{
0
,
};
static
unsigned
int
devindex
=
0
;
static
unsigned
int
devindex
=
0
;
MODULE_PARM
(
spdif
,
"1-"
__MODULE_STRING
(
NR_DEVICE
)
"i"
);
MODULE_PARM
(
spdif
,
"1-"
__MODULE_STRING
(
NR_DEVICE
)
"i"
);
MODULE_PARM_DESC
(
spdif
,
"if 1 the S/PDIF digital output is enabled"
);
MODULE_PARM_DESC
(
spdif
,
"if 1 the S/PDIF digital output is enabled"
);
MODULE_PARM
(
i2s_fmt
,
"1-"
__MODULE_STRING
(
NR_DEVICE
)
"i"
);
MODULE_PARM_DESC
(
i2s_fmt
,
"the format of I2S"
);
MODULE_AUTHOR
(
"Monta Vista Software, stevel@mvista.com"
);
MODULE_AUTHOR
(
"Monta Vista Software, stevel@mvista.com"
);
MODULE_DESCRIPTION
(
"IT8172 AudioPCI97 Driver"
);
MODULE_DESCRIPTION
(
"IT8172 Audio Driver"
);
MODULE_LICENSE
(
"GPL"
);
/* --------------------------------------------------------------------- */
/* --------------------------------------------------------------------- */
static
int
__devinit
it8172_probe
(
struct
pci_dev
*
pcidev
,
static
int
__devinit
it8172_probe
(
struct
pci_dev
*
pcidev
,
const
struct
pci_device_id
*
pciid
)
const
struct
pci_device_id
*
pciid
)
{
{
struct
it8172_state
*
s
;
struct
it8172_state
*
s
;
int
i
,
val
;
int
i
,
val
;
unsigned
short
pcisr
,
vol
;
unsigned
short
pcisr
,
vol
;
unsigned
char
legacy
,
imc
;
unsigned
char
legacy
,
imc
;
char
proc_str
[
80
];
char
proc_str
[
80
];
if
(
pcidev
->
irq
==
0
)
if
(
pcidev
->
irq
==
0
)
return
-
1
;
return
-
1
;
if
(
!
(
s
=
kmalloc
(
sizeof
(
struct
it8172_state
),
GFP_KERNEL
)))
{
if
(
!
(
s
=
kmalloc
(
sizeof
(
struct
it8172_state
),
GFP_KERNEL
)))
{
printk
(
KERN_ERR
PFX
"alloc of device struct failed
\n
"
);
err
(
"alloc of device struct failed"
);
return
-
1
;
return
-
1
;
}
}
memset
(
s
,
0
,
sizeof
(
struct
it8172_state
));
init_waitqueue_head
(
&
s
->
dma_adc
.
wait
);
init_waitqueue_head
(
&
s
->
dma_dac
.
wait
);
init_waitqueue_head
(
&
s
->
open_wait
);
init_MUTEX
(
&
s
->
open_sem
);
spin_lock_init
(
&
s
->
lock
);
s
->
dev
=
pcidev
;
s
->
io
=
pci_resource_start
(
pcidev
,
0
);
s
->
irq
=
pcidev
->
irq
;
s
->
vendor
=
pcidev
->
vendor
;
s
->
device
=
pcidev
->
device
;
pci_read_config_byte
(
pcidev
,
PCI_REVISION_ID
,
&
s
->
rev
);
memset
(
s
,
0
,
sizeof
(
struct
it8172_state
));
s
->
codec
=
ac97_alloc_codec
();
init_waitqueue_head
(
&
s
->
dma_adc
.
wait
);
if
(
s
->
codec
==
NULL
)
init_waitqueue_head
(
&
s
->
dma_dac
.
wait
);
goto
err_codec
;
init_waitqueue_head
(
&
s
->
open_wait
);
init_MUTEX
(
&
s
->
open_sem
);
s
->
codec
->
private_data
=
s
;
spin_lock_init
(
&
s
->
lock
);
s
->
codec
->
id
=
0
;
s
->
dev
=
pcidev
;
s
->
codec
->
codec_read
=
rdcodec
;
s
->
io
=
pci_resource_start
(
pcidev
,
0
);
s
->
codec
->
codec_write
=
wrcodec
;
s
->
irq
=
pcidev
->
irq
;
s
->
codec
->
codec_wait
=
waitcodec
;
s
->
vendor
=
pcidev
->
vendor
;
s
->
device
=
pcidev
->
device
;
if
(
!
request_region
(
s
->
io
,
pci_resource_len
(
pcidev
,
0
),
pci_read_config_byte
(
pcidev
,
PCI_REVISION_ID
,
&
s
->
rev
);
IT8172_MODULE_NAME
))
{
s
->
codec
.
private_data
=
s
;
err
(
"io ports %#lx->%#lx in use"
,
s
->
codec
.
id
=
0
;
s
->
io
,
s
->
io
+
pci_resource_len
(
pcidev
,
0
)
-
1
);
s
->
codec
.
codec_read
=
rdcodec
;
goto
err_region
;
s
->
codec
.
codec_write
=
wrcodec
;
}
s
->
codec
.
codec_wait
=
waitcodec
;
if
(
request_irq
(
s
->
irq
,
it8172_interrupt
,
SA_INTERRUPT
,
IT8172_MODULE_NAME
,
s
))
{
if
(
!
request_region
(
s
->
io
,
pci_resource_len
(
pcidev
,
0
),
err
(
"irq %u in use"
,
s
->
irq
);
IT8172_MODULE_NAME
))
{
goto
err_irq
;
printk
(
KERN_ERR
PFX
"io ports %#lx->%#lx in use
\n
"
,
}
s
->
io
,
s
->
io
+
pci_resource_len
(
pcidev
,
0
)
-
1
);
goto
err_region
;
info
(
"IO at %#lx, IRQ %d"
,
s
->
io
,
s
->
irq
);
}
if
(
request_irq
(
s
->
irq
,
it8172_interrupt
,
SA_INTERRUPT
,
/* register devices */
IT8172_MODULE_NAME
,
s
))
{
if
((
s
->
dev_audio
=
register_sound_dsp
(
&
it8172_audio_fops
,
-
1
))
<
0
)
printk
(
KERN_ERR
PFX
"irq %u in use
\n
"
,
s
->
irq
);
goto
err_dev1
;
goto
err_irq
;
if
((
s
->
codec
->
dev_mixer
=
}
register_sound_mixer
(
&
it8172_mixer_fops
,
-
1
))
<
0
)
goto
err_dev2
;
printk
(
KERN_INFO
PFX
"IO at %#lx, IRQ %d
\n
"
,
s
->
io
,
s
->
irq
);
/* register devices */
if
((
s
->
dev_audio
=
register_sound_dsp
(
&
it8172_audio_fops
,
-
1
))
<
0
)
goto
err_dev1
;
if
((
s
->
codec
.
dev_mixer
=
register_sound_mixer
(
&
it8172_mixer_fops
,
-
1
))
<
0
)
goto
err_dev2
;
#ifdef IT8172_DEBUG
#ifdef IT8172_DEBUG
/* ini
tialize the debug proc device */
/* in
tialize the debug proc device */
s
->
ps
=
create_proc_read_entry
(
IT8172_MODULE_NAME
,
0
,
NULL
,
s
->
ps
=
create_proc_read_entry
(
IT8172_MODULE_NAME
,
0
,
NULL
,
proc_it8172_dump
,
NULL
);
proc_it8172_dump
,
NULL
);
#endif
/* IT8172_DEBUG */
#endif
/* IT8172_DEBUG */
/*
/*
* Reset the Audio device using the IT8172 PCI Reset register. This
* Reset the Audio device using the IT8172 PCI Reset register. This
* creates an audible double click on a speaker connected to Line-out.
* creates an audible double click on a speaker connected to Line-out.
*/
*/
IT_IO_READ16
(
IT_PM_PCISR
,
pcisr
);
pcisr
|=
IT_PM_PCISR_ACSR
;
IT_IO_WRITE16
(
IT_PM_PCISR
,
pcisr
);
/* wait up to 100msec for reset to complete */
for
(
i
=
0
;
pcisr
&
IT_PM_PCISR_ACSR
;
i
++
)
{
it8172_delay
(
10
);
if
(
i
==
10
)
break
;
IT_IO_READ16
(
IT_PM_PCISR
,
pcisr
);
IT_IO_READ16
(
IT_PM_PCISR
,
pcisr
);
}
pcisr
|=
IT_PM_PCISR_ACSR
;
if
(
i
==
10
)
{
IT_IO_WRITE16
(
IT_PM_PCISR
,
pcisr
);
printk
(
KERN_ERR
PFX
"chip reset timeout!
\n
"
);
/* wait up to 100msec for reset to complete */
goto
err_dev3
;
for
(
i
=
0
;
pcisr
&
IT_PM_PCISR_ACSR
;
i
++
)
{
}
it8172_delay
(
10
);
if
(
i
==
10
)
break
;
IT_IO_READ16
(
IT_PM_PCISR
,
pcisr
);
}
if
(
i
==
10
)
{
err
(
"chip reset timeout!"
);
goto
err_dev3
;
}
/* enable pci io and bus mastering */
/* enable pci io and bus mastering */
if
(
pci_enable_device
(
pcidev
))
if
(
pci_enable_device
(
pcidev
))
goto
err_dev3
;
goto
err_dev3
;
pci_set_master
(
pcidev
);
pci_set_master
(
pcidev
);
/* get out of legacy mode */
/* get out of legacy mode */
pci_read_config_byte
(
pcidev
,
0x40
,
&
legacy
);
pci_read_config_byte
(
pcidev
,
0x40
,
&
legacy
);
pci_write_config_byte
(
pcidev
,
0x40
,
legacy
&
~
1
);
pci_write_config_byte
(
pcidev
,
0x40
,
legacy
&
~
1
);
s
->
spdif_volume
=
-
1
;
s
->
spdif_volume
=
-
1
;
/* check to see if s/pdif mode is being requested */
/* check to see if s/pdif mode is being requested */
if
(
spdif
[
devindex
])
{
if
(
spdif
[
devindex
])
{
printk
(
KERN_INFO
PFX
"enabling S/PDIF output
\n
"
);
info
(
"enabling S/PDIF output
"
);
s
->
spdif_volume
=
0
;
s
->
spdif_volume
=
0
;
outb
(
GC_SOE
,
s
->
io
+
IT_AC_GC
);
outb
(
GC_SOE
,
s
->
io
+
IT_AC_GC
);
}
else
{
}
else
{
printk
(
KERN_INFO
PFX
"disabling S/PDIF output
\n
"
);
info
(
"disabling S/PDIF output
"
);
outb
(
0
,
s
->
io
+
IT_AC_GC
);
outb
(
0
,
s
->
io
+
IT_AC_GC
);
}
}
/* cold reset the AC97 */
/* check to see if I2S format requested */
outw
(
CODECC_CR
,
s
->
io
+
IT_AC_CODECC
);
if
(
i2s_fmt
[
devindex
])
{
udelay
(
1000
);
info
(
"setting I2S format to 0x%02x"
,
i2s_fmt
[
devindex
]);
outw
(
0
,
s
->
io
+
IT_AC_CODECC
);
outb
(
i2s_fmt
[
devindex
],
s
->
io
+
IT_AC_I2SMC
);
/* need to delay around 500msec(bleech) to give
}
else
{
some CODECs enough time to wakeup */
outb
(
I2SMC_I2SF_I2S
,
s
->
io
+
IT_AC_I2SMC
);
it8172_delay
(
500
);
}
/* cold reset the AC97 */
outw
(
CODECC_CR
,
s
->
io
+
IT_AC_CODECC
);
udelay
(
1000
);
outw
(
0
,
s
->
io
+
IT_AC_CODECC
);
/* need to delay around 500msec(bleech) to give
some CODECs enough time to wakeup */
it8172_delay
(
500
);
/* AC97 warm reset to start the bitclk */
/* AC97 warm reset to start the bitclk */
outw
(
CODECC_WR
,
s
->
io
+
IT_AC_CODECC
);
outw
(
CODECC_WR
,
s
->
io
+
IT_AC_CODECC
);
udelay
(
1000
);
udelay
(
1000
);
outw
(
0
,
s
->
io
+
IT_AC_CODECC
);
outw
(
0
,
s
->
io
+
IT_AC_CODECC
);
/* codec init */
/* codec init */
if
(
!
ac97_probe_codec
(
&
s
->
codec
))
if
(
!
ac97_probe_codec
(
s
->
codec
))
goto
err_dev3
;
goto
err_dev3
;
/* Enable Volume button interrupts */
/* add I2S as allowable recording source */
imc
=
inb
(
s
->
io
+
IT_AC_IMC
);
s
->
codec
->
record_sources
|=
SOUND_MASK_I2S
;
outb
(
imc
&
~
IMC_VCIM
,
s
->
io
+
IT_AC_IMC
);
/* Enable Volume button interrupts */
/* Un-mute PCM and FM out on the controller */
imc
=
inb
(
s
->
io
+
IT_AC_IMC
);
vol
=
inw
(
s
->
io
+
IT_AC_PCMOV
);
outb
(
imc
&
~
IMC_VCIM
,
s
->
io
+
IT_AC_IMC
);
outw
(
vol
&
~
PCMOV_PCMOM
,
s
->
io
+
IT_AC_PCMOV
);
vol
=
inw
(
s
->
io
+
IT_AC_FMOV
);
/* Un-mute PCM and FM out on the controller */
outw
(
vol
&
~
FMOV_FMOM
,
s
->
io
+
IT_AC_FMOV
);
vol
=
inw
(
s
->
io
+
IT_AC_PCMOV
);
outw
(
vol
&
~
PCMOV_PCMOM
,
s
->
io
+
IT_AC_PCMOV
);
/* set channel defaults to 8-bit, mono, 8 Khz */
vol
=
inw
(
s
->
io
+
IT_AC_FMOV
);
s
->
pcc
=
0
;
outw
(
vol
&
~
FMOV_FMOM
,
s
->
io
+
IT_AC_FMOV
);
s
->
capcc
=
0
;
set_dac_rate
(
s
,
8000
);
/* set channel defaults to 8-bit, mono, 8 Khz */
set_adc_rate
(
s
,
8000
);
s
->
pcc
=
0
;
s
->
capcc
=
0
;
/* set mic to be the recording source */
set_dac_rate
(
s
,
8000
);
val
=
SOUND_MASK_MIC
;
set_adc_rate
(
s
,
8000
);
mixdev_ioctl
(
&
s
->
codec
,
SOUND_MIXER_WRITE_RECSRC
,
(
unsigned
long
)
&
val
);
/* set mic to be the recording source */
/* mute master and PCM when in S/PDIF mode */
val
=
SOUND_MASK_MIC
;
if
(
s
->
spdif_volume
!=
-
1
)
{
mixdev_ioctl
(
s
->
codec
,
SOUND_MIXER_WRITE_RECSRC
,
val
=
0x0000
;
mixdev_ioctl
(
&
s
->
codec
,
SOUND_MIXER_WRITE_VOLUME
,
(
unsigned
long
)
&
val
);
mixdev_ioctl
(
&
s
->
codec
,
SOUND_MIXER_WRITE_PCM
,
(
unsigned
long
)
&
val
);
(
unsigned
long
)
&
val
);
}
/* mute AC'97 master and PCM when in S/PDIF mode */
if
(
s
->
spdif_volume
!=
-
1
)
{
val
=
0x0000
;
s
->
codec
->
mixer_ioctl
(
s
->
codec
,
SOUND_MIXER_WRITE_VOLUME
,
(
unsigned
long
)
&
val
);
s
->
codec
->
mixer_ioctl
(
s
->
codec
,
SOUND_MIXER_WRITE_PCM
,
(
unsigned
long
)
&
val
);
}
#ifdef IT8172_DEBUG
#ifdef IT8172_DEBUG
sprintf
(
proc_str
,
"driver/%s/%d/ac97"
,
IT8172_MODULE_NAME
,
s
->
codec
.
id
);
sprintf
(
proc_str
,
"driver/%s/%d/ac97"
,
IT8172_MODULE_NAME
,
s
->
ac97_ps
=
create_proc_read_entry
(
proc_str
,
0
,
NULL
,
s
->
codec
->
id
);
ac97_read_proc
,
&
s
->
codec
);
s
->
ac97_ps
=
create_proc_read_entry
(
proc_str
,
0
,
NULL
,
ac97_read_proc
,
s
->
codec
);
#endif
#endif
/* store it in the driver field */
/* store it in the driver field */
pci_set_drvdata
(
pcidev
,
s
);
pci_set_drvdata
(
pcidev
,
s
);
pcidev
->
dma_mask
=
0xffffffff
;
pcidev
->
dma_mask
=
0xffffffff
;
/* put it into driver list */
/* put it into driver list */
list_add_tail
(
&
s
->
devs
,
&
devs
);
list_add_tail
(
&
s
->
devs
,
&
devs
);
/* increment devindex */
/* increment devindex */
if
(
devindex
<
NR_DEVICE
-
1
)
if
(
devindex
<
NR_DEVICE
-
1
)
devindex
++
;
devindex
++
;
return
0
;
return
0
;
err_dev3:
err_dev3:
unregister_sound_mixer
(
s
->
codec
.
dev_mixer
);
unregister_sound_mixer
(
s
->
codec
->
dev_mixer
);
err_dev2:
err_dev2:
unregister_sound_dsp
(
s
->
dev_audio
);
unregister_sound_dsp
(
s
->
dev_audio
);
err_dev1:
err_dev1:
printk
(
KERN_ERR
PFX
"cannot register misc device
\n
"
);
err
(
"cannot register misc device
"
);
free_irq
(
s
->
irq
,
s
);
free_irq
(
s
->
irq
,
s
);
err_irq:
err_irq:
release_region
(
s
->
io
,
pci_resource_len
(
pcidev
,
0
));
release_region
(
s
->
io
,
pci_resource_len
(
pcidev
,
0
));
err_region:
err_region:
kfree
(
s
);
ac97_release_codec
(
s
->
codec
);
return
-
1
;
err_codec:
kfree
(
s
);
return
-
1
;
}
}
static
void
__devinit
it8172_remove
(
struct
pci_dev
*
dev
)
static
void
__devinit
it8172_remove
(
struct
pci_dev
*
dev
)
{
{
struct
it8172_state
*
s
=
pci_get_drvdata
(
dev
);
struct
it8172_state
*
s
=
pci_get_drvdata
(
dev
);
if
(
!
s
)
if
(
!
s
)
return
;
return
;
list_del
(
&
s
->
devs
);
list_del
(
&
s
->
devs
);
#ifdef IT8172_DEBUG
#ifdef IT8172_DEBUG
if
(
s
->
ps
)
if
(
s
->
ps
)
remove_proc_entry
(
IT8172_MODULE_NAME
,
NULL
);
remove_proc_entry
(
IT8172_MODULE_NAME
,
NULL
);
#endif
/* IT8172_DEBUG */
#endif
/* IT8172_DEBUG */
synchronize_irq
(
s
->
irq
);
synchronize_irq
();
free_irq
(
s
->
irq
,
s
);
free_irq
(
s
->
irq
,
s
);
release_region
(
s
->
io
,
pci_resource_len
(
dev
,
0
));
release_region
(
s
->
io
,
pci_resource_len
(
dev
,
0
));
unregister_sound_dsp
(
s
->
dev_audio
);
unregister_sound_dsp
(
s
->
dev_audio
);
unregister_sound_mixer
(
s
->
codec
.
dev_mixer
);
unregister_sound_mixer
(
s
->
codec
->
dev_mixer
);
kfree
(
s
);
ac97_codec_release
(
s
->
codec
);
pci_set_drvdata
(
dev
,
NULL
);
kfree
(
s
);
pci_set_drvdata
(
dev
,
NULL
);
}
}
static
struct
pci_device_id
id_table
[]
__devinitdata
=
{
static
struct
pci_device_id
id_table
[]
__devinitdata
=
{
{
PCI_VENDOR_ID_ITE
,
PCI_DEVICE_ID_ITE_IT8172G_AUDIO
,
PCI_ANY_ID
,
{
PCI_VENDOR_ID_ITE
,
PCI_DEVICE_ID_ITE_IT8172G_AUDIO
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
},
PCI_ANY_ID
,
0
,
0
},
{
0
,
}
{
0
,
}
};
};
MODULE_DEVICE_TABLE
(
pci
,
id_table
);
MODULE_DEVICE_TABLE
(
pci
,
id_table
);
static
struct
pci_driver
it8172_driver
=
{
static
struct
pci_driver
it8172_driver
=
{
.
name
=
IT8172_MODULE_NAME
,
name:
IT8172_MODULE_NAME
,
.
id_table
=
id_table
,
id_table:
id_table
,
.
probe
=
it8172_probe
,
probe:
it8172_probe
,
.
remove
=
it8172_remove
,
remove:
it8172_remove
};
};
static
int
__init
init_it8172
(
void
)
static
int
__init
init_it8172
(
void
)
{
{
printk
(
"version v0.26 time "
__TIME__
" "
__DATE__
"
\n
"
);
if
(
!
pci_present
())
/* No PCI bus in this machine! */
return
pci_module_init
(
&
it8172_driver
);
return
-
ENODEV
;
info
(
"version v0.5 time "
__TIME__
" "
__DATE__
);
return
pci_module_init
(
&
it8172_driver
);
}
}
static
void
__exit
cleanup_it8172
(
void
)
static
void
__exit
cleanup_it8172
(
void
)
{
{
printk
(
KERN_INFO
PFX
"unloading
\n
"
);
info
(
"unloading
"
);
pci_unregister_driver
(
&
it8172_driver
);
pci_unregister_driver
(
&
it8172_driver
);
}
}
module_init
(
init_it8172
);
module_init
(
init_it8172
);
module_exit
(
cleanup_it8172
);
module_exit
(
cleanup_it8172
);
/* --------------------------------------------------------------------- */
#ifndef MODULE
/* format is: it8172=[spdif],[i2s:<I2S format>] */
static
int
__init
it8172_setup
(
char
*
options
)
{
char
*
this_opt
;
static
unsigned
__initdata
nr_dev
=
0
;
if
(
nr_dev
>=
NR_DEVICE
)
return
0
;
if
(
!
options
||
!*
options
)
return
0
;
for
(
this_opt
=
strtok
(
options
,
","
);
this_opt
;
this_opt
=
strtok
(
NULL
,
","
))
{
if
(
!
strncmp
(
this_opt
,
"spdif"
,
5
))
{
spdif
[
nr_dev
]
=
1
;
}
else
if
(
!
strncmp
(
this_opt
,
"i2s:"
,
4
))
{
if
(
!
strncmp
(
this_opt
+
4
,
"dac"
,
3
))
i2s_fmt
[
nr_dev
]
=
I2SMC_I2SF_DAC
;
else
if
(
!
strncmp
(
this_opt
+
4
,
"adc"
,
3
))
i2s_fmt
[
nr_dev
]
=
I2SMC_I2SF_ADC
;
else
if
(
!
strncmp
(
this_opt
+
4
,
"i2s"
,
3
))
i2s_fmt
[
nr_dev
]
=
I2SMC_I2SF_I2S
;
}
}
nr_dev
++
;
return
1
;
}
__setup
(
"it8172="
,
it8172_setup
);
#endif
/* MODULE */
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment