mirror of https://gitee.com/openkylin/linux.git
Merge branch 'for-linus' of master.kernel.org:/pub/scm/linux/kernel/git/scjody/ieee1394
This commit is contained in:
commit
cd535057f9
File diff suppressed because it is too large
Load Diff
|
@ -1,84 +0,0 @@
|
|||
/* -*- c-basic-offset: 8 -*- */
|
||||
|
||||
#ifndef __AMDTP_H
|
||||
#define __AMDTP_H
|
||||
|
||||
#include <asm/types.h>
|
||||
#include "ieee1394-ioctl.h"
|
||||
|
||||
/* The userspace interface for the Audio & Music Data Transmission
|
||||
* Protocol driver is really simple. First, open /dev/amdtp, use the
|
||||
* ioctl to configure format, rate, dimension and either plug or
|
||||
* channel, then start writing samples.
|
||||
*
|
||||
* The formats supported by the driver are listed below.
|
||||
* AMDTP_FORMAT_RAW corresponds to the AM824 raw format, which can
|
||||
* carry any number of channels, so use this if you're streaming
|
||||
* multichannel audio. The AMDTP_FORMAT_IEC958_PCM corresponds to the
|
||||
* AM824 IEC958 encapsulation without the IEC958 data bit set, using
|
||||
* AMDTP_FORMAT_IEC958_AC3 will transmit the samples with the data bit
|
||||
* set, suitable for transmitting compressed AC-3 audio.
|
||||
*
|
||||
* The rate field specifies the transmission rate; supported values
|
||||
* are 32000, 44100, 48000, 88200, 96000, 176400 and 192000.
|
||||
*
|
||||
* The dimension field specifies the dimension of the signal, that is,
|
||||
* the number of audio channels. Only AMDTP_FORMAT_RAW supports
|
||||
* settings greater than 2.
|
||||
*
|
||||
* The mode field specifies which transmission mode to use. The AMDTP
|
||||
* specifies two different transmission modes: blocking and
|
||||
* non-blocking. The blocking transmission mode always send a fixed
|
||||
* number of samples, typically 8, 16 or 32. To exactly match the
|
||||
* transmission rate, the driver alternates between sending empty and
|
||||
* non-empty packets. In non-blocking mode, the driver transmits as
|
||||
* small packets as possible. For example, for a transmission rate of
|
||||
* 44100Hz, the driver should send 5 41/80 samples in every cycle, but
|
||||
* this is not possible so instead the driver alternates between
|
||||
* sending 5 and 6 samples.
|
||||
*
|
||||
* The last thing to specify is either the isochronous channel to use
|
||||
* or the output plug to connect to. If you know what channel the
|
||||
* destination device will listen on, you can specify the channel
|
||||
* directly and use the AMDTP_IOC_CHANNEL ioctl. However, if the
|
||||
* destination device chooses the channel and uses the IEC61883-1 plug
|
||||
* mechanism, you can specify an output plug to connect to. The
|
||||
* driver will pick up the channel number from the plug once the
|
||||
* destination device locks the output plug control register. In this
|
||||
* case set the plug field and use the AMDTP_IOC_PLUG ioctl.
|
||||
*
|
||||
* Having configured the interface, the driver now accepts writes of
|
||||
* regular 16 bit signed little endian samples, with the channels
|
||||
* interleaved. For example, 4 channels would look like:
|
||||
*
|
||||
* | sample 0 | sample 1 ...
|
||||
* | ch. 0 | ch. 1 | ch. 2 | ch. 3 | ch. 0 | ...
|
||||
* | lsb | msb | lsb | msb | lsb | msb | lsb | msb | lsb | msb | ...
|
||||
*
|
||||
*/
|
||||
|
||||
enum {
|
||||
AMDTP_FORMAT_RAW,
|
||||
AMDTP_FORMAT_IEC958_PCM,
|
||||
AMDTP_FORMAT_IEC958_AC3
|
||||
};
|
||||
|
||||
enum {
|
||||
AMDTP_MODE_BLOCKING,
|
||||
AMDTP_MODE_NON_BLOCKING,
|
||||
};
|
||||
|
||||
enum {
|
||||
AMDTP_INPUT_LE16,
|
||||
AMDTP_INPUT_BE16,
|
||||
};
|
||||
|
||||
struct amdtp_ioctl {
|
||||
__u32 format;
|
||||
__u32 rate;
|
||||
__u32 dimension;
|
||||
__u32 mode;
|
||||
union { __u32 channel; __u32 plug; } u;
|
||||
};
|
||||
|
||||
#endif /* __AMDTP_H */
|
|
@ -1,311 +0,0 @@
|
|||
/* -*- c-basic-offset: 8 -*-
|
||||
*
|
||||
* cmp.c - Connection Management Procedures
|
||||
* Copyright (C) 2001 Kristian Høgsberg
|
||||
*
|
||||
* 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 Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/* TODO
|
||||
* ----
|
||||
*
|
||||
* - Implement IEC61883-1 output plugs and connection management.
|
||||
* This should probably be part of the general subsystem, as it could
|
||||
* be shared with dv1394.
|
||||
*
|
||||
* - Add IEC61883 unit directory when loading this module. This
|
||||
* requires a run-time changeable config rom.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include "hosts.h"
|
||||
#include "highlevel.h"
|
||||
#include "ieee1394.h"
|
||||
#include "ieee1394_core.h"
|
||||
#include "cmp.h"
|
||||
|
||||
struct plug {
|
||||
union {
|
||||
struct cmp_pcr pcr;
|
||||
quadlet_t quadlet;
|
||||
} u;
|
||||
void (*update)(struct cmp_pcr *plug, void *data);
|
||||
void *data;
|
||||
};
|
||||
|
||||
struct cmp_host {
|
||||
struct hpsb_host *host;
|
||||
|
||||
union {
|
||||
struct cmp_mpr ompr;
|
||||
quadlet_t ompr_quadlet;
|
||||
} u;
|
||||
struct plug opcr[2];
|
||||
|
||||
union {
|
||||
struct cmp_mpr impr;
|
||||
quadlet_t impr_quadlet;
|
||||
} v;
|
||||
struct plug ipcr[2];
|
||||
};
|
||||
|
||||
enum {
|
||||
CMP_P2P_CONNECTION,
|
||||
CMP_BC_CONNECTION
|
||||
};
|
||||
|
||||
#define CSR_PCR_MAP 0x900
|
||||
#define CSR_PCR_MAP_END 0x9fc
|
||||
|
||||
static struct hpsb_highlevel cmp_highlevel;
|
||||
|
||||
static void cmp_add_host(struct hpsb_host *host);
|
||||
static void cmp_host_reset(struct hpsb_host *host);
|
||||
static int pcr_read(struct hpsb_host *host, int nodeid, quadlet_t *buf,
|
||||
u64 addr, size_t length, u16 flags);
|
||||
static int pcr_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
|
||||
u64 addr, quadlet_t data, quadlet_t arg, int extcode, u16 flags);
|
||||
|
||||
static struct hpsb_highlevel cmp_highlevel = {
|
||||
.name = "cmp",
|
||||
.add_host = cmp_add_host,
|
||||
.host_reset = cmp_host_reset,
|
||||
};
|
||||
|
||||
static struct hpsb_address_ops pcr_ops = {
|
||||
.read = pcr_read,
|
||||
.lock = pcr_lock,
|
||||
};
|
||||
|
||||
|
||||
struct cmp_pcr *
|
||||
cmp_register_opcr(struct hpsb_host *host, int opcr_number, int payload,
|
||||
void (*update)(struct cmp_pcr *pcr, void *data),
|
||||
void *data)
|
||||
{
|
||||
struct cmp_host *ch;
|
||||
struct plug *plug;
|
||||
|
||||
ch = hpsb_get_hostinfo(&cmp_highlevel, host);
|
||||
|
||||
if (opcr_number >= ch->u.ompr.nplugs ||
|
||||
ch->opcr[opcr_number].update != NULL)
|
||||
return NULL;
|
||||
|
||||
plug = &ch->opcr[opcr_number];
|
||||
plug->u.pcr.online = 1;
|
||||
plug->u.pcr.bcast_count = 0;
|
||||
plug->u.pcr.p2p_count = 0;
|
||||
plug->u.pcr.overhead = 0;
|
||||
plug->u.pcr.payload = payload;
|
||||
plug->update = update;
|
||||
plug->data = data;
|
||||
|
||||
return &plug->u.pcr;
|
||||
}
|
||||
|
||||
void cmp_unregister_opcr(struct hpsb_host *host, struct cmp_pcr *opcr)
|
||||
{
|
||||
struct cmp_host *ch;
|
||||
struct plug *plug;
|
||||
|
||||
ch = hpsb_get_hostinfo(&cmp_highlevel, host);
|
||||
plug = (struct plug *)opcr;
|
||||
if (plug - ch->opcr >= ch->u.ompr.nplugs) BUG();
|
||||
|
||||
plug->u.pcr.online = 0;
|
||||
plug->update = NULL;
|
||||
}
|
||||
|
||||
static void reset_plugs(struct cmp_host *ch)
|
||||
{
|
||||
int i;
|
||||
|
||||
ch->u.ompr.non_persistent_ext = 0xff;
|
||||
for (i = 0; i < ch->u.ompr.nplugs; i++) {
|
||||
ch->opcr[i].u.pcr.bcast_count = 0;
|
||||
ch->opcr[i].u.pcr.p2p_count = 0;
|
||||
ch->opcr[i].u.pcr.overhead = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void cmp_add_host(struct hpsb_host *host)
|
||||
{
|
||||
struct cmp_host *ch = hpsb_create_hostinfo(&cmp_highlevel, host, sizeof (*ch));
|
||||
|
||||
if (ch == NULL) {
|
||||
HPSB_ERR("Failed to allocate cmp_host");
|
||||
return;
|
||||
}
|
||||
|
||||
hpsb_register_addrspace(&cmp_highlevel, host, &pcr_ops,
|
||||
CSR_REGISTER_BASE + CSR_PCR_MAP,
|
||||
CSR_REGISTER_BASE + CSR_PCR_MAP_END);
|
||||
|
||||
ch->host = host;
|
||||
ch->u.ompr.rate = IEEE1394_SPEED_100;
|
||||
ch->u.ompr.bcast_channel_base = 63;
|
||||
ch->u.ompr.nplugs = 2;
|
||||
|
||||
reset_plugs(ch);
|
||||
}
|
||||
|
||||
static void cmp_host_reset(struct hpsb_host *host)
|
||||
{
|
||||
struct cmp_host *ch;
|
||||
|
||||
ch = hpsb_get_hostinfo(&cmp_highlevel, host);
|
||||
if (ch == NULL) {
|
||||
HPSB_ERR("cmp: Tried to reset unknown host");
|
||||
return;
|
||||
}
|
||||
|
||||
reset_plugs(ch);
|
||||
}
|
||||
|
||||
static int pcr_read(struct hpsb_host *host, int nodeid, quadlet_t *buf,
|
||||
u64 addr, size_t length, u16 flags)
|
||||
{
|
||||
int csraddr = addr - CSR_REGISTER_BASE;
|
||||
int plug;
|
||||
struct cmp_host *ch;
|
||||
|
||||
if (length != 4)
|
||||
return RCODE_TYPE_ERROR;
|
||||
|
||||
ch = hpsb_get_hostinfo(&cmp_highlevel, host);
|
||||
if (csraddr == 0x900) {
|
||||
*buf = cpu_to_be32(ch->u.ompr_quadlet);
|
||||
return RCODE_COMPLETE;
|
||||
}
|
||||
else if (csraddr < 0x904 + ch->u.ompr.nplugs * 4) {
|
||||
plug = (csraddr - 0x904) / 4;
|
||||
*buf = cpu_to_be32(ch->opcr[plug].u.quadlet);
|
||||
return RCODE_COMPLETE;
|
||||
}
|
||||
else if (csraddr < 0x980) {
|
||||
return RCODE_ADDRESS_ERROR;
|
||||
}
|
||||
else if (csraddr == 0x980) {
|
||||
*buf = cpu_to_be32(ch->v.impr_quadlet);
|
||||
return RCODE_COMPLETE;
|
||||
}
|
||||
else if (csraddr < 0x984 + ch->v.impr.nplugs * 4) {
|
||||
plug = (csraddr - 0x984) / 4;
|
||||
*buf = cpu_to_be32(ch->ipcr[plug].u.quadlet);
|
||||
return RCODE_COMPLETE;
|
||||
}
|
||||
else
|
||||
return RCODE_ADDRESS_ERROR;
|
||||
}
|
||||
|
||||
static int pcr_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
|
||||
u64 addr, quadlet_t data, quadlet_t arg, int extcode, u16 flags)
|
||||
{
|
||||
int csraddr = addr - CSR_REGISTER_BASE;
|
||||
int plug;
|
||||
struct cmp_host *ch;
|
||||
|
||||
ch = hpsb_get_hostinfo(&cmp_highlevel, host);
|
||||
|
||||
if (extcode != EXTCODE_COMPARE_SWAP)
|
||||
return RCODE_TYPE_ERROR;
|
||||
|
||||
if (csraddr == 0x900) {
|
||||
/* FIXME: Ignore writes to bits 30-31 and 0-7 */
|
||||
*store = cpu_to_be32(ch->u.ompr_quadlet);
|
||||
if (arg == cpu_to_be32(ch->u.ompr_quadlet))
|
||||
ch->u.ompr_quadlet = be32_to_cpu(data);
|
||||
|
||||
return RCODE_COMPLETE;
|
||||
}
|
||||
if (csraddr < 0x904 + ch->u.ompr.nplugs * 4) {
|
||||
plug = (csraddr - 0x904) / 4;
|
||||
*store = cpu_to_be32(ch->opcr[plug].u.quadlet);
|
||||
|
||||
if (arg == *store)
|
||||
ch->opcr[plug].u.quadlet = be32_to_cpu(data);
|
||||
|
||||
if (be32_to_cpu(*store) != ch->opcr[plug].u.quadlet &&
|
||||
ch->opcr[plug].update != NULL)
|
||||
ch->opcr[plug].update(&ch->opcr[plug].u.pcr,
|
||||
ch->opcr[plug].data);
|
||||
|
||||
return RCODE_COMPLETE;
|
||||
}
|
||||
else if (csraddr < 0x980) {
|
||||
return RCODE_ADDRESS_ERROR;
|
||||
}
|
||||
else if (csraddr == 0x980) {
|
||||
/* FIXME: Ignore writes to bits 24-31 and 0-7 */
|
||||
*store = cpu_to_be32(ch->u.ompr_quadlet);
|
||||
if (arg == cpu_to_be32(ch->u.ompr_quadlet))
|
||||
ch->u.ompr_quadlet = be32_to_cpu(data);
|
||||
|
||||
return RCODE_COMPLETE;
|
||||
}
|
||||
else if (csraddr < 0x984 + ch->v.impr.nplugs * 4) {
|
||||
plug = (csraddr - 0x984) / 4;
|
||||
*store = cpu_to_be32(ch->ipcr[plug].u.quadlet);
|
||||
|
||||
if (arg == *store)
|
||||
ch->ipcr[plug].u.quadlet = be32_to_cpu(data);
|
||||
|
||||
if (be32_to_cpu(*store) != ch->ipcr[plug].u.quadlet &&
|
||||
ch->ipcr[plug].update != NULL)
|
||||
ch->ipcr[plug].update(&ch->ipcr[plug].u.pcr,
|
||||
ch->ipcr[plug].data);
|
||||
|
||||
return RCODE_COMPLETE;
|
||||
}
|
||||
else
|
||||
return RCODE_ADDRESS_ERROR;
|
||||
}
|
||||
|
||||
|
||||
/* Module interface */
|
||||
|
||||
MODULE_AUTHOR("Kristian Hogsberg <hogsberg@users.sf.net>");
|
||||
MODULE_DESCRIPTION("Connection Management Procedures (CMP)");
|
||||
MODULE_SUPPORTED_DEVICE("cmp");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
EXPORT_SYMBOL(cmp_register_opcr);
|
||||
EXPORT_SYMBOL(cmp_unregister_opcr);
|
||||
|
||||
static int __init cmp_init_module (void)
|
||||
{
|
||||
hpsb_register_highlevel (&cmp_highlevel);
|
||||
|
||||
HPSB_INFO("Loaded CMP driver");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit cmp_exit_module (void)
|
||||
{
|
||||
hpsb_unregister_highlevel(&cmp_highlevel);
|
||||
|
||||
HPSB_INFO("Unloaded CMP driver");
|
||||
}
|
||||
|
||||
module_init(cmp_init_module);
|
||||
module_exit(cmp_exit_module);
|
|
@ -1,31 +0,0 @@
|
|||
#ifndef __CMP_H
|
||||
#define __CMP_H
|
||||
|
||||
struct cmp_mpr {
|
||||
u32 nplugs:5;
|
||||
u32 reserved:3;
|
||||
u32 persistent_ext:8;
|
||||
u32 non_persistent_ext:8;
|
||||
u32 bcast_channel_base:6;
|
||||
u32 rate:2;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct cmp_pcr {
|
||||
u32 payload:10;
|
||||
u32 overhead:4;
|
||||
u32 speed:2;
|
||||
u32 channel:6;
|
||||
u32 reserved:2;
|
||||
u32 p2p_count:6;
|
||||
u32 bcast_count:1;
|
||||
u32 online:1;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct cmp_pcr *cmp_register_opcr(struct hpsb_host *host, int plug,
|
||||
int payload,
|
||||
void (*update)(struct cmp_pcr *plug,
|
||||
void *data),
|
||||
void *data);
|
||||
void cmp_unregister_opcr(struct hpsb_host *host, struct cmp_pcr *plug);
|
||||
|
||||
#endif /* __CMP_H */
|
Loading…
Reference in New Issue