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
5cb39380
Commit
5cb39380
authored
Nov 23, 2007
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Import 2.3.99pre7
parent
0f0078de
Changes
19
Hide whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
3676 additions
and
1405 deletions
+3676
-1405
Documentation/sound/via82cxxx.txt
Documentation/sound/via82cxxx.txt
+50
-37
Documentation/usb/ov511.txt
Documentation/usb/ov511.txt
+9
-2
drivers/cdrom/cdrom.c
drivers/cdrom/cdrom.c
+17
-15
drivers/ide/ide-cd.c
drivers/ide/ide-cd.c
+26
-20
drivers/ide/ide-cd.h
drivers/ide/ide-cd.h
+1
-11
drivers/net/starfire.c
drivers/net/starfire.c
+1
-1
drivers/sound/Config.in
drivers/sound/Config.in
+2
-1
drivers/sound/Makefile
drivers/sound/Makefile
+1
-1
drivers/sound/emu10k1/main.c
drivers/sound/emu10k1/main.c
+2
-2
drivers/sound/soundmodule.h
drivers/sound/soundmodule.h
+1
-1
drivers/sound/via82cxxx_audio.c
drivers/sound/via82cxxx_audio.c
+2240
-426
drivers/usb/ov511.c
drivers/usb/ov511.c
+1172
-799
drivers/usb/ov511.h
drivers/usb/ov511.h
+68
-49
drivers/video/clgenfb.c
drivers/video/clgenfb.c
+5
-4
drivers/video/vesafb.c
drivers/video/vesafb.c
+9
-2
fs/buffer.c
fs/buffer.c
+1
-3
include/linux/swap.h
include/linux/swap.h
+7
-2
mm/filemap.c
mm/filemap.c
+62
-25
mm/vmscan.c
mm/vmscan.c
+2
-4
No files found.
Documentation/sound/via82cxxx.txt
View file @
5cb39380
...
@@ -13,12 +13,11 @@ The via82cxxx audio driver found in the drivers/sound directory
...
@@ -13,12 +13,11 @@ The via82cxxx audio driver found in the drivers/sound directory
of the kernel source tree is a PCI audio driver for audio chips
of the kernel source tree is a PCI audio driver for audio chips
found on Via-based motherboards, such as the MVP4.
found on Via-based motherboards, such as the MVP4.
Currently the driver provides audio via SoundBlaster Pro compatibility,
Currently the driver exports the following features:
and MIDI via MPU-401 compatibility. An AC97 mixing device is also
supported, and is generally preferred over the SoundBlaster mixer.
IMPORTANT NOTE: Some users report that the SoundBlaster mixer does
* /dev/dsp and /dev/audio support
not work at all -- use the AC97 mixer if possible.
* 16-bit stereo PCM output channel
* AC97 mixer
Please send bug reports to the mailing list linux-via@gtf.org.
Please send bug reports to the mailing list linux-via@gtf.org.
To subscribe, e-mail majordomo@gtf.org with "subscribe linux-via" in the
To subscribe, e-mail majordomo@gtf.org with "subscribe linux-via" in the
...
@@ -27,7 +26,7 @@ body of the message.
...
@@ -27,7 +26,7 @@ body of the message.
Thanks
Thanks
------------------------------------------------------------------------
------------------------------------------------------------------------
Via for providing e-mail support, specs, and NDA'
s
source code.
Via for providing e-mail support, specs, and NDA'
d
source code.
MandrakeSoft for providing hacking time.
MandrakeSoft for providing hacking time.
...
@@ -40,15 +39,10 @@ Installation
...
@@ -40,15 +39,10 @@ Installation
If the driver is being statically compiled into the kernel, no
If the driver is being statically compiled into the kernel, no
configuration should be necessary.
configuration should be necessary.
If the driver is being compiled as a module, generally
two lines
must
If the driver is being compiled as a module, generally
one line
must
be added to your /etc/conf.modules (or /etc/modules.conf) file:
be added to your /etc/conf.modules (or /etc/modules.conf) file:
alias sound via82cxxx
alias sound via82cxxx_audio
options sb support=1
The second line is very important: it tells the required 'sb' module
not to load SoundBlaster support, but to instead let the Via driver
do so at a later time.
...
@@ -63,8 +57,8 @@ Some architecture remains for multiple cards, feel free to submit
...
@@ -63,8 +57,8 @@ Some architecture remains for multiple cards, feel free to submit
a patch to clean some of that up. Ideally,
a patch to clean some of that up. Ideally,
No consideration for SMP, this chipset is not known to be found on
No consideration for SMP, this chipset is not known to be found on
any SMP motherboards. However,
this will change when we start handling
any SMP motherboards. However,
spin_locks must be used anyway in order
our own interrupts in "native mode."
to handle interrupts correctly.
GNU indent formatting options: -kr -i8 -pcs
GNU indent formatting options: -kr -i8 -pcs
...
@@ -76,29 +70,17 @@ The following is an _incomplete_ list of motherboards supported by this
...
@@ -76,29 +70,17 @@ The following is an _incomplete_ list of motherboards supported by this
audio driver. If your motherboard (or notebook) is not listed here,
audio driver. If your motherboard (or notebook) is not listed here,
please e-mail the maintainer with details.
please e-mail the maintainer with details.
AOpen MX59 Pro (Apollo MVP4)
AOpen MX59 Pro
Compaq Presario 1247
The Future
Random Developer Notes / Comments
------------------------------------------------------------------------
------------------------------------------------------------------------
Via has graciously donated e-mail support and source code to help further
Via has graciously donated e-mail support and source code to help further
the development of this driver. Their assistance has been invaluable
the development of this driver. Their assistance has been invaluable
in the design and coding of the next major version of this driver.
in the design and coding of the next major version of this driver.
This audio chip supports a DirectSound(tm)-style hardware interface,
with a single 16-bit stereo input channel, and a single 16-bit stereo
output channel. Data is transferred to/from the hardware using
table-driven scatter-gather DMA buffers.
Work is currently underway to support this "native mode" of the chip.
When complete, SoundBlaster legacy mode will be completely removed.
After a round of testing, this code will become version 2.0.0.
Following the 2.0.0 release, the last major task to complete is
MIDI support. MPU-401 legacy support is available currently, but
not well tested at all.
The Via audio chip apparently provides a second PCM scatter-gather
The Via audio chip apparently provides a second PCM scatter-gather
DMA channel just for FM data, but does not have a full hardware MIDI
DMA channel just for FM data, but does not have a full hardware MIDI
processor. I haven't put much thought towards a solution here, but it
processor. I haven't put much thought towards a solution here, but it
...
@@ -109,11 +91,15 @@ support altogether and using the FM PCM channel as a second (input? output?)
...
@@ -109,11 +91,15 @@ support altogether and using the FM PCM channel as a second (input? output?)
General To-do List (patches/suggestions welcome)
General To-do List (patches/suggestions welcome)
------------------------------------------------------------------------
------------------------------------------------------------------------
Better docs
Recording support
Code review by sound guru(s)
mmap support
Native DSP audio driver using scatter-gather DMA, as described above
Other advanced ioctls
Better docs
Code review
Native MIDI driver, as described above
Native MIDI driver, as described above
...
@@ -121,8 +107,35 @@ Native MIDI driver, as described above
...
@@ -121,8 +107,35 @@ Native MIDI driver, as described above
Known bugs (patches/suggestions welcome)
Known bugs (patches/suggestions welcome)
------------------------------------------------------------------------
------------------------------------------------------------------------
1) Two MIDI devices are loaded by the sound driver. Eliminate one of them.
1) Volume too low on many systems. Workaround: use mixer program
such as xmixer to increase volume.
2) RealPlayer output very scratchy.
3) Applications which attempt to open the sound device in read/write
mode (O_RDWR) will fail. This is incorrect OSS behavior, but since
this driver will eventually support recording as well as playback,
we will be able to (in the future) support even broken programs which
unconditionally use O_RDWR.
Submitting a bug report
------------------------------------------------------------------------
Describe the application you were using to play/record sound, and how
to reproduce the problem.
Obtain the via-audio-diag diagnostics program from
http://gtf.org/garzik/drivers/via82cxxx/ and provide a dump of the
audio chip's registers while the problem is occurring. Sample command line:
./via-audio-diag -aps > diag-output.txt
Define "VIA_DEBUG" at the beginning of the driver, then capture and email
the kernel log output. This can be viewed in the system kernel log (if
enabled), or via the 'dmesg' program.
If you wish to increase the size of the buffer displayed by 'dmesg', then
change the LOG_BUF_LEN macro at the top of linux/kernel/printk.c, recompile
your kernel, and pass the "-s <size>" option to 'dmesg'.
2) Two mixer devices are loaded by the sound driver. Eliminate one of
them. At least one bug report says that SB mixer does not work at all,
only AC97 mixer.
Documentation/usb/ov511.txt
View file @
5cb39380
...
@@ -6,8 +6,11 @@ Author: Mark McClelland
...
@@ -6,8 +6,11 @@ Author: Mark McClelland
Homepage: http://alpha.dyndns.org/ov511
Homepage: http://alpha.dyndns.org/ov511
NEW IN THIS VERSION:
NEW IN THIS VERSION:
o Support for OV511+
o Improvements to sensor detection code
o Support for OV7620
o Added "i2c_detect_tries" and "aperture" parameters
o proc filesystem status support
o read() fixed partially
o code cleanups and minor fixes
INTRODUCTION:
INTRODUCTION:
...
@@ -151,11 +154,13 @@ WORKING FEATURES:
...
@@ -151,11 +154,13 @@ WORKING FEATURES:
o Monochrome
o Monochrome
o Setting/getting of saturation, contrast and brightness (no hue yet; only
o Setting/getting of saturation, contrast and brightness (no hue yet; only
works with OV7610, not the OV7620 or OV7620AE)
works with OV7610, not the OV7620 or OV7620AE)
o proc status reporting
EXPERIMENTAL FEATURES:
EXPERIMENTAL FEATURES:
o fix_rgb_offset: Sometimes works, but other times causes errors with xawtv and
o fix_rgb_offset: Sometimes works, but other times causes errors with xawtv and
corrupted frames.
corrupted frames.
o Snapshot mode (only works with some read() based apps; see below for more)
o Snapshot mode (only works with some read() based apps; see below for more)
o read() support
TODO:
TODO:
o Fix the noise / grainy image problem.
o Fix the noise / grainy image problem.
...
@@ -180,6 +185,8 @@ TODO:
...
@@ -180,6 +185,8 @@ TODO:
o Get rid of the memory management functions (put them in videodev.c??)
o Get rid of the memory management functions (put them in videodev.c??)
o Setting of contrast and brightness not working with 7620
o Setting of contrast and brightness not working with 7620
o Driver/camera state save/restore for when USB supports suspend/resume
o Driver/camera state save/restore for when USB supports suspend/resume
o Multiple cameras reportedly do not work simultaneously
o Problems with OHCI
HOW TO CONTACT ME:
HOW TO CONTACT ME:
...
...
drivers/cdrom/cdrom.c
View file @
5cb39380
...
@@ -199,11 +199,22 @@
...
@@ -199,11 +199,22 @@
home now.
home now.
-- Clear header length in mode_select unconditionally.
-- Clear header length in mode_select unconditionally.
-- Removed the register_disk() that was added, not needed here.
-- Removed the register_disk() that was added, not needed here.
3.08 May 1, 2000 - Jens Axboe <axboe@suse.de>
-- Fix direction flag in setup_send_key and setup_report_key. This
gave some SCSI adapters problems.
-- Always return -EROFS for write opens
-- Convert to module_init/module_exit style init and remove some
of the #ifdef MODULE stuff
-- Fix several dvd errors - DVD_LU_SEND_ASF should pass agid,
DVD_HOST_SEND_RPC_STATE did not set buffer size in cdb, and
dvd_do_auth passed uninitialized data to drive because init_cdrom_command
did not clear a 0 sized buffer.
-------------------------------------------------------------------------*/
-------------------------------------------------------------------------*/
#define REVISION "Revision: 3.0
7
"
#define REVISION "Revision: 3.0
8
"
#define VERSION "Id: cdrom.c 3.0
7 2000/02/02
"
#define VERSION "Id: cdrom.c 3.0
8 2000/05/01
"
/* I use an error-log mask to give fine grain control over the type of
/* I use an error-log mask to give fine grain control over the type of
messages dumped to the system logs. The available masks include: */
messages dumped to the system logs. The available masks include: */
...
@@ -432,17 +443,6 @@ struct cdrom_device_info *cdrom_find_device(kdev_t dev)
...
@@ -432,17 +443,6 @@ struct cdrom_device_info *cdrom_find_device(kdev_t dev)
while
(
cdi
!=
NULL
&&
cdi
->
dev
!=
dev
)
while
(
cdi
!=
NULL
&&
cdi
->
dev
!=
dev
)
cdi
=
cdi
->
next
;
cdi
=
cdi
->
next
;
/* we need to find the device this way when IDE devices such
* as /dev/hdc2 are opened. SCSI drives will be found above and
* so will /dev/hdc, for instance.
*/
if
(
cdi
==
NULL
)
{
kdev_t
cd_dev
=
MKDEV
(
MAJOR
(
dev
),
MINOR
(
dev
)
|
CD_PART_MASK
);
cdi
=
topCdromPtr
;
while
(
cdi
!=
NULL
&&
cdi
->
dev
!=
cd_dev
)
cdi
=
cdi
->
next
;
}
return
cdi
;
return
cdi
;
}
}
...
@@ -834,7 +834,7 @@ static int cdrom_media_changed(kdev_t dev)
...
@@ -834,7 +834,7 @@ static int cdrom_media_changed(kdev_t dev)
/* This talks to the VFS, which doesn't like errors - just 1 or 0.
/* This talks to the VFS, which doesn't like errors - just 1 or 0.
* Returning "0" is always safe (media hasn't been changed). Do that
* Returning "0" is always safe (media hasn't been changed). Do that
* if the low-level cdrom driver dosn't support media changed. */
* if the low-level cdrom driver dosn't support media changed. */
if
(
cdi
->
ops
->
media_changed
==
NULL
)
if
(
cdi
==
NULL
||
cdi
->
ops
->
media_changed
==
NULL
)
return
0
;
return
0
;
if
(
!
CDROM_CAN
(
CDC_MEDIA_CHANGED
))
if
(
!
CDROM_CAN
(
CDC_MEDIA_CHANGED
))
return
0
;
return
0
;
...
@@ -994,6 +994,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
...
@@ -994,6 +994,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
struct
cdrom_generic_command
cgc
;
struct
cdrom_generic_command
cgc
;
struct
cdrom_device_ops
*
cdo
=
cdi
->
ops
;
struct
cdrom_device_ops
*
cdo
=
cdi
->
ops
;
memset
(
buf
,
0
,
sizeof
(
buf
));
init_cdrom_command
(
&
cgc
,
buf
,
0
,
CGC_DATA_READ
);
init_cdrom_command
(
&
cgc
,
buf
,
0
,
CGC_DATA_READ
);
switch
(
ai
->
type
)
{
switch
(
ai
->
type
)
{
...
@@ -1052,7 +1053,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
...
@@ -1052,7 +1053,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
case
DVD_LU_SEND_ASF
:
case
DVD_LU_SEND_ASF
:
cdinfo
(
CD_DVD
,
"entering DVD_LU_SEND_ASF
\n
"
);
cdinfo
(
CD_DVD
,
"entering DVD_LU_SEND_ASF
\n
"
);
setup_report_key
(
&
cgc
,
ai
->
lsasf
.
a
sf
,
5
);
setup_report_key
(
&
cgc
,
ai
->
lsasf
.
a
gid
,
5
);
if
((
ret
=
cdo
->
generic_packet
(
cdi
,
&
cgc
)))
if
((
ret
=
cdo
->
generic_packet
(
cdi
,
&
cgc
)))
return
ret
;
return
ret
;
...
@@ -1113,6 +1114,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
...
@@ -1113,6 +1114,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
case
DVD_HOST_SEND_RPC_STATE
:
case
DVD_HOST_SEND_RPC_STATE
:
cdinfo
(
CD_DVD
,
"entering DVD_HOST_SEND_RPC_STATE
\n
"
);
cdinfo
(
CD_DVD
,
"entering DVD_HOST_SEND_RPC_STATE
\n
"
);
setup_send_key
(
&
cgc
,
0
,
6
);
setup_send_key
(
&
cgc
,
0
,
6
);
buf
[
1
]
=
6
;
buf
[
4
]
=
ai
->
hrpcs
.
pdrc
;
buf
[
4
]
=
ai
->
hrpcs
.
pdrc
;
if
((
ret
=
cdo
->
generic_packet
(
cdi
,
&
cgc
)))
if
((
ret
=
cdo
->
generic_packet
(
cdi
,
&
cgc
)))
...
...
drivers/ide/ide-cd.c
View file @
5cb39380
...
@@ -282,9 +282,12 @@
...
@@ -282,9 +282,12 @@
* - cdrom_read_capacity returns one frame too little.
* - cdrom_read_capacity returns one frame too little.
* - Fix real capacity reporting.
* - Fix real capacity reporting.
*
*
* 4.58 May 1, 2000 - Clean up ACER50 stuff.
* - Fix small problem with ide_cdrom_capacity
*
*************************************************************************/
*************************************************************************/
#define IDECD_VERSION "4.5
7
"
#define IDECD_VERSION "4.5
8
"
#include <linux/config.h>
#include <linux/config.h>
#include <linux/module.h>
#include <linux/module.h>
...
@@ -1521,7 +1524,7 @@ cdrom_lockdoor(ide_drive_t *drive, int lockflag, struct request_sense *sense)
...
@@ -1521,7 +1524,7 @@ cdrom_lockdoor(ide_drive_t *drive, int lockflag, struct request_sense *sense)
memset
(
&
pc
,
0
,
sizeof
(
pc
));
memset
(
&
pc
,
0
,
sizeof
(
pc
));
pc
.
sense
=
sense
;
pc
.
sense
=
sense
;
pc
.
c
[
0
]
=
GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL
;
pc
.
c
[
0
]
=
GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL
;
pc
.
c
[
4
]
=
(
lockflag
!=
0
)
;
pc
.
c
[
4
]
=
lockflag
?
3
:
0
;
stat
=
cdrom_queue_packet_command
(
drive
,
&
pc
);
stat
=
cdrom_queue_packet_command
(
drive
,
&
pc
);
}
}
...
@@ -1857,6 +1860,10 @@ static int ide_cdrom_packet(struct cdrom_device_info *cdi,
...
@@ -1857,6 +1860,10 @@ static int ide_cdrom_packet(struct cdrom_device_info *cdi,
pc
.
buffer
=
cgc
->
buffer
;
pc
.
buffer
=
cgc
->
buffer
;
pc
.
buflen
=
cgc
->
buflen
;
pc
.
buflen
=
cgc
->
buflen
;
cgc
->
stat
=
cdrom_queue_packet_command
(
drive
,
&
pc
);
cgc
->
stat
=
cdrom_queue_packet_command
(
drive
,
&
pc
);
/*
* FIXME: copy sense, don't just assign pointer!!
*/
cgc
->
sense
=
pc
.
sense
;
cgc
->
sense
=
pc
.
sense
;
return
cgc
->
stat
;
return
cgc
->
stat
;
...
@@ -2159,9 +2166,9 @@ static int ide_cdrom_register (ide_drive_t *drive, int nslots)
...
@@ -2159,9 +2166,9 @@ static int ide_cdrom_register (ide_drive_t *drive, int nslots)
{
{
struct
cdrom_info
*
info
=
drive
->
driver_data
;
struct
cdrom_info
*
info
=
drive
->
driver_data
;
struct
cdrom_device_info
*
devinfo
=
&
info
->
devinfo
;
struct
cdrom_device_info
*
devinfo
=
&
info
->
devinfo
;
int
minor
=
(
drive
->
select
.
b
.
unit
)
<<
PARTN_BITS
;
int
minor
=
(
drive
->
select
.
b
.
unit
)
<<
PARTN_BITS
;
devinfo
->
dev
=
MKDEV
(
HWIF
(
drive
)
->
major
,
minor
|
CD_PART_MASK
);
devinfo
->
dev
=
MKDEV
(
HWIF
(
drive
)
->
major
,
minor
);
devinfo
->
ops
=
&
ide_cdrom_dops
;
devinfo
->
ops
=
&
ide_cdrom_dops
;
devinfo
->
mask
=
0
;
devinfo
->
mask
=
0
;
*
(
int
*
)
&
devinfo
->
speed
=
CDROM_STATE_FLAGS
(
drive
)
->
current_speed
;
*
(
int
*
)
&
devinfo
->
speed
=
CDROM_STATE_FLAGS
(
drive
)
->
current_speed
;
...
@@ -2195,22 +2202,23 @@ static int ide_cdrom_register (ide_drive_t *drive, int nslots)
...
@@ -2195,22 +2202,23 @@ static int ide_cdrom_register (ide_drive_t *drive, int nslots)
return
register_cdrom
(
devinfo
);
return
register_cdrom
(
devinfo
);
}
}
/*
* the buffer struct used by ide_cdrom_get_capabilities()
*/
struct
get_capabilities_buf
{
char
pad
[
8
];
struct
atapi_capabilities_page
cap
;
char
extra_cap
[
4
];
};
static
static
int
ide_cdrom_get_capabilities
(
ide_drive_t
*
drive
,
struct
atapi_capabilities_page
*
cap
)
int
ide_cdrom_get_capabilities
(
ide_drive_t
*
drive
,
struct
atapi_capabilities_page
*
cap
)
{
{
struct
cdrom_info
*
info
=
drive
->
driver_data
;
struct
cdrom_info
*
info
=
drive
->
driver_data
;
struct
cdrom_device_info
*
cdi
=
&
info
->
devinfo
;
struct
cdrom_device_info
*
cdi
=
&
info
->
devinfo
;
struct
cdrom_generic_command
cgc
;
struct
cdrom_generic_command
cgc
;
int
stat
,
attempts
=
3
;
int
stat
,
attempts
=
3
,
size
=
sizeof
(
*
cap
);
/*
* ACER50 (and others?) require the full spec length mode sense
* page capabilities size, but older drives break.
*/
if
(
drive
->
id
)
{
if
(
!
(
!
strcmp
(
drive
->
id
->
model
,
"ATAPI CD ROM DRIVE 50X MAX"
)
||
!
strcmp
(
drive
->
id
->
model
,
"WPI CDS-32X"
)))
size
-=
sizeof
(
cap
->
pad
);
}
/* we have to cheat a little here. the packet will eventually
/* we have to cheat a little here. the packet will eventually
* be queued with ide_cdrom_packet(), which extracts the
* be queued with ide_cdrom_packet(), which extracts the
...
@@ -2220,7 +2228,7 @@ int ide_cdrom_get_capabilities(ide_drive_t *drive, struct atapi_capabilities_pag
...
@@ -2220,7 +2228,7 @@ int ide_cdrom_get_capabilities(ide_drive_t *drive, struct atapi_capabilities_pag
*/
*/
cdi
->
handle
=
(
ide_drive_t
*
)
drive
;
cdi
->
handle
=
(
ide_drive_t
*
)
drive
;
cdi
->
ops
=
&
ide_cdrom_dops
;
cdi
->
ops
=
&
ide_cdrom_dops
;
init_cdrom_command
(
&
cgc
,
cap
,
size
of
(
*
cap
)
,
CGC_DATA_UNKNOWN
);
init_cdrom_command
(
&
cgc
,
cap
,
size
,
CGC_DATA_UNKNOWN
);
do
{
/* we seem to get stat=0x01,err=0x00 the first time (??) */
do
{
/* we seem to get stat=0x01,err=0x00 the first time (??) */
stat
=
cdrom_mode_sense
(
cdi
,
&
cgc
,
GPMODE_CAPABILITIES_PAGE
,
0
);
stat
=
cdrom_mode_sense
(
cdi
,
&
cgc
,
GPMODE_CAPABILITIES_PAGE
,
0
);
if
(
!
stat
)
if
(
!
stat
)
...
@@ -2513,9 +2521,8 @@ void ide_cdrom_release (struct inode *inode, struct file *file,
...
@@ -2513,9 +2521,8 @@ void ide_cdrom_release (struct inode *inode, struct file *file,
static
static
int
ide_cdrom_check_media_change
(
ide_drive_t
*
drive
)
int
ide_cdrom_check_media_change
(
ide_drive_t
*
drive
)
{
{
return
cdrom_fops
.
check_media_change
return
cdrom_fops
.
check_media_change
(
MKDEV
(
HWIF
(
drive
)
->
major
,
(
MKDEV
(
HWIF
(
drive
)
->
major
,
(
drive
->
select
.
b
.
unit
)
<<
PARTN_BITS
));
(
drive
->
select
.
b
.
unit
)
<<
PARTN_BITS
));
}
}
static
static
...
@@ -2545,8 +2552,7 @@ unsigned long ide_cdrom_capacity (ide_drive_t *drive)
...
@@ -2545,8 +2552,7 @@ unsigned long ide_cdrom_capacity (ide_drive_t *drive)
{
{
unsigned
capacity
;
unsigned
capacity
;
capacity
=
cdrom_read_capacity
(
drive
,
&
capacity
,
NULL
);
return
cdrom_read_capacity
(
drive
,
&
capacity
,
NULL
)
?
0
:
capacity
*
SECTORS_PER_FRAME
;
return
capacity
?
0
:
capacity
*
SECTORS_PER_FRAME
;
}
}
static
static
...
...
drivers/ide/ide-cd.h
View file @
5cb39380
...
@@ -10,15 +10,6 @@
...
@@ -10,15 +10,6 @@
#include <linux/cdrom.h>
#include <linux/cdrom.h>
#include <asm/byteorder.h>
#include <asm/byteorder.h>
/*
* Apparently older drives have problems with filling out the entire
* mode_sense capability structure. Define this to 1 if your drive isn't
* probed correctly.
*/
#ifndef BROKEN_CAP_PAGE
#define BROKEN_CAP_PAGE 0
#endif
/* Turn this on to have the driver print out the meanings of the
/* Turn this on to have the driver print out the meanings of the
ATAPI error codes. This will use up additional kernel-space
ATAPI error codes. This will use up additional kernel-space
memory, though. */
memory, though. */
...
@@ -114,6 +105,7 @@ struct packet_command {
...
@@ -114,6 +105,7 @@ struct packet_command {
char
*
buffer
;
char
*
buffer
;
int
buflen
;
int
buflen
;
int
stat
;
int
stat
;
int
quiet
;
struct
request_sense
*
sense
;
struct
request_sense
*
sense
;
unsigned
char
c
[
12
];
unsigned
char
c
[
12
];
};
};
...
@@ -410,9 +402,7 @@ struct atapi_capabilities_page {
...
@@ -410,9 +402,7 @@ struct atapi_capabilities_page {
unsigned
short
buffer_size
;
unsigned
short
buffer_size
;
/* Current speed (in kB/s). */
/* Current speed (in kB/s). */
unsigned
short
curspeed
;
unsigned
short
curspeed
;
#if !BROKEN_CAP_PAGE
char
pad
[
4
];
char
pad
[
4
];
#endif
};
};
...
...
drivers/net/starfire.c
View file @
5cb39380
...
@@ -102,7 +102,7 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
...
@@ -102,7 +102,7 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
static
char
version1
[]
__devinitdata
=
static
char
version1
[]
__devinitdata
=
"starfire.c:v0.15+LK1.1.2 4/28/2000 Written by Donald Becker <becker@scyld.com>
\n
"
;
"starfire.c:v0.15+LK1.1.2 4/28/2000 Written by Donald Becker <becker@scyld.com>
\n
"
;
static
char
version2
[]
__devinitdata
=
static
char
version2
[]
__devinitdata
=
" U
n
dates and info at http://www.scyld.com/network/starfire.html
\n
"
;
" U
p
dates and info at http://www.scyld.com/network/starfire.html
\n
"
;
MODULE_AUTHOR
(
"Donald Becker <becker@scyld.com>"
);
MODULE_AUTHOR
(
"Donald Becker <becker@scyld.com>"
);
MODULE_DESCRIPTION
(
"Adaptec Starfire Ethernet driver"
);
MODULE_DESCRIPTION
(
"Adaptec Starfire Ethernet driver"
);
...
...
drivers/sound/Config.in
View file @
5cb39380
...
@@ -79,6 +79,8 @@ if [ "$CONFIG_SOUND_MSNDPIN" = "y" -o "$CONFIG_SOUND_MSNDCLAS" = "y" ]; then
...
@@ -79,6 +79,8 @@ if [ "$CONFIG_SOUND_MSNDPIN" = "y" -o "$CONFIG_SOUND_MSNDCLAS" = "y" ]; then
int 'MSND buffer size (kB)' CONFIG_MSND_FIFOSIZE 128
int 'MSND buffer size (kB)' CONFIG_MSND_FIFOSIZE 128
fi
fi
tristate ' VIA 82C686 Audio Codec' CONFIG_SOUND_VIA82CXXX
dep_tristate ' OSS sound modules' CONFIG_SOUND_OSS $CONFIG_SOUND
dep_tristate ' OSS sound modules' CONFIG_SOUND_OSS $CONFIG_SOUND
if [ "$CONFIG_SOUND_OSS" = "y" -o "$CONFIG_SOUND_OSS" = "m" ]; then
if [ "$CONFIG_SOUND_OSS" = "y" -o "$CONFIG_SOUND_OSS" = "m" ]; then
...
@@ -144,7 +146,6 @@ if [ "$CONFIG_SOUND_OSS" = "y" -o "$CONFIG_SOUND_OSS" = "m" ]; then
...
@@ -144,7 +146,6 @@ if [ "$CONFIG_SOUND_OSS" = "y" -o "$CONFIG_SOUND_OSS" = "m" ]; then
fi
fi
fi
fi
dep_tristate ' VIA 82C686 Audio Codec' CONFIG_SOUND_VIA82CXXX $CONFIG_SOUND_OSS
dep_tristate ' Yamaha FM synthesizer (YM3812/OPL-3) support' CONFIG_SOUND_YM3812 $CONFIG_SOUND_OSS
dep_tristate ' Yamaha FM synthesizer (YM3812/OPL-3) support' CONFIG_SOUND_YM3812 $CONFIG_SOUND_OSS
dep_tristate ' Yamaha OPL3-SA1 audio controller' CONFIG_SOUND_OPL3SA1 $CONFIG_SOUND_OSS
dep_tristate ' Yamaha OPL3-SA1 audio controller' CONFIG_SOUND_OPL3SA1 $CONFIG_SOUND_OSS
dep_tristate ' Yamaha OPL3-SA2, SA3, and SAx based PnP cards' CONFIG_SOUND_OPL3SA2 $CONFIG_SOUND_OSS
dep_tristate ' Yamaha OPL3-SA2, SA3, and SAx based PnP cards' CONFIG_SOUND_OPL3SA2 $CONFIG_SOUND_OSS
...
...
drivers/sound/Makefile
View file @
5cb39380
...
@@ -66,7 +66,7 @@ obj-$(CONFIG_SOUND_AD1816) += ad1816.o
...
@@ -66,7 +66,7 @@ obj-$(CONFIG_SOUND_AD1816) += ad1816.o
obj-$(CONFIG_SOUND_ACI_MIXER)
+=
aci.o
obj-$(CONFIG_SOUND_ACI_MIXER)
+=
aci.o
obj-$(CONFIG_SOUND_AWE32_SYNTH)
+=
awe_wave.o
obj-$(CONFIG_SOUND_AWE32_SYNTH)
+=
awe_wave.o
obj-$(CONFIG_SOUND_VIA82CXXX)
+=
via82cxxx_audio.o
sb_lib.o uart401.o ac97
.o
obj-$(CONFIG_SOUND_VIA82CXXX)
+=
via82cxxx_audio.o
ac97_codec
.o
obj-$(CONFIG_SOUND_MSNDCLAS)
+=
msnd.o msnd_classic.o
obj-$(CONFIG_SOUND_MSNDCLAS)
+=
msnd.o msnd_classic.o
obj-$(CONFIG_SOUND_MSNDPIN)
+=
msnd.o msnd_pinnacle.o
obj-$(CONFIG_SOUND_MSNDPIN)
+=
msnd.o msnd_pinnacle.o
obj-$(CONFIG_SOUND_VWSND)
+=
vwsnd.o
obj-$(CONFIG_SOUND_VWSND)
+=
vwsnd.o
...
...
drivers/sound/emu10k1/main.c
View file @
5cb39380
...
@@ -80,7 +80,7 @@ static char *card_names[] __devinitdata = {
...
@@ -80,7 +80,7 @@ static char *card_names[] __devinitdata = {
"EMU10K1"
,
"EMU10K1"
,
};
};
static
struct
pci_device_id
emu10k1_pci_tbl
[]
__initdata
=
{
static
struct
pci_device_id
emu10k1_pci_tbl
[]
=
{
{
PCI_VENDOR_ID_CREATIVE
,
PCI_DEVICE_ID_CREATIVE_EMU10K1
,
{
PCI_VENDOR_ID_CREATIVE
,
PCI_DEVICE_ID_CREATIVE_EMU10K1
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
EMU10K1
},
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
EMU10K1
},
{
0
,}
{
0
,}
...
@@ -763,7 +763,7 @@ static void __devexit emu10k1_remove(struct pci_dev *pci_dev)
...
@@ -763,7 +763,7 @@ static void __devexit emu10k1_remove(struct pci_dev *pci_dev)
MODULE_AUTHOR
(
"Bertrand Lee, Cai Ying. (Email to: emu10k1-devel@opensource.creative.com)"
);
MODULE_AUTHOR
(
"Bertrand Lee, Cai Ying. (Email to: emu10k1-devel@opensource.creative.com)"
);
MODULE_DESCRIPTION
(
"Creative EMU10K1 PCI Audio Driver v"
DRIVER_VERSION
"
\n
Copyright (C) 1999 Creative Technology Ltd."
);
MODULE_DESCRIPTION
(
"Creative EMU10K1 PCI Audio Driver v"
DRIVER_VERSION
"
\n
Copyright (C) 1999 Creative Technology Ltd."
);
static
struct
pci_driver
emu10k1_pci_driver
__initdata
=
{
static
struct
pci_driver
emu10k1_pci_driver
=
{
name:
"emu10k1"
,
name:
"emu10k1"
,
id_table:
emu10k1_pci_tbl
,
id_table:
emu10k1_pci_tbl
,
probe:
emu10k1_probe
,
probe:
emu10k1_probe
,
...
...
drivers/sound/soundmodule.h
View file @
5cb39380
...
@@ -26,4 +26,4 @@ static struct notifier_block sound_notifier=
...
@@ -26,4 +26,4 @@ static struct notifier_block sound_notifier=
0
0
};
};
#endif
#endif
/* _SOUNDMODULE_H */
drivers/sound/via82cxxx_audio.c
View file @
5cb39380
...
@@ -5,51 +5,45 @@
...
@@ -5,51 +5,45 @@
* Distributed under the GNU GENERAL PUBLIC LICENSE (GPL) Version 2.
* Distributed under the GNU GENERAL PUBLIC LICENSE (GPL) Version 2.
* See the "COPYING" file distributed with this software for more info.
* See the "COPYING" file distributed with this software for more info.
*
*
*
Documentation for this driver available as
*
For a list of known bugs (errata) and documentation,
*
linux/Documentation/sound/via82cxxx.txt
.
*
see via82cxxx.txt in linux/Documentation/sound
.
*
*
* Since the mixer is called from the OSS glue the kernel lock is always held
* on our AC97 mixing
*/
*/
#define VIA_VERSION "1.1.
2.1
"
#define VIA_VERSION "1.1.
5
"
#include <linux/module.h>
#include <linux/config.h>
#include <linux/config.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/pci.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/proc_fs.h>
#include <linux/spinlock.h>
#include <linux/sound.h>
#include <linux/soundcard.h>
#include <linux/ac97_codec.h>
#include <asm/io.h>
#include <asm/io.h>
#include <asm/delay.h>
#include <asm/uaccess.h>
#include <asm/hardirq.h>
#include "sound_config.h"
#include "sound_config.h"
#include "soundmodule.h"
#include "soundmodule.h"
#include "sb.h"
#include "ac97.h"
#include "mpu401.h"
#ifndef SOUND_LOCK
#define SOUND_LOCK do {} while (0)
#define SOUND_LOCK_END do {} while (0)
#endif
#
define VIA_DEBUG 0
/* define to 1
to enable debugging output and checks */
#
undef VIA_DEBUG
/* define
to enable debugging output and checks */
#if VIA_DEBUG
#if
def
VIA_DEBUG
/* note: prints function name for you */
/* note: prints function name for you */
#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
#else
#else
#define DPRINTK(fmt, args...)
#define DPRINTK(fmt, args...)
#endif
#endif
#define VIA_NDEBUG
0
/* define to 1
to disable lightweight runtime checks */
#define VIA_NDEBUG
/* define
to disable lightweight runtime checks */
#if VIA_NDEBUG
#if
def
VIA_NDEBUG
#define assert(expr)
#define assert(expr)
#else
#else
#define assert(expr) \
#define assert(expr) \
...
@@ -59,29 +53,109 @@
...
@@ -59,29 +53,109 @@
}
}
#endif
#endif
/* user switch: undefine to exclude /proc data */
#define VIA_PROC_FS 1
/* don't mess with this */
#ifndef CONFIG_PROC_FS
#undef VIA_PROC_FS
#endif
#define arraysize(x) (sizeof(x)/sizeof(*(x)))
#define arraysize(x) (sizeof(x)/sizeof(*(x)))
#define MAX_CARDS
2
#define MAX_CARDS
1
#define LINE_SIZE 10
#define LINE_SIZE 10
#define VIA_CARD_NAME "VIA 82Cxxx Audio driver " VIA_VERSION
#define VIA_CARD_NAME "VIA 82Cxxx Audio driver " VIA_VERSION
#define VIA_MODULE_NAME "via
_audio
"
#define VIA_MODULE_NAME "via
82cxxx
"
#define PFX VIA_MODULE_NAME ": "
#define PFX VIA_MODULE_NAME ": "
#define VIA_COUNTER_LIMIT 100000
#define VIA_COUNTER_LIMIT 100000
/* size of DMA buffers */
#define VIA_DMA_BUFFERS 16
#define VIA_DMA_BUF_SIZE PAGE_SIZE
/* 82C686 function 5 (audio codec) PCI configuration registers */
/* 82C686 function 5 (audio codec) PCI configuration registers */
#define VIA_ACLINK_CTRL 0x41
#define VIA_FUNC_ENABLE 0x42
#define VIA_FUNC_ENABLE 0x42
#define VIA_PNP_CONTROL 0x43
#define VIA_PNP_CONTROL 0x43
#define VIA_AC97_CTRL 0x80
#define VIA_FM_NMI_CTRL 0x48
/*
* controller base 0 (scatter-gather) registers
*
* NOTE: Via datasheet lists first channel as "read"
* channel and second channel as "write" channel.
* I changed the naming of the constants to be more
* clear than I felt the datasheet to be.
*/
#define VIA_BASE0_PCM_OUT_CHAN 0x00
/* output PCM to user */
#define VIA_BASE0_PCM_OUT_CHAN_STATUS 0x00
#define VIA_BASE0_PCM_OUT_CHAN_CTRL 0x01
#define VIA_BASE0_PCM_OUT_CHAN_TYPE 0x02
#define VIA_BASE0_PCM_OUT_BLOCK_COUNT 0x0C
#define VIA_BASE0_PCM_IN_CHAN 0x10
/* input PCM from user */
#define VIA_BASE0_PCM_IN_CHAN_STATUS 0x10
#define VIA_BASE0_PCM_IN_CHAN_CTRL 0x11
#define VIA_BASE0_PCM_IN_CHAN_TYPE 0x12
/* offsets from base */
#define VIA_PCM_STATUS 0x00
#define VIA_PCM_CONTROL 0x01
#define VIA_PCM_TYPE 0x02
#define VIA_PCM_TABLE_ADDR 0x04
/* XXX unused DMA channel for FM PCM data */
#define VIA_BASE0_FM_OUT_CHAN 0x20
#define VIA_BASE0_FM_OUT_CHAN_STATUS 0x20
#define VIA_BASE0_FM_OUT_CHAN_CTRL 0x21
#define VIA_BASE0_FM_OUT_CHAN_TYPE 0x22
#define VIA_BASE0_AC97_CTRL 0x80
#define VIA_BASE0_SGD_STATUS_SHADOW 0x84
#define VIA_BASE0_GPI_INT_ENABLE 0x8C
/* VIA_BASE0_AUDIO_xxx_CHAN_TYPE bits */
#define VIA_IRQ_ON_FLAG (1<<0)
/* int on each flagged scatter block */
#define VIA_IRQ_ON_EOL (1<<1)
/* int at end of scatter list */
#define VIA_INT_SEL_PCI_LAST_LINE_READ (0)
/* int at PCI read of last line */
#define VIA_INT_SEL_LAST_SAMPLE_SENT (1<<2)
/* int at last sample sent */
#define VIA_INT_SEL_ONE_LINE_LEFT (1<<3)
/* int at less than one line to send */
#define VIA_PCM_FMT_STEREO (1<<4)
/* PCM stereo format (bit clear == mono) */
#define VIA_PCM_FMT_16BIT (1<<5)
/* PCM 16-bit format (bit clear == 8-bit) */
#define VIA_PCM_FIFO (1<<6)
/* enable FIFO? documented as "reserved" */
#define VIA_RESTART_SGD_ON_EOL (1<<7)
/* restart scatter-gather at EOL */
#define VIA_PCM_FMT_MASK (VIA_PCM_FMT_STEREO|VIA_PCM_FMT_16BIT)
#define VIA_CHAN_TYPE_MASK (VIA_RESTART_SGD_ON_EOL | \
VIA_PCM_FIFO | \
VIA_IRQ_ON_FLAG | \
VIA_IRQ_ON_EOL)
#define VIA_CHAN_TYPE_INT_SELECT (VIA_INT_SEL_LAST_SAMPLE_SENT)
/* PCI configuration register bits and masks */
/* PCI configuration register bits and masks */
#define VIA_CR40_AC97_READY 0x01
#define VIA_CR40_AC97_READY 0x01
#define VIA_CR40_AC97_LOW_POWER 0x02
#define VIA_CR40_AC97_LOW_POWER 0x02
#define VIA_CR40_SECONDARY_READY 0x04
#define VIA_CR40_SECONDARY_READY 0x04
#define VIA_CR41_ACLINK_ENABLE 0x80
#define VIA_CR41_AC97_ENABLE 0x80
/* enable AC97 codec */
#define VIA_CR41_AC97_RESET 0x40
/* clear bit to reset AC97 */
#define VIA_CR41_AC97_WAKEUP 0x20
/* wake up from power-down mode */
#define VIA_CR41_AC97_SDO 0x10
/* force Serial Data Out (SDO) high */
#define VIA_CR41_VRA 0x08
/* enable variable sample rate */
#define VIA_CR41_PCM_ENABLE 0x04
/* AC Link SGD Read Channel PCM Data Output */
#define VIA_CR41_FM_PCM_ENABLE 0x02
/* AC Link FM Channel PCM Data Out */
#define VIA_CR41_SB_PCM_ENABLE 0x01
/* AC Link SB PCM Data Output */
#define VIA_CR41_BOOT_MASK (VIA_CR41_AC97_ENABLE | \
VIA_CR41_AC97_WAKEUP | \
VIA_CR41_AC97_SDO)
#define VIA_CR41_RUN_MASK (VIA_CR41_AC97_ENABLE | \
VIA_CR41_AC97_RESET | \
VIA_CR41_VRA | \
VIA_CR41_PCM_ENABLE)
#define VIA_CR42_SB_ENABLE 0x01
#define VIA_CR42_SB_ENABLE 0x01
#define VIA_CR42_MIDI_ENABLE 0x02
#define VIA_CR42_MIDI_ENABLE 0x02
...
@@ -91,272 +165,1937 @@
...
@@ -91,272 +165,1937 @@
#define VIA_CR44_SECOND_CODEC_SUPPORT (1 << 6)
#define VIA_CR44_SECOND_CODEC_SUPPORT (1 << 6)
#define VIA_CR44_AC_LINK_ACCESS (1 << 7)
#define VIA_CR44_AC_LINK_ACCESS (1 << 7)
#define VIA_CR48_FM_TRAP_TO_NMI (1 << 2)
/* controller base 0 register bitmasks */
#define VIA_INT_DISABLE_MASK (~(0x01|0x02))
#define VIA_SGD_STOPPED (1 << 2)
#define VIA_SGD_ACTIVE (1 << 7)
#define VIA_SGD_TERMINATE (1 << 6)
#define VIA_SGD_FLAG (1 << 0)
#define VIA_SGD_EOL (1 << 1)
#define VIA_SGD_START (1 << 7)
#define VIA_CR80_FIRST_CODEC 0
#define VIA_CR80_FIRST_CODEC 0
#define VIA_CR80_SECOND_CODEC (1 << 30)
#define VIA_CR80_SECOND_CODEC (1 << 30)
#define VIA_CR80_FIRST_CODEC_VALID (1 << 25)
#define VIA_CR80_FIRST_CODEC_VALID (1 << 25)
#define VIA_CR80_VALID (1 << 25)
#define VIA_CR80_SECOND_CODEC_VALID (1 << 27)
#define VIA_CR80_SECOND_CODEC_VALID (1 << 27)
#define VIA_CR80_BUSY (1 << 24)
#define VIA_CR80_BUSY (1 << 24)
#define VIA_CR80_READ_MODE (1 << 23)
#define VIA_CR83_BUSY (1)
#define VIA_CR83_FIRST_CODEC_VALID (1 << 1)
#define VIA_CR80_READ (1 << 23)
#define VIA_CR80_WRITE_MODE 0
#define VIA_CR80_WRITE_MODE 0
#define VIA_CR80_REG_IDX(idx) (((idx) & 0x7E) << 16)
#define VIA_CR80_REG_IDX(idx) ((((idx) & 0xFF) >> 1) << 16)
/* h r puff n stuff */
#define VIA_FMT_STEREO 0x01
#define VIA_FMT_16BIT 0x02
#define VIA_FMT_MASK 0x03
#define VIA_DAC_SHIFT 0
#define VIA_ADC_SHIFT 4
/* undocumented(?) values for setting rate, from Via's source */
#define VIA_SET_RATE_IN 0x00320000
/* set input rate */
#define VIA_SET_RATE_OUT 0x002c0000
/* set output rate */
/* scatter-gather DMA table entry, exactly as passed to hardware */
struct
via_sgd_table
{
u32
addr
;
u32
count
;
/* includes additional bits also */
};
#define VIA_EOL (1 << 31)
#define VIA_FLAG (1 << 30)
enum
via_channel_states
{
sgd_stopped
=
0
,
sgd_in_progress
=
1
,
};
struct
via_sgd_data
{
dma_addr_t
handle
;
volatile
void
*
cpuaddr
;
};
struct
via_channel
{
unsigned
rate
;
/* sample rate */
u8
pcm_fmt
;
/* VIA_PCM_FMT_xxx */
atomic_t
state
;
atomic_t
buf_in_use
;
atomic_t
next_buf
;
volatile
struct
via_sgd_table
*
sgtable
;
dma_addr_t
sgt_handle
;
struct
via_sgd_data
sgbuf
[
VIA_DMA_BUFFERS
];
wait_queue_head_t
wait
;
long
iobase
;
};
/* data stored for each chip */
struct
via_info
{
struct
via_info
{
struct
address_info
sb_data
;
struct
address_info
opl3_data
;
struct
pci_dev
*
pdev
;
struct
pci_dev
*
pdev
;
struct
ac97_hwint
ac97
;
long
baseaddr
;
int
mixer_oss_dev
;
int
have_ac97
;
struct
ac97_codec
ac97
;
spinlock_t
lock
;
int
card_num
;
/* unique card number, from 0 */
int
dev_dsp
;
/* /dev/dsp index from register_sound_dsp() */
unsigned
rev_h
:
1
;
wait_queue_head_t
open_wait
;
int
open_mode
;
struct
via_channel
ch_in
;
struct
via_channel
ch_out
;
};
/* number of cards, used for assigning unique numbers to cards */
static
unsigned
via_num_cards
=
0
;
/****************************************************************
*
* prototypes
*
*
*/
static
int
via_init_one
(
struct
pci_dev
*
dev
,
const
struct
pci_device_id
*
id
);
static
void
via_remove_one
(
struct
pci_dev
*
pdev
);
static
ssize_t
via_dsp_read
(
struct
file
*
file
,
char
*
buffer
,
size_t
count
,
loff_t
*
ppos
);
static
ssize_t
via_dsp_write
(
struct
file
*
file
,
const
char
*
buffer
,
size_t
count
,
loff_t
*
ppos
);
static
unsigned
int
via_dsp_poll
(
struct
file
*
file
,
struct
poll_table_struct
*
wait
);
static
int
via_dsp_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
);
static
int
via_dsp_open
(
struct
inode
*
inode
,
struct
file
*
file
);
static
int
via_dsp_release
(
struct
inode
*
inode
,
struct
file
*
file
);
static
u16
via_ac97_read_reg
(
struct
ac97_codec
*
codec
,
u8
reg
);
static
void
via_ac97_write_reg
(
struct
ac97_codec
*
codec
,
u8
reg
,
u16
value
);
static
u8
via_ac97_wait_idle
(
struct
via_info
*
card
);
static
u32
via_ac97_wait_valid
(
struct
via_info
*
card
);
static
void
via_chan_free
(
struct
via_info
*
card
,
struct
via_channel
*
chan
);
static
void
via_chan_clear
(
struct
via_channel
*
chan
);
static
void
via_chan_pcm_fmt
(
struct
via_info
*
card
,
struct
via_channel
*
chan
,
int
reset
);
/****************************************************************
*
* Various data the driver needs
*
*
*/
static
struct
pci_device_id
via_pci_tbl
[]
__initdata
=
{
{
PCI_VENDOR_ID_VIA
,
PCI_DEVICE_ID_VIA_82C686_5
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
0
},
{
0
,
},
};
};
static
struct
via_info
cards
[
MAX_CARDS
];
MODULE_DEVICE_TABLE
(
pci
,
via_pci_tbl
);
static
unsigned
num_cards
=
0
;
static
struct
pci_driver
via_driver
=
{
static
const
struct
{
name:
VIA_MODULE_NAME
,
int
revision
;
id_table:
via_pci_tbl
,
const
char
*
rev_name
;
probe:
via_init_one
,
}
via_chip_revs
[]
__initdata
=
{
remove:
via_remove_one
,
{
0x10
,
"A"
},
{
0x11
,
"B"
},
{
0x12
,
"C"
},
{
0x13
,
"D"
},
{
0x14
,
"E"
},
{
0x20
,
"H"
},
};
};
static
inline
void
via_ac97_write32
(
struct
pci_dev
*
pdev
,
int
port
,
u32
data
)
/****************************************************************
*
* Low-level base 0 register read/write helpers
*
*
*/
static
inline
void
via_chan_stop
(
int
iobase
)
{
if
(
inb
(
iobase
+
VIA_PCM_STATUS
)
&
VIA_SGD_ACTIVE
)
outb
(
VIA_SGD_TERMINATE
,
iobase
+
VIA_PCM_CONTROL
);
}
static
inline
void
via_chan_status_clear
(
int
iobase
)
{
u8
tmp
=
inb
(
iobase
+
VIA_PCM_STATUS
);
if
(
tmp
!=
0
)
outb
(
tmp
,
iobase
+
VIA_PCM_STATUS
);
}
static
inline
void
sg_begin
(
struct
via_channel
*
chan
)
{
outb
(
VIA_SGD_START
,
chan
->
iobase
+
VIA_PCM_CONTROL
);
}
static
inline
int
via_chan_bufs_in_use
(
struct
via_channel
*
chan
)
{
return
atomic_read
(
&
chan
->
next_buf
)
-
atomic_read
(
&
chan
->
buf_in_use
);
}
static
inline
int
via_chan_full
(
struct
via_channel
*
chan
)
{
return
(
via_chan_bufs_in_use
(
chan
)
==
VIA_DMA_BUFFERS
);
}
static
inline
int
via_chan_empty
(
struct
via_channel
*
chan
)
{
return
(
atomic_read
(
&
chan
->
next_buf
)
==
atomic_read
(
&
chan
->
buf_in_use
));
}
/****************************************************************
*
* Miscellaneous debris
*
*
*/
static
void
via_stop_everything
(
struct
via_info
*
card
)
{
DPRINTK
(
"ENTER
\n
"
);
assert
(
card
!=
NULL
);
/*
* terminate any existing operations on audio read/write channels
*/
via_chan_stop
(
card
->
baseaddr
+
VIA_BASE0_PCM_OUT_CHAN
);
via_chan_stop
(
card
->
baseaddr
+
VIA_BASE0_PCM_IN_CHAN
);
via_chan_stop
(
card
->
baseaddr
+
VIA_BASE0_FM_OUT_CHAN
);
/*
* clear any existing stops / flags (sanity check mainly)
*/
via_chan_status_clear
(
card
->
baseaddr
+
VIA_BASE0_PCM_OUT_CHAN
);
via_chan_status_clear
(
card
->
baseaddr
+
VIA_BASE0_PCM_IN_CHAN
);
via_chan_status_clear
(
card
->
baseaddr
+
VIA_BASE0_FM_OUT_CHAN
);
/*
* clear any enabled interrupt bits, reset to 8-bit mono PCM mode
*/
outb
(
0
,
card
->
baseaddr
+
VIA_BASE0_PCM_OUT_CHAN
);
outb
(
0
,
card
->
baseaddr
+
VIA_BASE0_PCM_IN_CHAN
);
outb
(
0
,
card
->
baseaddr
+
VIA_BASE0_FM_OUT_CHAN
);
DPRINTK
(
"EXIT
\n
"
);
}
static
int
via_set_rate
(
struct
via_info
*
card
,
unsigned
rate
,
int
inhale_deeply
)
{
#if 0
unsigned long flags;
u32 status;
u8 status8;
#endif
DPRINTK
(
"ENTER, rate = %d, inhale = %s
\n
"
,
rate
,
inhale_deeply
?
"yes"
:
"no"
);
if
(
rate
>
48000
)
rate
=
48000
;
if
(
rate
<
4000
)
rate
=
4000
;
#if 0
status8 = via_ac97_wait_idle (card);
if (status8 & VIA_CR83_BUSY) {
DPRINTK ("EXIT, status=0x%X, returning -EIO\n", status);
return -EIO;
}
if (inhale_deeply) {
card->ch_in.rate = rate;
spin_lock_irqsave (&card->lock, flags);
outl (VIA_SET_RATE_IN + rate,
card->baseaddr + VIA_BASE0_AC97_CTRL);
spin_unlock_irqrestore (&card->lock, flags);
} else {
card->ch_out.rate = rate;
spin_lock_irqsave (&card->lock, flags);
outl (VIA_SET_RATE_OUT + rate,
card->baseaddr + VIA_BASE0_AC97_CTRL);
spin_unlock_irqrestore (&card->lock, flags);
}
#else
via_ac97_write_reg
(
&
card
->
ac97
,
AC97_POWER_CONTROL
,
(
via_ac97_read_reg
(
&
card
->
ac97
,
AC97_POWER_CONTROL
)
&
~
0x0200
)
|
0x0200
);
via_ac97_write_reg
(
&
card
->
ac97
,
AC97_PCM_FRONT_DAC_RATE
,
rate
);
via_ac97_write_reg
(
&
card
->
ac97
,
AC97_POWER_CONTROL
,
via_ac97_read_reg
(
&
card
->
ac97
,
AC97_POWER_CONTROL
)
&
~
0x0200
);
#endif
DPRINTK
(
"EXIT, returning 0
\n
"
);
return
rate
;
}
static
inline
int
via_set_adc_rate
(
struct
via_info
*
card
,
int
rate
)
{
{
struct
resource
*
rsrc
=
&
pdev
->
resource
[
0
];
return
via_set_rate
(
card
,
rate
,
1
);
outw
((
u16
)
data
,
rsrc
->
start
+
port
);
outw
((
u16
)(
data
>>
16
),
rsrc
->
start
+
port
+
2
);
}
}
static
inline
u32
via_ac97_read32
(
struct
pci_dev
*
pdev
,
int
port
)
static
inline
int
via_set_dac_rate
(
struct
via_info
*
card
,
int
rate
)
{
{
struct
resource
*
rsrc
=
&
pdev
->
resource
[
0
];
return
via_set_rate
(
card
,
rate
,
0
);
return
((
u32
)
inw
(
rsrc
->
start
+
port
))
|
(((
u32
)
inw
(
rsrc
->
start
+
port
+
2
))
<<
16
);
}
}
/****************************************************************
/****************************************************************
*
*
*
Intel Audio Codec '97 interface
*
Channel-specific operations
*
*
*
*
*/
*/
static
inline
void
via_ac97_wait_idle
(
struct
pci_dev
*
pdev
)
static
int
via_chan_init
(
struct
via_info
*
card
,
struct
via_channel
*
chan
,
long
chan_ofs
)
{
{
u32
tmp
;
int
i
;
int
counter
=
VIA_COUNTER_LIMIT
;
unsigned
long
flags
;
DPRINTK
(
"ENTER
\n
"
);
DPRINTK
(
"ENTER
\n
"
);
assert
(
pdev
!=
NULL
);
memset
(
chan
,
0
,
sizeof
(
*
chan
));
/* alloc DMA-able memory for scatter-gather table */
chan
->
sgtable
=
pci_alloc_consistent
(
card
->
pdev
,
(
sizeof
(
struct
via_sgd_table
)
*
VIA_DMA_BUFFERS
),
&
chan
->
sgt_handle
);
if
(
!
chan
->
sgtable
)
{
printk
(
KERN_ERR
PFX
"DMA table alloc fail, aborting
\n
"
);
DPRINTK
(
"EXIT
\n
"
);
return
-
ENOMEM
;
}
memset
((
void
*
)
chan
->
sgtable
,
0
,
(
sizeof
(
struct
via_sgd_table
)
*
VIA_DMA_BUFFERS
));
/* alloc DMA-able memory for scatter-gather buffers */
for
(
i
=
0
;
i
<
VIA_DMA_BUFFERS
;
i
++
)
{
chan
->
sgbuf
[
i
].
cpuaddr
=
pci_alloc_consistent
(
card
->
pdev
,
VIA_DMA_BUF_SIZE
,
&
chan
->
sgbuf
[
i
].
handle
);
if
(
!
chan
->
sgbuf
[
i
].
cpuaddr
)
goto
err_out_nomem
;
if
(
i
<
(
VIA_DMA_BUFFERS
-
1
))
chan
->
sgtable
[
i
].
count
=
cpu_to_le32
(
VIA_DMA_BUF_SIZE
|
VIA_FLAG
);
else
chan
->
sgtable
[
i
].
count
=
cpu_to_le32
(
VIA_DMA_BUF_SIZE
|
VIA_EOL
);
chan
->
sgtable
[
i
].
addr
=
cpu_to_le32
(
chan
->
sgbuf
[
i
].
handle
);
#ifndef VIA_NDEBUG
memset
(
chan
->
sgbuf
[
i
].
cpuaddr
,
0xBC
,
VIA_DMA_BUF_SIZE
);
#endif
#if 1
DPRINTK
(
"dmabuf #%d (h=%lx, 32(h)=%lx, v2p=%lx, a=%p)
\n
"
,
i
,
(
long
)
chan
->
sgbuf
[
i
].
handle
,
(
long
)
chan
->
sgtable
[
i
].
addr
,
virt_to_phys
(
chan
->
sgbuf
[
i
].
cpuaddr
),
chan
->
sgbuf
[
i
].
cpuaddr
);
#endif
}
init_waitqueue_head
(
&
chan
->
wait
);
chan
->
pcm_fmt
=
VIA_PCM_FMT_MASK
;
chan
->
iobase
=
card
->
baseaddr
+
chan_ofs
;
spin_lock_irqsave
(
&
card
->
lock
,
flags
);
/* stop any existing channel output */
via_chan_clear
(
chan
);
via_chan_status_clear
(
chan
->
iobase
);
via_chan_pcm_fmt
(
card
,
chan
,
1
);
spin_unlock_irqrestore
(
&
card
->
lock
,
flags
);
/* set location of DMA-able scatter-gather info table */
DPRINTK
(
"outl (0x%X, 0x%04lX)
\n
"
,
cpu_to_le32
(
chan
->
sgt_handle
),
card
->
baseaddr
+
chan_ofs
+
VIA_PCM_TABLE_ADDR
);
via_ac97_wait_idle
(
card
);
outl
(
cpu_to_le32
(
chan
->
sgt_handle
),
card
->
baseaddr
+
chan_ofs
+
VIA_PCM_TABLE_ADDR
);
udelay
(
20
);
via_ac97_wait_idle
(
card
);
DPRINTK
(
"inl (0x%lX) = %x
\n
"
,
chan
->
iobase
+
VIA_PCM_TABLE_ADDR
,
inl
(
chan
->
iobase
+
VIA_PCM_TABLE_ADDR
));
DPRINTK
(
"EXIT
\n
"
);
return
0
;
err_out_nomem:
printk
(
KERN_ERR
PFX
"DMA buffer alloc fail, aborting
\n
"
);
via_chan_free
(
card
,
chan
);
DPRINTK
(
"EXIT
\n
"
);
return
-
ENOMEM
;
}
static
void
via_chan_free
(
struct
via_info
*
card
,
struct
via_channel
*
chan
)
{
int
i
;
unsigned
long
flags
;
DPRINTK
(
"ENTER
\n
"
);
synchronize_irq
();
spin_lock_irqsave
(
&
card
->
lock
,
flags
);
/* stop any existing channel output */
via_chan_stop
(
chan
->
iobase
);
via_chan_status_clear
(
chan
->
iobase
);
via_chan_pcm_fmt
(
card
,
chan
,
1
);
spin_unlock_irqrestore
(
&
card
->
lock
,
flags
);
/* zero location of DMA-able scatter-gather info table */
via_ac97_wait_idle
(
card
);
outl
(
0
,
chan
->
iobase
+
VIA_PCM_TABLE_ADDR
);
for
(
i
=
0
;
i
<
VIA_DMA_BUFFERS
;
i
++
)
if
(
chan
->
sgbuf
[
i
].
cpuaddr
)
{
pci_free_consistent
(
card
->
pdev
,
VIA_DMA_BUF_SIZE
,
(
void
*
)
chan
->
sgbuf
[
i
].
cpuaddr
,
chan
->
sgbuf
[
i
].
handle
);
chan
->
sgbuf
[
i
].
cpuaddr
=
NULL
;
chan
->
sgbuf
[
i
].
handle
=
0
;
}
if
(
chan
->
sgtable
)
{
pci_free_consistent
(
card
->
pdev
,
(
sizeof
(
struct
via_sgd_table
)
*
VIA_DMA_BUFFERS
),
(
void
*
)
chan
->
sgtable
,
chan
->
sgt_handle
);
chan
->
sgtable
=
NULL
;
}
DPRINTK
(
"EXIT
\n
"
);
}
static
void
via_chan_pcm_fmt
(
struct
via_info
*
card
,
struct
via_channel
*
chan
,
int
reset
)
{
DPRINTK
(
"ENTER, pcm_fmt=0x%02X, reset=%s
\n
"
,
chan
->
pcm_fmt
,
reset
?
"yes"
:
"no"
);
assert
(
card
!=
NULL
);
assert
(
chan
!=
NULL
);
if
(
reset
)
/* reset to 8-bit mono mode */
chan
->
pcm_fmt
=
0
;
/* enable interrupts on FLAG and EOL */
chan
->
pcm_fmt
|=
VIA_CHAN_TYPE_MASK
;
/* set interrupt select bits where applicable (PCM & FM out channels) */
if
(
chan
==
&
card
->
ch_out
)
chan
->
pcm_fmt
|=
VIA_CHAN_TYPE_INT_SELECT
;
outb
(
chan
->
pcm_fmt
,
chan
->
iobase
+
2
);
DPRINTK
(
"EXIT, pcm_fmt = 0x%02X, reg = 0x%02X
\n
"
,
chan
->
pcm_fmt
,
inb
(
chan
->
iobase
+
2
));
}
static
void
via_chan_clear
(
struct
via_channel
*
chan
)
{
via_chan_stop
(
chan
->
iobase
);
atomic_set
(
&
chan
->
state
,
sgd_stopped
);
atomic_set
(
&
chan
->
buf_in_use
,
0
);
atomic_set
(
&
chan
->
next_buf
,
0
);
}
static
int
via_chan_set_speed
(
struct
via_info
*
card
,
struct
via_channel
*
chan
,
int
val
)
{
DPRINTK
(
"ENTER, requested rate = %d
\n
"
,
val
);
via_chan_clear
(
chan
);
val
=
via_set_rate
(
card
,
val
,
chan
==
&
card
->
ch_in
);
DPRINTK
(
"EXIT, returning %d
\n
"
,
val
);
return
val
;
}
static
int
via_chan_set_fmt
(
struct
via_info
*
card
,
struct
via_channel
*
chan
,
int
val
)
{
DPRINTK
(
"ENTER, val=%s
\n
"
,
val
==
AFMT_U8
?
"AFMT_U8"
:
val
==
AFMT_S16_LE
?
"AFMT_S16_LE"
:
"unknown"
);
via_chan_clear
(
chan
);
switch
(
val
)
{
case
AFMT_U8
:
chan
->
pcm_fmt
&=
~
VIA_PCM_FMT_16BIT
;
via_chan_pcm_fmt
(
card
,
chan
,
0
);
break
;
case
AFMT_S16_LE
:
chan
->
pcm_fmt
|=
VIA_PCM_FMT_16BIT
;
via_chan_pcm_fmt
(
card
,
chan
,
0
);
break
;
default:
printk
(
KERN_WARNING
PFX
"unknown AFMT
\n
"
);
val
=
-
EINVAL
;
break
;
}
DPRINTK
(
"EXIT, returning %d
\n
"
,
val
);
return
val
;
}
static
int
via_chan_set_stereo
(
struct
via_info
*
card
,
struct
via_channel
*
chan
,
int
val
)
{
DPRINTK
(
"ENTER, channels = %d
\n
"
,
val
);
via_chan_clear
(
chan
);
switch
(
val
)
{
/* mono */
case
1
:
chan
->
pcm_fmt
&=
~
VIA_PCM_FMT_STEREO
;
via_chan_pcm_fmt
(
card
,
chan
,
0
);
break
;
/* stereo */
case
2
:
chan
->
pcm_fmt
|=
VIA_PCM_FMT_STEREO
;
via_chan_pcm_fmt
(
card
,
chan
,
0
);
break
;
/* unknown */
default:
printk
(
KERN_WARNING
PFX
"unknown number of channels
\n
"
);
val
=
-
EINVAL
;
break
;
}
DPRINTK
(
"EXIT, returning %d
\n
"
,
val
);
return
val
;
}
#if 0
static void via_chan_dump_bufs (struct via_channel *chan)
{
int i;
for (i = 0; i < VIA_DMA_BUFFERS; i++) {
DPRINTK ("#%02d: addr=%x, count=%u, flag=%d, eol=%d\n",
i, chan->sgtable[i].addr,
chan->sgtable[i].count & 0x00FFFFFF,
chan->sgtable[i].count & VIA_FLAG ? 1 : 0,
chan->sgtable[i].count & VIA_EOL ? 1 : 0);
}
DPRINTK ("buf_in_use = %d, nextbuf = %d\n",
atomic_read (&chan->buf_in_use),
atomic_read (&chan->next_buf));
}
#endif
/****************************************************************
*
* Interface to ac97-codec module
*
*
*/
static
u8
via_ac97_wait_idle
(
struct
via_info
*
card
)
{
u8
tmp8
;
int
counter
=
VIA_COUNTER_LIMIT
;
DPRINTK
(
"ENTER/EXIT
\n
"
);
assert
(
card
!=
NULL
);
assert
(
card
->
pdev
!=
NULL
);
do
{
do
{
tmp
=
via_ac97_read32
(
pdev
,
VIA_AC97_CTRL
);
if
(
current
->
need_resched
)
}
while
((
tmp
&
VIA_CR80_BUSY
)
&&
(
counter
--
>
0
));
schedule
();
else
udelay
(
10
);
DPRINTK
(
"EXIT%s
\n
"
,
counter
>
0
?
""
:
", counter limit reached"
);
spin_lock_irq
(
&
card
->
lock
);
tmp8
=
inb
(
card
->
baseaddr
+
0x83
);
spin_unlock_irq
(
&
card
->
lock
);
}
while
((
tmp8
&
VIA_CR83_BUSY
)
&&
(
counter
--
>
0
));
return
tmp8
;
}
}
static
int
via_ac97_read_reg
(
struct
ac97_hwint
*
dev
,
u8
reg
)
static
u32
via_ac97_wait_valid
(
struct
via_info
*
card
)
{
{
u32
data
;
u32
tmp
;
struct
via_info
*
card
;
int
counter
=
VIA_COUNTER_LIMIT
;
struct
pci_dev
*
pdev
;
DPRINTK
(
"ENTER
\n
"
);
DPRINTK
(
"ENTER
\n
"
);
assert
(
dev
!=
NULL
);
assert
(
card
!=
NULL
);
assert
(
dev
->
driver_private
!=
NULL
);
assert
(
card
->
pdev
!=
NULL
);
do
{
if
(
current
->
need_resched
)
schedule
();
spin_lock_irq
(
&
card
->
lock
);
tmp
=
inl
(
card
->
baseaddr
+
VIA_BASE0_AC97_CTRL
);
spin_unlock_irq
(
&
card
->
lock
);
udelay
(
10
);
if
(
tmp
&
VIA_CR80_FIRST_CODEC_VALID
)
{
DPRINTK
(
"EXIT valid, tmp=0x%X, cnt=%d
\n
"
,
tmp
,
counter
);
return
tmp
;
}
}
while
((
tmp
&
VIA_CR80_BUSY
)
&&
(
counter
--
>
0
));
DPRINTK
(
"EXIT, tmp=0x%X, cnt=%d%s
\n
"
,
tmp
,
counter
,
counter
>
0
?
""
:
", counter limit reached"
);
return
tmp
;
}
static
u16
via_ac97_read_reg
(
struct
ac97_codec
*
codec
,
u8
reg
)
{
u32
data
;
struct
via_info
*
card
;
int
counter
;
DPRINTK
(
"ENTER
\n
"
);
assert
(
codec
!=
NULL
);
assert
(
codec
->
private_data
!=
NULL
);
card
=
codec
->
private_data
;
data
=
(
reg
<<
16
)
|
VIA_CR80_READ
;
outl
(
data
,
card
->
baseaddr
+
VIA_BASE0_AC97_CTRL
);
udelay
(
20
);
for
(
counter
=
VIA_COUNTER_LIMIT
;
counter
>
0
;
counter
--
)
{
if
(
inl
(
card
->
baseaddr
+
0x80
)
&
VIA_CR80_VALID
)
goto
out
;
udelay
(
10
);
if
(
current
->
need_resched
)
schedule
();
}
printk
(
KERN_WARNING
PFX
"timeout while reading AC97 codec
\n
"
);
goto
err_out
;
out:
data
=
inl
(
card
->
baseaddr
+
0x80
);
outb
(
0x02
,
card
->
baseaddr
+
0x83
);
if
(((
data
&
0x007F0000
)
>>
16
)
==
reg
)
{
DPRINTK
(
"EXIT, success, data=0x%x, retval=0x%x
\n
"
,
data
,
data
&
0x0000FFFF
);
return
data
&
0x0000FFFF
;
}
DPRINTK
(
"WARNING: not our index: reg=0x%x, newreg=0x%x
\n
"
,
reg
,
((
data
&
0x007F0000
)
>>
16
));
err_out:
DPRINTK
(
"EXIT, returning 0
\n
"
);
return
0
;
}
static
void
via_ac97_write_reg
(
struct
ac97_codec
*
codec
,
u8
reg
,
u16
value
)
{
u32
data
;
struct
via_info
*
card
;
int
counter
;
DPRINTK
(
"ENTER
\n
"
);
assert
(
codec
!=
NULL
);
assert
(
codec
->
private_data
!=
NULL
);
card
=
codec
->
private_data
;
data
=
(
reg
<<
16
)
+
value
;
outl
(
data
,
card
->
baseaddr
+
VIA_BASE0_AC97_CTRL
);
udelay
(
20
);
for
(
counter
=
VIA_COUNTER_LIMIT
;
counter
>
0
;
counter
--
)
{
if
((
inb
(
card
->
baseaddr
+
0x83
)
&
VIA_CR83_BUSY
)
==
0
)
goto
out
;
udelay
(
10
);
if
(
current
->
need_resched
)
schedule
();
}
printk
(
KERN_WARNING
PFX
"timeout after AC97 codec write
\n
"
);
out:
DPRINTK
(
"EXIT
\n
"
);
}
static
int
via_mixer_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
int
minor
=
MINOR
(
inode
->
i_rdev
);
struct
via_info
*
card
;
struct
pci_dev
*
pdev
;
struct
pci_driver
*
drvr
;
DPRINTK
(
"ENTER
\n
"
);
MOD_INC_USE_COUNT
;
pci_for_each_dev
(
pdev
)
{
drvr
=
pci_dev_driver
(
pdev
);
if
(
drvr
==
&
via_driver
)
{
assert
(
pdev
->
driver_data
!=
NULL
);
card
=
pdev
->
driver_data
;
if
(
card
->
ac97
.
dev_mixer
==
minor
)
goto
match
;
}
}
DPRINTK
(
"EXIT, returning -ENODEV
\n
"
);
MOD_DEC_USE_COUNT
;
return
-
ENODEV
;
match:
file
->
private_data
=
&
card
->
ac97
;
DPRINTK
(
"EXIT, returning 0
\n
"
);
return
0
;
}
static
int
via_mixer_release
(
struct
inode
*
inode
,
struct
file
*
file
)
{
DPRINTK
(
"ENTER
\n
"
);
MOD_DEC_USE_COUNT
;
DPRINTK
(
"EXIT, returning 0
\n
"
);
return
0
;
}
static
int
via_mixer_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
)
{
struct
ac97_codec
*
codec
=
file
->
private_data
;
int
rc
;
assert
(
codec
!=
NULL
);
rc
=
codec
->
mixer_ioctl
(
codec
,
cmd
,
arg
);
return
rc
;
}
static
loff_t
via_llseek
(
struct
file
*
file
,
loff_t
offset
,
int
origin
)
{
DPRINTK
(
"ENTER
\n
"
);
DPRINTK
(
"EXIT, returning -ESPIPE
\n
"
);
return
-
ESPIPE
;
}
static
struct
file_operations
via_mixer_fops
=
{
open:
via_mixer_open
,
release:
via_mixer_release
,
llseek:
via_llseek
,
ioctl:
via_mixer_ioctl
,
};
static
struct
{
u8
reg
;
u16
data
;
}
mixer_init_vals
[]
__devinitdata
=
{
{
0x2
,
0x404
},
{
0x4
,
0x404
},
{
0x6
,
0x404
},
{
0x18
,
0x404
},
{
0x10
,
0x404
},
{
0x1a
,
0x404
},
{
0x1c
,
0x404
},
{
0x1a
,
0x404
},
{
0x1c
,
0xc0c
},
{
0x12
,
0x808
},
{
0x10
,
0x808
},
{
0xe
,
0x2
},
{
0x2
,
0x808
},
{
0x18
,
0x808
},
};
static
int
__init
via_ac97_reset
(
struct
via_info
*
card
)
{
struct
pci_dev
*
pdev
=
card
->
pdev
;
u8
tmp8
;
u16
tmp16
;
size_t
idx
;
DPRINTK
(
"ENTER
\n
"
);
assert
(
pdev
!=
NULL
);
#ifndef NDEBUG
{
u8
r40
,
r41
,
r42
,
r43
,
r44
,
r48
;
pci_read_config_byte
(
card
->
pdev
,
0x40
,
&
r40
);
pci_read_config_byte
(
card
->
pdev
,
0x41
,
&
r41
);
pci_read_config_byte
(
card
->
pdev
,
0x42
,
&
r42
);
pci_read_config_byte
(
card
->
pdev
,
0x43
,
&
r43
);
pci_read_config_byte
(
card
->
pdev
,
0x44
,
&
r44
);
pci_read_config_byte
(
card
->
pdev
,
0x48
,
&
r48
);
DPRINTK
(
"PCI config: %02X %02X %02X %02X %02X %02X
\n
"
,
r40
,
r41
,
r42
,
r43
,
r44
,
r48
);
spin_lock_irq
(
&
card
->
lock
);
DPRINTK
(
"regs==%02X %02X %02X %08X %08X %08X %08X
\n
"
,
inb
(
card
->
baseaddr
+
0x00
),
inb
(
card
->
baseaddr
+
0x01
),
inb
(
card
->
baseaddr
+
0x02
),
inl
(
card
->
baseaddr
+
0x04
),
inl
(
card
->
baseaddr
+
0x0C
),
inl
(
card
->
baseaddr
+
0x80
),
inl
(
card
->
baseaddr
+
0x84
));
spin_unlock_irq
(
&
card
->
lock
);
}
#endif
#if 1
/*
* reset AC97 controller: enable, disable, enable
* pause after each command for good luck
*/
pci_write_config_byte
(
pdev
,
VIA_ACLINK_CTRL
,
VIA_CR41_AC97_ENABLE
|
VIA_CR41_AC97_RESET
|
VIA_CR41_AC97_WAKEUP
);
udelay
(
100
);
pci_write_config_byte
(
pdev
,
VIA_ACLINK_CTRL
,
0
);
udelay
(
100
);
pci_write_config_byte
(
pdev
,
VIA_ACLINK_CTRL
,
VIA_CR41_AC97_ENABLE
|
VIA_CR41_PCM_ENABLE
|
VIA_CR41_VRA
|
VIA_CR41_AC97_RESET
);
udelay
(
100
);
#endif
#if 0
/*
* reset AC97 controller
*/
pci_read_config_byte(pdev, 0x08, &tmp8);
if ((tmp8 & 0xff) >= 0x20 ) {
pci_read_config_byte(pdev, 0x42, &tmp8);
pci_write_config_byte(pdev, 0x42,(tmp8 & 0x3f));
}
udelay (100);
/* init other mixer defaults */
for (idx = 0; idx < arraysize(mixer_init_vals); idx++) {
via_ac97_write_reg (&card->ac97,
mixer_init_vals[idx].reg,
mixer_init_vals[idx].data);
udelay (20);
}
pci_write_config_byte (pdev, 0x41, 0xc0);
udelay (10);
pci_read_config_byte (pdev, 0x41, &tmp8);
udelay (10);
pci_write_config_byte (pdev, 0x41, tmp8 | 0x0f);
udelay (10);
#endif
/* disable legacy stuff */
pci_write_config_byte
(
pdev
,
0x42
,
0x00
);
udelay
(
10
);
/* route FM trap to IRQ, disable FM trap */
pci_write_config_byte
(
pdev
,
0x48
,
0x05
);
udelay
(
10
);
/* disable all codec GPI interrupts */
outl
(
0
,
pci_resource_start
(
pdev
,
0
)
+
0x8C
);
#if 0 /* ALSA */
via_ac97_write_reg (&card->ac97, AC97_EXTENDED_STATUS, 0x0009);
#if 0
via_ac97_write_reg (&card->ac97, AC97_POWER_CONTROL,
via_ac97_read_reg (&card->ac97, AC97_POWER_CONTROL) | 0x0300);
#endif
via_ac97_write_reg (&card->ac97, AC97_EXTENDED_STATUS,
via_ac97_read_reg (&card->ac97, AC97_EXTENDED_STATUS) | 0xe800);
#endif
/* enable variable rate */
tmp16
=
via_ac97_read_reg
(
&
card
->
ac97
,
0x2A
);
via_ac97_write_reg
(
&
card
->
ac97
,
0x2A
,
tmp16
|
0x01
);
/* boost headphone vol if disabled */
tmp16
=
via_ac97_read_reg
(
&
card
->
ac97
,
AC97_HEADPHONE_VOL
);
if
(
tmp16
==
0
)
via_ac97_write_reg
(
&
card
->
ac97
,
AC97_HEADPHONE_VOL
,
0x1F1F
);
pci_read_config_byte
(
pdev
,
VIA_ACLINK_CTRL
,
&
tmp8
);
if
((
tmp8
&
(
VIA_CR41_AC97_ENABLE
|
VIA_CR41_AC97_RESET
))
==
0
)
{
printk
(
KERN_ERR
PFX
"cannot enable AC97 controller, aborting
\n
"
);
DPRINTK
(
"EXIT, tmp8=%X, returning -ENODEV
\n
"
,
tmp8
);
return
-
ENODEV
;
}
DPRINTK
(
"EXIT, returning 0
\n
"
);
return
0
;
}
static
int
__init
via_ac97_init
(
struct
via_info
*
card
)
{
int
rc
;
u16
tmp16
;
DPRINTK
(
"ENTER
\n
"
);
assert
(
card
!=
NULL
);
memset
(
&
card
->
ac97
,
0
,
sizeof
(
card
->
ac97
));
card
->
ac97
.
private_data
=
card
;
card
->
ac97
.
codec_read
=
via_ac97_read_reg
;
card
->
ac97
.
codec_write
=
via_ac97_write_reg
;
card
->
ac97
.
dev_mixer
=
register_sound_mixer
(
&
via_mixer_fops
,
-
1
);
if
(
card
->
ac97
.
dev_mixer
<
0
)
{
printk
(
KERN_ERR
PFX
"unable to register AC97 mixer, aborting
\n
"
);
DPRINTK
(
"EXIT, returning -EIO
\n
"
);
return
-
EIO
;
}
rc
=
via_ac97_reset
(
card
);
if
(
rc
)
{
printk
(
KERN_ERR
PFX
"unable to reset AC97 codec, aborting
\n
"
);
goto
err_out
;
}
if
(
ac97_probe_codec
(
&
card
->
ac97
)
==
0
)
{
printk
(
KERN_ERR
PFX
"unable to probe AC97 codec, aborting
\n
"
);
rc
=
-
EIO
;
goto
err_out
;
}
tmp16
=
via_ac97_read_reg
(
&
card
->
ac97
,
0x2A
);
via_ac97_write_reg
(
&
card
->
ac97
,
0x2A
,
tmp16
|
0x01
);
DPRINTK
(
"EXIT, returning 0
\n
"
);
return
0
;
err_out:
unregister_sound_mixer
(
card
->
ac97
.
dev_mixer
);
DPRINTK
(
"EXIT, returning %d
\n
"
,
rc
);
return
rc
;
}
static
void
via_ac97_cleanup
(
struct
via_info
*
card
)
{
DPRINTK
(
"ENTER
\n
"
);
assert
(
card
!=
NULL
);
assert
(
card
->
ac97
.
dev_mixer
>=
0
);
unregister_sound_mixer
(
card
->
ac97
.
dev_mixer
);
DPRINTK
(
"EXIT
\n
"
);
}
/****************************************************************
*
* Interrupt-related code
*
*/
static
inline
void
via_interrupt_write
(
struct
via_channel
*
chan
)
{
assert
(
atomic_read
(
&
chan
->
buf_in_use
)
<
atomic_read
(
&
chan
->
next_buf
));
/* XXX sanity check: read h/w counter to
* ensure no lost frames */
atomic_inc
(
&
chan
->
buf_in_use
);
/* if SG ptr catches up with userland ptr, stop playback */
if
(
atomic_read
(
&
chan
->
buf_in_use
)
==
atomic_read
(
&
chan
->
next_buf
))
{
atomic_set
(
&
chan
->
state
,
sgd_stopped
);
via_chan_stop
(
chan
->
iobase
);
}
/* wake up anybody listening */
if
(
waitqueue_active
(
&
chan
->
wait
))
wake_up
(
&
chan
->
wait
);
}
static
void
via_interrupt
(
int
irq
,
void
*
dev_id
,
struct
pt_regs
*
regs
)
{
struct
via_info
*
card
=
dev_id
;
struct
via_channel
*
chan
;
u8
status
;
int
unhandled
=
1
;
static
long
intcount
=
0
;
assert
(
irq
==
card
->
pdev
->
irq
);
intcount
++
;
status
=
inb
(
card
->
baseaddr
+
0x00
);
if
(
status
)
{
assert
(
card
->
open_mode
&
FMODE_WRITE
);
chan
=
&
card
->
ch_out
;
unhandled
=
0
;
if
(
status
&
VIA_SGD_FLAG
)
{
assert
((
status
&
VIA_SGD_EOL
)
==
0
);
outb
(
VIA_SGD_FLAG
,
chan
->
iobase
+
0x00
);
DPRINTK
(
"FLAG intr, status=0x%02X, intcount=%ld
\n
"
,
status
,
intcount
);
via_interrupt_write
(
chan
);
}
if
(
status
&
VIA_SGD_EOL
)
{
assert
((
status
&
VIA_SGD_FLAG
)
==
0
);
outb
(
VIA_SGD_EOL
,
chan
->
iobase
+
0x00
);
DPRINTK
(
"EOL intr, status=0x%02X, intcount=%ld
\n
"
,
status
,
intcount
);
via_interrupt_write
(
chan
);
}
if
(
status
&
VIA_SGD_STOPPED
)
{
outb
(
VIA_SGD_STOPPED
,
chan
->
iobase
+
0x00
);
DPRINTK
(
"STOPPED intr, status=0x%02X, intcount=%ld
\n
"
,
status
,
intcount
);
}
#if 0
via_chan_dump_bufs (&card->ch_out);
#endif
}
if
(
unhandled
)
printk
(
KERN_WARNING
PFX
"unhandled interrupt, st=%02x, st32=%08x
\n
"
,
status
,
inl
(
card
->
baseaddr
+
0x84
));
}
static
void
via_interrupt_disable
(
struct
via_info
*
card
)
{
u8
tmp8
;
unsigned
long
flags
;
DPRINTK
(
"ENTER
\n
"
);
assert
(
card
!=
NULL
);
spin_lock_irqsave
(
&
card
->
lock
,
flags
);
pci_read_config_byte
(
card
->
pdev
,
VIA_FM_NMI_CTRL
,
&
tmp8
);
if
((
tmp8
&
VIA_CR48_FM_TRAP_TO_NMI
)
==
0
)
{
tmp8
|=
VIA_CR48_FM_TRAP_TO_NMI
;
pci_write_config_byte
(
card
->
pdev
,
VIA_FM_NMI_CTRL
,
tmp8
);
}
outb
(
inb
(
card
->
baseaddr
+
VIA_BASE0_PCM_OUT_CHAN_TYPE
)
&
VIA_INT_DISABLE_MASK
,
card
->
baseaddr
+
VIA_BASE0_PCM_OUT_CHAN_TYPE
);
outb
(
inb
(
card
->
baseaddr
+
VIA_BASE0_PCM_IN_CHAN_TYPE
)
&
VIA_INT_DISABLE_MASK
,
card
->
baseaddr
+
VIA_BASE0_PCM_IN_CHAN_TYPE
);
outb
(
inb
(
card
->
baseaddr
+
VIA_BASE0_FM_OUT_CHAN_TYPE
)
&
VIA_INT_DISABLE_MASK
,
card
->
baseaddr
+
VIA_BASE0_FM_OUT_CHAN_TYPE
);
spin_unlock_irqrestore
(
&
card
->
lock
,
flags
);
DPRINTK
(
"EXIT
\n
"
);
}
static
int
via_interrupt_init
(
struct
via_info
*
card
)
{
DPRINTK
(
"ENTER
\n
"
);
assert
(
card
!=
NULL
);
assert
(
card
->
pdev
!=
NULL
);
/* check for sane IRQ number. can this ever happen? */
if
(
card
->
pdev
->
irq
<
2
)
{
printk
(
KERN_ERR
PFX
"insane IRQ %d, aborting
\n
"
,
card
->
pdev
->
irq
);
DPRINTK
(
"EXIT, returning -EIO
\n
"
);
return
-
EIO
;
}
if
(
request_irq
(
card
->
pdev
->
irq
,
via_interrupt
,
SA_SHIRQ
,
VIA_MODULE_NAME
,
card
))
{
printk
(
KERN_ERR
PFX
"unable to obtain IRQ %d, aborting
\n
"
,
card
->
pdev
->
irq
);
DPRINTK
(
"EXIT, returning -EBUSY
\n
"
);
return
-
EBUSY
;
}
/* we don't want interrupts until we're opened */
via_interrupt_disable
(
card
);
DPRINTK
(
"EXIT, returning 0
\n
"
);
return
0
;
}
static
void
via_interrupt_cleanup
(
struct
via_info
*
card
)
{
DPRINTK
(
"ENTER
\n
"
);
assert
(
card
!=
NULL
);
assert
(
card
->
pdev
!=
NULL
);
via_interrupt_disable
(
card
);
free_irq
(
card
->
pdev
->
irq
,
card
);
DPRINTK
(
"EXIT
\n
"
);
}
/****************************************************************
*
* OSS DSP device
*
*/
static
struct
file_operations
via_dsp_fops
=
{
open:
via_dsp_open
,
release:
via_dsp_release
,
read:
via_dsp_read
,
write:
via_dsp_write
,
poll:
via_dsp_poll
,
llseek:
via_llseek
,
ioctl:
via_dsp_ioctl
,
};
static
int
__init
via_dsp_init
(
struct
via_info
*
card
)
{
u8
tmp8
;
DPRINTK
(
"ENTER
\n
"
);
assert
(
card
!=
NULL
);
/* turn off legacy features, if not already */
pci_read_config_byte
(
card
->
pdev
,
VIA_FUNC_ENABLE
,
&
tmp8
);
tmp8
&=
~
(
VIA_CR42_SB_ENABLE
|
VIA_CR42_MIDI_ENABLE
|
VIA_CR42_FM_ENABLE
);
pci_write_config_byte
(
card
->
pdev
,
VIA_FUNC_ENABLE
,
tmp8
);
via_stop_everything
(
card
);
card
->
dev_dsp
=
register_sound_dsp
(
&
via_dsp_fops
,
-
1
);
if
(
card
->
dev_dsp
<
0
)
{
DPRINTK
(
"EXIT, returning -ENODEV
\n
"
);
return
-
ENODEV
;
}
DPRINTK
(
"EXIT, returning 0
\n
"
);
return
0
;
}
static
void
via_dsp_cleanup
(
struct
via_info
*
card
)
{
DPRINTK
(
"ENTER
\n
"
);
assert
(
card
!=
NULL
);
assert
(
card
->
dev_dsp
>=
0
);
via_stop_everything
(
card
);
unregister_sound_dsp
(
card
->
dev_dsp
);
DPRINTK
(
"EXIT
\n
"
);
}
static
ssize_t
via_dsp_read
(
struct
file
*
file
,
char
*
buffer
,
size_t
count
,
loff_t
*
ppos
)
{
struct
via_info
*
card
;
DPRINTK
(
"ENTER
\n
"
);
assert
(
file
!=
NULL
);
assert
(
buffer
!=
NULL
);
card
=
file
->
private_data
;
assert
(
card
!=
NULL
);
DPRINTK
(
"EXIT, returning -EINVAL
\n
"
);
return
-
EINVAL
;
}
#define sgcount(n) (sgtable[(n)].count & 0x00FFFFFF)
#define NEXTBUF (atomic_read(&chan->next_buf) % VIA_DMA_BUFFERS)
#define BUF_IN_USE (atomic_read(&chan->buf_in_use) % VIA_DMA_BUFFERS)
#define STATE_STOPPED (atomic_read (state) == sgd_stopped)
#define STATE_STARTED (atomic_read (state) == sgd_in_progress)
static
ssize_t
via_dsp_do_write
(
struct
via_info
*
card
,
const
char
*
userbuf
,
size_t
count
,
int
non_blocking
)
{
const
char
*
orig_userbuf
=
userbuf
;
struct
via_channel
*
chan
=
&
card
->
ch_out
;
volatile
struct
via_sgd_table
*
sgtable
=
chan
->
sgtable
;
atomic_t
*
state
=
&
chan
->
state
;
size_t
size
;
int
nextbuf
,
prevbuf
,
n
,
realcount
;
ssize_t
rc
;
while
(
count
>
0
)
{
if
(
current
->
need_resched
)
schedule
();
spin_lock_irq
(
&
card
->
lock
);
DPRINTK
(
"regs==%02X %02X %02X %08X %08X %08X %08X
\n
"
,
inb
(
card
->
baseaddr
+
0x00
),
inb
(
card
->
baseaddr
+
0x01
),
inb
(
card
->
baseaddr
+
0x02
),
inl
(
card
->
baseaddr
+
0x04
),
inl
(
card
->
baseaddr
+
0x0C
),
inl
(
card
->
baseaddr
+
0x80
),
inl
(
card
->
baseaddr
+
0x84
));
spin_unlock_irq
(
&
card
->
lock
);
size
=
(
count
<
VIA_DMA_BUF_SIZE
)
?
count
:
VIA_DMA_BUF_SIZE
;
/* case 1: SGD not active, list is ours for the mangling */
if
(
STATE_STOPPED
)
{
DPRINTK
(
"case 1
\n
"
);
if
(
copy_from_user
((
void
*
)
chan
->
sgbuf
[
0
].
cpuaddr
,
userbuf
,
size
))
return
-
EFAULT
;
assert
(
sgtable
[
0
].
addr
==
cpu_to_le32
(
chan
->
sgbuf
[
0
].
handle
));
sgtable
[
0
].
count
=
size
|
VIA_FLAG
;
atomic_set
(
state
,
sgd_in_progress
);
atomic_set
(
&
chan
->
buf_in_use
,
0
);
atomic_set
(
&
chan
->
next_buf
,
1
);
count
-=
size
;
userbuf
+=
size
;
spin_lock_irq
(
&
card
->
lock
);
sg_begin
(
chan
);
spin_unlock_irq
(
&
card
->
lock
);
continue
;
}
nextbuf
=
NEXTBUF
;
if
(
nextbuf
)
prevbuf
=
nextbuf
-
1
;
else
prevbuf
=
VIA_DMA_BUFFERS
-
1
;
/* case 2: if final buffer is (a) a fragment, and (b) not
* currently being consumed by the SGD engine, then append
* as much data as possible to the fragment. */
realcount
=
sgcount
(
prevbuf
);
if
(
STATE_STARTED
&&
(
prevbuf
!=
BUF_IN_USE
)
&&
(
realcount
<
VIA_DMA_BUF_SIZE
))
{
DPRINTK
(
"case 2
\n
"
);
DPRINTK
(
"st=%d, fb=%d -- nb=%d, pb=%d, n=%d, rc=%d
\n
"
,
atomic_read
(
state
),
BUF_IN_USE
,
nextbuf
,
prevbuf
,
prevbuf
/* n */
,
realcount
);
n
=
prevbuf
;
if
((
VIA_DMA_BUF_SIZE
-
realcount
)
<
size
)
size
=
VIA_DMA_BUF_SIZE
-
realcount
;
if
(
copy_from_user
((
void
*
)(
chan
->
sgbuf
[
n
].
cpuaddr
+
realcount
),
userbuf
,
size
))
return
-
EFAULT
;
/* slack way to try and prevent races */
if
(
prevbuf
==
BUF_IN_USE
||
!
STATE_STARTED
)
continue
;
assert
(
sgtable
[
n
].
addr
==
cpu_to_le32
(
chan
->
sgbuf
[
n
].
handle
));
if
(
n
==
(
VIA_DMA_BUFFERS
-
1
))
sgtable
[
n
].
count
=
(
realcount
+
size
)
|
VIA_EOL
;
else
sgtable
[
n
].
count
=
(
realcount
+
size
)
|
VIA_FLAG
;
count
-=
size
;
userbuf
+=
size
;
continue
;
}
/* case 3: if there are buffers left, use one
* XXX needs more review for possible races */
else
if
(
STATE_STARTED
&&
!
via_chan_full
(
chan
))
{
DPRINTK
(
"case 3
\n
"
);
DPRINTK
(
"st=%d, fb=%d -- nb=%d, pb=%d, n=%d
\n
"
,
atomic_read
(
state
),
BUF_IN_USE
,
nextbuf
,
prevbuf
,
nextbuf
/* n */
);
n
=
nextbuf
;
if
(
copy_from_user
((
void
*
)
chan
->
sgbuf
[
n
].
cpuaddr
,
userbuf
,
size
))
return
-
EFAULT
;
if
(
n
==
(
VIA_DMA_BUFFERS
-
1
))
sgtable
[
n
].
count
=
size
|
VIA_EOL
;
else
sgtable
[
n
].
count
=
size
|
VIA_FLAG
;
/* if SGD stopped during data copy or SG table update,
* then loop back to the beginning without updating
* any pointers.
* ie. slack way to prevent race */
if
(
!
STATE_STARTED
)
continue
;
atomic_inc
(
&
chan
->
next_buf
);
count
-=
size
;
userbuf
+=
size
;
continue
;
}
/* case 4, final SGT active case: no free buffers, wait for one */
else
{
DPRINTK
(
"case 4
\n
"
);
DPRINTK
(
"st=%d, fb=%d -- nb=%d, pb=%d
\n
"
,
atomic_read
(
state
),
BUF_IN_USE
,
nextbuf
,
prevbuf
);
/* if playback stopped, no need to sleep */
if
(
!
STATE_STARTED
)
continue
;
/* if buffer free, no need to sleep */
if
(
!
via_chan_full
(
chan
))
continue
;
if
(
non_blocking
)
{
rc
=
userbuf
-
orig_userbuf
;
if
(
rc
==
0
)
rc
=
-
EAGAIN
;
return
rc
;
}
DPRINTK
(
"sleeping
\n
"
);
interruptible_sleep_on
(
&
chan
->
wait
);
if
(
signal_pending
(
current
))
return
-
ERESTARTSYS
;
}
}
#if 0
{
u8 r40,r41,r42,r43,r44,r48;
pci_read_config_byte (card->pdev, 0x40, &r40);
pci_read_config_byte (card->pdev, 0x41, &r41);
pci_read_config_byte (card->pdev, 0x42, &r42);
pci_read_config_byte (card->pdev, 0x43, &r43);
pci_read_config_byte (card->pdev, 0x44, &r44);
pci_read_config_byte (card->pdev, 0x48, &r48);
DPRINTK("PCI config: %02X %02X %02X %02X %02X %02X\n",
r40,r41,r42,r43,r44,r48);
}
#endif
DPRINTK
(
"EXIT, returning %d
\n
"
,
userbuf
-
orig_userbuf
);
return
userbuf
-
orig_userbuf
;
}
#undef sgcount
#undef NEXTBUF
#undef BUF_IN_USE
#undef STATE_STOPPED
#undef STATE_STARTED
static
ssize_t
via_dsp_write
(
struct
file
*
file
,
const
char
*
buffer
,
size_t
count
,
loff_t
*
ppos
)
{
struct
via_info
*
card
;
ssize_t
rc
;
DPRINTK
(
"ENTER, file=%p, buffer=%p, count=%u, ppos=%lu
\n
"
,
file
,
buffer
,
count
,
ppos
?
((
unsigned
long
)
*
ppos
)
:
0
);
assert
(
file
!=
NULL
);
assert
(
buffer
!=
NULL
);
card
=
file
->
private_data
;
assert
(
card
!=
NULL
);
if
(
ppos
!=
&
file
->
f_pos
)
{
DPRINTK
(
"EXIT, returning -ESPIPE
\n
"
);
return
-
ESPIPE
;
}
rc
=
via_dsp_do_write
(
card
,
buffer
,
count
,
(
file
->
f_flags
&
O_NONBLOCK
));
DPRINTK
(
"EXIT, returning %ld
\n
"
,(
long
)
rc
);
return
rc
;
}
static
unsigned
int
via_dsp_poll
(
struct
file
*
file
,
struct
poll_table_struct
*
wait
)
{
struct
via_info
*
card
;
unsigned
int
mask
=
0
;
DPRINTK
(
"ENTER
\n
"
);
assert
(
file
!=
NULL
);
assert
(
wait
!=
NULL
);
card
=
file
->
private_data
;
assert
(
card
!=
NULL
);
if
((
file
->
f_mode
&
FMODE_WRITE
)
&&
(
atomic_read
(
&
card
->
ch_out
.
state
)
!=
sgd_stopped
))
{
poll_wait
(
file
,
&
card
->
ch_out
.
wait
,
wait
);
/* XXX is this correct */
if
(
atomic_read
(
&
card
->
ch_out
.
buf_in_use
)
<
atomic_read
(
&
card
->
ch_out
.
next_buf
))
mask
|=
POLLOUT
|
POLLWRNORM
;
}
card
=
(
struct
via_info
*
)
dev
->
driver_private
;
DPRINTK
(
"EXIT, returning %u
\n
"
,
mask
)
;
pdev
=
card
->
pdev
;
return
mask
;
assert
(
pdev
!=
NULL
);
}
via_ac97_wait_idle
(
pdev
);
data
=
VIA_CR80_FIRST_CODEC
|
VIA_CR80_FIRST_CODEC_VALID
|
VIA_CR80_READ_MODE
|
VIA_CR80_REG_IDX
(
reg
);
via_ac97_write32
(
pdev
,
VIA_AC97_CTRL
,
data
);
via_ac97_wait_idle
(
pdev
);
data
=
via_ac97_read32
(
pdev
,
VIA_AC97_CTRL
);
#if 0
static
int
via_dsp_drain_dac
(
struct
via_info
*
card
,
int
non_block
)
if (! (data & VIA_CR80_FIRST_CODEC_VALID)) {
{
DPRINTK ("EXIT, first codec not valid, returning -1\n");
DPRINTK
(
"ENTER, non_block = %d
\n
"
,
non_block
);
return -1;
while
(
!
via_chan_empty
(
&
card
->
ch_out
))
{
if
(
non_block
)
{
DPRINTK
(
"EXIT, returning -EBUSY
\n
"
);
return
-
EBUSY
;
}
if
(
signal_pending
(
current
))
{
DPRINTK
(
"EXIT, returning -ERESTARTSYS
\n
"
);
return
-
ERESTARTSYS
;
}
#ifndef NDEBUG
{
u8
r40
,
r41
,
r42
,
r43
,
r44
,
r48
;
pci_read_config_byte
(
card
->
pdev
,
0x40
,
&
r40
);
pci_read_config_byte
(
card
->
pdev
,
0x41
,
&
r41
);
pci_read_config_byte
(
card
->
pdev
,
0x42
,
&
r42
);
pci_read_config_byte
(
card
->
pdev
,
0x43
,
&
r43
);
pci_read_config_byte
(
card
->
pdev
,
0x44
,
&
r44
);
pci_read_config_byte
(
card
->
pdev
,
0x48
,
&
r48
);
DPRINTK
(
"PCI config: %02X %02X %02X %02X %02X %02X
\n
"
,
r40
,
r41
,
r42
,
r43
,
r44
,
r48
);
spin_lock_irq
(
&
card
->
lock
);
DPRINTK
(
"regs==%02X %02X %02X %08X %08X %08X %08X
\n
"
,
inb
(
card
->
baseaddr
+
0x00
),
inb
(
card
->
baseaddr
+
0x01
),
inb
(
card
->
baseaddr
+
0x02
),
inl
(
card
->
baseaddr
+
0x04
),
inl
(
card
->
baseaddr
+
0x0C
),
inl
(
card
->
baseaddr
+
0x80
),
inl
(
card
->
baseaddr
+
0x84
));
spin_unlock_irq
(
&
card
->
lock
);
}
}
#endif
#endif
DPRINTK
(
"EXIT, returning %d
\n
"
,
data
&
0xFFFF
);
DPRINTK
(
"sleeping
\n
"
);
return
data
&
0xFFFF
;
interruptible_sleep_on
(
&
card
->
ch_out
.
wait
);
}
DPRINTK
(
"EXIT
\n
"
);
return
0
;
}
}
static
int
via_ac97_write_reg
(
struct
ac97_hwint
*
dev
,
u8
reg
,
u16
value
)
static
int
via_dsp_ioctl_space
(
struct
via_info
*
card
,
struct
via_channel
*
chan
,
void
*
arg
)
{
{
u32
data
;
audio_buf_info
info
;
struct
via_info
*
card
;
int
n
;
struct
pci_dev
*
pdev
;
DPRINTK
(
"ENTER
\n
"
);
assert
(
dev
!=
NULL
)
;
info
.
fragstotal
=
VIA_DMA_BUFFERS
;
assert
(
dev
->
driver_private
!=
NULL
)
;
info
.
fragsize
=
VIA_DMA_BUF_SIZE
;
card
=
(
struct
via_info
*
)
dev
->
driver_private
;
/* number of full fragments we can read without blocking */
pdev
=
card
->
pdev
;
n
=
atomic_read
(
&
chan
->
next_buf
)
-
atomic_read
(
&
chan
->
buf_in_use
)
;
assert
(
pdev
!=
NULL
)
;
info
.
fragments
=
VIA_DMA_BUFFERS
-
n
;
via_ac97_wait_idle
(
pdev
);
/* number of bytes that can be read or written immediately
data
=
VIA_CR80_FIRST_CODEC
|
VIA_CR80_FIRST_CODEC_VALID
|
* without blocking. FIXME: we are lazy and ignore partially-full
VIA_CR80_WRITE_MODE
|
VIA_CR80_REG_IDX
(
reg
)
|
value
;
* buffers.
via_ac97_write32
(
pdev
,
VIA_AC97_CTRL
,
data
);
*/
info
.
bytes
=
info
.
fragments
*
VIA_DMA_BUF_SIZE
;
#if 0
DPRINTK
(
"EXIT, returning fragstotal=%d, fragsize=%d, fragments=%d, bytes=%d
\n
"
,
if (! (data & VIA_CR80_FIRST_CODEC_VALID)) {
info
.
fragstotal
,
DPRINTK ("EXIT, first codec invalid, returning -1\n");
info
.
fragsize
,
return -1;
info
.
fragments
,
}
info
.
bytes
);
#endif
DPRINTK
(
"EXIT, returning 0
\n
"
);
return
copy_to_user
(
arg
,
&
info
,
sizeof
(
info
));
return
0
;
}
}
static
int
via_ac97_reset
(
struct
ac97_hwint
*
dev
)
static
int
via_dsp_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
)
{
{
int
rc
=
-
EINVAL
,
rd
=
0
,
wr
=
0
,
val
=
0
;
struct
via_info
*
card
;
struct
via_info
*
card
;
struct
pci_dev
*
pdev
;
DPRINTK
(
"ENTER
\n
"
);
assert
(
dev
!=
NULL
);
DPRINTK
(
"ENTER, cmd = 0x%08X
\n
"
,
cmd
);
assert
(
dev
->
driver_private
!=
NULL
);
card
=
(
struct
via_info
*
)
dev
->
driver_private
;
assert
(
file
!=
NULL
);
pdev
=
card
->
pdev
;
card
=
file
->
private_data
;
assert
(
pdev
!=
NULL
);
assert
(
card
!=
NULL
);
if
(
file
->
f_mode
&
FMODE_WRITE
)
wr
=
1
;
if
(
file
->
f_mode
&
FMODE_READ
)
rd
=
1
;
switch
(
cmd
)
{
/* OSS API version. XXX unverified */
case
OSS_GETVERSION
:
DPRINTK
(
"EXIT, returning SOUND_VERSION
\n
"
);
return
put_user
(
SOUND_VERSION
,
(
int
*
)
arg
);
/* list of supported PCM data formats */
case
SNDCTL_DSP_GETFMTS
:
DPRINTK
(
"EXIT, returning AFMT U8|S16_LE
\n
"
);
return
put_user
(
AFMT_U8
|
AFMT_S16_LE
,
(
int
*
)
arg
);
/* query or set current channel's PCM data format */
case
SNDCTL_DSP_SETFMT
:
get_user_ret
(
val
,
(
int
*
)
arg
,
-
EFAULT
);
if
(
val
!=
AFMT_QUERY
)
{
rc
=
0
;
spin_lock_irq
(
&
card
->
lock
);
if
(
rc
==
0
&&
rd
)
rc
=
via_chan_set_fmt
(
card
,
&
card
->
ch_in
,
val
);
if
(
rc
==
0
&&
wr
)
rc
=
via_chan_set_fmt
(
card
,
&
card
->
ch_out
,
val
);
spin_unlock_irq
(
&
card
->
lock
);
if
(
rc
<=
0
)
return
rc
?
rc
:
-
EINVAL
;
val
=
rc
;
}
else
{
spin_lock_irq
(
&
card
->
lock
);
if
((
rd
&&
(
card
->
ch_in
.
pcm_fmt
&
VIA_PCM_FMT_16BIT
))
||
(
wr
&&
(
card
->
ch_out
.
pcm_fmt
&
VIA_PCM_FMT_16BIT
)))
val
=
AFMT_S16_LE
;
else
val
=
AFMT_U8
;
spin_unlock_irq
(
&
card
->
lock
);
}
DPRINTK
(
"SETFMT EXIT, returning %d
\n
"
,
val
);
return
put_user
(
val
,
(
int
*
)
arg
);
/* query or set number of channels (1=mono, 2=stereo) */
case
SNDCTL_DSP_CHANNELS
:
get_user_ret
(
val
,
(
int
*
)
arg
,
-
EFAULT
);
if
(
val
!=
0
)
{
rc
=
0
;
spin_lock_irq
(
&
card
->
lock
);
if
(
rc
==
0
&&
rd
)
rc
=
via_chan_set_stereo
(
card
,
&
card
->
ch_in
,
val
);
if
(
rc
==
0
&&
wr
)
rc
=
via_chan_set_stereo
(
card
,
&
card
->
ch_out
,
val
);
spin_unlock_irq
(
&
card
->
lock
);
if
(
rc
<=
0
)
return
rc
?
rc
:
-
EINVAL
;
val
=
rc
;
}
else
{
spin_lock_irq
(
&
card
->
lock
);
if
((
rd
&&
(
card
->
ch_in
.
pcm_fmt
&
VIA_PCM_FMT_STEREO
))
||
(
wr
&&
(
card
->
ch_out
.
pcm_fmt
&
VIA_PCM_FMT_STEREO
)))
val
=
2
;
else
val
=
1
;
spin_unlock_irq
(
&
card
->
lock
);
}
DPRINTK
(
"CHANNELS EXIT, returning %d
\n
"
,
val
);
return
put_user
(
val
,
(
int
*
)
arg
);
/* enable (val is not zero) or disable (val == 0) stereo */
case
SNDCTL_DSP_STEREO
:
get_user_ret
(
val
,
(
int
*
)
arg
,
-
EFAULT
);
rc
=
0
;
spin_lock_irq
(
&
card
->
lock
);
if
(
rc
==
0
&&
rd
)
rc
=
via_chan_set_stereo
(
card
,
&
card
->
ch_in
,
val
?
2
:
1
);
if
(
rc
==
0
&&
wr
)
rc
=
via_chan_set_stereo
(
card
,
&
card
->
ch_out
,
val
?
2
:
1
);
spin_unlock_irq
(
&
card
->
lock
);
if
(
rc
<=
0
)
return
rc
?
rc
:
-
EINVAL
;
DPRINTK
(
"STEREO EXIT, returning %d
\n
"
,
val
);
return
0
;
/* query or set sampling rate */
case
SNDCTL_DSP_SPEED
:
get_user_ret
(
val
,
(
int
*
)
arg
,
-
EFAULT
);
if
(
val
<
0
)
return
-
EINVAL
;
if
(
val
>
0
)
{
rc
=
0
;
spin_lock_irqsave
(
&
card
->
lock
,
flags
);
if
(
rc
==
0
&&
rd
)
rc
=
via_chan_set_speed
(
card
,
&
card
->
ch_in
,
val
);
if
(
rc
==
0
&&
wr
)
rc
=
via_chan_set_speed
(
card
,
&
card
->
ch_out
,
val
);
spin_unlock_irqrestore
(
&
card
->
lock
,
flags
);
if
(
rc
<=
0
)
return
rc
?
rc
:
-
EINVAL
;
val
=
rc
;
}
else
{
spin_lock_irqsave
(
&
card
->
lock
,
flags
);
if
(
rd
)
val
=
card
->
ch_in
.
rate
;
else
if
(
wr
)
val
=
card
->
ch_out
.
rate
;
else
val
=
0
;
spin_unlock_irqrestore
(
&
card
->
lock
,
flags
);
}
DPRINTK
(
"SPEED EXIT, returning %d
\n
"
,
val
);
return
put_user
(
val
,
(
int
*
)
arg
);
pci_write_config_word
(
pdev
,
PCI_COMMAND
,
PCI_COMMAND_IO
);
/* wait until all buffers have been played, and then stop device */
case
SNDCTL_DSP_SYNC
:
if
(
wr
)
{
DPRINTK
(
"SYNC EXIT (after calling via_dsp_drain_dac)
\n
"
);
return
via_dsp_drain_dac
(
card
,
file
->
f_flags
&
O_NONBLOCK
);
}
break
;
/* stop recording/playback immediately */
case
SNDCTL_DSP_RESET
:
if
(
rd
)
{
spin_lock_irqsave
(
&
card
->
lock
,
flags
);
via_chan_clear
(
&
card
->
ch_in
);
via_chan_pcm_fmt
(
card
,
&
card
->
ch_in
,
1
);
spin_unlock_irqrestore
(
&
card
->
lock
,
flags
);
}
if
(
wr
)
{
spin_lock_irqsave
(
&
card
->
lock
,
flags
);
via_chan_clear
(
&
card
->
ch_out
);
via_chan_pcm_fmt
(
card
,
&
card
->
ch_out
,
1
);
spin_unlock_irqrestore
(
&
card
->
lock
,
flags
);
}
DPRINTK
(
"RESET EXIT, returning 0
\n
"
);
return
0
;
DPRINTK
(
"EXIT, returning 0
\n
"
);
/* obtain bitmask of device capabilities, such as mmap, full duplex, etc. */
return
0
;
case
SNDCTL_DSP_GETCAPS
:
}
DPRINTK
(
"GETCAPS EXIT
\n
"
);
return
put_user
(
DSP_CAP_REVISION
,
(
int
*
)
arg
);
/* obtain bitmask of device capabilities, such as mmap, full duplex, etc. */
case
SNDCTL_DSP_GETBLKSIZE
:
DPRINTK
(
"GETBLKSIZE EXIT
\n
"
);
return
put_user
(
VIA_DMA_BUF_SIZE
,
(
int
*
)
arg
);
/* obtain information about input buffering */
case
SNDCTL_DSP_GETISPACE
:
DPRINTK
(
"GETISPACE EXIT
\n
"
);
return
via_dsp_ioctl_space
(
card
,
&
card
->
ch_in
,
(
void
*
)
arg
);
/* obtain information about output buffering */
case
SNDCTL_DSP_GETOSPACE
:
DPRINTK
(
"GETOSPACE EXIT
\n
"
);
return
via_dsp_ioctl_space
(
card
,
&
card
->
ch_out
,
(
void
*
)
arg
);
/* return number of bytes remaining to be played by DMA engine */
case
SNDCTL_DSP_GETODELAY
:
{
int
n
;
n
=
atomic_read
(
&
card
->
ch_out
.
next_buf
)
-
atomic_read
(
&
card
->
ch_out
.
buf_in_use
);
assert
(
n
>=
0
);
if
(
n
==
0
)
val
=
0
;
else
{
val
=
(
n
-
1
)
*
VIA_DMA_BUF_SIZE
;
val
+=
inl
(
card
->
ch_out
.
iobase
+
VIA_BASE0_PCM_OUT_BLOCK_COUNT
);
}
DPRINTK
(
"GETODELAY EXIT, val = %d bytes
\n
"
,
val
);
return
put_user
(
val
,
(
int
*
)
arg
);
}
/* set fragment size. implemented as a successful no-op for now */
case
SNDCTL_DSP_SETFRAGMENT
:
get_user_ret
(
val
,
(
int
*
)
arg
,
-
EFAULT
);
static
struct
via_info
*
via_ac97_find_card_for_mixer
(
int
dev
)
DPRINTK
(
"SNDCTL_DSP_SETFRAGMENT (fragshift==0x%04X (%d), maxfrags==0x%04X (%d))
\n
"
,
{
val
&
0xFFFF
,
int
x
;
val
&
0xFFFF
,
(
val
>>
16
)
&
0xFFFF
,
(
val
>>
16
)
&
0xFFFF
);
DPRINTK
(
"ENTER
\n
"
);
/* just to shut up some programs */
return
0
;
for
(
x
=
0
;
x
<
num_cards
;
x
++
)
/* inform device of an upcoming pause in input (or output). not implemented */
if
(
cards
[
x
].
mixer_oss_dev
==
dev
)
{
case
SNDCTL_DSP_POST
:
DPRINTK
(
"EXIT, returning %p
\n
"
,
cards
+
x
);
DPRINTK
(
"POST EXIT (null ioctl, returning -EINVAL)
\n
"
);
return
cards
+
x
;
return
-
EINVAL
;
}
DPRINTK
(
"EXIT, returning 0
\n
"
);
/* not implemented */
return
NULL
;
default:
DPRINTK
(
"unhandled ioctl
\n
"
);
break
;
}
DPRINTK
(
"EXIT, returning %d
\n
"
,
rc
);
return
rc
;
}
}
static
int
static
int
via_dsp_open
(
struct
inode
*
inode
,
struct
file
*
file
)
via_ac97_default_mixer_ioctl
(
int
dev
,
unsigned
int
cmd
,
caddr_t
arg
)
{
{
int
rc
;
int
open_mode
,
rc
=
-
EINVAL
,
minor
=
MINOR
(
inode
->
i_rdev
);
struct
via_info
*
card
=
via_ac97_find_card_for_mixer
(
dev
);
int
got_read_chan
=
0
,
is_busy
;
struct
via_info
*
card
;
struct
pci_dev
*
pdev
;
struct
pci_driver
*
drvr
;
unsigned
long
flags
;
DPRINTK
(
"ENTER
\n
"
);
DPRINTK
(
"ENTER, minor=%d, file->f_mode=0x%x
\n
"
,
minor
,
file
->
f_mode
);
MOD_INC_USE_COUNT
;
if
(
file
->
f_mode
&
FMODE_READ
)
/* no input ATM */
goto
err_out
;
card
=
NULL
;
pci_for_each_dev
(
pdev
)
{
drvr
=
pci_dev_driver
(
pdev
);
if
(
drvr
==
&
via_driver
)
{
assert
(
pdev
->
driver_data
!=
NULL
);
card
=
pdev
->
driver_data
;
DPRINTK
(
"dev_dsp = %d, minor = %d, assn = %d
\n
"
,
card
->
dev_dsp
,
minor
,
(
card
->
dev_dsp
^
minor
)
&
~
0xf
);
if
(
card
!=
NULL
)
{
if
(((
card
->
dev_dsp
^
minor
)
&
~
0xf
)
==
0
)
rc
=
ac97_mixer_ioctl
(
&
card
->
ac97
,
cmd
,
arg
);
goto
match
;
DPRINTK
(
"EXIT, returning %d
\n
"
,
rc
);
}
return
rc
;
}
}
DPRINTK
(
"EXIT, returning -ENODEV
\n
"
);
DPRINTK
(
"no matching %s found
\n
"
,
card
?
"minor"
:
"driver"
);
return
-
ENODEV
;
rc
=
-
ENODEV
;
goto
err_out
;
}
match:
file
->
private_data
=
card
;
/* wait for device to become free */
spin_lock_irqsave
(
&
card
->
lock
,
flags
);
open_mode
=
card
->
open_mode
;
if
(
open_mode
&
file
->
f_mode
)
is_busy
=
1
;
else
{
is_busy
=
0
;
card
->
open_mode
|=
file
->
f_mode
;
open_mode
=
card
->
open_mode
;
}
spin_unlock_irqrestore
(
&
card
->
lock
,
flags
);
if
(
is_busy
)
{
rc
=
-
EBUSY
;
goto
err_out
;
}
static
struct
mixer_operations
via_ac97_mixer_operations
=
DPRINTK
(
"open_mode now 0x%x
\n
"
,
open_mode
);
{
"VIA82Cxxx"
,
"via82cxxxAC97Mixer"
,
via_ac97_default_mixer_ioctl
};
static
int
__init
via_attach_ac97
(
struct
via_info
*
card
)
/* handle input from analog source */
{
if
(
file
->
f_mode
&
FMODE_READ
)
{
int
mixer
;
rc
=
via_chan_init
(
card
,
&
card
->
ch_in
,
0x10
);
struct
ac97_hwint
*
mdev
;
if
(
rc
)
goto
err_out_clear_mode
;
got_read_chan
=
1
;
/* why is this forced to 16-bit stereo in all drivers? */
card
->
ch_in
.
pcm_fmt
=
VIA_PCM_FMT_16BIT
|
VIA_PCM_FMT_STEREO
;
DPRINTK
(
"ENTER
\n
"
);
spin_lock_irqsave
(
&
card
->
lock
,
flags
);
via_chan_pcm_fmt
(
card
,
&
card
->
ch_out
,
0
);
spin_unlock_irqrestore
(
&
card
->
lock
,
flags
);
assert
(
card
!=
NULL
);
via_set_adc_rate
(
card
,
8000
);
}
mdev
=
&
card
->
ac97
;
/* handle output to analog source */
if
(
file
->
f_mode
&
FMODE_WRITE
)
{
rc
=
via_chan_init
(
card
,
&
card
->
ch_out
,
0x00
);
if
(
rc
)
goto
err_out_clear_mode
;
if
((
minor
&
0xf
)
==
SND_DEV_DSP16
)
card
->
ch_out
.
pcm_fmt
|=
VIA_PCM_FMT_16BIT
;
memset
(
mdev
,
0
,
sizeof
(
*
mdev
));
spin_lock_irqsave
(
&
card
->
lock
,
flags
);
mdev
->
reset_device
=
via_ac97_reset
;
via_chan_pcm_fmt
(
card
,
&
card
->
ch_out
,
0
);
mdev
->
read_reg
=
via_ac97_read_reg
;
spin_unlock_irqrestore
(
&
card
->
lock
,
flags
);
mdev
->
write_reg
=
via_ac97_write_reg
;
mdev
->
driver_private
=
(
void
*
)
card
;
if
(
ac97_init
(
mdev
))
{
via_set_dac_rate
(
card
,
8000
);
printk
(
KERN_ERR
PFX
"Unable to init AC97
\n
"
);
DPRINTK
(
"EXIT, returning -1
\n
"
);
return
-
1
;
}
mixer
=
sound_alloc_mixerdev
();
if
(
mixer
<
0
||
num_mixers
>=
MAX_MIXER_DEV
)
{
printk
(
KERN_ERR
PFX
"Unable to alloc mixerdev
\n
"
);
DPRINTK
(
"EXIT, returning -1
\n
"
);
return
-
1
;
}
}
mixer_devs
[
mixer
]
=
&
via_ac97_mixer_operations
;
card
->
mixer_oss_dev
=
mixer
;
/* Some reasonable default values. */
ac97_set_mixer
(
mdev
,
SOUND_MIXER_VOLUME
,
(
85
<<
8
)
|
85
);
ac97_set_mixer
(
mdev
,
SOUND_MIXER_SPEAKER
,
100
);
ac97_set_mixer
(
mdev
,
SOUND_MIXER_PCM
,
(
65
<<
8
)
|
65
);
ac97_set_mixer
(
mdev
,
SOUND_MIXER_CD
,
(
65
<<
8
)
|
65
);
printk
(
KERN_INFO
PFX
"Initialized AC97 mixer
\n
"
);
card
->
have_ac97
=
mixer
;
DPRINTK
(
"EXIT, returning 0
\n
"
);
DPRINTK
(
"EXIT, returning 0
\n
"
);
return
0
;
return
0
;
err_out_clear_mode:
if
(
got_read_chan
)
via_chan_free
(
card
,
&
card
->
ch_in
);
spin_lock_irqsave
(
&
card
->
lock
,
flags
);
card
->
open_mode
&=
~
file
->
f_mode
;
spin_unlock_irqrestore
(
&
card
->
lock
,
flags
);
err_out:
MOD_DEC_USE_COUNT
;
DPRINTK
(
"ERROR EXIT, returning %d
\n
"
,
rc
);
return
rc
;
}
}
static
void
via_unload_ac97
(
struct
via_info
*
card
)
static
int
via_dsp_release
(
struct
inode
*
inode
,
struct
file
*
file
)
{
{
DPRINTK
(
"ENTER
\n
"
);
struct
via_info
*
card
;
unsigned
long
flags
;
DPRINTK
(
"ENTER
\n
"
);
assert
(
file
!=
NULL
);
card
=
file
->
private_data
;
assert
(
card
!=
NULL
);
assert
(
card
!=
NULL
);
if
(
file
->
f_mode
&
FMODE_READ
)
via_chan_free
(
card
,
&
card
->
ch_in
);
if
(
card
->
have_ac97
>=
0
)
if
(
file
->
f_mode
&
FMODE_WRITE
)
{
sound_unload_mixerdev
(
card
->
have_ac97
);
via_dsp_drain_dac
(
card
,
file
->
f_flags
&
O_NONBLOCK
);
via_chan_free
(
card
,
&
card
->
ch_out
);
}
spin_lock_irqsave
(
&
card
->
lock
,
flags
);
card
->
open_mode
&=
~
(
file
->
f_mode
);
spin_unlock_irqrestore
(
&
card
->
lock
,
flags
);
DPRINTK
(
"EXIT
\n
"
);
wake_up
(
&
card
->
open_wait
);
MOD_DEC_USE_COUNT
;
DPRINTK
(
"EXIT, returning 0
\n
"
);
return
0
;
}
}
#ifdef
CONFIG
_PROC_FS
#ifdef
VIA
_PROC_FS
/****************************************************************
/****************************************************************
*
*
* /proc/driver/via
82cxxx
/info
* /proc/driver/via/info
*
*
*
*
*/
*/
...
@@ -365,64 +2104,84 @@ static int via_info_read_proc (char *page, char **start, off_t off,
...
@@ -365,64 +2104,84 @@ static int via_info_read_proc (char *page, char **start, off_t off,
int
count
,
int
*
eof
,
void
*
data
)
int
count
,
int
*
eof
,
void
*
data
)
{
{
#define YN(val,bit) (((val) & (bit)) ? "yes" : "no")
#define YN(val,bit) (((val) & (bit)) ? "yes" : "no")
#define ED(val,bit) (((val) & (bit)) ? "enable" : "disable")
int
len
=
0
,
i
;
int
len
=
0
;
u8
r40
,
r41
,
r42
,
r44
;
u8
r40
,
r41
,
r42
,
r44
;
struct
via_info
*
card
=
data
;
u16
tmp16
;
DPRINTK
(
"ENTER
\n
"
);
DPRINTK
(
"ENTER
\n
"
);
assert
(
card
!=
NULL
);
len
+=
sprintf
(
page
+
len
,
VIA_CARD_NAME
"
\n\n
"
);
len
+=
sprintf
(
page
+
len
,
VIA_CARD_NAME
"
\n\n
"
);
for
(
i
=
0
;
i
<
num_cards
;
i
++
)
{
pci_read_config_byte
(
card
->
pdev
,
0x40
,
&
r40
);
pci_read_config_byte
(
cards
[
i
].
pdev
,
0x40
,
&
r40
);
pci_read_config_byte
(
card
->
pdev
,
0x41
,
&
r41
);
pci_read_config_byte
(
cards
[
i
].
pdev
,
0x42
,
&
r41
);
pci_read_config_byte
(
card
->
pdev
,
0x42
,
&
r42
);
pci_read_config_byte
(
cards
[
i
].
pdev
,
0x42
,
&
r42
);
pci_read_config_byte
(
card
->
pdev
,
0x44
,
&
r44
);
pci_read_config_byte
(
cards
[
i
].
pdev
,
0x44
,
&
r44
);
len
+=
sprintf
(
page
+
len
,
len
+=
sprintf
(
page
+
len
,
"40 AC97 Codec Ready: %s
\n
"
"Via 82Cxxx PCI registers:
\n
"
" AC97 Codec Low-power: %s
\n
"
"
\n
"
" Secondary Codec Ready: %s
\n
"
"40 Codec Ready: %s
\n
"
" Codec Low-power: %s
\n
"
"41 AC-Link Interface Enable: %s
\n
"
" Secondary Codec Ready: %s
\n
"
"
\n
"
"42 Game port enabled: %s
\n
"
"41 Interface Enable: %s
\n
"
" SoundBlaster enabled: %s
\n
"
" De-Assert Reset: %s
\n
"
" FM enabled: %s
\n
"
" Force SYNC high: %s
\n
"
" MIDI enabled: %s
\n
"
" Force SDO high: %s
\n
"
" Variable Sample Rate On-Demand Mode: %s
\n
"
" SGD Read Channel PCM Data Out: %s
\n
"
" FM Channel PCM Data Out: %s
\n
"
" SB PCM Data Out: %s
\n
"
"
\n
"
"42 Game port enabled: %s
\n
"
" SoundBlaster enabled: %s
\n
"
" FM enabled: %s
\n
"
" MIDI enabled: %s
\n
"
"
\n
"
"44 AC-Link Interface Access: %s
\n
"
" Secondary Codec Support: %s
\n
"
"44 AC-Link Interface Access: %s
\n
"
"
\n
"
,
" Secondary Codec Support: %s
\n
"
"
\n
"
,
YN
(
r40
,
VIA_CR40_AC97_READY
),
YN
(
r40
,
VIA_CR40_AC97_LOW_POWER
),
YN
(
r40
,
VIA_CR40_SECONDARY_READY
),
ED
(
r41
,
VIA_CR41_AC97_ENABLE
),
YN
(
r41
,
(
1
<<
6
)),
YN
(
r41
,
(
1
<<
5
)),
YN
(
r41
,
(
1
<<
4
)),
ED
(
r41
,
(
1
<<
3
)),
ED
(
r41
,
(
1
<<
2
)),
ED
(
r41
,
(
1
<<
1
)),
ED
(
r41
,
(
1
<<
0
)),
YN
(
r42
,
VIA_CR42_GAME_ENABLE
),
YN
(
r42
,
VIA_CR42_SB_ENABLE
),
YN
(
r42
,
VIA_CR42_FM_ENABLE
),
YN
(
r42
,
VIA_CR42_MIDI_ENABLE
),
YN
(
r44
,
VIA_CR44_AC_LINK_ACCESS
),
YN
(
r44
,
VIA_CR44_SECOND_CODEC_SUPPORT
)
YN
(
r40
,
VIA_CR40_AC97_READY
),
);
YN
(
r40
,
VIA_CR40_AC97_LOW_POWER
),
YN
(
r40
,
VIA_CR40_SECONDARY_READY
),
YN
(
r41
,
VIA_CR41_ACLINK_ENABLE
),
YN
(
r42
,
VIA_CR42_GAME_ENABLE
),
YN
(
r42
,
VIA_CR42_SB_ENABLE
),
YN
(
r42
,
VIA_CR42_FM_ENABLE
),
YN
(
r42
,
VIA_CR42_MIDI_ENABLE
),
YN
(
r44
,
VIA_CR44_AC_LINK_ACCESS
),
YN
(
r44
,
VIA_CR44_SECOND_CODEC_SUPPORT
)
);
}
DPRINTK
(
"EXIT, returning %d
\n
"
,
len
);
DPRINTK
(
"EXIT, returning %d
\n
"
,
len
);
return
len
;
return
len
;
#undef YN
#undef YN
#undef ED
}
}
/****************************************************************
/****************************************************************
*
*
* /proc/driver/via
82cxxx
* /proc/driver/via
/... setup and cleanup
*
*
*
*
*/
*/
...
@@ -431,87 +2190,93 @@ static int __init via_init_proc (void)
...
@@ -431,87 +2190,93 @@ static int __init via_init_proc (void)
{
{
DPRINTK
(
"ENTER
\n
"
);
DPRINTK
(
"ENTER
\n
"
);
proc_mkdir
(
"driver/via_audio"
,
0
);
if
(
!
proc_mkdir
(
"driver/via"
,
0
))
create_proc_read_entry
(
"driver/via_audio/info"
,
0
,
0
,
via_info_read_proc
,
NULL
)
;
return
-
EIO
;
DPRINTK
(
"EXIT
\n
"
);
DPRINTK
(
"EXIT, returning 0
\n
"
);
return
0
;
return
0
;
}
}
static
void
via_cleanup_proc
(
void
)
static
void
__exit
via_cleanup_proc
(
void
)
{
{
DPRINTK
(
"ENTER
\n
"
);
DPRINTK
(
"ENTER
\n
"
);
remove_proc_entry
(
"driver/via_audio/info"
,
NULL
);
remove_proc_entry
(
"driver/via_audio"
,
NULL
);
DPRINTK
(
"EXIT
\n
"
);
}
#else
static
inline
int
via_init_proc
(
void
)
{
return
0
;
}
static
inline
void
via_cleanup_proc
(
void
)
{}
#endif
/* CONFIG_PROC_FS */
remove_proc_entry
(
"driver/via"
,
NULL
);
DPRINTK
(
"EXIT
\n
"
);
}
/****************************************************************
*
* Legacy SoundBlaster Pro, FM support via OSS
*
*
*/
static
void
__init
via_attach_sb
(
struct
address_info
*
hw_config
)
static
int
__init
via_card_init_proc
(
struct
via_info
*
card
)
{
{
char
s
[
32
];
int
rc
;
DPRINTK
(
"ENTER
\n
"
);
DPRINTK
(
"ENTER
\n
"
);
if
(
!
sb_dsp_init
(
hw_config
))
sprintf
(
s
,
"driver/via/%d"
,
card
->
card_num
);
hw_config
->
slots
[
0
]
=
-
1
;
if
(
!
proc_mkdir
(
s
,
0
))
{
rc
=
-
EIO
;
goto
err_out_none
;
}
sprintf
(
s
,
"driver/via/%d/info"
,
card
->
card_num
);
if
(
!
create_proc_read_entry
(
s
,
0
,
0
,
via_info_read_proc
,
card
))
{
rc
=
-
EIO
;
goto
err_out_dir
;
}
DPRINTK
(
"EXIT
\n
"
);
sprintf
(
s
,
"driver/via/%d/ac97"
,
card
->
card_num
);
}
if
(
!
create_proc_read_entry
(
s
,
0
,
0
,
ac97_read_proc
,
&
card
->
ac97
))
{
rc
=
-
EIO
;
goto
err_out_info
;
}
DPRINTK
(
"EXIT, returning 0
\n
"
);
return
0
;
static
int
__init
via_probe_sb
(
struct
address_info
*
hw_config
)
err_out_info:
{
sprintf
(
s
,
"driver/via/%d/info"
,
card
->
card_num
);
DPRINTK
(
"ENTER
\n
"
);
remove_proc_entry
(
s
,
NULL
);
if
(
check_region
(
hw_config
->
io_base
,
16
))
err_out_dir:
{
sprintf
(
s
,
"driver/via/%d"
,
card
->
card_num
);
printk
(
KERN_DEBUG
PFX
"SBPro port 0x%x is already in use
\n
"
,
remove_proc_entry
(
s
,
NULL
);
hw_config
->
io_base
);
return
0
;
err_out_none:
}
DPRINTK
(
"EXIT, returning %d
\n
"
,
rc
);
DPRINTK
(
"EXIT after sb_dsp_detect
\n
"
);
return
rc
;
return
sb_dsp_detect
(
hw_config
,
0
,
0
,
NULL
);
}
}
static
void
__exit
via_unload_sb
(
struct
address_info
*
hw_config
)
static
void
via_card_cleanup_proc
(
struct
via_info
*
card
)
{
{
char
s
[
32
];
DPRINTK
(
"ENTER
\n
"
);
DPRINTK
(
"ENTER
\n
"
);
if
(
hw_config
->
slots
[
0
]
!=
-
1
)
sprintf
(
s
,
"driver/via/%d/ac97"
,
card
->
card_num
);
sb_dsp_unload
(
hw_config
,
1
);
remove_proc_entry
(
s
,
NULL
);
DPRINTK
(
"EXIT
\n
"
);
sprintf
(
s
,
"driver/via/%d/info"
,
card
->
card_num
);
remove_proc_entry
(
s
,
NULL
);
sprintf
(
s
,
"driver/via/%d"
,
card
->
card_num
);
remove_proc_entry
(
s
,
NULL
);
DPRINTK
(
"EXIT
\n
"
);
}
}
static
const
struct
{
#else
int
sb_irq
,
sb_dma
,
static
inline
int
via_init_proc
(
void
)
{
return
0
;
}
midi_base
,
static
inline
void
via_cleanup_proc
(
void
)
{}
sb_io_base
;
static
inline
int
via_card_init_proc
(
struct
via_info
*
card
)
{
return
0
;
}
}
via_pnp_data
[]
__initdata
=
{
static
inline
void
via_card_cleanup_proc
(
struct
via_info
*
card
)
{}
{
5
,
0
,
0x300
,
0x220
},
{
7
,
1
,
0x310
,
0x240
},
#endif
/* VIA_PROC_FS */
{
9
,
2
,
0x320
,
0x260
},
{
10
,
3
,
0x330
,
0x280
},
};
/****************************************************************
/****************************************************************
...
@@ -521,202 +2286,251 @@ static const struct {
...
@@ -521,202 +2286,251 @@ static const struct {
*
*
*/
*/
static
int
__init
via
82cxxx_install
(
struct
pci_dev
*
pcidev
)
static
int
__init
via
_init_one
(
struct
pci_dev
*
pdev
,
const
struct
pci_device_id
*
id
)
{
{
int
sb_io_base
;
int
rc
;
int
sb_irq
;
struct
via_info
*
card
;
int
sb_dma
;
u8
tmp
;
int
midi_base
,
rc
;
static
int
printed_version
=
0
;
u8
tmp8
;
struct
via_info
*
card
=
&
cards
[
num_cards
];
DPRINTK
(
"ENTER
\n
"
);
DPRINTK
(
"ENTER
\n
"
);
if
(
printed_version
++
==
0
)
printk
(
KERN_INFO
"Via 686a audio driver "
VIA_VERSION
"
\n
"
);
if
(
!
request_region
(
pci_resource_start
(
pdev
,
0
),
pci_resource_len
(
pdev
,
0
),
VIA_MODULE_NAME
))
{
printk
(
KERN_ERR
PFX
"unable to obtain I/O resources, aborting
\n
"
);
rc
=
-
EBUSY
;
goto
err_out
;
}
card
->
pdev
=
pcidev
;
#if 0
card
->
have_ac97
=
-
1
;
/* chipset init copied from via */
pci_write_config_byte(pdev, 0x41,(0xc0));
udelay(10);
pci_read_config_byte(pdev, 0x41, &tmp);
udelay(10);
pci_write_config_byte(pdev, 0x41,(tmp | 0x0f));
udelay(10);
pci_read_config_byte(pdev, 0x42, &tmp);
udelay(10);
pci_write_config_byte(pdev, 0x42,(tmp | 0x3f));
#endif
if
(
pci_enable_device
(
pdev
))
{
rc
=
-
EIO
;
goto
err_out_none
;
}
/* turn off legacy features, if not already */
#if 0
pci_read_config_byte
(
pcidev
,
VIA_FUNC_ENABLE
,
&
tmp8
);
/* chipset init copied from ALSA */
tmp8
&=
~
(
VIA_CR42_SB_ENABLE
|
VIA_CR42_MIDI_ENABLE
|
pci_write_config_byte(pdev, 0x42, 0);
VIA_CR42_FM_ENABLE
);
pci_write_config_byte(pdev, 0x41, 0x40);
pci_write_config_byte
(
pcidev
,
VIA_FUNC_ENABLE
,
tmp8
);
udelay(100);
pci_write_config_byte(pdev, 0x41, 0x60);
udelay(10);
pci_write_config_byte(pdev, 0x41, 0xCC);
udelay(10);
{
u32 data = ((AC97_POWER_CONTROL & 0x7F) << 16) | 0x0000;
udelay(100);
outl (data, pci_resource_start (pdev, 0) + VIA_BASE0_AC97_CTRL);
}
#endif
card
=
kmalloc
(
sizeof
(
*
card
),
GFP_KERNEL
);
if
(
!
card
)
{
printk
(
KERN_ERR
PFX
"out of memory, aborting
\n
"
);
rc
=
-
ENOMEM
;
goto
err_out_none
;
}
pdev
->
driver_data
=
card
;
memset
(
card
,
0
,
sizeof
(
*
card
));
card
->
pdev
=
pdev
;
card
->
baseaddr
=
pci_resource_start
(
pdev
,
0
);
card
->
card_num
=
via_num_cards
++
;
spin_lock_init
(
&
card
->
lock
);
init_waitqueue_head
(
&
card
->
open_wait
);
/* if BAR 2 is present, chip is Rev H or later,
* which means it has a few extra features */
if
(
pci_resource_start
(
pdev
,
2
)
>
0
)
card
->
rev_h
=
1
;
if
(
pdev
->
irq
<
1
)
{
printk
(
KERN_ERR
PFX
"invalid PCI IRQ %d, aborting
\n
"
,
pdev
->
irq
);
rc
=
-
ENODEV
;
goto
err_out_kfree
;
}
if
(
!
(
pci_resource_flags
(
pdev
,
0
)
&
IORESOURCE_IO
))
{
printk
(
KERN_ERR
PFX
"unable to locate I/O resources, aborting
\n
"
);
rc
=
-
ENODEV
;
goto
err_out_kfree
;
}
/*
/*
*
try to init AC97 mixer device
*
init AC97 mixer and codec
*/
*/
rc
=
via_a
ttach_ac97
(
card
);
rc
=
via_a
c97_init
(
card
);
if
(
rc
)
{
if
(
rc
)
{
printk
(
KERN_
WARNING
PFX
printk
(
KERN_
ERR
PFX
"AC97 init failed, aborting
\n
"
);
"AC97 init failed, SB legacy mode only
\n
"
)
;
goto
err_out_kfree
;
}
}
/* turn on legacy features */
pci_read_config_byte
(
pcidev
,
VIA_FUNC_ENABLE
,
&
tmp8
);
tmp8
|=
VIA_CR42_SB_ENABLE
|
VIA_CR42_MIDI_ENABLE
|
VIA_CR42_FM_ENABLE
;
pci_write_config_byte
(
pcidev
,
VIA_FUNC_ENABLE
,
tmp8
);
/* read legacy PNP info byte */
/*
pci_read_config_byte
(
pcidev
,
VIA_PNP_CONTROL
,
&
tmp8
);
* init DSP device
pci_write_config_byte
(
pcidev
,
VIA_PNP_CONTROL
,
tmp8
);
*/
rc
=
via_dsp_init
(
card
);
if
(
rc
)
{
printk
(
KERN_ERR
PFX
"DSP device init failed, aborting
\n
"
);
goto
err_out_have_mixer
;
}
sb_irq
=
via_pnp_data
[((
tmp8
>>
6
)
&
0x03
)].
sb_irq
;
/*
sb_dma
=
via_pnp_data
[((
tmp8
>>
4
)
&
0x03
)].
sb_dma
;
* per-card /proc info
midi_base
=
via_pnp_data
[((
tmp8
>>
2
)
&
0x03
)].
midi_base
;
*/
sb_io_base
=
via_pnp_data
[(
tmp8
&
0x03
)].
sb_io_base
;
rc
=
via_card_init_proc
(
card
);
if
(
rc
)
{
printk
(
KERN_ERR
PFX
"card-specific /proc init failed, aborting
\n
"
);
goto
err_out_have_dsp
;
}
udelay
(
100
);
/*
* init and turn on interrupts, as the last thing we do
*/
rc
=
via_interrupt_init
(
card
);
if
(
rc
)
{
printk
(
KERN_ERR
PFX
"interrupt init failed, aborting
\n
"
);
goto
err_out_have_proc
;
}
printk
(
KERN_INFO
PFX
"legacy "
pci_read_config_byte
(
pdev
,
0x3C
,
&
tmp
);
"MIDI: 0x%X, SB: 0x%X / %d IRQ / %d DMA
\n
"
,
if
((
tmp
&
0x0F
)
!=
pdev
->
irq
)
{
midi_base
,
sb_io_base
,
sb_irq
,
sb_dma
);
printk
(
KERN_WARNING
PFX
"IRQ fixup, 0x3C==0x%02X
\n
"
,
tmp
);
tmp
&=
0xF0
;
card
->
sb_data
.
name
=
VIA_CARD_NAME
;
tmp
|=
pdev
->
irq
;
card
->
sb_data
.
card_subtype
=
MDL_SBPRO
;
pci_write_config_byte
(
pdev
,
0x3C
,
tmp
);
card
->
sb_data
.
io_base
=
sb_io_base
;
DPRINTK
(
"new 0x3c==0x%02x
\n
"
,
tmp
);
card
->
sb_data
.
irq
=
sb_irq
;
card
->
sb_data
.
dma
=
sb_dma
;
/* register legacy SoundBlaster Pro */
if
(
!
via_probe_sb
(
&
card
->
sb_data
))
{
printk
(
KERN_ERR
PFX
"SB probe @ 0x%X failed, aborting
\n
"
,
sb_io_base
);
DPRINTK
(
"EXIT, returning -1
\n
"
);
return
-
1
;
}
via_attach_sb
(
&
card
->
sb_data
);
card
->
opl3_data
.
name
=
card
->
sb_data
.
name
;
card
->
opl3_data
.
io_base
=
midi_base
;
card
->
opl3_data
.
irq
=
-
1
;
/* register legacy MIDI */
if
(
!
probe_uart401
(
&
card
->
opl3_data
))
{
printk
(
KERN_WARNING
PFX
"MIDI probe @ 0x%X failed, continuing
\n
"
,
midi_base
);
card
->
opl3_data
.
io_base
=
0
;
}
else
{
}
else
{
attach_uart401
(
&
card
->
opl3_data
);
DPRINTK
(
"IRQ reg 0x3c==0x%02x, irq==%d
\n
"
,
tmp
,
tmp
&
0x0F
);
}
}
num_cards
++
;
printk
(
KERN_INFO
PFX
"board #%d at 0x%04lX, IRQ %d
\n
"
,
card
->
card_num
+
1
,
card
->
baseaddr
,
pdev
->
irq
);
DPRINTK
(
"EXIT, returning 0
\n
"
);
DPRINTK
(
"EXIT, returning 0
\n
"
);
return
0
;
return
0
;
err_out_have_proc:
via_card_cleanup_proc
(
card
);
err_out_have_dsp:
via_dsp_cleanup
(
card
);
err_out_have_mixer:
via_ac97_cleanup
(
card
);
err_out_kfree:
#ifndef VIA_NDEBUG
memset
(
card
,
0xAB
,
sizeof
(
*
card
));
/* poison memory */
#endif
kfree
(
card
);
err_out_none:
release_region
(
pci_resource_start
(
pdev
,
0
),
pci_resource_len
(
pdev
,
0
));
err_out:
pdev
->
driver_data
=
NULL
;
DPRINTK
(
"EXIT - returning %d
\n
"
,
rc
);
return
rc
;
}
}
/*
static
void
__exit
via_remove_one
(
struct
pci_dev
*
pdev
)
* This loop walks the PCI configuration database and finds where
* the sound cards are.
*
* Note - only a single PCI scan occurs, eliminating possibility
* of multiple audio chips
*
*/
static
int
__init
probe_via82cxxx
(
void
)
{
{
struct
pci_dev
*
pcidev
=
NULL
;
struct
via_info
*
card
;
DPRINTK
(
"ENTER
\n
"
);
DPRINTK
(
"ENTER
\n
"
);
assert
(
pdev
!=
NULL
);
card
=
pdev
->
driver_data
;
assert
(
card
!=
NULL
);
via_interrupt_cleanup
(
card
);
via_card_cleanup_proc
(
card
);
via_dsp_cleanup
(
card
);
pcidev
=
pci_find_device
(
PCI_VENDOR_ID_VIA
,
release_region
(
pci_resource_start
(
pdev
,
0
),
pci_resource_len
(
pdev
,
0
));
PCI_DEVICE_ID_VIA_82C686_5
,
NULL
);
if
(
!
pcidev
||
via82cxxx_install
(
pcidev
)
!=
0
)
{
#ifndef VIA_NDEBUG
printk
(
KERN_ERR
PFX
"audio init failed
\n
"
);
memset
(
card
,
0xAB
,
sizeof
(
*
card
));
/* poison memory */
DPRINTK
(
"EXIT, returning -1
\n
"
);
#endif
return
-
1
;
kfree
(
card
);
}
DPRINTK
(
"EXIT, returning 0
\n
"
);
pdev
->
driver_data
=
NULL
;
return
0
;
pci_set_power_state
(
pdev
,
3
);
/* ...zzzzzz */
DPRINTK
(
"EXIT
\n
"
);
return
;
}
}
/*
/****************************************************************
* This function is called when the user or kernel loads the
*
* module into memory.
* Driver initialization and cleanup
*
*
*/
*/
static
int
__init
init_via82cxxx_audio
(
void
)
static
int
__init
init_via82cxxx_module
(
void
)
{
{
u8
tmp
;
int
rc
;
int
i
;
const
char
*
rev
=
"unknown!"
;
memset
(
cards
,
0
,
sizeof
(
cards
));
DPRINTK
(
"ENTER
\n
"
);
DPRINTK
(
"ENTER
\n
"
);
MOD_INC_USE_COUNT
;
if
(
!
pci_present
())
{
rc
=
via_init_proc
();
printk
(
KERN_DEBUG
PFX
"PCI not present, exiting
\n
"
);
if
(
rc
)
{
DPRINTK
(
"EXIT, returning -ENODEV
\n
"
);
MOD_DEC_USE_COUNT
;
return
-
ENODEV
;
DPRINTK
(
"EXIT, returning %d
\n
"
,
rc
);
return
rc
;
}
}
if
(
probe_via82cxxx
()
!=
0
)
{
rc
=
pci_register_driver
(
&
via_driver
);
printk
(
KERN_ERR
PFX
"probe failed, aborting
\n
"
);
if
(
rc
<
1
)
{
/* XXX unload cards registered so far, if any */
if
(
rc
==
0
)
pci_unregister_driver
(
&
via_driver
);
via_cleanup_proc
();
MOD_DEC_USE_COUNT
;
DPRINTK
(
"EXIT, returning -ENODEV
\n
"
);
DPRINTK
(
"EXIT, returning -ENODEV
\n
"
);
return
-
ENODEV
;
return
-
ENODEV
;
}
}
pci_read_config_byte
(
cards
[
0
].
pdev
,
PCI_REVISION_ID
,
&
tmp
);
MOD_DEC_USE_COUNT
;
for
(
i
=
0
;
i
<
arraysize
(
via_chip_revs
);
i
++
)
if
(
via_chip_revs
[
i
].
revision
==
tmp
)
{
rev
=
via_chip_revs
[
i
].
rev_name
;
break
;
}
printk
(
KERN_INFO
PFX
VIA_CARD_NAME
" loaded
\n
"
);
printk
(
KERN_INFO
PFX
"Chip rev %s. Features: SBPro compat%s%s
\n
"
,
rev
,
cards
[
0
].
opl3_data
.
io_base
==
0
?
""
:
", MPU-401 MIDI"
,
cards
[
0
].
have_ac97
==
-
1
?
""
:
", AC97 mixer"
);
if
(
via_init_proc
()
!=
0
)
{
printk
(
KERN_WARNING
PFX
"Unable to init experimental /proc, ignoring
\n
"
);
}
/*
* Binds us to the sound subsystem
*/
SOUND_LOCK
;
DPRINTK
(
"EXIT, returning 0
\n
"
);
DPRINTK
(
"EXIT, returning 0
\n
"
);
return
0
;
return
0
;
}
}
/*
* This is called when it is removed. It will only be removed
* when its use count is 0. For sound the SOUND_LOCK/SOUND_UNLOCK
* macros hide the entire work for this.
*/
static
void
__exit
cleanup_via82cxxx_
module
(
void
)
static
void
__exit
cleanup_via82cxxx_
audio
(
void
)
{
{
DPRINTK
(
"ENTER
\n
"
);
DPRINTK
(
"ENTER
\n
"
);
if
(
cards
[
0
].
opl3_data
.
io_base
)
pci_unregister_driver
(
&
via_driver
);
unload_uart401
(
&
cards
[
0
].
opl3_data
);
via_unload_sb
(
&
cards
[
0
].
sb_data
);
via_unload_ac97
(
&
cards
[
0
]);
via_cleanup_proc
();
via_cleanup_proc
();
/*
* Final clean up with the sound layer
*/
SOUND_LOCK_END
;
DPRINTK
(
"EXIT
\n
"
);
DPRINTK
(
"EXIT
\n
"
);
}
}
module_init
(
init_via82cxxx_module
);
module_exit
(
cleanup_via82cxxx_module
);
module_init
(
init_via82cxxx_audio
);
module_exit
(
cleanup_via82cxxx_audio
);
drivers/usb/ov511.c
View file @
5cb39380
/*
/*
* OmniVision OV511 Camera-to-USB Bridge Driver
* OmniVision OV511 Camera-to-USB Bridge Driver
* Copyright (c) 1999/2000 Mark W. McClelland
*
* Copyright (c) 1999-2000 Mark W. McClelland
* Many improvements by Bret Wallach
* Many improvements by Bret Wallach
* Color fixes by by Orion Sky Lawlor, olawlor@acm.org, 2/26/2000
* Color fixes by by Orion Sky Lawlor, olawlor@acm.org, 2/26/2000
* Snapshot code by Kevin Moore
* Snapshot code by Kevin Moore
* OV7620 fixes by Charl P. Botha <cpbotha@ieee.org>
* OV7620 fixes by Charl P. Botha <cpbotha@ieee.org>
* Changes by Claudio Matsuoka, claudio@conectiva.com, 3/26/2000
*
*
* Based on the Linux CPiA driver.
* Based on the Linux CPiA driver written by Peter Pregler,
* Scott J. Bertin and Johannes Erdfelt.
*
*
* Released under GPL v.2 license.
*
* Version: 1.11
*
* Please see the file: linux/Documentation/usb/ov511.txt
* Please see the file: linux/Documentation/usb/ov511.txt
* and the website at: http://alpha.dyndns.org/ov511
* and the website at: http://alpha.dyndns.org/ov511
* for more info.
* for more info.
*/
*
/*
* This program is free software; you can redistribute it and/or modify it
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* Free Software Foundation; either version 2 of the License, or (at your
...
@@ -33,23 +30,28 @@
...
@@ -33,23 +30,28 @@
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
*/
static
const
char
version
[]
=
"1.13"
;
#define __NO_VERSION__
#define __NO_VERSION__
#include <linux/kernel.h>
#include <linux/config.h>
#include <linux/sched.h>
#include <linux/list.h>
#include <linux/malloc.h>
#include <linux/mm.h>
#include <linux/smp_lock.h>
#include <linux/videodev.h>
#include <linux/vmalloc.h>
#include <linux/wrapper.h>
#include <linux/module.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/init.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/fs.h>
#include <linux/time.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
#include <linux/proc_fs.h>
#include <linux/ctype.h>
#include <linux/pagemap.h>
#include <linux/usb.h>
#include <linux/usb.h>
#include <asm/io.h>
#include <asm/io.h>
#include <asm/semaphore.h>
#include <linux/wrapper.h>
#ifdef CONFIG_KMOD
#include <linux/kmod.h>
#endif
#include "ov511.h"
#include "ov511.h"
...
@@ -59,11 +61,10 @@
...
@@ -59,11 +61,10 @@
#define MAX_FRAME_SIZE (640 * 480 * 3)
#define MAX_FRAME_SIZE (640 * 480 * 3)
#define MAX_DATA_SIZE (MAX_FRAME_SIZE + sizeof(struct timeval))
#define MAX_DATA_SIZE (MAX_FRAME_SIZE + sizeof(struct timeval))
// FIXME - Should find a better way to do this.
#define DEFAULT_WIDTH 640
#define DEFAULT_WIDTH 640
#define DEFAULT_HEIGHT 480
#define DEFAULT_HEIGHT 480
/
/ PARAMETER VARIABLES:
/
* PARAMETER VARIABLES: */
static
int
autoadjust
=
1
;
/* CCD dynamically changes exposure, etc... */
static
int
autoadjust
=
1
;
/* CCD dynamically changes exposure, etc... */
/* 0=no debug messages
/* 0=no debug messages
...
@@ -85,24 +86,61 @@ static int snapshot = 0;
...
@@ -85,24 +86,61 @@ static int snapshot = 0;
/* Sensor detection override (global for all attached cameras) */
/* Sensor detection override (global for all attached cameras) */
static
int
sensor
=
0
;
static
int
sensor
=
0
;
/* Increase this if you are getting "Failed to read sensor ID..." */
static
int
i2c_detect_tries
=
5
;
/* For legal values, see the OV7610/7620 specs under register Common F,
upper nybble (set to 0-F) */
static
int
aperture
=
-
1
;
MODULE_PARM
(
autoadjust
,
"i"
);
MODULE_PARM
(
autoadjust
,
"i"
);
MODULE_PARM
(
debug
,
"i"
);
MODULE_PARM
(
debug
,
"i"
);
MODULE_PARM
(
fix_rgb_offset
,
"i"
);
MODULE_PARM
(
fix_rgb_offset
,
"i"
);
MODULE_PARM
(
snapshot
,
"i"
);
MODULE_PARM
(
snapshot
,
"i"
);
MODULE_PARM
(
sensor
,
"i"
);
MODULE_PARM
(
sensor
,
"i"
);
MODULE_PARM
(
i2c_detect_tries
,
"i"
);
MODULE_PARM
(
aperture
,
"i"
);
MODULE_AUTHOR
(
"Mark McClelland (and others)"
);
MODULE_AUTHOR
(
"Mark McClelland (and others)"
);
MODULE_DESCRIPTION
(
"OV511 USB Camera Driver"
);
MODULE_DESCRIPTION
(
"OV511 USB Camera Driver"
);
char
kernel_version
[]
=
UTS_RELEASE
;
char
kernel_version
[]
=
UTS_RELEASE
;
/*******************************/
static
struct
usb_driver
ov511_driver
;
/* Memory management functions */
/*******************************/
#define MDEBUG(x) do { } while(0)
/* Debug memory management */
/**********************************************************************
* List of known OV511-based cameras
**********************************************************************/
static
struct
cam_list
clist
[]
=
{
{
0
,
"generic model (no ID)"
},
{
3
,
"D-Link DSB-C300"
},
{
4
,
"generic OV511/OV7610"
},
{
5
,
"Puretek PT-6007"
},
{
21
,
"Creative Labs WebCam 3"
},
{
36
,
"Koala-Cam"
},
{
38
,
"Lifeview USB Life TV"
},
/* No support yet! */
{
100
,
"Lifeview RoboCam"
},
{
102
,
"AverMedia InterCam Elite"
},
{
112
,
"MediaForte MV300"
},
/* or OV7110 evaluation kit */
{
-
1
,
NULL
}
};
static
struct
usb_driver
ov511_driver
;
/**********************************************************************
*
* Memory management
*
* This is a shameless copy from the USB-cpia driver (linux kernel
* version 2.3.29 or so, I have no idea what this code actually does ;).
* Actually it seems to be a copy of a shameless copy of the bttv-driver.
* Or that is a copy of a shameless copy of ... (To the powers: is there
* no generic kernel-function to do this sort of stuff?)
*
* Yes, it was a shameless copy from the bttv-driver. IIRC, Alan says
* there will be one, but apparentely not yet -jerdfelt
*
* So I copied it again for the OV511 driver -claudio
**********************************************************************/
/* Given PGD from the address space's page table, return the kernel
/* Given PGD from the address space's page table, return the kernel
* virtual mapping of the physical memory mapped at ADR.
* virtual mapping of the physical memory mapped at ADR.
...
@@ -119,31 +157,11 @@ static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr)
...
@@ -119,31 +157,11 @@ static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr)
ptep
=
pte_offset
(
pmd
,
adr
);
ptep
=
pte_offset
(
pmd
,
adr
);
pte
=
*
ptep
;
pte
=
*
ptep
;
if
(
pte_present
(
pte
))
if
(
pte_present
(
pte
))
ret
=
page_address
(
pte_page
(
pte
))
|
(
adr
&
(
PAGE_SIZE
-
1
));
ret
=
page_address
(
pte_page
(
pte
))
|
(
adr
&
(
PAGE_SIZE
-
1
));
}
}
}
}
MDEBUG
(
printk
(
"uv2kva(%lx-->%lx)"
,
adr
,
ret
));
return
ret
;
}
static
inline
unsigned
long
uvirt_to_bus
(
unsigned
long
adr
)
{
unsigned
long
kva
,
ret
;
kva
=
uvirt_to_kva
(
pgd_offset
(
current
->
mm
,
adr
),
adr
);
ret
=
virt_to_bus
((
void
*
)
kva
);
MDEBUG
(
printk
(
"uv2b(%lx-->%lx)"
,
adr
,
ret
));
return
ret
;
}
static
inline
unsigned
long
kvirt_to_bus
(
unsigned
long
adr
)
{
unsigned
long
va
,
kva
,
ret
;
va
=
VMALLOC_VMADDR
(
adr
);
kva
=
uvirt_to_kva
(
pgd_offset_k
(
va
),
va
);
ret
=
virt_to_bus
((
void
*
)
kva
);
MDEBUG
(
printk
(
"kv2b(%lx-->%lx)"
,
adr
,
ret
));
return
ret
;
return
ret
;
}
}
...
@@ -158,7 +176,6 @@ static inline unsigned long kvirt_to_pa(unsigned long adr)
...
@@ -158,7 +176,6 @@ static inline unsigned long kvirt_to_pa(unsigned long adr)
va
=
VMALLOC_VMADDR
(
adr
);
va
=
VMALLOC_VMADDR
(
adr
);
kva
=
uvirt_to_kva
(
pgd_offset_k
(
va
),
va
);
kva
=
uvirt_to_kva
(
pgd_offset_k
(
va
),
va
);
ret
=
__pa
(
kva
);
ret
=
__pa
(
kva
);
MDEBUG
(
printk
(
"kv2pa(%lx-->%lx)"
,
adr
,
ret
));
return
ret
;
return
ret
;
}
}
...
@@ -213,9 +230,269 @@ static void rvfree(void *mem, unsigned long size)
...
@@ -213,9 +230,269 @@ static void rvfree(void *mem, unsigned long size)
vfree
(
mem
);
vfree
(
mem
);
}
}
/**********************************************************************
* /proc interface
* Based on the CPiA driver version 0.7.4 -claudio
**********************************************************************/
#ifdef CONFIG_PROC_FS
static
struct
proc_dir_entry
*
ov511_proc_root
=
NULL
;
#define YES_NO(x) ((x) ? "yes" : "no")
static
int
ov511_read_proc
(
char
*
page
,
char
**
start
,
off_t
off
,
int
count
,
int
*
eof
,
void
*
data
)
{
char
*
out
=
page
;
int
i
,
len
;
struct
usb_ov511
*
ov511
=
data
;
/* IMPORTANT: This output MUST be kept under PAGE_SIZE
* or we need to get more sophisticated. */
out
+=
sprintf
(
out
,
"custom_id : %d
\n
"
,
ov511
->
customid
);
out
+=
sprintf
(
out
,
"model : %s
\n
"
,
ov511
->
desc
?
clist
[
ov511
->
desc
].
description
:
"unknown"
);
out
+=
sprintf
(
out
,
"streaming : %s
\n
"
,
YES_NO
(
ov511
->
streaming
));
out
+=
sprintf
(
out
,
"grabbing : %s
\n
"
,
YES_NO
(
ov511
->
grabbing
));
out
+=
sprintf
(
out
,
"compress : %s
\n
"
,
YES_NO
(
ov511
->
compress
));
out
+=
sprintf
(
out
,
"subcapture : %s
\n
"
,
YES_NO
(
ov511
->
sub_flag
));
out
+=
sprintf
(
out
,
"sub_size : %d %d %d %d
\n
"
,
ov511
->
subx
,
ov511
->
suby
,
ov511
->
subw
,
ov511
->
subh
);
out
+=
sprintf
(
out
,
"num_frames : %d
\n
"
,
OV511_NUMFRAMES
);
for
(
i
=
0
;
i
<
OV511_NUMFRAMES
;
i
++
)
{
out
+=
sprintf
(
out
,
"frame : %d
\n
"
,
i
);
out
+=
sprintf
(
out
,
" depth : %d
\n
"
,
ov511
->
frame
[
i
].
depth
);
out
+=
sprintf
(
out
,
" size : %d %d
\n
"
,
ov511
->
frame
[
i
].
width
,
ov511
->
frame
[
i
].
height
);
out
+=
sprintf
(
out
,
" hdr_size : %d %d
\n
"
,
ov511
->
frame
[
i
].
hdrwidth
,
ov511
->
frame
[
i
].
hdrheight
);
out
+=
sprintf
(
out
,
" format : %d
\n
"
,
ov511
->
frame
[
i
].
format
);
out
+=
sprintf
(
out
,
" segsize : %d
\n
"
,
ov511
->
frame
[
i
].
segsize
);
#if 0
out += sprintf (out, " curline : %d\n",
ov511->frame[i].curline);
out += sprintf (out, " segment : %d\n",
ov511->frame[i].segment);
out += sprintf (out, " scanlength : %ld\n",
ov511->frame[i].scanlength);
out += sprintf (out, " bytesread : %ld\n",
ov511->frame[i].bytes_read);
#endif
}
out
+=
sprintf
(
out
,
"snap_enabled : %s
\n
"
,
YES_NO
(
ov511
->
snap_enabled
));
out
+=
sprintf
(
out
,
"bridge : %d
\n
"
,
ov511
->
bridge
);
out
+=
sprintf
(
out
,
"sensor : %d
\n
"
,
ov511
->
sensor
);
out
+=
sprintf
(
out
,
"packet_size : %d
\n
"
,
ov511
->
packet_size
);
len
=
out
-
page
;
len
-=
off
;
if
(
len
<
count
)
{
*
eof
=
1
;
if
(
len
<=
0
)
return
0
;
}
else
len
=
count
;
*
start
=
page
+
off
;
return
len
;
}
static
int
ov511_write_proc
(
struct
file
*
file
,
const
char
*
buffer
,
unsigned
long
count
,
void
*
data
)
{
int
retval
=
-
EINVAL
;
#if 0
/* struct cam_data *cam = data; */
struct usb_ov511 new_params;
int size = count;
int find_colon;
unsigned long val;
u32 command_flags = 0;
u8 new_mains;
if (down_interruptible(&cam->param_lock))
return -ERESTARTSYS;
/*
* Skip over leading whitespace
*/
while (count && isspace(*buffer)) {
--count;
++buffer;
}
#define MATCH(x) \
({ \
int _len = strlen(x), _ret, _colon_found; \
_ret = (_len <= count && strncmp(buffer, x, _len) == 0); \
if (_ret) { \
buffer += _len; \
count -= _len; \
if (find_colon) { \
_colon_found = 0; \
while (count && (*buffer == ' ' || *buffer == '\t' || \
(!_colon_found && *buffer == ':'))) { \
if (*buffer == ':') \
_colon_found = 1; \
--count; \
++buffer; \
} \
if (!count || !_colon_found) \
retval = -EINVAL; \
find_colon = 0; \
} \
} \
_ret; \
})
#define VALUE \
({ \
char *_p; \
unsigned long int _ret; \
_ret = simple_strtoul(buffer, &_p, 0); \
if (_p == buffer) \
retval = -EINVAL; \
else { \
count -= _p - buffer; \
buffer = _p; \
} \
_ret; \
})
retval = 0;
while (count && !retval) {
find_colon = 1;
if (MATCH("")) {
if (!retval)
val = VALUE;
if (!retval) {
if (val <= 0xff)
/* ... = val */ ;
else
retval = -EINVAL;
}
} else {
DBG("No match found\n");
retval = -EINVAL;
}
if (!retval) {
while (count && isspace(*buffer) && *buffer != '\n') {
--count;
++buffer;
}
if (count) {
if (*buffer != '\n' && *buffer != ';')
retval = -EINVAL;
else {
--count;
++buffer;
}
}
}
}
#undef MATCH
#undef FIRMWARE_VERSION
#undef VALUE
#undef FIND_VALUE
#undef FIND_END
if (!retval) {
if (command_flags & COMMAND_SETCOLOURPARAMS) {
/* Adjust cam->vp to reflect these changes */
cam->vp.brightness =
new_params.colourParams.brightness*65535/100;
cam->vp.contrast =
new_params.colourParams.contrast*65535/100;
cam->vp.colour =
new_params.colourParams.saturation*65535/100;
}
memcpy(&cam->params, &new_params, sizeof(struct cam_params));
cam->mainsFreq = new_mains;
cam->cmd_queue |= command_flags;
retval = size;
} else
PDEBUG(3, "error: %d\n", retval);
up(&cam->param_lock);
#endif
return
retval
;
}
static
void
create_proc_ov511_cam
(
struct
usb_ov511
*
ov511
)
{
char
name
[
7
];
struct
proc_dir_entry
*
ent
;
PDEBUG
(
4
,
"***************"
);
if
(
!
ov511_proc_root
||
!
ov511
)
return
;
sprintf
(
name
,
"video%d"
,
ov511
->
vdev
.
minor
);
PDEBUG
(
4
,
"==== name: %s"
,
name
);
ent
=
create_proc_entry
(
name
,
S_IFREG
|
S_IRUGO
|
S_IWUSR
,
ov511_proc_root
);
if
(
!
ent
)
return
;
ent
->
data
=
ov511
;
ent
->
read_proc
=
ov511_read_proc
;
ent
->
write_proc
=
ov511_write_proc
;
ent
->
size
=
3626
;
/* FIXME */
ov511
->
proc_entry
=
ent
;
}
static
void
destroy_proc_ov511_cam
(
struct
usb_ov511
*
ov511
)
{
char
name
[
7
];
if
(
!
ov511
||
!
ov511
->
proc_entry
)
return
;
sprintf
(
name
,
"video%d"
,
ov511
->
vdev
.
minor
);
PDEBUG
(
4
,
"==== name: %s"
,
name
);
#if 0
remove_proc_entry(name, ov511_proc_root);
ov511->proc_entry = NULL;
#endif
}
static
void
proc_ov511_create
(
void
)
{
ov511_proc_root
=
create_proc_entry
(
"ov511"
,
S_IFDIR
,
0
);
if
(
ov511_proc_root
)
ov511_proc_root
->
owner
=
THIS_MODULE
;
else
printk
(
"Unable to initialise /proc/ov511
\n
"
);
/***********/
}
static
void
proc_ov511_destroy
(
void
)
{
remove_proc_entry
(
"ov511"
,
0
);
}
#endif
/* CONFIG_PROC_FS */
/**********************************************************************
*
* Camera interface
*
**********************************************************************/
static
int
ov511_reg_write
(
struct
usb_device
*
dev
,
static
int
ov511_reg_write
(
struct
usb_device
*
dev
,
unsigned
char
reg
,
unsigned
char
reg
,
unsigned
char
value
)
unsigned
char
value
)
{
{
int
rc
;
int
rc
;
...
@@ -233,6 +510,7 @@ static int ov511_reg_write(struct usb_device *dev,
...
@@ -233,6 +510,7 @@ static int ov511_reg_write(struct usb_device *dev,
return
rc
;
return
rc
;
}
}
/* returns: negative is error, pos or zero is data */
/* returns: negative is error, pos or zero is data */
static
int
ov511_reg_read
(
struct
usb_device
*
dev
,
unsigned
char
reg
)
static
int
ov511_reg_read
(
struct
usb_device
*
dev
,
unsigned
char
reg
)
{
{
...
@@ -247,24 +525,25 @@ static int ov511_reg_read(struct usb_device *dev, unsigned char reg)
...
@@ -247,24 +525,25 @@ static int ov511_reg_read(struct usb_device *dev, unsigned char reg)
PDEBUG
(
5
,
"reg read: 0x%02X:0x%02X"
,
reg
,
buffer
[
0
]);
PDEBUG
(
5
,
"reg read: 0x%02X:0x%02X"
,
reg
,
buffer
[
0
]);
if
(
rc
<
0
)
{
if
(
rc
<
0
)
{
err
(
"ov511_reg_read: error %d"
,
rc
);
err
(
"ov511_reg_read: error %d"
,
rc
);
return
rc
;
return
rc
;
}
}
else
{
else
return
buffer
[
0
];
return
buffer
[
0
];
}
}
}
static
int
ov511_i2c_write
(
struct
usb_device
*
dev
,
static
int
ov511_i2c_write
(
struct
usb_device
*
dev
,
unsigned
char
reg
,
unsigned
char
reg
,
unsigned
char
value
)
unsigned
char
value
)
{
{
int
rc
,
retries
;
int
rc
,
retries
;
PDEBUG
(
5
,
"i2c write: 0x%02X:0x%02X"
,
reg
,
value
);
PDEBUG
(
5
,
"i2c write: 0x%02X:0x%02X"
,
reg
,
value
);
/* Three byte write cycle */
/* Three byte write cycle */
for
(
retries
=
OV511_I2C_RETRIES
;;
)
{
for
(
retries
=
OV511_I2C_RETRIES
;
;
)
{
/* Select camera register */
/* Select camera register */
rc
=
ov511_reg_write
(
dev
,
OV511_REG_I2C_SUB_ADDRESS_3_BYTE
,
reg
);
rc
=
ov511_reg_write
(
dev
,
OV511_REG_I2C_SUB_ADDRESS_3_BYTE
,
reg
);
if
(
rc
<
0
)
goto
error
;
if
(
rc
<
0
)
goto
error
;
...
@@ -278,10 +557,10 @@ static int ov511_i2c_write(struct usb_device *dev,
...
@@ -278,10 +557,10 @@ static int ov511_i2c_write(struct usb_device *dev,
if
(
rc
<
0
)
goto
error
;
if
(
rc
<
0
)
goto
error
;
do
rc
=
ov511_reg_read
(
dev
,
OV511_REG_I2C_CONTROL
);
do
rc
=
ov511_reg_read
(
dev
,
OV511_REG_I2C_CONTROL
);
while
(
rc
>
0
&&
((
rc
&
1
)
==
0
));
/* Retry until idle */
while
(
rc
>
0
&&
((
rc
&
1
)
==
0
));
/* Retry until idle */
if
(
rc
<
0
)
goto
error
;
if
(
rc
<
0
)
goto
error
;
if
((
rc
&
2
)
==
0
)
/* Ack? */
if
((
rc
&
2
)
==
0
)
/* Ack? */
break
;
break
;
#if 0
#if 0
/* I2C abort */
/* I2C abort */
...
@@ -301,13 +580,14 @@ static int ov511_i2c_write(struct usb_device *dev,
...
@@ -301,13 +580,14 @@ static int ov511_i2c_write(struct usb_device *dev,
return
rc
;
return
rc
;
}
}
/* returns: negative is error, pos or zero is data */
/* returns: negative is error, pos or zero is data */
static
int
ov511_i2c_read
(
struct
usb_device
*
dev
,
unsigned
char
reg
)
static
int
ov511_i2c_read
(
struct
usb_device
*
dev
,
unsigned
char
reg
)
{
{
int
rc
,
value
,
retries
;
int
rc
,
value
,
retries
;
/* Two byte write cycle */
/* Two byte write cycle */
for
(
retries
=
OV511_I2C_RETRIES
;;
)
{
for
(
retries
=
OV511_I2C_RETRIES
;
;
)
{
/* Select camera register */
/* Select camera register */
rc
=
ov511_reg_write
(
dev
,
OV511_REG_I2C_SUB_ADDRESS_2_BYTE
,
reg
);
rc
=
ov511_reg_write
(
dev
,
OV511_REG_I2C_SUB_ADDRESS_2_BYTE
,
reg
);
if
(
rc
<
0
)
goto
error
;
if
(
rc
<
0
)
goto
error
;
...
@@ -317,10 +597,10 @@ static int ov511_i2c_read(struct usb_device *dev, unsigned char reg)
...
@@ -317,10 +597,10 @@ static int ov511_i2c_read(struct usb_device *dev, unsigned char reg)
if
(
rc
<
0
)
goto
error
;
if
(
rc
<
0
)
goto
error
;
do
rc
=
ov511_reg_read
(
dev
,
OV511_REG_I2C_CONTROL
);
do
rc
=
ov511_reg_read
(
dev
,
OV511_REG_I2C_CONTROL
);
while
(
rc
>
0
&&
((
rc
&
1
)
==
0
));
/* Retry until idle */
while
(
rc
>
0
&&
((
rc
&
1
)
==
0
));
/* Retry until idle */
if
(
rc
<
0
)
goto
error
;
if
(
rc
<
0
)
goto
error
;
if
((
rc
&
2
)
==
0
)
/* Ack? */
if
((
rc
&
2
)
==
0
)
/* Ack? */
break
;
break
;
/* I2C abort */
/* I2C abort */
...
@@ -334,16 +614,16 @@ static int ov511_i2c_read(struct usb_device *dev, unsigned char reg)
...
@@ -334,16 +614,16 @@ static int ov511_i2c_read(struct usb_device *dev, unsigned char reg)
}
}
/* Two byte read cycle */
/* Two byte read cycle */
for
(
retries
=
OV511_I2C_RETRIES
;;
)
{
for
(
retries
=
OV511_I2C_RETRIES
;
;
)
{
/* Initiate 2-byte read cycle */
/* Initiate 2-byte read cycle */
rc
=
ov511_reg_write
(
dev
,
OV511_REG_I2C_CONTROL
,
0x05
);
rc
=
ov511_reg_write
(
dev
,
OV511_REG_I2C_CONTROL
,
0x05
);
if
(
rc
<
0
)
goto
error
;
if
(
rc
<
0
)
goto
error
;
do
rc
=
ov511_reg_read
(
dev
,
OV511_REG_I2C_CONTROL
);
do
rc
=
ov511_reg_read
(
dev
,
OV511_REG_I2C_CONTROL
);
while
(
rc
>
0
&&
((
rc
&
1
)
==
0
));
/* Retry until idle */
while
(
rc
>
0
&&
((
rc
&
1
)
==
0
));
/* Retry until idle */
if
(
rc
<
0
)
goto
error
;
if
(
rc
<
0
)
goto
error
;
if
((
rc
&
2
)
==
0
)
/* Ack? */
if
((
rc
&
2
)
==
0
)
/* Ack? */
break
;
break
;
/* I2C abort */
/* I2C abort */
...
@@ -363,7 +643,8 @@ static int ov511_i2c_read(struct usb_device *dev, unsigned char reg)
...
@@ -363,7 +643,8 @@ static int ov511_i2c_read(struct usb_device *dev, unsigned char reg)
/* This is needed to make ov511_i2c_write() work */
/* This is needed to make ov511_i2c_write() work */
rc
=
ov511_reg_write
(
dev
,
OV511_REG_I2C_CONTROL
,
0x05
);
rc
=
ov511_reg_write
(
dev
,
OV511_REG_I2C_CONTROL
,
0x05
);
if
(
rc
<
0
)
goto
error
;
if
(
rc
<
0
)
goto
error
;
return
value
;
return
value
;
...
@@ -372,12 +653,13 @@ static int ov511_i2c_read(struct usb_device *dev, unsigned char reg)
...
@@ -372,12 +653,13 @@ static int ov511_i2c_read(struct usb_device *dev, unsigned char reg)
return
rc
;
return
rc
;
}
}
static
int
ov511_write_regvals
(
struct
usb_device
*
dev
,
static
int
ov511_write_regvals
(
struct
usb_device
*
dev
,
struct
ov511_regvals
*
pRegvals
)
struct
ov511_regvals
*
pRegvals
)
{
{
int
rc
;
int
rc
;
while
(
pRegvals
->
bus
!=
OV511_DONE_BUS
)
{
while
(
pRegvals
->
bus
!=
OV511_DONE_BUS
)
{
if
(
pRegvals
->
bus
==
OV511_REG_BUS
)
{
if
(
pRegvals
->
bus
==
OV511_REG_BUS
)
{
if
((
rc
=
ov511_reg_write
(
dev
,
pRegvals
->
reg
,
if
((
rc
=
ov511_reg_write
(
dev
,
pRegvals
->
reg
,
pRegvals
->
val
))
<
0
)
pRegvals
->
val
))
<
0
)
...
@@ -400,6 +682,7 @@ static int ov511_write_regvals(struct usb_device *dev,
...
@@ -400,6 +682,7 @@ static int ov511_write_regvals(struct usb_device *dev,
return
rc
;
return
rc
;
}
}
#if 0
#if 0
static void ov511_dump_i2c_range( struct usb_device *dev, int reg1, int regn)
static void ov511_dump_i2c_range( struct usb_device *dev, int reg1, int regn)
{
{
...
@@ -411,12 +694,14 @@ static void ov511_dump_i2c_range( struct usb_device *dev, int reg1, int regn)
...
@@ -411,12 +694,14 @@ static void ov511_dump_i2c_range( struct usb_device *dev, int reg1, int regn)
}
}
}
}
static void ov511_dump_i2c_regs( struct usb_device *dev)
static void ov511_dump_i2c_regs( struct usb_device *dev)
{
{
PDEBUG(3, "I2C REGS");
PDEBUG(3, "I2C REGS");
ov511_dump_i2c_range(dev, 0x00, 0x38);
ov511_dump_i2c_range(dev, 0x00, 0x38);
}
}
static void ov511_dump_reg_range( struct usb_device *dev, int reg1, int regn)
static void ov511_dump_reg_range( struct usb_device *dev, int reg1, int regn)
{
{
int i;
int i;
...
@@ -427,6 +712,7 @@ static void ov511_dump_reg_range( struct usb_device *dev, int reg1, int regn)
...
@@ -427,6 +712,7 @@ static void ov511_dump_reg_range( struct usb_device *dev, int reg1, int regn)
}
}
}
}
static void ov511_dump_regs( struct usb_device *dev)
static void ov511_dump_regs( struct usb_device *dev)
{
{
PDEBUG(1, "CAMERA INTERFACE REGS");
PDEBUG(1, "CAMERA INTERFACE REGS");
...
@@ -451,6 +737,7 @@ static void ov511_dump_regs( struct usb_device *dev)
...
@@ -451,6 +737,7 @@ static void ov511_dump_regs( struct usb_device *dev)
}
}
#endif
#endif
static
int
ov511_reset
(
struct
usb_device
*
dev
,
unsigned
char
reset_type
)
static
int
ov511_reset
(
struct
usb_device
*
dev
,
unsigned
char
reset_type
)
{
{
int
rc
;
int
rc
;
...
@@ -465,6 +752,7 @@ static int ov511_reset(struct usb_device *dev, unsigned char reset_type)
...
@@ -465,6 +752,7 @@ static int ov511_reset(struct usb_device *dev, unsigned char reset_type)
return
rc
;
return
rc
;
}
}
/* Temporarily stops OV511 from functioning. Must do this before changing
/* Temporarily stops OV511 from functioning. Must do this before changing
* registers while the camera is streaming */
* registers while the camera is streaming */
static
inline
int
ov511_stop
(
struct
usb_device
*
dev
)
static
inline
int
ov511_stop
(
struct
usb_device
*
dev
)
...
@@ -473,6 +761,7 @@ static inline int ov511_stop(struct usb_device *dev)
...
@@ -473,6 +761,7 @@ static inline int ov511_stop(struct usb_device *dev)
return
(
ov511_reg_write
(
dev
,
OV511_REG_SYSTEM_RESET
,
0x3d
));
return
(
ov511_reg_write
(
dev
,
OV511_REG_SYSTEM_RESET
,
0x3d
));
}
}
/* Restarts OV511 after ov511_stop() is called */
/* Restarts OV511 after ov511_stop() is called */
static
inline
int
ov511_restart
(
struct
usb_device
*
dev
)
static
inline
int
ov511_restart
(
struct
usb_device
*
dev
)
{
{
...
@@ -480,6 +769,7 @@ static inline int ov511_restart(struct usb_device *dev)
...
@@ -480,6 +769,7 @@ static inline int ov511_restart(struct usb_device *dev)
return
(
ov511_reg_write
(
dev
,
OV511_REG_SYSTEM_RESET
,
0x00
));
return
(
ov511_reg_write
(
dev
,
OV511_REG_SYSTEM_RESET
,
0x00
));
}
}
static
int
ov511_set_packet_size
(
struct
usb_ov511
*
ov511
,
int
size
)
static
int
ov511_set_packet_size
(
struct
usb_ov511
*
ov511
,
int
size
)
{
{
int
alt
,
mult
;
int
alt
,
mult
;
...
@@ -487,7 +777,7 @@ static int ov511_set_packet_size(struct usb_ov511 *ov511, int size)
...
@@ -487,7 +777,7 @@ static int ov511_set_packet_size(struct usb_ov511 *ov511, int size)
if
(
ov511_stop
(
ov511
->
dev
)
<
0
)
if
(
ov511_stop
(
ov511
->
dev
)
<
0
)
return
-
EIO
;
return
-
EIO
;
mult
=
size
/
32
;
mult
=
size
>>
5
;
if
(
ov511
->
bridge
==
BRG_OV511
)
{
if
(
ov511
->
bridge
==
BRG_OV511
)
{
if
(
size
==
0
)
alt
=
OV511_ALT_SIZE_0
;
if
(
size
==
0
)
alt
=
OV511_ALT_SIZE_0
;
...
@@ -502,8 +792,7 @@ static int ov511_set_packet_size(struct usb_ov511 *ov511, int size)
...
@@ -502,8 +792,7 @@ static int ov511_set_packet_size(struct usb_ov511 *ov511, int size)
err
(
"Set packet size: invalid size (%d)"
,
size
);
err
(
"Set packet size: invalid size (%d)"
,
size
);
return
-
EINVAL
;
return
-
EINVAL
;
}
}
}
}
else
if
(
ov511
->
bridge
==
BRG_OV511PLUS
)
{
else
if
(
ov511
->
bridge
==
BRG_OV511PLUS
)
{
if
(
size
==
0
)
alt
=
OV511PLUS_ALT_SIZE_0
;
if
(
size
==
0
)
alt
=
OV511PLUS_ALT_SIZE_0
;
else
if
(
size
==
33
)
alt
=
OV511PLUS_ALT_SIZE_33
;
else
if
(
size
==
33
)
alt
=
OV511PLUS_ALT_SIZE_33
;
else
if
(
size
==
129
)
alt
=
OV511PLUS_ALT_SIZE_129
;
else
if
(
size
==
129
)
alt
=
OV511PLUS_ALT_SIZE_129
;
...
@@ -516,16 +805,14 @@ static int ov511_set_packet_size(struct usb_ov511 *ov511, int size)
...
@@ -516,16 +805,14 @@ static int ov511_set_packet_size(struct usb_ov511 *ov511, int size)
err
(
"Set packet size: invalid size (%d)"
,
size
);
err
(
"Set packet size: invalid size (%d)"
,
size
);
return
-
EINVAL
;
return
-
EINVAL
;
}
}
}
}
else
{
else
{
err
(
"Set packet size: Invalid bridge type"
);
err
(
"Set packet size: Invalid bridge type"
);
return
-
EINVAL
;
return
-
EINVAL
;
}
}
PDEBUG
(
3
,
"set packet size: %d, mult=%d, alt=%d"
,
size
,
mult
,
alt
);
PDEBUG
(
3
,
"set packet size: %d, mult=%d, alt=%d"
,
size
,
mult
,
alt
);
if
(
ov511_reg_write
(
ov511
->
dev
,
OV511_REG_FIFO_PACKET_SIZE
,
if
(
ov511_reg_write
(
ov511
->
dev
,
OV511_REG_FIFO_PACKET_SIZE
,
mult
)
<
0
)
mult
)
<
0
)
return
-
ENOMEM
;
return
-
ENOMEM
;
if
(
usb_set_interface
(
ov511
->
dev
,
ov511
->
iface
,
alt
)
<
0
)
{
if
(
usb_set_interface
(
ov511
->
dev
,
ov511
->
iface
,
alt
)
<
0
)
{
...
@@ -545,8 +832,9 @@ static int ov511_set_packet_size(struct usb_ov511 *ov511, int size)
...
@@ -545,8 +832,9 @@ static int ov511_set_packet_size(struct usb_ov511 *ov511, int size)
return
0
;
return
0
;
}
}
static
inline
int
ov7610_set_picture
(
struct
usb_ov511
*
ov511
,
struct
video_picture
*
p
)
static
inline
int
ov7610_set_picture
(
struct
usb_ov511
*
ov511
,
struct
video_picture
*
p
)
{
{
int
ret
;
int
ret
;
struct
usb_device
*
dev
=
ov511
->
dev
;
struct
usb_device
*
dev
=
ov511
->
dev
;
...
@@ -556,10 +844,10 @@ static inline int ov7610_set_picture(struct usb_ov511 *ov511,
...
@@ -556,10 +844,10 @@ static inline int ov7610_set_picture(struct usb_ov511 *ov511,
if
(
ov511_stop
(
dev
)
<
0
)
if
(
ov511_stop
(
dev
)
<
0
)
return
-
EIO
;
return
-
EIO
;
if
((
ret
=
ov511_i2c_read
(
dev
,
OV7610_REG_COM_B
))
<
0
)
if
((
ret
=
ov511_i2c_read
(
dev
,
OV7610_REG_COM_B
))
<
0
)
return
-
EIO
;
return
-
EIO
;
#if 0
#if 0
if(ov511_i2c_write(dev, OV7610_REG_COM_B, ret & 0xfe) < 0)
if
(ov511_i2c_write(dev, OV7610_REG_COM_B, ret & 0xfe) < 0)
return -EIO;
return -EIO;
#endif
#endif
if
(
ov511
->
sensor
==
SEN_OV7610
||
ov511
->
sensor
==
SEN_OV7620AE
)
if
(
ov511
->
sensor
==
SEN_OV7610
||
ov511
->
sensor
==
SEN_OV7620AE
)
...
@@ -572,17 +860,18 @@ static inline int ov7610_set_picture(struct usb_ov511 *ov511,
...
@@ -572,17 +860,18 @@ static inline int ov7610_set_picture(struct usb_ov511 *ov511,
if
(
ov511_i2c_write
(
dev
,
OV7610_REG_BRT
,
p
->
brightness
>>
8
)
<
0
)
if
(
ov511_i2c_write
(
dev
,
OV7610_REG_BRT
,
p
->
brightness
>>
8
)
<
0
)
return
-
EIO
;
return
-
EIO
;
}
}
else
if
((
ov511
->
sensor
==
SEN_OV7620
)
else
if
((
ov511
->
sensor
==
SEN_OV7620
)
||
(
ov511
->
sensor
==
SEN_OV7620AE
))
{
||
(
ov511
->
sensor
==
SEN_OV7620AE
))
{
// cur_con = ov511_i2c_read(dev, OV7610_REG_CNT);
#if 0
// cur_brt = ov511_i2c_read(dev, OV7610_REG_BRT);
cur_con = ov511_i2c_read(dev, OV7610_REG_CNT);
// // DEBUG_CODE
cur_brt = ov511_i2c_read(dev, OV7610_REG_BRT);
// PDEBUG(1, "con=%d brt=%d", ov511_i2c_read(dev, OV7610_REG_CNT),
// DEBUG_CODE
// ov511_i2c_read(dev, OV7610_REG_BRT));
PDEBUG(1, "con=%d brt=%d", ov511_i2c_read(dev, OV7610_REG_CNT),
//
ov511_i2c_read(dev, OV7610_REG_BRT));
// if(ov511_i2c_write(dev, OV7610_REG_CNT, p->contrast >> 8) < 0)
// return -EIO;
if(ov511_i2c_write(dev, OV7610_REG_CNT, p->contrast >> 8) < 0)
return -EIO;
#endif
}
}
if
(
ov511_restart
(
dev
)
<
0
)
if
(
ov511_restart
(
dev
)
<
0
)
...
@@ -591,8 +880,9 @@ static inline int ov7610_set_picture(struct usb_ov511 *ov511,
...
@@ -591,8 +880,9 @@ static inline int ov7610_set_picture(struct usb_ov511 *ov511,
return
0
;
return
0
;
}
}
static
inline
int
ov7610_get_picture
(
struct
usb_ov511
*
ov511
,
struct
video_picture
*
p
)
static
inline
int
ov7610_get_picture
(
struct
usb_ov511
*
ov511
,
struct
video_picture
*
p
)
{
{
int
ret
;
int
ret
;
struct
usb_device
*
dev
=
ov511
->
dev
;
struct
usb_device
*
dev
=
ov511
->
dev
;
...
@@ -613,7 +903,11 @@ static inline int ov7610_get_picture(struct usb_ov511 *ov511,
...
@@ -613,7 +903,11 @@ static inline int ov7610_get_picture(struct usb_ov511 *ov511,
p
->
hue
=
0x8000
;
p
->
hue
=
0x8000
;
p
->
whiteness
=
105
<<
8
;
p
->
whiteness
=
105
<<
8
;
#if 0
p->depth = 3; /* Don't know if this is right */
p->depth = 3; /* Don't know if this is right */
#else
p
->
depth
=
24
;
#endif
p
->
palette
=
VIDEO_PALETTE_RGB24
;
p
->
palette
=
VIDEO_PALETTE_RGB24
;
if
(
ov511_restart
(
dev
)
<
0
)
if
(
ov511_restart
(
dev
)
<
0
)
...
@@ -622,15 +916,17 @@ static inline int ov7610_get_picture(struct usb_ov511 *ov511,
...
@@ -622,15 +916,17 @@ static inline int ov7610_get_picture(struct usb_ov511 *ov511,
return
0
;
return
0
;
}
}
static
int
ov511_mode_init_regs
(
struct
usb_ov511
*
ov511
,
int
width
,
int
height
,
int
mode
,
int
sub_flag
)
static
int
ov511_mode_init_regs
(
struct
usb_ov511
*
ov511
,
int
width
,
int
height
,
int
mode
,
int
sub_flag
)
{
{
int
rc
=
0
;
int
rc
=
0
;
struct
usb_device
*
dev
=
ov511
->
dev
;
struct
usb_device
*
dev
=
ov511
->
dev
;
int
hwsbase
=
0
;
int
hwsbase
=
0
;
int
hwebase
=
0
;
int
hwebase
=
0
;
PDEBUG
(
3
,
"
ov511_mode_init_regs(ov511, w:%d, h:%d, mode:%d, sub:%d)
"
,
PDEBUG
(
3
,
"
width:%d, height:%d, mode:%d, sub:%d
"
,
width
,
height
,
mode
,
sub_flag
);
width
,
height
,
mode
,
sub_flag
);
if
(
ov511_stop
(
ov511
->
dev
)
<
0
)
if
(
ov511_stop
(
ov511
->
dev
)
<
0
)
...
@@ -644,34 +940,39 @@ static int ov511_mode_init_regs(struct usb_ov511 *ov511,
...
@@ -644,34 +940,39 @@ static int ov511_mode_init_regs(struct usb_ov511 *ov511,
ov511_i2c_write
(
dev
,
0x0e
,
0x44
);
ov511_i2c_write
(
dev
,
0x0e
,
0x44
);
}
}
ov511_i2c_write
(
dev
,
0x13
,
autoadjust
?
0x21
:
0x20
);
ov511_i2c_write
(
dev
,
0x13
,
autoadjust
?
0x21
:
0x20
);
/* For snapshot */
/* For snapshot */
ov511_reg_write
(
dev
,
0x1e
,
0x00
);
ov511_reg_write
(
dev
,
0x1e
,
0x00
);
ov511_reg_write
(
dev
,
0x1f
,
0x01
);
ov511_reg_write
(
dev
,
0x1f
,
0x01
);
}
else
{
}
else
{
ov511_reg_write
(
dev
,
0x16
,
0x01
);
ov511_reg_write
(
dev
,
0x16
,
0x01
);
if
(
ov511
->
sensor
==
SEN_OV7610
if
(
ov511
->
sensor
==
SEN_OV7610
||
ov511
->
sensor
==
SEN_OV7620AE
)
{
||
ov511
->
sensor
==
SEN_OV7620AE
)
{
/* not valid on the OV7620 */
/* not valid on the OV7620 */
ov511_i2c_write
(
dev
,
0x0e
,
0x04
);
ov511_i2c_write
(
dev
,
0x0e
,
0x04
);
}
}
ov511_i2c_write
(
dev
,
0x13
,
autoadjust
?
0x01
:
0x00
);
ov511_i2c_write
(
dev
,
0x13
,
autoadjust
?
0x01
:
0x00
);
/* For snapshot */
/* For snapshot */
ov511_reg_write
(
dev
,
0x1e
,
0x01
);
ov511_reg_write
(
dev
,
0x1e
,
0x01
);
ov511_reg_write
(
dev
,
0x1f
,
0x03
);
ov511_reg_write
(
dev
,
0x1f
,
0x03
);
}
}
/* The different sensor ICs handle setting up of window differently */
/* The different sensor ICs handle setting up of window differently */
switch
(
ov511
->
sensor
)
{
switch
(
ov511
->
sensor
)
{
case
SEN_OV7610
:
case
SEN_OV7610
:
case
SEN_OV7620AE
:
case
SEN_OV7620AE
:
hwsbase
=
0x38
;
hwsbase
=
0x38
;
hwebase
=
0x3a
;
break
;
hwebase
=
0x3a
;
case
SEN_OV7620
:
break
;
hwsbase
=
0x2c
;
case
SEN_OV7620
:
hwebase
=
0x2d
;
break
;
hwsbase
=
0x2c
;
default:
hwebase
=
0x2d
;
hwsbase
=
0
;
break
;
hwebase
=
0
;
break
;
default:
hwsbase
=
0
;
hwebase
=
0
;
break
;
}
}
if
(
width
==
640
&&
height
==
480
)
{
if
(
width
==
640
&&
height
==
480
)
{
...
@@ -680,12 +981,12 @@ static int ov511_mode_init_regs(struct usb_ov511 *ov511,
...
@@ -680,12 +981,12 @@ static int ov511_mode_init_regs(struct usb_ov511 *ov511,
ov511_i2c_write
(
dev
,
0x17
,
hwsbase
+
(
ov511
->
subx
>>
2
));
ov511_i2c_write
(
dev
,
0x17
,
hwsbase
+
(
ov511
->
subx
>>
2
));
/* horizontal window end */
/* horizontal window end */
ov511_i2c_write
(
dev
,
0x18
,
ov511_i2c_write
(
dev
,
0x18
,
hwebase
+
((
ov511
->
subx
+
ov511
->
subw
)
>>
2
));
hwebase
+
((
ov511
->
subx
+
ov511
->
subw
)
>>
2
));
/* vertical window start */
/* vertical window start */
ov511_i2c_write
(
dev
,
0x19
,
0x5
+
(
ov511
->
suby
>>
1
));
ov511_i2c_write
(
dev
,
0x19
,
0x5
+
(
ov511
->
suby
>>
1
));
/* vertical window end */
/* vertical window end */
ov511_i2c_write
(
dev
,
0x1a
,
ov511_i2c_write
(
dev
,
0x1a
,
0x5
+
((
ov511
->
suby
+
ov511
->
subh
)
>>
1
));
0x5
+
((
ov511
->
suby
+
ov511
->
subh
)
>>
1
));
ov511_reg_write
(
dev
,
0x12
,
(
ov511
->
subw
>>
3
)
-
1
);
ov511_reg_write
(
dev
,
0x12
,
(
ov511
->
subw
>>
3
)
-
1
);
ov511_reg_write
(
dev
,
0x13
,
(
ov511
->
subh
>>
3
)
-
1
);
ov511_reg_write
(
dev
,
0x13
,
(
ov511
->
subh
>>
3
)
-
1
);
/* clock rate control */
/* clock rate control */
...
@@ -762,255 +1063,267 @@ static int ov511_mode_init_regs(struct usb_ov511 *ov511,
...
@@ -762,255 +1063,267 @@ static int ov511_mode_init_regs(struct usb_ov511 *ov511,
return
rc
;
return
rc
;
}
}
/*************************************************************
Turn a YUV4:2:0 block into an RGB block
Video4Linux seems to use the blue, green, red channel
/**********************************************************************
order convention-- rgb[0] is blue, rgb[1] is green, rgb[2] is red.
*
* Color correction functions
Color space conversion coefficients taken from the excellent
*
http://www.inforamp.net/~poynton/ColorFAQ.html
**********************************************************************/
In his terminology, this is a CCIR 601.1 YCbCr -> RGB.
Y values are given for all 4 pixels, but the U (Pb)
and V (Pr) are assumed constant over the 2x2 block.
To avoid floating point arithmetic, the color conversion
/*
coefficients are scaled into 16.16 fixed-point integers.
* Turn a YUV4:2:0 block into an RGB block
*
* Video4Linux seems to use the blue, green, red channel
* order convention-- rgb[0] is blue, rgb[1] is green, rgb[2] is red.
*
* Color space conversion coefficients taken from the excellent
* http://www.inforamp.net/~poynton/ColorFAQ.html
* In his terminology, this is a CCIR 601.1 YCbCr -> RGB.
* Y values are given for all 4 pixels, but the U (Pb)
* and V (Pr) are assumed constant over the 2x2 block.
*
* To avoid floating point arithmetic, the color conversion
* coefficients are scaled into 16.16 fixed-point integers.
*/
*************************************************************/
/* LIMIT: convert a 16.16 fixed-point value to a byte, with clipping. */
// LIMIT: convert a 16.16 fixed-point value to a byte, with clipping.
#define LIMIT(x) ((x)>0xffffff?0xff: ((x)<=0xffff?0:((x)>>16)))
#define LIMIT(x) ((x)>0xffffff?0xff: ((x)<=0xffff?0:((x)>>16)))
static
inline
void
ov511_move_420_block
(
int
yTL
,
int
yTR
,
int
yBL
,
int
yBR
,
static
inline
void
int
u
,
int
v
,
ov511_move_420_block
(
int
yTL
,
int
yTR
,
int
yBL
,
int
yBR
,
int
u
,
int
v
,
int
rowPixels
,
unsigned
char
*
rgb
)
int
rowPixels
,
unsigned
char
*
rgb
)
{
{
const
double
brightness
=
1
.
0
;
//
0->black; 1->full scale
const
double
brightness
=
1
.
0
;
//
0->black; 1->full scale
const
double
saturation
=
1
.
0
;
//
0->greyscale; 1->full color
const
double
saturation
=
1
.
0
;
//
0->greyscale; 1->full color
const
double
fixScale
=
brightness
*
256
*
256
;
const
double
fixScale
=
brightness
*
256
*
256
;
const
int
rvScale
=
(
int
)(
1
.
402
*
saturation
*
fixScale
);
const
int
rvScale
=
(
int
)(
1
.
402
*
saturation
*
fixScale
);
const
int
guScale
=
(
int
)(
-
0
.
344136
*
saturation
*
fixScale
);
const
int
guScale
=
(
int
)(
-
0
.
344136
*
saturation
*
fixScale
);
const
int
gvScale
=
(
int
)(
-
0
.
714136
*
saturation
*
fixScale
);
const
int
gvScale
=
(
int
)(
-
0
.
714136
*
saturation
*
fixScale
);
const
int
buScale
=
(
int
)(
1
.
772
*
saturation
*
fixScale
);
const
int
buScale
=
(
int
)(
1
.
772
*
saturation
*
fixScale
);
const
int
yScale
=
(
int
)(
fixScale
);
const
int
yScale
=
(
int
)(
fixScale
);
int
r
=
rvScale
*
v
;
int
r
=
rvScale
*
v
;
int
g
=
guScale
*
u
+
gvScale
*
v
;
int
g
=
guScale
*
u
+
gvScale
*
v
;
int
b
=
buScale
*
u
;
int
b
=
buScale
*
u
;
yTL
*=
yScale
;
yTR
*=
yScale
;
yTL
*=
yScale
;
yTR
*=
yScale
;
yBL
*=
yScale
;
yBR
*=
yScale
;
yBL
*=
yScale
;
yBR
*=
yScale
;
//Write out top two pixels
//Write out top two pixels
rgb
[
0
]
=
LIMIT
(
b
+
yTL
);
rgb
[
1
]
=
LIMIT
(
g
+
yTL
);
rgb
[
2
]
=
LIMIT
(
r
+
yTL
);
rgb
[
0
]
=
LIMIT
(
b
+
yTL
);
rgb
[
1
]
=
LIMIT
(
g
+
yTL
);
rgb
[
2
]
=
LIMIT
(
r
+
yTL
);
rgb
[
3
]
=
LIMIT
(
b
+
yTR
);
rgb
[
4
]
=
LIMIT
(
g
+
yTR
);
rgb
[
5
]
=
LIMIT
(
r
+
yTR
);
rgb
[
3
]
=
LIMIT
(
b
+
yTR
);
rgb
[
4
]
=
LIMIT
(
g
+
yTR
);
rgb
[
5
]
=
LIMIT
(
r
+
yTR
);
rgb
+=
3
*
rowPixels
;
//Skip down to next line to write out bottom two pixels
rgb
[
0
]
=
LIMIT
(
b
+
yBL
);
rgb
[
1
]
=
LIMIT
(
g
+
yBL
);
rgb
[
2
]
=
LIMIT
(
r
+
yBL
);
rgb
[
3
]
=
LIMIT
(
b
+
yBR
);
rgb
[
4
]
=
LIMIT
(
g
+
yBR
);
rgb
[
5
]
=
LIMIT
(
r
+
yBR
);
}
/***************************************************************
For a 640x480 YUV4:2:0 images, data shows up in 1200 384 byte segments. The
first 64 bytes of each segment are U, the next 64 are V. The U and
V are arranged as follows:
0 1 ... 7
8 9 ... 15
...
56 57 ... 63
U and V are shipped at half resolution (1 U,V sample -> one 2x2 block).
The next 256 bytes are full resolution Y data and represent 4
squares of 8x8 pixels as follows:
0 1 ... 7 64 65 ... 71 ... 192 193 ... 199
//Skip down to next line to write out bottom two pixels
8 9 ... 15 72 73 ... 79 200 201 ... 207
rgb
+=
3
*
rowPixels
;
... ... ...
rgb
[
0
]
=
LIMIT
(
b
+
yBL
);
rgb
[
1
]
=
LIMIT
(
g
+
yBL
);
rgb
[
2
]
=
LIMIT
(
r
+
yBL
);
56 57 ... 63 120 121 127 248 249 ... 255
rgb
[
3
]
=
LIMIT
(
b
+
yBR
);
rgb
[
4
]
=
LIMIT
(
g
+
yBR
);
rgb
[
5
]
=
LIMIT
(
r
+
yBR
);
}
Note that the U and V data in one segment represents a 16 x 16 pixel
area, but the Y data represents a 32 x 8 pixel area.
If OV511_DUMPPIX is defined, _parse_data just dumps the
/*
incoming segments, verbatim, in order, into the frame.
* For a 640x480 YUV4:2:0 images, data shows up in 1200 384 byte segments.
When used with vidcat -f ppm -s 640x480 this puts the data
* The first 64 bytes of each segment are U, the next 64 are V. The U and
on the standard output and can be analyzed with the parseppm.c
* V are arranged as follows:
utility I wrote. That's a much faster way for figuring out how
*
this data is scrambled.
* 0 1 ... 7
* 8 9 ... 15
* ...
* 56 57 ... 63
*
* U and V are shipped at half resolution (1 U,V sample -> one 2x2 block).
*
* The next 256 bytes are full resolution Y data and represent 4 squares
* of 8x8 pixels as follows:
*
* 0 1 ... 7 64 65 ... 71 ... 192 193 ... 199
* 8 9 ... 15 72 73 ... 79 200 201 ... 207
* ... ... ...
* 56 57 ... 63 120 121 127 248 249 ... 255
*
* Note that the U and V data in one segment represents a 16 x 16 pixel
* area, but the Y data represents a 32 x 8 pixel area.
*
* If OV511_DUMPPIX is defined, _parse_data just dumps the incoming segments,
* verbatim, in order, into the frame. When used with vidcat -f ppm -s 640x480
* this puts the data on the standard output and can be analyzed with the
* parseppm.c utility I wrote. That's a much faster way for figuring out how
* this data is scrambled.
*/
****************************************************************/
#define HDIV 8
#define HDIV 8
#define WDIV (256/HDIV)
#define WDIV (256/HDIV)
#undef OV511_DUMPPIX
static
void
ov511_parse_data_rgb24
(
unsigned
char
*
pIn0
,
static
void
unsigned
char
*
pOut0
,
ov511_parse_data_rgb24
(
unsigned
char
*
pIn0
,
unsigned
char
*
pOut0
,
int
iOutY
,
int
iOutY
,
int
iOutUV
,
int
iHalf
,
int
iWidth
)
int
iOutUV
,
int
iHalf
,
int
iWidth
)
{
{
#ifndef OV511_DUMPPIX
#ifndef OV511_DUMPPIX
int
k
,
l
,
m
;
int
k
,
l
,
m
;
unsigned
char
*
pIn
;
unsigned
char
*
pIn
;
unsigned
char
*
pOut
,
*
pOut1
;
unsigned
char
*
pOut
,
*
pOut1
;
/* Just copy the Y's if in the first stripe */
if
(
!
iHalf
)
{
pIn
=
pIn0
+
128
;
pOut
=
pOut0
+
iOutY
;
for
(
k
=
0
;
k
<
4
;
k
++
)
{
pOut1
=
pOut
;
for
(
l
=
0
;
l
<
8
;
l
++
)
{
for
(
m
=
0
;
m
<
8
;
m
++
)
{
*
pOut1
=
*
pIn
++
;
pOut1
+=
3
;
}
pOut1
+=
(
iWidth
-
8
)
*
3
;
}
pOut
+=
8
*
3
;
}
}
/* Just copy the Y's if in the first stripe */
/* Use the first half of VUs to calculate value */
if
(
!
iHalf
)
{
pIn
=
pIn0
;
pIn
=
pIn0
+
128
;
pOut
=
pOut0
+
iOutUV
;
pOut
=
pOut0
+
iOutY
;
for
(
l
=
0
;
l
<
4
;
l
++
)
{
for
(
k
=
0
;
k
<
4
;
k
++
)
{
for
(
m
=
0
;
m
<
8
;
m
++
)
{
pOut1
=
pOut
;
int
y00
=
*
(
pOut
);
for
(
l
=
0
;
l
<
8
;
l
++
)
{
int
y01
=
*
(
pOut
+
3
);
for
(
m
=
0
;
m
<
8
;
m
++
)
{
int
y10
=
*
(
pOut
+
iWidth
*
3
);
*
pOut1
=
*
pIn
++
;
int
y11
=
*
(
pOut
+
iWidth
*
3
+
3
);
pOut1
+=
3
;
int
v
=
*
(
pIn
+
64
)
-
128
;
}
int
u
=
*
pIn
++
-
128
;
pOut1
+=
(
iWidth
-
8
)
*
3
;
ov511_move_420_block
(
y00
,
y01
,
y10
,
y11
,
u
,
v
,
iWidth
,
}
pOut
);
pOut
+=
8
*
3
;
pOut
+=
6
;
}
}
}
pOut
+=
(
iWidth
*
2
-
16
)
*
3
;
}
/* Use the first half of VUs to calculate value */
pIn
=
pIn0
;
/* Just copy the other UV rows */
pOut
=
pOut0
+
iOutUV
;
for
(
l
=
0
;
l
<
4
;
l
++
)
{
for
(
l
=
0
;
l
<
4
;
l
++
)
{
for
(
m
=
0
;
m
<
8
;
m
++
)
{
for
(
m
=
0
;
m
<
8
;
m
++
)
{
*
pOut
++
=
*
(
pIn
+
64
);
int
y00
=
*
(
pOut
);
*
pOut
=
*
pIn
++
;
int
y01
=
*
(
pOut
+
3
);
pOut
+=
5
;
int
y10
=
*
(
pOut
+
iWidth
*
3
);
}
int
y11
=
*
(
pOut
+
iWidth
*
3
+
3
);
pOut
+=
(
iWidth
*
2
-
16
)
*
3
;
int
v
=
*
(
pIn
+
64
)
-
128
;
}
int
u
=
*
pIn
++
-
128
;
ov511_move_420_block
(
y00
,
y01
,
y10
,
y11
,
u
,
v
,
iWidth
,
pOut
);
/* Calculate values if it's the second half */
pOut
+=
6
;
if
(
iHalf
)
{
}
pIn
=
pIn0
+
128
;
pOut
+=
(
iWidth
*
2
-
16
)
*
3
;
pOut
=
pOut0
+
iOutY
;
}
for
(
k
=
0
;
k
<
4
;
k
++
)
{
pOut1
=
pOut
;
/* Just copy the other UV rows */
for
(
l
=
0
;
l
<
4
;
l
++
)
{
for
(
l
=
0
;
l
<
4
;
l
++
)
{
for
(
m
=
0
;
m
<
4
;
m
++
)
{
for
(
m
=
0
;
m
<
8
;
m
++
)
{
int
y10
=
*
(
pIn
+
8
);
*
pOut
++
=
*
(
pIn
+
64
);
int
y00
=
*
pIn
++
;
*
pOut
=
*
pIn
++
;
int
y11
=
*
(
pIn
+
8
);
pOut
+=
5
;
int
y01
=
*
pIn
++
;
}
int
v
=
*
pOut1
-
128
;
pOut
+=
(
iWidth
*
2
-
16
)
*
3
;
int
u
=
*
(
pOut1
+
1
)
-
128
;
}
ov511_move_420_block
(
y00
,
y01
,
y10
,
y11
,
u
,
v
,
iWidth
,
pOut1
);
/* Calculate values if it's the second half */
pOut1
+=
6
;
if
(
iHalf
)
{
}
pIn
=
pIn0
+
128
;
pOut1
+=
(
iWidth
*
2
-
8
)
*
3
;
pOut
=
pOut0
+
iOutY
;
pIn
+=
8
;
for
(
k
=
0
;
k
<
4
;
k
++
)
{
}
pOut1
=
pOut
;
pOut
+=
8
*
3
;
for
(
l
=
0
;
l
<
4
;
l
++
)
{
}
for
(
m
=
0
;
m
<
4
;
m
++
)
{
}
int
y10
=
*
(
pIn
+
8
);
int
y00
=
*
pIn
++
;
int
y11
=
*
(
pIn
+
8
);
int
y01
=
*
pIn
++
;
int
v
=
*
pOut1
-
128
;
int
u
=
*
(
pOut1
+
1
)
-
128
;
ov511_move_420_block
(
y00
,
y01
,
y10
,
y11
,
u
,
v
,
iWidth
,
pOut1
);
pOut1
+=
6
;
}
pOut1
+=
(
iWidth
*
2
-
8
)
*
3
;
pIn
+=
8
;
}
pOut
+=
8
*
3
;
}
}
#else
#else
/* Just dump pix data straight out for debug */
/* Just dump pix data straight out for debug */
int
i
;
int
i
,
j
;
pOut0
+=
iSegmentY
*
384
;
for
(
i
=
0
;
i
<
384
;
i
++
)
{
pOut0
+=
iOutY
;
*
pOut0
++
=
*
pIn0
++
;
for
(
i
=
0
;
i
<
HDIV
;
i
++
)
{
for
(
j
=
0
;
j
<
WDIV
;
j
++
)
{
*
pOut0
++
=
*
pIn0
++
;
*
pOut0
++
=
*
pIn0
++
;
*
pOut0
++
=
*
pIn0
++
;
}
pOut0
+=
(
iWidth
-
WDIV
)
*
3
;
}
}
#endif
#endif
}
}
/***************************************************************
For 640x480 RAW BW images, data shows up in 1200 256 byte segments.
The segments represent 4 squares of 8x8 pixels as
follows:
0 1 ... 7 64 65 ... 71 ... 192 193 ... 199
/*
8 9 ... 15 72 73 ... 79 200 201 ... 207
* For 640x480 RAW BW images, data shows up in 1200 256 byte segments.
... ... ...
* The segments represent 4 squares of 8x8 pixels as follows:
56 57 ... 63 120 121 127 248 249 ... 255
*
* 0 1 ... 7 64 65 ... 71 ... 192 193 ... 199
****************************************************************/
* 8 9 ... 15 72 73 ... 79 200 201 ... 207
static
void
ov511_parse_data_grey
(
unsigned
char
*
pIn0
,
* ... ... ...
unsigned
char
*
pOut0
,
* 56 57 ... 63 120 121 127 248 249 ... 255
int
iOutY
,
*
int
iWidth
)
*/
static
void
ov511_parse_data_grey
(
unsigned
char
*
pIn0
,
unsigned
char
*
pOut0
,
int
iOutY
,
int
iWidth
)
{
{
int
k
,
l
,
m
;
int
k
,
l
,
m
;
unsigned
char
*
pIn
;
unsigned
char
*
pIn
;
unsigned
char
*
pOut
,
*
pOut1
;
unsigned
char
*
pOut
,
*
pOut1
;
pIn
=
pIn0
;
pIn
=
pIn0
;
pOut
=
pOut0
+
iOutY
;
pOut
=
pOut0
+
iOutY
;
for
(
k
=
0
;
k
<
4
;
k
++
)
{
for
(
k
=
0
;
k
<
4
;
k
++
)
{
pOut1
=
pOut
;
pOut1
=
pOut
;
for
(
l
=
0
;
l
<
8
;
l
++
)
{
for
(
l
=
0
;
l
<
8
;
l
++
)
{
for
(
m
=
0
;
m
<
8
;
m
++
)
{
for
(
m
=
0
;
m
<
8
;
m
++
)
{
*
pOut1
++
=
*
pIn
++
;
*
pOut1
++
=
*
pIn
++
;
}
}
pOut1
+=
iWidth
-
8
;
pOut1
+=
iWidth
-
8
;
}
}
pOut
+=
8
;
pOut
+=
8
;
}
}
}
}
/*
*************************************************************
/*
* fixFrameRGBoffset--
* fixFrameRGBoffset--
* My camera seems to return the red channel about 1 pixel
* My camera seems to return the red channel about 1 pixel
* low, and the blue channel about 1 pixel high. After YUV->RGB
* low, and the blue channel about 1 pixel high. After YUV->RGB
* conversion, we can correct this easily. OSL 2/24/2000.
* conversion, we can correct this easily. OSL 2/24/2000.
*
************************************************************
/
*/
static
void
fixFrameRGBoffset
(
struct
ov511_frame
*
frame
)
static
void
fixFrameRGBoffset
(
struct
ov511_frame
*
frame
)
{
{
int
x
,
y
;
int
x
,
y
;
int
rowBytes
=
frame
->
width
*
3
,
w
=
frame
->
width
;
int
rowBytes
=
frame
->
width
*
3
,
w
=
frame
->
width
;
unsigned
char
*
rgb
=
frame
->
data
;
unsigned
char
*
rgb
=
frame
->
data
;
const
int
shift
=
1
;
//Distance to shift pixels by, vertically
const
int
shift
=
1
;
/* Distance to shift pixels by, vertically */
if
(
frame
->
width
<
400
)
/* Don't bother with little images */
return
;
//Don't bother with little images
if
(
frame
->
width
<
400
)
return
;
//Shift red channel up
for
(
y
=
shift
;
y
<
frame
->
height
;
y
++
)
/* Shift red channel up */
{
for
(
y
=
shift
;
y
<
frame
->
height
;
y
++
)
{
int
lp
=
(
y
-
shift
)
*
rowBytes
;
//Previous line offset
int
lp
=
(
y
-
shift
)
*
rowBytes
;
/* Previous line offset */
int
lc
=
y
*
rowBytes
;
//Current line offset
int
lc
=
y
*
rowBytes
;
/* Current line offset */
for
(
x
=
0
;
x
<
w
;
x
++
)
for
(
x
=
0
;
x
<
w
;
x
++
)
rgb
[
lp
+
x
*
3
+
2
]
=
rgb
[
lc
+
x
*
3
+
2
];
//Shift red up
rgb
[
lp
+
x
*
3
+
2
]
=
rgb
[
lc
+
x
*
3
+
2
];
/* Shift red up */
}
}
//Shift blue channel down
/* Shift blue channel down */
for
(
y
=
frame
->
height
-
shift
-
1
;
y
>=
0
;
y
--
)
for
(
y
=
frame
->
height
-
shift
-
1
;
y
>=
0
;
y
--
)
{
{
int
ln
=
(
y
+
shift
)
*
rowBytes
;
/* Next line offset */
int
ln
=
(
y
+
shift
)
*
rowBytes
;
//Next line offset
int
lc
=
y
*
rowBytes
;
/* Current line offset */
int
lc
=
y
*
rowBytes
;
//Current line offset
for
(
x
=
0
;
x
<
w
;
x
++
)
for
(
x
=
0
;
x
<
w
;
x
++
)
rgb
[
ln
+
x
*
3
+
0
]
=
rgb
[
lc
+
x
*
3
+
0
];
/* Shift blue down */
rgb
[
ln
+
x
*
3
+
0
]
=
rgb
[
lc
+
x
*
3
+
0
];
//Shift blue down
}
}
}
}
/**********************************************************************
*
* OV511 data transfer, IRQ handler
*
**********************************************************************/
static
int
ov511_move_data
(
struct
usb_ov511
*
ov511
,
urb_t
*
urb
)
static
int
ov511_move_data
(
struct
usb_ov511
*
ov511
,
urb_t
*
urb
)
{
{
unsigned
char
*
cdata
;
unsigned
char
*
cdata
;
...
@@ -1175,6 +1488,7 @@ static int ov511_move_data(struct usb_ov511 *ov511, urb_t *urb)
...
@@ -1175,6 +1488,7 @@ static int ov511_move_data(struct usb_ov511 *ov511, urb_t *urb)
return
totlen
;
return
totlen
;
}
}
static
void
ov511_isoc_irq
(
struct
urb
*
urb
)
static
void
ov511_isoc_irq
(
struct
urb
*
urb
)
{
{
int
len
;
int
len
;
...
@@ -1187,28 +1501,32 @@ static void ov511_isoc_irq(struct urb *urb)
...
@@ -1187,28 +1501,32 @@ static void ov511_isoc_irq(struct urb *urb)
if
(
!
ov511
->
streaming
)
{
if
(
!
ov511
->
streaming
)
{
PDEBUG
(
2
,
"hmmm... not streaming, but got interrupt"
);
PDEBUG
(
2
,
"hmmm... not streaming, but got interrupt"
);
return
;
return
;
}
else
{
PDEBUG
(
5
,
"streaming. got interrupt"
);
}
}
sbuf
=
&
ov511
->
sbuf
[
ov511
->
cursbuf
];
sbuf
=
&
ov511
->
sbuf
[
ov511
->
cursbuf
];
/* Copy the data received into our scratch buffer */
/* Copy the data received into our scratch buffer */
if
(
ov511
->
curframe
>=
0
)
if
(
ov511
->
curframe
>=
0
)
{
len
=
ov511_move_data
(
ov511
,
urb
);
len
=
ov511_move_data
(
ov511
,
urb
);
else
if
(
waitqueue_active
(
&
ov511
->
wq
))
}
else
if
(
waitqueue_active
(
&
ov511
->
wq
))
{
wake_up_interruptible
(
&
ov511
->
wq
);
wake_up_interruptible
(
&
ov511
->
wq
);
}
/* Move to the next sbuf */
/* Move to the next sbuf */
ov511
->
cursbuf
=
(
ov511
->
cursbuf
+
1
)
%
OV511_NUMSBUF
;
ov511
->
cursbuf
=
(
ov511
->
cursbuf
+
1
)
%
OV511_NUMSBUF
;
return
;
return
;
}
}
static
int
ov511_init_isoc
(
struct
usb_ov511
*
ov511
)
static
int
ov511_init_isoc
(
struct
usb_ov511
*
ov511
)
{
{
urb_t
*
urb
;
urb_t
*
urb
;
int
fx
,
err
;
int
fx
,
err
;
PDEBUG
(
4
,
"ov511_init_isoc
"
);
PDEBUG
(
3
,
"*** Initializing capture ***
"
);
ov511
->
compress
=
0
;
ov511
->
compress
=
0
;
ov511
->
curframe
=
-
1
;
ov511
->
curframe
=
-
1
;
...
@@ -1235,11 +1553,11 @@ static int ov511_init_isoc(struct usb_ov511 *ov511)
...
@@ -1235,11 +1553,11 @@ static int ov511_init_isoc(struct usb_ov511 *ov511)
urb
->
pipe
=
usb_rcvisocpipe
(
ov511
->
dev
,
OV511_ENDPOINT_ADDRESS
);
urb
->
pipe
=
usb_rcvisocpipe
(
ov511
->
dev
,
OV511_ENDPOINT_ADDRESS
);
urb
->
transfer_flags
=
USB_ISO_ASAP
;
urb
->
transfer_flags
=
USB_ISO_ASAP
;
urb
->
transfer_buffer
=
ov511
->
sbuf
[
0
].
data
;
urb
->
transfer_buffer
=
ov511
->
sbuf
[
0
].
data
;
urb
->
complete
=
ov511_isoc_irq
;
urb
->
complete
=
ov511_isoc_irq
;
urb
->
number_of_packets
=
FRAMES_PER_DESC
;
urb
->
number_of_packets
=
FRAMES_PER_DESC
;
urb
->
transfer_buffer_length
=
ov511
->
packet_size
*
FRAMES_PER_DESC
;
urb
->
transfer_buffer_length
=
ov511
->
packet_size
*
FRAMES_PER_DESC
;
for
(
fx
=
0
;
fx
<
FRAMES_PER_DESC
;
fx
++
)
{
for
(
fx
=
0
;
fx
<
FRAMES_PER_DESC
;
fx
++
)
{
urb
->
iso_frame_desc
[
fx
].
offset
=
ov511
->
packet_size
*
fx
;
urb
->
iso_frame_desc
[
fx
].
offset
=
ov511
->
packet_size
*
fx
;
urb
->
iso_frame_desc
[
fx
].
length
=
ov511
->
packet_size
;
urb
->
iso_frame_desc
[
fx
].
length
=
ov511
->
packet_size
;
}
}
...
@@ -1254,11 +1572,11 @@ static int ov511_init_isoc(struct usb_ov511 *ov511)
...
@@ -1254,11 +1572,11 @@ static int ov511_init_isoc(struct usb_ov511 *ov511)
urb
->
pipe
=
usb_rcvisocpipe
(
ov511
->
dev
,
OV511_ENDPOINT_ADDRESS
);
urb
->
pipe
=
usb_rcvisocpipe
(
ov511
->
dev
,
OV511_ENDPOINT_ADDRESS
);
urb
->
transfer_flags
=
USB_ISO_ASAP
;
urb
->
transfer_flags
=
USB_ISO_ASAP
;
urb
->
transfer_buffer
=
ov511
->
sbuf
[
1
].
data
;
urb
->
transfer_buffer
=
ov511
->
sbuf
[
1
].
data
;
urb
->
complete
=
ov511_isoc_irq
;
urb
->
complete
=
ov511_isoc_irq
;
urb
->
number_of_packets
=
FRAMES_PER_DESC
;
urb
->
number_of_packets
=
FRAMES_PER_DESC
;
urb
->
transfer_buffer_length
=
ov511
->
packet_size
*
FRAMES_PER_DESC
;
urb
->
transfer_buffer_length
=
ov511
->
packet_size
*
FRAMES_PER_DESC
;
for
(
fx
=
0
;
fx
<
FRAMES_PER_DESC
;
fx
++
)
{
for
(
fx
=
0
;
fx
<
FRAMES_PER_DESC
;
fx
++
)
{
urb
->
iso_frame_desc
[
fx
].
offset
=
ov511
->
packet_size
*
fx
;
urb
->
iso_frame_desc
[
fx
].
offset
=
ov511
->
packet_size
*
fx
;
urb
->
iso_frame_desc
[
fx
].
length
=
ov511
->
packet_size
;
urb
->
iso_frame_desc
[
fx
].
length
=
ov511
->
packet_size
;
}
}
...
@@ -1280,10 +1598,11 @@ static int ov511_init_isoc(struct usb_ov511 *ov511)
...
@@ -1280,10 +1598,11 @@ static int ov511_init_isoc(struct usb_ov511 *ov511)
static
void
ov511_stop_isoc
(
struct
usb_ov511
*
ov511
)
static
void
ov511_stop_isoc
(
struct
usb_ov511
*
ov511
)
{
{
PDEBUG
(
4
,
"ov511_stop_isoc"
);
if
(
!
ov511
->
streaming
||
!
ov511
->
dev
)
if
(
!
ov511
->
streaming
||
!
ov511
->
dev
)
return
;
return
;
PDEBUG
(
3
,
"*** Stopping capture ***"
);
ov511_set_packet_size
(
ov511
,
0
);
ov511_set_packet_size
(
ov511
,
0
);
ov511
->
streaming
=
0
;
ov511
->
streaming
=
0
;
...
@@ -1303,18 +1622,19 @@ static void ov511_stop_isoc(struct usb_ov511 *ov511)
...
@@ -1303,18 +1622,19 @@ static void ov511_stop_isoc(struct usb_ov511 *ov511)
}
}
}
}
static
int
ov511_new_frame
(
struct
usb_ov511
*
ov511
,
int
framenum
)
static
int
ov511_new_frame
(
struct
usb_ov511
*
ov511
,
int
framenum
)
{
{
struct
ov511_frame
*
frame
;
struct
ov511_frame
*
frame
;
int
width
,
height
;
int
width
,
height
;
PDEBUG
(
4
,
"ov511
_new_frame"
);
PDEBUG
(
4
,
"ov511
->curframe = %d, framenum = %d"
,
ov511
->
curframe
,
framenum
);
if
(
!
ov511
->
dev
)
if
(
!
ov511
->
dev
)
return
-
1
;
return
-
1
;
/* If we're not grabbing a frame right now and the other frame is */
/* If we're not grabbing a frame right now and the other frame is */
/*
ready to be grabbed into, then use it instead */
/* ready to be grabbed into, then use it instead */
if
(
ov511
->
curframe
==
-
1
)
{
if
(
ov511
->
curframe
==
-
1
)
{
if
(
ov511
->
frame
[(
framenum
-
1
+
OV511_NUMFRAMES
)
%
OV511_NUMFRAMES
].
grabstate
==
FRAME_READY
)
if
(
ov511
->
frame
[(
framenum
-
1
+
OV511_NUMFRAMES
)
%
OV511_NUMFRAMES
].
grabstate
==
FRAME_READY
)
framenum
=
(
framenum
-
1
+
OV511_NUMFRAMES
)
%
OV511_NUMFRAMES
;
framenum
=
(
framenum
-
1
+
OV511_NUMFRAMES
)
%
OV511_NUMFRAMES
;
...
@@ -1325,6 +1645,9 @@ static int ov511_new_frame(struct usb_ov511 *ov511, int framenum)
...
@@ -1325,6 +1645,9 @@ static int ov511_new_frame(struct usb_ov511 *ov511, int framenum)
width
=
frame
->
width
;
width
=
frame
->
width
;
height
=
frame
->
height
;
height
=
frame
->
height
;
PDEBUG
(
4
,
"framenum = %d, width = %d, height = %d"
,
framenum
,
width
,
height
);
frame
->
grabstate
=
FRAME_GRABBING
;
frame
->
grabstate
=
FRAME_GRABBING
;
frame
->
scanstate
=
STATE_SCANNING
;
frame
->
scanstate
=
STATE_SCANNING
;
frame
->
scanlength
=
0
;
/* accumulated in ov511_parse_data() */
frame
->
scanlength
=
0
;
/* accumulated in ov511_parse_data() */
...
@@ -1335,11 +1658,17 @@ static int ov511_new_frame(struct usb_ov511 *ov511, int framenum)
...
@@ -1335,11 +1658,17 @@ static int ov511_new_frame(struct usb_ov511 *ov511, int framenum)
/* Make sure it's not too big */
/* Make sure it's not too big */
if
(
width
>
DEFAULT_WIDTH
)
if
(
width
>
DEFAULT_WIDTH
)
width
=
DEFAULT_WIDTH
;
width
=
DEFAULT_WIDTH
;
#if 0
width = (width / 8) * 8; /* Multiple of 8 */
width = (width / 8) * 8; /* Multiple of 8 */
#endif
width
&=
~
7L
;
if
(
height
>
DEFAULT_HEIGHT
)
if
(
height
>
DEFAULT_HEIGHT
)
height
=
DEFAULT_HEIGHT
;
height
=
DEFAULT_HEIGHT
;
#if 0
height = (height / 4) * 4; /* Multiple of 4 */
height = (height / 4) * 4; /* Multiple of 4 */
#endif
width
&=
~
3L
;
// /* We want a fresh frame every 30 we get */
// /* We want a fresh frame every 30 we get */
// ov511->compress = (ov511->compress + 1) % 30;
// ov511->compress = (ov511->compress + 1) % 30;
...
@@ -1348,7 +1677,12 @@ static int ov511_new_frame(struct usb_ov511 *ov511, int framenum)
...
@@ -1348,7 +1677,12 @@ static int ov511_new_frame(struct usb_ov511 *ov511, int framenum)
}
}
/* Video 4 Linux API */
/****************************************************************************
*
* V4L API
*
***************************************************************************/
static
int
ov511_open
(
struct
video_device
*
dev
,
int
flags
)
static
int
ov511_open
(
struct
video_device
*
dev
,
int
flags
)
{
{
int
err
=
-
EBUSY
;
int
err
=
-
EBUSY
;
...
@@ -1409,9 +1743,9 @@ static int ov511_open(struct video_device *dev, int flags)
...
@@ -1409,9 +1743,9 @@ static int ov511_open(struct video_device *dev, int flags)
out_unlock:
out_unlock:
up
(
&
ov511
->
lock
);
up
(
&
ov511
->
lock
);
return
err
;
return
err
;
}
}
static
void
ov511_close
(
struct
video_device
*
dev
)
static
void
ov511_close
(
struct
video_device
*
dev
)
{
{
struct
usb_ov511
*
ov511
=
(
struct
usb_ov511
*
)
dev
;
struct
usb_ov511
*
ov511
=
(
struct
usb_ov511
*
)
dev
;
...
@@ -1438,16 +1772,23 @@ static void ov511_close(struct video_device *dev)
...
@@ -1438,16 +1772,23 @@ static void ov511_close(struct video_device *dev)
}
}
}
}
static
int
ov511_init_done
(
struct
video_device
*
dev
)
static
int
ov511_init_done
(
struct
video_device
*
dev
)
{
{
#ifdef CONFIG_PROC_FS
create_proc_ov511_cam
((
struct
usb_ov511
*
)
dev
);
#endif
return
0
;
return
0
;
}
}
static
long
ov511_write
(
struct
video_device
*
dev
,
const
char
*
buf
,
unsigned
long
count
,
int
noblock
)
static
long
ov511_write
(
struct
video_device
*
dev
,
const
char
*
buf
,
unsigned
long
count
,
int
noblock
)
{
{
return
-
EINVAL
;
return
-
EINVAL
;
}
}
static
int
ov511_ioctl
(
struct
video_device
*
vdev
,
unsigned
int
cmd
,
void
*
arg
)
static
int
ov511_ioctl
(
struct
video_device
*
vdev
,
unsigned
int
cmd
,
void
*
arg
)
{
{
struct
usb_ov511
*
ov511
=
(
struct
usb_ov511
*
)
vdev
;
struct
usb_ov511
*
ov511
=
(
struct
usb_ov511
*
)
vdev
;
...
@@ -1458,311 +1799,313 @@ static int ov511_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
...
@@ -1458,311 +1799,313 @@ static int ov511_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
return
-
EIO
;
return
-
EIO
;
switch
(
cmd
)
{
switch
(
cmd
)
{
case
VIDIOCGCAP
:
case
VIDIOCGCAP
:
{
{
struct
video_capability
b
;
struct
video_capability
b
;
strcpy
(
b
.
name
,
"OV511 USB Camera"
);
strcpy
(
b
.
name
,
"OV511 USB Camera"
);
b
.
type
=
VID_TYPE_CAPTURE
|
VID_TYPE_SUBCAPTURE
;
b
.
type
=
VID_TYPE_CAPTURE
|
VID_TYPE_SUBCAPTURE
;
b
.
channels
=
1
;
b
.
channels
=
1
;
b
.
audios
=
0
;
b
.
audios
=
0
;
b
.
maxwidth
=
DEFAULT_WIDTH
;
b
.
maxwidth
=
DEFAULT_WIDTH
;
b
.
maxheight
=
DEFAULT_HEIGHT
;
b
.
maxheight
=
DEFAULT_HEIGHT
;
b
.
minwidth
=
32
;
b
.
minwidth
=
32
;
b
.
minheight
=
16
;
b
.
minheight
=
16
;
if
(
copy_to_user
(
arg
,
&
b
,
sizeof
(
b
)))
if
(
copy_to_user
(
arg
,
&
b
,
sizeof
(
b
)))
return
-
EFAULT
;
return
-
EFAULT
;
return
0
;
return
0
;
}
}
case
VIDIOCGCHAN
:
case
VIDIOCGCHAN
:
{
{
struct
video_channel
v
;
struct
video_channel
v
;
if
(
copy_from_user
(
&
v
,
arg
,
sizeof
(
v
)))
if
(
copy_from_user
(
&
v
,
arg
,
sizeof
(
v
)))
return
-
EFAULT
;
return
-
EFAULT
;
if
(
v
.
channel
!=
0
)
if
(
v
.
channel
!=
0
)
return
-
EINVAL
;
return
-
EINVAL
;
v
.
flags
=
0
;
v
.
flags
=
0
;
v
.
tuners
=
0
;
v
.
tuners
=
0
;
v
.
type
=
VIDEO_TYPE_CAMERA
;
v
.
type
=
VIDEO_TYPE_CAMERA
;
strcpy
(
v
.
name
,
"Camera"
);
strcpy
(
v
.
name
,
"Camera"
);
if
(
copy_to_user
(
arg
,
&
v
,
sizeof
(
v
)))
if
(
copy_to_user
(
arg
,
&
v
,
sizeof
(
v
)))
return
-
EFAULT
;
return
-
EFAULT
;
return
0
;
return
0
;
}
}
case
VIDIOCSCHAN
:
case
VIDIOCSCHAN
:
{
{
int
v
;
int
v
;
if
(
copy_from_user
(
&
v
,
arg
,
sizeof
(
v
)))
return
-
EFAULT
;
if
(
v
!=
0
)
if
(
copy_from_user
(
&
v
,
arg
,
sizeof
(
v
))
)
return
-
EINVAL
;
return
-
EFAULT
;
return
0
;
if
(
v
!=
0
)
}
return
-
EINVAL
;
case
VIDIOCGPICT
:
return
0
;
{
}
struct
video_picture
p
;
case
VIDIOCGPICT
:
{
struct
video_picture
p
;
if
(
ov7610_get_picture
(
ov511
,
&
p
))
if
(
ov7610_get_picture
(
ov511
,
&
p
))
return
-
EIO
;
return
-
EIO
;
if
(
copy_to_user
(
arg
,
&
p
,
sizeof
(
p
)))
if
(
copy_to_user
(
arg
,
&
p
,
sizeof
(
p
)))
return
-
EFAULT
;
return
-
EFAULT
;
return
0
;
}
case
VIDIOCSPICT
:
{
struct
video_picture
p
;
if
(
copy_from_user
(
&
p
,
arg
,
sizeof
(
p
)))
return
0
;
return
-
EFAULT
;
}
case
VIDIOCSPICT
:
if
(
ov7610_set_picture
(
ov511
,
&
p
))
{
return
-
EIO
;
struct
video_picture
p
;
return
0
;
if
(
copy_from_user
(
&
p
,
arg
,
sizeof
(
p
)))
}
return
-
EFAULT
;
case
VIDIOCGCAPTURE
:
{
if
(
ov7610_set_picture
(
ov511
,
&
p
))
int
vf
;
return
-
EIO
;
if
(
copy_from_user
(
&
vf
,
arg
,
sizeof
(
vf
)))
return
-
EFAULT
;
ov511
->
sub_flag
=
vf
;
return
0
;
}
case
VIDIOCSCAPTURE
:
{
struct
video_capture
vc
;
if
(
copy_from_user
(
&
vc
,
arg
,
sizeof
(
vc
)))
return
0
;
return
-
EFAULT
;
}
if
(
vc
.
flags
)
case
VIDIOCGCAPTURE
:
return
-
EINVAL
;
{
if
(
vc
.
decimation
)
int
vf
;
return
-
EINVAL
;
if
(
copy_from_user
(
&
vf
,
arg
,
sizeof
(
vf
)))
vc
.
x
/=
4
;
return
-
EFAULT
;
vc
.
x
*=
4
;
ov511
->
sub_flag
=
vf
;
vc
.
y
/=
2
;
return
0
;
vc
.
y
*=
2
;
}
vc
.
width
/=
32
;
case
VIDIOCSCAPTURE
:
vc
.
width
*=
32
;
{
if
(
vc
.
width
==
0
)
vc
.
width
=
32
;
struct
video_capture
vc
;
vc
.
height
/=
16
;
vc
.
height
*=
16
;
if
(
vc
.
height
==
0
)
vc
.
height
=
16
;
ov511
->
subx
=
vc
.
x
;
ov511
->
suby
=
vc
.
y
;
ov511
->
subw
=
vc
.
width
;
ov511
->
subh
=
vc
.
height
;
return
0
;
}
case
VIDIOCSWIN
:
{
struct
video_window
vw
;
if
(
copy_from_user
(
&
vw
,
arg
,
sizeof
(
vw
)))
if
(
copy_from_user
(
&
vc
,
arg
,
sizeof
(
vc
)))
return
-
EFAULT
;
return
-
EFAULT
;
if
(
vw
.
flags
)
if
(
vc
.
flags
)
return
-
EINVAL
;
return
-
EINVAL
;
if
(
vw
.
clipcount
)
if
(
vc
.
decimation
)
return
-
EINVAL
;
return
-
EINVAL
;
if
(
vw
.
height
!=
DEFAULT_HEIGHT
)
vc
.
x
/=
4
;
return
-
EINVAL
;
vc
.
x
*=
4
;
if
(
vw
.
width
!=
DEFAULT_WIDTH
)
vc
.
y
/=
2
;
return
-
EINVAL
;
vc
.
y
*=
2
;
vc
.
width
/=
32
;
vc
.
width
*=
32
;
if
(
vc
.
width
==
0
)
vc
.
width
=
32
;
vc
.
height
/=
16
;
vc
.
height
*=
16
;
if
(
vc
.
height
==
0
)
vc
.
height
=
16
;
ov511
->
subx
=
vc
.
x
;
ov511
->
suby
=
vc
.
y
;
ov511
->
subw
=
vc
.
width
;
ov511
->
subh
=
vc
.
height
;
ov511
->
compress
=
0
;
return
0
;
}
case
VIDIOCSWIN
:
{
struct
video_window
vw
;
return
0
;
if
(
copy_from_user
(
&
vw
,
arg
,
sizeof
(
vw
)))
}
return
-
EFAULT
;
case
VIDIOCGWIN
:
if
(
vw
.
flags
)
{
return
-
EINVAL
;
struct
video_window
vw
;
if
(
vw
.
clipcount
)
return
-
EINVAL
;
if
(
vw
.
height
!=
DEFAULT_HEIGHT
)
return
-
EINVAL
;
if
(
vw
.
width
!=
DEFAULT_WIDTH
)
return
-
EINVAL
;
vw
.
x
=
0
;
ov511
->
compress
=
0
;
vw
.
y
=
0
;
vw
.
width
=
DEFAULT_WIDTH
;
vw
.
height
=
DEFAULT_HEIGHT
;
vw
.
chromakey
=
0
;
vw
.
flags
=
30
;
if
(
copy_to_user
(
arg
,
&
vw
,
sizeof
(
vw
)))
return
0
;
return
-
EFAULT
;
}
case
VIDIOCGWIN
:
{
struct
video_window
vw
;
return
0
;
vw
.
x
=
0
;
}
vw
.
y
=
0
;
case
VIDIOCGMBUF
:
vw
.
width
=
DEFAULT_WIDTH
;
{
vw
.
height
=
DEFAULT_HEIGHT
;
struct
video_mbuf
vm
;
vw
.
chromakey
=
0
;
vw
.
flags
=
30
;
memset
(
&
vm
,
0
,
sizeof
(
vm
));
if
(
copy_to_user
(
arg
,
&
vw
,
sizeof
(
vw
)))
vm
.
size
=
2
*
MAX_DATA_SIZE
;
return
-
EFAULT
;
vm
.
frames
=
2
;
vm
.
offsets
[
0
]
=
0
;
vm
.
offsets
[
1
]
=
MAX_FRAME_SIZE
+
sizeof
(
struct
timeval
);
if
(
copy_to_user
((
void
*
)
arg
,
(
void
*
)
&
vm
,
sizeof
(
vm
)))
return
0
;
return
-
EFAULT
;
}
case
VIDIOCGMBUF
:
{
struct
video_mbuf
vm
;
return
0
;
memset
(
&
vm
,
0
,
sizeof
(
vm
))
;
}
vm
.
size
=
2
*
MAX_DATA_SIZE
;
case
VIDIOCMCAPTURE
:
vm
.
frames
=
2
;
{
vm
.
offsets
[
0
]
=
0
;
struct
video_mmap
vm
;
vm
.
offsets
[
1
]
=
MAX_FRAME_SIZE
+
sizeof
(
struct
timeval
)
;
if
(
copy_from_user
((
void
*
)
&
vm
,
(
void
*
)
arg
,
sizeof
(
vm
)))
if
(
copy_to_user
((
void
*
)
arg
,
(
void
*
)
&
vm
,
sizeof
(
vm
)))
return
-
EFAULT
;
return
-
EFAULT
;
PDEBUG
(
4
,
"MCAPTURE"
);
return
0
;
PDEBUG
(
4
,
"frame: %d, size: %dx%d, format: %d"
,
}
vm
.
frame
,
vm
.
width
,
vm
.
height
,
vm
.
format
);
case
VIDIOCMCAPTURE
:
{
struct
video_mmap
vm
;
if
(
vm
.
format
!=
VIDEO_PALETTE_RGB24
&&
if
(
copy_from_user
((
void
*
)
&
vm
,
(
void
*
)
arg
,
sizeof
(
vm
)))
vm
.
format
!=
VIDEO_PALETTE_GREY
)
return
-
EFAULT
;
return
-
EINVAL
;
if
((
vm
.
frame
!=
0
)
&&
(
vm
.
frame
!=
1
))
PDEBUG
(
4
,
"MCAPTURE"
);
return
-
EINVAL
;
PDEBUG
(
4
,
"frame: %d, size: %dx%d, format: %d"
,
vm
.
frame
,
vm
.
width
,
vm
.
height
,
vm
.
format
);
if
(
vm
.
format
!=
VIDEO_PALETTE_RGB24
&&
vm
.
format
!=
VIDEO_PALETTE_GREY
)
return
-
EINVAL
;
if
((
vm
.
frame
!=
0
)
&&
(
vm
.
frame
!=
1
))
return
-
EINVAL
;
if
(
ov511
->
frame
[
vm
.
frame
].
grabstate
==
FRAME_GRABBING
)
if
(
ov511
->
frame
[
vm
.
frame
].
grabstate
==
FRAME_GRABBING
)
return
-
EBUSY
;
return
-
EBUSY
;
/* Don't compress if the size changed */
/* Don't compress if the size changed */
if
((
ov511
->
frame
[
vm
.
frame
].
width
!=
vm
.
width
)
||
if
((
ov511
->
frame
[
vm
.
frame
].
width
!=
vm
.
width
)
||
(
ov511
->
frame
[
vm
.
frame
].
height
!=
vm
.
height
)
||
(
ov511
->
frame
[
vm
.
frame
].
height
!=
vm
.
height
)
||
(
ov511
->
frame
[
vm
.
frame
].
format
!=
vm
.
format
)
||
(
ov511
->
frame
[
vm
.
frame
].
format
!=
vm
.
format
)
||
(
ov511
->
frame
[
vm
.
frame
].
sub_flag
!=
(
ov511
->
frame
[
vm
.
frame
].
sub_flag
!=
ov511
->
sub_flag
))
{
ov511
->
sub_flag
))
{
/* If we're collecting previous frame wait
/* If we're collecting previous frame wait
before changing modes */
before changing modes */
interruptible_sleep_on
(
&
ov511
->
wq
);
interruptible_sleep_on
(
&
ov511
->
wq
);
if
(
signal_pending
(
current
))
return
-
EINTR
;
if
(
signal_pending
(
current
))
return
-
EINTR
;
ov511_mode_init_regs
(
ov511
,
ov511_mode_init_regs
(
ov511
,
vm
.
width
,
vm
.
height
,
vm
.
width
,
vm
.
height
,
vm
.
format
,
ov511
->
sub_flag
);
vm
.
format
,
ov511
->
sub_flag
);
}
}
ov511
->
frame
[
vm
.
frame
].
width
=
vm
.
width
;
ov511
->
frame
[
vm
.
frame
].
width
=
vm
.
width
;
ov511
->
frame
[
vm
.
frame
].
height
=
vm
.
height
;
ov511
->
frame
[
vm
.
frame
].
height
=
vm
.
height
;
ov511
->
frame
[
vm
.
frame
].
format
=
vm
.
format
;
ov511
->
frame
[
vm
.
frame
].
format
=
vm
.
format
;
ov511
->
frame
[
vm
.
frame
].
sub_flag
=
ov511
->
sub_flag
;
ov511
->
frame
[
vm
.
frame
].
sub_flag
=
ov511
->
sub_flag
;
ov511
->
frame
[
vm
.
frame
].
segsize
=
ov511
->
frame
[
vm
.
frame
].
segsize
=
vm
.
format
==
VIDEO_PALETTE_RGB24
?
384
:
256
;
vm
.
format
==
VIDEO_PALETTE_RGB24
?
384
:
256
;
ov511
->
frame
[
vm
.
frame
].
depth
=
ov511
->
frame
[
vm
.
frame
].
depth
=
vm
.
format
==
VIDEO_PALETTE_RGB24
?
3
:
1
;
vm
.
format
==
VIDEO_PALETTE_RGB24
?
3
:
1
;
/* Mark it as ready */
/* Mark it as ready */
ov511
->
frame
[
vm
.
frame
].
grabstate
=
FRAME_READY
;
ov511
->
frame
[
vm
.
frame
].
grabstate
=
FRAME_READY
;
return
ov511_new_frame
(
ov511
,
vm
.
frame
);
return
ov511_new_frame
(
ov511
,
vm
.
frame
);
}
}
case
VIDIOCSYNC
:
case
VIDIOCSYNC
:
{
{
int
frame
;
int
frame
;
if
(
copy_from_user
((
void
*
)
&
frame
,
arg
,
sizeof
(
int
)))
if
(
copy_from_user
((
void
*
)
&
frame
,
arg
,
sizeof
(
int
)))
return
-
EFAULT
;
return
-
EFAULT
;
PDEBUG
(
4
,
"syncing to frame %d, grabstate = %d"
,
frame
,
PDEBUG
(
4
,
"syncing to frame %d, grabstate = %d"
,
frame
,
ov511
->
frame
[
frame
].
grabstate
);
ov511
->
frame
[
frame
].
grabstate
);
switch
(
ov511
->
frame
[
frame
].
grabstate
)
{
switch
(
ov511
->
frame
[
frame
].
grabstate
)
{
case
FRAME_UNUSED
:
case
FRAME_UNUSED
:
return
-
EINVAL
;
return
-
EINVAL
;
case
FRAME_READY
:
case
FRAME_READY
:
case
FRAME_GRABBING
:
case
FRAME_GRABBING
:
case
FRAME_ERROR
:
case
FRAME_ERROR
:
redo:
redo:
if
(
!
ov511
->
dev
)
if
(
!
ov511
->
dev
)
return
-
EIO
;
return
-
EIO
;
do
{
do
{
#if 0
#if 0
init_waitqueue_head(&ov511->frame[frame].wq);
init_waitqueue_head(&ov511->frame[frame].wq);
#endif
#endif
interruptible_sleep_on
(
&
ov511
->
frame
[
frame
].
wq
);
interruptible_sleep_on
(
&
ov511
->
frame
[
frame
].
wq
);
if
(
signal_pending
(
current
))
if
(
signal_pending
(
current
))
return
-
EINTR
;
return
-
EINTR
;
}
while
(
ov511
->
frame
[
frame
].
grabstate
==
FRAME_GRABBING
);
}
while
(
ov511
->
frame
[
frame
].
grabstate
==
FRAME_GRABBING
);
if
(
ov511
->
frame
[
frame
].
grabstate
==
FRAME_ERROR
)
{
if
(
ov511
->
frame
[
frame
].
grabstate
==
FRAME_ERROR
)
{
int
ret
;
int
ret
;
if
((
ret
=
ov511_new_frame
(
ov511
,
frame
))
<
0
)
if
((
ret
=
ov511_new_frame
(
ov511
,
frame
))
<
0
)
return
ret
;
return
ret
;
goto
redo
;
goto
redo
;
}
}
case
FRAME_DONE
:
case
FRAME_DONE
:
ov511
->
frame
[
frame
].
grabstate
=
FRAME_UNUSED
;
ov511
->
frame
[
frame
].
grabstate
=
FRAME_UNUSED
;
break
;
break
;
}
}
ov511
->
frame
[
frame
].
grabstate
=
FRAME_UNUSED
;
/* Reset the hardware snapshot button */
ov511
->
frame
[
frame
].
grabstate
=
FRAME_UNUSED
;
/* FIXME - Is this the best place for this? */
if
((
ov511
->
snap_enabled
)
&&
(
ov511
->
frame
[
frame
].
snapshot
))
{
ov511
->
frame
[
frame
].
snapshot
=
0
;
ov511_reg_write
(
ov511
->
dev
,
0x52
,
0x01
);
ov511_reg_write
(
ov511
->
dev
,
0x52
,
0x03
);
ov511_reg_write
(
ov511
->
dev
,
0x52
,
0x01
);
}
return
0
;
/* Reset the hardware snapshot button */
/* FIXME - Is this the best place for this? */
if
((
ov511
->
snap_enabled
)
&&
(
ov511
->
frame
[
frame
].
snapshot
))
{
ov511
->
frame
[
frame
].
snapshot
=
0
;
ov511_reg_write
(
ov511
->
dev
,
0x52
,
0x01
);
ov511_reg_write
(
ov511
->
dev
,
0x52
,
0x03
);
ov511_reg_write
(
ov511
->
dev
,
0x52
,
0x01
);
}
}
case
VIDIOCGFBUF
:
{
struct
video_buffer
vb
;
memset
(
&
vb
,
0
,
sizeof
(
vb
));
return
0
;
vb
.
base
=
NULL
;
/* frame buffer not supported, not used */
}
case
VIDIOCGFBUF
:
{
struct
video_buffer
vb
;
if
(
copy_to_user
((
void
*
)
arg
,
(
void
*
)
&
vb
,
sizeof
(
vb
)))
memset
(
&
vb
,
0
,
sizeof
(
vb
));
return
-
EFAULT
;
vb
.
base
=
NULL
;
/* frame buffer not supported, not used */
return
0
;
if
(
copy_to_user
((
void
*
)
arg
,
(
void
*
)
&
vb
,
sizeof
(
vb
)))
}
return
-
EFAULT
;
case
VIDIOCKEY
:
return
0
;
return
0
;
case
VIDIOCCAPTURE
:
return
-
EINVAL
;
case
VIDIOCSFBUF
:
return
-
EINVAL
;
case
VIDIOCGTUNER
:
case
VIDIOCSTUNER
:
return
-
EINVAL
;
case
VIDIOCGFREQ
:
case
VIDIOCSFREQ
:
return
-
EINVAL
;
case
VIDIOCGAUDIO
:
case
VIDIOCSAUDIO
:
return
-
EINVAL
;
default:
return
-
ENOIOCTLCMD
;
}
}
case
VIDIOCKEY
:
return
0
;
case
VIDIOCCAPTURE
:
return
-
EINVAL
;
case
VIDIOCSFBUF
:
return
-
EINVAL
;
case
VIDIOCGTUNER
:
case
VIDIOCSTUNER
:
return
-
EINVAL
;
case
VIDIOCGFREQ
:
case
VIDIOCSFREQ
:
return
-
EINVAL
;
case
VIDIOCGAUDIO
:
case
VIDIOCSAUDIO
:
return
-
EINVAL
;
default:
return
-
ENOIOCTLCMD
;
}
/* End switch(cmd) */
return
0
;
return
0
;
}
}
static
long
ov511_read
(
struct
video_device
*
dev
,
char
*
buf
,
unsigned
long
count
,
int
noblock
)
static
long
ov511_read
(
struct
video_device
*
dev
,
char
*
buf
,
unsigned
long
count
,
int
noblock
)
{
{
struct
usb_ov511
*
ov511
=
(
struct
usb_ov511
*
)
dev
;
struct
usb_ov511
*
ov511
=
(
struct
usb_ov511
*
)
dev
;
int
i
;
int
frmx
=
-
1
;
int
frmx
=
-
1
;
volatile
struct
ov511_frame
*
frame
;
volatile
struct
ov511_frame
*
frame
;
PDEBUG
(
4
,
"
ov511_read:
%ld bytes, noblock=%d"
,
count
,
noblock
);
PDEBUG
(
4
,
"%ld bytes, noblock=%d"
,
count
,
noblock
);
if
(
!
dev
||
!
buf
)
if
(
!
dev
||
!
buf
)
return
-
EFAULT
;
return
-
EFAULT
;
...
@@ -1776,6 +2119,7 @@ static long ov511_read(struct video_device *dev, char *buf, unsigned long count,
...
@@ -1776,6 +2119,7 @@ static long ov511_read(struct video_device *dev, char *buf, unsigned long count,
else
if
(
ov511
->
frame
[
1
].
grabstate
>=
FRAME_DONE
)
/* _DONE or _ERROR */
else
if
(
ov511
->
frame
[
1
].
grabstate
>=
FRAME_DONE
)
/* _DONE or _ERROR */
frmx
=
1
;
frmx
=
1
;
/* If nonblocking we return immediately */
if
(
noblock
&&
(
frmx
==
-
1
))
if
(
noblock
&&
(
frmx
==
-
1
))
return
-
EAGAIN
;
return
-
EAGAIN
;
...
@@ -1794,19 +2138,26 @@ static long ov511_read(struct video_device *dev, char *buf, unsigned long count,
...
@@ -1794,19 +2138,26 @@ static long ov511_read(struct video_device *dev, char *buf, unsigned long count,
frame
=
&
ov511
->
frame
[
frmx
];
frame
=
&
ov511
->
frame
[
frmx
];
/* FIXME */
frame
->
segsize
=
frame
->
format
==
VIDEO_PALETTE_RGB24
?
384
:
256
;
frame
->
depth
=
frame
->
format
==
VIDEO_PALETTE_RGB24
?
24
:
8
;
restart:
restart:
if
(
!
ov511
->
dev
)
if
(
!
ov511
->
dev
)
return
-
EIO
;
return
-
EIO
;
/* Wait while we're grabbing the image */
PDEBUG
(
4
,
"Waiting image grabbing"
);
while
(
frame
->
grabstate
==
FRAME_GRABBING
)
{
while
(
frame
->
grabstate
==
FRAME_GRABBING
)
{
interruptible_sleep_on
(
&
ov511
->
frame
[
frmx
].
wq
);
interruptible_sleep_on
(
&
ov511
->
frame
[
frmx
].
wq
);
if
(
signal_pending
(
current
))
if
(
signal_pending
(
current
))
return
-
EINTR
;
return
-
EINTR
;
}
}
PDEBUG
(
4
,
"Got image, frame->grabstate = %d"
,
frame
->
grabstate
);
if
(
frame
->
grabstate
==
FRAME_ERROR
)
{
if
(
frame
->
grabstate
==
FRAME_ERROR
)
{
frame
->
bytes_read
=
0
;
frame
->
bytes_read
=
0
;
err
(
"
ov511_read: e
rrored frame %d"
,
ov511
->
curframe
);
err
(
"
** ick! ** E
rrored frame %d"
,
ov511
->
curframe
);
if
(
ov511_new_frame
(
ov511
,
frmx
))
if
(
ov511_new_frame
(
ov511
,
frmx
))
err
(
"ov511_read: ov511_new_frame error"
);
err
(
"ov511_read: ov511_new_frame error"
);
goto
restart
;
goto
restart
;
...
@@ -1814,14 +2165,21 @@ static long ov511_read(struct video_device *dev, char *buf, unsigned long count,
...
@@ -1814,14 +2165,21 @@ static long ov511_read(struct video_device *dev, char *buf, unsigned long count,
/* Repeat until we get a snapshot frame */
/* Repeat until we get a snapshot frame */
if
(
!
ov511
->
snap_enabled
)
{
PDEBUG
(
4
,
"snap disabled"
);
}
else
{
PDEBUG
(
4
,
"Waiting snapshot frame"
);
}
if
(
ov511
->
snap_enabled
&&
!
frame
->
snapshot
)
{
if
(
ov511
->
snap_enabled
&&
!
frame
->
snapshot
)
{
frame
->
bytes_read
=
0
;
frame
->
bytes_read
=
0
;
if
(
ov511_new_frame
(
ov511
,
frmx
))
if
(
ov511_new_frame
(
ov511
,
frmx
))
err
(
"ov511_
read: ov511_
new_frame error"
);
err
(
"ov511_new_frame error"
);
goto
restart
;
goto
restart
;
}
}
/* Clear the snapshot */
/* Clear the snapshot */
if
(
ov511
->
snap_enabled
)
PDEBUG
(
4
,
"Clear snapshot"
);
if
(
ov511
->
snap_enabled
&&
frame
->
snapshot
)
{
if
(
ov511
->
snap_enabled
&&
frame
->
snapshot
)
{
frame
->
snapshot
=
0
;
frame
->
snapshot
=
0
;
ov511_reg_write
(
ov511
->
dev
,
0x52
,
0x01
);
ov511_reg_write
(
ov511
->
dev
,
0x52
,
0x01
);
...
@@ -1829,20 +2187,24 @@ static long ov511_read(struct video_device *dev, char *buf, unsigned long count,
...
@@ -1829,20 +2187,24 @@ static long ov511_read(struct video_device *dev, char *buf, unsigned long count,
ov511_reg_write
(
ov511
->
dev
,
0x52
,
0x01
);
ov511_reg_write
(
ov511
->
dev
,
0x52
,
0x01
);
}
}
PDEBUG
(
4
,
"
ov511_read:
frmx=%d, bytes_read=%ld, scanlength=%ld"
,
frmx
,
PDEBUG
(
4
,
"frmx=%d, bytes_read=%ld, scanlength=%ld"
,
frmx
,
frame
->
bytes_read
,
frame
->
scanlength
);
frame
->
bytes_read
,
frame
->
scanlength
);
/* copy bytes to user space; we allow for partials reads */
/* copy bytes to user space; we allow for partials reads */
// if ((count + frame->bytes_read) > frame->scanlength)
// if ((count + frame->bytes_read) > frame->scanlength)
// count = frame->scanlength - frame->bytes_read;
// count = frame->scanlength - frame->bytes_read;
/* FIXME - count hardwired to be one frame... */
/* FIXME - count hardwired to be one frame... */
count
=
frame
->
width
*
frame
->
height
*
frame
->
depth
;
count
=
frame
->
width
*
frame
->
height
*
(
frame
->
depth
>>
3
)
;
if
(
copy_to_user
(
buf
,
frame
->
data
+
frame
->
bytes_read
,
count
))
PDEBUG
(
4
,
"Copy to user space: %ld bytes"
,
count
);
if
((
i
=
copy_to_user
(
buf
,
frame
->
data
+
frame
->
bytes_read
,
count
)))
{
PDEBUG
(
4
,
"Copy failed! %d bytes not copied"
,
i
);
return
-
EFAULT
;
return
-
EFAULT
;
}
frame
->
bytes_read
+=
count
;
frame
->
bytes_read
+=
count
;
PDEBUG
(
4
,
"
ov511_read:
{copy} count used=%ld, new bytes_read=%ld"
,
PDEBUG
(
4
,
"{copy} count used=%ld, new bytes_read=%ld"
,
count
,
frame
->
bytes_read
);
count
,
frame
->
bytes_read
);
if
(
frame
->
bytes_read
>=
frame
->
scanlength
)
{
/* All data has been read */
if
(
frame
->
bytes_read
>=
frame
->
scanlength
)
{
/* All data has been read */
...
@@ -1851,13 +2213,17 @@ static long ov511_read(struct video_device *dev, char *buf, unsigned long count,
...
@@ -1851,13 +2213,17 @@ static long ov511_read(struct video_device *dev, char *buf, unsigned long count,
/* Mark it as available to be used again. */
/* Mark it as available to be used again. */
ov511
->
frame
[
frmx
].
grabstate
=
FRAME_UNUSED
;
ov511
->
frame
[
frmx
].
grabstate
=
FRAME_UNUSED
;
if
(
ov511_new_frame
(
ov511
,
frmx
?
0
:
1
))
if
(
ov511_new_frame
(
ov511
,
frmx
?
0
:
1
))
err
(
"ov511_
read: ov511_
new_frame returned error"
);
err
(
"ov511_new_frame returned error"
);
}
}
PDEBUG
(
4
,
"read finished, returning %ld (sweet)"
,
count
);
return
count
;
return
count
;
}
}
static
int
ov511_mmap
(
struct
video_device
*
dev
,
const
char
*
adr
,
unsigned
long
size
)
static
int
ov511_mmap
(
struct
video_device
*
dev
,
const
char
*
adr
,
unsigned
long
size
)
{
{
struct
usb_ov511
*
ov511
=
(
struct
usb_ov511
*
)
dev
;
struct
usb_ov511
*
ov511
=
(
struct
usb_ov511
*
)
dev
;
unsigned
long
start
=
(
unsigned
long
)
adr
;
unsigned
long
start
=
(
unsigned
long
)
adr
;
...
@@ -1888,6 +2254,7 @@ static int ov511_mmap(struct video_device *dev, const char *adr, unsigned long s
...
@@ -1888,6 +2254,7 @@ static int ov511_mmap(struct video_device *dev, const char *adr, unsigned long s
return
0
;
return
0
;
}
}
static
struct
video_device
ov511_template
=
{
static
struct
video_device
ov511_template
=
{
name:
"OV511 USB Camera"
,
name:
"OV511 USB Camera"
,
type:
VID_TYPE_CAPTURE
,
type:
VID_TYPE_CAPTURE
,
...
@@ -1901,12 +2268,81 @@ static struct video_device ov511_template = {
...
@@ -1901,12 +2268,81 @@ static struct video_device ov511_template = {
initialize:
ov511_init_done
,
initialize:
ov511_init_done
,
};
};
static
int
ov7610_configure
(
struct
usb_ov511
*
ov511
)
/****************************************************************************
*
* OV511/OV7610 configuration
*
***************************************************************************/
static
int
ov76xx_configure
(
struct
usb_ov511
*
ov511
)
{
{
struct
usb_device
*
dev
=
ov511
->
dev
;
struct
usb_device
*
dev
=
ov511
->
dev
;
int
trie
s
;
int
i
,
succes
s
;
int
rc
;
int
rc
;
static
struct
ov511_regvals
aRegvalsNorm7610
[]
=
{{
OV511_I2C_BUS
,
0x10
,
0xff
},
{
OV511_I2C_BUS
,
0x16
,
0x06
},
{
OV511_I2C_BUS
,
0x28
,
0x24
},
{
OV511_I2C_BUS
,
0x2b
,
0xac
},
{
OV511_I2C_BUS
,
0x05
,
0x00
},
{
OV511_I2C_BUS
,
0x06
,
0x00
},
{
OV511_I2C_BUS
,
0x12
,
0x00
},
{
OV511_I2C_BUS
,
0x38
,
0x81
},
{
OV511_I2C_BUS
,
0x28
,
0x24
},
/* 0c */
{
OV511_I2C_BUS
,
0x05
,
0x00
},
{
OV511_I2C_BUS
,
0x0f
,
0x05
},
{
OV511_I2C_BUS
,
0x15
,
0x01
},
{
OV511_I2C_BUS
,
0x20
,
0x1c
},
{
OV511_I2C_BUS
,
0x23
,
0x2a
},
{
OV511_I2C_BUS
,
0x24
,
0x10
},
{
OV511_I2C_BUS
,
0x25
,
0x8a
},
{
OV511_I2C_BUS
,
0x27
,
0xc2
},
{
OV511_I2C_BUS
,
0x29
,
0x03
},
/* 91 */
{
OV511_I2C_BUS
,
0x2a
,
0x04
},
{
OV511_I2C_BUS
,
0x2c
,
0xfe
},
{
OV511_I2C_BUS
,
0x30
,
0x71
},
{
OV511_I2C_BUS
,
0x31
,
0x60
},
{
OV511_I2C_BUS
,
0x32
,
0x26
},
{
OV511_I2C_BUS
,
0x33
,
0x20
},
{
OV511_I2C_BUS
,
0x34
,
0x48
},
{
OV511_I2C_BUS
,
0x12
,
0x24
},
{
OV511_I2C_BUS
,
0x11
,
0x01
},
{
OV511_I2C_BUS
,
0x0c
,
0x24
},
{
OV511_I2C_BUS
,
0x0d
,
0x24
},
{
OV511_DONE_BUS
,
0x0
,
0x00
},
};
static
struct
ov511_regvals
aRegvalsNorm7620
[]
=
{{
OV511_I2C_BUS
,
0x10
,
0xff
},
{
OV511_I2C_BUS
,
0x16
,
0x06
},
{
OV511_I2C_BUS
,
0x28
,
0x24
},
{
OV511_I2C_BUS
,
0x2b
,
0xac
},
{
OV511_I2C_BUS
,
0x12
,
0x00
},
{
OV511_I2C_BUS
,
0x28
,
0x24
},
{
OV511_I2C_BUS
,
0x05
,
0x00
},
{
OV511_I2C_BUS
,
0x0f
,
0x05
},
{
OV511_I2C_BUS
,
0x15
,
0x01
},
{
OV511_I2C_BUS
,
0x23
,
0x00
},
{
OV511_I2C_BUS
,
0x24
,
0x10
},
{
OV511_I2C_BUS
,
0x25
,
0x8a
},
{
OV511_I2C_BUS
,
0x27
,
0xe2
},
{
OV511_I2C_BUS
,
0x29
,
0x03
},
{
OV511_I2C_BUS
,
0x2a
,
0x00
},
{
OV511_I2C_BUS
,
0x2c
,
0xfe
},
{
OV511_I2C_BUS
,
0x30
,
0x71
},
{
OV511_I2C_BUS
,
0x31
,
0x60
},
{
OV511_I2C_BUS
,
0x32
,
0x26
},
{
OV511_I2C_BUS
,
0x33
,
0x20
},
{
OV511_I2C_BUS
,
0x34
,
0x48
},
{
OV511_I2C_BUS
,
0x12
,
0x24
},
{
OV511_I2C_BUS
,
0x11
,
0x01
},
{
OV511_I2C_BUS
,
0x0c
,
0x24
},
{
OV511_I2C_BUS
,
0x0d
,
0x24
},
{
OV511_DONE_BUS
,
0x0
,
0x00
},
};
if
(
ov511_reg_write
(
dev
,
OV511_REG_I2C_SLAVE_ID_WRITE
,
if
(
ov511_reg_write
(
dev
,
OV511_REG_I2C_SLAVE_ID_WRITE
,
OV7610_I2C_WRITE_ID
)
<
0
)
OV7610_I2C_WRITE_ID
)
<
0
)
return
-
1
;
return
-
1
;
...
@@ -1918,64 +2354,90 @@ static int ov7610_configure(struct usb_ov511 *ov511)
...
@@ -1918,64 +2354,90 @@ static int ov7610_configure(struct usb_ov511 *ov511)
if
(
ov511_reset
(
dev
,
OV511_RESET_NOREGS
)
<
0
)
if
(
ov511_reset
(
dev
,
OV511_RESET_NOREGS
)
<
0
)
return
-
1
;
return
-
1
;
/* Reset the 76
10 and wait a bit for it to initialize
*/
/* Reset the 76
xx
*/
if
(
ov511_i2c_write
(
dev
,
0x12
,
0x80
)
<
0
)
return
-
1
;
if
(
ov511_i2c_write
(
dev
,
0x12
,
0x80
)
<
0
)
return
-
1
;
schedule_timeout
(
1
+
150
*
HZ
/
1000
);
/* Dummy read to sync I2C */
for
(
i
=
0
,
success
=
0
;
i
<
i2c_detect_tries
&&
!
success
;
i
++
)
{
if
(
ov511_i2c_read
(
dev
,
0x00
)
<
0
)
if
((
ov511_i2c_read
(
dev
,
OV7610_REG_ID_HIGH
)
==
0x7F
)
&&
return
-
1
;
(
ov511_i2c_read
(
dev
,
OV7610_REG_ID_LOW
)
==
0xA2
))
success
=
1
;
tries
=
5
;
while
((
tries
>
0
)
&&
/* Dummy read to sync I2C */
((
ov511_i2c_read
(
dev
,
OV7610_REG_ID_HIGH
)
!=
0x7F
)
||
if
(
ov511_i2c_read
(
dev
,
0x00
)
<
0
)
return
-
1
;
(
ov511_i2c_read
(
dev
,
OV7610_REG_ID_LOW
)
!=
0xA2
)))
{
/* Wait for it to initialize */
--
tries
;
schedule_timeout
(
1
+
150
*
HZ
/
1000
)
;
}
}
if
(
tries
==
1
)
{
if
(
success
)
{
err
(
"Failed to read sensor ID. You might not have an OV7610/20,"
);
PDEBUG
(
1
,
"I2C synced in %d attempt(s)"
,
i
);
}
else
{
err
(
"Failed to read sensor ID. You might not have an OV76xx,"
);
err
(
"or it may be not responding. Report this to"
);
err
(
"or it may be not responding. Report this to"
);
err
(
"mmcclelland@delphi.com"
);
err
(
"mmcclelland@delphi.com"
);
return
-
1
;
return
-
1
;
}
}
/* Detect sensor if user didn't use override param */
if
(
sensor
==
0
)
{
if
(
sensor
==
0
)
{
rc
=
ov511_i2c_read
(
dev
,
OV7610_REG_COM_I
);
rc
=
ov511_i2c_read
(
dev
,
OV7610_REG_COM_I
);
if
(
rc
<
0
)
{
if
(
rc
<
0
)
{
err
(
"Error detecting sensor type"
);
err
(
"Error detecting sensor type"
);
return
-
1
;
return
-
1
;
}
}
else
if
((
rc
&
3
)
==
3
)
{
else
if
((
rc
&
3
)
==
3
)
{
printk
(
"ov511: Sensor is an OV7610
\n
"
);
printk
(
"ov511: Sensor is an OV7610
\n
"
);
ov511
->
sensor
=
SEN_OV7610
;
ov511
->
sensor
=
SEN_OV7610
;
}
}
else
if
((
rc
&
3
)
==
1
)
{
else
if
((
rc
&
3
)
==
1
)
{
printk
(
"ov511: Sensor is an OV7620AE
\n
"
);
printk
(
"ov511: Sensor is an OV7620AE
\n
"
);
ov511
->
sensor
=
SEN_OV7620AE
;
ov511
->
sensor
=
SEN_OV7620AE
;
}
}
else
if
((
rc
&
3
)
==
0
)
{
else
if
((
rc
&
3
)
==
0
)
{
printk
(
"ov511: Sensor is an OV7620
\n
"
);
printk
(
"ov511: Sensor is an OV7620
\n
"
);
ov511
->
sensor
=
SEN_OV7620
;
ov511
->
sensor
=
SEN_OV7620
;
}
}
else
{
else
{
err
(
"Unknown image sensor version: %d"
,
rc
&
3
);
err
(
"Unknown image sensor version: %d"
,
rc
&
3
);
return
-
1
;
return
-
1
;
}
}
}
}
else
{
/* sensor != 0; user overrode detection */
else
{
/* sensor != 0; user overrode detection */
ov511
->
sensor
=
sensor
;
ov511
->
sensor
=
sensor
;
printk
(
"ov511: Sensor set to type %d
\n
"
,
ov511
->
sensor
);
printk
(
"ov511: Sensor set to type %d
\n
"
,
ov511
->
sensor
);
}
}
if
(
ov511
->
sensor
==
SEN_OV7620
)
{
if
(
ov511_write_regvals
(
dev
,
aRegvalsNorm7620
))
return
-
1
;
}
else
{
if
(
ov511_write_regvals
(
dev
,
aRegvalsNorm7610
))
return
-
1
;
}
if
(
aperture
<
0
)
{
/* go with the default */
if
(
ov511_i2c_write
(
dev
,
0x26
,
0xa2
)
<
0
)
return
-
1
;
}
else
if
(
aperture
<=
0xf
)
{
/* user overrode default */
if
(
ov511_i2c_write
(
dev
,
0x26
,
(
aperture
<<
4
)
+
2
)
<
0
)
return
-
1
;
}
else
{
err
(
"Invalid setting for aperture; legal value: 0 - 15"
);
return
-
1
;
}
if
(
autoadjust
)
{
if
(
ov511_i2c_write
(
dev
,
0x13
,
0x01
)
<
0
)
return
-
1
;
if
(
ov511_i2c_write
(
dev
,
0x2d
,
ov511
->
sensor
==
SEN_OV7620
?
0x91
:
0x93
)
<
0
)
return
-
1
;
}
else
{
if
(
ov511_i2c_write
(
dev
,
0x13
,
0x00
)
<
0
)
return
-
1
;
if
(
ov511_i2c_write
(
dev
,
0x2d
,
ov511
->
sensor
==
SEN_OV7620
?
0x81
:
0x83
)
<
0
)
return
-
1
;
ov511_i2c_write
(
dev
,
0x28
,
ov511_i2c_read
(
dev
,
0x28
)
|
8
);
}
return
0
;
return
0
;
}
}
static
int
ov511_configure
(
struct
usb_ov511
*
ov511
)
static
int
ov511_configure
(
struct
usb_ov511
*
ov511
)
{
{
struct
usb_device
*
dev
=
ov511
->
dev
;
struct
usb_device
*
dev
=
ov511
->
dev
;
int
rc
;
static
struct
ov511_regvals
aRegvalsInit
[]
=
static
struct
ov511_regvals
aRegvalsInit
[]
=
{{
OV511_REG_BUS
,
OV511_REG_SYSTEM_RESET
,
0x7f
},
{{
OV511_REG_BUS
,
OV511_REG_SYSTEM_RESET
,
0x7f
},
...
@@ -1988,7 +2450,7 @@ static int ov511_configure(struct usb_ov511 *ov511)
...
@@ -1988,7 +2450,7 @@ static int ov511_configure(struct usb_ov511 *ov511)
{
OV511_DONE_BUS
,
0x0
,
0x00
},
{
OV511_DONE_BUS
,
0x0
,
0x00
},
};
};
static
struct
ov511_regvals
aRegvalsNorm
7610
[]
=
static
struct
ov511_regvals
aRegvalsNorm
511
[]
=
{{
OV511_REG_BUS
,
0x20
,
0x01
},
{{
OV511_REG_BUS
,
0x20
,
0x01
},
{
OV511_REG_BUS
,
0x52
,
0x02
},
{
OV511_REG_BUS
,
0x52
,
0x02
},
{
OV511_REG_BUS
,
0x52
,
0x00
},
{
OV511_REG_BUS
,
0x52
,
0x00
},
...
@@ -2003,85 +2465,6 @@ static int ov511_configure(struct usb_ov511 *ov511)
...
@@ -2003,85 +2465,6 @@ static int ov511_configure(struct usb_ov511 *ov511)
{
OV511_REG_BUS
,
0x77
,
0x01
},
{
OV511_REG_BUS
,
0x77
,
0x01
},
{
OV511_REG_BUS
,
0x78
,
0x06
},
{
OV511_REG_BUS
,
0x78
,
0x06
},
{
OV511_REG_BUS
,
0x79
,
0x03
},
{
OV511_REG_BUS
,
0x79
,
0x03
},
{
OV511_I2C_BUS
,
0x10
,
0xff
},
{
OV511_I2C_BUS
,
0x16
,
0x06
},
{
OV511_I2C_BUS
,
0x28
,
0x24
},
{
OV511_I2C_BUS
,
0x2b
,
0xac
},
{
OV511_I2C_BUS
,
0x05
,
0x00
},
{
OV511_I2C_BUS
,
0x06
,
0x00
},
{
OV511_I2C_BUS
,
0x12
,
0x00
},
{
OV511_I2C_BUS
,
0x38
,
0x81
},
{
OV511_I2C_BUS
,
0x28
,
0x24
},
/* 0c */
{
OV511_I2C_BUS
,
0x05
,
0x00
},
{
OV511_I2C_BUS
,
0x0f
,
0x05
},
{
OV511_I2C_BUS
,
0x15
,
0x01
},
{
OV511_I2C_BUS
,
0x20
,
0x1c
},
{
OV511_I2C_BUS
,
0x23
,
0x2a
},
{
OV511_I2C_BUS
,
0x24
,
0x10
},
{
OV511_I2C_BUS
,
0x25
,
0x8a
},
{
OV511_I2C_BUS
,
0x26
,
0x90
},
{
OV511_I2C_BUS
,
0x27
,
0xc2
},
{
OV511_I2C_BUS
,
0x29
,
0x03
},
/* 91 */
{
OV511_I2C_BUS
,
0x2a
,
0x04
},
{
OV511_I2C_BUS
,
0x2c
,
0xfe
},
{
OV511_I2C_BUS
,
0x30
,
0x71
},
{
OV511_I2C_BUS
,
0x31
,
0x60
},
{
OV511_I2C_BUS
,
0x32
,
0x26
},
{
OV511_I2C_BUS
,
0x33
,
0x20
},
{
OV511_I2C_BUS
,
0x34
,
0x48
},
{
OV511_I2C_BUS
,
0x12
,
0x24
},
{
OV511_I2C_BUS
,
0x11
,
0x01
},
{
OV511_I2C_BUS
,
0x0c
,
0x24
},
{
OV511_I2C_BUS
,
0x0d
,
0x24
},
{
OV511_DONE_BUS
,
0x0
,
0x00
},
};
static
struct
ov511_regvals
aRegvalsNorm7620
[]
=
{{
OV511_REG_BUS
,
0x20
,
0x01
},
{
OV511_REG_BUS
,
0x52
,
0x02
},
{
OV511_REG_BUS
,
0x52
,
0x00
},
{
OV511_REG_BUS
,
0x31
,
0x1f
},
{
OV511_REG_BUS
,
0x70
,
0x3f
},
{
OV511_REG_BUS
,
0x71
,
0x3f
},
{
OV511_REG_BUS
,
0x72
,
0x01
},
{
OV511_REG_BUS
,
0x73
,
0x01
},
{
OV511_REG_BUS
,
0x74
,
0x01
},
{
OV511_REG_BUS
,
0x75
,
0x01
},
{
OV511_REG_BUS
,
0x76
,
0x01
},
{
OV511_REG_BUS
,
0x77
,
0x01
},
{
OV511_REG_BUS
,
0x78
,
0x06
},
{
OV511_REG_BUS
,
0x79
,
0x03
},
{
OV511_I2C_BUS
,
0x10
,
0xff
},
{
OV511_I2C_BUS
,
0x16
,
0x06
},
{
OV511_I2C_BUS
,
0x28
,
0x24
},
{
OV511_I2C_BUS
,
0x2b
,
0xac
},
{
OV511_I2C_BUS
,
0x12
,
0x00
},
{
OV511_I2C_BUS
,
0x28
,
0x24
},
{
OV511_I2C_BUS
,
0x05
,
0x00
},
{
OV511_I2C_BUS
,
0x0f
,
0x05
},
{
OV511_I2C_BUS
,
0x15
,
0x01
},
{
OV511_I2C_BUS
,
0x23
,
0x00
},
{
OV511_I2C_BUS
,
0x24
,
0x10
},
{
OV511_I2C_BUS
,
0x25
,
0x8a
},
{
OV511_I2C_BUS
,
0x26
,
0xa2
},
{
OV511_I2C_BUS
,
0x27
,
0xe2
},
{
OV511_I2C_BUS
,
0x29
,
0x03
},
{
OV511_I2C_BUS
,
0x2a
,
0x00
},
{
OV511_I2C_BUS
,
0x2c
,
0xfe
},
{
OV511_I2C_BUS
,
0x30
,
0x71
},
{
OV511_I2C_BUS
,
0x31
,
0x60
},
{
OV511_I2C_BUS
,
0x32
,
0x26
},
{
OV511_I2C_BUS
,
0x33
,
0x20
},
{
OV511_I2C_BUS
,
0x34
,
0x48
},
{
OV511_I2C_BUS
,
0x12
,
0x24
},
{
OV511_I2C_BUS
,
0x11
,
0x01
},
{
OV511_I2C_BUS
,
0x0c
,
0x24
},
{
OV511_I2C_BUS
,
0x0d
,
0x24
},
{
OV511_DONE_BUS
,
0x0
,
0x00
},
{
OV511_DONE_BUS
,
0x0
,
0x00
},
};
};
...
@@ -2096,54 +2479,36 @@ static int ov511_configure(struct usb_ov511 *ov511)
...
@@ -2096,54 +2479,36 @@ static int ov511_configure(struct usb_ov511 *ov511)
return
-
EBUSY
;
return
-
EBUSY
;
}
}
if
((
rc
=
ov511_write_regvals
(
dev
,
aRegvalsInit
)))
if
(
ov511_write_regvals
(
dev
,
aRegvalsInit
))
goto
error
;
return
rc
;
if
(
ov511_write_regvals
(
dev
,
aRegvalsNorm511
))
goto
error
;
if
(
ov7610_configure
(
ov511
)
<
0
)
{
err
(
"failed to configure OV7610"
);
goto
error
;
}
ov511_set_packet_size
(
ov511
,
0
);
ov511_set_packet_size
(
ov511
,
0
);
/* Disable compression */
if
(
ov511_reg_write
(
dev
,
OV511_OMNICE_ENABLE
,
0x00
)
<
0
)
goto
error
;
ov511
->
snap_enabled
=
snapshot
;
ov511
->
snap_enabled
=
snapshot
;
/* Set default sizes in case IOCTL (VIDIOCMCAPTURE) is not used
/* Set default sizes in case IOCTL (VIDIOCMCAPTURE) is not used
* (using read() instead). */
* (using read() instead). */
ov511
->
frame
[
0
].
width
=
DEFAULT_WIDTH
;
ov511
->
frame
[
0
].
width
=
DEFAULT_WIDTH
;
ov511
->
frame
[
0
].
height
=
DEFAULT_HEIGHT
;
ov511
->
frame
[
0
].
height
=
DEFAULT_HEIGHT
;
ov511
->
frame
[
0
].
depth
=
24
;
/**************/
ov511
->
frame
[
0
].
bytes_read
=
0
;
ov511
->
frame
[
0
].
bytes_read
=
0
;
ov511
->
frame
[
0
].
segment
=
0
;
ov511
->
frame
[
1
].
width
=
DEFAULT_WIDTH
;
ov511
->
frame
[
1
].
width
=
DEFAULT_WIDTH
;
ov511
->
frame
[
1
].
height
=
DEFAULT_HEIGHT
;
ov511
->
frame
[
1
].
height
=
DEFAULT_HEIGHT
;
ov511
->
frame
[
1
].
depth
=
24
;
ov511
->
frame
[
1
].
bytes_read
=
0
;
ov511
->
frame
[
1
].
bytes_read
=
0
;
ov511
->
frame
[
1
].
segment
=
0
;
/* Initialize to DEFAULT_WIDTH, DEFAULT_HEIGHT, YUV4:2:0 */
/* Initialize to DEFAULT_WIDTH, DEFAULT_HEIGHT, YUV4:2:0 */
if
(
ov511
->
sensor
==
SEN_OV7620
)
{
if
(
ov76xx_configure
(
ov511
)
<
0
)
{
if
(
ov511_write_regvals
(
dev
,
aRegvalsNorm7620
))
goto
error
;
err
(
"failed to configure OV76xx"
);
}
goto
error
;
else
{
if
(
ov511_write_regvals
(
dev
,
aRegvalsNorm7610
))
goto
error
;
}
}
if
(
ov511_mode_init_regs
(
ov511
,
DEFAULT_WIDTH
,
DEFAULT_HEIGHT
,
if
(
ov511_mode_init_regs
(
ov511
,
DEFAULT_WIDTH
,
DEFAULT_HEIGHT
,
VIDEO_PALETTE_RGB24
,
0
)
<
0
)
goto
error
;
VIDEO_PALETTE_RGB24
,
0
)
<
0
)
goto
error
;
if
(
autoadjust
)
{
if
(
ov511_i2c_write
(
dev
,
0x13
,
0x01
)
<
0
)
goto
error
;
if
(
ov511_i2c_write
(
dev
,
0x2d
,
ov511
->
sensor
==
SEN_OV7620
?
0x91
:
0x93
)
<
0
)
goto
error
;
}
else
{
if
(
ov511_i2c_write
(
dev
,
0x13
,
0x00
)
<
0
)
goto
error
;
if
(
ov511_i2c_write
(
dev
,
0x2d
,
ov511
->
sensor
==
SEN_OV7620
?
0x81
:
0x83
)
<
0
)
goto
error
;
ov511_i2c_write
(
dev
,
0x28
,
ov511_i2c_read
(
dev
,
0x28
)
|
8
);
}
return
0
;
return
0
;
...
@@ -2158,11 +2523,18 @@ static int ov511_configure(struct usb_ov511 *ov511)
...
@@ -2158,11 +2523,18 @@ static int ov511_configure(struct usb_ov511 *ov511)
return
-
EBUSY
;
return
-
EBUSY
;
}
}
/****************************************************************************
*
* USB routines
*
***************************************************************************/
static
void
*
ov511_probe
(
struct
usb_device
*
dev
,
unsigned
int
ifnum
)
static
void
*
ov511_probe
(
struct
usb_device
*
dev
,
unsigned
int
ifnum
)
{
{
struct
usb_interface_descriptor
*
interface
;
struct
usb_interface_descriptor
*
interface
;
struct
usb_ov511
*
ov511
;
struct
usb_ov511
*
ov511
;
int
rc
;
int
i
;
PDEBUG
(
1
,
"probing for device..."
);
PDEBUG
(
1
,
"probing for device..."
);
...
@@ -2191,79 +2563,58 @@ static void* ov511_probe(struct usb_device *dev, unsigned int ifnum)
...
@@ -2191,79 +2563,58 @@ static void* ov511_probe(struct usb_device *dev, unsigned int ifnum)
}
}
memset
(
ov511
,
0
,
sizeof
(
*
ov511
));
memset
(
ov511
,
0
,
sizeof
(
*
ov511
));
ov511
->
dev
=
dev
;
ov511
->
dev
=
dev
;
ov511
->
iface
=
interface
->
bInterfaceNumber
;
ov511
->
iface
=
interface
->
bInterfaceNumber
;
if
(
dev
->
descriptor
.
idProduct
==
0x0511
)
{
switch
(
dev
->
descriptor
.
idProduct
)
{
case
0x0511
:
info
(
"USB OV511 camera found"
);
info
(
"USB OV511 camera found"
);
ov511
->
bridge
=
BRG_OV511
;
ov511
->
bridge
=
BRG_OV511
;
}
break
;
else
if
(
dev
->
descriptor
.
idProduct
==
0xA511
)
{
case
0xA511
:
info
(
"USB OV511+ camera found"
);
info
(
"USB OV511+ camera found"
);
ov511
->
bridge
=
BRG_OV511PLUS
;
ov511
->
bridge
=
BRG_OV511PLUS
;
break
;
}
}
rc
=
ov511_reg_read
(
dev
,
OV511_REG_SYSTEM_CUSTOM_ID
);
ov511
->
customid
=
ov511_reg_read
(
dev
,
OV511_REG_SYSTEM_CUSTOM_ID
);
if
(
rc
<
0
)
{
if
(
ov511
->
customid
<
0
)
{
err
(
"Unable to read camera bridge registers"
);
err
(
"Unable to read camera bridge registers"
);
goto
error
;
goto
error
;
}
}
switch
(
ov511
->
customid
=
rc
)
{
ov511
->
desc
=
-
1
;
case
0
:
/* This also means that no custom ID was set */
PDEBUG
(
4
,
"CustomID = %d"
,
ov511
->
customid
);
printk
(
"ov511: Camera is a generic model (no ID)
\n
"
);
for
(
i
=
0
;
clist
[
i
].
id
>=
0
;
i
++
)
{
break
;
if
(
ov511
->
customid
==
clist
[
i
].
id
)
{
case
3
:
printk
(
"Camera: %s
\n
"
,
clist
[
i
].
description
);
printk
(
"ov511: Camera is a D-Link DSB-C300
\n
"
);
ov511
->
desc
=
i
;
break
;
break
;
case
4
:
}
printk
(
"ov511: Camera is a generic OV511/OV7610
\n
"
);
}
break
;
case
5
:
/* Lifeview USB Life TV not supported */
printk
(
"ov511: Camera is a Puretek PT-6007
\n
"
);
if
(
clist
[
i
].
id
==
38
)
{
break
;
err
(
"This device is not supported yet."
);
case
21
:
return
NULL
;
printk
(
"ov511: Camera is a Creative Labs WebCam 3
\n
"
);
}
break
;
case
36
:
if
(
clist
[
i
].
id
==
-
1
)
{
printk
(
"ov511: Camera is a Koala-Cam
\n
"
);
err
(
"Camera type (%d) not recognized"
,
ov511
->
customid
);
break
;
case
38
:
printk
(
"ov511: Camera is a Lifeview USB Life TV
\n
"
);
printk
(
"ov511: This device is not supported, exiting...
\n
"
);
goto
error
;
break
;
case
100
:
printk
(
"ov511: Camera is a Lifeview RoboCam
\n
"
);
break
;
case
102
:
printk
(
"ov511: Camera is a AverMedia InterCam Elite
\n
"
);
break
;
case
112
:
/* The OmniVision OV7110 evaluation kit uses this too */
printk
(
"ov511: Camera is a MediaForte MV300
\n
"
);
break
;
default:
err
(
"Specific camera type (%d) not recognized"
,
rc
);
err
(
"Please contact mmcclelland@delphi.com to request"
);
err
(
"Please contact mmcclelland@delphi.com to request"
);
err
(
"support for your camera."
);
err
(
"support for your camera."
);
}
}
// if (ov511->bridge == BRG_OV511PLUS) {
// err("Sorry, the OV511+ chip is not supported yet");
// goto error;
// }
if
(
!
ov511_configure
(
ov511
))
{
if
(
!
ov511_configure
(
ov511
))
{
ov511
->
user
=
0
;
ov511
->
user
=
0
;
init_MUTEX
(
&
ov511
->
lock
);
/* to 1 == available */
init_MUTEX
(
&
ov511
->
lock
);
/* to 1 == available */
return
ov511
;
return
ov511
;
}
}
else
{
else
{
err
(
"Failed to configure camera"
);
err
(
"Failed to configure camera"
);
goto
error
;
goto
error
;
}
}
return
ov511
;
return
ov511
;
error:
error:
...
@@ -2272,12 +2623,12 @@ static void* ov511_probe(struct usb_device *dev, unsigned int ifnum)
...
@@ -2272,12 +2623,12 @@ static void* ov511_probe(struct usb_device *dev, unsigned int ifnum)
ov511
=
NULL
;
ov511
=
NULL
;
}
}
return
NULL
;
return
NULL
;
}
}
static
void
ov511_disconnect
(
struct
usb_device
*
dev
,
void
*
ptr
)
static
void
ov511_disconnect
(
struct
usb_device
*
dev
,
void
*
ptr
)
{
{
struct
usb_ov511
*
ov511
=
(
struct
usb_ov511
*
)
ptr
;
struct
usb_ov511
*
ov511
=
(
struct
usb_ov511
*
)
ptr
;
// video_unregister_device(&ov511->vdev);
// video_unregister_device(&ov511->vdev);
...
@@ -2318,6 +2669,11 @@ static void ov511_disconnect(struct usb_device *dev, void *ptr)
...
@@ -2318,6 +2669,11 @@ static void ov511_disconnect(struct usb_device *dev, void *ptr)
ov511
->
sbuf
[
0
].
urb
=
NULL
;
ov511
->
sbuf
[
0
].
urb
=
NULL
;
}
}
#ifdef CONFIG_PROC_FS
PDEBUG
(
3
,
"destroying /proc/ov511/video%d"
,
ov511
->
vdev
.
minor
);
destroy_proc_ov511_cam
(
ov511
);
#endif
/* Free the memory */
/* Free the memory */
if
(
!
ov511
->
user
)
{
if
(
!
ov511
->
user
)
{
kfree
(
ov511
);
kfree
(
ov511
);
...
@@ -2332,18 +2688,35 @@ static struct usb_driver ov511_driver = {
...
@@ -2332,18 +2688,35 @@ static struct usb_driver ov511_driver = {
{
NULL
,
NULL
}
{
NULL
,
NULL
}
};
};
/****************************************************************************
*
* Module routines
*
***************************************************************************/
static
int
__init
usb_ov511_init
(
void
)
static
int
__init
usb_ov511_init
(
void
)
{
{
#ifdef CONFIG_PROC_FS
PDEBUG
(
3
,
"creating /proc/ov511"
);
proc_ov511_create
();
#endif
if
(
usb_register
(
&
ov511_driver
)
<
0
)
if
(
usb_register
(
&
ov511_driver
)
<
0
)
return
-
1
;
return
-
1
;
info
(
"ov511 driver
registered"
);
info
(
"ov511 driver
version %s registered"
,
version
);
return
0
;
return
0
;
}
}
static
void
__exit
usb_ov511_exit
(
void
)
static
void
__exit
usb_ov511_exit
(
void
)
{
{
#ifdef CONFIG_PROC_FS
PDEBUG
(
3
,
"destroying /proc/ov511"
);
proc_ov511_destroy
();
#endif
usb_deregister
(
&
ov511_driver
);
usb_deregister
(
&
ov511_driver
);
info
(
"ov511 driver deregistered"
);
info
(
"ov511 driver deregistered"
);
}
}
...
...
drivers/usb/ov511.h
View file @
5cb39380
#ifndef __LINUX_OV511_H
#ifndef __LINUX_OV511_H
#define __LINUX_OV511_H
#define __LINUX_OV511_H
#include <asm/uaccess.h>
#include <linux/videodev.h>
#include <linux/smp_lock.h>
#define OV511_DEBUG
/* Turn on debug messages */
#define OV511_DEBUG
/* Turn on debug messages */
#ifdef OV511_DEBUG
#ifdef OV511_DEBUG
# define PDEBUG(level, fmt, args...) \
# define PDEBUG(level, fmt, args...) \
if (debug >= level) printk("ov511:
" fmt "\n"
, ## args)
if (debug >= level) printk("ov511:
[" __PRETTY_FUNCTION__ ":%d] " fmt "\n", __LINE__
, ## args)
#else
#else
# define PDEBUG(level, fmt, args...) do {} while(0)
# define PDEBUG(level, fmt, args...) do {} while(0)
#endif
#endif
/* Camera interface register numbers */
/* Camera interface register numbers */
#define OV511_REG_CAMERA_DELAY_MODE
0x10
#define OV511_REG_CAMERA_DELAY_MODE 0x10
#define OV511_REG_CAMERA_EDGE_MODE
0x11
#define OV511_REG_CAMERA_EDGE_MODE 0x11
#define OV511_REG_CAMERA_CLAMPED_PIXEL_NUM 0x12
#define OV511_REG_CAMERA_CLAMPED_PIXEL_NUM 0x12
#define OV511_REG_CAMERA_CLAMPED_LINE_NUM 0x13
#define OV511_REG_CAMERA_CLAMPED_LINE_NUM 0x13
#define OV511_REG_CAMERA_PIXEL_DIVISOR 0x14
#define OV511_REG_CAMERA_PIXEL_DIVISOR 0x14
#define OV511_REG_CAMERA_LINE_DIVISOR 0x15
#define OV511_REG_CAMERA_LINE_DIVISOR 0x15
#define OV511_REG_CAMERA_DATA_INPUT_SELECT 0x16
#define OV511_REG_CAMERA_DATA_INPUT_SELECT 0x16
#define OV511_REG_CAMERA_RESERVED_LINE_MODE 0x17
#define OV511_REG_CAMERA_RESERVED_LINE_MODE 0x17
#define OV511_REG_CAMERA_BITMASK
0x18
#define OV511_REG_CAMERA_BITMASK 0x18
/* Snapshot mode camera interface register numbers */
/* Snapshot mode camera interface register numbers */
#define OV511_REG_SNAP_CAPTURED_FRAME 0x19
#define OV511_REG_SNAP_CAPTURED_FRAME 0x19
#define OV511_REG_SNAP_CLAMPED_PIXEL_NUM 0x1A
#define OV511_REG_SNAP_CLAMPED_PIXEL_NUM 0x1A
#define OV511_REG_SNAP_CLAMPED_LINE_NUM 0x1B
#define OV511_REG_SNAP_CLAMPED_LINE_NUM 0x1B
#define OV511_REG_SNAP_PIXEL_DIVISOR 0x1C
#define OV511_REG_SNAP_PIXEL_DIVISOR 0x1C
#define OV511_REG_SNAP_LINE_DIVISOR
0x1D
#define OV511_REG_SNAP_LINE_DIVISOR 0x1D
#define OV511_REG_SNAP_DATA_INPUT_SELECT 0x1E
#define OV511_REG_SNAP_DATA_INPUT_SELECT 0x1E
#define OV511_REG_SNAP_BITMASK
0x1F
#define OV511_REG_SNAP_BITMASK 0x1F
/* DRAM register numbers */
/* DRAM register numbers */
#define OV511_REG_DRAM_ENABLE_FLOW_CONTROL 0x20
#define OV511_REG_DRAM_ENABLE_FLOW_CONTROL 0x20
...
@@ -37,21 +41,21 @@ if (debug >= level) printk("ov511: " fmt "\n" , ## args)
...
@@ -37,21 +41,21 @@ if (debug >= level) printk("ov511: " fmt "\n" , ## args)
#define OV511_REG_DRAM_REFRESH_COUNTER 0x23
#define OV511_REG_DRAM_REFRESH_COUNTER 0x23
/* ISO FIFO register numbers */
/* ISO FIFO register numbers */
#define OV511_REG_FIFO_PACKET_SIZE
0x30
#define OV511_REG_FIFO_PACKET_SIZE 0x30
#define OV511_REG_FIFO_BITMASK
0x31
#define OV511_REG_FIFO_BITMASK 0x31
/* PIO register numbers */
/* PIO register numbers */
#define OV511_REG_PIO_BITMASK
0x38
#define OV511_REG_PIO_BITMASK 0x38
#define OV511_REG_PIO_DATA_PORT
0x39
#define OV511_REG_PIO_DATA_PORT 0x39
#define OV511_REG_PIO_BIST
0x3E
#define OV511_REG_PIO_BIST 0x3E
/* I2C register numbers */
/* I2C register numbers */
#define OV511_REG_I2C_CONTROL
0x40
#define OV511_REG_I2C_CONTROL 0x40
#define OV511_REG_I2C_SLAVE_ID_WRITE 0x41
#define OV511_REG_I2C_SLAVE_ID_WRITE 0x41
#define OV511_REG_I2C_SUB_ADDRESS_3_BYTE 0x42
#define OV511_REG_I2C_SUB_ADDRESS_3_BYTE 0x42
#define OV511_REG_I2C_SUB_ADDRESS_2_BYTE 0x43
#define OV511_REG_I2C_SUB_ADDRESS_2_BYTE 0x43
#define OV511_REG_I2C_SLAVE_ID_READ
0x44
#define OV511_REG_I2C_SLAVE_ID_READ 0x44
#define OV511_REG_I2C_DATA_PORT
0x45
#define OV511_REG_I2C_DATA_PORT 0x45
#define OV511_REG_I2C_CLOCK_PRESCALER 0x46
#define OV511_REG_I2C_CLOCK_PRESCALER 0x46
#define OV511_REG_I2C_TIME_OUT_COUNTER 0x47
#define OV511_REG_I2C_TIME_OUT_COUNTER 0x47
...
@@ -60,39 +64,39 @@ if (debug >= level) printk("ov511: " fmt "\n" , ## args)
...
@@ -60,39 +64,39 @@ if (debug >= level) printk("ov511: " fmt "\n" , ## args)
#define OV511_REG_I2C_SNAP_DATA_PORT 0x49
#define OV511_REG_I2C_SNAP_DATA_PORT 0x49
/* System control register numbers */
/* System control register numbers */
#define OV511_REG_SYSTEM_RESET
0x50
#define OV511_REG_SYSTEM_RESET 0x50
#define OV511_RESET_UDC
0x01
#define OV511_RESET_UDC 0x01
#define OV511_RESET_I2C
0x02
#define OV511_RESET_I2C 0x02
#define OV511_RESET_FIFO
0x04
#define OV511_RESET_FIFO 0x04
#define OV511_RESET_OMNICE
0x08
#define OV511_RESET_OMNICE 0x08
#define OV511_RESET_DRAM_INTF 0x10
#define OV511_RESET_DRAM_INTF 0x10
#define OV511_RESET_CAMERA_INTF 0x20
#define OV511_RESET_CAMERA_INTF 0x20
#define
OV511_RESET_OV511
0x40
#define
OV511_RESET_OV511
0x40
#define
OV511_RESET_NOREGS 0x3F
/* All but OV511 & regs */
#define
OV511_RESET_NOREGS 0x3F
/* All but OV511 & regs */
#define OV511_RESET_ALL
0x7F
#define OV511_RESET_ALL 0x7F
#define OV511_REG_SYSTEM_CLOCK_DIVISOR 0x51
#define OV511_REG_SYSTEM_CLOCK_DIVISOR 0x51
#define OV511_REG_SYSTEM_SNAPSHOT
0x52
#define OV511_REG_SYSTEM_SNAPSHOT 0x52
#define OV511_REG_SYSTEM_INIT 0x53
#define OV511_REG_SYSTEM_INIT 0x53
#define OV511_REG_SYSTEM_PWR_CLK
0x54
/* OV511+ only */
#define OV511_REG_SYSTEM_PWR_CLK
0x54
/* OV511+ only */
#define OV511_REG_SYSTEM_LED_CTL
0x55
/* OV511+ only */
#define OV511_REG_SYSTEM_LED_CTL
0x55
/* OV511+ only */
#define OV511_REG_SYSTEM_USER_DEFINED 0x5E
#define OV511_REG_SYSTEM_USER_DEFINED 0x5E
#define OV511_REG_SYSTEM_CUSTOM_ID
0x5F
#define OV511_REG_SYSTEM_CUSTOM_ID 0x5F
/* OmniCE register numbers */
/* OmniCE register numbers */
#define OV511_OMNICE_PREDICTION_HORIZ_Y 0x70
#define OV511_OMNICE_PREDICTION_HORIZ_Y
0x70
#define OV511_OMNICE_PREDICTION_HORIZ_UV 0x71
#define OV511_OMNICE_PREDICTION_HORIZ_UV 0x71
#define OV511_OMNICE_PREDICTION_VERT_Y 0x72
#define OV511_OMNICE_PREDICTION_VERT_Y 0x72
#define OV511_OMNICE_PREDICTION_VERT_UV 0x73
#define OV511_OMNICE_PREDICTION_VERT_UV
0x73
#define OV511_OMNICE_QUANTIZATION_HORIZ_Y 0x74
#define OV511_OMNICE_QUANTIZATION_HORIZ_Y 0x74
#define OV511_OMNICE_QUANTIZATION_HORIZ_UV 0x75
#define OV511_OMNICE_QUANTIZATION_HORIZ_UV 0x75
#define OV511_OMNICE_QUANTIZATION_VERT_Y 0x76
#define OV511_OMNICE_QUANTIZATION_VERT_Y 0x76
#define OV511_OMNICE_QUANTIZATION_VERT_UV 0x77
#define OV511_OMNICE_QUANTIZATION_VERT_UV 0x77
#define OV511_OMNICE_ENABLE
0x78
#define OV511_OMNICE_ENABLE 0x78
#define OV511_OMNICE_LUT_ENABLE
0x79
#define OV511_OMNICE_LUT_ENABLE 0x79
#define OV511_OMNICE_Y_LUT_BEGIN
0x80
#define OV511_OMNICE_Y_LUT_BEGIN 0x80
#define OV511_OMNICE_Y_LUT_END
0x9F
#define OV511_OMNICE_Y_LUT_END 0x9F
#define OV511_OMNICE_UV_LUT_BEGIN
0xA0
#define OV511_OMNICE_UV_LUT_BEGIN 0xA0
#define OV511_OMNICE_UV_LUT_END
0xBF
#define OV511_OMNICE_UV_LUT_END 0xBF
/* Alternate numbers for various max packet sizes (OV511 only) */
/* Alternate numbers for various max packet sizes (OV511 only) */
#define OV511_ALT_SIZE_992 0
#define OV511_ALT_SIZE_992 0
...
@@ -114,7 +118,7 @@ if (debug >= level) printk("ov511: " fmt "\n" , ## args)
...
@@ -114,7 +118,7 @@ if (debug >= level) printk("ov511: " fmt "\n" , ## args)
#define OV511PLUS_ALT_SIZE_769 6
#define OV511PLUS_ALT_SIZE_769 6
#define OV511PLUS_ALT_SIZE_961 7
#define OV511PLUS_ALT_SIZE_961 7
/*
ov
7610 registers */
/*
OV
7610 registers */
#define OV7610_REG_GAIN 0x00
#define OV7610_REG_GAIN 0x00
#define OV7610_REG_BLUE 0x01
#define OV7610_REG_BLUE 0x01
#define OV7610_REG_RED 0x02
#define OV7610_REG_RED 0x02
...
@@ -163,12 +167,12 @@ if (debug >= level) printk("ov511: " fmt "\n" , ## args)
...
@@ -163,12 +167,12 @@ if (debug >= level) printk("ov511: " fmt "\n" , ## args)
#define SCRATCH_BUF_SIZE 384
#define SCRATCH_BUF_SIZE 384
#define FRAMES_PER_DESC 10
/* FIXME - What should this be? */
#define FRAMES_PER_DESC 10
/* FIXME - What should this be? */
#define FRAME_SIZE_PER_DESC 993
/* FIXME - Deprecated */
#define FRAME_SIZE_PER_DESC 993
/* FIXME - Deprecated */
#define MAX_FRAME_SIZE_PER_DESC 993
/* For statically allocated stuff */
#define MAX_FRAME_SIZE_PER_DESC 993
/* For statically allocated stuff */
// FIXME - should this be 0x81 (endpoint address) or 0x01 (endpoint number)?
// FIXME - should this be 0x81 (endpoint address) or 0x01 (endpoint number)?
#define OV511_ENDPOINT_ADDRESS 0x81
/* Address of isoc endpoint */
#define OV511_ENDPOINT_ADDRESS 0x81
/* Address of isoc endpoint */
// CAMERA SPECIFIC
// CAMERA SPECIFIC
// FIXME - these can vary between specific models
// FIXME - these can vary between specific models
...
@@ -213,7 +217,7 @@ enum {
...
@@ -213,7 +217,7 @@ enum {
FRAME_UNUSED
,
/* Unused (no MCAPTURE) */
FRAME_UNUSED
,
/* Unused (no MCAPTURE) */
FRAME_READY
,
/* Ready to start grabbing */
FRAME_READY
,
/* Ready to start grabbing */
FRAME_GRABBING
,
/* In the process of being grabbed into */
FRAME_GRABBING
,
/* In the process of being grabbed into */
FRAME_DONE
,
/* Finished grabbing, but not been synced yet */
FRAME_DONE
,
/* Finished grabbing, but not been synced yet */
FRAME_ERROR
,
/* Something bad happened while processing */
FRAME_ERROR
,
/* Something bad happened while processing */
};
};
...
@@ -238,7 +242,7 @@ struct ov511_frame {
...
@@ -238,7 +242,7 @@ struct ov511_frame {
int
hdrheight
;
/* Height */
int
hdrheight
;
/* Height */
int
sub_flag
;
/* Sub-capture mode for this frame? */
int
sub_flag
;
/* Sub-capture mode for this frame? */
int
format
;
/* Format for this frame */
int
format
;
/* Format for this frame */
int
segsize
;
/* How big is each segment from the camera? */
int
segsize
;
/* How big is each segment from the camera? */
volatile
int
grabstate
;
/* State of grabbing */
volatile
int
grabstate
;
/* State of grabbing */
...
@@ -253,7 +257,7 @@ struct ov511_frame {
...
@@ -253,7 +257,7 @@ struct ov511_frame {
wait_queue_head_t
wq
;
/* Processes waiting */
wait_queue_head_t
wq
;
/* Processes waiting */
int
snapshot
;
/* True if frame was a snapshot */
int
snapshot
;
/* True if frame was a snapshot */
};
};
#define OV511_NUMFRAMES 2
#define OV511_NUMFRAMES 2
...
@@ -261,23 +265,28 @@ struct ov511_frame {
...
@@ -261,23 +265,28 @@ struct ov511_frame {
struct
usb_ov511
{
struct
usb_ov511
{
struct
video_device
vdev
;
struct
video_device
vdev
;
/* Device structure */
/* Device structure */
struct
usb_device
*
dev
;
struct
usb_device
*
dev
;
#if 0
unsigned char customid; /* Type of camera */
unsigned char customid; /* Type of camera */
#else
int
customid
;
int
desc
;
#endif
unsigned
char
iface
;
unsigned
char
iface
;
struct
semaphore
lock
;
struct
semaphore
lock
;
int
user
;
/* user count for exclusive use */
int
user
;
/* user count for exclusive use */
int
streaming
;
/* Are we streaming Isochronous? */
int
streaming
;
/* Are we streaming Isochronous? */
int
grabbing
;
/* Are we grabbing? */
int
grabbing
;
/* Are we grabbing? */
int
compress
;
/* Should the next frame be compressed? */
int
compress
;
/* Should the next frame be compressed? */
char
*
fbuf
;
/* Videodev buffer area */
char
*
fbuf
;
/* Videodev buffer area */
int
sub_flag
;
/* Pix Array subcapture on flag */
int
sub_flag
;
/* Pix Array subcapture on flag */
int
subx
;
/* Pix Array subcapture x offset */
int
subx
;
/* Pix Array subcapture x offset */
...
@@ -297,12 +306,22 @@ struct usb_ov511 {
...
@@ -297,12 +306,22 @@ struct usb_ov511 {
wait_queue_head_t
wq
;
/* Processes waiting */
wait_queue_head_t
wq
;
/* Processes waiting */
int
snap_enabled
;
/* Snapshot mode enabled */
int
snap_enabled
;
/* Snapshot mode enabled */
int
bridge
;
/* Type of bridge (OV511 or OV511+) */
int
bridge
;
/* Type of bridge (OV511 or OV511+) */
int
sensor
;
/* Type of image sensor chip */
int
sensor
;
/* Type of image sensor chip */
int
packet_size
;
/* Frame size per isoc desc */
/* proc interface */
struct
semaphore
param_lock
;
/* params lock for this camera */
struct
proc_dir_entry
*
proc_entry
;
/* /proc/ov511/videoX */
};
int
packet_size
;
/* Frame size per isoc desc */
struct
cam_list
{
int
id
;
char
*
description
;
};
};
#endif
#endif
...
...
drivers/video/clgenfb.c
View file @
5cb39380
...
@@ -31,9 +31,10 @@
...
@@ -31,9 +31,10 @@
*
*
*/
*/
#define CLGEN_VERSION "1.9.
5
"
#define CLGEN_VERSION "1.9.
6
"
#include <linux/config.h>
#include <linux/config.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/errno.h>
...
@@ -2652,14 +2653,14 @@ static int __init clgen_pci_setup (struct clgenfb_info *info,
...
@@ -2652,14 +2653,14 @@ static int __init clgen_pci_setup (struct clgenfb_info *info,
if
(
!
request_mem_region
(
board_addr
,
board_size
,
"clgenfb"
))
{
if
(
!
request_mem_region
(
board_addr
,
board_size
,
"clgenfb"
))
{
pci_write_config_word
(
pdev
,
PCI_COMMAND
,
tmp16
);
pci_write_config_word
(
pdev
,
PCI_COMMAND
,
tmp16
);
printk
(
KERN_ERR
"clgen: cannot reserve region 0x%l
u
, abort
\n
"
,
printk
(
KERN_ERR
"clgen: cannot reserve region 0x%l
x
, abort
\n
"
,
board_addr
);
board_addr
);
return
-
1
;
return
-
1
;
}
}
#if 0 /* if the system didn't claim this region, we would... */
#if 0 /* if the system didn't claim this region, we would... */
if (!request_mem_region(0xA0000, 65535, "clgenfb")) {
if (!request_mem_region(0xA0000, 65535, "clgenfb")) {
pci_write_config_word (pdev, PCI_COMMAND, tmp16);
pci_write_config_word (pdev, PCI_COMMAND, tmp16);
printk(KERN_ERR "clgen: cannot reserve region 0x%l
u
, abort\n",
printk(KERN_ERR "clgen: cannot reserve region 0x%l
x
, abort\n",
0xA0000L);
0xA0000L);
release_mem_region(board_addr, board_size);
release_mem_region(board_addr, board_size);
return -1;
return -1;
...
@@ -2760,7 +2761,7 @@ static int __init clgen_zorro_setup (struct clgenfb_info *info,
...
@@ -2760,7 +2761,7 @@ static int __init clgen_zorro_setup (struct clgenfb_info *info,
info
->
board_size
=
board_size
=
z
->
resource
.
end
-
z
->
resource
.
start
+
1
;
info
->
board_size
=
board_size
=
z
->
resource
.
end
-
z
->
resource
.
start
+
1
;
if
(
!
request_mem_region
(
board_addr
,
board_size
,
"clgenfb"
))
{
if
(
!
request_mem_region
(
board_addr
,
board_size
,
"clgenfb"
))
{
printk
(
KERN_ERR
"clgen: cannot reserve region 0x%l
u
, abort
\n
"
,
printk
(
KERN_ERR
"clgen: cannot reserve region 0x%l
x
, abort
\n
"
,
board_addr
);
board_addr
);
return
-
1
;
return
-
1
;
}
}
...
...
drivers/video/vesafb.c
View file @
5cb39380
...
@@ -543,12 +543,19 @@ int __init vesafb_init(void)
...
@@ -543,12 +543,19 @@ int __init vesafb_init(void)
if
(
!
request_mem_region
(
video_base
,
video_size
,
"vesafb"
))
{
if
(
!
request_mem_region
(
video_base
,
video_size
,
"vesafb"
))
{
printk
(
KERN_ERR
printk
(
KERN_ERR
"vesafb: abort, cannot reserve video memory at 0x%l
u
\n
"
,
"vesafb: abort, cannot reserve video memory at 0x%l
x
\n
"
,
video_base
);
video_base
);
return
-
1
;
return
-
EBUSY
;
}
}
video_vbase
=
ioremap
(
video_base
,
video_size
);
video_vbase
=
ioremap
(
video_base
,
video_size
);
if
(
!
video_vbase
)
{
release_mem_region
(
video_base
,
video_size
);
printk
(
KERN_ERR
"vesafb: abort, cannot ioremap video memory 0x%lx @ 0x%lx
\n
"
,
video_size
,
video_base
);
return
-
EIO
;
}
printk
(
KERN_INFO
"vesafb: framebuffer at 0x%lx, mapped to 0x%p, size %dk
\n
"
,
printk
(
KERN_INFO
"vesafb: framebuffer at 0x%lx, mapped to 0x%p, size %dk
\n
"
,
video_base
,
video_vbase
,
video_size
/
1024
);
video_base
,
video_vbase
,
video_size
/
1024
);
...
...
fs/buffer.c
View file @
5cb39380
...
@@ -2129,9 +2129,7 @@ static void sync_page_buffers(struct buffer_head *bh)
...
@@ -2129,9 +2129,7 @@ static void sync_page_buffers(struct buffer_head *bh)
do
{
do
{
struct
buffer_head
*
p
=
tmp
;
struct
buffer_head
*
p
=
tmp
;
tmp
=
tmp
->
b_this_page
;
tmp
=
tmp
->
b_this_page
;
if
(
buffer_locked
(
p
))
if
(
buffer_dirty
(
p
)
&&
!
buffer_locked
(
p
))
__wait_on_buffer
(
p
);
else
if
(
buffer_dirty
(
p
))
ll_rw_block
(
WRITE
,
1
,
&
p
);
ll_rw_block
(
WRITE
,
1
,
&
p
);
}
while
(
tmp
!=
bh
);
}
while
(
tmp
!=
bh
);
}
}
...
...
include/linux/swap.h
View file @
5cb39380
...
@@ -171,13 +171,18 @@ do { \
...
@@ -171,13 +171,18 @@ do { \
spin_unlock(&pagemap_lru_lock); \
spin_unlock(&pagemap_lru_lock); \
} while (0)
} while (0)
#define __lru_cache_del(page) \
do { \
list_del(&(page)->lru); \
nr_lru_pages--; \
} while (0)
#define lru_cache_del(page) \
#define lru_cache_del(page) \
do { \
do { \
if (!PageLocked(page)) \
if (!PageLocked(page)) \
BUG(); \
BUG(); \
spin_lock(&pagemap_lru_lock); \
spin_lock(&pagemap_lru_lock); \
list_del(&(page)->lru); \
__lru_cache_del(page); \
nr_lru_pages--; \
spin_unlock(&pagemap_lru_lock); \
spin_unlock(&pagemap_lru_lock); \
} while (0)
} while (0)
...
...
mm/filemap.c
View file @
5cb39380
...
@@ -67,7 +67,7 @@ void __add_page_to_hash_queue(struct page * page, struct page **p)
...
@@ -67,7 +67,7 @@ void __add_page_to_hash_queue(struct page * page, struct page **p)
PAGE_BUG
(
page
);
PAGE_BUG
(
page
);
}
}
static
void
remove_page_from_hash_queue
(
struct
page
*
page
)
static
inline
void
remove_page_from_hash_queue
(
struct
page
*
page
)
{
{
if
(
page
->
pprev_hash
)
{
if
(
page
->
pprev_hash
)
{
if
(
page
->
next_hash
)
if
(
page
->
next_hash
)
...
@@ -92,44 +92,71 @@ static inline int sync_page(struct page *page)
...
@@ -92,44 +92,71 @@ static inline int sync_page(struct page *page)
* sure the page is locked and that nobody else uses it - or that usage
* sure the page is locked and that nobody else uses it - or that usage
* is safe.
* is safe.
*/
*/
static
inline
void
__remove_inode_page
(
struct
page
*
page
)
{
remove_page_from_inode_queue
(
page
);
remove_page_from_hash_queue
(
page
);
page
->
mapping
=
NULL
;
}
void
remove_inode_page
(
struct
page
*
page
)
void
remove_inode_page
(
struct
page
*
page
)
{
{
if
(
!
PageLocked
(
page
))
if
(
!
PageLocked
(
page
))
PAGE_BUG
(
page
);
PAGE_BUG
(
page
);
spin_lock
(
&
pagecache_lock
);
spin_lock
(
&
pagecache_lock
);
remove_page_from_inode_queue
(
page
);
__remove_inode_page
(
page
);
remove_page_from_hash_queue
(
page
);
page
->
mapping
=
NULL
;
spin_unlock
(
&
pagecache_lock
);
spin_unlock
(
&
pagecache_lock
);
}
}
#define ITERATIONS 100
void
invalidate_inode_pages
(
struct
inode
*
inode
)
void
invalidate_inode_pages
(
struct
inode
*
inode
)
{
{
struct
list_head
*
head
,
*
curr
;
struct
list_head
*
head
,
*
curr
;
struct
page
*
page
;
struct
page
*
page
;
int
count
;
repeat:
head
=
&
inode
->
i_mapping
->
pages
;
head
=
&
inode
->
i_mapping
->
pages
;
spin_lock
(
&
pagecache_lock
);
curr
=
head
->
next
;
while
(
curr
!=
head
)
{
while
(
head
!=
head
->
next
)
{
page
=
list_entry
(
curr
,
struct
page
,
list
);
spin_lock
(
&
pagecache_lock
);
curr
=
curr
->
next
;
spin_lock
(
&
pagemap_lru_lock
);
head
=
&
inode
->
i_mapping
->
pages
;
curr
=
head
->
next
;
count
=
0
;
/* We cannot invalidate a locked page */
while
((
curr
!=
head
)
&&
(
count
++
<
ITERATIONS
))
{
if
(
TryLockPage
(
page
))
page
=
list_entry
(
curr
,
struct
page
,
list
);
continue
;
curr
=
curr
->
next
;
spin_unlock
(
&
pagecache_lock
);
lru_cache_del
(
page
);
/* We cannot invalidate a locked page */
remove_inode_page
(
page
);
if
(
TryLockPage
(
page
))
UnlockPage
(
page
);
continue
;
page_cache_release
(
page
);
goto
repeat
;
__lru_cache_del
(
page
);
__remove_inode_page
(
page
);
UnlockPage
(
page
);
page_cache_release
(
page
);
}
/* At this stage we have passed through the list
* once, and there may still be locked pages. */
if
(
head
->
next
!=
head
)
{
page
=
list_entry
(
head
->
next
,
struct
page
,
list
);
get_page
(
page
);
spin_unlock
(
&
pagemap_lru_lock
);
spin_unlock
(
&
pagecache_lock
);
/* We need to block */
lock_page
(
page
);
UnlockPage
(
page
);
page_cache_release
(
page
);
}
else
{
spin_unlock
(
&
pagemap_lru_lock
);
spin_unlock
(
&
pagecache_lock
);
}
}
}
spin_unlock
(
&
pagecache_lock
);
}
}
/*
/*
...
@@ -160,10 +187,10 @@ void truncate_inode_pages(struct address_space * mapping, loff_t lstart)
...
@@ -160,10 +187,10 @@ void truncate_inode_pages(struct address_space * mapping, loff_t lstart)
/* page wholly truncated - free it */
/* page wholly truncated - free it */
if
(
offset
>=
start
)
{
if
(
offset
>=
start
)
{
if
(
TryLockPage
(
page
))
{
if
(
TryLockPage
(
page
))
{
spin_unlock
(
&
pagecache_lock
);
get_page
(
page
);
get_page
(
page
);
spin_unlock
(
&
pagecache_lock
);
wait_on_page
(
page
);
wait_on_page
(
page
);
p
ut_pag
e
(
page
);
p
age_cache_releas
e
(
page
);
goto
repeat
;
goto
repeat
;
}
}
get_page
(
page
);
get_page
(
page
);
...
@@ -253,7 +280,19 @@ int shrink_mmap(int priority, int gfp_mask)
...
@@ -253,7 +280,19 @@ int shrink_mmap(int priority, int gfp_mask)
goto
dispose_continue
;
goto
dispose_continue
;
count
--
;
count
--
;
/*
* I'm ambivalent on this one.. Should we try to
* maintain LRU on the LRU list, and put pages that
* are old at the end of the queue, even if that
* means that we'll re-scan then again soon and
* often waste CPU time? Or should be just let any
* pages we do not want to touch now for one reason
* or another percolate to be "young"?
*
dispose = &old;
dispose = &old;
*
*/
/*
/*
* Avoid unscalable SMP locking for pages we can
* Avoid unscalable SMP locking for pages we can
...
@@ -323,9 +362,7 @@ int shrink_mmap(int priority, int gfp_mask)
...
@@ -323,9 +362,7 @@ int shrink_mmap(int priority, int gfp_mask)
/* is it a page-cache page? */
/* is it a page-cache page? */
if
(
page
->
mapping
)
{
if
(
page
->
mapping
)
{
if
(
!
PageDirty
(
page
)
&&
!
pgcache_under_min
())
{
if
(
!
PageDirty
(
page
)
&&
!
pgcache_under_min
())
{
remove_page_from_inode_queue
(
page
);
__remove_inode_page
(
page
);
remove_page_from_hash_queue
(
page
);
page
->
mapping
=
NULL
;
spin_unlock
(
&
pagecache_lock
);
spin_unlock
(
&
pagecache_lock
);
goto
made_inode_progress
;
goto
made_inode_progress
;
}
}
...
...
mm/vmscan.c
View file @
5cb39380
...
@@ -347,7 +347,6 @@ static int swap_out(unsigned int priority, int gfp_mask)
...
@@ -347,7 +347,6 @@ static int swap_out(unsigned int priority, int gfp_mask)
struct
task_struct
*
p
;
struct
task_struct
*
p
;
int
counter
;
int
counter
;
int
__ret
=
0
;
int
__ret
=
0
;
int
assign
=
0
;
lock_kernel
();
lock_kernel
();
/*
/*
...
@@ -364,7 +363,7 @@ static int swap_out(unsigned int priority, int gfp_mask)
...
@@ -364,7 +363,7 @@ static int swap_out(unsigned int priority, int gfp_mask)
* Think of swap_cnt as a "shadow rss" - it tells us which process
* Think of swap_cnt as a "shadow rss" - it tells us which process
* we want to page out (always try largest first).
* we want to page out (always try largest first).
*/
*/
counter
=
nr_threads
/
(
priority
+
1
);
counter
=
(
nr_threads
<<
1
)
>>
(
priority
>>
1
);
if
(
counter
<
1
)
if
(
counter
<
1
)
counter
=
1
;
counter
=
1
;
...
@@ -372,6 +371,7 @@ static int swap_out(unsigned int priority, int gfp_mask)
...
@@ -372,6 +371,7 @@ static int swap_out(unsigned int priority, int gfp_mask)
unsigned
long
max_cnt
=
0
;
unsigned
long
max_cnt
=
0
;
struct
mm_struct
*
best
=
NULL
;
struct
mm_struct
*
best
=
NULL
;
int
pid
=
0
;
int
pid
=
0
;
int
assign
=
0
;
select:
select:
read_lock
(
&
tasklist_lock
);
read_lock
(
&
tasklist_lock
);
p
=
init_task
.
next_task
;
p
=
init_task
.
next_task
;
...
@@ -391,8 +391,6 @@ static int swap_out(unsigned int priority, int gfp_mask)
...
@@ -391,8 +391,6 @@ static int swap_out(unsigned int priority, int gfp_mask)
}
}
}
}
read_unlock
(
&
tasklist_lock
);
read_unlock
(
&
tasklist_lock
);
if
(
assign
==
1
)
assign
=
2
;
if
(
!
best
)
{
if
(
!
best
)
{
if
(
!
assign
)
{
if
(
!
assign
)
{
assign
=
1
;
assign
=
1
;
...
...
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