|
@@ -15,6 +15,9 @@
|
|
#include "hosts.h"
|
|
#include "hosts.h"
|
|
#include "iso.h"
|
|
#include "iso.h"
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * hpsb_iso_stop - stop DMA
|
|
|
|
+ */
|
|
void hpsb_iso_stop(struct hpsb_iso *iso)
|
|
void hpsb_iso_stop(struct hpsb_iso *iso)
|
|
{
|
|
{
|
|
if (!(iso->flags & HPSB_ISO_DRIVER_STARTED))
|
|
if (!(iso->flags & HPSB_ISO_DRIVER_STARTED))
|
|
@@ -25,6 +28,9 @@ void hpsb_iso_stop(struct hpsb_iso *iso)
|
|
iso->flags &= ~HPSB_ISO_DRIVER_STARTED;
|
|
iso->flags &= ~HPSB_ISO_DRIVER_STARTED;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * hpsb_iso_shutdown - deallocate buffer and DMA context
|
|
|
|
+ */
|
|
void hpsb_iso_shutdown(struct hpsb_iso *iso)
|
|
void hpsb_iso_shutdown(struct hpsb_iso *iso)
|
|
{
|
|
{
|
|
if (iso->flags & HPSB_ISO_DRIVER_INIT) {
|
|
if (iso->flags & HPSB_ISO_DRIVER_INIT) {
|
|
@@ -130,6 +136,9 @@ static struct hpsb_iso *hpsb_iso_common_init(struct hpsb_host *host,
|
|
return NULL;
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * hpsb_iso_n_ready - returns number of packets ready to send or receive
|
|
|
|
+ */
|
|
int hpsb_iso_n_ready(struct hpsb_iso *iso)
|
|
int hpsb_iso_n_ready(struct hpsb_iso *iso)
|
|
{
|
|
{
|
|
unsigned long flags;
|
|
unsigned long flags;
|
|
@@ -142,6 +151,9 @@ int hpsb_iso_n_ready(struct hpsb_iso *iso)
|
|
return val;
|
|
return val;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * hpsb_iso_xmit_init - allocate the buffer and DMA context
|
|
|
|
+ */
|
|
struct hpsb_iso *hpsb_iso_xmit_init(struct hpsb_host *host,
|
|
struct hpsb_iso *hpsb_iso_xmit_init(struct hpsb_host *host,
|
|
unsigned int data_buf_size,
|
|
unsigned int data_buf_size,
|
|
unsigned int buf_packets,
|
|
unsigned int buf_packets,
|
|
@@ -172,6 +184,11 @@ struct hpsb_iso *hpsb_iso_xmit_init(struct hpsb_host *host,
|
|
return NULL;
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * hpsb_iso_recv_init - allocate the buffer and DMA context
|
|
|
|
+ *
|
|
|
|
+ * Note, if channel = -1, multi-channel receive is enabled.
|
|
|
|
+ */
|
|
struct hpsb_iso *hpsb_iso_recv_init(struct hpsb_host *host,
|
|
struct hpsb_iso *hpsb_iso_recv_init(struct hpsb_host *host,
|
|
unsigned int data_buf_size,
|
|
unsigned int data_buf_size,
|
|
unsigned int buf_packets,
|
|
unsigned int buf_packets,
|
|
@@ -199,6 +216,11 @@ struct hpsb_iso *hpsb_iso_recv_init(struct hpsb_host *host,
|
|
return NULL;
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * hpsb_iso_recv_listen_channel
|
|
|
|
+ *
|
|
|
|
+ * multi-channel only
|
|
|
|
+ */
|
|
int hpsb_iso_recv_listen_channel(struct hpsb_iso *iso, unsigned char channel)
|
|
int hpsb_iso_recv_listen_channel(struct hpsb_iso *iso, unsigned char channel)
|
|
{
|
|
{
|
|
if (iso->type != HPSB_ISO_RECV || iso->channel != -1 || channel >= 64)
|
|
if (iso->type != HPSB_ISO_RECV || iso->channel != -1 || channel >= 64)
|
|
@@ -206,6 +228,11 @@ int hpsb_iso_recv_listen_channel(struct hpsb_iso *iso, unsigned char channel)
|
|
return iso->host->driver->isoctl(iso, RECV_LISTEN_CHANNEL, channel);
|
|
return iso->host->driver->isoctl(iso, RECV_LISTEN_CHANNEL, channel);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * hpsb_iso_recv_unlisten_channel
|
|
|
|
+ *
|
|
|
|
+ * multi-channel only
|
|
|
|
+ */
|
|
int hpsb_iso_recv_unlisten_channel(struct hpsb_iso *iso, unsigned char channel)
|
|
int hpsb_iso_recv_unlisten_channel(struct hpsb_iso *iso, unsigned char channel)
|
|
{
|
|
{
|
|
if (iso->type != HPSB_ISO_RECV || iso->channel != -1 || channel >= 64)
|
|
if (iso->type != HPSB_ISO_RECV || iso->channel != -1 || channel >= 64)
|
|
@@ -213,6 +240,11 @@ int hpsb_iso_recv_unlisten_channel(struct hpsb_iso *iso, unsigned char channel)
|
|
return iso->host->driver->isoctl(iso, RECV_UNLISTEN_CHANNEL, channel);
|
|
return iso->host->driver->isoctl(iso, RECV_UNLISTEN_CHANNEL, channel);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * hpsb_iso_recv_set_channel_mask
|
|
|
|
+ *
|
|
|
|
+ * multi-channel only
|
|
|
|
+ */
|
|
int hpsb_iso_recv_set_channel_mask(struct hpsb_iso *iso, u64 mask)
|
|
int hpsb_iso_recv_set_channel_mask(struct hpsb_iso *iso, u64 mask)
|
|
{
|
|
{
|
|
if (iso->type != HPSB_ISO_RECV || iso->channel != -1)
|
|
if (iso->type != HPSB_ISO_RECV || iso->channel != -1)
|
|
@@ -221,6 +253,12 @@ int hpsb_iso_recv_set_channel_mask(struct hpsb_iso *iso, u64 mask)
|
|
(unsigned long)&mask);
|
|
(unsigned long)&mask);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * hpsb_iso_recv_flush - check for arrival of new packets
|
|
|
|
+ *
|
|
|
|
+ * check for arrival of new packets immediately (even if irq_interval
|
|
|
|
+ * has not yet been reached)
|
|
|
|
+ */
|
|
int hpsb_iso_recv_flush(struct hpsb_iso *iso)
|
|
int hpsb_iso_recv_flush(struct hpsb_iso *iso)
|
|
{
|
|
{
|
|
if (iso->type != HPSB_ISO_RECV)
|
|
if (iso->type != HPSB_ISO_RECV)
|
|
@@ -238,6 +276,9 @@ static int do_iso_xmit_start(struct hpsb_iso *iso, int cycle)
|
|
return retval;
|
|
return retval;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * hpsb_iso_xmit_start - start DMA
|
|
|
|
+ */
|
|
int hpsb_iso_xmit_start(struct hpsb_iso *iso, int cycle, int prebuffer)
|
|
int hpsb_iso_xmit_start(struct hpsb_iso *iso, int cycle, int prebuffer)
|
|
{
|
|
{
|
|
if (iso->type != HPSB_ISO_XMIT)
|
|
if (iso->type != HPSB_ISO_XMIT)
|
|
@@ -270,6 +311,9 @@ int hpsb_iso_xmit_start(struct hpsb_iso *iso, int cycle, int prebuffer)
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * hpsb_iso_recv_start - start DMA
|
|
|
|
+ */
|
|
int hpsb_iso_recv_start(struct hpsb_iso *iso, int cycle, int tag_mask, int sync)
|
|
int hpsb_iso_recv_start(struct hpsb_iso *iso, int cycle, int tag_mask, int sync)
|
|
{
|
|
{
|
|
int retval = 0;
|
|
int retval = 0;
|
|
@@ -306,8 +350,7 @@ int hpsb_iso_recv_start(struct hpsb_iso *iso, int cycle, int tag_mask, int sync)
|
|
}
|
|
}
|
|
|
|
|
|
/* check to make sure the user has not supplied bogus values of offset/len
|
|
/* check to make sure the user has not supplied bogus values of offset/len
|
|
- that would cause the kernel to access memory outside the buffer */
|
|
|
|
-
|
|
|
|
|
|
+ * that would cause the kernel to access memory outside the buffer */
|
|
static int hpsb_iso_check_offset_len(struct hpsb_iso *iso,
|
|
static int hpsb_iso_check_offset_len(struct hpsb_iso *iso,
|
|
unsigned int offset, unsigned short len,
|
|
unsigned int offset, unsigned short len,
|
|
unsigned int *out_offset,
|
|
unsigned int *out_offset,
|
|
@@ -331,6 +374,12 @@ static int hpsb_iso_check_offset_len(struct hpsb_iso *iso,
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * hpsb_iso_xmit_queue_packet - queue a packet for transmission.
|
|
|
|
+ *
|
|
|
|
+ * @offset is relative to the beginning of the DMA buffer, where the packet's
|
|
|
|
+ * data payload should already have been placed.
|
|
|
|
+ */
|
|
int hpsb_iso_xmit_queue_packet(struct hpsb_iso *iso, u32 offset, u16 len,
|
|
int hpsb_iso_xmit_queue_packet(struct hpsb_iso *iso, u32 offset, u16 len,
|
|
u8 tag, u8 sy)
|
|
u8 tag, u8 sy)
|
|
{
|
|
{
|
|
@@ -380,6 +429,9 @@ int hpsb_iso_xmit_queue_packet(struct hpsb_iso *iso, u32 offset, u16 len,
|
|
return rv;
|
|
return rv;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * hpsb_iso_xmit_sync - wait until all queued packets have been transmitted
|
|
|
|
+ */
|
|
int hpsb_iso_xmit_sync(struct hpsb_iso *iso)
|
|
int hpsb_iso_xmit_sync(struct hpsb_iso *iso)
|
|
{
|
|
{
|
|
if (iso->type != HPSB_ISO_XMIT)
|
|
if (iso->type != HPSB_ISO_XMIT)
|
|
@@ -390,6 +442,15 @@ int hpsb_iso_xmit_sync(struct hpsb_iso *iso)
|
|
iso->buf_packets);
|
|
iso->buf_packets);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * hpsb_iso_packet_sent
|
|
|
|
+ *
|
|
|
|
+ * Available to low-level drivers.
|
|
|
|
+ *
|
|
|
|
+ * Call after a packet has been transmitted to the bus (interrupt context is
|
|
|
|
+ * OK). @cycle is the _exact_ cycle the packet was sent on. @error should be
|
|
|
|
+ * non-zero if some sort of error occurred when sending the packet.
|
|
|
|
+ */
|
|
void hpsb_iso_packet_sent(struct hpsb_iso *iso, int cycle, int error)
|
|
void hpsb_iso_packet_sent(struct hpsb_iso *iso, int cycle, int error)
|
|
{
|
|
{
|
|
unsigned long flags;
|
|
unsigned long flags;
|
|
@@ -413,6 +474,13 @@ void hpsb_iso_packet_sent(struct hpsb_iso *iso, int cycle, int error)
|
|
spin_unlock_irqrestore(&iso->lock, flags);
|
|
spin_unlock_irqrestore(&iso->lock, flags);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * hpsb_iso_packet_received
|
|
|
|
+ *
|
|
|
|
+ * Available to low-level drivers.
|
|
|
|
+ *
|
|
|
|
+ * Call after a packet has been received (interrupt context is OK).
|
|
|
|
+ */
|
|
void hpsb_iso_packet_received(struct hpsb_iso *iso, u32 offset, u16 len,
|
|
void hpsb_iso_packet_received(struct hpsb_iso *iso, u32 offset, u16 len,
|
|
u16 total_len, u16 cycle, u8 channel, u8 tag,
|
|
u16 total_len, u16 cycle, u8 channel, u8 tag,
|
|
u8 sy)
|
|
u8 sy)
|
|
@@ -442,6 +510,11 @@ void hpsb_iso_packet_received(struct hpsb_iso *iso, u32 offset, u16 len,
|
|
spin_unlock_irqrestore(&iso->lock, flags);
|
|
spin_unlock_irqrestore(&iso->lock, flags);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * hpsb_iso_recv_release_packets - release packets, reuse buffer
|
|
|
|
+ *
|
|
|
|
+ * @n_packets have been read out of the buffer, re-use the buffer space
|
|
|
|
+ */
|
|
int hpsb_iso_recv_release_packets(struct hpsb_iso *iso, unsigned int n_packets)
|
|
int hpsb_iso_recv_release_packets(struct hpsb_iso *iso, unsigned int n_packets)
|
|
{
|
|
{
|
|
unsigned long flags;
|
|
unsigned long flags;
|
|
@@ -477,6 +550,13 @@ int hpsb_iso_recv_release_packets(struct hpsb_iso *iso, unsigned int n_packets)
|
|
return rv;
|
|
return rv;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * hpsb_iso_wake
|
|
|
|
+ *
|
|
|
|
+ * Available to low-level drivers.
|
|
|
|
+ *
|
|
|
|
+ * Call to wake waiting processes after buffer space has opened up.
|
|
|
|
+ */
|
|
void hpsb_iso_wake(struct hpsb_iso *iso)
|
|
void hpsb_iso_wake(struct hpsb_iso *iso)
|
|
{
|
|
{
|
|
wake_up_interruptible(&iso->waitq);
|
|
wake_up_interruptible(&iso->waitq);
|