Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging-2.6: Staging/vt66*: kconfig, depends on WLAN Staging: batman-adv: introduce missing kfree Staging: batman-adv: Add Kconfig dependancies on PROC_FS and PACKET. Staging: panel: Adjust range for PANEL_KEYPAD in Kconfig Staging: panel: Fix compilation error with custom lcd charset Staging: ramzswap: remove ARM specific d-cache hack Staging: rtl8192x: fix printk formats Staging: wlan-ng: fix Correct size given to memset staging: rtl8192su: add USB VID/PID for HWNUm-300 staging: fix rtl8192su compilation errors with mac80211 staging: fix rtl8192e compilation errors with mac80211 Staging: fix rtl8187se compilation errors with mac80211 Staging: rtl8192su: fix test for negative error in rtl8192_rx_isr() Staging: comedi: jr3_pci: Don't ioremap too much space. Check result. Staging: comedi: removed "depricated" from COMEDI_CB_BLOCK Staging: comedi: usbdux.c: fix locking up of the driver when the comedi ringbuffer runs empty Staging: dst: remove from the tree Staging: sm7xx: add a new framebuffer driver Staging: batman: fix debug Kconfig option
This commit is contained in:
commit
f988dac7fe
|
@ -87,8 +87,6 @@ source "drivers/staging/frontier/Kconfig"
|
|||
|
||||
source "drivers/staging/dream/Kconfig"
|
||||
|
||||
source "drivers/staging/dst/Kconfig"
|
||||
|
||||
source "drivers/staging/pohmelfs/Kconfig"
|
||||
|
||||
source "drivers/staging/b3dfg/Kconfig"
|
||||
|
@ -145,5 +143,7 @@ source "drivers/staging/wavelan/Kconfig"
|
|||
|
||||
source "drivers/staging/netwave/Kconfig"
|
||||
|
||||
source "drivers/staging/sm7xx/Kconfig"
|
||||
|
||||
endif # !STAGING_EXCLUDE_BUILD
|
||||
endif # STAGING
|
||||
|
|
|
@ -26,7 +26,6 @@ obj-$(CONFIG_RTL8192E) += rtl8192e/
|
|||
obj-$(CONFIG_INPUT_MIMIO) += mimio/
|
||||
obj-$(CONFIG_TRANZPORT) += frontier/
|
||||
obj-$(CONFIG_DREAM) += dream/
|
||||
obj-$(CONFIG_DST) += dst/
|
||||
obj-$(CONFIG_POHMELFS) += pohmelfs/
|
||||
obj-$(CONFIG_B3DFG) += b3dfg/
|
||||
obj-$(CONFIG_IDE_PHISON) += phison/
|
||||
|
@ -53,3 +52,4 @@ obj-$(CONFIG_ARLAN) += arlan/
|
|||
obj-$(CONFIG_WAVELAN) += wavelan/
|
||||
obj-$(CONFIG_PCMCIA_WAVELAN) += wavelan/
|
||||
obj-$(CONFIG_PCMCIA_NETWAVE) += netwave/
|
||||
obj-$(CONFIG_FB_SM7XX) += sm7xx/
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
config BATMAN_ADV
|
||||
tristate "B.A.T.M.A.N. Advanced Meshing Protocol"
|
||||
depends on PROC_FS && PACKET
|
||||
default n
|
||||
---help---
|
||||
|
||||
|
|
|
@ -363,8 +363,10 @@ void add_bcast_packet_to_list(unsigned char *packet_buff, int packet_len)
|
|||
return;
|
||||
|
||||
forw_packet->packet_buff = kmalloc(packet_len, GFP_ATOMIC);
|
||||
if (!forw_packet->packet_buff)
|
||||
if (!forw_packet->packet_buff) {
|
||||
kfree(forw_packet);
|
||||
return;
|
||||
}
|
||||
|
||||
forw_packet->packet_len = packet_len;
|
||||
memcpy(forw_packet->packet_buff, packet_buff, forw_packet->packet_len);
|
||||
|
|
|
@ -451,7 +451,7 @@
|
|||
|
||||
#define COMEDI_CB_EOS 1 /* end of scan */
|
||||
#define COMEDI_CB_EOA 2 /* end of acquisition */
|
||||
#define COMEDI_CB_BLOCK 4 /* DEPRECATED: convenient block size */
|
||||
#define COMEDI_CB_BLOCK 4 /* data has arrived: wakes up read() / write() */
|
||||
#define COMEDI_CB_EOBUF 8 /* DEPRECATED: end of buffer */
|
||||
#define COMEDI_CB_ERROR 16 /* card error during acquisition */
|
||||
#define COMEDI_CB_OVERFLOW 32 /* buffer overflow/underflow */
|
||||
|
|
|
@ -849,8 +849,11 @@ static int jr3_pci_attach(struct comedi_device *dev,
|
|||
}
|
||||
|
||||
devpriv->pci_enabled = 1;
|
||||
devpriv->iobase =
|
||||
ioremap(pci_resource_start(card, 0), sizeof(struct jr3_t));
|
||||
devpriv->iobase = ioremap(pci_resource_start(card, 0),
|
||||
offsetof(struct jr3_t, channel[devpriv->n_channels]));
|
||||
if (!devpriv->iobase)
|
||||
return -ENOMEM;
|
||||
|
||||
result = alloc_subdevices(dev, devpriv->n_channels);
|
||||
if (result < 0)
|
||||
goto out;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#define DRIVER_VERSION "v2.3"
|
||||
#define DRIVER_VERSION "v2.4"
|
||||
#define DRIVER_AUTHOR "Bernd Porr, BerndPorr@f2s.com"
|
||||
#define DRIVER_DESC "Stirling/ITL USB-DUX -- Bernd.Porr@f2s.com"
|
||||
/*
|
||||
|
@ -81,6 +81,8 @@ sampling rate. If you sample two channels you get 4kHz and so on.
|
|||
* 2.1: changed PWM API
|
||||
* 2.2: added firmware kernel request to fix an udev problem
|
||||
* 2.3: corrected a bug in bulk timeouts which were far too short
|
||||
* 2.4: fixed a bug which causes the driver to hang when it ran out of data.
|
||||
* Thanks to Jan-Matthias Braun and Ian to spot the bug and fix it.
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -532,6 +534,7 @@ static void usbduxsub_ai_IsocIrq(struct urb *urb)
|
|||
}
|
||||
}
|
||||
/* tell comedi that data is there */
|
||||
s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS;
|
||||
comedi_event(this_usbduxsub->comedidev, s);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,67 +0,0 @@
|
|||
config DST
|
||||
tristate "Distributed storage"
|
||||
depends on NET && CRYPTO && SYSFS && BLK_DEV
|
||||
select CONNECTOR
|
||||
---help---
|
||||
DST is a network block device storage, which can be used to organize
|
||||
exported storage on the remote nodes into the local block device.
|
||||
|
||||
DST works on top of any network media and protocol; it is just a matter
|
||||
of configuration utility to understand the correct addresses. The most
|
||||
common example is TCP over IP, which allows to pass through firewalls and
|
||||
create remote backup storage in a different datacenter. DST requires
|
||||
single port to be enabled on the exporting node and outgoing connections
|
||||
on the local node.
|
||||
|
||||
DST works with in-kernel client and server, which improves performance by
|
||||
eliminating unneded data copies and by not depending on the version
|
||||
of the external IO components. It requires userspace configuration utility
|
||||
though.
|
||||
|
||||
DST uses transaction model, when each store has to be explicitly acked
|
||||
from the remote node to be considered as successfully written. There
|
||||
may be lots of in-flight transactions. When remote host does not ack
|
||||
the transaction it will be resent predefined number of times with specified
|
||||
timeouts between them. All those parameters are configurable. Transactions
|
||||
are marked as failed after all resends complete unsuccessfully; having
|
||||
long enough resend timeout and/or large number of resends allows not to
|
||||
return error to the higher (FS usually) layer in case of short network
|
||||
problems or remote node outages. In case of network RAID setup this means
|
||||
that storage will not degrade until transactions are marked as failed, and
|
||||
thus will not force checksum recalculation and data rebuild. In case of
|
||||
connection failure DST will try to reconnect to the remote node automatically.
|
||||
DST sends ping commands at idle time to detect if remote node is alive.
|
||||
|
||||
Because of transactional model it is possible to use zero-copy sending
|
||||
without worry of data corruption (which in turn could be detected by the
|
||||
strong checksums though).
|
||||
|
||||
DST may fully encrypt the data channel in case of untrusted channel and implement
|
||||
strong checksum of the transferred data. It is possible to configure algorithms
|
||||
and crypto keys; they should match on both sides of the network channel.
|
||||
Crypto processing does not introduce noticeble performance overhead, since DST
|
||||
uses configurable pool of threads to perform crypto processing.
|
||||
|
||||
DST utilizes memory pool model of all its transaction allocations (it is the
|
||||
only additional allocation on the client) and server allocations (bio pools,
|
||||
while pages are allocated from the slab).
|
||||
|
||||
At startup DST performs a simple negotiation with the export node to determine
|
||||
access permissions and size of the exported storage. It can be extended if
|
||||
new parameters should be autonegotiated.
|
||||
|
||||
DST carries block IO flags in the protocol, which allows to transparently implement
|
||||
barriers and sync/flush operations. Those flags are used in the export node where
|
||||
IO against the local storage is performed, which means that sync write will be sync
|
||||
on the remote node too, which in turn improves data integrity and improved resistance
|
||||
to errors and data corruption during power outages or storage damages.
|
||||
|
||||
Homepage: http://www.ioremap.net/projects/dst
|
||||
Userspace configuration utility and the latest releases: http://www.ioremap.net/archive/dst/
|
||||
|
||||
config DST_DEBUG
|
||||
bool "DST debug"
|
||||
depends on DST
|
||||
---help---
|
||||
This option will enable HEAVY debugging of the DST.
|
||||
Turn it on ONLY if you have to debug some really obscure problem.
|
|
@ -1,3 +0,0 @@
|
|||
obj-$(CONFIG_DST) += nst.o
|
||||
|
||||
nst-y := dcore.o state.o export.o thread_pool.o crypto.o trans.o
|
|
@ -1,733 +0,0 @@
|
|||
/*
|
||||
* 2007+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net>
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/bio.h>
|
||||
#include <linux/crypto.h>
|
||||
#include <linux/dst.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
/*
|
||||
* Tricky bastard, but IV can be more complex with time...
|
||||
*/
|
||||
static inline u64 dst_gen_iv(struct dst_trans *t)
|
||||
{
|
||||
return t->gen;
|
||||
}
|
||||
|
||||
/*
|
||||
* Crypto machinery: hash/cipher support for the given crypto controls.
|
||||
*/
|
||||
static struct crypto_hash *dst_init_hash(struct dst_crypto_ctl *ctl, u8 *key)
|
||||
{
|
||||
int err;
|
||||
struct crypto_hash *hash;
|
||||
|
||||
hash = crypto_alloc_hash(ctl->hash_algo, 0, CRYPTO_ALG_ASYNC);
|
||||
if (IS_ERR(hash)) {
|
||||
err = PTR_ERR(hash);
|
||||
dprintk("%s: failed to allocate hash '%s', err: %d.\n",
|
||||
__func__, ctl->hash_algo, err);
|
||||
goto err_out_exit;
|
||||
}
|
||||
|
||||
ctl->crypto_attached_size = crypto_hash_digestsize(hash);
|
||||
|
||||
if (!ctl->hash_keysize)
|
||||
return hash;
|
||||
|
||||
err = crypto_hash_setkey(hash, key, ctl->hash_keysize);
|
||||
if (err) {
|
||||
dprintk("%s: failed to set key for hash '%s', err: %d.\n",
|
||||
__func__, ctl->hash_algo, err);
|
||||
goto err_out_free;
|
||||
}
|
||||
|
||||
return hash;
|
||||
|
||||
err_out_free:
|
||||
crypto_free_hash(hash);
|
||||
err_out_exit:
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
static struct crypto_ablkcipher *dst_init_cipher(struct dst_crypto_ctl *ctl,
|
||||
u8 *key)
|
||||
{
|
||||
int err = -EINVAL;
|
||||
struct crypto_ablkcipher *cipher;
|
||||
|
||||
if (!ctl->cipher_keysize)
|
||||
goto err_out_exit;
|
||||
|
||||
cipher = crypto_alloc_ablkcipher(ctl->cipher_algo, 0, 0);
|
||||
if (IS_ERR(cipher)) {
|
||||
err = PTR_ERR(cipher);
|
||||
dprintk("%s: failed to allocate cipher '%s', err: %d.\n",
|
||||
__func__, ctl->cipher_algo, err);
|
||||
goto err_out_exit;
|
||||
}
|
||||
|
||||
crypto_ablkcipher_clear_flags(cipher, ~0);
|
||||
|
||||
err = crypto_ablkcipher_setkey(cipher, key, ctl->cipher_keysize);
|
||||
if (err) {
|
||||
dprintk("%s: failed to set key for cipher '%s', err: %d.\n",
|
||||
__func__, ctl->cipher_algo, err);
|
||||
goto err_out_free;
|
||||
}
|
||||
|
||||
return cipher;
|
||||
|
||||
err_out_free:
|
||||
crypto_free_ablkcipher(cipher);
|
||||
err_out_exit:
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
/*
|
||||
* Crypto engine has a pool of pages to encrypt data into before sending
|
||||
* it over the network. This pool is freed/allocated here.
|
||||
*/
|
||||
static void dst_crypto_pages_free(struct dst_crypto_engine *e)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < e->page_num; ++i)
|
||||
__free_page(e->pages[i]);
|
||||
kfree(e->pages);
|
||||
}
|
||||
|
||||
static int dst_crypto_pages_alloc(struct dst_crypto_engine *e, int num)
|
||||
{
|
||||
int i;
|
||||
|
||||
e->pages = kmalloc(num * sizeof(struct page **), GFP_KERNEL);
|
||||
if (!e->pages)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < num; ++i) {
|
||||
e->pages[i] = alloc_page(GFP_KERNEL);
|
||||
if (!e->pages[i])
|
||||
goto err_out_free_pages;
|
||||
}
|
||||
|
||||
e->page_num = num;
|
||||
return 0;
|
||||
|
||||
err_out_free_pages:
|
||||
while (--i >= 0)
|
||||
__free_page(e->pages[i]);
|
||||
|
||||
kfree(e->pages);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize crypto engine for given node.
|
||||
* Setup cipher/hash, keys, pool of threads and private data.
|
||||
*/
|
||||
static int dst_crypto_engine_init(struct dst_crypto_engine *e,
|
||||
struct dst_node *n)
|
||||
{
|
||||
int err;
|
||||
struct dst_crypto_ctl *ctl = &n->crypto;
|
||||
|
||||
err = dst_crypto_pages_alloc(e, n->max_pages);
|
||||
if (err)
|
||||
goto err_out_exit;
|
||||
|
||||
e->size = PAGE_SIZE;
|
||||
e->data = kmalloc(e->size, GFP_KERNEL);
|
||||
if (!e->data) {
|
||||
err = -ENOMEM;
|
||||
goto err_out_free_pages;
|
||||
}
|
||||
|
||||
if (ctl->hash_algo[0]) {
|
||||
e->hash = dst_init_hash(ctl, n->hash_key);
|
||||
if (IS_ERR(e->hash)) {
|
||||
err = PTR_ERR(e->hash);
|
||||
e->hash = NULL;
|
||||
goto err_out_free;
|
||||
}
|
||||
}
|
||||
|
||||
if (ctl->cipher_algo[0]) {
|
||||
e->cipher = dst_init_cipher(ctl, n->cipher_key);
|
||||
if (IS_ERR(e->cipher)) {
|
||||
err = PTR_ERR(e->cipher);
|
||||
e->cipher = NULL;
|
||||
goto err_out_free_hash;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_out_free_hash:
|
||||
crypto_free_hash(e->hash);
|
||||
err_out_free:
|
||||
kfree(e->data);
|
||||
err_out_free_pages:
|
||||
dst_crypto_pages_free(e);
|
||||
err_out_exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
static void dst_crypto_engine_exit(struct dst_crypto_engine *e)
|
||||
{
|
||||
if (e->hash)
|
||||
crypto_free_hash(e->hash);
|
||||
if (e->cipher)
|
||||
crypto_free_ablkcipher(e->cipher);
|
||||
dst_crypto_pages_free(e);
|
||||
kfree(e->data);
|
||||
}
|
||||
|
||||
/*
|
||||
* Waiting for cipher processing to be completed.
|
||||
*/
|
||||
struct dst_crypto_completion {
|
||||
struct completion complete;
|
||||
int error;
|
||||
};
|
||||
|
||||
static void dst_crypto_complete(struct crypto_async_request *req, int err)
|
||||
{
|
||||
struct dst_crypto_completion *c = req->data;
|
||||
|
||||
if (err == -EINPROGRESS)
|
||||
return;
|
||||
|
||||
dprintk("%s: req: %p, err: %d.\n", __func__, req, err);
|
||||
c->error = err;
|
||||
complete(&c->complete);
|
||||
}
|
||||
|
||||
static int dst_crypto_process(struct ablkcipher_request *req,
|
||||
struct scatterlist *sg_dst, struct scatterlist *sg_src,
|
||||
void *iv, int enc, unsigned long timeout)
|
||||
{
|
||||
struct dst_crypto_completion c;
|
||||
int err;
|
||||
|
||||
init_completion(&c.complete);
|
||||
c.error = -EINPROGRESS;
|
||||
|
||||
ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
|
||||
dst_crypto_complete, &c);
|
||||
|
||||
ablkcipher_request_set_crypt(req, sg_src, sg_dst, sg_src->length, iv);
|
||||
|
||||
if (enc)
|
||||
err = crypto_ablkcipher_encrypt(req);
|
||||
else
|
||||
err = crypto_ablkcipher_decrypt(req);
|
||||
|
||||
switch (err) {
|
||||
case -EINPROGRESS:
|
||||
case -EBUSY:
|
||||
err = wait_for_completion_interruptible_timeout(&c.complete,
|
||||
timeout);
|
||||
if (!err)
|
||||
err = -ETIMEDOUT;
|
||||
else
|
||||
err = c.error;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* DST uses generic iteration approach for data crypto processing.
|
||||
* Single block IO request is switched into array of scatterlists,
|
||||
* which are submitted to the crypto processing iterator.
|
||||
*
|
||||
* Input and output iterator initialization are different, since
|
||||
* in output case we can not encrypt data in-place and need a
|
||||
* temporary storage, which is then being sent to the remote peer.
|
||||
*/
|
||||
static int dst_trans_iter_out(struct bio *bio, struct dst_crypto_engine *e,
|
||||
int (*iterator) (struct dst_crypto_engine *e,
|
||||
struct scatterlist *dst,
|
||||
struct scatterlist *src))
|
||||
{
|
||||
struct bio_vec *bv;
|
||||
int err, i;
|
||||
|
||||
sg_init_table(e->src, bio->bi_vcnt);
|
||||
sg_init_table(e->dst, bio->bi_vcnt);
|
||||
|
||||
bio_for_each_segment(bv, bio, i) {
|
||||
sg_set_page(&e->src[i], bv->bv_page, bv->bv_len, bv->bv_offset);
|
||||
sg_set_page(&e->dst[i], e->pages[i], bv->bv_len, bv->bv_offset);
|
||||
|
||||
err = iterator(e, &e->dst[i], &e->src[i]);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dst_trans_iter_in(struct bio *bio, struct dst_crypto_engine *e,
|
||||
int (*iterator) (struct dst_crypto_engine *e,
|
||||
struct scatterlist *dst,
|
||||
struct scatterlist *src))
|
||||
{
|
||||
struct bio_vec *bv;
|
||||
int err, i;
|
||||
|
||||
sg_init_table(e->src, bio->bi_vcnt);
|
||||
sg_init_table(e->dst, bio->bi_vcnt);
|
||||
|
||||
bio_for_each_segment(bv, bio, i) {
|
||||
sg_set_page(&e->src[i], bv->bv_page, bv->bv_len, bv->bv_offset);
|
||||
sg_set_page(&e->dst[i], bv->bv_page, bv->bv_len, bv->bv_offset);
|
||||
|
||||
err = iterator(e, &e->dst[i], &e->src[i]);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dst_crypt_iterator(struct dst_crypto_engine *e,
|
||||
struct scatterlist *sg_dst, struct scatterlist *sg_src)
|
||||
{
|
||||
struct ablkcipher_request *req = e->data;
|
||||
u8 iv[32];
|
||||
|
||||
memset(iv, 0, sizeof(iv));
|
||||
|
||||
memcpy(iv, &e->iv, sizeof(e->iv));
|
||||
|
||||
return dst_crypto_process(req, sg_dst, sg_src, iv, e->enc, e->timeout);
|
||||
}
|
||||
|
||||
static int dst_crypt(struct dst_crypto_engine *e, struct bio *bio)
|
||||
{
|
||||
struct ablkcipher_request *req = e->data;
|
||||
|
||||
memset(req, 0, sizeof(struct ablkcipher_request));
|
||||
ablkcipher_request_set_tfm(req, e->cipher);
|
||||
|
||||
if (e->enc)
|
||||
return dst_trans_iter_out(bio, e, dst_crypt_iterator);
|
||||
else
|
||||
return dst_trans_iter_in(bio, e, dst_crypt_iterator);
|
||||
}
|
||||
|
||||
static int dst_hash_iterator(struct dst_crypto_engine *e,
|
||||
struct scatterlist *sg_dst, struct scatterlist *sg_src)
|
||||
{
|
||||
return crypto_hash_update(e->data, sg_src, sg_src->length);
|
||||
}
|
||||
|
||||
static int dst_hash(struct dst_crypto_engine *e, struct bio *bio, void *dst)
|
||||
{
|
||||
struct hash_desc *desc = e->data;
|
||||
int err;
|
||||
|
||||
desc->tfm = e->hash;
|
||||
desc->flags = 0;
|
||||
|
||||
err = crypto_hash_init(desc);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = dst_trans_iter_in(bio, e, dst_hash_iterator);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = crypto_hash_final(desc, dst);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize/cleanup a crypto thread. The only thing it should
|
||||
* do is to allocate a pool of pages as temporary storage.
|
||||
* And to setup cipher and/or hash.
|
||||
*/
|
||||
static void *dst_crypto_thread_init(void *data)
|
||||
{
|
||||
struct dst_node *n = data;
|
||||
struct dst_crypto_engine *e;
|
||||
int err = -ENOMEM;
|
||||
|
||||
e = kzalloc(sizeof(struct dst_crypto_engine), GFP_KERNEL);
|
||||
if (!e)
|
||||
goto err_out_exit;
|
||||
e->src = kcalloc(2 * n->max_pages, sizeof(struct scatterlist),
|
||||
GFP_KERNEL);
|
||||
if (!e->src)
|
||||
goto err_out_free;
|
||||
|
||||
e->dst = e->src + n->max_pages;
|
||||
|
||||
err = dst_crypto_engine_init(e, n);
|
||||
if (err)
|
||||
goto err_out_free_all;
|
||||
|
||||
return e;
|
||||
|
||||
err_out_free_all:
|
||||
kfree(e->src);
|
||||
err_out_free:
|
||||
kfree(e);
|
||||
err_out_exit:
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
static void dst_crypto_thread_cleanup(void *private)
|
||||
{
|
||||
struct dst_crypto_engine *e = private;
|
||||
|
||||
dst_crypto_engine_exit(e);
|
||||
kfree(e->src);
|
||||
kfree(e);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize crypto engine for given node: store keys, create pool
|
||||
* of threads, initialize each one.
|
||||
*
|
||||
* Each thread has unique ID, but 0 and 1 are reserved for receiving and
|
||||
* accepting threads (if export node), so IDs could start from 2, but starting
|
||||
* them from 10 allows easily understand what this thread is for.
|
||||
*/
|
||||
int dst_node_crypto_init(struct dst_node *n, struct dst_crypto_ctl *ctl)
|
||||
{
|
||||
void *key = (ctl + 1);
|
||||
int err = -ENOMEM, i;
|
||||
char name[32];
|
||||
|
||||
if (ctl->hash_keysize) {
|
||||
n->hash_key = kmalloc(ctl->hash_keysize, GFP_KERNEL);
|
||||
if (!n->hash_key)
|
||||
goto err_out_exit;
|
||||
memcpy(n->hash_key, key, ctl->hash_keysize);
|
||||
}
|
||||
|
||||
if (ctl->cipher_keysize) {
|
||||
n->cipher_key = kmalloc(ctl->cipher_keysize, GFP_KERNEL);
|
||||
if (!n->cipher_key)
|
||||
goto err_out_free_hash;
|
||||
memcpy(n->cipher_key, key, ctl->cipher_keysize);
|
||||
}
|
||||
memcpy(&n->crypto, ctl, sizeof(struct dst_crypto_ctl));
|
||||
|
||||
for (i = 0; i < ctl->thread_num; ++i) {
|
||||
snprintf(name, sizeof(name), "%s-crypto-%d", n->name, i);
|
||||
/* Unique ids... */
|
||||
err = thread_pool_add_worker(n->pool, name, i + 10,
|
||||
dst_crypto_thread_init, dst_crypto_thread_cleanup, n);
|
||||
if (err)
|
||||
goto err_out_free_threads;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_out_free_threads:
|
||||
while (--i >= 0)
|
||||
thread_pool_del_worker_id(n->pool, i+10);
|
||||
|
||||
if (ctl->cipher_keysize)
|
||||
kfree(n->cipher_key);
|
||||
ctl->cipher_keysize = 0;
|
||||
err_out_free_hash:
|
||||
if (ctl->hash_keysize)
|
||||
kfree(n->hash_key);
|
||||
ctl->hash_keysize = 0;
|
||||
err_out_exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
void dst_node_crypto_exit(struct dst_node *n)
|
||||
{
|
||||
struct dst_crypto_ctl *ctl = &n->crypto;
|
||||
|
||||
if (ctl->cipher_algo[0] || ctl->hash_algo[0]) {
|
||||
kfree(n->hash_key);
|
||||
kfree(n->cipher_key);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Thrad pool setup callback. Just stores a transaction in private data.
|
||||
*/
|
||||
static int dst_trans_crypto_setup(void *crypto_engine, void *trans)
|
||||
{
|
||||
struct dst_crypto_engine *e = crypto_engine;
|
||||
|
||||
e->private = trans;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void dst_dump_bio(struct bio *bio)
|
||||
{
|
||||
u8 *p;
|
||||
struct bio_vec *bv;
|
||||
int i;
|
||||
|
||||
bio_for_each_segment(bv, bio, i) {
|
||||
dprintk("%s: %llu/%u: size: %u, offset: %u, data: ",
|
||||
__func__, bio->bi_sector, bio->bi_size,
|
||||
bv->bv_len, bv->bv_offset);
|
||||
|
||||
p = kmap(bv->bv_page) + bv->bv_offset;
|
||||
for (i = 0; i < bv->bv_len; ++i)
|
||||
printk(KERN_DEBUG "%02x ", p[i]);
|
||||
kunmap(bv->bv_page);
|
||||
printk("\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Encrypt/hash data and send it to the network.
|
||||
*/
|
||||
static int dst_crypto_process_sending(struct dst_crypto_engine *e,
|
||||
struct bio *bio, u8 *hash)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (e->cipher) {
|
||||
err = dst_crypt(e, bio);
|
||||
if (err)
|
||||
goto err_out_exit;
|
||||
}
|
||||
|
||||
if (e->hash) {
|
||||
err = dst_hash(e, bio, hash);
|
||||
if (err)
|
||||
goto err_out_exit;
|
||||
|
||||
#ifdef CONFIG_DST_DEBUG
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
/* dst_dump_bio(bio); */
|
||||
|
||||
printk(KERN_DEBUG "%s: bio: %llu/%u, rw: %lu, hash: ",
|
||||
__func__, (u64)bio->bi_sector,
|
||||
bio->bi_size, bio_data_dir(bio));
|
||||
for (i = 0; i < crypto_hash_digestsize(e->hash); ++i)
|
||||
printk("%02x ", hash[i]);
|
||||
printk("\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_out_exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if received data is valid. Decipher if it is.
|
||||
*/
|
||||
static int dst_crypto_process_receiving(struct dst_crypto_engine *e,
|
||||
struct bio *bio, u8 *hash, u8 *recv_hash)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (e->hash) {
|
||||
int mismatch;
|
||||
|
||||
err = dst_hash(e, bio, hash);
|
||||
if (err)
|
||||
goto err_out_exit;
|
||||
|
||||
mismatch = !!memcmp(recv_hash, hash,
|
||||
crypto_hash_digestsize(e->hash));
|
||||
#ifdef CONFIG_DST_DEBUG
|
||||
/* dst_dump_bio(bio); */
|
||||
|
||||
printk(KERN_DEBUG "%s: bio: %llu/%u, rw: %lu, hash mismatch: %d",
|
||||
__func__, (u64)bio->bi_sector, bio->bi_size,
|
||||
bio_data_dir(bio), mismatch);
|
||||
if (mismatch) {
|
||||
unsigned int i;
|
||||
|
||||
printk(", recv/calc: ");
|
||||
for (i = 0; i < crypto_hash_digestsize(e->hash); ++i)
|
||||
printk("%02x/%02x ", recv_hash[i], hash[i]);
|
||||
|
||||
}
|
||||
printk("\n");
|
||||
#endif
|
||||
err = -1;
|
||||
if (mismatch)
|
||||
goto err_out_exit;
|
||||
}
|
||||
|
||||
if (e->cipher) {
|
||||
err = dst_crypt(e, bio);
|
||||
if (err)
|
||||
goto err_out_exit;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_out_exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Thread pool callback to encrypt data and send it to the netowork.
|
||||
*/
|
||||
static int dst_trans_crypto_action(void *crypto_engine, void *schedule_data)
|
||||
{
|
||||
struct dst_crypto_engine *e = crypto_engine;
|
||||
struct dst_trans *t = schedule_data;
|
||||
struct bio *bio = t->bio;
|
||||
int err;
|
||||
|
||||
dprintk("%s: t: %p, gen: %llu, cipher: %p, hash: %p.\n",
|
||||
__func__, t, t->gen, e->cipher, e->hash);
|
||||
|
||||
e->enc = t->enc;
|
||||
e->iv = dst_gen_iv(t);
|
||||
|
||||
if (bio_data_dir(bio) == WRITE) {
|
||||
err = dst_crypto_process_sending(e, bio, t->cmd.hash);
|
||||
if (err)
|
||||
goto err_out_exit;
|
||||
|
||||
if (e->hash) {
|
||||
t->cmd.csize = crypto_hash_digestsize(e->hash);
|
||||
t->cmd.size += t->cmd.csize;
|
||||
}
|
||||
|
||||
return dst_trans_send(t);
|
||||
} else {
|
||||
u8 *hash = e->data + e->size/2;
|
||||
|
||||
err = dst_crypto_process_receiving(e, bio, hash, t->cmd.hash);
|
||||
if (err)
|
||||
goto err_out_exit;
|
||||
|
||||
dst_trans_remove(t);
|
||||
dst_trans_put(t);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_out_exit:
|
||||
t->error = err;
|
||||
dst_trans_put(t);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Schedule crypto processing for given transaction.
|
||||
*/
|
||||
int dst_trans_crypto(struct dst_trans *t)
|
||||
{
|
||||
struct dst_node *n = t->n;
|
||||
int err;
|
||||
|
||||
err = thread_pool_schedule(n->pool,
|
||||
dst_trans_crypto_setup, dst_trans_crypto_action,
|
||||
t, MAX_SCHEDULE_TIMEOUT);
|
||||
if (err)
|
||||
goto err_out_exit;
|
||||
|
||||
return 0;
|
||||
|
||||
err_out_exit:
|
||||
dst_trans_put(t);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Crypto machinery for the export node.
|
||||
*/
|
||||
static int dst_export_crypto_setup(void *crypto_engine, void *bio)
|
||||
{
|
||||
struct dst_crypto_engine *e = crypto_engine;
|
||||
|
||||
e->private = bio;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dst_export_crypto_action(void *crypto_engine, void *schedule_data)
|
||||
{
|
||||
struct dst_crypto_engine *e = crypto_engine;
|
||||
struct bio *bio = schedule_data;
|
||||
struct dst_export_priv *p = bio->bi_private;
|
||||
int err;
|
||||
|
||||
dprintk("%s: e: %p, data: %p, bio: %llu/%u, dir: %lu.\n",
|
||||
__func__, e, e->data, (u64)bio->bi_sector,
|
||||
bio->bi_size, bio_data_dir(bio));
|
||||
|
||||
e->enc = (bio_data_dir(bio) == READ);
|
||||
e->iv = p->cmd.id;
|
||||
|
||||
if (bio_data_dir(bio) == WRITE) {
|
||||
u8 *hash = e->data + e->size/2;
|
||||
|
||||
err = dst_crypto_process_receiving(e, bio, hash, p->cmd.hash);
|
||||
if (err)
|
||||
goto err_out_exit;
|
||||
|
||||
generic_make_request(bio);
|
||||
} else {
|
||||
err = dst_crypto_process_sending(e, bio, p->cmd.hash);
|
||||
if (err)
|
||||
goto err_out_exit;
|
||||
|
||||
if (e->hash) {
|
||||
p->cmd.csize = crypto_hash_digestsize(e->hash);
|
||||
p->cmd.size += p->cmd.csize;
|
||||
}
|
||||
|
||||
err = dst_export_send_bio(bio);
|
||||
}
|
||||
return 0;
|
||||
|
||||
err_out_exit:
|
||||
bio_put(bio);
|
||||
return err;
|
||||
}
|
||||
|
||||
int dst_export_crypto(struct dst_node *n, struct bio *bio)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = thread_pool_schedule(n->pool,
|
||||
dst_export_crypto_setup, dst_export_crypto_action,
|
||||
bio, MAX_SCHEDULE_TIMEOUT);
|
||||
if (err)
|
||||
goto err_out_exit;
|
||||
|
||||
return 0;
|
||||
|
||||
err_out_exit:
|
||||
bio_put(bio);
|
||||
return err;
|
||||
}
|
|
@ -1,968 +0,0 @@
|
|||
/*
|
||||
* 2007+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net>
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/bio.h>
|
||||
#include <linux/buffer_head.h>
|
||||
#include <linux/connector.h>
|
||||
#include <linux/dst.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/jhash.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/namei.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/socket.h>
|
||||
|
||||
#include <linux/in.h>
|
||||
#include <linux/in6.h>
|
||||
|
||||
#include <net/sock.h>
|
||||
|
||||
static int dst_major;
|
||||
|
||||
static DEFINE_MUTEX(dst_hash_lock);
|
||||
static struct list_head *dst_hashtable;
|
||||
static unsigned int dst_hashtable_size = 128;
|
||||
module_param(dst_hashtable_size, uint, 0644);
|
||||
|
||||
static char dst_name[] = "Dementianting goldfish";
|
||||
|
||||
static DEFINE_IDR(dst_index_idr);
|
||||
static struct cb_id cn_dst_id = { CN_DST_IDX, CN_DST_VAL };
|
||||
|
||||
/*
|
||||
* DST sysfs tree for device called 'storage':
|
||||
*
|
||||
* /sys/bus/dst/devices/storage/
|
||||
* /sys/bus/dst/devices/storage/type : 192.168.4.80:1025
|
||||
* /sys/bus/dst/devices/storage/size : 800
|
||||
* /sys/bus/dst/devices/storage/name : storage
|
||||
*/
|
||||
|
||||
static int dst_dev_match(struct device *dev, struct device_driver *drv)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct bus_type dst_dev_bus_type = {
|
||||
.name = "dst",
|
||||
.match = &dst_dev_match,
|
||||
};
|
||||
|
||||
static void dst_node_release(struct device *dev)
|
||||
{
|
||||
struct dst_info *info = container_of(dev, struct dst_info, device);
|
||||
|
||||
kfree(info);
|
||||
}
|
||||
|
||||
static struct device dst_node_dev = {
|
||||
.bus = &dst_dev_bus_type,
|
||||
.release = &dst_node_release
|
||||
};
|
||||
|
||||
/*
|
||||
* Setting size of the node after it was changed.
|
||||
*/
|
||||
static void dst_node_set_size(struct dst_node *n)
|
||||
{
|
||||
struct block_device *bdev;
|
||||
|
||||
set_capacity(n->disk, n->size >> 9);
|
||||
|
||||
bdev = bdget_disk(n->disk, 0);
|
||||
if (bdev) {
|
||||
mutex_lock(&bdev->bd_inode->i_mutex);
|
||||
i_size_write(bdev->bd_inode, n->size);
|
||||
mutex_unlock(&bdev->bd_inode->i_mutex);
|
||||
bdput(bdev);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Distributed storage request processing function.
|
||||
*/
|
||||
static int dst_request(struct request_queue *q, struct bio *bio)
|
||||
{
|
||||
struct dst_node *n = q->queuedata;
|
||||
int err = -EIO;
|
||||
|
||||
if (bio_empty_barrier(bio) && !blk_queue_discard(q)) {
|
||||
/*
|
||||
* This is a dirty^Wnice hack, but if we complete this
|
||||
* operation with -EOPNOTSUPP like intended, XFS
|
||||
* will stuck and freeze the machine. This may be
|
||||
* not particulary XFS problem though, but it is the
|
||||
* only FS which sends empty barrier at umount time
|
||||
* I worked with.
|
||||
*
|
||||
* Empty barriers are not allowed anyway, see 51fd77bd9f512
|
||||
* for example, although later it was changed to
|
||||
* bio_rw_flagged(bio, BIO_RW_DISCARD) only, which does not
|
||||
* work in this case.
|
||||
*/
|
||||
/* err = -EOPNOTSUPP; */
|
||||
err = 0;
|
||||
goto end_io;
|
||||
}
|
||||
|
||||
bio_get(bio);
|
||||
|
||||
return dst_process_bio(n, bio);
|
||||
|
||||
end_io:
|
||||
bio_endio(bio, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Open/close callbacks for appropriate block device.
|
||||
*/
|
||||
static int dst_bdev_open(struct block_device *bdev, fmode_t mode)
|
||||
{
|
||||
struct dst_node *n = bdev->bd_disk->private_data;
|
||||
|
||||
dst_node_get(n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dst_bdev_release(struct gendisk *disk, fmode_t mode)
|
||||
{
|
||||
struct dst_node *n = disk->private_data;
|
||||
|
||||
dst_node_put(n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct block_device_operations dst_blk_ops = {
|
||||
.open = dst_bdev_open,
|
||||
.release = dst_bdev_release,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
/*
|
||||
* Block layer binding - disk is created when array is fully configured
|
||||
* by userspace request.
|
||||
*/
|
||||
static int dst_node_create_disk(struct dst_node *n)
|
||||
{
|
||||
int err = -ENOMEM;
|
||||
u32 index = 0;
|
||||
|
||||
n->queue = blk_init_queue(NULL, NULL);
|
||||
if (!n->queue)
|
||||
goto err_out_exit;
|
||||
|
||||
n->queue->queuedata = n;
|
||||
blk_queue_make_request(n->queue, dst_request);
|
||||
blk_queue_max_phys_segments(n->queue, n->max_pages);
|
||||
blk_queue_max_hw_segments(n->queue, n->max_pages);
|
||||
|
||||
err = -ENOMEM;
|
||||
n->disk = alloc_disk(1);
|
||||
if (!n->disk)
|
||||
goto err_out_free_queue;
|
||||
|
||||
if (!(n->state->permissions & DST_PERM_WRITE)) {
|
||||
printk(KERN_INFO "DST node %s attached read-only.\n", n->name);
|
||||
set_disk_ro(n->disk, 1);
|
||||
}
|
||||
|
||||
if (!idr_pre_get(&dst_index_idr, GFP_KERNEL))
|
||||
goto err_out_put;
|
||||
|
||||
mutex_lock(&dst_hash_lock);
|
||||
err = idr_get_new(&dst_index_idr, NULL, &index);
|
||||
mutex_unlock(&dst_hash_lock);
|
||||
if (err)
|
||||
goto err_out_put;
|
||||
|
||||
n->disk->major = dst_major;
|
||||
n->disk->first_minor = index;
|
||||
n->disk->fops = &dst_blk_ops;
|
||||
n->disk->queue = n->queue;
|
||||
n->disk->private_data = n;
|
||||
snprintf(n->disk->disk_name, sizeof(n->disk->disk_name),
|
||||
"dst-%s", n->name);
|
||||
|
||||
return 0;
|
||||
|
||||
err_out_put:
|
||||
put_disk(n->disk);
|
||||
err_out_free_queue:
|
||||
blk_cleanup_queue(n->queue);
|
||||
err_out_exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sysfs machinery: show device's size.
|
||||
*/
|
||||
static ssize_t dst_show_size(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct dst_info *info = container_of(dev, struct dst_info, device);
|
||||
|
||||
return sprintf(buf, "%llu\n", info->size);
|
||||
}
|
||||
|
||||
/*
|
||||
* Show local exported device.
|
||||
*/
|
||||
static ssize_t dst_show_local(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct dst_info *info = container_of(dev, struct dst_info, device);
|
||||
|
||||
return sprintf(buf, "%s\n", info->local);
|
||||
}
|
||||
|
||||
/*
|
||||
* Shows type of the remote node - device major/minor number
|
||||
* for local nodes and address (af_inet ipv4/ipv6 only) for remote nodes.
|
||||
*/
|
||||
static ssize_t dst_show_type(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct dst_info *info = container_of(dev, struct dst_info, device);
|
||||
int family = info->net.addr.sa_family;
|
||||
|
||||
if (family == AF_INET) {
|
||||
struct sockaddr_in *sin = (struct sockaddr_in *)&info->net.addr;
|
||||
return sprintf(buf, "%u.%u.%u.%u:%d\n",
|
||||
NIPQUAD(sin->sin_addr.s_addr), ntohs(sin->sin_port));
|
||||
} else if (family == AF_INET6) {
|
||||
struct sockaddr_in6 *sin = (struct sockaddr_in6 *)
|
||||
&info->net.addr;
|
||||
return sprintf(buf,
|
||||
"%pi6:%d\n",
|
||||
&sin->sin6_addr, ntohs(sin->sin6_port));
|
||||
} else {
|
||||
int i, sz = PAGE_SIZE - 2; /* 0 symbol and '\n' below */
|
||||
int size, addrlen = info->net.addr.sa_data_len;
|
||||
unsigned char *a = (unsigned char *)&info->net.addr.sa_data;
|
||||
char *buf_orig = buf;
|
||||
|
||||
size = snprintf(buf, sz, "family: %d, addrlen: %u, addr: ",
|
||||
family, addrlen);
|
||||
sz -= size;
|
||||
buf += size;
|
||||
|
||||
for (i = 0; i < addrlen; ++i) {
|
||||
if (sz < 3)
|
||||
break;
|
||||
|
||||
size = snprintf(buf, sz, "%02x ", a[i]);
|
||||
sz -= size;
|
||||
buf += size;
|
||||
}
|
||||
buf += sprintf(buf, "\n");
|
||||
|
||||
return buf - buf_orig;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct device_attribute dst_node_attrs[] = {
|
||||
__ATTR(size, 0444, dst_show_size, NULL),
|
||||
__ATTR(type, 0444, dst_show_type, NULL),
|
||||
__ATTR(local, 0444, dst_show_local, NULL),
|
||||
};
|
||||
|
||||
static int dst_create_node_attributes(struct dst_node *n)
|
||||
{
|
||||
int err, i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(dst_node_attrs); ++i) {
|
||||
err = device_create_file(&n->info->device,
|
||||
&dst_node_attrs[i]);
|
||||
if (err)
|
||||
goto err_out_remove_all;
|
||||
}
|
||||
return 0;
|
||||
|
||||
err_out_remove_all:
|
||||
while (--i >= 0)
|
||||
device_remove_file(&n->info->device,
|
||||
&dst_node_attrs[i]);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void dst_remove_node_attributes(struct dst_node *n)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(dst_node_attrs); ++i)
|
||||
device_remove_file(&n->info->device,
|
||||
&dst_node_attrs[i]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sysfs cleanup and initialization.
|
||||
* Shows number of useful parameters.
|
||||
*/
|
||||
static void dst_node_sysfs_exit(struct dst_node *n)
|
||||
{
|
||||
if (n->info) {
|
||||
dst_remove_node_attributes(n);
|
||||
device_unregister(&n->info->device);
|
||||
n->info = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int dst_node_sysfs_init(struct dst_node *n)
|
||||
{
|
||||
int err;
|
||||
|
||||
n->info = kzalloc(sizeof(struct dst_info), GFP_KERNEL);
|
||||
if (!n->info)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(&n->info->device, &dst_node_dev, sizeof(struct device));
|
||||
n->info->size = n->size;
|
||||
|
||||
dev_set_name(&n->info->device, "dst-%s", n->name);
|
||||
err = device_register(&n->info->device);
|
||||
if (err) {
|
||||
dprintk(KERN_ERR "Failed to register node '%s', err: %d.\n",
|
||||
n->name, err);
|
||||
goto err_out_exit;
|
||||
}
|
||||
|
||||
dst_create_node_attributes(n);
|
||||
|
||||
return 0;
|
||||
|
||||
err_out_exit:
|
||||
kfree(n->info);
|
||||
n->info = NULL;
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* DST node hash tables machinery.
|
||||
*/
|
||||
static inline unsigned int dst_hash(char *str, unsigned int size)
|
||||
{
|
||||
return jhash(str, size, 0) % dst_hashtable_size;
|
||||
}
|
||||
|
||||
static void dst_node_remove(struct dst_node *n)
|
||||
{
|
||||
mutex_lock(&dst_hash_lock);
|
||||
list_del_init(&n->node_entry);
|
||||
mutex_unlock(&dst_hash_lock);
|
||||
}
|
||||
|
||||
static void dst_node_add(struct dst_node *n)
|
||||
{
|
||||
unsigned hash = dst_hash(n->name, sizeof(n->name));
|
||||
|
||||
mutex_lock(&dst_hash_lock);
|
||||
list_add_tail(&n->node_entry, &dst_hashtable[hash]);
|
||||
mutex_unlock(&dst_hash_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Cleaning node when it is about to be freed.
|
||||
* There are still users of the socket though,
|
||||
* so connection cleanup should be protected.
|
||||
*/
|
||||
static void dst_node_cleanup(struct dst_node *n)
|
||||
{
|
||||
struct dst_state *st = n->state;
|
||||
|
||||
if (!st)
|
||||
return;
|
||||
|
||||
if (n->queue) {
|
||||
blk_cleanup_queue(n->queue);
|
||||
|
||||
mutex_lock(&dst_hash_lock);
|
||||
idr_remove(&dst_index_idr, n->disk->first_minor);
|
||||
mutex_unlock(&dst_hash_lock);
|
||||
|
||||
put_disk(n->disk);
|
||||
}
|
||||
|
||||
if (n->bdev) {
|
||||
sync_blockdev(n->bdev);
|
||||
close_bdev_exclusive(n->bdev, FMODE_READ|FMODE_WRITE);
|
||||
}
|
||||
|
||||
dst_state_lock(st);
|
||||
st->need_exit = 1;
|
||||
dst_state_exit_connected(st);
|
||||
dst_state_unlock(st);
|
||||
|
||||
wake_up(&st->thread_wait);
|
||||
|
||||
dst_state_put(st);
|
||||
n->state = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free security attributes attached to given node.
|
||||
*/
|
||||
static void dst_security_exit(struct dst_node *n)
|
||||
{
|
||||
struct dst_secure *s, *tmp;
|
||||
|
||||
list_for_each_entry_safe(s, tmp, &n->security_list, sec_entry) {
|
||||
list_del(&s->sec_entry);
|
||||
kfree(s);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Free node when there are no more users.
|
||||
* Actually node has to be freed on behalf od userspace process,
|
||||
* since there are number of threads, which are embedded in the
|
||||
* node, so they can not exit and free node from there, that is
|
||||
* why there is a wakeup if reference counter is not equal to zero.
|
||||
*/
|
||||
void dst_node_put(struct dst_node *n)
|
||||
{
|
||||
if (unlikely(!n))
|
||||
return;
|
||||
|
||||
dprintk("%s: n: %p, refcnt: %d.\n",
|
||||
__func__, n, atomic_read(&n->refcnt));
|
||||
|
||||
if (atomic_dec_and_test(&n->refcnt)) {
|
||||
dst_node_remove(n);
|
||||
n->trans_scan_timeout = 0;
|
||||
dst_node_cleanup(n);
|
||||
thread_pool_destroy(n->pool);
|
||||
dst_node_sysfs_exit(n);
|
||||
dst_node_crypto_exit(n);
|
||||
dst_security_exit(n);
|
||||
dst_node_trans_exit(n);
|
||||
|
||||
kfree(n);
|
||||
|
||||
dprintk("%s: freed n: %p.\n", __func__, n);
|
||||
} else {
|
||||
wake_up(&n->wait);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Setting up export device: lookup by the name, get its size
|
||||
* and setup listening socket, which will accept clients, which
|
||||
* will submit IO for given storage.
|
||||
*/
|
||||
static int dst_setup_export(struct dst_node *n, struct dst_ctl *ctl,
|
||||
struct dst_export_ctl *le)
|
||||
{
|
||||
int err;
|
||||
|
||||
snprintf(n->info->local, sizeof(n->info->local), "%s", le->device);
|
||||
|
||||
n->bdev = open_bdev_exclusive(le->device, FMODE_READ|FMODE_WRITE, NULL);
|
||||
if (IS_ERR(n->bdev))
|
||||
return PTR_ERR(n->bdev);
|
||||
|
||||
if (n->size != 0)
|
||||
n->size = min_t(loff_t, n->bdev->bd_inode->i_size, n->size);
|
||||
else
|
||||
n->size = n->bdev->bd_inode->i_size;
|
||||
|
||||
n->info->size = n->size;
|
||||
err = dst_node_init_listened(n, le);
|
||||
if (err)
|
||||
goto err_out_cleanup;
|
||||
|
||||
return 0;
|
||||
|
||||
err_out_cleanup:
|
||||
close_bdev_exclusive(n->bdev, FMODE_READ|FMODE_WRITE);
|
||||
n->bdev = NULL;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Empty thread pool callbacks for the network processing threads. */
|
||||
static inline void *dst_thread_network_init(void *data)
|
||||
{
|
||||
dprintk("%s: data: %p.\n", __func__, data);
|
||||
return data;
|
||||
}
|
||||
|
||||
static inline void dst_thread_network_cleanup(void *data)
|
||||
{
|
||||
dprintk("%s: data: %p.\n", __func__, data);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate DST node and initialize some of its parameters.
|
||||
*/
|
||||
static struct dst_node *dst_alloc_node(struct dst_ctl *ctl,
|
||||
int (*start)(struct dst_node *),
|
||||
int num)
|
||||
{
|
||||
struct dst_node *n;
|
||||
int err;
|
||||
|
||||
n = kzalloc(sizeof(struct dst_node), GFP_KERNEL);
|
||||
if (!n)
|
||||
return NULL;
|
||||
|
||||
INIT_LIST_HEAD(&n->node_entry);
|
||||
|
||||
INIT_LIST_HEAD(&n->security_list);
|
||||
mutex_init(&n->security_lock);
|
||||
|
||||
init_waitqueue_head(&n->wait);
|
||||
|
||||
n->trans_scan_timeout = msecs_to_jiffies(ctl->trans_scan_timeout);
|
||||
if (!n->trans_scan_timeout)
|
||||
n->trans_scan_timeout = HZ;
|
||||
|
||||
n->trans_max_retries = ctl->trans_max_retries;
|
||||
if (!n->trans_max_retries)
|
||||
n->trans_max_retries = 10;
|
||||
|
||||
/*
|
||||
* Pretty much arbitrary default numbers.
|
||||
* 32 matches maximum number of pages in bio originated from ext3 (31).
|
||||
*/
|
||||
n->max_pages = ctl->max_pages;
|
||||
if (!n->max_pages)
|
||||
n->max_pages = 32;
|
||||
|
||||
if (n->max_pages > 1024)
|
||||
n->max_pages = 1024;
|
||||
|
||||
n->start = start;
|
||||
n->size = ctl->size;
|
||||
|
||||
atomic_set(&n->refcnt, 1);
|
||||
atomic_long_set(&n->gen, 0);
|
||||
snprintf(n->name, sizeof(n->name), "%s", ctl->name);
|
||||
|
||||
err = dst_node_sysfs_init(n);
|
||||
if (err)
|
||||
goto err_out_free;
|
||||
|
||||
n->pool = thread_pool_create(num, n->name, dst_thread_network_init,
|
||||
dst_thread_network_cleanup, n);
|
||||
if (IS_ERR(n->pool)) {
|
||||
err = PTR_ERR(n->pool);
|
||||
goto err_out_sysfs_exit;
|
||||
}
|
||||
|
||||
dprintk("%s: n: %p, name: %s.\n", __func__, n, n->name);
|
||||
|
||||
return n;
|
||||
|
||||
err_out_sysfs_exit:
|
||||
dst_node_sysfs_exit(n);
|
||||
err_out_free:
|
||||
kfree(n);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Starting a node, connected to the remote server:
|
||||
* register block device and initialize transaction mechanism.
|
||||
* In revers order though.
|
||||
*
|
||||
* It will autonegotiate some parameters with the remote node
|
||||
* and update local if needed.
|
||||
*
|
||||
* Transaction initialization should be the last thing before
|
||||
* starting the node, since transaction should include not only
|
||||
* block IO, but also crypto related data (if any), which are
|
||||
* initialized separately.
|
||||
*/
|
||||
static int dst_start_remote(struct dst_node *n)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = dst_node_trans_init(n, sizeof(struct dst_trans));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = dst_node_create_disk(n);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
dst_node_set_size(n);
|
||||
add_disk(n->disk);
|
||||
|
||||
dprintk("DST: started remote node '%s', minor: %d.\n",
|
||||
n->name, n->disk->first_minor);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Adding remote node and initialize connection.
|
||||
*/
|
||||
static int dst_add_remote(struct dst_node *n, struct dst_ctl *ctl,
|
||||
void *data, unsigned int size)
|
||||
{
|
||||
int err;
|
||||
struct dst_network_ctl *rctl = data;
|
||||
|
||||
if (n)
|
||||
return -EEXIST;
|
||||
|
||||
if (size != sizeof(struct dst_network_ctl))
|
||||
return -EINVAL;
|
||||
|
||||
n = dst_alloc_node(ctl, dst_start_remote, 1);
|
||||
if (!n)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(&n->info->net, rctl, sizeof(struct dst_network_ctl));
|
||||
err = dst_node_init_connected(n, rctl);
|
||||
if (err)
|
||||
goto err_out_free;
|
||||
|
||||
dst_node_add(n);
|
||||
|
||||
return 0;
|
||||
|
||||
err_out_free:
|
||||
dst_node_put(n);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Adding export node: initializing block device and listening socket.
|
||||
*/
|
||||
static int dst_add_export(struct dst_node *n, struct dst_ctl *ctl,
|
||||
void *data, unsigned int size)
|
||||
{
|
||||
int err;
|
||||
struct dst_export_ctl *le = data;
|
||||
|
||||
if (n)
|
||||
return -EEXIST;
|
||||
|
||||
if (size != sizeof(struct dst_export_ctl))
|
||||
return -EINVAL;
|
||||
|
||||
n = dst_alloc_node(ctl, dst_start_export, 2);
|
||||
if (!n)
|
||||
return -EINVAL;
|
||||
|
||||
err = dst_setup_export(n, ctl, le);
|
||||
if (err)
|
||||
goto err_out_free;
|
||||
|
||||
dst_node_add(n);
|
||||
|
||||
return 0;
|
||||
|
||||
err_out_free:
|
||||
dst_node_put(n);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int dst_node_remove_unload(struct dst_node *n)
|
||||
{
|
||||
printk(KERN_INFO "STOPPED name: '%s', size: %llu.\n",
|
||||
n->name, n->size);
|
||||
|
||||
if (n->disk)
|
||||
del_gendisk(n->disk);
|
||||
|
||||
dst_node_remove(n);
|
||||
dst_node_sysfs_exit(n);
|
||||
|
||||
/*
|
||||
* This is not a hack. Really.
|
||||
* Node's reference counter allows to implement fine grained
|
||||
* node freeing, but since all transactions (which hold node's
|
||||
* reference counter) are processed in the dedicated thread,
|
||||
* it is possible that reference will hit zero in that thread,
|
||||
* so we will not be able to exit thread and cleanup the node.
|
||||
*
|
||||
* So, we remove disk, so no new activity is possible, and
|
||||
* wait until all pending transaction are completed (either
|
||||
* in receiving thread or by timeout in workqueue), in this
|
||||
* case reference counter will be less or equal to 2 (once set in
|
||||
* dst_alloc_node() and then in connector message parser;
|
||||
* or when we force module unloading, and connector message
|
||||
* parser does not hold a reference, in this case reference
|
||||
* counter will be equal to 1),
|
||||
* and subsequent dst_node_put() calls will free the node.
|
||||
*/
|
||||
dprintk("%s: going to sleep with %d refcnt.\n",
|
||||
__func__, atomic_read(&n->refcnt));
|
||||
wait_event(n->wait, atomic_read(&n->refcnt) <= 2);
|
||||
|
||||
dst_node_put(n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove node from the hash table.
|
||||
*/
|
||||
static int dst_del_node(struct dst_node *n, struct dst_ctl *ctl,
|
||||
void *data, unsigned int size)
|
||||
{
|
||||
if (!n)
|
||||
return -ENODEV;
|
||||
|
||||
return dst_node_remove_unload(n);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize crypto processing for given node.
|
||||
*/
|
||||
static int dst_crypto_init(struct dst_node *n, struct dst_ctl *ctl,
|
||||
void *data, unsigned int size)
|
||||
{
|
||||
struct dst_crypto_ctl *crypto = data;
|
||||
|
||||
if (!n)
|
||||
return -ENODEV;
|
||||
|
||||
if (size != sizeof(struct dst_crypto_ctl) + crypto->hash_keysize +
|
||||
crypto->cipher_keysize)
|
||||
return -EINVAL;
|
||||
|
||||
if (n->trans_cache)
|
||||
return -EEXIST;
|
||||
|
||||
return dst_node_crypto_init(n, crypto);
|
||||
}
|
||||
|
||||
/*
|
||||
* Security attributes for given node.
|
||||
*/
|
||||
static int dst_security_init(struct dst_node *n, struct dst_ctl *ctl,
|
||||
void *data, unsigned int size)
|
||||
{
|
||||
struct dst_secure *s;
|
||||
|
||||
if (!n)
|
||||
return -ENODEV;
|
||||
|
||||
if (size != sizeof(struct dst_secure_user))
|
||||
return -EINVAL;
|
||||
|
||||
s = kmalloc(sizeof(struct dst_secure), GFP_KERNEL);
|
||||
if (!s)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(&s->sec, data, size);
|
||||
|
||||
mutex_lock(&n->security_lock);
|
||||
list_add_tail(&s->sec_entry, &n->security_list);
|
||||
mutex_unlock(&n->security_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Kill'em all!
|
||||
*/
|
||||
static int dst_start_node(struct dst_node *n, struct dst_ctl *ctl,
|
||||
void *data, unsigned int size)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (!n)
|
||||
return -ENODEV;
|
||||
|
||||
if (n->trans_cache)
|
||||
return 0;
|
||||
|
||||
err = n->start(n);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
printk(KERN_INFO "STARTED name: '%s', size: %llu.\n", n->name, n->size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef int (*dst_command_func)(struct dst_node *n, struct dst_ctl *ctl,
|
||||
void *data, unsigned int size);
|
||||
|
||||
/*
|
||||
* List of userspace commands.
|
||||
*/
|
||||
static dst_command_func dst_commands[] = {
|
||||
[DST_ADD_REMOTE] = &dst_add_remote,
|
||||
[DST_ADD_EXPORT] = &dst_add_export,
|
||||
[DST_DEL_NODE] = &dst_del_node,
|
||||
[DST_CRYPTO] = &dst_crypto_init,
|
||||
[DST_SECURITY] = &dst_security_init,
|
||||
[DST_START] = &dst_start_node,
|
||||
};
|
||||
|
||||
/*
|
||||
* Configuration parser.
|
||||
*/
|
||||
static void cn_dst_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
|
||||
{
|
||||
struct dst_ctl *ctl;
|
||||
int err;
|
||||
struct dst_ctl_ack ack;
|
||||
struct dst_node *n = NULL, *tmp;
|
||||
unsigned int hash;
|
||||
|
||||
if (!cap_raised(nsp->eff_cap, CAP_SYS_ADMIN)) {
|
||||
err = -EPERM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (msg->len < sizeof(struct dst_ctl)) {
|
||||
err = -EBADMSG;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ctl = (struct dst_ctl *)msg->data;
|
||||
|
||||
if (ctl->cmd >= DST_CMD_MAX) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
hash = dst_hash(ctl->name, sizeof(ctl->name));
|
||||
|
||||
mutex_lock(&dst_hash_lock);
|
||||
list_for_each_entry(tmp, &dst_hashtable[hash], node_entry) {
|
||||
if (!memcmp(tmp->name, ctl->name, sizeof(tmp->name))) {
|
||||
n = tmp;
|
||||
dst_node_get(n);
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&dst_hash_lock);
|
||||
|
||||
err = dst_commands[ctl->cmd](n, ctl, msg->data + sizeof(struct dst_ctl),
|
||||
msg->len - sizeof(struct dst_ctl));
|
||||
|
||||
dst_node_put(n);
|
||||
out:
|
||||
memcpy(&ack.msg, msg, sizeof(struct cn_msg));
|
||||
|
||||
ack.msg.ack = msg->ack + 1;
|
||||
ack.msg.len = sizeof(struct dst_ctl_ack) - sizeof(struct cn_msg);
|
||||
|
||||
ack.error = err;
|
||||
|
||||
cn_netlink_send(&ack.msg, 0, GFP_KERNEL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Global initialization: sysfs, hash table, block device registration,
|
||||
* connector and various caches.
|
||||
*/
|
||||
static int __init dst_sysfs_init(void)
|
||||
{
|
||||
return bus_register(&dst_dev_bus_type);
|
||||
}
|
||||
|
||||
static void dst_sysfs_exit(void)
|
||||
{
|
||||
bus_unregister(&dst_dev_bus_type);
|
||||
}
|
||||
|
||||
static int __init dst_hashtable_init(void)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
dst_hashtable = kcalloc(dst_hashtable_size, sizeof(struct list_head),
|
||||
GFP_KERNEL);
|
||||
if (!dst_hashtable)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < dst_hashtable_size; ++i)
|
||||
INIT_LIST_HEAD(&dst_hashtable[i]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dst_hashtable_exit(void)
|
||||
{
|
||||
unsigned int i;
|
||||
struct dst_node *n, *tmp;
|
||||
|
||||
for (i = 0; i < dst_hashtable_size; ++i) {
|
||||
list_for_each_entry_safe(n, tmp, &dst_hashtable[i], node_entry) {
|
||||
dst_node_remove_unload(n);
|
||||
}
|
||||
}
|
||||
|
||||
kfree(dst_hashtable);
|
||||
}
|
||||
|
||||
static int __init dst_sys_init(void)
|
||||
{
|
||||
int err = -ENOMEM;
|
||||
|
||||
err = dst_hashtable_init();
|
||||
if (err)
|
||||
goto err_out_exit;
|
||||
|
||||
err = dst_export_init();
|
||||
if (err)
|
||||
goto err_out_hashtable_exit;
|
||||
|
||||
err = register_blkdev(dst_major, DST_NAME);
|
||||
if (err < 0)
|
||||
goto err_out_export_exit;
|
||||
if (err)
|
||||
dst_major = err;
|
||||
|
||||
err = dst_sysfs_init();
|
||||
if (err)
|
||||
goto err_out_unregister;
|
||||
|
||||
err = cn_add_callback(&cn_dst_id, "DST", cn_dst_callback);
|
||||
if (err)
|
||||
goto err_out_sysfs_exit;
|
||||
|
||||
printk(KERN_INFO "Distributed storage, '%s' release.\n", dst_name);
|
||||
|
||||
return 0;
|
||||
|
||||
err_out_sysfs_exit:
|
||||
dst_sysfs_exit();
|
||||
err_out_unregister:
|
||||
unregister_blkdev(dst_major, DST_NAME);
|
||||
err_out_export_exit:
|
||||
dst_export_exit();
|
||||
err_out_hashtable_exit:
|
||||
dst_hashtable_exit();
|
||||
err_out_exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __exit dst_sys_exit(void)
|
||||
{
|
||||
cn_del_callback(&cn_dst_id);
|
||||
unregister_blkdev(dst_major, DST_NAME);
|
||||
dst_hashtable_exit();
|
||||
dst_sysfs_exit();
|
||||
dst_export_exit();
|
||||
}
|
||||
|
||||
module_init(dst_sys_init);
|
||||
module_exit(dst_sys_exit);
|
||||
|
||||
MODULE_DESCRIPTION("Distributed storage");
|
||||
MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -1,660 +0,0 @@
|
|||
/*
|
||||
* 2007+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net>
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/bio.h>
|
||||
#include <linux/dst.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/in6.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/socket.h>
|
||||
|
||||
#include <net/sock.h>
|
||||
|
||||
/*
|
||||
* Export bioset is used for server block IO requests.
|
||||
*/
|
||||
static struct bio_set *dst_bio_set;
|
||||
|
||||
int __init dst_export_init(void)
|
||||
{
|
||||
int err = -ENOMEM;
|
||||
|
||||
dst_bio_set = bioset_create(32, sizeof(struct dst_export_priv));
|
||||
if (!dst_bio_set)
|
||||
goto err_out_exit;
|
||||
|
||||
return 0;
|
||||
|
||||
err_out_exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
void dst_export_exit(void)
|
||||
{
|
||||
bioset_free(dst_bio_set);
|
||||
}
|
||||
|
||||
/*
|
||||
* When client connects and autonegotiates with the server node,
|
||||
* its permissions are checked in a security attributes and sent
|
||||
* back.
|
||||
*/
|
||||
static unsigned int dst_check_permissions(struct dst_state *main,
|
||||
struct dst_state *st)
|
||||
{
|
||||
struct dst_node *n = main->node;
|
||||
struct dst_secure *sentry;
|
||||
struct dst_secure_user *s;
|
||||
struct saddr *sa = &st->ctl.addr;
|
||||
unsigned int perm = 0;
|
||||
|
||||
mutex_lock(&n->security_lock);
|
||||
list_for_each_entry(sentry, &n->security_list, sec_entry) {
|
||||
s = &sentry->sec;
|
||||
|
||||
if (s->addr.sa_family != sa->sa_family)
|
||||
continue;
|
||||
|
||||
if (s->addr.sa_data_len != sa->sa_data_len)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* This '2' below is a port field. This may be very wrong to do
|
||||
* in atalk for example though. If there will be any need
|
||||
* to extent protocol to something else, I can create
|
||||
* per-family helpers and use them instead of this memcmp.
|
||||
*/
|
||||
if (memcmp(s->addr.sa_data + 2, sa->sa_data + 2,
|
||||
sa->sa_data_len - 2))
|
||||
continue;
|
||||
|
||||
perm = s->permissions;
|
||||
}
|
||||
mutex_unlock(&n->security_lock);
|
||||
|
||||
return perm;
|
||||
}
|
||||
|
||||
/*
|
||||
* Accept new client: allocate appropriate network state and check permissions.
|
||||
*/
|
||||
static struct dst_state *dst_accept_client(struct dst_state *st)
|
||||
{
|
||||
unsigned int revents = 0;
|
||||
unsigned int err_mask = POLLERR | POLLHUP | POLLRDHUP;
|
||||
unsigned int mask = err_mask | POLLIN;
|
||||
struct dst_node *n = st->node;
|
||||
int err = 0;
|
||||
struct socket *sock = NULL;
|
||||
struct dst_state *new;
|
||||
|
||||
while (!err && !sock) {
|
||||
revents = dst_state_poll(st);
|
||||
|
||||
if (!(revents & mask)) {
|
||||
DEFINE_WAIT(wait);
|
||||
|
||||
for (;;) {
|
||||
prepare_to_wait(&st->thread_wait,
|
||||
&wait, TASK_INTERRUPTIBLE);
|
||||
if (!n->trans_scan_timeout || st->need_exit)
|
||||
break;
|
||||
|
||||
revents = dst_state_poll(st);
|
||||
|
||||
if (revents & mask)
|
||||
break;
|
||||
|
||||
if (signal_pending(current))
|
||||
break;
|
||||
|
||||
/*
|
||||
* Magic HZ? Polling check above is not safe in
|
||||
* all cases (like socket reset in BH context),
|
||||
* so it is simpler just to postpone it to the
|
||||
* process context instead of implementing
|
||||
* special locking there.
|
||||
*/
|
||||
schedule_timeout(HZ);
|
||||
}
|
||||
finish_wait(&st->thread_wait, &wait);
|
||||
}
|
||||
|
||||
err = -ECONNRESET;
|
||||
dst_state_lock(st);
|
||||
|
||||
dprintk("%s: st: %p, revents: %x [err: %d, in: %d].\n",
|
||||
__func__, st, revents, revents & err_mask,
|
||||
revents & POLLIN);
|
||||
|
||||
if (revents & err_mask) {
|
||||
dprintk("%s: revents: %x, socket: %p, err: %d.\n",
|
||||
__func__, revents, st->socket, err);
|
||||
err = -ECONNRESET;
|
||||
}
|
||||
|
||||
if (!n->trans_scan_timeout || st->need_exit)
|
||||
err = -ENODEV;
|
||||
|
||||
if (st->socket && (revents & POLLIN))
|
||||
err = kernel_accept(st->socket, &sock, 0);
|
||||
|
||||
dst_state_unlock(st);
|
||||
}
|
||||
|
||||
if (err)
|
||||
goto err_out_exit;
|
||||
|
||||
new = dst_state_alloc(st->node);
|
||||
if (IS_ERR(new)) {
|
||||
err = -ENOMEM;
|
||||
goto err_out_release;
|
||||
}
|
||||
new->socket = sock;
|
||||
|
||||
new->ctl.addr.sa_data_len = sizeof(struct sockaddr);
|
||||
err = kernel_getpeername(sock, (struct sockaddr *)&new->ctl.addr,
|
||||
(int *)&new->ctl.addr.sa_data_len);
|
||||
if (err)
|
||||
goto err_out_put;
|
||||
|
||||
new->permissions = dst_check_permissions(st, new);
|
||||
if (new->permissions == 0) {
|
||||
err = -EPERM;
|
||||
dst_dump_addr(sock, (struct sockaddr *)&new->ctl.addr,
|
||||
"Client is not allowed to connect");
|
||||
goto err_out_put;
|
||||
}
|
||||
|
||||
err = dst_poll_init(new);
|
||||
if (err)
|
||||
goto err_out_put;
|
||||
|
||||
dst_dump_addr(sock, (struct sockaddr *)&new->ctl.addr,
|
||||
"Connected client");
|
||||
|
||||
return new;
|
||||
|
||||
err_out_put:
|
||||
dst_state_put(new);
|
||||
err_out_release:
|
||||
sock_release(sock);
|
||||
err_out_exit:
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
/*
|
||||
* Each server's block request sometime finishes.
|
||||
* Usually it happens in hard irq context of the appropriate controller,
|
||||
* so to play good with all cases we just queue BIO into the queue
|
||||
* and wake up processing thread, which gets completed request and
|
||||
* send (encrypting if needed) it back to the client (if it was a read
|
||||
* request), or sends back reply that writing successfully completed.
|
||||
*/
|
||||
static int dst_export_process_request_queue(struct dst_state *st)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct dst_export_priv *p = NULL;
|
||||
struct bio *bio;
|
||||
int err = 0;
|
||||
|
||||
while (!list_empty(&st->request_list)) {
|
||||
spin_lock_irqsave(&st->request_lock, flags);
|
||||
if (!list_empty(&st->request_list)) {
|
||||
p = list_first_entry(&st->request_list,
|
||||
struct dst_export_priv, request_entry);
|
||||
list_del(&p->request_entry);
|
||||
}
|
||||
spin_unlock_irqrestore(&st->request_lock, flags);
|
||||
|
||||
if (!p)
|
||||
break;
|
||||
|
||||
bio = p->bio;
|
||||
|
||||
if (dst_need_crypto(st->node) && (bio_data_dir(bio) == READ))
|
||||
err = dst_export_crypto(st->node, bio);
|
||||
else
|
||||
err = dst_export_send_bio(bio);
|
||||
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Cleanup export state.
|
||||
* It has to wait until all requests are finished,
|
||||
* and then free them all.
|
||||
*/
|
||||
static void dst_state_cleanup_export(struct dst_state *st)
|
||||
{
|
||||
struct dst_export_priv *p;
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* This loop waits for all pending bios to be completed and freed.
|
||||
*/
|
||||
while (atomic_read(&st->refcnt) > 1) {
|
||||
dprintk("%s: st: %p, refcnt: %d, list_empty: %d.\n",
|
||||
__func__, st, atomic_read(&st->refcnt),
|
||||
list_empty(&st->request_list));
|
||||
wait_event_timeout(st->thread_wait,
|
||||
(atomic_read(&st->refcnt) == 1) ||
|
||||
!list_empty(&st->request_list),
|
||||
HZ/2);
|
||||
|
||||
while (!list_empty(&st->request_list)) {
|
||||
p = NULL;
|
||||
spin_lock_irqsave(&st->request_lock, flags);
|
||||
if (!list_empty(&st->request_list)) {
|
||||
p = list_first_entry(&st->request_list,
|
||||
struct dst_export_priv, request_entry);
|
||||
list_del(&p->request_entry);
|
||||
}
|
||||
spin_unlock_irqrestore(&st->request_lock, flags);
|
||||
|
||||
if (p)
|
||||
bio_put(p->bio);
|
||||
|
||||
dprintk("%s: st: %p, refcnt: %d, list_empty: %d, p: "
|
||||
"%p.\n", __func__, st, atomic_read(&st->refcnt),
|
||||
list_empty(&st->request_list), p);
|
||||
}
|
||||
}
|
||||
|
||||
dst_state_put(st);
|
||||
}
|
||||
|
||||
/*
|
||||
* Client accepting thread.
|
||||
* Not only accepts new connection, but also schedules receiving thread
|
||||
* and performs request completion described above.
|
||||
*/
|
||||
static int dst_accept(void *init_data, void *schedule_data)
|
||||
{
|
||||
struct dst_state *main_st = schedule_data;
|
||||
struct dst_node *n = init_data;
|
||||
struct dst_state *st;
|
||||
int err;
|
||||
|
||||
while (n->trans_scan_timeout && !main_st->need_exit) {
|
||||
dprintk("%s: main_st: %p, n: %p.\n", __func__, main_st, n);
|
||||
st = dst_accept_client(main_st);
|
||||
if (IS_ERR(st))
|
||||
continue;
|
||||
|
||||
err = dst_state_schedule_receiver(st);
|
||||
if (!err) {
|
||||
while (n->trans_scan_timeout) {
|
||||
err = wait_event_interruptible_timeout(st->thread_wait,
|
||||
!list_empty(&st->request_list) ||
|
||||
!n->trans_scan_timeout ||
|
||||
st->need_exit,
|
||||
HZ);
|
||||
|
||||
if (!n->trans_scan_timeout || st->need_exit)
|
||||
break;
|
||||
|
||||
if (list_empty(&st->request_list))
|
||||
continue;
|
||||
|
||||
err = dst_export_process_request_queue(st);
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
|
||||
st->need_exit = 1;
|
||||
wake_up(&st->thread_wait);
|
||||
}
|
||||
|
||||
dst_state_cleanup_export(st);
|
||||
}
|
||||
|
||||
dprintk("%s: freeing listening socket st: %p.\n", __func__, main_st);
|
||||
|
||||
dst_state_lock(main_st);
|
||||
dst_poll_exit(main_st);
|
||||
dst_state_socket_release(main_st);
|
||||
dst_state_unlock(main_st);
|
||||
dst_state_put(main_st);
|
||||
dprintk("%s: freed listening socket st: %p.\n", __func__, main_st);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dst_start_export(struct dst_node *n)
|
||||
{
|
||||
if (list_empty(&n->security_list)) {
|
||||
printk(KERN_ERR "You are trying to export node '%s' "
|
||||
"without security attributes.\nNo clients will "
|
||||
"be allowed to connect. Exiting.\n", n->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
return dst_node_trans_init(n, sizeof(struct dst_export_priv));
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize listening state and schedule accepting thread.
|
||||
*/
|
||||
int dst_node_init_listened(struct dst_node *n, struct dst_export_ctl *le)
|
||||
{
|
||||
struct dst_state *st;
|
||||
int err = -ENOMEM;
|
||||
struct dst_network_ctl *ctl = &le->ctl;
|
||||
|
||||
memcpy(&n->info->net, ctl, sizeof(struct dst_network_ctl));
|
||||
|
||||
st = dst_state_alloc(n);
|
||||
if (IS_ERR(st)) {
|
||||
err = PTR_ERR(st);
|
||||
goto err_out_exit;
|
||||
}
|
||||
memcpy(&st->ctl, ctl, sizeof(struct dst_network_ctl));
|
||||
|
||||
err = dst_state_socket_create(st);
|
||||
if (err)
|
||||
goto err_out_put;
|
||||
|
||||
st->socket->sk->sk_reuse = 1;
|
||||
|
||||
err = kernel_bind(st->socket, (struct sockaddr *)&ctl->addr,
|
||||
ctl->addr.sa_data_len);
|
||||
if (err)
|
||||
goto err_out_socket_release;
|
||||
|
||||
err = kernel_listen(st->socket, 1024);
|
||||
if (err)
|
||||
goto err_out_socket_release;
|
||||
n->state = st;
|
||||
|
||||
err = dst_poll_init(st);
|
||||
if (err)
|
||||
goto err_out_socket_release;
|
||||
|
||||
dst_state_get(st);
|
||||
|
||||
err = thread_pool_schedule(n->pool, dst_thread_setup,
|
||||
dst_accept, st, MAX_SCHEDULE_TIMEOUT);
|
||||
if (err)
|
||||
goto err_out_poll_exit;
|
||||
|
||||
return 0;
|
||||
|
||||
err_out_poll_exit:
|
||||
dst_poll_exit(st);
|
||||
err_out_socket_release:
|
||||
dst_state_socket_release(st);
|
||||
err_out_put:
|
||||
dst_state_put(st);
|
||||
err_out_exit:
|
||||
n->state = NULL;
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free bio and related private data.
|
||||
* Also drop a reference counter for appropriate state,
|
||||
* which waits when there are no more block IOs in-flight.
|
||||
*/
|
||||
static void dst_bio_destructor(struct bio *bio)
|
||||
{
|
||||
struct bio_vec *bv;
|
||||
struct dst_export_priv *priv = bio->bi_private;
|
||||
int i;
|
||||
|
||||
bio_for_each_segment(bv, bio, i) {
|
||||
if (!bv->bv_page)
|
||||
break;
|
||||
|
||||
__free_page(bv->bv_page);
|
||||
}
|
||||
|
||||
if (priv)
|
||||
dst_state_put(priv->state);
|
||||
bio_free(bio, dst_bio_set);
|
||||
}
|
||||
|
||||
/*
|
||||
* Block IO completion. Queue request to be sent back to
|
||||
* the client (or just confirmation).
|
||||
*/
|
||||
static void dst_bio_end_io(struct bio *bio, int err)
|
||||
{
|
||||
struct dst_export_priv *p = bio->bi_private;
|
||||
struct dst_state *st = p->state;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&st->request_lock, flags);
|
||||
list_add_tail(&p->request_entry, &st->request_list);
|
||||
spin_unlock_irqrestore(&st->request_lock, flags);
|
||||
|
||||
wake_up(&st->thread_wait);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate read request for the server.
|
||||
*/
|
||||
static int dst_export_read_request(struct bio *bio, unsigned int total_size)
|
||||
{
|
||||
unsigned int size;
|
||||
struct page *page;
|
||||
int err;
|
||||
|
||||
while (total_size) {
|
||||
err = -ENOMEM;
|
||||
page = alloc_page(GFP_KERNEL);
|
||||
if (!page)
|
||||
goto err_out_exit;
|
||||
|
||||
size = min_t(unsigned int, PAGE_SIZE, total_size);
|
||||
|
||||
err = bio_add_page(bio, page, size, 0);
|
||||
dprintk("%s: bio: %llu/%u, size: %u, err: %d.\n",
|
||||
__func__, (u64)bio->bi_sector, bio->bi_size,
|
||||
size, err);
|
||||
if (err <= 0)
|
||||
goto err_out_free_page;
|
||||
|
||||
total_size -= size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_out_free_page:
|
||||
__free_page(page);
|
||||
err_out_exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate write request for the server.
|
||||
* Should not only get pages, but also read data from the network.
|
||||
*/
|
||||
static int dst_export_write_request(struct dst_state *st,
|
||||
struct bio *bio, unsigned int total_size)
|
||||
{
|
||||
unsigned int size;
|
||||
struct page *page;
|
||||
void *data;
|
||||
int err;
|
||||
|
||||
while (total_size) {
|
||||
err = -ENOMEM;
|
||||
page = alloc_page(GFP_KERNEL);
|
||||
if (!page)
|
||||
goto err_out_exit;
|
||||
|
||||
data = kmap(page);
|
||||
if (!data)
|
||||
goto err_out_free_page;
|
||||
|
||||
size = min_t(unsigned int, PAGE_SIZE, total_size);
|
||||
|
||||
err = dst_data_recv(st, data, size);
|
||||
if (err)
|
||||
goto err_out_unmap_page;
|
||||
|
||||
err = bio_add_page(bio, page, size, 0);
|
||||
if (err <= 0)
|
||||
goto err_out_unmap_page;
|
||||
|
||||
kunmap(page);
|
||||
|
||||
total_size -= size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_out_unmap_page:
|
||||
kunmap(page);
|
||||
err_out_free_page:
|
||||
__free_page(page);
|
||||
err_out_exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Groovy, we've gotten an IO request from the client.
|
||||
* Allocate BIO from the bioset, private data from the mempool
|
||||
* and lots of pages for IO.
|
||||
*/
|
||||
int dst_process_io(struct dst_state *st)
|
||||
{
|
||||
struct dst_node *n = st->node;
|
||||
struct dst_cmd *cmd = st->data;
|
||||
struct bio *bio;
|
||||
struct dst_export_priv *priv;
|
||||
int err = -ENOMEM;
|
||||
|
||||
if (unlikely(!n->bdev)) {
|
||||
err = -EINVAL;
|
||||
goto err_out_exit;
|
||||
}
|
||||
|
||||
bio = bio_alloc_bioset(GFP_KERNEL,
|
||||
PAGE_ALIGN(cmd->size) >> PAGE_SHIFT,
|
||||
dst_bio_set);
|
||||
if (!bio)
|
||||
goto err_out_exit;
|
||||
|
||||
priv = (struct dst_export_priv *)(((void *)bio) -
|
||||
sizeof (struct dst_export_priv));
|
||||
|
||||
priv->state = dst_state_get(st);
|
||||
priv->bio = bio;
|
||||
|
||||
bio->bi_private = priv;
|
||||
bio->bi_end_io = dst_bio_end_io;
|
||||
bio->bi_destructor = dst_bio_destructor;
|
||||
bio->bi_bdev = n->bdev;
|
||||
|
||||
/*
|
||||
* Server side is only interested in two low bits:
|
||||
* uptodate (set by itself actually) and rw block
|
||||
*/
|
||||
bio->bi_flags |= cmd->flags & 3;
|
||||
|
||||
bio->bi_rw = cmd->rw;
|
||||
bio->bi_size = 0;
|
||||
bio->bi_sector = cmd->sector;
|
||||
|
||||
dst_bio_to_cmd(bio, &priv->cmd, DST_IO_RESPONSE, cmd->id);
|
||||
|
||||
priv->cmd.flags = 0;
|
||||
priv->cmd.size = cmd->size;
|
||||
|
||||
if (bio_data_dir(bio) == WRITE) {
|
||||
err = dst_recv_cdata(st, priv->cmd.hash);
|
||||
if (err)
|
||||
goto err_out_free;
|
||||
|
||||
err = dst_export_write_request(st, bio, cmd->size);
|
||||
if (err)
|
||||
goto err_out_free;
|
||||
|
||||
if (dst_need_crypto(n))
|
||||
return dst_export_crypto(n, bio);
|
||||
} else {
|
||||
err = dst_export_read_request(bio, cmd->size);
|
||||
if (err)
|
||||
goto err_out_free;
|
||||
}
|
||||
|
||||
dprintk("%s: bio: %llu/%u, rw: %lu, dir: %lu, flags: %lx, phys: %d.\n",
|
||||
__func__, (u64)bio->bi_sector, bio->bi_size,
|
||||
bio->bi_rw, bio_data_dir(bio),
|
||||
bio->bi_flags, bio->bi_phys_segments);
|
||||
|
||||
generic_make_request(bio);
|
||||
|
||||
return 0;
|
||||
|
||||
err_out_free:
|
||||
bio_put(bio);
|
||||
err_out_exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ok, block IO is ready, let's send it back to the client...
|
||||
*/
|
||||
int dst_export_send_bio(struct bio *bio)
|
||||
{
|
||||
struct dst_export_priv *p = bio->bi_private;
|
||||
struct dst_state *st = p->state;
|
||||
struct dst_cmd *cmd = &p->cmd;
|
||||
int err;
|
||||
|
||||
dprintk("%s: id: %llu, bio: %llu/%u, csize: %u, flags: %lu, rw: %lu.\n",
|
||||
__func__, cmd->id, (u64)bio->bi_sector, bio->bi_size,
|
||||
cmd->csize, bio->bi_flags, bio->bi_rw);
|
||||
|
||||
dst_convert_cmd(cmd);
|
||||
|
||||
dst_state_lock(st);
|
||||
if (!st->socket) {
|
||||
err = -ECONNRESET;
|
||||
goto err_out_unlock;
|
||||
}
|
||||
|
||||
if (bio_data_dir(bio) == WRITE) {
|
||||
/* ... or just confirmation that writing has completed. */
|
||||
cmd->size = cmd->csize = 0;
|
||||
err = dst_data_send_header(st->socket, cmd,
|
||||
sizeof(struct dst_cmd), 0);
|
||||
if (err)
|
||||
goto err_out_unlock;
|
||||
} else {
|
||||
err = dst_send_bio(st, cmd, bio);
|
||||
if (err)
|
||||
goto err_out_unlock;
|
||||
}
|
||||
|
||||
dst_state_unlock(st);
|
||||
|
||||
bio_put(bio);
|
||||
return 0;
|
||||
|
||||
err_out_unlock:
|
||||
dst_state_unlock(st);
|
||||
|
||||
bio_put(bio);
|
||||
return err;
|
||||
}
|
|
@ -1,844 +0,0 @@
|
|||
/*
|
||||
* 2007+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net>
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/buffer_head.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/bio.h>
|
||||
#include <linux/connector.h>
|
||||
#include <linux/dst.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/in6.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <net/sock.h>
|
||||
|
||||
/*
|
||||
* Polling machinery.
|
||||
*/
|
||||
|
||||
struct dst_poll_helper {
|
||||
poll_table pt;
|
||||
struct dst_state *st;
|
||||
};
|
||||
|
||||
static int dst_queue_wake(wait_queue_t *wait, unsigned mode,
|
||||
int sync, void *key)
|
||||
{
|
||||
struct dst_state *st = container_of(wait, struct dst_state, wait);
|
||||
|
||||
wake_up(&st->thread_wait);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void dst_queue_func(struct file *file, wait_queue_head_t *whead,
|
||||
poll_table *pt)
|
||||
{
|
||||
struct dst_state *st = container_of(pt, struct dst_poll_helper, pt)->st;
|
||||
|
||||
st->whead = whead;
|
||||
init_waitqueue_func_entry(&st->wait, dst_queue_wake);
|
||||
add_wait_queue(whead, &st->wait);
|
||||
}
|
||||
|
||||
void dst_poll_exit(struct dst_state *st)
|
||||
{
|
||||
if (st->whead) {
|
||||
remove_wait_queue(st->whead, &st->wait);
|
||||
st->whead = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int dst_poll_init(struct dst_state *st)
|
||||
{
|
||||
struct dst_poll_helper ph;
|
||||
|
||||
ph.st = st;
|
||||
init_poll_funcptr(&ph.pt, &dst_queue_func);
|
||||
|
||||
st->socket->ops->poll(NULL, st->socket, &ph.pt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Header receiving function - may block.
|
||||
*/
|
||||
static int dst_data_recv_header(struct socket *sock,
|
||||
void *data, unsigned int size, int block)
|
||||
{
|
||||
struct msghdr msg;
|
||||
struct kvec iov;
|
||||
int err;
|
||||
|
||||
iov.iov_base = data;
|
||||
iov.iov_len = size;
|
||||
|
||||
msg.msg_iov = (struct iovec *)&iov;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_name = NULL;
|
||||
msg.msg_namelen = 0;
|
||||
msg.msg_control = NULL;
|
||||
msg.msg_controllen = 0;
|
||||
msg.msg_flags = (block) ? MSG_WAITALL : MSG_DONTWAIT;
|
||||
|
||||
err = kernel_recvmsg(sock, &msg, &iov, 1, iov.iov_len,
|
||||
msg.msg_flags);
|
||||
if (err != size)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Header sending function - may block.
|
||||
*/
|
||||
int dst_data_send_header(struct socket *sock,
|
||||
void *data, unsigned int size, int more)
|
||||
{
|
||||
struct msghdr msg;
|
||||
struct kvec iov;
|
||||
int err;
|
||||
|
||||
iov.iov_base = data;
|
||||
iov.iov_len = size;
|
||||
|
||||
msg.msg_iov = (struct iovec *)&iov;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_name = NULL;
|
||||
msg.msg_namelen = 0;
|
||||
msg.msg_control = NULL;
|
||||
msg.msg_controllen = 0;
|
||||
msg.msg_flags = MSG_WAITALL | (more ? MSG_MORE : 0);
|
||||
|
||||
err = kernel_sendmsg(sock, &msg, &iov, 1, iov.iov_len);
|
||||
if (err != size) {
|
||||
dprintk("%s: size: %u, more: %d, err: %d.\n",
|
||||
__func__, size, more, err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Block autoconfiguration: request size of the storage and permissions.
|
||||
*/
|
||||
static int dst_request_remote_config(struct dst_state *st)
|
||||
{
|
||||
struct dst_node *n = st->node;
|
||||
int err = -EINVAL;
|
||||
struct dst_cmd *cmd = st->data;
|
||||
|
||||
memset(cmd, 0, sizeof(struct dst_cmd));
|
||||
cmd->cmd = DST_CFG;
|
||||
|
||||
dst_convert_cmd(cmd);
|
||||
|
||||
err = dst_data_send_header(st->socket, cmd, sizeof(struct dst_cmd), 0);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = dst_data_recv_header(st->socket, cmd, sizeof(struct dst_cmd), 1);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
dst_convert_cmd(cmd);
|
||||
|
||||
if (cmd->cmd != DST_CFG) {
|
||||
err = -EINVAL;
|
||||
dprintk("%s: checking result: cmd: %d, size reported: %llu.\n",
|
||||
__func__, cmd->cmd, cmd->sector);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (n->size != 0)
|
||||
n->size = min_t(loff_t, n->size, cmd->sector);
|
||||
else
|
||||
n->size = cmd->sector;
|
||||
|
||||
n->info->size = n->size;
|
||||
st->permissions = cmd->rw;
|
||||
|
||||
out:
|
||||
dprintk("%s: n: %p, err: %d, size: %llu, permission: %x.\n",
|
||||
__func__, n, err, n->size, st->permissions);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Socket machinery.
|
||||
*/
|
||||
|
||||
#define DST_DEFAULT_TIMEO 20000
|
||||
|
||||
int dst_state_socket_create(struct dst_state *st)
|
||||
{
|
||||
int err;
|
||||
struct socket *sock;
|
||||
struct dst_network_ctl *ctl = &st->ctl;
|
||||
|
||||
err = sock_create(ctl->addr.sa_family, ctl->type, ctl->proto, &sock);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
sock->sk->sk_sndtimeo = sock->sk->sk_rcvtimeo =
|
||||
msecs_to_jiffies(DST_DEFAULT_TIMEO);
|
||||
sock->sk->sk_allocation = GFP_NOIO;
|
||||
|
||||
st->socket = st->read_socket = sock;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dst_state_socket_release(struct dst_state *st)
|
||||
{
|
||||
dprintk("%s: st: %p, socket: %p, n: %p.\n",
|
||||
__func__, st, st->socket, st->node);
|
||||
if (st->socket) {
|
||||
sock_release(st->socket);
|
||||
st->socket = NULL;
|
||||
st->read_socket = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void dst_dump_addr(struct socket *sk, struct sockaddr *sa, char *str)
|
||||
{
|
||||
if (sk->ops->family == AF_INET) {
|
||||
struct sockaddr_in *sin = (struct sockaddr_in *)sa;
|
||||
printk(KERN_INFO "%s %u.%u.%u.%u:%d.\n", str,
|
||||
NIPQUAD(sin->sin_addr.s_addr), ntohs(sin->sin_port));
|
||||
} else if (sk->ops->family == AF_INET6) {
|
||||
struct sockaddr_in6 *sin = (struct sockaddr_in6 *)sa;
|
||||
printk(KERN_INFO "%s %pi6:%d",
|
||||
str, &sin->sin6_addr, ntohs(sin->sin6_port));
|
||||
}
|
||||
}
|
||||
|
||||
void dst_state_exit_connected(struct dst_state *st)
|
||||
{
|
||||
if (st->socket) {
|
||||
dst_poll_exit(st);
|
||||
st->socket->ops->shutdown(st->socket, 2);
|
||||
|
||||
dst_dump_addr(st->socket, (struct sockaddr *)&st->ctl.addr,
|
||||
"Disconnected peer");
|
||||
dst_state_socket_release(st);
|
||||
}
|
||||
}
|
||||
|
||||
static int dst_state_init_connected(struct dst_state *st)
|
||||
{
|
||||
int err;
|
||||
struct dst_network_ctl *ctl = &st->ctl;
|
||||
|
||||
err = dst_state_socket_create(st);
|
||||
if (err)
|
||||
goto err_out_exit;
|
||||
|
||||
err = kernel_connect(st->socket, (struct sockaddr *)&st->ctl.addr,
|
||||
st->ctl.addr.sa_data_len, 0);
|
||||
if (err)
|
||||
goto err_out_release;
|
||||
|
||||
err = dst_poll_init(st);
|
||||
if (err)
|
||||
goto err_out_release;
|
||||
|
||||
dst_dump_addr(st->socket, (struct sockaddr *)&ctl->addr,
|
||||
"Connected to peer");
|
||||
|
||||
return 0;
|
||||
|
||||
err_out_release:
|
||||
dst_state_socket_release(st);
|
||||
err_out_exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* State reset is used to reconnect to the remote peer.
|
||||
* May fail, but who cares, we will try again later.
|
||||
*/
|
||||
static inline void dst_state_reset_nolock(struct dst_state *st)
|
||||
{
|
||||
dst_state_exit_connected(st);
|
||||
dst_state_init_connected(st);
|
||||
}
|
||||
|
||||
static inline void dst_state_reset(struct dst_state *st)
|
||||
{
|
||||
dst_state_lock(st);
|
||||
dst_state_reset_nolock(st);
|
||||
dst_state_unlock(st);
|
||||
}
|
||||
|
||||
/*
|
||||
* Basic network sending/receiving functions.
|
||||
* Blocked mode is used.
|
||||
*/
|
||||
static int dst_data_recv_raw(struct dst_state *st, void *buf, u64 size)
|
||||
{
|
||||
struct msghdr msg;
|
||||
struct kvec iov;
|
||||
int err;
|
||||
|
||||
BUG_ON(!size);
|
||||
|
||||
iov.iov_base = buf;
|
||||
iov.iov_len = size;
|
||||
|
||||
msg.msg_iov = (struct iovec *)&iov;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_name = NULL;
|
||||
msg.msg_namelen = 0;
|
||||
msg.msg_control = NULL;
|
||||
msg.msg_controllen = 0;
|
||||
msg.msg_flags = MSG_DONTWAIT;
|
||||
|
||||
err = kernel_recvmsg(st->socket, &msg, &iov, 1, iov.iov_len,
|
||||
msg.msg_flags);
|
||||
if (err <= 0) {
|
||||
dprintk("%s: failed to recv data: size: %llu, err: %d.\n",
|
||||
__func__, size, err);
|
||||
if (err == 0)
|
||||
err = -ECONNRESET;
|
||||
|
||||
dst_state_exit_connected(st);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ping command to early detect failed nodes.
|
||||
*/
|
||||
static int dst_send_ping(struct dst_state *st)
|
||||
{
|
||||
struct dst_cmd *cmd = st->data;
|
||||
int err = -ECONNRESET;
|
||||
|
||||
dst_state_lock(st);
|
||||
if (st->socket) {
|
||||
memset(cmd, 0, sizeof(struct dst_cmd));
|
||||
|
||||
cmd->cmd = __cpu_to_be32(DST_PING);
|
||||
|
||||
err = dst_data_send_header(st->socket, cmd,
|
||||
sizeof(struct dst_cmd), 0);
|
||||
}
|
||||
dprintk("%s: st: %p, socket: %p, err: %d.\n", __func__,
|
||||
st, st->socket, err);
|
||||
dst_state_unlock(st);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Receiving function, which should either return error or read
|
||||
* whole block request. If there was no traffic for a one second,
|
||||
* send a ping, since remote node may die.
|
||||
*/
|
||||
int dst_data_recv(struct dst_state *st, void *data, unsigned int size)
|
||||
{
|
||||
unsigned int revents = 0;
|
||||
unsigned int err_mask = POLLERR | POLLHUP | POLLRDHUP;
|
||||
unsigned int mask = err_mask | POLLIN;
|
||||
struct dst_node *n = st->node;
|
||||
int err = 0;
|
||||
|
||||
while (size && !err) {
|
||||
revents = dst_state_poll(st);
|
||||
|
||||
if (!(revents & mask)) {
|
||||
DEFINE_WAIT(wait);
|
||||
|
||||
for (;;) {
|
||||
prepare_to_wait(&st->thread_wait, &wait,
|
||||
TASK_INTERRUPTIBLE);
|
||||
if (!n->trans_scan_timeout || st->need_exit)
|
||||
break;
|
||||
|
||||
revents = dst_state_poll(st);
|
||||
|
||||
if (revents & mask)
|
||||
break;
|
||||
|
||||
if (signal_pending(current))
|
||||
break;
|
||||
|
||||
if (!schedule_timeout(HZ)) {
|
||||
err = dst_send_ping(st);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
finish_wait(&st->thread_wait, &wait);
|
||||
}
|
||||
|
||||
err = -ECONNRESET;
|
||||
dst_state_lock(st);
|
||||
|
||||
if (st->socket && (st->read_socket == st->socket) &&
|
||||
(revents & POLLIN)) {
|
||||
err = dst_data_recv_raw(st, data, size);
|
||||
if (err > 0) {
|
||||
data += err;
|
||||
size -= err;
|
||||
err = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (revents & err_mask || !st->socket) {
|
||||
dprintk("%s: revents: %x, socket: %p, size: %u, "
|
||||
"err: %d.\n", __func__, revents,
|
||||
st->socket, size, err);
|
||||
err = -ECONNRESET;
|
||||
}
|
||||
|
||||
dst_state_unlock(st);
|
||||
|
||||
if (!n->trans_scan_timeout)
|
||||
err = -ENODEV;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send block autoconf reply.
|
||||
*/
|
||||
static int dst_process_cfg(struct dst_state *st)
|
||||
{
|
||||
struct dst_node *n = st->node;
|
||||
struct dst_cmd *cmd = st->data;
|
||||
int err;
|
||||
|
||||
cmd->sector = n->size;
|
||||
cmd->rw = st->permissions;
|
||||
|
||||
dst_convert_cmd(cmd);
|
||||
|
||||
dst_state_lock(st);
|
||||
err = dst_data_send_header(st->socket, cmd, sizeof(struct dst_cmd), 0);
|
||||
dst_state_unlock(st);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Receive block IO from the network.
|
||||
*/
|
||||
static int dst_recv_bio(struct dst_state *st, struct bio *bio,
|
||||
unsigned int total_size)
|
||||
{
|
||||
struct bio_vec *bv;
|
||||
int i, err;
|
||||
void *data;
|
||||
unsigned int sz;
|
||||
|
||||
bio_for_each_segment(bv, bio, i) {
|
||||
sz = min(total_size, bv->bv_len);
|
||||
|
||||
dprintk("%s: bio: %llu/%u, total: %u, len: %u, sz: %u, "
|
||||
"off: %u.\n", __func__, (u64)bio->bi_sector,
|
||||
bio->bi_size, total_size, bv->bv_len, sz,
|
||||
bv->bv_offset);
|
||||
|
||||
data = kmap(bv->bv_page) + bv->bv_offset;
|
||||
err = dst_data_recv(st, data, sz);
|
||||
kunmap(bv->bv_page);
|
||||
|
||||
bv->bv_len = sz;
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
total_size -= sz;
|
||||
if (total_size == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Our block IO has just completed and arrived: get it.
|
||||
*/
|
||||
static int dst_process_io_response(struct dst_state *st)
|
||||
{
|
||||
struct dst_node *n = st->node;
|
||||
struct dst_cmd *cmd = st->data;
|
||||
struct dst_trans *t;
|
||||
int err = 0;
|
||||
struct bio *bio;
|
||||
|
||||
mutex_lock(&n->trans_lock);
|
||||
t = dst_trans_search(n, cmd->id);
|
||||
mutex_unlock(&n->trans_lock);
|
||||
|
||||
if (!t)
|
||||
goto err_out_exit;
|
||||
|
||||
bio = t->bio;
|
||||
|
||||
dprintk("%s: bio: %llu/%u, cmd_size: %u, csize: %u, dir: %lu.\n",
|
||||
__func__, (u64)bio->bi_sector, bio->bi_size, cmd->size,
|
||||
cmd->csize, bio_data_dir(bio));
|
||||
|
||||
if (bio_data_dir(bio) == READ) {
|
||||
if (bio->bi_size != cmd->size - cmd->csize)
|
||||
goto err_out_exit;
|
||||
|
||||
if (dst_need_crypto(n)) {
|
||||
err = dst_recv_cdata(st, t->cmd.hash);
|
||||
if (err)
|
||||
goto err_out_exit;
|
||||
}
|
||||
|
||||
err = dst_recv_bio(st, t->bio, bio->bi_size);
|
||||
if (err)
|
||||
goto err_out_exit;
|
||||
|
||||
if (dst_need_crypto(n))
|
||||
return dst_trans_crypto(t);
|
||||
} else {
|
||||
err = -EBADMSG;
|
||||
if (cmd->size || cmd->csize)
|
||||
goto err_out_exit;
|
||||
}
|
||||
|
||||
dst_trans_remove(t);
|
||||
dst_trans_put(t);
|
||||
|
||||
return 0;
|
||||
|
||||
err_out_exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Receive crypto data.
|
||||
*/
|
||||
int dst_recv_cdata(struct dst_state *st, void *cdata)
|
||||
{
|
||||
struct dst_cmd *cmd = st->data;
|
||||
struct dst_node *n = st->node;
|
||||
struct dst_crypto_ctl *c = &n->crypto;
|
||||
int err;
|
||||
|
||||
if (cmd->csize != c->crypto_attached_size) {
|
||||
dprintk("%s: cmd: cmd: %u, sector: %llu, size: %u, "
|
||||
"csize: %u != digest size %u.\n",
|
||||
__func__, cmd->cmd, cmd->sector, cmd->size,
|
||||
cmd->csize, c->crypto_attached_size);
|
||||
err = -EINVAL;
|
||||
goto err_out_exit;
|
||||
}
|
||||
|
||||
err = dst_data_recv(st, cdata, cmd->csize);
|
||||
if (err)
|
||||
goto err_out_exit;
|
||||
|
||||
cmd->size -= cmd->csize;
|
||||
return 0;
|
||||
|
||||
err_out_exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Receive the command and start its processing.
|
||||
*/
|
||||
static int dst_recv_processing(struct dst_state *st)
|
||||
{
|
||||
int err = -EINTR;
|
||||
struct dst_cmd *cmd = st->data;
|
||||
|
||||
/*
|
||||
* If socket will be reset after this statement, then
|
||||
* dst_data_recv() will just fail and loop will
|
||||
* start again, so it can be done without any locks.
|
||||
*
|
||||
* st->read_socket is needed to prevents state machine
|
||||
* breaking between this data reading and subsequent one
|
||||
* in protocol specific functions during connection reset.
|
||||
* In case of reset we have to read next command and do
|
||||
* not expect data for old command to magically appear in
|
||||
* new connection.
|
||||
*/
|
||||
st->read_socket = st->socket;
|
||||
err = dst_data_recv(st, cmd, sizeof(struct dst_cmd));
|
||||
if (err)
|
||||
goto out_exit;
|
||||
|
||||
dst_convert_cmd(cmd);
|
||||
|
||||
dprintk("%s: cmd: %u, size: %u, csize: %u, id: %llu, "
|
||||
"sector: %llu, flags: %llx, rw: %llx.\n",
|
||||
__func__, cmd->cmd, cmd->size,
|
||||
cmd->csize, cmd->id, cmd->sector,
|
||||
cmd->flags, cmd->rw);
|
||||
|
||||
/*
|
||||
* This should catch protocol breakage and random garbage
|
||||
* instead of commands.
|
||||
*/
|
||||
if (unlikely(cmd->csize > st->size - sizeof(struct dst_cmd))) {
|
||||
err = -EBADMSG;
|
||||
goto out_exit;
|
||||
}
|
||||
|
||||
err = -EPROTO;
|
||||
switch (cmd->cmd) {
|
||||
case DST_IO_RESPONSE:
|
||||
err = dst_process_io_response(st);
|
||||
break;
|
||||
case DST_IO:
|
||||
err = dst_process_io(st);
|
||||
break;
|
||||
case DST_CFG:
|
||||
err = dst_process_cfg(st);
|
||||
break;
|
||||
case DST_PING:
|
||||
err = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
out_exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Receiving thread. For the client node we should try to reconnect,
|
||||
* for accepted client we just drop the state and expect it to reconnect.
|
||||
*/
|
||||
static int dst_recv(void *init_data, void *schedule_data)
|
||||
{
|
||||
struct dst_state *st = schedule_data;
|
||||
struct dst_node *n = init_data;
|
||||
int err = 0;
|
||||
|
||||
dprintk("%s: start st: %p, n: %p, scan: %lu, need_exit: %d.\n",
|
||||
__func__, st, n, n->trans_scan_timeout, st->need_exit);
|
||||
|
||||
while (n->trans_scan_timeout && !st->need_exit) {
|
||||
err = dst_recv_processing(st);
|
||||
if (err < 0) {
|
||||
if (!st->ctl.type)
|
||||
break;
|
||||
|
||||
if (!n->trans_scan_timeout || st->need_exit)
|
||||
break;
|
||||
|
||||
dst_state_reset(st);
|
||||
msleep(1000);
|
||||
}
|
||||
}
|
||||
|
||||
st->need_exit = 1;
|
||||
wake_up(&st->thread_wait);
|
||||
|
||||
dprintk("%s: freeing receiving socket st: %p.\n", __func__, st);
|
||||
dst_state_lock(st);
|
||||
dst_state_exit_connected(st);
|
||||
dst_state_unlock(st);
|
||||
dst_state_put(st);
|
||||
|
||||
dprintk("%s: freed receiving socket st: %p.\n", __func__, st);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Network state dies here and borns couple of lines below.
|
||||
* This object is the main network state processing engine:
|
||||
* sending, receiving, reconnections, all network related
|
||||
* tasks are handled on behalf of the state.
|
||||
*/
|
||||
static void dst_state_free(struct dst_state *st)
|
||||
{
|
||||
dprintk("%s: st: %p.\n", __func__, st);
|
||||
if (st->cleanup)
|
||||
st->cleanup(st);
|
||||
kfree(st->data);
|
||||
kfree(st);
|
||||
}
|
||||
|
||||
struct dst_state *dst_state_alloc(struct dst_node *n)
|
||||
{
|
||||
struct dst_state *st;
|
||||
int err = -ENOMEM;
|
||||
|
||||
st = kzalloc(sizeof(struct dst_state), GFP_KERNEL);
|
||||
if (!st)
|
||||
goto err_out_exit;
|
||||
|
||||
st->node = n;
|
||||
st->need_exit = 0;
|
||||
|
||||
st->size = PAGE_SIZE;
|
||||
st->data = kmalloc(st->size, GFP_KERNEL);
|
||||
if (!st->data)
|
||||
goto err_out_free;
|
||||
|
||||
spin_lock_init(&st->request_lock);
|
||||
INIT_LIST_HEAD(&st->request_list);
|
||||
|
||||
mutex_init(&st->state_lock);
|
||||
init_waitqueue_head(&st->thread_wait);
|
||||
|
||||
/*
|
||||
* One for processing thread, another one for node itself.
|
||||
*/
|
||||
atomic_set(&st->refcnt, 2);
|
||||
|
||||
dprintk("%s: st: %p, n: %p.\n", __func__, st, st->node);
|
||||
|
||||
return st;
|
||||
|
||||
err_out_free:
|
||||
kfree(st);
|
||||
err_out_exit:
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
int dst_state_schedule_receiver(struct dst_state *st)
|
||||
{
|
||||
return thread_pool_schedule_private(st->node->pool, dst_thread_setup,
|
||||
dst_recv, st, MAX_SCHEDULE_TIMEOUT, st->node);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize client's connection to the remote peer: allocate state,
|
||||
* connect and perform block IO autoconfiguration.
|
||||
*/
|
||||
int dst_node_init_connected(struct dst_node *n, struct dst_network_ctl *r)
|
||||
{
|
||||
struct dst_state *st;
|
||||
int err = -ENOMEM;
|
||||
|
||||
st = dst_state_alloc(n);
|
||||
if (IS_ERR(st)) {
|
||||
err = PTR_ERR(st);
|
||||
goto err_out_exit;
|
||||
}
|
||||
memcpy(&st->ctl, r, sizeof(struct dst_network_ctl));
|
||||
|
||||
err = dst_state_init_connected(st);
|
||||
if (err)
|
||||
goto err_out_free_data;
|
||||
|
||||
err = dst_request_remote_config(st);
|
||||
if (err)
|
||||
goto err_out_exit_connected;
|
||||
n->state = st;
|
||||
|
||||
err = dst_state_schedule_receiver(st);
|
||||
if (err)
|
||||
goto err_out_exit_connected;
|
||||
|
||||
return 0;
|
||||
|
||||
err_out_exit_connected:
|
||||
dst_state_exit_connected(st);
|
||||
err_out_free_data:
|
||||
dst_state_free(st);
|
||||
err_out_exit:
|
||||
n->state = NULL;
|
||||
return err;
|
||||
}
|
||||
|
||||
void dst_state_put(struct dst_state *st)
|
||||
{
|
||||
dprintk("%s: st: %p, refcnt: %d.\n",
|
||||
__func__, st, atomic_read(&st->refcnt));
|
||||
if (atomic_dec_and_test(&st->refcnt))
|
||||
dst_state_free(st);
|
||||
}
|
||||
|
||||
/*
|
||||
* Send block IO to the network one by one using zero-copy ->sendpage().
|
||||
*/
|
||||
int dst_send_bio(struct dst_state *st, struct dst_cmd *cmd, struct bio *bio)
|
||||
{
|
||||
struct bio_vec *bv;
|
||||
struct dst_crypto_ctl *c = &st->node->crypto;
|
||||
int err, i = 0;
|
||||
int flags = MSG_WAITALL;
|
||||
|
||||
err = dst_data_send_header(st->socket, cmd,
|
||||
sizeof(struct dst_cmd) + c->crypto_attached_size, bio->bi_vcnt);
|
||||
if (err)
|
||||
goto err_out_exit;
|
||||
|
||||
bio_for_each_segment(bv, bio, i) {
|
||||
if (i < bio->bi_vcnt - 1)
|
||||
flags |= MSG_MORE;
|
||||
|
||||
err = kernel_sendpage(st->socket, bv->bv_page, bv->bv_offset,
|
||||
bv->bv_len, flags);
|
||||
if (err <= 0)
|
||||
goto err_out_exit;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_out_exit:
|
||||
dprintk("%s: %d/%d, flags: %x, err: %d.\n",
|
||||
__func__, i, bio->bi_vcnt, flags, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send transaction to the remote peer.
|
||||
*/
|
||||
int dst_trans_send(struct dst_trans *t)
|
||||
{
|
||||
int err;
|
||||
struct dst_state *st = t->n->state;
|
||||
struct bio *bio = t->bio;
|
||||
|
||||
dst_convert_cmd(&t->cmd);
|
||||
|
||||
dst_state_lock(st);
|
||||
if (!st->socket) {
|
||||
err = dst_state_init_connected(st);
|
||||
if (err)
|
||||
goto err_out_unlock;
|
||||
}
|
||||
|
||||
if (bio_data_dir(bio) == WRITE) {
|
||||
err = dst_send_bio(st, &t->cmd, t->bio);
|
||||
} else {
|
||||
err = dst_data_send_header(st->socket, &t->cmd,
|
||||
sizeof(struct dst_cmd), 0);
|
||||
}
|
||||
if (err)
|
||||
goto err_out_reset;
|
||||
|
||||
dst_state_unlock(st);
|
||||
return 0;
|
||||
|
||||
err_out_reset:
|
||||
dst_state_reset_nolock(st);
|
||||
err_out_unlock:
|
||||
dst_state_unlock(st);
|
||||
|
||||
return err;
|
||||
}
|
|
@ -1,348 +0,0 @@
|
|||
/*
|
||||
* 2007+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net>
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/dst.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
/*
|
||||
* Thread pool abstraction allows to schedule a work to be performed
|
||||
* on behalf of kernel thread. One does not operate with threads itself,
|
||||
* instead user provides setup and cleanup callbacks for thread pool itself,
|
||||
* and action and cleanup callbacks for each submitted work.
|
||||
*
|
||||
* Each worker has private data initialized at creation time and data,
|
||||
* provided by user at scheduling time.
|
||||
*
|
||||
* When action is being performed, thread can not be used by other users,
|
||||
* instead they will sleep until there is free thread to pick their work.
|
||||
*/
|
||||
struct thread_pool_worker {
|
||||
struct list_head worker_entry;
|
||||
|
||||
struct task_struct *thread;
|
||||
|
||||
struct thread_pool *pool;
|
||||
|
||||
int error;
|
||||
int has_data;
|
||||
int need_exit;
|
||||
unsigned int id;
|
||||
|
||||
wait_queue_head_t wait;
|
||||
|
||||
void *private;
|
||||
void *schedule_data;
|
||||
|
||||
int (*action)(void *private, void *schedule_data);
|
||||
void (*cleanup)(void *private);
|
||||
};
|
||||
|
||||
static void thread_pool_exit_worker(struct thread_pool_worker *w)
|
||||
{
|
||||
kthread_stop(w->thread);
|
||||
|
||||
w->cleanup(w->private);
|
||||
kfree(w);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called to mark thread as ready and allow users to schedule new work.
|
||||
*/
|
||||
static void thread_pool_worker_make_ready(struct thread_pool_worker *w)
|
||||
{
|
||||
struct thread_pool *p = w->pool;
|
||||
|
||||
mutex_lock(&p->thread_lock);
|
||||
|
||||
if (!w->need_exit) {
|
||||
list_move_tail(&w->worker_entry, &p->ready_list);
|
||||
w->has_data = 0;
|
||||
mutex_unlock(&p->thread_lock);
|
||||
|
||||
wake_up(&p->wait);
|
||||
} else {
|
||||
p->thread_num--;
|
||||
list_del(&w->worker_entry);
|
||||
mutex_unlock(&p->thread_lock);
|
||||
|
||||
thread_pool_exit_worker(w);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Thread action loop: waits until there is new work.
|
||||
*/
|
||||
static int thread_pool_worker_func(void *data)
|
||||
{
|
||||
struct thread_pool_worker *w = data;
|
||||
|
||||
while (!kthread_should_stop()) {
|
||||
wait_event_interruptible(w->wait,
|
||||
kthread_should_stop() || w->has_data);
|
||||
|
||||
if (kthread_should_stop())
|
||||
break;
|
||||
|
||||
if (!w->has_data)
|
||||
continue;
|
||||
|
||||
w->action(w->private, w->schedule_data);
|
||||
thread_pool_worker_make_ready(w);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove single worker without specifying which one.
|
||||
*/
|
||||
void thread_pool_del_worker(struct thread_pool *p)
|
||||
{
|
||||
struct thread_pool_worker *w = NULL;
|
||||
|
||||
while (!w && p->thread_num) {
|
||||
wait_event(p->wait, !list_empty(&p->ready_list) ||
|
||||
!p->thread_num);
|
||||
|
||||
dprintk("%s: locking list_empty: %d, thread_num: %d.\n",
|
||||
__func__, list_empty(&p->ready_list),
|
||||
p->thread_num);
|
||||
|
||||
mutex_lock(&p->thread_lock);
|
||||
if (!list_empty(&p->ready_list)) {
|
||||
w = list_first_entry(&p->ready_list,
|
||||
struct thread_pool_worker,
|
||||
worker_entry);
|
||||
|
||||
dprintk("%s: deleting w: %p, thread_num: %d, "
|
||||
"list: %p [%p.%p].\n", __func__,
|
||||
w, p->thread_num, &p->ready_list,
|
||||
p->ready_list.prev, p->ready_list.next);
|
||||
|
||||
p->thread_num--;
|
||||
list_del(&w->worker_entry);
|
||||
}
|
||||
mutex_unlock(&p->thread_lock);
|
||||
}
|
||||
|
||||
if (w)
|
||||
thread_pool_exit_worker(w);
|
||||
dprintk("%s: deleted w: %p, thread_num: %d.\n",
|
||||
__func__, w, p->thread_num);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove a worker with given ID.
|
||||
*/
|
||||
void thread_pool_del_worker_id(struct thread_pool *p, unsigned int id)
|
||||
{
|
||||
struct thread_pool_worker *w;
|
||||
int found = 0;
|
||||
|
||||
mutex_lock(&p->thread_lock);
|
||||
list_for_each_entry(w, &p->ready_list, worker_entry) {
|
||||
if (w->id == id) {
|
||||
found = 1;
|
||||
p->thread_num--;
|
||||
list_del(&w->worker_entry);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
list_for_each_entry(w, &p->active_list, worker_entry) {
|
||||
if (w->id == id) {
|
||||
w->need_exit = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
mutex_unlock(&p->thread_lock);
|
||||
|
||||
if (found)
|
||||
thread_pool_exit_worker(w);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add new worker thread with given parameters.
|
||||
* If initialization callback fails, return error.
|
||||
*/
|
||||
int thread_pool_add_worker(struct thread_pool *p,
|
||||
char *name,
|
||||
unsigned int id,
|
||||
void *(*init)(void *private),
|
||||
void (*cleanup)(void *private),
|
||||
void *private)
|
||||
{
|
||||
struct thread_pool_worker *w;
|
||||
int err = -ENOMEM;
|
||||
|
||||
w = kzalloc(sizeof(struct thread_pool_worker), GFP_KERNEL);
|
||||
if (!w)
|
||||
goto err_out_exit;
|
||||
|
||||
w->pool = p;
|
||||
init_waitqueue_head(&w->wait);
|
||||
w->cleanup = cleanup;
|
||||
w->id = id;
|
||||
|
||||
w->thread = kthread_run(thread_pool_worker_func, w, "%s", name);
|
||||
if (IS_ERR(w->thread)) {
|
||||
err = PTR_ERR(w->thread);
|
||||
goto err_out_free;
|
||||
}
|
||||
|
||||
w->private = init(private);
|
||||
if (IS_ERR(w->private)) {
|
||||
err = PTR_ERR(w->private);
|
||||
goto err_out_stop_thread;
|
||||
}
|
||||
|
||||
mutex_lock(&p->thread_lock);
|
||||
list_add_tail(&w->worker_entry, &p->ready_list);
|
||||
p->thread_num++;
|
||||
mutex_unlock(&p->thread_lock);
|
||||
|
||||
return 0;
|
||||
|
||||
err_out_stop_thread:
|
||||
kthread_stop(w->thread);
|
||||
err_out_free:
|
||||
kfree(w);
|
||||
err_out_exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroy the whole pool.
|
||||
*/
|
||||
void thread_pool_destroy(struct thread_pool *p)
|
||||
{
|
||||
while (p->thread_num) {
|
||||
dprintk("%s: num: %d.\n", __func__, p->thread_num);
|
||||
thread_pool_del_worker(p);
|
||||
}
|
||||
|
||||
kfree(p);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a pool with given number of threads.
|
||||
* They will have sequential IDs started from zero.
|
||||
*/
|
||||
struct thread_pool *thread_pool_create(int num, char *name,
|
||||
void *(*init)(void *private),
|
||||
void (*cleanup)(void *private),
|
||||
void *private)
|
||||
{
|
||||
struct thread_pool_worker *w, *tmp;
|
||||
struct thread_pool *p;
|
||||
int err = -ENOMEM;
|
||||
int i;
|
||||
|
||||
p = kzalloc(sizeof(struct thread_pool), GFP_KERNEL);
|
||||
if (!p)
|
||||
goto err_out_exit;
|
||||
|
||||
init_waitqueue_head(&p->wait);
|
||||
mutex_init(&p->thread_lock);
|
||||
INIT_LIST_HEAD(&p->ready_list);
|
||||
INIT_LIST_HEAD(&p->active_list);
|
||||
p->thread_num = 0;
|
||||
|
||||
for (i = 0; i < num; ++i) {
|
||||
err = thread_pool_add_worker(p, name, i, init,
|
||||
cleanup, private);
|
||||
if (err)
|
||||
goto err_out_free_all;
|
||||
}
|
||||
|
||||
return p;
|
||||
|
||||
err_out_free_all:
|
||||
list_for_each_entry_safe(w, tmp, &p->ready_list, worker_entry) {
|
||||
list_del(&w->worker_entry);
|
||||
thread_pool_exit_worker(w);
|
||||
}
|
||||
kfree(p);
|
||||
err_out_exit:
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
/*
|
||||
* Schedule execution of the action on a given thread,
|
||||
* provided ID pointer has to match previously stored
|
||||
* private data.
|
||||
*/
|
||||
int thread_pool_schedule_private(struct thread_pool *p,
|
||||
int (*setup)(void *private, void *data),
|
||||
int (*action)(void *private, void *data),
|
||||
void *data, long timeout, void *id)
|
||||
{
|
||||
struct thread_pool_worker *w, *tmp, *worker = NULL;
|
||||
int err = 0;
|
||||
|
||||
while (!worker && !err) {
|
||||
timeout = wait_event_interruptible_timeout(p->wait,
|
||||
!list_empty(&p->ready_list),
|
||||
timeout);
|
||||
|
||||
if (!timeout) {
|
||||
err = -ETIMEDOUT;
|
||||
break;
|
||||
}
|
||||
|
||||
worker = NULL;
|
||||
mutex_lock(&p->thread_lock);
|
||||
list_for_each_entry_safe(w, tmp, &p->ready_list, worker_entry) {
|
||||
if (id && id != w->private)
|
||||
continue;
|
||||
|
||||
worker = w;
|
||||
|
||||
list_move_tail(&w->worker_entry, &p->active_list);
|
||||
|
||||
err = setup(w->private, data);
|
||||
if (!err) {
|
||||
w->schedule_data = data;
|
||||
w->action = action;
|
||||
w->has_data = 1;
|
||||
wake_up(&w->wait);
|
||||
} else {
|
||||
list_move_tail(&w->worker_entry,
|
||||
&p->ready_list);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
mutex_unlock(&p->thread_lock);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Schedule execution on arbitrary thread from the pool.
|
||||
*/
|
||||
int thread_pool_schedule(struct thread_pool *p,
|
||||
int (*setup)(void *private, void *data),
|
||||
int (*action)(void *private, void *data),
|
||||
void *data, long timeout)
|
||||
{
|
||||
return thread_pool_schedule_private(p, setup,
|
||||
action, data, timeout, NULL);
|
||||
}
|
|
@ -1,337 +0,0 @@
|
|||
/*
|
||||
* 2007+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net>
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/bio.h>
|
||||
#include <linux/dst.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mempool.h>
|
||||
|
||||
/*
|
||||
* Transaction memory pool size.
|
||||
*/
|
||||
static int dst_mempool_num = 32;
|
||||
module_param(dst_mempool_num, int, 0644);
|
||||
|
||||
/*
|
||||
* Transaction tree management.
|
||||
*/
|
||||
static inline int dst_trans_cmp(dst_gen_t gen, dst_gen_t new)
|
||||
{
|
||||
if (gen < new)
|
||||
return 1;
|
||||
if (gen > new)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct dst_trans *dst_trans_search(struct dst_node *node, dst_gen_t gen)
|
||||
{
|
||||
struct rb_root *root = &node->trans_root;
|
||||
struct rb_node *n = root->rb_node;
|
||||
struct dst_trans *t, *ret = NULL;
|
||||
int cmp;
|
||||
|
||||
while (n) {
|
||||
t = rb_entry(n, struct dst_trans, trans_entry);
|
||||
|
||||
cmp = dst_trans_cmp(t->gen, gen);
|
||||
if (cmp < 0)
|
||||
n = n->rb_left;
|
||||
else if (cmp > 0)
|
||||
n = n->rb_right;
|
||||
else {
|
||||
ret = t;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dprintk("%s: %s transaction: id: %llu.\n", __func__,
|
||||
(ret) ? "found" : "not found", gen);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dst_trans_insert(struct dst_trans *new)
|
||||
{
|
||||
struct rb_root *root = &new->n->trans_root;
|
||||
struct rb_node **n = &root->rb_node, *parent = NULL;
|
||||
struct dst_trans *ret = NULL, *t;
|
||||
int cmp;
|
||||
|
||||
while (*n) {
|
||||
parent = *n;
|
||||
|
||||
t = rb_entry(parent, struct dst_trans, trans_entry);
|
||||
|
||||
cmp = dst_trans_cmp(t->gen, new->gen);
|
||||
if (cmp < 0)
|
||||
n = &parent->rb_left;
|
||||
else if (cmp > 0)
|
||||
n = &parent->rb_right;
|
||||
else {
|
||||
ret = t;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
new->send_time = jiffies;
|
||||
if (ret) {
|
||||
printk(KERN_DEBUG "%s: exist: old: gen: %llu, bio: %llu/%u, "
|
||||
"send_time: %lu, new: gen: %llu, bio: %llu/%u, "
|
||||
"send_time: %lu.\n", __func__,
|
||||
ret->gen, (u64)ret->bio->bi_sector,
|
||||
ret->bio->bi_size, ret->send_time,
|
||||
new->gen, (u64)new->bio->bi_sector,
|
||||
new->bio->bi_size, new->send_time);
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
rb_link_node(&new->trans_entry, parent, n);
|
||||
rb_insert_color(&new->trans_entry, root);
|
||||
|
||||
dprintk("%s: inserted: gen: %llu, bio: %llu/%u, send_time: %lu.\n",
|
||||
__func__, new->gen, (u64)new->bio->bi_sector,
|
||||
new->bio->bi_size, new->send_time);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dst_trans_remove_nolock(struct dst_trans *t)
|
||||
{
|
||||
struct dst_node *n = t->n;
|
||||
|
||||
if (t->trans_entry.rb_parent_color) {
|
||||
rb_erase(&t->trans_entry, &n->trans_root);
|
||||
t->trans_entry.rb_parent_color = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dst_trans_remove(struct dst_trans *t)
|
||||
{
|
||||
int ret;
|
||||
struct dst_node *n = t->n;
|
||||
|
||||
mutex_lock(&n->trans_lock);
|
||||
ret = dst_trans_remove_nolock(t);
|
||||
mutex_unlock(&n->trans_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* When transaction is completed and there are no more users,
|
||||
* we complete appriate block IO request with given error status.
|
||||
*/
|
||||
void dst_trans_put(struct dst_trans *t)
|
||||
{
|
||||
if (atomic_dec_and_test(&t->refcnt)) {
|
||||
struct bio *bio = t->bio;
|
||||
|
||||
dprintk("%s: completed t: %p, gen: %llu, bio: %p.\n",
|
||||
__func__, t, t->gen, bio);
|
||||
|
||||
bio_endio(bio, t->error);
|
||||
bio_put(bio);
|
||||
|
||||
dst_node_put(t->n);
|
||||
mempool_free(t, t->n->trans_pool);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Process given block IO request: allocate transaction, insert it into the tree
|
||||
* and send/schedule crypto processing.
|
||||
*/
|
||||
int dst_process_bio(struct dst_node *n, struct bio *bio)
|
||||
{
|
||||
struct dst_trans *t;
|
||||
int err = -ENOMEM;
|
||||
|
||||
t = mempool_alloc(n->trans_pool, GFP_NOFS);
|
||||
if (!t)
|
||||
goto err_out_exit;
|
||||
|
||||
t->n = dst_node_get(n);
|
||||
t->bio = bio;
|
||||
t->error = 0;
|
||||
t->retries = 0;
|
||||
atomic_set(&t->refcnt, 1);
|
||||
t->gen = atomic_long_inc_return(&n->gen);
|
||||
|
||||
t->enc = bio_data_dir(bio);
|
||||
dst_bio_to_cmd(bio, &t->cmd, DST_IO, t->gen);
|
||||
|
||||
mutex_lock(&n->trans_lock);
|
||||
err = dst_trans_insert(t);
|
||||
mutex_unlock(&n->trans_lock);
|
||||
if (err)
|
||||
goto err_out_free;
|
||||
|
||||
dprintk("%s: gen: %llu, bio: %llu/%u, dir/enc: %d, need_crypto: %d.\n",
|
||||
__func__, t->gen, (u64)bio->bi_sector,
|
||||
bio->bi_size, t->enc, dst_need_crypto(n));
|
||||
|
||||
if (dst_need_crypto(n) && t->enc)
|
||||
dst_trans_crypto(t);
|
||||
else
|
||||
dst_trans_send(t);
|
||||
|
||||
return 0;
|
||||
|
||||
err_out_free:
|
||||
dst_node_put(n);
|
||||
mempool_free(t, n->trans_pool);
|
||||
err_out_exit:
|
||||
bio_endio(bio, err);
|
||||
bio_put(bio);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Scan for timeout/stale transactions.
|
||||
* Each transaction is being resent multiple times before error completion.
|
||||
*/
|
||||
static void dst_trans_scan(struct work_struct *work)
|
||||
{
|
||||
struct dst_node *n = container_of(work, struct dst_node,
|
||||
trans_work.work);
|
||||
struct rb_node *rb_node;
|
||||
struct dst_trans *t;
|
||||
unsigned long timeout = n->trans_scan_timeout;
|
||||
int num = 10 * n->trans_max_retries;
|
||||
|
||||
mutex_lock(&n->trans_lock);
|
||||
|
||||
for (rb_node = rb_first(&n->trans_root); rb_node; ) {
|
||||
t = rb_entry(rb_node, struct dst_trans, trans_entry);
|
||||
|
||||
if (timeout && time_after(t->send_time + timeout, jiffies)
|
||||
&& t->retries == 0)
|
||||
break;
|
||||
#if 0
|
||||
dprintk("%s: t: %p, gen: %llu, n: %s, retries: %u, max: %u.\n",
|
||||
__func__, t, t->gen, n->name,
|
||||
t->retries, n->trans_max_retries);
|
||||
#endif
|
||||
if (--num == 0)
|
||||
break;
|
||||
|
||||
dst_trans_get(t);
|
||||
|
||||
rb_node = rb_next(rb_node);
|
||||
|
||||
if (timeout && (++t->retries < n->trans_max_retries)) {
|
||||
dst_trans_send(t);
|
||||
} else {
|
||||
t->error = -ETIMEDOUT;
|
||||
dst_trans_remove_nolock(t);
|
||||
dst_trans_put(t);
|
||||
}
|
||||
|
||||
dst_trans_put(t);
|
||||
}
|
||||
|
||||
mutex_unlock(&n->trans_lock);
|
||||
|
||||
/*
|
||||
* If no timeout specified then system is in the middle of exiting
|
||||
* process, so no need to reschedule scanning process again.
|
||||
*/
|
||||
if (timeout) {
|
||||
if (!num)
|
||||
timeout = HZ;
|
||||
schedule_delayed_work(&n->trans_work, timeout);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Flush all transactions and mark them as timed out.
|
||||
* Destroy transaction pools.
|
||||
*/
|
||||
void dst_node_trans_exit(struct dst_node *n)
|
||||
{
|
||||
struct dst_trans *t;
|
||||
struct rb_node *rb_node;
|
||||
|
||||
if (!n->trans_cache)
|
||||
return;
|
||||
|
||||
dprintk("%s: n: %p, cancelling the work.\n", __func__, n);
|
||||
cancel_delayed_work_sync(&n->trans_work);
|
||||
flush_scheduled_work();
|
||||
dprintk("%s: n: %p, work has been cancelled.\n", __func__, n);
|
||||
|
||||
for (rb_node = rb_first(&n->trans_root); rb_node; ) {
|
||||
t = rb_entry(rb_node, struct dst_trans, trans_entry);
|
||||
|
||||
dprintk("%s: t: %p, gen: %llu, n: %s.\n",
|
||||
__func__, t, t->gen, n->name);
|
||||
|
||||
rb_node = rb_next(rb_node);
|
||||
|
||||
t->error = -ETIMEDOUT;
|
||||
dst_trans_remove_nolock(t);
|
||||
dst_trans_put(t);
|
||||
}
|
||||
|
||||
mempool_destroy(n->trans_pool);
|
||||
kmem_cache_destroy(n->trans_cache);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize transaction storage for given node.
|
||||
* Transaction stores not only control information,
|
||||
* but also network command and crypto data (if needed)
|
||||
* to reduce number of allocations. Thus transaction size
|
||||
* differs from node to node.
|
||||
*/
|
||||
int dst_node_trans_init(struct dst_node *n, unsigned int size)
|
||||
{
|
||||
/*
|
||||
* We need this, since node with given name can be dropped from the
|
||||
* hash table, but be still alive, so subsequent creation of the node
|
||||
* with the same name may collide with existing cache name.
|
||||
*/
|
||||
|
||||
snprintf(n->cache_name, sizeof(n->cache_name), "%s-%p", n->name, n);
|
||||
|
||||
n->trans_cache = kmem_cache_create(n->cache_name,
|
||||
size + n->crypto.crypto_attached_size,
|
||||
0, 0, NULL);
|
||||
if (!n->trans_cache)
|
||||
goto err_out_exit;
|
||||
|
||||
n->trans_pool = mempool_create_slab_pool(dst_mempool_num,
|
||||
n->trans_cache);
|
||||
if (!n->trans_pool)
|
||||
goto err_out_cache_destroy;
|
||||
|
||||
mutex_init(&n->trans_lock);
|
||||
n->trans_root = RB_ROOT;
|
||||
|
||||
INIT_DELAYED_WORK(&n->trans_work, dst_trans_scan);
|
||||
schedule_delayed_work(&n->trans_work, n->trans_scan_timeout);
|
||||
|
||||
dprintk("%s: n: %p, size: %u, crypto: %u.\n",
|
||||
__func__, n, size, n->crypto.crypto_attached_size);
|
||||
|
||||
return 0;
|
||||
|
||||
err_out_cache_destroy:
|
||||
kmem_cache_destroy(n->trans_cache);
|
||||
err_out_exit:
|
||||
return -ENOMEM;
|
||||
}
|
|
@ -47,7 +47,7 @@ config PANEL_PROFILE
|
|||
config PANEL_KEYPAD
|
||||
depends on PANEL && PANEL_PROFILE="0"
|
||||
int "Keypad type (0=none, 1=old 6 keys, 2=new 6 keys, 3=Nexcom 4 keys)"
|
||||
range 0 4
|
||||
range 0 3
|
||||
default 0
|
||||
---help---
|
||||
This enables and configures a keypad connected to the parallel port.
|
||||
|
|
|
@ -378,7 +378,7 @@ static unsigned char lcd_bits[LCD_PORTS][LCD_BITS][BIT_STATES];
|
|||
|
||||
#ifdef CONFIG_PANEL_LCD_CHARSET
|
||||
#undef DEFAULT_LCD_CHARSET
|
||||
#define DEFAULT_LCD_CHARSET
|
||||
#define DEFAULT_LCD_CHARSET CONFIG_PANEL_LCD_CHARSET
|
||||
#endif
|
||||
|
||||
#endif /* DEFAULT_PROFILE == 0 */
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
TODO:
|
||||
- Add support for swap notifiers
|
||||
- Remove CONFIG_ARM hack
|
||||
|
||||
Please send patches to Greg Kroah-Hartman <greg@kroah.com> and
|
||||
Nitin Gupta <ngupta@vflare.org>
|
||||
|
|
|
@ -222,28 +222,6 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void ramzswap_flush_dcache_page(struct page *page)
|
||||
{
|
||||
#ifdef CONFIG_ARM
|
||||
int flag = 0;
|
||||
/*
|
||||
* Ugly hack to get flush_dcache_page() work on ARM.
|
||||
* page_mapping(page) == NULL after clearing this swap cache flag.
|
||||
* Without clearing this flag, flush_dcache_page() will simply set
|
||||
* "PG_dcache_dirty" bit and return.
|
||||
*/
|
||||
if (PageSwapCache(page)) {
|
||||
flag = 1;
|
||||
ClearPageSwapCache(page);
|
||||
}
|
||||
#endif
|
||||
flush_dcache_page(page);
|
||||
#ifdef CONFIG_ARM
|
||||
if (flag)
|
||||
SetPageSwapCache(page);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ramzswap_ioctl_get_stats(struct ramzswap *rzs,
|
||||
struct ramzswap_ioctl_stats *s)
|
||||
{
|
||||
|
@ -655,7 +633,7 @@ static int handle_zero_page(struct bio *bio)
|
|||
memset(user_mem, 0, PAGE_SIZE);
|
||||
kunmap_atomic(user_mem, KM_USER0);
|
||||
|
||||
ramzswap_flush_dcache_page(page);
|
||||
flush_dcache_page(page);
|
||||
|
||||
set_bit(BIO_UPTODATE, &bio->bi_flags);
|
||||
bio_endio(bio, 0);
|
||||
|
@ -679,7 +657,7 @@ static int handle_uncompressed_page(struct ramzswap *rzs, struct bio *bio)
|
|||
kunmap_atomic(user_mem, KM_USER0);
|
||||
kunmap_atomic(cmem, KM_USER1);
|
||||
|
||||
ramzswap_flush_dcache_page(page);
|
||||
flush_dcache_page(page);
|
||||
|
||||
set_bit(BIO_UPTODATE, &bio->bi_flags);
|
||||
bio_endio(bio, 0);
|
||||
|
@ -779,7 +757,7 @@ static int ramzswap_read(struct ramzswap *rzs, struct bio *bio)
|
|||
goto out;
|
||||
}
|
||||
|
||||
ramzswap_flush_dcache_page(page);
|
||||
flush_dcache_page(page);
|
||||
|
||||
set_bit(BIO_UPTODATE, &bio->bi_flags);
|
||||
bio_endio(bio, 0);
|
||||
|
|
|
@ -1318,13 +1318,13 @@ extern int ieee80211_encrypt_fragment(
|
|||
struct sk_buff *frag,
|
||||
int hdr_len);
|
||||
|
||||
extern int ieee80211_xmit(struct sk_buff *skb,
|
||||
extern int ieee80211_rtl_xmit(struct sk_buff *skb,
|
||||
struct net_device *dev);
|
||||
extern void ieee80211_txb_free(struct ieee80211_txb *);
|
||||
|
||||
|
||||
/* ieee80211_rx.c */
|
||||
extern int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
|
||||
extern int ieee80211_rtl_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
|
||||
struct ieee80211_rx_stats *rx_stats);
|
||||
extern void ieee80211_rx_mgt(struct ieee80211_device *ieee,
|
||||
struct ieee80211_hdr_4addr *header,
|
||||
|
@ -1376,8 +1376,8 @@ extern void ieee80211_stop_protocol(struct ieee80211_device *ieee);
|
|||
extern void ieee80211_softmac_start_protocol(struct ieee80211_device *ieee);
|
||||
extern void ieee80211_softmac_stop_protocol(struct ieee80211_device *ieee);
|
||||
extern void ieee80211_reset_queue(struct ieee80211_device *ieee);
|
||||
extern void ieee80211_wake_queue(struct ieee80211_device *ieee);
|
||||
extern void ieee80211_stop_queue(struct ieee80211_device *ieee);
|
||||
extern void ieee80211_rtl_wake_queue(struct ieee80211_device *ieee);
|
||||
extern void ieee80211_rtl_stop_queue(struct ieee80211_device *ieee);
|
||||
extern struct sk_buff *ieee80211_get_beacon(struct ieee80211_device *ieee);
|
||||
extern void ieee80211_start_send_beacons(struct ieee80211_device *ieee);
|
||||
extern void ieee80211_stop_send_beacons(struct ieee80211_device *ieee);
|
||||
|
@ -1385,7 +1385,7 @@ extern int ieee80211_wpa_supplicant_ioctl(struct ieee80211_device *ieee, struct
|
|||
extern void notify_wx_assoc_event(struct ieee80211_device *ieee);
|
||||
extern void ieee80211_ps_tx_ack(struct ieee80211_device *ieee, short success);
|
||||
extern void SendDisassociation(struct ieee80211_device *ieee,u8* asSta,u8 asRsn);
|
||||
extern void ieee80211_start_scan(struct ieee80211_device *ieee);
|
||||
extern void ieee80211_rtl_start_scan(struct ieee80211_device *ieee);
|
||||
|
||||
//Add for RF power on power off by lizhaoming 080512
|
||||
extern void SendDisassociation(struct ieee80211_device *ieee,
|
||||
|
|
|
@ -469,7 +469,7 @@ drop:
|
|||
/* All received frames are sent to this function. @skb contains the frame in
|
||||
* IEEE 802.11 format, i.e., in the format it was sent over air.
|
||||
* This function is called only as a tasklet (software IRQ). */
|
||||
int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
|
||||
int ieee80211_rtl_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
|
||||
struct ieee80211_rx_stats *rx_stats)
|
||||
{
|
||||
struct net_device *dev = ieee->dev;
|
||||
|
|
|
@ -689,7 +689,7 @@ void ieee80211_stop_scan(struct ieee80211_device *ieee)
|
|||
}
|
||||
|
||||
/* called with ieee->lock held */
|
||||
void ieee80211_start_scan(struct ieee80211_device *ieee)
|
||||
void ieee80211_rtl_start_scan(struct ieee80211_device *ieee)
|
||||
{
|
||||
if(IS_DOT11D_ENABLE(ieee) )
|
||||
{
|
||||
|
@ -1196,7 +1196,7 @@ void ieee80211_associate_step1(struct ieee80211_device *ieee)
|
|||
}
|
||||
}
|
||||
|
||||
void ieee80211_auth_challenge(struct ieee80211_device *ieee, u8 *challenge, int chlen)
|
||||
void ieee80211_rtl_auth_challenge(struct ieee80211_device *ieee, u8 *challenge, int chlen)
|
||||
{
|
||||
u8 *c;
|
||||
struct sk_buff *skb;
|
||||
|
@ -1898,7 +1898,7 @@ associate_complete:
|
|||
|
||||
ieee80211_associate_step2(ieee);
|
||||
}else{
|
||||
ieee80211_auth_challenge(ieee, challenge, chlen);
|
||||
ieee80211_rtl_auth_challenge(ieee, challenge, chlen);
|
||||
}
|
||||
}else{
|
||||
ieee->softmac_stats.rx_auth_rs_err++;
|
||||
|
@ -2047,7 +2047,7 @@ void ieee80211_reset_queue(struct ieee80211_device *ieee)
|
|||
|
||||
}
|
||||
|
||||
void ieee80211_wake_queue(struct ieee80211_device *ieee)
|
||||
void ieee80211_rtl_wake_queue(struct ieee80211_device *ieee)
|
||||
{
|
||||
|
||||
unsigned long flags;
|
||||
|
@ -2089,7 +2089,7 @@ exit :
|
|||
}
|
||||
|
||||
|
||||
void ieee80211_stop_queue(struct ieee80211_device *ieee)
|
||||
void ieee80211_rtl_stop_queue(struct ieee80211_device *ieee)
|
||||
{
|
||||
//unsigned long flags;
|
||||
//spin_lock_irqsave(&ieee->lock,flags);
|
||||
|
@ -2301,7 +2301,7 @@ void ieee80211_start_bss(struct ieee80211_device *ieee)
|
|||
//#else
|
||||
if (ieee->state == IEEE80211_NOLINK){
|
||||
ieee->actscanning = true;
|
||||
ieee80211_start_scan(ieee);
|
||||
ieee80211_rtl_start_scan(ieee);
|
||||
}
|
||||
//#endif
|
||||
spin_unlock_irqrestore(&ieee->lock, flags);
|
||||
|
@ -2357,7 +2357,7 @@ void ieee80211_associate_retry_wq(struct work_struct *work)
|
|||
if(ieee->state == IEEE80211_NOLINK){
|
||||
ieee->beinretry = false;
|
||||
ieee->actscanning = true;
|
||||
ieee80211_start_scan(ieee);
|
||||
ieee80211_rtl_start_scan(ieee);
|
||||
}
|
||||
//YJ,add,080828, notify os here
|
||||
if(ieee->state == IEEE80211_NOLINK)
|
||||
|
|
|
@ -304,7 +304,7 @@ ieee80211_classify(struct sk_buff *skb, struct ieee80211_network *network)
|
|||
}
|
||||
|
||||
/* SKBs are added to the ieee->tx_queue. */
|
||||
int ieee80211_xmit(struct sk_buff *skb,
|
||||
int ieee80211_rtl_xmit(struct sk_buff *skb,
|
||||
struct net_device *dev)
|
||||
{
|
||||
struct ieee80211_device *ieee = netdev_priv(dev);
|
||||
|
|
|
@ -1811,7 +1811,7 @@ void rtl8180_rx(struct net_device *dev)
|
|||
if(priv->rx_skb->len > 4)
|
||||
skb_trim(priv->rx_skb,priv->rx_skb->len-4);
|
||||
#ifndef RX_DONT_PASS_UL
|
||||
if(!ieee80211_rx(priv->ieee80211,
|
||||
if(!ieee80211_rtl_rx(priv->ieee80211,
|
||||
priv->rx_skb, &stats)){
|
||||
#endif // RX_DONT_PASS_UL
|
||||
|
||||
|
@ -1917,11 +1917,11 @@ rate)
|
|||
if (!check_nic_enought_desc(dev, priority)){
|
||||
DMESGW("Error: no descriptor left by previous TX (avail %d) ",
|
||||
get_curr_tx_free_desc(dev, priority));
|
||||
ieee80211_stop_queue(priv->ieee80211);
|
||||
ieee80211_rtl_stop_queue(priv->ieee80211);
|
||||
}
|
||||
rtl8180_tx(dev, skb->data, skb->len, priority, morefrag,0,rate);
|
||||
if (!check_nic_enought_desc(dev, priority))
|
||||
ieee80211_stop_queue(priv->ieee80211);
|
||||
ieee80211_rtl_stop_queue(priv->ieee80211);
|
||||
|
||||
spin_unlock_irqrestore(&priv->tx_lock,flags);
|
||||
}
|
||||
|
@ -3680,7 +3680,7 @@ static const struct net_device_ops rtl8180_netdev_ops = {
|
|||
.ndo_set_mac_address = r8180_set_mac_adr,
|
||||
.ndo_validate_addr = eth_validate_addr,
|
||||
.ndo_change_mtu = eth_change_mtu,
|
||||
.ndo_start_xmit = ieee80211_xmit,
|
||||
.ndo_start_xmit = ieee80211_rtl_xmit,
|
||||
};
|
||||
|
||||
static int __devinit rtl8180_pci_probe(struct pci_dev *pdev,
|
||||
|
@ -3900,7 +3900,7 @@ void rtl8180_try_wake_queue(struct net_device *dev, int pri)
|
|||
spin_unlock_irqrestore(&priv->tx_lock,flags);
|
||||
|
||||
if(enough_desc)
|
||||
ieee80211_wake_queue(priv->ieee80211);
|
||||
ieee80211_rtl_wake_queue(priv->ieee80211);
|
||||
}
|
||||
|
||||
void rtl8180_tx_isr(struct net_device *dev, int pri,short error)
|
||||
|
|
|
@ -377,7 +377,7 @@ static int r8180_wx_set_scan(struct net_device *dev, struct iw_request_info *a,
|
|||
// queue_work(priv->ieee80211->wq, &priv->ieee80211->wx_sync_scan_wq);
|
||||
//printk("start scan============================>\n");
|
||||
ieee80211_softmac_ips_scan_syncro(priv->ieee80211);
|
||||
//ieee80211_start_scan(priv->ieee80211);
|
||||
//ieee80211_rtl_start_scan(priv->ieee80211);
|
||||
/* intentionally forget to up sem */
|
||||
// up(&priv->ieee80211->wx_sem);
|
||||
ret = 0;
|
||||
|
|
|
@ -303,8 +303,8 @@ enum _ReasonCode{
|
|||
#define ieee80211_rx_mgt ieee80211_rx_mgt_rsl
|
||||
|
||||
#define ieee80211_get_beacon ieee80211_get_beacon_rsl
|
||||
#define ieee80211_wake_queue ieee80211_wake_queue_rsl
|
||||
#define ieee80211_stop_queue ieee80211_stop_queue_rsl
|
||||
#define ieee80211_rtl_wake_queue ieee80211_rtl_wake_queue_rsl
|
||||
#define ieee80211_rtl_stop_queue ieee80211_rtl_stop_queue_rsl
|
||||
#define ieee80211_reset_queue ieee80211_reset_queue_rsl
|
||||
#define ieee80211_softmac_stop_protocol ieee80211_softmac_stop_protocol_rsl
|
||||
#define ieee80211_softmac_start_protocol ieee80211_softmac_start_protocol_rsl
|
||||
|
@ -2435,13 +2435,13 @@ extern int ieee80211_encrypt_fragment(
|
|||
struct sk_buff *frag,
|
||||
int hdr_len);
|
||||
|
||||
extern int ieee80211_xmit(struct sk_buff *skb,
|
||||
extern int ieee80211_rtl_xmit(struct sk_buff *skb,
|
||||
struct net_device *dev);
|
||||
extern void ieee80211_txb_free(struct ieee80211_txb *);
|
||||
|
||||
|
||||
/* ieee80211_rx.c */
|
||||
extern int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
|
||||
extern int ieee80211_rtl_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
|
||||
struct ieee80211_rx_stats *rx_stats);
|
||||
extern void ieee80211_rx_mgt(struct ieee80211_device *ieee,
|
||||
struct ieee80211_hdr_4addr *header,
|
||||
|
@ -2502,8 +2502,8 @@ extern void ieee80211_stop_protocol(struct ieee80211_device *ieee);
|
|||
extern void ieee80211_softmac_start_protocol(struct ieee80211_device *ieee);
|
||||
extern void ieee80211_softmac_stop_protocol(struct ieee80211_device *ieee);
|
||||
extern void ieee80211_reset_queue(struct ieee80211_device *ieee);
|
||||
extern void ieee80211_wake_queue(struct ieee80211_device *ieee);
|
||||
extern void ieee80211_stop_queue(struct ieee80211_device *ieee);
|
||||
extern void ieee80211_rtl_wake_queue(struct ieee80211_device *ieee);
|
||||
extern void ieee80211_rtl_stop_queue(struct ieee80211_device *ieee);
|
||||
extern struct sk_buff *ieee80211_get_beacon(struct ieee80211_device *ieee);
|
||||
extern void ieee80211_start_send_beacons(struct ieee80211_device *ieee);
|
||||
extern void ieee80211_stop_send_beacons(struct ieee80211_device *ieee);
|
||||
|
|
|
@ -333,8 +333,8 @@ enum _ReasonCode{
|
|||
#define ieee80211_rx_mgt ieee80211_rx_mgt_rsl
|
||||
|
||||
#define ieee80211_get_beacon ieee80211_get_beacon_rsl
|
||||
#define ieee80211_wake_queue ieee80211_wake_queue_rsl
|
||||
#define ieee80211_stop_queue ieee80211_stop_queue_rsl
|
||||
#define ieee80211_rtl_wake_queue ieee80211_rtl_wake_queue_rsl
|
||||
#define ieee80211_rtl_stop_queue ieee80211_rtl_stop_queue_rsl
|
||||
#define ieee80211_reset_queue ieee80211_reset_queue_rsl
|
||||
#define ieee80211_softmac_stop_protocol ieee80211_softmac_stop_protocol_rsl
|
||||
#define ieee80211_softmac_start_protocol ieee80211_softmac_start_protocol_rsl
|
||||
|
@ -2546,13 +2546,13 @@ extern int ieee80211_encrypt_fragment(
|
|||
struct sk_buff *frag,
|
||||
int hdr_len);
|
||||
|
||||
extern int ieee80211_xmit(struct sk_buff *skb,
|
||||
extern int ieee80211_rtl_xmit(struct sk_buff *skb,
|
||||
struct net_device *dev);
|
||||
extern void ieee80211_txb_free(struct ieee80211_txb *);
|
||||
|
||||
|
||||
/* ieee80211_rx.c */
|
||||
extern int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
|
||||
extern int ieee80211_rtl_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
|
||||
struct ieee80211_rx_stats *rx_stats);
|
||||
extern void ieee80211_rx_mgt(struct ieee80211_device *ieee,
|
||||
struct ieee80211_hdr_4addr *header,
|
||||
|
@ -2613,8 +2613,8 @@ extern void ieee80211_stop_protocol(struct ieee80211_device *ieee);
|
|||
extern void ieee80211_softmac_start_protocol(struct ieee80211_device *ieee);
|
||||
extern void ieee80211_softmac_stop_protocol(struct ieee80211_device *ieee);
|
||||
extern void ieee80211_reset_queue(struct ieee80211_device *ieee);
|
||||
extern void ieee80211_wake_queue(struct ieee80211_device *ieee);
|
||||
extern void ieee80211_stop_queue(struct ieee80211_device *ieee);
|
||||
extern void ieee80211_rtl_wake_queue(struct ieee80211_device *ieee);
|
||||
extern void ieee80211_rtl_stop_queue(struct ieee80211_device *ieee);
|
||||
extern struct sk_buff *ieee80211_get_beacon(struct ieee80211_device *ieee);
|
||||
extern void ieee80211_start_send_beacons(struct ieee80211_device *ieee);
|
||||
extern void ieee80211_stop_send_beacons(struct ieee80211_device *ieee);
|
||||
|
|
|
@ -119,7 +119,7 @@ struct net_device *alloc_ieee80211(int sizeof_priv)
|
|||
ieee = (struct ieee80211_device *)dev->priv;
|
||||
#endif
|
||||
#if 0
|
||||
dev->hard_start_xmit = ieee80211_xmit;
|
||||
dev->hard_start_xmit = ieee80211_rtl_xmit;
|
||||
#endif
|
||||
|
||||
memset(ieee, 0, sizeof(struct ieee80211_device)+sizeof_priv);
|
||||
|
@ -333,7 +333,7 @@ extern void ieee80211_crypto_ccmp_exit(void);
|
|||
extern int ieee80211_crypto_wep_init(void);
|
||||
extern void ieee80211_crypto_wep_exit(void);
|
||||
|
||||
int __init ieee80211_init(void)
|
||||
int __init ieee80211_rtl_init(void)
|
||||
{
|
||||
struct proc_dir_entry *e;
|
||||
int retval;
|
||||
|
@ -389,7 +389,7 @@ int __init ieee80211_init(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void __exit ieee80211_exit(void)
|
||||
void __exit ieee80211_rtl_exit(void)
|
||||
{
|
||||
if (ieee80211_proc) {
|
||||
remove_proc_entry("debug_level", ieee80211_proc);
|
||||
|
@ -412,8 +412,8 @@ module_param(debug, int, 0444);
|
|||
MODULE_PARM_DESC(debug, "debug output mask");
|
||||
|
||||
|
||||
//module_exit(ieee80211_exit);
|
||||
//module_init(ieee80211_init);
|
||||
//module_exit(ieee80211_rtl_exit);
|
||||
//module_init(ieee80211_rtl_init);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
|
|
@ -923,7 +923,7 @@ u8 parse_subframe(struct sk_buff *skb,
|
|||
/* All received frames are sent to this function. @skb contains the frame in
|
||||
* IEEE 802.11 format, i.e., in the format it was sent over air.
|
||||
* This function is called only as a tasklet (software IRQ). */
|
||||
int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
|
||||
int ieee80211_rtl_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
|
||||
struct ieee80211_rx_stats *rx_stats)
|
||||
{
|
||||
struct net_device *dev = ieee->dev;
|
||||
|
|
|
@ -684,7 +684,7 @@ void ieee80211_stop_scan(struct ieee80211_device *ieee)
|
|||
}
|
||||
|
||||
/* called with ieee->lock held */
|
||||
void ieee80211_start_scan(struct ieee80211_device *ieee)
|
||||
void ieee80211_rtl_start_scan(struct ieee80211_device *ieee)
|
||||
{
|
||||
#ifdef ENABLE_DOT11D
|
||||
if(IS_DOT11D_ENABLE(ieee) )
|
||||
|
@ -1430,7 +1430,7 @@ void ieee80211_associate_step1(struct ieee80211_device *ieee)
|
|||
}
|
||||
}
|
||||
|
||||
void ieee80211_auth_challenge(struct ieee80211_device *ieee, u8 *challenge, int chlen)
|
||||
void ieee80211_rtl_auth_challenge(struct ieee80211_device *ieee, u8 *challenge, int chlen)
|
||||
{
|
||||
u8 *c;
|
||||
struct sk_buff *skb;
|
||||
|
@ -2262,7 +2262,7 @@ ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb,
|
|||
|
||||
ieee80211_associate_step2(ieee);
|
||||
}else{
|
||||
ieee80211_auth_challenge(ieee, challenge, chlen);
|
||||
ieee80211_rtl_auth_challenge(ieee, challenge, chlen);
|
||||
}
|
||||
}else{
|
||||
ieee->softmac_stats.rx_auth_rs_err++;
|
||||
|
@ -2376,7 +2376,7 @@ void ieee80211_softmac_xmit(struct ieee80211_txb *txb, struct ieee80211_device *
|
|||
* to check it any more.
|
||||
* */
|
||||
//printk("error:no descriptor left@queue_index %d\n", queue_index);
|
||||
//ieee80211_stop_queue(ieee);
|
||||
//ieee80211_rtl_stop_queue(ieee);
|
||||
#ifdef USB_TX_DRIVER_AGGREGATION_ENABLE
|
||||
skb_queue_tail(&ieee->skb_drv_aggQ[queue_index], txb->fragments[i]);
|
||||
#else
|
||||
|
@ -2440,7 +2440,7 @@ void ieee80211_reset_queue(struct ieee80211_device *ieee)
|
|||
|
||||
}
|
||||
|
||||
void ieee80211_wake_queue(struct ieee80211_device *ieee)
|
||||
void ieee80211_rtl_wake_queue(struct ieee80211_device *ieee)
|
||||
{
|
||||
|
||||
unsigned long flags;
|
||||
|
@ -2481,7 +2481,7 @@ exit :
|
|||
}
|
||||
|
||||
|
||||
void ieee80211_stop_queue(struct ieee80211_device *ieee)
|
||||
void ieee80211_rtl_stop_queue(struct ieee80211_device *ieee)
|
||||
{
|
||||
//unsigned long flags;
|
||||
//spin_lock_irqsave(&ieee->lock,flags);
|
||||
|
@ -2706,7 +2706,7 @@ void ieee80211_start_bss(struct ieee80211_device *ieee)
|
|||
|
||||
if (ieee->state == IEEE80211_NOLINK){
|
||||
ieee->actscanning = true;
|
||||
ieee80211_start_scan(ieee);
|
||||
ieee80211_rtl_start_scan(ieee);
|
||||
}
|
||||
spin_unlock_irqrestore(&ieee->lock, flags);
|
||||
}
|
||||
|
@ -2775,7 +2775,7 @@ void ieee80211_associate_retry_wq(struct ieee80211_device *ieee)
|
|||
{
|
||||
ieee->is_roaming= false;
|
||||
ieee->actscanning = true;
|
||||
ieee80211_start_scan(ieee);
|
||||
ieee80211_rtl_start_scan(ieee);
|
||||
}
|
||||
spin_unlock_irqrestore(&ieee->lock, flags);
|
||||
|
||||
|
@ -3497,8 +3497,8 @@ void notify_wx_assoc_event(struct ieee80211_device *ieee)
|
|||
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
|
||||
//EXPORT_SYMBOL(ieee80211_get_beacon);
|
||||
//EXPORT_SYMBOL(ieee80211_wake_queue);
|
||||
//EXPORT_SYMBOL(ieee80211_stop_queue);
|
||||
//EXPORT_SYMBOL(ieee80211_rtl_wake_queue);
|
||||
//EXPORT_SYMBOL(ieee80211_rtl_stop_queue);
|
||||
//EXPORT_SYMBOL(ieee80211_reset_queue);
|
||||
//EXPORT_SYMBOL(ieee80211_softmac_stop_protocol);
|
||||
//EXPORT_SYMBOL(ieee80211_softmac_start_protocol);
|
||||
|
@ -3518,8 +3518,8 @@ void notify_wx_assoc_event(struct ieee80211_device *ieee)
|
|||
//EXPORT_SYMBOL(ieee80211_start_scan_syncro);
|
||||
#else
|
||||
EXPORT_SYMBOL_NOVERS(ieee80211_get_beacon);
|
||||
EXPORT_SYMBOL_NOVERS(ieee80211_wake_queue);
|
||||
EXPORT_SYMBOL_NOVERS(ieee80211_stop_queue);
|
||||
EXPORT_SYMBOL_NOVERS(ieee80211_rtl_wake_queue);
|
||||
EXPORT_SYMBOL_NOVERS(ieee80211_rtl_stop_queue);
|
||||
EXPORT_SYMBOL_NOVERS(ieee80211_reset_queue);
|
||||
EXPORT_SYMBOL_NOVERS(ieee80211_softmac_stop_protocol);
|
||||
EXPORT_SYMBOL_NOVERS(ieee80211_softmac_start_protocol);
|
||||
|
|
|
@ -604,7 +604,7 @@ void ieee80211_query_seqnum(struct ieee80211_device*ieee, struct sk_buff* skb, u
|
|||
}
|
||||
}
|
||||
|
||||
int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
int ieee80211_rtl_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
|
||||
struct ieee80211_device *ieee = netdev_priv(dev);
|
||||
|
|
|
@ -976,7 +976,7 @@ int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len)
|
|||
{
|
||||
if (len != ie[1]+2)
|
||||
{
|
||||
printk("len:%d, ie:%d\n", len, ie[1]);
|
||||
printk("len:%zu, ie:%d\n", len, ie[1]);
|
||||
return -EINVAL;
|
||||
}
|
||||
buf = kmalloc(len, GFP_KERNEL);
|
||||
|
|
|
@ -382,7 +382,7 @@ int ieee80211_rx_ADDBAReq( struct ieee80211_device* ieee, struct sk_buff *skb)
|
|||
|
||||
if (skb->len < sizeof( struct ieee80211_hdr_3addr) + 9)
|
||||
{
|
||||
IEEE80211_DEBUG(IEEE80211_DL_ERR, " Invalid skb len in BAREQ(%d / %d)\n", skb->len, (sizeof( struct ieee80211_hdr_3addr) + 9));
|
||||
IEEE80211_DEBUG(IEEE80211_DL_ERR, " Invalid skb len in BAREQ(%d / %zu)\n", skb->len, (sizeof( struct ieee80211_hdr_3addr) + 9));
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -481,7 +481,7 @@ int ieee80211_rx_ADDBARsp( struct ieee80211_device* ieee, struct sk_buff *skb)
|
|||
|
||||
if (skb->len < sizeof( struct ieee80211_hdr_3addr) + 9)
|
||||
{
|
||||
IEEE80211_DEBUG(IEEE80211_DL_ERR, " Invalid skb len in BARSP(%d / %d)\n", skb->len, (sizeof( struct ieee80211_hdr_3addr) + 9));
|
||||
IEEE80211_DEBUG(IEEE80211_DL_ERR, " Invalid skb len in BARSP(%d / %zu)\n", skb->len, (sizeof( struct ieee80211_hdr_3addr) + 9));
|
||||
return -1;
|
||||
}
|
||||
rsp = ( struct ieee80211_hdr_3addr*)skb->data;
|
||||
|
@ -611,7 +611,7 @@ int ieee80211_rx_DELBA(struct ieee80211_device* ieee,struct sk_buff *skb)
|
|||
|
||||
if (skb->len < sizeof( struct ieee80211_hdr_3addr) + 6)
|
||||
{
|
||||
IEEE80211_DEBUG(IEEE80211_DL_ERR, " Invalid skb len in DELBA(%d / %d)\n", skb->len, (sizeof( struct ieee80211_hdr_3addr) + 6));
|
||||
IEEE80211_DEBUG(IEEE80211_DL_ERR, " Invalid skb len in DELBA(%d / %zu)\n", skb->len, (sizeof( struct ieee80211_hdr_3addr) + 6));
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
|
@ -5795,7 +5795,7 @@ static void rtl8192_rx(struct net_device *dev)
|
|||
stats.fragoffset = 0;
|
||||
stats.ntotalfrag = 1;
|
||||
|
||||
if(!ieee80211_rx(priv->ieee80211, skb, &stats)){
|
||||
if(!ieee80211_rtl_rx(priv->ieee80211, skb, &stats)){
|
||||
dev_kfree_skb_any(skb);
|
||||
} else {
|
||||
priv->stats.rxok++;
|
||||
|
@ -5837,7 +5837,7 @@ static const struct net_device_ops rtl8192_netdev_ops = {
|
|||
.ndo_do_ioctl = rtl8192_ioctl,
|
||||
.ndo_set_multicast_list = r8192_set_multicast,
|
||||
.ndo_set_mac_address = r8192_set_mac_adr,
|
||||
.ndo_start_xmit = ieee80211_xmit,
|
||||
.ndo_start_xmit = ieee80211_rtl_xmit,
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -6121,14 +6121,14 @@ static void __devexit rtl8192_pci_disconnect(struct pci_dev *pdev)
|
|||
RT_TRACE(COMP_DOWN, "wlan driver removed\n");
|
||||
}
|
||||
|
||||
extern int ieee80211_init(void);
|
||||
extern void ieee80211_exit(void);
|
||||
extern int ieee80211_rtl_init(void);
|
||||
extern void ieee80211_rtl_exit(void);
|
||||
|
||||
static int __init rtl8192_pci_module_init(void)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = ieee80211_init();
|
||||
retval = ieee80211_rtl_init();
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
|
@ -6153,7 +6153,7 @@ static void __exit rtl8192_pci_module_exit(void)
|
|||
|
||||
RT_TRACE(COMP_DOWN, "Exiting");
|
||||
rtl8192_proc_module_remove();
|
||||
ieee80211_exit();
|
||||
ieee80211_rtl_exit();
|
||||
}
|
||||
|
||||
//warning message WB
|
||||
|
@ -6313,7 +6313,7 @@ void rtl8192_try_wake_queue(struct net_device *dev, int pri)
|
|||
spin_unlock_irqrestore(&priv->tx_lock,flags);
|
||||
|
||||
if(enough_desc)
|
||||
ieee80211_wake_queue(priv->ieee80211);
|
||||
ieee80211_rtl_wake_queue(priv->ieee80211);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -1721,13 +1721,13 @@ extern int ieee80211_encrypt_fragment(
|
|||
struct sk_buff *frag,
|
||||
int hdr_len);
|
||||
|
||||
extern int rtl8192_ieee80211_xmit(struct sk_buff *skb,
|
||||
extern int rtl8192_ieee80211_rtl_xmit(struct sk_buff *skb,
|
||||
struct net_device *dev);
|
||||
extern void ieee80211_txb_free(struct ieee80211_txb *);
|
||||
|
||||
|
||||
/* ieee80211_rx.c */
|
||||
extern int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
|
||||
extern int ieee80211_rtl_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
|
||||
struct ieee80211_rx_stats *rx_stats);
|
||||
extern void ieee80211_rx_mgt(struct ieee80211_device *ieee,
|
||||
struct ieee80211_hdr_4addr *header,
|
||||
|
@ -1783,8 +1783,8 @@ extern void ieee80211_stop_protocol(struct ieee80211_device *ieee);
|
|||
extern void ieee80211_softmac_start_protocol(struct ieee80211_device *ieee);
|
||||
extern void ieee80211_softmac_stop_protocol(struct ieee80211_device *ieee);
|
||||
extern void ieee80211_reset_queue(struct ieee80211_device *ieee);
|
||||
extern void ieee80211_wake_queue(struct ieee80211_device *ieee);
|
||||
extern void ieee80211_stop_queue(struct ieee80211_device *ieee);
|
||||
extern void ieee80211_rtl_wake_queue(struct ieee80211_device *ieee);
|
||||
extern void ieee80211_rtl_stop_queue(struct ieee80211_device *ieee);
|
||||
extern struct sk_buff *ieee80211_get_beacon(struct ieee80211_device *ieee);
|
||||
extern void ieee80211_start_send_beacons(struct ieee80211_device *ieee);
|
||||
extern void ieee80211_stop_send_beacons(struct ieee80211_device *ieee);
|
||||
|
|
|
@ -208,7 +208,7 @@ static int ieee80211_frag_cache_invalidate(struct ieee80211_device *ieee,
|
|||
*
|
||||
* Responsible for handling management control frames
|
||||
*
|
||||
* Called by ieee80211_rx */
|
||||
* Called by ieee80211_rtl_rx */
|
||||
static inline int
|
||||
ieee80211_rx_frame_mgmt(struct ieee80211_device *ieee, struct sk_buff *skb,
|
||||
struct ieee80211_rx_stats *rx_stats, u16 type,
|
||||
|
@ -289,7 +289,7 @@ static int ieee80211_is_eapol_frame(struct ieee80211_device *ieee,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Called only as a tasklet (software IRQ), by ieee80211_rx */
|
||||
/* Called only as a tasklet (software IRQ), by ieee80211_rtl_rx */
|
||||
static inline int
|
||||
ieee80211_rx_frame_decrypt(struct ieee80211_device* ieee, struct sk_buff *skb,
|
||||
struct ieee80211_crypt_data *crypt)
|
||||
|
@ -858,7 +858,7 @@ u8 parse_subframe(struct sk_buff *skb,
|
|||
/* All received frames are sent to this function. @skb contains the frame in
|
||||
* IEEE 802.11 format, i.e., in the format it was sent over air.
|
||||
* This function is called only as a tasklet (software IRQ). */
|
||||
int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
|
||||
int ieee80211_rtl_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
|
||||
struct ieee80211_rx_stats *rx_stats)
|
||||
{
|
||||
struct net_device *dev = ieee->dev;
|
||||
|
|
|
@ -610,7 +610,7 @@ void ieee80211_stop_scan(struct ieee80211_device *ieee)
|
|||
}
|
||||
|
||||
/* called with ieee->lock held */
|
||||
void ieee80211_start_scan(struct ieee80211_device *ieee)
|
||||
void ieee80211_rtl_start_scan(struct ieee80211_device *ieee)
|
||||
{
|
||||
if(IS_DOT11D_ENABLE(ieee) )
|
||||
{
|
||||
|
@ -1281,7 +1281,7 @@ void ieee80211_associate_step1(struct ieee80211_device *ieee)
|
|||
}
|
||||
}
|
||||
|
||||
void ieee80211_auth_challenge(struct ieee80211_device *ieee, u8 *challenge, int chlen)
|
||||
void ieee80211_rtl_auth_challenge(struct ieee80211_device *ieee, u8 *challenge, int chlen)
|
||||
{
|
||||
u8 *c;
|
||||
struct sk_buff *skb;
|
||||
|
@ -2054,7 +2054,7 @@ ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb,
|
|||
|
||||
ieee80211_associate_step2(ieee);
|
||||
}else{
|
||||
ieee80211_auth_challenge(ieee, challenge, chlen);
|
||||
ieee80211_rtl_auth_challenge(ieee, challenge, chlen);
|
||||
}
|
||||
}else{
|
||||
ieee->softmac_stats.rx_auth_rs_err++;
|
||||
|
@ -2162,7 +2162,7 @@ void ieee80211_softmac_xmit(struct ieee80211_txb *txb, struct ieee80211_device *
|
|||
* to check it any more.
|
||||
* */
|
||||
//printk("error:no descriptor left@queue_index %d, %d, %d\n", queue_index, skb_queue_len(&ieee->skb_waitQ[queue_index]), ieee->check_nic_enough_desc(ieee->dev,queue_index));
|
||||
//ieee80211_stop_queue(ieee);
|
||||
//ieee80211_rtl_stop_queue(ieee);
|
||||
skb_queue_tail(&ieee->skb_waitQ[queue_index], txb->fragments[i]);
|
||||
}else{
|
||||
ieee->softmac_data_hard_start_xmit(
|
||||
|
@ -2222,7 +2222,7 @@ void ieee80211_reset_queue(struct ieee80211_device *ieee)
|
|||
|
||||
}
|
||||
|
||||
void ieee80211_wake_queue(struct ieee80211_device *ieee)
|
||||
void ieee80211_rtl_wake_queue(struct ieee80211_device *ieee)
|
||||
{
|
||||
|
||||
unsigned long flags;
|
||||
|
@ -2263,7 +2263,7 @@ exit :
|
|||
}
|
||||
|
||||
|
||||
void ieee80211_stop_queue(struct ieee80211_device *ieee)
|
||||
void ieee80211_rtl_stop_queue(struct ieee80211_device *ieee)
|
||||
{
|
||||
//unsigned long flags;
|
||||
//spin_lock_irqsave(&ieee->lock,flags);
|
||||
|
@ -2479,7 +2479,7 @@ void ieee80211_start_bss(struct ieee80211_device *ieee)
|
|||
|
||||
if (ieee->state == IEEE80211_NOLINK){
|
||||
ieee->actscanning = true;
|
||||
ieee80211_start_scan(ieee);
|
||||
ieee80211_rtl_start_scan(ieee);
|
||||
}
|
||||
spin_unlock_irqrestore(&ieee->lock, flags);
|
||||
}
|
||||
|
@ -2552,7 +2552,7 @@ void ieee80211_associate_retry_wq(struct work_struct *work)
|
|||
if(ieee->state == IEEE80211_NOLINK)
|
||||
{
|
||||
ieee->actscanning = true;
|
||||
ieee80211_start_scan(ieee);
|
||||
ieee80211_rtl_start_scan(ieee);
|
||||
}
|
||||
spin_unlock_irqrestore(&ieee->lock, flags);
|
||||
|
||||
|
|
|
@ -604,7 +604,7 @@ void ieee80211_query_seqnum(struct ieee80211_device*ieee, struct sk_buff* skb, u
|
|||
}
|
||||
}
|
||||
|
||||
int rtl8192_ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
int rtl8192_ieee80211_rtl_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
struct ieee80211_device *ieee = netdev_priv(dev);
|
||||
struct ieee80211_txb *txb = NULL;
|
||||
|
|
|
@ -126,6 +126,8 @@ static struct usb_device_id rtl8192_usb_id_tbl[] = {
|
|||
{USB_DEVICE(0x2001, 0x3301)},
|
||||
/* Zinwell */
|
||||
{USB_DEVICE(0x5a57, 0x0290)},
|
||||
/* Guillemot */
|
||||
{USB_DEVICE(0x06f8, 0xe031)},
|
||||
//92SU
|
||||
{USB_DEVICE(0x0bda, 0x8172)},
|
||||
{}
|
||||
|
@ -1501,7 +1503,7 @@ static void rtl8192_rx_isr(struct urb *urb)
|
|||
urb->context = skb;
|
||||
skb_queue_tail(&priv->rx_queue, skb);
|
||||
err = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
if(err && err != EPERM)
|
||||
if(err && err != -EPERM)
|
||||
printk("can not submit rxurb, err is %x,URB status is %x\n",err,urb->status);
|
||||
}
|
||||
|
||||
|
@ -7155,7 +7157,7 @@ void rtl8192SU_rx_nomal(struct sk_buff* skb)
|
|||
unicast_packet = true;
|
||||
}
|
||||
|
||||
if(!ieee80211_rx(priv->ieee80211,skb, &stats)) {
|
||||
if(!ieee80211_rtl_rx(priv->ieee80211,skb, &stats)) {
|
||||
dev_kfree_skb_any(skb);
|
||||
} else {
|
||||
// priv->stats.rxoktotal++; //YJ,test,090108
|
||||
|
@ -7426,7 +7428,7 @@ static const struct net_device_ops rtl8192_netdev_ops = {
|
|||
.ndo_set_mac_address = r8192_set_mac_adr,
|
||||
.ndo_validate_addr = eth_validate_addr,
|
||||
.ndo_change_mtu = eth_change_mtu,
|
||||
.ndo_start_xmit = rtl8192_ieee80211_xmit,
|
||||
.ndo_start_xmit = rtl8192_ieee80211_rtl_xmit,
|
||||
};
|
||||
|
||||
static int __devinit rtl8192_usb_probe(struct usb_interface *intf,
|
||||
|
@ -7619,7 +7621,7 @@ void rtl8192_try_wake_queue(struct net_device *dev, int pri)
|
|||
spin_unlock_irqrestore(&priv->tx_lock,flags);
|
||||
|
||||
if(enough_desc)
|
||||
ieee80211_wake_queue(priv->ieee80211);
|
||||
ieee80211_rtl_wake_queue(priv->ieee80211);
|
||||
}
|
||||
|
||||
void EnableHWSecurityConfig8192(struct net_device *dev)
|
||||
|
|
|
@ -845,7 +845,7 @@ int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len)
|
|||
{
|
||||
if (len != ie[1]+2)
|
||||
{
|
||||
printk("len:%d, ie:%d\n", len, ie[1]);
|
||||
printk("len:%zu, ie:%d\n", len, ie[1]);
|
||||
return -EINVAL;
|
||||
}
|
||||
buf = kmalloc(len, GFP_KERNEL);
|
||||
|
|
|
@ -340,7 +340,7 @@ int ieee80211_rx_ADDBAReq( struct ieee80211_device* ieee, struct sk_buff *skb)
|
|||
|
||||
if (skb->len < sizeof( struct ieee80211_hdr_3addr) + 9)
|
||||
{
|
||||
IEEE80211_DEBUG(IEEE80211_DL_ERR, " Invalid skb len in BAREQ(%d / %d)\n", skb->len, (sizeof( struct ieee80211_hdr_3addr) + 9));
|
||||
IEEE80211_DEBUG(IEEE80211_DL_ERR, " Invalid skb len in BAREQ(%d / %zu)\n", skb->len, (sizeof( struct ieee80211_hdr_3addr) + 9));
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -439,7 +439,7 @@ int ieee80211_rx_ADDBARsp( struct ieee80211_device* ieee, struct sk_buff *skb)
|
|||
|
||||
if (skb->len < sizeof( struct ieee80211_hdr_3addr) + 9)
|
||||
{
|
||||
IEEE80211_DEBUG(IEEE80211_DL_ERR, " Invalid skb len in BARSP(%d / %d)\n", skb->len, (sizeof( struct ieee80211_hdr_3addr) + 9));
|
||||
IEEE80211_DEBUG(IEEE80211_DL_ERR, " Invalid skb len in BARSP(%d / %zu)\n", skb->len, (sizeof( struct ieee80211_hdr_3addr) + 9));
|
||||
return -1;
|
||||
}
|
||||
rsp = ( struct ieee80211_hdr_3addr*)skb->data;
|
||||
|
@ -569,7 +569,7 @@ int ieee80211_rx_DELBA(struct ieee80211_device* ieee,struct sk_buff *skb)
|
|||
|
||||
if (skb->len < sizeof( struct ieee80211_hdr_3addr) + 6)
|
||||
{
|
||||
IEEE80211_DEBUG(IEEE80211_DL_ERR, " Invalid skb len in DELBA(%d / %d)\n", skb->len, (sizeof( struct ieee80211_hdr_3addr) + 6));
|
||||
IEEE80211_DEBUG(IEEE80211_DL_ERR, " Invalid skb len in DELBA(%d / %zu)\n", skb->len, (sizeof( struct ieee80211_hdr_3addr) + 6));
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
config FB_SM7XX
|
||||
tristate "Silicon Motion SM7XX Frame Buffer Support"
|
||||
depends on FB
|
||||
select FB_CFB_FILLRECT
|
||||
select FB_CFB_COPYAREA
|
||||
select FB_CFB_IMAGEBLIT
|
||||
help
|
||||
Frame Buffer driver for the Silicon Motion SM7XX serial graphic card.
|
||||
|
||||
config FB_SM7XX_ACCEL
|
||||
bool "Siliconmotion Acceleration functions (EXPERIMENTAL)"
|
||||
depends on FB_SM7XX && EXPERIMENTAL
|
||||
help
|
||||
This will compile the Trident frame buffer device with
|
||||
acceleration functions.
|
|
@ -0,0 +1,3 @@
|
|||
obj-$(CONFIG_FB_SM7XX) += sm7xx.o
|
||||
|
||||
sm7xx-y := smtcfb.o
|
|
@ -0,0 +1,10 @@
|
|||
TODO:
|
||||
- Dual head support
|
||||
- use kernel coding style
|
||||
- checkpatch.pl clean
|
||||
- refine the code and remove unused code
|
||||
- use kernel framebuffer mode setting instead of hard code
|
||||
- move it to drivers/video/sm7xx/ or make it be drivers/video/sm7xxfb.c
|
||||
|
||||
Please send any patches to Greg Kroah-Hartman <greg@kroah.com> and
|
||||
Teddy Wang <teddy.wang@siliconmotion.com.cn>.
|
|
@ -0,0 +1,979 @@
|
|||
/*
|
||||
* Silicon Motion SM7XX 2D drawing engine functions.
|
||||
*
|
||||
* Copyright (C) 2006 Silicon Motion Technology Corp.
|
||||
* Author: Boyod boyod.yang@siliconmotion.com.cn
|
||||
*
|
||||
* Copyright (C) 2009 Lemote, Inc.
|
||||
* Author: Wu Zhangjin, wuzj@lemote.com
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file COPYING in the main directory of this archive for
|
||||
* more details.
|
||||
*
|
||||
* Version 0.10.26192.21.01
|
||||
* - Add PowerPC support
|
||||
* - Add 2D support for Lynx -
|
||||
* Verified on 2.6.19.2
|
||||
* Boyod.yang <boyod.yang@siliconmotion.com.cn>
|
||||
*/
|
||||
|
||||
unsigned char smtc_de_busy;
|
||||
|
||||
void SMTC_write2Dreg(unsigned long nOffset, unsigned long nData)
|
||||
{
|
||||
writel(nData, smtc_2DBaseAddress + nOffset);
|
||||
}
|
||||
|
||||
unsigned long SMTC_read2Dreg(unsigned long nOffset)
|
||||
{
|
||||
return readl(smtc_2DBaseAddress + nOffset);
|
||||
}
|
||||
|
||||
void SMTC_write2Ddataport(unsigned long nOffset, unsigned long nData)
|
||||
{
|
||||
writel(nData, smtc_2Ddataport + nOffset);
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
*
|
||||
* deInit
|
||||
*
|
||||
* Purpose
|
||||
* Drawing engine initialization.
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
void deInit(unsigned int nModeWidth, unsigned int nModeHeight,
|
||||
unsigned int bpp)
|
||||
{
|
||||
/* Get current power configuration. */
|
||||
unsigned char clock;
|
||||
clock = smtc_seqr(0x21);
|
||||
|
||||
/* initialize global 'mutex lock' variable */
|
||||
smtc_de_busy = 0;
|
||||
|
||||
/* Enable 2D Drawing Engine */
|
||||
smtc_seqw(0x21, clock & 0xF8);
|
||||
|
||||
SMTC_write2Dreg(DE_CLIP_TL,
|
||||
FIELD_VALUE(0, DE_CLIP_TL, TOP, 0) |
|
||||
FIELD_SET(0, DE_CLIP_TL, STATUS, DISABLE) |
|
||||
FIELD_SET(0, DE_CLIP_TL, INHIBIT, OUTSIDE) |
|
||||
FIELD_VALUE(0, DE_CLIP_TL, LEFT, 0));
|
||||
|
||||
if (bpp >= 24) {
|
||||
SMTC_write2Dreg(DE_PITCH,
|
||||
FIELD_VALUE(0, DE_PITCH, DESTINATION,
|
||||
nModeWidth * 3) | FIELD_VALUE(0,
|
||||
DE_PITCH,
|
||||
SOURCE,
|
||||
nModeWidth
|
||||
* 3));
|
||||
} else {
|
||||
SMTC_write2Dreg(DE_PITCH,
|
||||
FIELD_VALUE(0, DE_PITCH, DESTINATION,
|
||||
nModeWidth) | FIELD_VALUE(0,
|
||||
DE_PITCH,
|
||||
SOURCE,
|
||||
nModeWidth));
|
||||
}
|
||||
|
||||
SMTC_write2Dreg(DE_WINDOW_WIDTH,
|
||||
FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION,
|
||||
nModeWidth) | FIELD_VALUE(0,
|
||||
DE_WINDOW_WIDTH,
|
||||
SOURCE,
|
||||
nModeWidth));
|
||||
|
||||
switch (bpp) {
|
||||
case 8:
|
||||
SMTC_write2Dreg(DE_STRETCH_FORMAT,
|
||||
FIELD_SET(0, DE_STRETCH_FORMAT, PATTERN_XY,
|
||||
NORMAL) | FIELD_VALUE(0,
|
||||
DE_STRETCH_FORMAT,
|
||||
PATTERN_Y,
|
||||
0) |
|
||||
FIELD_VALUE(0, DE_STRETCH_FORMAT, PATTERN_X,
|
||||
0) | FIELD_SET(0, DE_STRETCH_FORMAT,
|
||||
PIXEL_FORMAT,
|
||||
8) | FIELD_SET(0,
|
||||
DE_STRETCH_FORMAT,
|
||||
ADDRESSING,
|
||||
XY) |
|
||||
FIELD_VALUE(0, DE_STRETCH_FORMAT,
|
||||
SOURCE_HEIGHT, 3));
|
||||
break;
|
||||
case 24:
|
||||
SMTC_write2Dreg(DE_STRETCH_FORMAT,
|
||||
FIELD_SET(0, DE_STRETCH_FORMAT, PATTERN_XY,
|
||||
NORMAL) | FIELD_VALUE(0,
|
||||
DE_STRETCH_FORMAT,
|
||||
PATTERN_Y,
|
||||
0) |
|
||||
FIELD_VALUE(0, DE_STRETCH_FORMAT, PATTERN_X,
|
||||
0) | FIELD_SET(0, DE_STRETCH_FORMAT,
|
||||
PIXEL_FORMAT,
|
||||
24) | FIELD_SET(0,
|
||||
DE_STRETCH_FORMAT,
|
||||
ADDRESSING,
|
||||
XY) |
|
||||
FIELD_VALUE(0, DE_STRETCH_FORMAT,
|
||||
SOURCE_HEIGHT, 3));
|
||||
break;
|
||||
case 16:
|
||||
default:
|
||||
SMTC_write2Dreg(DE_STRETCH_FORMAT,
|
||||
FIELD_SET(0, DE_STRETCH_FORMAT, PATTERN_XY,
|
||||
NORMAL) | FIELD_VALUE(0,
|
||||
DE_STRETCH_FORMAT,
|
||||
PATTERN_Y,
|
||||
0) |
|
||||
FIELD_VALUE(0, DE_STRETCH_FORMAT, PATTERN_X,
|
||||
0) | FIELD_SET(0, DE_STRETCH_FORMAT,
|
||||
PIXEL_FORMAT,
|
||||
16) | FIELD_SET(0,
|
||||
DE_STRETCH_FORMAT,
|
||||
ADDRESSING,
|
||||
XY) |
|
||||
FIELD_VALUE(0, DE_STRETCH_FORMAT,
|
||||
SOURCE_HEIGHT, 3));
|
||||
break;
|
||||
}
|
||||
|
||||
SMTC_write2Dreg(DE_MASKS,
|
||||
FIELD_VALUE(0, DE_MASKS, BYTE_MASK, 0xFFFF) |
|
||||
FIELD_VALUE(0, DE_MASKS, BIT_MASK, 0xFFFF));
|
||||
SMTC_write2Dreg(DE_COLOR_COMPARE_MASK,
|
||||
FIELD_VALUE(0, DE_COLOR_COMPARE_MASK, MASKS, \
|
||||
0xFFFFFF));
|
||||
SMTC_write2Dreg(DE_COLOR_COMPARE,
|
||||
FIELD_VALUE(0, DE_COLOR_COMPARE, COLOR, 0xFFFFFF));
|
||||
}
|
||||
|
||||
void deVerticalLine(unsigned long dst_base,
|
||||
unsigned long dst_pitch,
|
||||
unsigned long nX,
|
||||
unsigned long nY,
|
||||
unsigned long dst_height, unsigned long nColor)
|
||||
{
|
||||
deWaitForNotBusy();
|
||||
|
||||
SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE,
|
||||
FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE, ADDRESS,
|
||||
dst_base));
|
||||
|
||||
SMTC_write2Dreg(DE_PITCH,
|
||||
FIELD_VALUE(0, DE_PITCH, DESTINATION, dst_pitch) |
|
||||
FIELD_VALUE(0, DE_PITCH, SOURCE, dst_pitch));
|
||||
|
||||
SMTC_write2Dreg(DE_WINDOW_WIDTH,
|
||||
FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION,
|
||||
dst_pitch) | FIELD_VALUE(0, DE_WINDOW_WIDTH,
|
||||
SOURCE,
|
||||
dst_pitch));
|
||||
|
||||
SMTC_write2Dreg(DE_FOREGROUND,
|
||||
FIELD_VALUE(0, DE_FOREGROUND, COLOR, nColor));
|
||||
|
||||
SMTC_write2Dreg(DE_DESTINATION,
|
||||
FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) |
|
||||
FIELD_VALUE(0, DE_DESTINATION, X, nX) |
|
||||
FIELD_VALUE(0, DE_DESTINATION, Y, nY));
|
||||
|
||||
SMTC_write2Dreg(DE_DIMENSION,
|
||||
FIELD_VALUE(0, DE_DIMENSION, X, 1) |
|
||||
FIELD_VALUE(0, DE_DIMENSION, Y_ET, dst_height));
|
||||
|
||||
SMTC_write2Dreg(DE_CONTROL,
|
||||
FIELD_SET(0, DE_CONTROL, STATUS, START) |
|
||||
FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT) |
|
||||
FIELD_SET(0, DE_CONTROL, MAJOR, Y) |
|
||||
FIELD_SET(0, DE_CONTROL, STEP_X, NEGATIVE) |
|
||||
FIELD_SET(0, DE_CONTROL, STEP_Y, POSITIVE) |
|
||||
FIELD_SET(0, DE_CONTROL, LAST_PIXEL, OFF) |
|
||||
FIELD_SET(0, DE_CONTROL, COMMAND, SHORT_STROKE) |
|
||||
FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) |
|
||||
FIELD_VALUE(0, DE_CONTROL, ROP, 0x0C));
|
||||
|
||||
smtc_de_busy = 1;
|
||||
}
|
||||
|
||||
void deHorizontalLine(unsigned long dst_base,
|
||||
unsigned long dst_pitch,
|
||||
unsigned long nX,
|
||||
unsigned long nY,
|
||||
unsigned long dst_width, unsigned long nColor)
|
||||
{
|
||||
deWaitForNotBusy();
|
||||
|
||||
SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE,
|
||||
FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE, ADDRESS,
|
||||
dst_base));
|
||||
|
||||
SMTC_write2Dreg(DE_PITCH,
|
||||
FIELD_VALUE(0, DE_PITCH, DESTINATION, dst_pitch) |
|
||||
FIELD_VALUE(0, DE_PITCH, SOURCE, dst_pitch));
|
||||
|
||||
SMTC_write2Dreg(DE_WINDOW_WIDTH,
|
||||
FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION,
|
||||
dst_pitch) | FIELD_VALUE(0, DE_WINDOW_WIDTH,
|
||||
SOURCE,
|
||||
dst_pitch));
|
||||
SMTC_write2Dreg(DE_FOREGROUND,
|
||||
FIELD_VALUE(0, DE_FOREGROUND, COLOR, nColor));
|
||||
SMTC_write2Dreg(DE_DESTINATION,
|
||||
FIELD_SET(0, DE_DESTINATION, WRAP,
|
||||
DISABLE) | FIELD_VALUE(0, DE_DESTINATION, X,
|
||||
nX) | FIELD_VALUE(0,
|
||||
DE_DESTINATION,
|
||||
Y,
|
||||
nY));
|
||||
SMTC_write2Dreg(DE_DIMENSION,
|
||||
FIELD_VALUE(0, DE_DIMENSION, X,
|
||||
dst_width) | FIELD_VALUE(0, DE_DIMENSION,
|
||||
Y_ET, 1));
|
||||
SMTC_write2Dreg(DE_CONTROL,
|
||||
FIELD_SET(0, DE_CONTROL, STATUS, START) | FIELD_SET(0,
|
||||
DE_CONTROL,
|
||||
DIRECTION,
|
||||
RIGHT_TO_LEFT)
|
||||
| FIELD_SET(0, DE_CONTROL, MAJOR, X) | FIELD_SET(0,
|
||||
DE_CONTROL,
|
||||
STEP_X,
|
||||
POSITIVE)
|
||||
| FIELD_SET(0, DE_CONTROL, STEP_Y,
|
||||
NEGATIVE) | FIELD_SET(0, DE_CONTROL,
|
||||
LAST_PIXEL,
|
||||
OFF) | FIELD_SET(0,
|
||||
DE_CONTROL,
|
||||
COMMAND,
|
||||
SHORT_STROKE)
|
||||
| FIELD_SET(0, DE_CONTROL, ROP_SELECT,
|
||||
ROP2) | FIELD_VALUE(0, DE_CONTROL, ROP,
|
||||
0x0C));
|
||||
|
||||
smtc_de_busy = 1;
|
||||
}
|
||||
|
||||
void deLine(unsigned long dst_base,
|
||||
unsigned long dst_pitch,
|
||||
unsigned long nX1,
|
||||
unsigned long nY1,
|
||||
unsigned long nX2, unsigned long nY2, unsigned long nColor)
|
||||
{
|
||||
unsigned long nCommand =
|
||||
FIELD_SET(0, DE_CONTROL, STATUS, START) |
|
||||
FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT) |
|
||||
FIELD_SET(0, DE_CONTROL, MAJOR, X) |
|
||||
FIELD_SET(0, DE_CONTROL, STEP_X, POSITIVE) |
|
||||
FIELD_SET(0, DE_CONTROL, STEP_Y, POSITIVE) |
|
||||
FIELD_SET(0, DE_CONTROL, LAST_PIXEL, OFF) |
|
||||
FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) |
|
||||
FIELD_VALUE(0, DE_CONTROL, ROP, 0x0C);
|
||||
unsigned long DeltaX;
|
||||
unsigned long DeltaY;
|
||||
|
||||
/* Calculate delta X */
|
||||
if (nX1 <= nX2)
|
||||
DeltaX = nX2 - nX1;
|
||||
else {
|
||||
DeltaX = nX1 - nX2;
|
||||
nCommand = FIELD_SET(nCommand, DE_CONTROL, STEP_X, NEGATIVE);
|
||||
}
|
||||
|
||||
/* Calculate delta Y */
|
||||
if (nY1 <= nY2)
|
||||
DeltaY = nY2 - nY1;
|
||||
else {
|
||||
DeltaY = nY1 - nY2;
|
||||
nCommand = FIELD_SET(nCommand, DE_CONTROL, STEP_Y, NEGATIVE);
|
||||
}
|
||||
|
||||
/* Determine the major axis */
|
||||
if (DeltaX < DeltaY)
|
||||
nCommand = FIELD_SET(nCommand, DE_CONTROL, MAJOR, Y);
|
||||
|
||||
/* Vertical line? */
|
||||
if (nX1 == nX2)
|
||||
deVerticalLine(dst_base, dst_pitch, nX1, nY1, DeltaY, nColor);
|
||||
|
||||
/* Horizontal line? */
|
||||
else if (nY1 == nY2)
|
||||
deHorizontalLine(dst_base, dst_pitch, nX1, nY1, \
|
||||
DeltaX, nColor);
|
||||
|
||||
/* Diagonal line? */
|
||||
else if (DeltaX == DeltaY) {
|
||||
deWaitForNotBusy();
|
||||
|
||||
SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE,
|
||||
FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE,
|
||||
ADDRESS, dst_base));
|
||||
|
||||
SMTC_write2Dreg(DE_PITCH,
|
||||
FIELD_VALUE(0, DE_PITCH, DESTINATION,
|
||||
dst_pitch) | FIELD_VALUE(0,
|
||||
DE_PITCH,
|
||||
SOURCE,
|
||||
dst_pitch));
|
||||
|
||||
SMTC_write2Dreg(DE_WINDOW_WIDTH,
|
||||
FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION,
|
||||
dst_pitch) | FIELD_VALUE(0,
|
||||
DE_WINDOW_WIDTH,
|
||||
SOURCE,
|
||||
dst_pitch));
|
||||
|
||||
SMTC_write2Dreg(DE_FOREGROUND,
|
||||
FIELD_VALUE(0, DE_FOREGROUND, COLOR, nColor));
|
||||
|
||||
SMTC_write2Dreg(DE_DESTINATION,
|
||||
FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) |
|
||||
FIELD_VALUE(0, DE_DESTINATION, X, 1) |
|
||||
FIELD_VALUE(0, DE_DESTINATION, Y, nY1));
|
||||
|
||||
SMTC_write2Dreg(DE_DIMENSION,
|
||||
FIELD_VALUE(0, DE_DIMENSION, X, 1) |
|
||||
FIELD_VALUE(0, DE_DIMENSION, Y_ET, DeltaX));
|
||||
|
||||
SMTC_write2Dreg(DE_CONTROL,
|
||||
FIELD_SET(nCommand, DE_CONTROL, COMMAND,
|
||||
SHORT_STROKE));
|
||||
}
|
||||
|
||||
/* Generic line */
|
||||
else {
|
||||
unsigned int k1, k2, et, w;
|
||||
if (DeltaX < DeltaY) {
|
||||
k1 = 2 * DeltaX;
|
||||
et = k1 - DeltaY;
|
||||
k2 = et - DeltaY;
|
||||
w = DeltaY + 1;
|
||||
} else {
|
||||
k1 = 2 * DeltaY;
|
||||
et = k1 - DeltaX;
|
||||
k2 = et - DeltaX;
|
||||
w = DeltaX + 1;
|
||||
}
|
||||
|
||||
deWaitForNotBusy();
|
||||
|
||||
SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE,
|
||||
FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE,
|
||||
ADDRESS, dst_base));
|
||||
|
||||
SMTC_write2Dreg(DE_PITCH,
|
||||
FIELD_VALUE(0, DE_PITCH, DESTINATION,
|
||||
dst_pitch) | FIELD_VALUE(0,
|
||||
DE_PITCH,
|
||||
SOURCE,
|
||||
dst_pitch));
|
||||
|
||||
SMTC_write2Dreg(DE_WINDOW_WIDTH,
|
||||
FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION,
|
||||
dst_pitch) | FIELD_VALUE(0,
|
||||
DE_WINDOW_WIDTH,
|
||||
SOURCE,
|
||||
dst_pitch));
|
||||
|
||||
SMTC_write2Dreg(DE_FOREGROUND,
|
||||
FIELD_VALUE(0, DE_FOREGROUND, COLOR, nColor));
|
||||
|
||||
SMTC_write2Dreg(DE_SOURCE,
|
||||
FIELD_SET(0, DE_SOURCE, WRAP, DISABLE) |
|
||||
FIELD_VALUE(0, DE_SOURCE, X_K1, k1) |
|
||||
FIELD_VALUE(0, DE_SOURCE, Y_K2, k2));
|
||||
|
||||
SMTC_write2Dreg(DE_DESTINATION,
|
||||
FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) |
|
||||
FIELD_VALUE(0, DE_DESTINATION, X, nX1) |
|
||||
FIELD_VALUE(0, DE_DESTINATION, Y, nY1));
|
||||
|
||||
SMTC_write2Dreg(DE_DIMENSION,
|
||||
FIELD_VALUE(0, DE_DIMENSION, X, w) |
|
||||
FIELD_VALUE(0, DE_DIMENSION, Y_ET, et));
|
||||
|
||||
SMTC_write2Dreg(DE_CONTROL,
|
||||
FIELD_SET(nCommand, DE_CONTROL, COMMAND,
|
||||
LINE_DRAW));
|
||||
}
|
||||
|
||||
smtc_de_busy = 1;
|
||||
}
|
||||
|
||||
void deFillRect(unsigned long dst_base,
|
||||
unsigned long dst_pitch,
|
||||
unsigned long dst_X,
|
||||
unsigned long dst_Y,
|
||||
unsigned long dst_width,
|
||||
unsigned long dst_height, unsigned long nColor)
|
||||
{
|
||||
deWaitForNotBusy();
|
||||
|
||||
SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE,
|
||||
FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE, ADDRESS,
|
||||
dst_base));
|
||||
|
||||
if (dst_pitch) {
|
||||
SMTC_write2Dreg(DE_PITCH,
|
||||
FIELD_VALUE(0, DE_PITCH, DESTINATION,
|
||||
dst_pitch) | FIELD_VALUE(0,
|
||||
DE_PITCH,
|
||||
SOURCE,
|
||||
dst_pitch));
|
||||
|
||||
SMTC_write2Dreg(DE_WINDOW_WIDTH,
|
||||
FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION,
|
||||
dst_pitch) | FIELD_VALUE(0,
|
||||
DE_WINDOW_WIDTH,
|
||||
SOURCE,
|
||||
dst_pitch));
|
||||
}
|
||||
|
||||
SMTC_write2Dreg(DE_FOREGROUND,
|
||||
FIELD_VALUE(0, DE_FOREGROUND, COLOR, nColor));
|
||||
|
||||
SMTC_write2Dreg(DE_DESTINATION,
|
||||
FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) |
|
||||
FIELD_VALUE(0, DE_DESTINATION, X, dst_X) |
|
||||
FIELD_VALUE(0, DE_DESTINATION, Y, dst_Y));
|
||||
|
||||
SMTC_write2Dreg(DE_DIMENSION,
|
||||
FIELD_VALUE(0, DE_DIMENSION, X, dst_width) |
|
||||
FIELD_VALUE(0, DE_DIMENSION, Y_ET, dst_height));
|
||||
|
||||
SMTC_write2Dreg(DE_CONTROL,
|
||||
FIELD_SET(0, DE_CONTROL, STATUS, START) |
|
||||
FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT) |
|
||||
FIELD_SET(0, DE_CONTROL, LAST_PIXEL, OFF) |
|
||||
FIELD_SET(0, DE_CONTROL, COMMAND, RECTANGLE_FILL) |
|
||||
FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) |
|
||||
FIELD_VALUE(0, DE_CONTROL, ROP, 0x0C));
|
||||
|
||||
smtc_de_busy = 1;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
*
|
||||
* deRotatePattern
|
||||
*
|
||||
* Purpose
|
||||
* Rotate the given pattern if necessary
|
||||
*
|
||||
* Parameters
|
||||
* [in]
|
||||
* pPattern - Pointer to DE_SURFACE structure containing
|
||||
* pattern attributes
|
||||
* patternX - X position (0-7) of pattern origin
|
||||
* patternY - Y position (0-7) of pattern origin
|
||||
*
|
||||
* [out]
|
||||
* pattern_dstaddr - Pointer to pre-allocated buffer containing
|
||||
* rotated pattern
|
||||
*
|
||||
**********************************************************************/
|
||||
void deRotatePattern(unsigned char *pattern_dstaddr,
|
||||
unsigned long pattern_src_addr,
|
||||
unsigned long pattern_BPP,
|
||||
unsigned long pattern_stride, int patternX, int patternY)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned long pattern[PATTERN_WIDTH * PATTERN_HEIGHT];
|
||||
unsigned int x, y;
|
||||
unsigned char *pjPatByte;
|
||||
|
||||
if (pattern_dstaddr != NULL) {
|
||||
deWaitForNotBusy();
|
||||
|
||||
if (patternX || patternY) {
|
||||
/* Rotate pattern */
|
||||
pjPatByte = (unsigned char *)pattern;
|
||||
|
||||
switch (pattern_BPP) {
|
||||
case 8:
|
||||
{
|
||||
for (y = 0; y < 8; y++) {
|
||||
unsigned char *pjBuffer =
|
||||
pattern_dstaddr +
|
||||
((patternY + y) & 7) * 8;
|
||||
for (x = 0; x < 8; x++) {
|
||||
pjBuffer[(patternX +
|
||||
x) & 7] =
|
||||
pjPatByte[x];
|
||||
}
|
||||
pjPatByte += pattern_stride;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 16:
|
||||
{
|
||||
for (y = 0; y < 8; y++) {
|
||||
unsigned short *pjBuffer =
|
||||
(unsigned short *)
|
||||
pattern_dstaddr +
|
||||
((patternY + y) & 7) * 8;
|
||||
for (x = 0; x < 8; x++) {
|
||||
pjBuffer[(patternX +
|
||||
x) & 7] =
|
||||
((unsigned short *)
|
||||
pjPatByte)[x];
|
||||
}
|
||||
pjPatByte += pattern_stride;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 32:
|
||||
{
|
||||
for (y = 0; y < 8; y++) {
|
||||
unsigned long *pjBuffer =
|
||||
(unsigned long *)
|
||||
pattern_dstaddr +
|
||||
((patternY + y) & 7) * 8;
|
||||
for (x = 0; x < 8; x++) {
|
||||
pjBuffer[(patternX +
|
||||
x) & 7] =
|
||||
((unsigned long *)
|
||||
pjPatByte)[x];
|
||||
}
|
||||
pjPatByte += pattern_stride;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/*Don't rotate,just copy pattern into pattern_dstaddr*/
|
||||
for (i = 0; i < (pattern_BPP * 2); i++) {
|
||||
((unsigned long *)pattern_dstaddr)[i] =
|
||||
pattern[i];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
*
|
||||
* deCopy
|
||||
*
|
||||
* Purpose
|
||||
* Copy a rectangular area of the source surface to a destination surface
|
||||
*
|
||||
* Remarks
|
||||
* Source bitmap must have the same color depth (BPP) as the destination
|
||||
* bitmap.
|
||||
*
|
||||
**********************************************************************/
|
||||
void deCopy(unsigned long dst_base,
|
||||
unsigned long dst_pitch,
|
||||
unsigned long dst_BPP,
|
||||
unsigned long dst_X,
|
||||
unsigned long dst_Y,
|
||||
unsigned long dst_width,
|
||||
unsigned long dst_height,
|
||||
unsigned long src_base,
|
||||
unsigned long src_pitch,
|
||||
unsigned long src_X,
|
||||
unsigned long src_Y, pTransparent pTransp, unsigned char nROP2)
|
||||
{
|
||||
unsigned long nDirection = 0;
|
||||
unsigned long nTransparent = 0;
|
||||
/* Direction of ROP2 operation:
|
||||
* 1 = Left to Right,
|
||||
* (-1) = Right to Left
|
||||
*/
|
||||
unsigned long opSign = 1;
|
||||
/* xWidth is in pixels */
|
||||
unsigned long xWidth = 192 / (dst_BPP / 8);
|
||||
unsigned long de_ctrl = 0;
|
||||
|
||||
deWaitForNotBusy();
|
||||
|
||||
SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE,
|
||||
FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE, ADDRESS,
|
||||
dst_base));
|
||||
|
||||
SMTC_write2Dreg(DE_WINDOW_SOURCE_BASE,
|
||||
FIELD_VALUE(0, DE_WINDOW_SOURCE_BASE, ADDRESS,
|
||||
src_base));
|
||||
|
||||
if (dst_pitch && src_pitch) {
|
||||
SMTC_write2Dreg(DE_PITCH,
|
||||
FIELD_VALUE(0, DE_PITCH, DESTINATION,
|
||||
dst_pitch) | FIELD_VALUE(0,
|
||||
DE_PITCH,
|
||||
SOURCE,
|
||||
src_pitch));
|
||||
|
||||
SMTC_write2Dreg(DE_WINDOW_WIDTH,
|
||||
FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION,
|
||||
dst_pitch) | FIELD_VALUE(0,
|
||||
DE_WINDOW_WIDTH,
|
||||
SOURCE,
|
||||
src_pitch));
|
||||
}
|
||||
|
||||
/* Set transparent bits if necessary */
|
||||
if (pTransp != NULL) {
|
||||
nTransparent =
|
||||
pTransp->match | pTransp->select | pTransp->control;
|
||||
|
||||
/* Set color compare register */
|
||||
SMTC_write2Dreg(DE_COLOR_COMPARE,
|
||||
FIELD_VALUE(0, DE_COLOR_COMPARE, COLOR,
|
||||
pTransp->color));
|
||||
}
|
||||
|
||||
/* Determine direction of operation */
|
||||
if (src_Y < dst_Y) {
|
||||
/* +----------+
|
||||
|S |
|
||||
| +----------+
|
||||
| | | |
|
||||
| | | |
|
||||
+---|------+ |
|
||||
| D |
|
||||
+----------+ */
|
||||
|
||||
nDirection = BOTTOM_TO_TOP;
|
||||
} else if (src_Y > dst_Y) {
|
||||
/* +----------+
|
||||
|D |
|
||||
| +----------+
|
||||
| | | |
|
||||
| | | |
|
||||
+---|------+ |
|
||||
| S |
|
||||
+----------+ */
|
||||
|
||||
nDirection = TOP_TO_BOTTOM;
|
||||
} else {
|
||||
/* src_Y == dst_Y */
|
||||
|
||||
if (src_X <= dst_X) {
|
||||
/* +------+---+------+
|
||||
|S | | D|
|
||||
| | | |
|
||||
| | | |
|
||||
| | | |
|
||||
+------+---+------+ */
|
||||
|
||||
nDirection = RIGHT_TO_LEFT;
|
||||
} else {
|
||||
/* src_X > dst_X */
|
||||
|
||||
/* +------+---+------+
|
||||
|D | | S|
|
||||
| | | |
|
||||
| | | |
|
||||
| | | |
|
||||
+------+---+------+ */
|
||||
|
||||
nDirection = LEFT_TO_RIGHT;
|
||||
}
|
||||
}
|
||||
|
||||
if ((nDirection == BOTTOM_TO_TOP) || (nDirection == RIGHT_TO_LEFT)) {
|
||||
src_X += dst_width - 1;
|
||||
src_Y += dst_height - 1;
|
||||
dst_X += dst_width - 1;
|
||||
dst_Y += dst_height - 1;
|
||||
opSign = (-1);
|
||||
}
|
||||
|
||||
if (dst_BPP >= 24) {
|
||||
src_X *= 3;
|
||||
src_Y *= 3;
|
||||
dst_X *= 3;
|
||||
dst_Y *= 3;
|
||||
dst_width *= 3;
|
||||
if ((nDirection == BOTTOM_TO_TOP)
|
||||
|| (nDirection == RIGHT_TO_LEFT)) {
|
||||
src_X += 2;
|
||||
dst_X += 2;
|
||||
}
|
||||
}
|
||||
|
||||
/* Workaround for 192 byte hw bug */
|
||||
if ((nROP2 != 0x0C) && ((dst_width * (dst_BPP / 8)) >= 192)) {
|
||||
/*
|
||||
* Perform the ROP2 operation in chunks of (xWidth *
|
||||
* dst_height)
|
||||
*/
|
||||
while (1) {
|
||||
deWaitForNotBusy();
|
||||
|
||||
SMTC_write2Dreg(DE_SOURCE,
|
||||
FIELD_SET(0, DE_SOURCE, WRAP, DISABLE) |
|
||||
FIELD_VALUE(0, DE_SOURCE, X_K1, src_X) |
|
||||
FIELD_VALUE(0, DE_SOURCE, Y_K2, src_Y));
|
||||
|
||||
SMTC_write2Dreg(DE_DESTINATION,
|
||||
FIELD_SET(0, DE_DESTINATION, WRAP,
|
||||
DISABLE) | FIELD_VALUE(0,
|
||||
DE_DESTINATION,
|
||||
X,
|
||||
dst_X)
|
||||
| FIELD_VALUE(0, DE_DESTINATION, Y,
|
||||
dst_Y));
|
||||
|
||||
SMTC_write2Dreg(DE_DIMENSION,
|
||||
FIELD_VALUE(0, DE_DIMENSION, X,
|
||||
xWidth) | FIELD_VALUE(0,
|
||||
DE_DIMENSION,
|
||||
Y_ET,
|
||||
dst_height));
|
||||
|
||||
de_ctrl =
|
||||
FIELD_VALUE(0, DE_CONTROL, ROP,
|
||||
nROP2) | nTransparent | FIELD_SET(0,
|
||||
DE_CONTROL,
|
||||
ROP_SELECT,
|
||||
ROP2)
|
||||
| FIELD_SET(0, DE_CONTROL, COMMAND,
|
||||
BITBLT) | ((nDirection ==
|
||||
1) ? FIELD_SET(0,
|
||||
DE_CONTROL,
|
||||
DIRECTION,
|
||||
RIGHT_TO_LEFT)
|
||||
: FIELD_SET(0, DE_CONTROL,
|
||||
DIRECTION,
|
||||
LEFT_TO_RIGHT)) |
|
||||
FIELD_SET(0, DE_CONTROL, STATUS, START);
|
||||
|
||||
SMTC_write2Dreg(DE_CONTROL, de_ctrl);
|
||||
|
||||
src_X += (opSign * xWidth);
|
||||
dst_X += (opSign * xWidth);
|
||||
dst_width -= xWidth;
|
||||
|
||||
if (dst_width <= 0) {
|
||||
/* ROP2 operation is complete */
|
||||
break;
|
||||
}
|
||||
|
||||
if (xWidth > dst_width)
|
||||
xWidth = dst_width;
|
||||
}
|
||||
} else {
|
||||
deWaitForNotBusy();
|
||||
SMTC_write2Dreg(DE_SOURCE,
|
||||
FIELD_SET(0, DE_SOURCE, WRAP, DISABLE) |
|
||||
FIELD_VALUE(0, DE_SOURCE, X_K1, src_X) |
|
||||
FIELD_VALUE(0, DE_SOURCE, Y_K2, src_Y));
|
||||
|
||||
SMTC_write2Dreg(DE_DESTINATION,
|
||||
FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) |
|
||||
FIELD_VALUE(0, DE_DESTINATION, X, dst_X) |
|
||||
FIELD_VALUE(0, DE_DESTINATION, Y, dst_Y));
|
||||
|
||||
SMTC_write2Dreg(DE_DIMENSION,
|
||||
FIELD_VALUE(0, DE_DIMENSION, X, dst_width) |
|
||||
FIELD_VALUE(0, DE_DIMENSION, Y_ET, dst_height));
|
||||
|
||||
de_ctrl = FIELD_VALUE(0, DE_CONTROL, ROP, nROP2) |
|
||||
nTransparent |
|
||||
FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) |
|
||||
FIELD_SET(0, DE_CONTROL, COMMAND, BITBLT) |
|
||||
((nDirection == 1) ? FIELD_SET(0, DE_CONTROL, DIRECTION,
|
||||
RIGHT_TO_LEFT)
|
||||
: FIELD_SET(0, DE_CONTROL, DIRECTION,
|
||||
LEFT_TO_RIGHT)) | FIELD_SET(0, DE_CONTROL,
|
||||
STATUS, START);
|
||||
SMTC_write2Dreg(DE_CONTROL, de_ctrl);
|
||||
}
|
||||
|
||||
smtc_de_busy = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function sets the pixel format that will apply to the 2D Engine.
|
||||
*/
|
||||
void deSetPixelFormat(unsigned long bpp)
|
||||
{
|
||||
unsigned long de_format;
|
||||
|
||||
de_format = SMTC_read2Dreg(DE_STRETCH_FORMAT);
|
||||
|
||||
switch (bpp) {
|
||||
case 8:
|
||||
de_format =
|
||||
FIELD_SET(de_format, DE_STRETCH_FORMAT, PIXEL_FORMAT, 8);
|
||||
break;
|
||||
default:
|
||||
case 16:
|
||||
de_format =
|
||||
FIELD_SET(de_format, DE_STRETCH_FORMAT, PIXEL_FORMAT, 16);
|
||||
break;
|
||||
case 32:
|
||||
de_format =
|
||||
FIELD_SET(de_format, DE_STRETCH_FORMAT, PIXEL_FORMAT, 32);
|
||||
break;
|
||||
}
|
||||
|
||||
SMTC_write2Dreg(DE_STRETCH_FORMAT, de_format);
|
||||
}
|
||||
|
||||
/*
|
||||
* System memory to Video memory monochrome expansion.
|
||||
*
|
||||
* Source is monochrome image in system memory. This function expands the
|
||||
* monochrome data to color image in video memory.
|
||||
*/
|
||||
|
||||
long deSystemMem2VideoMemMonoBlt(const char *pSrcbuf,
|
||||
long srcDelta,
|
||||
unsigned long startBit,
|
||||
unsigned long dBase,
|
||||
unsigned long dPitch,
|
||||
unsigned long bpp,
|
||||
unsigned long dx, unsigned long dy,
|
||||
unsigned long width, unsigned long height,
|
||||
unsigned long fColor,
|
||||
unsigned long bColor,
|
||||
unsigned long rop2) {
|
||||
unsigned long bytePerPixel;
|
||||
unsigned long ulBytesPerScan;
|
||||
unsigned long ul4BytesPerScan;
|
||||
unsigned long ulBytesRemain;
|
||||
unsigned long de_ctrl = 0;
|
||||
unsigned char ajRemain[4];
|
||||
long i, j;
|
||||
|
||||
bytePerPixel = bpp / 8;
|
||||
|
||||
/* Just make sure the start bit is within legal range */
|
||||
startBit &= 7;
|
||||
|
||||
ulBytesPerScan = (width + startBit + 7) / 8;
|
||||
ul4BytesPerScan = ulBytesPerScan & ~3;
|
||||
ulBytesRemain = ulBytesPerScan & 3;
|
||||
|
||||
if (smtc_de_busy)
|
||||
deWaitForNotBusy();
|
||||
|
||||
/*
|
||||
* 2D Source Base. Use 0 for HOST Blt.
|
||||
*/
|
||||
|
||||
SMTC_write2Dreg(DE_WINDOW_SOURCE_BASE, 0);
|
||||
|
||||
/*
|
||||
* 2D Destination Base.
|
||||
*
|
||||
* It is an address offset (128 bit aligned) from the beginning of
|
||||
* frame buffer.
|
||||
*/
|
||||
|
||||
SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE, dBase);
|
||||
|
||||
if (dPitch) {
|
||||
|
||||
/*
|
||||
* Program pitch (distance between the 1st points of two
|
||||
* adjacent lines).
|
||||
*
|
||||
* Note that input pitch is BYTE value, but the 2D Pitch
|
||||
* register uses pixel values. Need Byte to pixel convertion.
|
||||
*/
|
||||
|
||||
SMTC_write2Dreg(DE_PITCH,
|
||||
FIELD_VALUE(0, DE_PITCH, DESTINATION,
|
||||
dPitch /
|
||||
bytePerPixel) | FIELD_VALUE(0,
|
||||
DE_PITCH,
|
||||
SOURCE,
|
||||
dPitch /
|
||||
bytePerPixel));
|
||||
|
||||
/* Screen Window width in Pixels.
|
||||
*
|
||||
* 2D engine uses this value to calculate the linear address in
|
||||
* frame buffer for a given point.
|
||||
*/
|
||||
|
||||
SMTC_write2Dreg(DE_WINDOW_WIDTH,
|
||||
FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION,
|
||||
(dPitch /
|
||||
bytePerPixel)) | FIELD_VALUE(0,
|
||||
DE_WINDOW_WIDTH,
|
||||
SOURCE,
|
||||
(dPitch
|
||||
/
|
||||
bytePerPixel)));
|
||||
}
|
||||
/* Note: For 2D Source in Host Write, only X_K1 field is needed, and
|
||||
* Y_K2 field is not used. For mono bitmap, use startBit for X_K1.
|
||||
*/
|
||||
|
||||
SMTC_write2Dreg(DE_SOURCE,
|
||||
FIELD_SET(0, DE_SOURCE, WRAP, DISABLE) |
|
||||
FIELD_VALUE(0, DE_SOURCE, X_K1, startBit) |
|
||||
FIELD_VALUE(0, DE_SOURCE, Y_K2, 0));
|
||||
|
||||
SMTC_write2Dreg(DE_DESTINATION,
|
||||
FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) |
|
||||
FIELD_VALUE(0, DE_DESTINATION, X, dx) |
|
||||
FIELD_VALUE(0, DE_DESTINATION, Y, dy));
|
||||
|
||||
SMTC_write2Dreg(DE_DIMENSION,
|
||||
FIELD_VALUE(0, DE_DIMENSION, X, width) |
|
||||
FIELD_VALUE(0, DE_DIMENSION, Y_ET, height));
|
||||
|
||||
SMTC_write2Dreg(DE_FOREGROUND, fColor);
|
||||
SMTC_write2Dreg(DE_BACKGROUND, bColor);
|
||||
|
||||
if (bpp)
|
||||
deSetPixelFormat(bpp);
|
||||
/* Set the pixel format of the destination */
|
||||
|
||||
de_ctrl = FIELD_VALUE(0, DE_CONTROL, ROP, rop2) |
|
||||
FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) |
|
||||
FIELD_SET(0, DE_CONTROL, COMMAND, HOST_WRITE) |
|
||||
FIELD_SET(0, DE_CONTROL, HOST, MONO) |
|
||||
FIELD_SET(0, DE_CONTROL, STATUS, START);
|
||||
|
||||
SMTC_write2Dreg(DE_CONTROL, de_ctrl | deGetTransparency());
|
||||
|
||||
/* Write MONO data (line by line) to 2D Engine data port */
|
||||
for (i = 0; i < height; i++) {
|
||||
/* For each line, send the data in chunks of 4 bytes */
|
||||
for (j = 0; j < (ul4BytesPerScan / 4); j++)
|
||||
SMTC_write2Ddataport(0,
|
||||
*(unsigned long *)(pSrcbuf +
|
||||
(j * 4)));
|
||||
|
||||
if (ulBytesRemain) {
|
||||
memcpy(ajRemain, pSrcbuf + ul4BytesPerScan,
|
||||
ulBytesRemain);
|
||||
SMTC_write2Ddataport(0, *(unsigned long *)ajRemain);
|
||||
}
|
||||
|
||||
pSrcbuf += srcDelta;
|
||||
}
|
||||
smtc_de_busy = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function gets the transparency status from DE_CONTROL register.
|
||||
* It returns a double word with the transparent fields properly set,
|
||||
* while other fields are 0.
|
||||
*/
|
||||
unsigned long deGetTransparency(void)
|
||||
{
|
||||
unsigned long de_ctrl;
|
||||
|
||||
de_ctrl = SMTC_read2Dreg(DE_CONTROL);
|
||||
|
||||
de_ctrl &=
|
||||
FIELD_MASK(DE_CONTROL_TRANSPARENCY_MATCH) |
|
||||
FIELD_MASK(DE_CONTROL_TRANSPARENCY_SELECT) |
|
||||
FIELD_MASK(DE_CONTROL_TRANSPARENCY);
|
||||
|
||||
return de_ctrl;
|
||||
}
|
|
@ -0,0 +1,530 @@
|
|||
/*
|
||||
* Silicon Motion SM712 2D drawing engine functions.
|
||||
*
|
||||
* Copyright (C) 2006 Silicon Motion Technology Corp.
|
||||
* Author: Ge Wang, gewang@siliconmotion.com
|
||||
*
|
||||
* Copyright (C) 2009 Lemote, Inc.
|
||||
* Author: Wu Zhangjin, wuzj@lemote.com
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file COPYING in the main directory of this archive for
|
||||
* more details.
|
||||
*/
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
|
||||
/* Internal macros */
|
||||
|
||||
#define _F_START(f) (0 ? f)
|
||||
#define _F_END(f) (1 ? f)
|
||||
#define _F_SIZE(f) (1 + _F_END(f) - _F_START(f))
|
||||
#define _F_MASK(f) (((1ULL << _F_SIZE(f)) - 1) << _F_START(f))
|
||||
#define _F_NORMALIZE(v, f) (((v) & _F_MASK(f)) >> _F_START(f))
|
||||
#define _F_DENORMALIZE(v, f) (((v) << _F_START(f)) & _F_MASK(f))
|
||||
|
||||
/* Global macros */
|
||||
|
||||
#define FIELD_GET(x, reg, field) \
|
||||
( \
|
||||
_F_NORMALIZE((x), reg ## _ ## field) \
|
||||
)
|
||||
|
||||
#define FIELD_SET(x, reg, field, value) \
|
||||
( \
|
||||
(x & ~_F_MASK(reg ## _ ## field)) \
|
||||
| _F_DENORMALIZE(reg ## _ ## field ## _ ## value, reg ## _ ## field) \
|
||||
)
|
||||
|
||||
#define FIELD_VALUE(x, reg, field, value) \
|
||||
( \
|
||||
(x & ~_F_MASK(reg ## _ ## field)) \
|
||||
| _F_DENORMALIZE(value, reg ## _ ## field) \
|
||||
)
|
||||
|
||||
#define FIELD_CLEAR(reg, field) \
|
||||
( \
|
||||
~_F_MASK(reg ## _ ## field) \
|
||||
)
|
||||
|
||||
/* Field Macros */
|
||||
|
||||
#define FIELD_START(field) (0 ? field)
|
||||
#define FIELD_END(field) (1 ? field)
|
||||
#define FIELD_SIZE(field) \
|
||||
(1 + FIELD_END(field) - FIELD_START(field))
|
||||
|
||||
#define FIELD_MASK(field) \
|
||||
(((1 << (FIELD_SIZE(field)-1)) \
|
||||
| ((1 << (FIELD_SIZE(field)-1)) - 1)) \
|
||||
<< FIELD_START(field))
|
||||
|
||||
#define FIELD_NORMALIZE(reg, field) \
|
||||
(((reg) & FIELD_MASK(field)) >> FIELD_START(field))
|
||||
|
||||
#define FIELD_DENORMALIZE(field, value) \
|
||||
(((value) << FIELD_START(field)) & FIELD_MASK(field))
|
||||
|
||||
#define FIELD_INIT(reg, field, value) \
|
||||
FIELD_DENORMALIZE(reg ## _ ## field, \
|
||||
reg ## _ ## field ## _ ## value)
|
||||
|
||||
#define FIELD_INIT_VAL(reg, field, value) \
|
||||
(FIELD_DENORMALIZE(reg ## _ ## field, value))
|
||||
|
||||
#define FIELD_VAL_SET(x, r, f, v) ({ \
|
||||
x = (x & ~FIELD_MASK(r ## _ ## f)) \
|
||||
| FIELD_DENORMALIZE(r ## _ ## f, r ## _ ## f ## _ ## v) \
|
||||
})
|
||||
|
||||
#define RGB(r, g, b) ((unsigned long)(((r) << 16) | ((g) << 8) | (b)))
|
||||
|
||||
/* Transparent info definition */
|
||||
typedef struct {
|
||||
unsigned long match; /* Matching pixel is OPAQUE/TRANSPARENT */
|
||||
unsigned long select; /* Transparency controlled by SRC/DST */
|
||||
unsigned long control; /* ENABLE/DISABLE transparency */
|
||||
unsigned long color; /* Transparent color */
|
||||
} Transparent, *pTransparent;
|
||||
|
||||
#define PIXEL_DEPTH_1_BP 0 /* 1 bit per pixel */
|
||||
#define PIXEL_DEPTH_8_BPP 1 /* 8 bits per pixel */
|
||||
#define PIXEL_DEPTH_16_BPP 2 /* 16 bits per pixel */
|
||||
#define PIXEL_DEPTH_32_BPP 3 /* 32 bits per pixel */
|
||||
#define PIXEL_DEPTH_YUV422 8 /* 16 bits per pixel YUV422 */
|
||||
#define PIXEL_DEPTH_YUV420 9 /* 16 bits per pixel YUV420 */
|
||||
|
||||
#define PATTERN_WIDTH 8
|
||||
#define PATTERN_HEIGHT 8
|
||||
|
||||
#define TOP_TO_BOTTOM 0
|
||||
#define BOTTOM_TO_TOP 1
|
||||
#define RIGHT_TO_LEFT BOTTOM_TO_TOP
|
||||
#define LEFT_TO_RIGHT TOP_TO_BOTTOM
|
||||
|
||||
/* Constants used in Transparent structure */
|
||||
#define MATCH_OPAQUE 0x00000000
|
||||
#define MATCH_TRANSPARENT 0x00000400
|
||||
#define SOURCE 0x00000000
|
||||
#define DESTINATION 0x00000200
|
||||
|
||||
/* 2D registers. */
|
||||
|
||||
#define DE_SOURCE 0x000000
|
||||
#define DE_SOURCE_WRAP 31 : 31
|
||||
#define DE_SOURCE_WRAP_DISABLE 0
|
||||
#define DE_SOURCE_WRAP_ENABLE 1
|
||||
#define DE_SOURCE_X_K1 29 : 16
|
||||
#define DE_SOURCE_Y_K2 15 : 0
|
||||
|
||||
#define DE_DESTINATION 0x000004
|
||||
#define DE_DESTINATION_WRAP 31 : 31
|
||||
#define DE_DESTINATION_WRAP_DISABLE 0
|
||||
#define DE_DESTINATION_WRAP_ENABLE 1
|
||||
#define DE_DESTINATION_X 28 : 16
|
||||
#define DE_DESTINATION_Y 15 : 0
|
||||
|
||||
#define DE_DIMENSION 0x000008
|
||||
#define DE_DIMENSION_X 28 : 16
|
||||
#define DE_DIMENSION_Y_ET 15 : 0
|
||||
|
||||
#define DE_CONTROL 0x00000C
|
||||
#define DE_CONTROL_STATUS 31 : 31
|
||||
#define DE_CONTROL_STATUS_STOP 0
|
||||
#define DE_CONTROL_STATUS_START 1
|
||||
#define DE_CONTROL_PATTERN 30 : 30
|
||||
#define DE_CONTROL_PATTERN_MONO 0
|
||||
#define DE_CONTROL_PATTERN_COLOR 1
|
||||
#define DE_CONTROL_UPDATE_DESTINATION_X 29 : 29
|
||||
#define DE_CONTROL_UPDATE_DESTINATION_X_DISABLE 0
|
||||
#define DE_CONTROL_UPDATE_DESTINATION_X_ENABLE 1
|
||||
#define DE_CONTROL_QUICK_START 28 : 28
|
||||
#define DE_CONTROL_QUICK_START_DISABLE 0
|
||||
#define DE_CONTROL_QUICK_START_ENABLE 1
|
||||
#define DE_CONTROL_DIRECTION 27 : 27
|
||||
#define DE_CONTROL_DIRECTION_LEFT_TO_RIGHT 0
|
||||
#define DE_CONTROL_DIRECTION_RIGHT_TO_LEFT 1
|
||||
#define DE_CONTROL_MAJOR 26 : 26
|
||||
#define DE_CONTROL_MAJOR_X 0
|
||||
#define DE_CONTROL_MAJOR_Y 1
|
||||
#define DE_CONTROL_STEP_X 25 : 25
|
||||
#define DE_CONTROL_STEP_X_POSITIVE 1
|
||||
#define DE_CONTROL_STEP_X_NEGATIVE 0
|
||||
#define DE_CONTROL_STEP_Y 24 : 24
|
||||
#define DE_CONTROL_STEP_Y_POSITIVE 1
|
||||
#define DE_CONTROL_STEP_Y_NEGATIVE 0
|
||||
#define DE_CONTROL_STRETCH 23 : 23
|
||||
#define DE_CONTROL_STRETCH_DISABLE 0
|
||||
#define DE_CONTROL_STRETCH_ENABLE 1
|
||||
#define DE_CONTROL_HOST 22 : 22
|
||||
#define DE_CONTROL_HOST_COLOR 0
|
||||
#define DE_CONTROL_HOST_MONO 1
|
||||
#define DE_CONTROL_LAST_PIXEL 21 : 21
|
||||
#define DE_CONTROL_LAST_PIXEL_OFF 0
|
||||
#define DE_CONTROL_LAST_PIXEL_ON 1
|
||||
#define DE_CONTROL_COMMAND 20 : 16
|
||||
#define DE_CONTROL_COMMAND_BITBLT 0
|
||||
#define DE_CONTROL_COMMAND_RECTANGLE_FILL 1
|
||||
#define DE_CONTROL_COMMAND_DE_TILE 2
|
||||
#define DE_CONTROL_COMMAND_TRAPEZOID_FILL 3
|
||||
#define DE_CONTROL_COMMAND_ALPHA_BLEND 4
|
||||
#define DE_CONTROL_COMMAND_RLE_STRIP 5
|
||||
#define DE_CONTROL_COMMAND_SHORT_STROKE 6
|
||||
#define DE_CONTROL_COMMAND_LINE_DRAW 7
|
||||
#define DE_CONTROL_COMMAND_HOST_WRITE 8
|
||||
#define DE_CONTROL_COMMAND_HOST_READ 9
|
||||
#define DE_CONTROL_COMMAND_HOST_WRITE_BOTTOM_UP 10
|
||||
#define DE_CONTROL_COMMAND_ROTATE 11
|
||||
#define DE_CONTROL_COMMAND_FONT 12
|
||||
#define DE_CONTROL_COMMAND_TEXTURE_LOAD 15
|
||||
#define DE_CONTROL_ROP_SELECT 15 : 15
|
||||
#define DE_CONTROL_ROP_SELECT_ROP3 0
|
||||
#define DE_CONTROL_ROP_SELECT_ROP2 1
|
||||
#define DE_CONTROL_ROP2_SOURCE 14 : 14
|
||||
#define DE_CONTROL_ROP2_SOURCE_BITMAP 0
|
||||
#define DE_CONTROL_ROP2_SOURCE_PATTERN 1
|
||||
#define DE_CONTROL_MONO_DATA 13 : 12
|
||||
#define DE_CONTROL_MONO_DATA_NOT_PACKED 0
|
||||
#define DE_CONTROL_MONO_DATA_8_PACKED 1
|
||||
#define DE_CONTROL_MONO_DATA_16_PACKED 2
|
||||
#define DE_CONTROL_MONO_DATA_32_PACKED 3
|
||||
#define DE_CONTROL_REPEAT_ROTATE 11 : 11
|
||||
#define DE_CONTROL_REPEAT_ROTATE_DISABLE 0
|
||||
#define DE_CONTROL_REPEAT_ROTATE_ENABLE 1
|
||||
#define DE_CONTROL_TRANSPARENCY_MATCH 10 : 10
|
||||
#define DE_CONTROL_TRANSPARENCY_MATCH_OPAQUE 0
|
||||
#define DE_CONTROL_TRANSPARENCY_MATCH_TRANSPARENT 1
|
||||
#define DE_CONTROL_TRANSPARENCY_SELECT 9 : 9
|
||||
#define DE_CONTROL_TRANSPARENCY_SELECT_SOURCE 0
|
||||
#define DE_CONTROL_TRANSPARENCY_SELECT_DESTINATION 1
|
||||
#define DE_CONTROL_TRANSPARENCY 8 : 8
|
||||
#define DE_CONTROL_TRANSPARENCY_DISABLE 0
|
||||
#define DE_CONTROL_TRANSPARENCY_ENABLE 1
|
||||
#define DE_CONTROL_ROP 7 : 0
|
||||
|
||||
/* Pseudo fields. */
|
||||
|
||||
#define DE_CONTROL_SHORT_STROKE_DIR 27 : 24
|
||||
#define DE_CONTROL_SHORT_STROKE_DIR_225 0
|
||||
#define DE_CONTROL_SHORT_STROKE_DIR_135 1
|
||||
#define DE_CONTROL_SHORT_STROKE_DIR_315 2
|
||||
#define DE_CONTROL_SHORT_STROKE_DIR_45 3
|
||||
#define DE_CONTROL_SHORT_STROKE_DIR_270 4
|
||||
#define DE_CONTROL_SHORT_STROKE_DIR_90 5
|
||||
#define DE_CONTROL_SHORT_STROKE_DIR_180 8
|
||||
#define DE_CONTROL_SHORT_STROKE_DIR_0 10
|
||||
#define DE_CONTROL_ROTATION 25 : 24
|
||||
#define DE_CONTROL_ROTATION_0 0
|
||||
#define DE_CONTROL_ROTATION_270 1
|
||||
#define DE_CONTROL_ROTATION_90 2
|
||||
#define DE_CONTROL_ROTATION_180 3
|
||||
|
||||
#define DE_PITCH 0x000010
|
||||
#define DE_PITCH_DESTINATION 28 : 16
|
||||
#define DE_PITCH_SOURCE 12 : 0
|
||||
|
||||
#define DE_FOREGROUND 0x000014
|
||||
#define DE_FOREGROUND_COLOR 31 : 0
|
||||
|
||||
#define DE_BACKGROUND 0x000018
|
||||
#define DE_BACKGROUND_COLOR 31 : 0
|
||||
|
||||
#define DE_STRETCH_FORMAT 0x00001C
|
||||
#define DE_STRETCH_FORMAT_PATTERN_XY 30 : 30
|
||||
#define DE_STRETCH_FORMAT_PATTERN_XY_NORMAL 0
|
||||
#define DE_STRETCH_FORMAT_PATTERN_XY_OVERWRITE 1
|
||||
#define DE_STRETCH_FORMAT_PATTERN_Y 29 : 27
|
||||
#define DE_STRETCH_FORMAT_PATTERN_X 25 : 23
|
||||
#define DE_STRETCH_FORMAT_PIXEL_FORMAT 21 : 20
|
||||
#define DE_STRETCH_FORMAT_PIXEL_FORMAT_8 0
|
||||
#define DE_STRETCH_FORMAT_PIXEL_FORMAT_16 1
|
||||
#define DE_STRETCH_FORMAT_PIXEL_FORMAT_24 3
|
||||
#define DE_STRETCH_FORMAT_PIXEL_FORMAT_32 2
|
||||
#define DE_STRETCH_FORMAT_ADDRESSING 19 : 16
|
||||
#define DE_STRETCH_FORMAT_ADDRESSING_XY 0
|
||||
#define DE_STRETCH_FORMAT_ADDRESSING_LINEAR 15
|
||||
#define DE_STRETCH_FORMAT_SOURCE_HEIGHT 11 : 0
|
||||
|
||||
#define DE_COLOR_COMPARE 0x000020
|
||||
#define DE_COLOR_COMPARE_COLOR 23 : 0
|
||||
|
||||
#define DE_COLOR_COMPARE_MASK 0x000024
|
||||
#define DE_COLOR_COMPARE_MASK_MASKS 23 : 0
|
||||
|
||||
#define DE_MASKS 0x000028
|
||||
#define DE_MASKS_BYTE_MASK 31 : 16
|
||||
#define DE_MASKS_BIT_MASK 15 : 0
|
||||
|
||||
#define DE_CLIP_TL 0x00002C
|
||||
#define DE_CLIP_TL_TOP 31 : 16
|
||||
#define DE_CLIP_TL_STATUS 13 : 13
|
||||
#define DE_CLIP_TL_STATUS_DISABLE 0
|
||||
#define DE_CLIP_TL_STATUS_ENABLE 1
|
||||
#define DE_CLIP_TL_INHIBIT 12 : 12
|
||||
#define DE_CLIP_TL_INHIBIT_OUTSIDE 0
|
||||
#define DE_CLIP_TL_INHIBIT_INSIDE 1
|
||||
#define DE_CLIP_TL_LEFT 11 : 0
|
||||
|
||||
#define DE_CLIP_BR 0x000030
|
||||
#define DE_CLIP_BR_BOTTOM 31 : 16
|
||||
#define DE_CLIP_BR_RIGHT 12 : 0
|
||||
|
||||
#define DE_MONO_PATTERN_LOW 0x000034
|
||||
#define DE_MONO_PATTERN_LOW_PATTERN 31 : 0
|
||||
|
||||
#define DE_MONO_PATTERN_HIGH 0x000038
|
||||
#define DE_MONO_PATTERN_HIGH_PATTERN 31 : 0
|
||||
|
||||
#define DE_WINDOW_WIDTH 0x00003C
|
||||
#define DE_WINDOW_WIDTH_DESTINATION 28 : 16
|
||||
#define DE_WINDOW_WIDTH_SOURCE 12 : 0
|
||||
|
||||
#define DE_WINDOW_SOURCE_BASE 0x000040
|
||||
#define DE_WINDOW_SOURCE_BASE_EXT 27 : 27
|
||||
#define DE_WINDOW_SOURCE_BASE_EXT_LOCAL 0
|
||||
#define DE_WINDOW_SOURCE_BASE_EXT_EXTERNAL 1
|
||||
#define DE_WINDOW_SOURCE_BASE_CS 26 : 26
|
||||
#define DE_WINDOW_SOURCE_BASE_CS_0 0
|
||||
#define DE_WINDOW_SOURCE_BASE_CS_1 1
|
||||
#define DE_WINDOW_SOURCE_BASE_ADDRESS 25 : 0
|
||||
|
||||
#define DE_WINDOW_DESTINATION_BASE 0x000044
|
||||
#define DE_WINDOW_DESTINATION_BASE_EXT 27 : 27
|
||||
#define DE_WINDOW_DESTINATION_BASE_EXT_LOCAL 0
|
||||
#define DE_WINDOW_DESTINATION_BASE_EXT_EXTERNAL 1
|
||||
#define DE_WINDOW_DESTINATION_BASE_CS 26 : 26
|
||||
#define DE_WINDOW_DESTINATION_BASE_CS_0 0
|
||||
#define DE_WINDOW_DESTINATION_BASE_CS_1 1
|
||||
#define DE_WINDOW_DESTINATION_BASE_ADDRESS 25 : 0
|
||||
|
||||
#define DE_ALPHA 0x000048
|
||||
#define DE_ALPHA_VALUE 7 : 0
|
||||
|
||||
#define DE_WRAP 0x00004C
|
||||
#define DE_WRAP_X 31 : 16
|
||||
#define DE_WRAP_Y 15 : 0
|
||||
|
||||
#define DE_STATUS 0x000050
|
||||
#define DE_STATUS_CSC 1 : 1
|
||||
#define DE_STATUS_CSC_CLEAR 0
|
||||
#define DE_STATUS_CSC_NOT_ACTIVE 0
|
||||
#define DE_STATUS_CSC_ACTIVE 1
|
||||
#define DE_STATUS_2D 0 : 0
|
||||
#define DE_STATUS_2D_CLEAR 0
|
||||
#define DE_STATUS_2D_NOT_ACTIVE 0
|
||||
#define DE_STATUS_2D_ACTIVE 1
|
||||
|
||||
/* Color Space Conversion registers. */
|
||||
|
||||
#define CSC_Y_SOURCE_BASE 0x0000C8
|
||||
#define CSC_Y_SOURCE_BASE_EXT 27 : 27
|
||||
#define CSC_Y_SOURCE_BASE_EXT_LOCAL 0
|
||||
#define CSC_Y_SOURCE_BASE_EXT_EXTERNAL 1
|
||||
#define CSC_Y_SOURCE_BASE_CS 26 : 26
|
||||
#define CSC_Y_SOURCE_BASE_CS_0 0
|
||||
#define CSC_Y_SOURCE_BASE_CS_1 1
|
||||
#define CSC_Y_SOURCE_BASE_ADDRESS 25 : 0
|
||||
|
||||
#define CSC_CONSTANTS 0x0000CC
|
||||
#define CSC_CONSTANTS_Y 31 : 24
|
||||
#define CSC_CONSTANTS_R 23 : 16
|
||||
#define CSC_CONSTANTS_G 15 : 8
|
||||
#define CSC_CONSTANTS_B 7 : 0
|
||||
|
||||
#define CSC_Y_SOURCE_X 0x0000D0
|
||||
#define CSC_Y_SOURCE_X_INTEGER 26 : 16
|
||||
#define CSC_Y_SOURCE_X_FRACTION 15 : 3
|
||||
|
||||
#define CSC_Y_SOURCE_Y 0x0000D4
|
||||
#define CSC_Y_SOURCE_Y_INTEGER 27 : 16
|
||||
#define CSC_Y_SOURCE_Y_FRACTION 15 : 3
|
||||
|
||||
#define CSC_U_SOURCE_BASE 0x0000D8
|
||||
#define CSC_U_SOURCE_BASE_EXT 27 : 27
|
||||
#define CSC_U_SOURCE_BASE_EXT_LOCAL 0
|
||||
#define CSC_U_SOURCE_BASE_EXT_EXTERNAL 1
|
||||
#define CSC_U_SOURCE_BASE_CS 26 : 26
|
||||
#define CSC_U_SOURCE_BASE_CS_0 0
|
||||
#define CSC_U_SOURCE_BASE_CS_1 1
|
||||
#define CSC_U_SOURCE_BASE_ADDRESS 25 : 0
|
||||
|
||||
#define CSC_V_SOURCE_BASE 0x0000DC
|
||||
#define CSC_V_SOURCE_BASE_EXT 27 : 27
|
||||
#define CSC_V_SOURCE_BASE_EXT_LOCAL 0
|
||||
#define CSC_V_SOURCE_BASE_EXT_EXTERNAL 1
|
||||
#define CSC_V_SOURCE_BASE_CS 26 : 26
|
||||
#define CSC_V_SOURCE_BASE_CS_0 0
|
||||
#define CSC_V_SOURCE_BASE_CS_1 1
|
||||
#define CSC_V_SOURCE_BASE_ADDRESS 25 : 0
|
||||
|
||||
#define CSC_SOURCE_DIMENSION 0x0000E0
|
||||
#define CSC_SOURCE_DIMENSION_X 31 : 16
|
||||
#define CSC_SOURCE_DIMENSION_Y 15 : 0
|
||||
|
||||
#define CSC_SOURCE_PITCH 0x0000E4
|
||||
#define CSC_SOURCE_PITCH_Y 31 : 16
|
||||
#define CSC_SOURCE_PITCH_UV 15 : 0
|
||||
|
||||
#define CSC_DESTINATION 0x0000E8
|
||||
#define CSC_DESTINATION_WRAP 31 : 31
|
||||
#define CSC_DESTINATION_WRAP_DISABLE 0
|
||||
#define CSC_DESTINATION_WRAP_ENABLE 1
|
||||
#define CSC_DESTINATION_X 27 : 16
|
||||
#define CSC_DESTINATION_Y 11 : 0
|
||||
|
||||
#define CSC_DESTINATION_DIMENSION 0x0000EC
|
||||
#define CSC_DESTINATION_DIMENSION_X 31 : 16
|
||||
#define CSC_DESTINATION_DIMENSION_Y 15 : 0
|
||||
|
||||
#define CSC_DESTINATION_PITCH 0x0000F0
|
||||
#define CSC_DESTINATION_PITCH_X 31 : 16
|
||||
#define CSC_DESTINATION_PITCH_Y 15 : 0
|
||||
|
||||
#define CSC_SCALE_FACTOR 0x0000F4
|
||||
#define CSC_SCALE_FACTOR_HORIZONTAL 31 : 16
|
||||
#define CSC_SCALE_FACTOR_VERTICAL 15 : 0
|
||||
|
||||
#define CSC_DESTINATION_BASE 0x0000F8
|
||||
#define CSC_DESTINATION_BASE_EXT 27 : 27
|
||||
#define CSC_DESTINATION_BASE_EXT_LOCAL 0
|
||||
#define CSC_DESTINATION_BASE_EXT_EXTERNAL 1
|
||||
#define CSC_DESTINATION_BASE_CS 26 : 26
|
||||
#define CSC_DESTINATION_BASE_CS_0 0
|
||||
#define CSC_DESTINATION_BASE_CS_1 1
|
||||
#define CSC_DESTINATION_BASE_ADDRESS 25 : 0
|
||||
|
||||
#define CSC_CONTROL 0x0000FC
|
||||
#define CSC_CONTROL_STATUS 31 : 31
|
||||
#define CSC_CONTROL_STATUS_STOP 0
|
||||
#define CSC_CONTROL_STATUS_START 1
|
||||
#define CSC_CONTROL_SOURCE_FORMAT 30 : 28
|
||||
#define CSC_CONTROL_SOURCE_FORMAT_YUV422 0
|
||||
#define CSC_CONTROL_SOURCE_FORMAT_YUV420I 1
|
||||
#define CSC_CONTROL_SOURCE_FORMAT_YUV420 2
|
||||
#define CSC_CONTROL_SOURCE_FORMAT_YVU9 3
|
||||
#define CSC_CONTROL_SOURCE_FORMAT_IYU1 4
|
||||
#define CSC_CONTROL_SOURCE_FORMAT_IYU2 5
|
||||
#define CSC_CONTROL_SOURCE_FORMAT_RGB565 6
|
||||
#define CSC_CONTROL_SOURCE_FORMAT_RGB8888 7
|
||||
#define CSC_CONTROL_DESTINATION_FORMAT 27 : 26
|
||||
#define CSC_CONTROL_DESTINATION_FORMAT_RGB565 0
|
||||
#define CSC_CONTROL_DESTINATION_FORMAT_RGB8888 1
|
||||
#define CSC_CONTROL_HORIZONTAL_FILTER 25 : 25
|
||||
#define CSC_CONTROL_HORIZONTAL_FILTER_DISABLE 0
|
||||
#define CSC_CONTROL_HORIZONTAL_FILTER_ENABLE 1
|
||||
#define CSC_CONTROL_VERTICAL_FILTER 24 : 24
|
||||
#define CSC_CONTROL_VERTICAL_FILTER_DISABLE 0
|
||||
#define CSC_CONTROL_VERTICAL_FILTER_ENABLE 1
|
||||
#define CSC_CONTROL_BYTE_ORDER 23 : 23
|
||||
#define CSC_CONTROL_BYTE_ORDER_YUYV 0
|
||||
#define CSC_CONTROL_BYTE_ORDER_UYVY 1
|
||||
|
||||
#define DE_DATA_PORT_501 0x110000
|
||||
#define DE_DATA_PORT_712 0x400000
|
||||
#define DE_DATA_PORT_722 0x6000
|
||||
|
||||
/* point to virtual Memory Map IO starting address */
|
||||
extern char *smtc_RegBaseAddress;
|
||||
/* point to virtual video memory starting address */
|
||||
extern char *smtc_VRAMBaseAddress;
|
||||
extern unsigned char smtc_de_busy;
|
||||
|
||||
extern unsigned long memRead32(unsigned long nOffset);
|
||||
extern void memWrite32(unsigned long nOffset, unsigned long nData);
|
||||
extern unsigned long SMTC_read2Dreg(unsigned long nOffset);
|
||||
|
||||
/* 2D functions */
|
||||
extern void deInit(unsigned int nModeWidth, unsigned int nModeHeight,
|
||||
unsigned int bpp);
|
||||
|
||||
extern void deWaitForNotBusy(void);
|
||||
|
||||
extern void deVerticalLine(unsigned long dst_base,
|
||||
unsigned long dst_pitch,
|
||||
unsigned long nX,
|
||||
unsigned long nY,
|
||||
unsigned long dst_height,
|
||||
unsigned long nColor);
|
||||
|
||||
extern void deHorizontalLine(unsigned long dst_base,
|
||||
unsigned long dst_pitch,
|
||||
unsigned long nX,
|
||||
unsigned long nY,
|
||||
unsigned long dst_width,
|
||||
unsigned long nColor);
|
||||
|
||||
extern void deLine(unsigned long dst_base,
|
||||
unsigned long dst_pitch,
|
||||
unsigned long nX1,
|
||||
unsigned long nY1,
|
||||
unsigned long nX2,
|
||||
unsigned long nY2,
|
||||
unsigned long nColor);
|
||||
|
||||
extern void deFillRect(unsigned long dst_base,
|
||||
unsigned long dst_pitch,
|
||||
unsigned long dst_X,
|
||||
unsigned long dst_Y,
|
||||
unsigned long dst_width,
|
||||
unsigned long dst_height,
|
||||
unsigned long nColor);
|
||||
|
||||
extern void deRotatePattern(unsigned char *pattern_dstaddr,
|
||||
unsigned long pattern_src_addr,
|
||||
unsigned long pattern_BPP,
|
||||
unsigned long pattern_stride,
|
||||
int patternX,
|
||||
int patternY);
|
||||
|
||||
extern void deCopy(unsigned long dst_base,
|
||||
unsigned long dst_pitch,
|
||||
unsigned long dst_BPP,
|
||||
unsigned long dst_X,
|
||||
unsigned long dst_Y,
|
||||
unsigned long dst_width,
|
||||
unsigned long dst_height,
|
||||
unsigned long src_base,
|
||||
unsigned long src_pitch,
|
||||
unsigned long src_X,
|
||||
unsigned long src_Y,
|
||||
pTransparent pTransp,
|
||||
unsigned char nROP2);
|
||||
|
||||
/*
|
||||
* System memory to Video memory monochrome expansion.
|
||||
*
|
||||
* Source is monochrome image in system memory. This function expands the
|
||||
* monochrome data to color image in video memory.
|
||||
*
|
||||
* @pSrcbuf: pointer to start of source buffer in system memory
|
||||
* @srcDelta: Pitch value (in bytes) of the source buffer, +ive means top
|
||||
* down and -ive mean button up
|
||||
* @startBit: Mono data can start at any bit in a byte, this value should
|
||||
* be 0 to 7
|
||||
* @dBase: Address of destination : offset in frame buffer
|
||||
* @dPitch: Pitch value of destination surface in BYTE
|
||||
* @bpp: Color depth of destination surface
|
||||
* @dx, dy: Starting coordinate of destination surface
|
||||
* @width, height: width and height of rectange in pixel value
|
||||
* @fColor,bColor: Foreground, Background color (corresponding to a 1, 0 in
|
||||
* the monochrome data)
|
||||
* @rop2: ROP value
|
||||
*/
|
||||
|
||||
extern long deSystemMem2VideoMemMonoBlt(
|
||||
const char *pSrcbuf,
|
||||
long srcDelta,
|
||||
unsigned long startBit,
|
||||
unsigned long dBase,
|
||||
unsigned long dPitch,
|
||||
unsigned long bpp,
|
||||
unsigned long dx, unsigned long dy,
|
||||
unsigned long width, unsigned long height,
|
||||
unsigned long fColor,
|
||||
unsigned long bColor,
|
||||
unsigned long rop2);
|
||||
|
||||
extern unsigned long deGetTransparency(void);
|
||||
extern void deSetPixelFormat(unsigned long bpp);
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,793 @@
|
|||
/*
|
||||
* Silicon Motion SM712 frame buffer device
|
||||
*
|
||||
* Copyright (C) 2006 Silicon Motion Technology Corp.
|
||||
* Authors: Ge Wang, gewang@siliconmotion.com
|
||||
* Boyod boyod.yang@siliconmotion.com.cn
|
||||
*
|
||||
* Copyright (C) 2009 Lemote, Inc.
|
||||
* Author: Wu Zhangjin, wuzj@lemote.com
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file COPYING in the main directory of this archive for
|
||||
* more details.
|
||||
*/
|
||||
|
||||
#define SMTC_LINUX_FB_VERSION "version 0.11.2619.21.01 July 27, 2008"
|
||||
|
||||
#define NR_PALETTE 256
|
||||
#define NR_RGB 2
|
||||
|
||||
#define FB_ACCEL_SMI_LYNX 88
|
||||
|
||||
#ifdef __BIG_ENDIAN
|
||||
#define PC_VGA 0
|
||||
#else
|
||||
#define PC_VGA 1
|
||||
#endif
|
||||
|
||||
#define SCREEN_X_RES 1024
|
||||
#define SCREEN_Y_RES 600
|
||||
#define SCREEN_BPP 16
|
||||
|
||||
#ifndef FIELD_OFFSET
|
||||
#define FIELD_OFSFET(type, field) \
|
||||
((unsigned long) (PUCHAR) & (((type *)0)->field))
|
||||
#endif
|
||||
|
||||
/*Assume SM712 graphics chip has 4MB VRAM */
|
||||
#define SM712_VIDEOMEMORYSIZE 0x00400000
|
||||
/*Assume SM722 graphics chip has 8MB VRAM */
|
||||
#define SM722_VIDEOMEMORYSIZE 0x00800000
|
||||
|
||||
#define dac_reg (0x3c8)
|
||||
#define dac_val (0x3c9)
|
||||
|
||||
extern char *smtc_RegBaseAddress;
|
||||
#define smtc_mmiowb(dat, reg) writeb(dat, smtc_RegBaseAddress + reg)
|
||||
#define smtc_mmioww(dat, reg) writew(dat, smtc_RegBaseAddress + reg)
|
||||
#define smtc_mmiowl(dat, reg) writel(dat, smtc_RegBaseAddress + reg)
|
||||
|
||||
#define smtc_mmiorb(reg) readb(smtc_RegBaseAddress + reg)
|
||||
#define smtc_mmiorw(reg) readw(smtc_RegBaseAddress + reg)
|
||||
#define smtc_mmiorl(reg) readl(smtc_RegBaseAddress + reg)
|
||||
|
||||
#define SIZE_SR00_SR04 (0x04 - 0x00 + 1)
|
||||
#define SIZE_SR10_SR24 (0x24 - 0x10 + 1)
|
||||
#define SIZE_SR30_SR75 (0x75 - 0x30 + 1)
|
||||
#define SIZE_SR80_SR93 (0x93 - 0x80 + 1)
|
||||
#define SIZE_SRA0_SRAF (0xAF - 0xA0 + 1)
|
||||
#define SIZE_GR00_GR08 (0x08 - 0x00 + 1)
|
||||
#define SIZE_AR00_AR14 (0x14 - 0x00 + 1)
|
||||
#define SIZE_CR00_CR18 (0x18 - 0x00 + 1)
|
||||
#define SIZE_CR30_CR4D (0x4D - 0x30 + 1)
|
||||
#define SIZE_CR90_CRA7 (0xA7 - 0x90 + 1)
|
||||
#define SIZE_VPR (0x6C + 1)
|
||||
#define SIZE_DPR (0x44 + 1)
|
||||
|
||||
static inline void smtc_crtcw(int reg, int val)
|
||||
{
|
||||
smtc_mmiowb(reg, 0x3d4);
|
||||
smtc_mmiowb(val, 0x3d5);
|
||||
}
|
||||
|
||||
static inline unsigned int smtc_crtcr(int reg)
|
||||
{
|
||||
smtc_mmiowb(reg, 0x3d4);
|
||||
return smtc_mmiorb(0x3d5);
|
||||
}
|
||||
|
||||
static inline void smtc_grphw(int reg, int val)
|
||||
{
|
||||
smtc_mmiowb(reg, 0x3ce);
|
||||
smtc_mmiowb(val, 0x3cf);
|
||||
}
|
||||
|
||||
static inline unsigned int smtc_grphr(int reg)
|
||||
{
|
||||
smtc_mmiowb(reg, 0x3ce);
|
||||
return smtc_mmiorb(0x3cf);
|
||||
}
|
||||
|
||||
static inline void smtc_attrw(int reg, int val)
|
||||
{
|
||||
smtc_mmiorb(0x3da);
|
||||
smtc_mmiowb(reg, 0x3c0);
|
||||
smtc_mmiorb(0x3c1);
|
||||
smtc_mmiowb(val, 0x3c0);
|
||||
}
|
||||
|
||||
static inline void smtc_seqw(int reg, int val)
|
||||
{
|
||||
smtc_mmiowb(reg, 0x3c4);
|
||||
smtc_mmiowb(val, 0x3c5);
|
||||
}
|
||||
|
||||
static inline unsigned int smtc_seqr(int reg)
|
||||
{
|
||||
smtc_mmiowb(reg, 0x3c4);
|
||||
return smtc_mmiorb(0x3c5);
|
||||
}
|
||||
|
||||
/* The next structure holds all information relevant for a specific video mode.
|
||||
*/
|
||||
|
||||
struct ModeInit {
|
||||
int mmSizeX;
|
||||
int mmSizeY;
|
||||
int bpp;
|
||||
int hz;
|
||||
unsigned char Init_MISC;
|
||||
unsigned char Init_SR00_SR04[SIZE_SR00_SR04];
|
||||
unsigned char Init_SR10_SR24[SIZE_SR10_SR24];
|
||||
unsigned char Init_SR30_SR75[SIZE_SR30_SR75];
|
||||
unsigned char Init_SR80_SR93[SIZE_SR80_SR93];
|
||||
unsigned char Init_SRA0_SRAF[SIZE_SRA0_SRAF];
|
||||
unsigned char Init_GR00_GR08[SIZE_GR00_GR08];
|
||||
unsigned char Init_AR00_AR14[SIZE_AR00_AR14];
|
||||
unsigned char Init_CR00_CR18[SIZE_CR00_CR18];
|
||||
unsigned char Init_CR30_CR4D[SIZE_CR30_CR4D];
|
||||
unsigned char Init_CR90_CRA7[SIZE_CR90_CRA7];
|
||||
};
|
||||
|
||||
/**********************************************************************
|
||||
SM712 Mode table.
|
||||
**********************************************************************/
|
||||
struct ModeInit VGAMode[] = {
|
||||
{
|
||||
/* mode#0: 640 x 480 16Bpp 60Hz */
|
||||
640, 480, 16, 60,
|
||||
/* Init_MISC */
|
||||
0xE3,
|
||||
{ /* Init_SR0_SR4 */
|
||||
0x03, 0x01, 0x0F, 0x00, 0x0E,
|
||||
},
|
||||
{ /* Init_SR10_SR24 */
|
||||
0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
|
||||
0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xC4, 0x30, 0x02, 0x01, 0x01,
|
||||
},
|
||||
{ /* Init_SR30_SR75 */
|
||||
0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32,
|
||||
0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF,
|
||||
0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
|
||||
0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32,
|
||||
0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA,
|
||||
0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32,
|
||||
0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
|
||||
0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04,
|
||||
0x00, 0x45, 0x30, 0x30, 0x40, 0x30,
|
||||
},
|
||||
{ /* Init_SR80_SR93 */
|
||||
0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32,
|
||||
0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
},
|
||||
{ /* Init_SRA0_SRAF */
|
||||
0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
|
||||
0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF,
|
||||
},
|
||||
{ /* Init_GR00_GR08 */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
|
||||
0xFF,
|
||||
},
|
||||
{ /* Init_AR00_AR14 */
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x41, 0x00, 0x0F, 0x00, 0x00,
|
||||
},
|
||||
{ /* Init_CR00_CR18 */
|
||||
0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E,
|
||||
0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3,
|
||||
0xFF,
|
||||
},
|
||||
{ /* Init_CR30_CR4D */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20,
|
||||
0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD,
|
||||
0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00,
|
||||
0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF,
|
||||
},
|
||||
{ /* Init_CR90_CRA7 */
|
||||
0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55,
|
||||
0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00,
|
||||
0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00,
|
||||
},
|
||||
},
|
||||
{
|
||||
/* mode#1: 640 x 480 24Bpp 60Hz */
|
||||
640, 480, 24, 60,
|
||||
/* Init_MISC */
|
||||
0xE3,
|
||||
{ /* Init_SR0_SR4 */
|
||||
0x03, 0x01, 0x0F, 0x00, 0x0E,
|
||||
},
|
||||
{ /* Init_SR10_SR24 */
|
||||
0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
|
||||
0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xC4, 0x30, 0x02, 0x01, 0x01,
|
||||
},
|
||||
{ /* Init_SR30_SR75 */
|
||||
0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32,
|
||||
0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF,
|
||||
0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
|
||||
0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32,
|
||||
0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA,
|
||||
0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32,
|
||||
0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
|
||||
0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04,
|
||||
0x00, 0x45, 0x30, 0x30, 0x40, 0x30,
|
||||
},
|
||||
{ /* Init_SR80_SR93 */
|
||||
0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32,
|
||||
0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
},
|
||||
{ /* Init_SRA0_SRAF */
|
||||
0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
|
||||
0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF,
|
||||
},
|
||||
{ /* Init_GR00_GR08 */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
|
||||
0xFF,
|
||||
},
|
||||
{ /* Init_AR00_AR14 */
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x41, 0x00, 0x0F, 0x00, 0x00,
|
||||
},
|
||||
{ /* Init_CR00_CR18 */
|
||||
0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E,
|
||||
0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3,
|
||||
0xFF,
|
||||
},
|
||||
{ /* Init_CR30_CR4D */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20,
|
||||
0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD,
|
||||
0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00,
|
||||
0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF,
|
||||
},
|
||||
{ /* Init_CR90_CRA7 */
|
||||
0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55,
|
||||
0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00,
|
||||
0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00,
|
||||
},
|
||||
},
|
||||
{
|
||||
/* mode#0: 640 x 480 32Bpp 60Hz */
|
||||
640, 480, 32, 60,
|
||||
/* Init_MISC */
|
||||
0xE3,
|
||||
{ /* Init_SR0_SR4 */
|
||||
0x03, 0x01, 0x0F, 0x00, 0x0E,
|
||||
},
|
||||
{ /* Init_SR10_SR24 */
|
||||
0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
|
||||
0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xC4, 0x30, 0x02, 0x01, 0x01,
|
||||
},
|
||||
{ /* Init_SR30_SR75 */
|
||||
0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32,
|
||||
0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF,
|
||||
0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
|
||||
0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32,
|
||||
0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA,
|
||||
0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32,
|
||||
0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
|
||||
0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04,
|
||||
0x00, 0x45, 0x30, 0x30, 0x40, 0x30,
|
||||
},
|
||||
{ /* Init_SR80_SR93 */
|
||||
0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32,
|
||||
0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
},
|
||||
{ /* Init_SRA0_SRAF */
|
||||
0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
|
||||
0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF,
|
||||
},
|
||||
{ /* Init_GR00_GR08 */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
|
||||
0xFF,
|
||||
},
|
||||
{ /* Init_AR00_AR14 */
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x41, 0x00, 0x0F, 0x00, 0x00,
|
||||
},
|
||||
{ /* Init_CR00_CR18 */
|
||||
0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E,
|
||||
0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3,
|
||||
0xFF,
|
||||
},
|
||||
{ /* Init_CR30_CR4D */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20,
|
||||
0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD,
|
||||
0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00,
|
||||
0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF,
|
||||
},
|
||||
{ /* Init_CR90_CRA7 */
|
||||
0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55,
|
||||
0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00,
|
||||
0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00,
|
||||
},
|
||||
},
|
||||
|
||||
{ /* mode#2: 800 x 600 16Bpp 60Hz */
|
||||
800, 600, 16, 60,
|
||||
/* Init_MISC */
|
||||
0x2B,
|
||||
{ /* Init_SR0_SR4 */
|
||||
0x03, 0x01, 0x0F, 0x03, 0x0E,
|
||||
},
|
||||
{ /* Init_SR10_SR24 */
|
||||
0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
|
||||
0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xC4, 0x30, 0x02, 0x01, 0x01,
|
||||
},
|
||||
{ /* Init_SR30_SR75 */
|
||||
0x34, 0x03, 0x20, 0x09, 0xC0, 0x24, 0x24, 0x24,
|
||||
0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x03, 0xFF,
|
||||
0x00, 0xFC, 0x00, 0x00, 0x20, 0x38, 0x00, 0xFC,
|
||||
0x20, 0x0C, 0x44, 0x20, 0x00, 0x24, 0x24, 0x24,
|
||||
0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58,
|
||||
0x04, 0x55, 0x59, 0x24, 0x24, 0x00, 0x00, 0x24,
|
||||
0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00,
|
||||
0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13,
|
||||
0x02, 0x45, 0x30, 0x35, 0x40, 0x20,
|
||||
},
|
||||
{ /* Init_SR80_SR93 */
|
||||
0x00, 0x00, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x24,
|
||||
0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x24, 0x24,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
},
|
||||
{ /* Init_SRA0_SRAF */
|
||||
0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
|
||||
0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF,
|
||||
},
|
||||
{ /* Init_GR00_GR08 */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
|
||||
0xFF,
|
||||
},
|
||||
{ /* Init_AR00_AR14 */
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x41, 0x00, 0x0F, 0x00, 0x00,
|
||||
},
|
||||
{ /* Init_CR00_CR18 */
|
||||
0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0,
|
||||
0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3,
|
||||
0xFF,
|
||||
},
|
||||
{ /* Init_CR30_CR4D */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20,
|
||||
0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD,
|
||||
0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00,
|
||||
0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57,
|
||||
},
|
||||
{ /* Init_CR90_CRA7 */
|
||||
0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA,
|
||||
0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00,
|
||||
0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00,
|
||||
},
|
||||
},
|
||||
{ /* mode#3: 800 x 600 24Bpp 60Hz */
|
||||
800, 600, 24, 60,
|
||||
0x2B,
|
||||
{ /* Init_SR0_SR4 */
|
||||
0x03, 0x01, 0x0F, 0x03, 0x0E,
|
||||
},
|
||||
{ /* Init_SR10_SR24 */
|
||||
0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
|
||||
0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xC4, 0x30, 0x02, 0x01, 0x01,
|
||||
},
|
||||
{ /* Init_SR30_SR75 */
|
||||
0x36, 0x03, 0x20, 0x09, 0xC0, 0x36, 0x36, 0x36,
|
||||
0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x03, 0xFF,
|
||||
0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
|
||||
0x20, 0x0C, 0x44, 0x20, 0x00, 0x36, 0x36, 0x36,
|
||||
0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58,
|
||||
0x04, 0x55, 0x59, 0x36, 0x36, 0x00, 0x00, 0x36,
|
||||
0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
|
||||
0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13,
|
||||
0x02, 0x45, 0x30, 0x30, 0x40, 0x20,
|
||||
},
|
||||
{ /* Init_SR80_SR93 */
|
||||
0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x36,
|
||||
0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x36, 0x36,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
},
|
||||
{ /* Init_SRA0_SRAF */
|
||||
0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
|
||||
0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF,
|
||||
},
|
||||
{ /* Init_GR00_GR08 */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
|
||||
0xFF,
|
||||
},
|
||||
{ /* Init_AR00_AR14 */
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x41, 0x00, 0x0F, 0x00, 0x00,
|
||||
},
|
||||
{ /* Init_CR00_CR18 */
|
||||
0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0,
|
||||
0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3,
|
||||
0xFF,
|
||||
},
|
||||
{ /* Init_CR30_CR4D */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20,
|
||||
0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD,
|
||||
0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00,
|
||||
0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57,
|
||||
},
|
||||
{ /* Init_CR90_CRA7 */
|
||||
0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA,
|
||||
0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00,
|
||||
0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00,
|
||||
},
|
||||
},
|
||||
{ /* mode#7: 800 x 600 32Bpp 60Hz */
|
||||
800, 600, 32, 60,
|
||||
/* Init_MISC */
|
||||
0x2B,
|
||||
{ /* Init_SR0_SR4 */
|
||||
0x03, 0x01, 0x0F, 0x03, 0x0E,
|
||||
},
|
||||
{ /* Init_SR10_SR24 */
|
||||
0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
|
||||
0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xC4, 0x30, 0x02, 0x01, 0x01,
|
||||
},
|
||||
{ /* Init_SR30_SR75 */
|
||||
0x34, 0x03, 0x20, 0x09, 0xC0, 0x24, 0x24, 0x24,
|
||||
0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x03, 0xFF,
|
||||
0x00, 0xFC, 0x00, 0x00, 0x20, 0x38, 0x00, 0xFC,
|
||||
0x20, 0x0C, 0x44, 0x20, 0x00, 0x24, 0x24, 0x24,
|
||||
0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58,
|
||||
0x04, 0x55, 0x59, 0x24, 0x24, 0x00, 0x00, 0x24,
|
||||
0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00,
|
||||
0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13,
|
||||
0x02, 0x45, 0x30, 0x35, 0x40, 0x20,
|
||||
},
|
||||
{ /* Init_SR80_SR93 */
|
||||
0x00, 0x00, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x24,
|
||||
0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x24, 0x24,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
},
|
||||
{ /* Init_SRA0_SRAF */
|
||||
0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
|
||||
0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF,
|
||||
},
|
||||
{ /* Init_GR00_GR08 */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
|
||||
0xFF,
|
||||
},
|
||||
{ /* Init_AR00_AR14 */
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x41, 0x00, 0x0F, 0x00, 0x00,
|
||||
},
|
||||
{ /* Init_CR00_CR18 */
|
||||
0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0,
|
||||
0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3,
|
||||
0xFF,
|
||||
},
|
||||
{ /* Init_CR30_CR4D */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20,
|
||||
0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD,
|
||||
0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00,
|
||||
0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57,
|
||||
},
|
||||
{ /* Init_CR90_CRA7 */
|
||||
0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA,
|
||||
0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00,
|
||||
0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00,
|
||||
},
|
||||
},
|
||||
/* We use 1024x768 table to light 1024x600 panel for lemote */
|
||||
{ /* mode#4: 1024 x 600 16Bpp 60Hz */
|
||||
1024, 600, 16, 60,
|
||||
/* Init_MISC */
|
||||
0xEB,
|
||||
{ /* Init_SR0_SR4 */
|
||||
0x03, 0x01, 0x0F, 0x00, 0x0E,
|
||||
},
|
||||
{ /* Init_SR10_SR24 */
|
||||
0xC8, 0x40, 0x14, 0x60, 0x00, 0x0A, 0x17, 0x20,
|
||||
0x51, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xC4, 0x30, 0x02, 0x00, 0x01,
|
||||
},
|
||||
{ /* Init_SR30_SR75 */
|
||||
0x22, 0x03, 0x24, 0x09, 0xC0, 0x22, 0x22, 0x22,
|
||||
0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x03, 0xFF,
|
||||
0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
|
||||
0x20, 0x0C, 0x44, 0x20, 0x00, 0x22, 0x22, 0x22,
|
||||
0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
|
||||
0x00, 0x60, 0x59, 0x22, 0x22, 0x00, 0x00, 0x22,
|
||||
0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00,
|
||||
0x50, 0x03, 0x16, 0x02, 0x0D, 0x82, 0x09, 0x02,
|
||||
0x04, 0x45, 0x3F, 0x30, 0x40, 0x20,
|
||||
},
|
||||
{ /* Init_SR80_SR93 */
|
||||
0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
|
||||
0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
},
|
||||
{ /* Init_SRA0_SRAF */
|
||||
0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
|
||||
0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
|
||||
},
|
||||
{ /* Init_GR00_GR08 */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
|
||||
0xFF,
|
||||
},
|
||||
{ /* Init_AR00_AR14 */
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x41, 0x00, 0x0F, 0x00, 0x00,
|
||||
},
|
||||
{ /* Init_CR00_CR18 */
|
||||
0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
|
||||
0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
|
||||
0xFF,
|
||||
},
|
||||
{ /* Init_CR30_CR4D */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
|
||||
0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
|
||||
0xA3, 0x7F, 0x00, 0x82, 0x0b, 0x6f, 0x57, 0x00,
|
||||
0x5c, 0x0f, 0xE0, 0xe0, 0x7F, 0x57,
|
||||
},
|
||||
{ /* Init_CR90_CRA7 */
|
||||
0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
|
||||
0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
|
||||
},
|
||||
},
|
||||
{ /* mode#5: 1024 x 768 24Bpp 60Hz */
|
||||
1024, 768, 24, 60,
|
||||
/* Init_MISC */
|
||||
0xEB,
|
||||
{ /* Init_SR0_SR4 */
|
||||
0x03, 0x01, 0x0F, 0x03, 0x0E,
|
||||
},
|
||||
{ /* Init_SR10_SR24 */
|
||||
0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
|
||||
0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xC4, 0x30, 0x02, 0x01, 0x01,
|
||||
},
|
||||
{ /* Init_SR30_SR75 */
|
||||
0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
|
||||
0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
|
||||
0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
|
||||
0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
|
||||
0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
|
||||
0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
|
||||
0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
|
||||
0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02,
|
||||
0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
|
||||
},
|
||||
{ /* Init_SR80_SR93 */
|
||||
0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
|
||||
0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
},
|
||||
{ /* Init_SRA0_SRAF */
|
||||
0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
|
||||
0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
|
||||
},
|
||||
{ /* Init_GR00_GR08 */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
|
||||
0xFF,
|
||||
},
|
||||
{ /* Init_AR00_AR14 */
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x41, 0x00, 0x0F, 0x00, 0x00,
|
||||
},
|
||||
{ /* Init_CR00_CR18 */
|
||||
0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
|
||||
0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
|
||||
0xFF,
|
||||
},
|
||||
{ /* Init_CR30_CR4D */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
|
||||
0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
|
||||
0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00,
|
||||
0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF,
|
||||
},
|
||||
{ /* Init_CR90_CRA7 */
|
||||
0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
|
||||
0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
|
||||
},
|
||||
},
|
||||
{ /* mode#4: 1024 x 768 32Bpp 60Hz */
|
||||
1024, 768, 32, 60,
|
||||
/* Init_MISC */
|
||||
0xEB,
|
||||
{ /* Init_SR0_SR4 */
|
||||
0x03, 0x01, 0x0F, 0x03, 0x0E,
|
||||
},
|
||||
{ /* Init_SR10_SR24 */
|
||||
0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
|
||||
0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xC4, 0x32, 0x02, 0x01, 0x01,
|
||||
},
|
||||
{ /* Init_SR30_SR75 */
|
||||
0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
|
||||
0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
|
||||
0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
|
||||
0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
|
||||
0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
|
||||
0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
|
||||
0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
|
||||
0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02,
|
||||
0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
|
||||
},
|
||||
{ /* Init_SR80_SR93 */
|
||||
0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
|
||||
0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
},
|
||||
{ /* Init_SRA0_SRAF */
|
||||
0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
|
||||
0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
|
||||
},
|
||||
{ /* Init_GR00_GR08 */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
|
||||
0xFF,
|
||||
},
|
||||
{ /* Init_AR00_AR14 */
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x41, 0x00, 0x0F, 0x00, 0x00,
|
||||
},
|
||||
{ /* Init_CR00_CR18 */
|
||||
0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
|
||||
0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
|
||||
0xFF,
|
||||
},
|
||||
{ /* Init_CR30_CR4D */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
|
||||
0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
|
||||
0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00,
|
||||
0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF,
|
||||
},
|
||||
{ /* Init_CR90_CRA7 */
|
||||
0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
|
||||
0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
|
||||
},
|
||||
},
|
||||
{ /* mode#6: 320 x 240 16Bpp 60Hz */
|
||||
320, 240, 16, 60,
|
||||
/* Init_MISC */
|
||||
0xEB,
|
||||
{ /* Init_SR0_SR4 */
|
||||
0x03, 0x01, 0x0F, 0x03, 0x0E,
|
||||
},
|
||||
{ /* Init_SR10_SR24 */
|
||||
0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
|
||||
0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xC4, 0x32, 0x02, 0x01, 0x01,
|
||||
},
|
||||
{ /* Init_SR30_SR75 */
|
||||
0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
|
||||
0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
|
||||
0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
|
||||
0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
|
||||
0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
|
||||
0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
|
||||
0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
|
||||
0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43,
|
||||
0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
|
||||
},
|
||||
{ /* Init_SR80_SR93 */
|
||||
0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
|
||||
0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
},
|
||||
{ /* Init_SRA0_SRAF */
|
||||
0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
|
||||
0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
|
||||
},
|
||||
{ /* Init_GR00_GR08 */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
|
||||
0xFF,
|
||||
},
|
||||
{ /* Init_AR00_AR14 */
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x41, 0x00, 0x0F, 0x00, 0x00,
|
||||
},
|
||||
{ /* Init_CR00_CR18 */
|
||||
0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
|
||||
0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
|
||||
0xFF,
|
||||
},
|
||||
{ /* Init_CR30_CR4D */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
|
||||
0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
|
||||
0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00,
|
||||
0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF,
|
||||
},
|
||||
{ /* Init_CR90_CRA7 */
|
||||
0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
|
||||
0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
|
||||
},
|
||||
},
|
||||
|
||||
{ /* mode#8: 320 x 240 32Bpp 60Hz */
|
||||
320, 240, 32, 60,
|
||||
/* Init_MISC */
|
||||
0xEB,
|
||||
{ /* Init_SR0_SR4 */
|
||||
0x03, 0x01, 0x0F, 0x03, 0x0E,
|
||||
},
|
||||
{ /* Init_SR10_SR24 */
|
||||
0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
|
||||
0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xC4, 0x32, 0x02, 0x01, 0x01,
|
||||
},
|
||||
{ /* Init_SR30_SR75 */
|
||||
0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
|
||||
0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
|
||||
0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
|
||||
0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
|
||||
0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
|
||||
0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
|
||||
0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
|
||||
0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43,
|
||||
0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
|
||||
},
|
||||
{ /* Init_SR80_SR93 */
|
||||
0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
|
||||
0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
},
|
||||
{ /* Init_SRA0_SRAF */
|
||||
0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
|
||||
0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
|
||||
},
|
||||
{ /* Init_GR00_GR08 */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
|
||||
0xFF,
|
||||
},
|
||||
{ /* Init_AR00_AR14 */
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x41, 0x00, 0x0F, 0x00, 0x00,
|
||||
},
|
||||
{ /* Init_CR00_CR18 */
|
||||
0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
|
||||
0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
|
||||
0xFF,
|
||||
},
|
||||
{ /* Init_CR30_CR4D */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
|
||||
0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
|
||||
0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00,
|
||||
0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF,
|
||||
},
|
||||
{ /* Init_CR90_CRA7 */
|
||||
0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
|
||||
0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
#define numVGAModes (sizeof(VGAMode) / sizeof(struct ModeInit))
|
|
@ -1,6 +1,6 @@
|
|||
config VT6655
|
||||
tristate "VIA Technologies VT6655 support"
|
||||
depends on PCI
|
||||
depends on PCI && WLAN
|
||||
select WIRELESS_EXT
|
||||
select WEXT_PRIV
|
||||
---help---
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
config VT6656
|
||||
tristate "VIA Technologies VT6656 support"
|
||||
depends on USB
|
||||
depends on USB && WLAN
|
||||
select WIRELESS_EXT
|
||||
select WEXT_PRIV
|
||||
---help---
|
||||
|
|
|
@ -439,7 +439,7 @@ void free_chunks(imgchunk_t *fchunk, unsigned int *nfchunks)
|
|||
}
|
||||
}
|
||||
*nfchunks = 0;
|
||||
memset(fchunk, 0, sizeof(fchunk));
|
||||
memset(fchunk, 0, sizeof(*fchunk));
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1,587 +0,0 @@
|
|||
/*
|
||||
* 2007+ Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __DST_H
|
||||
#define __DST_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/connector.h>
|
||||
|
||||
#define DST_NAMELEN 32
|
||||
#define DST_NAME "dst"
|
||||
|
||||
enum {
|
||||
/* Remove node with given id from storage */
|
||||
DST_DEL_NODE = 0,
|
||||
/* Add remote node with given id to the storage */
|
||||
DST_ADD_REMOTE,
|
||||
/* Add local node with given id to the storage to be exported and used by remote peers */
|
||||
DST_ADD_EXPORT,
|
||||
/* Crypto initialization command (hash/cipher used to protect the connection) */
|
||||
DST_CRYPTO,
|
||||
/* Security attributes for given connection (permissions for example) */
|
||||
DST_SECURITY,
|
||||
/* Register given node in the block layer subsystem */
|
||||
DST_START,
|
||||
DST_CMD_MAX
|
||||
};
|
||||
|
||||
struct dst_ctl
|
||||
{
|
||||
/* Storage name */
|
||||
char name[DST_NAMELEN];
|
||||
/* Command flags */
|
||||
__u32 flags;
|
||||
/* Command itself (see above) */
|
||||
__u32 cmd;
|
||||
/* Maximum number of pages per single request in this device */
|
||||
__u32 max_pages;
|
||||
/* Stale/error transaction scanning timeout in milliseconds */
|
||||
__u32 trans_scan_timeout;
|
||||
/* Maximum number of retry sends before completing transaction as broken */
|
||||
__u32 trans_max_retries;
|
||||
/* Storage size */
|
||||
__u64 size;
|
||||
};
|
||||
|
||||
/* Reply command carries completion status */
|
||||
struct dst_ctl_ack
|
||||
{
|
||||
struct cn_msg msg;
|
||||
int error;
|
||||
int unused[3];
|
||||
};
|
||||
|
||||
/*
|
||||
* Unfortunaltely socket address structure is not exported to userspace
|
||||
* and is redefined there.
|
||||
*/
|
||||
#define SADDR_MAX_DATA 128
|
||||
|
||||
struct saddr {
|
||||
/* address family, AF_xxx */
|
||||
unsigned short sa_family;
|
||||
/* 14 bytes of protocol address */
|
||||
char sa_data[SADDR_MAX_DATA];
|
||||
/* Number of bytes used in sa_data */
|
||||
unsigned short sa_data_len;
|
||||
};
|
||||
|
||||
/* Address structure */
|
||||
struct dst_network_ctl
|
||||
{
|
||||
/* Socket type: datagram, stream...*/
|
||||
unsigned int type;
|
||||
/* Let me guess, is it a Jupiter diameter? */
|
||||
unsigned int proto;
|
||||
/* Peer's address */
|
||||
struct saddr addr;
|
||||
};
|
||||
|
||||
struct dst_crypto_ctl
|
||||
{
|
||||
/* Cipher and hash names */
|
||||
char cipher_algo[DST_NAMELEN];
|
||||
char hash_algo[DST_NAMELEN];
|
||||
|
||||
/* Key sizes. Can be zero for digest for example */
|
||||
unsigned int cipher_keysize, hash_keysize;
|
||||
/* Alignment. Calculated by the DST itself. */
|
||||
unsigned int crypto_attached_size;
|
||||
/* Number of threads to perform crypto operations */
|
||||
int thread_num;
|
||||
};
|
||||
|
||||
/* Export security attributes have this bits checked in when client connects */
|
||||
#define DST_PERM_READ (1<<0)
|
||||
#define DST_PERM_WRITE (1<<1)
|
||||
|
||||
/*
|
||||
* Right now it is simple model, where each remote address
|
||||
* is assigned to set of permissions it is allowed to perform.
|
||||
* In real world block device does not know anything but
|
||||
* reading and writing, so it should be more than enough.
|
||||
*/
|
||||
struct dst_secure_user
|
||||
{
|
||||
unsigned int permissions;
|
||||
struct saddr addr;
|
||||
};
|
||||
|
||||
/*
|
||||
* Export control command: device to export and network address to accept
|
||||
* clients to work with given device
|
||||
*/
|
||||
struct dst_export_ctl
|
||||
{
|
||||
char device[DST_NAMELEN];
|
||||
struct dst_network_ctl ctl;
|
||||
};
|
||||
|
||||
enum {
|
||||
DST_CFG = 1, /* Request remote configuration */
|
||||
DST_IO, /* IO command */
|
||||
DST_IO_RESPONSE, /* IO response */
|
||||
DST_PING, /* Keepalive message */
|
||||
DST_NCMD_MAX,
|
||||
};
|
||||
|
||||
struct dst_cmd
|
||||
{
|
||||
/* Network command itself, see above */
|
||||
__u32 cmd;
|
||||
/*
|
||||
* Size of the attached data
|
||||
* (in most cases, for READ command it means how many bytes were requested)
|
||||
*/
|
||||
__u32 size;
|
||||
/* Crypto size: number of attached bytes with digest/hmac */
|
||||
__u32 csize;
|
||||
/* Here we can carry secret data */
|
||||
__u32 reserved;
|
||||
/* Read/write bits, see how they are encoded in bio structure */
|
||||
__u64 rw;
|
||||
/* BIO flags */
|
||||
__u64 flags;
|
||||
/* Unique command id (like transaction ID) */
|
||||
__u64 id;
|
||||
/* Sector to start IO from */
|
||||
__u64 sector;
|
||||
/* Hash data is placed after this header */
|
||||
__u8 hash[0];
|
||||
};
|
||||
|
||||
/*
|
||||
* Convert command to/from network byte order.
|
||||
* We do not use hton*() functions, since there is
|
||||
* no 64-bit implementation.
|
||||
*/
|
||||
static inline void dst_convert_cmd(struct dst_cmd *c)
|
||||
{
|
||||
c->cmd = __cpu_to_be32(c->cmd);
|
||||
c->csize = __cpu_to_be32(c->csize);
|
||||
c->size = __cpu_to_be32(c->size);
|
||||
c->sector = __cpu_to_be64(c->sector);
|
||||
c->id = __cpu_to_be64(c->id);
|
||||
c->flags = __cpu_to_be64(c->flags);
|
||||
c->rw = __cpu_to_be64(c->rw);
|
||||
}
|
||||
|
||||
/* Transaction id */
|
||||
typedef __u64 dst_gen_t;
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/bio.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/mempool.h>
|
||||
#include <linux/net.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/rbtree.h>
|
||||
|
||||
#ifdef CONFIG_DST_DEBUG
|
||||
#define dprintk(f, a...) printk(KERN_NOTICE f, ##a)
|
||||
#else
|
||||
static inline void __attribute__ ((format (printf, 1, 2)))
|
||||
dprintk(const char *fmt, ...) {}
|
||||
#endif
|
||||
|
||||
struct dst_node;
|
||||
|
||||
struct dst_trans
|
||||
{
|
||||
/* DST node we are working with */
|
||||
struct dst_node *n;
|
||||
|
||||
/* Entry inside transaction tree */
|
||||
struct rb_node trans_entry;
|
||||
|
||||
/* Merlin kills this transaction when this memory cell equals zero */
|
||||
atomic_t refcnt;
|
||||
|
||||
/* How this transaction should be processed by crypto engine */
|
||||
short enc;
|
||||
/* How many times this transaction was resent */
|
||||
short retries;
|
||||
/* Completion status */
|
||||
int error;
|
||||
|
||||
/* When did we send it to the remote peer */
|
||||
long send_time;
|
||||
|
||||
/* My name is...
|
||||
* Well, computers does not speak, they have unique id instead */
|
||||
dst_gen_t gen;
|
||||
|
||||
/* Block IO we are working with */
|
||||
struct bio *bio;
|
||||
|
||||
/* Network command for above block IO request */
|
||||
struct dst_cmd cmd;
|
||||
};
|
||||
|
||||
struct dst_crypto_engine
|
||||
{
|
||||
/* What should we do with all block requests */
|
||||
struct crypto_hash *hash;
|
||||
struct crypto_ablkcipher *cipher;
|
||||
|
||||
/* Pool of pages used to encrypt data into before sending */
|
||||
int page_num;
|
||||
struct page **pages;
|
||||
|
||||
/* What to do with current request */
|
||||
int enc;
|
||||
/* Who we are and where do we go */
|
||||
struct scatterlist *src, *dst;
|
||||
|
||||
/* Maximum timeout waiting for encryption to be completed */
|
||||
long timeout;
|
||||
/* IV is a 64-bit sequential counter */
|
||||
u64 iv;
|
||||
|
||||
/* Secret data */
|
||||
void *private;
|
||||
|
||||
/* Cached temporary data lives here */
|
||||
int size;
|
||||
void *data;
|
||||
};
|
||||
|
||||
struct dst_state
|
||||
{
|
||||
/* The main state protection */
|
||||
struct mutex state_lock;
|
||||
|
||||
/* Polling machinery for sockets */
|
||||
wait_queue_t wait;
|
||||
wait_queue_head_t *whead;
|
||||
/* Most of events are being waited here */
|
||||
wait_queue_head_t thread_wait;
|
||||
|
||||
/* Who owns this? */
|
||||
struct dst_node *node;
|
||||
|
||||
/* Network address for this state */
|
||||
struct dst_network_ctl ctl;
|
||||
|
||||
/* Permissions to work with: read-only or rw connection */
|
||||
u32 permissions;
|
||||
|
||||
/* Called when we need to clean private data */
|
||||
void (* cleanup)(struct dst_state *st);
|
||||
|
||||
/* Used by the server: BIO completion queues BIOs here */
|
||||
struct list_head request_list;
|
||||
spinlock_t request_lock;
|
||||
|
||||
/* Guess what? No, it is not number of planets */
|
||||
atomic_t refcnt;
|
||||
|
||||
/* This flags is set when connection should be dropped */
|
||||
int need_exit;
|
||||
|
||||
/*
|
||||
* Socket to work with. Second pointer is used for
|
||||
* lockless check if socket was changed before performing
|
||||
* next action (like working with cached polling result)
|
||||
*/
|
||||
struct socket *socket, *read_socket;
|
||||
|
||||
/* Cached preallocated data */
|
||||
void *data;
|
||||
unsigned int size;
|
||||
|
||||
/* Currently processed command */
|
||||
struct dst_cmd cmd;
|
||||
};
|
||||
|
||||
struct dst_info
|
||||
{
|
||||
/* Device size */
|
||||
u64 size;
|
||||
|
||||
/* Local device name for export devices */
|
||||
char local[DST_NAMELEN];
|
||||
|
||||
/* Network setup */
|
||||
struct dst_network_ctl net;
|
||||
|
||||
/* Sysfs bits use this */
|
||||
struct device device;
|
||||
};
|
||||
|
||||
struct dst_node
|
||||
{
|
||||
struct list_head node_entry;
|
||||
|
||||
/* Hi, my name is stored here */
|
||||
char name[DST_NAMELEN];
|
||||
/* My cache name is stored here */
|
||||
char cache_name[DST_NAMELEN];
|
||||
|
||||
/* Block device attached to given node.
|
||||
* Only valid for exporting nodes */
|
||||
struct block_device *bdev;
|
||||
/* Network state machine for given peer */
|
||||
struct dst_state *state;
|
||||
|
||||
/* Block IO machinery */
|
||||
struct request_queue *queue;
|
||||
struct gendisk *disk;
|
||||
|
||||
/* Number of threads in processing pool */
|
||||
int thread_num;
|
||||
/* Maximum number of pages in single IO */
|
||||
int max_pages;
|
||||
|
||||
/* I'm that big in bytes */
|
||||
loff_t size;
|
||||
|
||||
/* Exported to userspace node information */
|
||||
struct dst_info *info;
|
||||
|
||||
/*
|
||||
* Security attribute list.
|
||||
* Used only by exporting node currently.
|
||||
*/
|
||||
struct list_head security_list;
|
||||
struct mutex security_lock;
|
||||
|
||||
/*
|
||||
* When this unerflows below zero, university collapses.
|
||||
* But this will not happen, since node will be freed,
|
||||
* when reference counter reaches zero.
|
||||
*/
|
||||
atomic_t refcnt;
|
||||
|
||||
/* How precisely should I be started? */
|
||||
int (*start)(struct dst_node *);
|
||||
|
||||
/* Crypto capabilities */
|
||||
struct dst_crypto_ctl crypto;
|
||||
u8 *hash_key;
|
||||
u8 *cipher_key;
|
||||
|
||||
/* Pool of processing thread */
|
||||
struct thread_pool *pool;
|
||||
|
||||
/* Transaction IDs live here */
|
||||
atomic_long_t gen;
|
||||
|
||||
/*
|
||||
* How frequently and how many times transaction
|
||||
* tree should be scanned to drop stale objects.
|
||||
*/
|
||||
long trans_scan_timeout;
|
||||
int trans_max_retries;
|
||||
|
||||
/* Small gnomes live here */
|
||||
struct rb_root trans_root;
|
||||
struct mutex trans_lock;
|
||||
|
||||
/*
|
||||
* Transaction cache/memory pool.
|
||||
* It is big enough to contain not only transaction
|
||||
* itself, but additional crypto data (digest/hmac).
|
||||
*/
|
||||
struct kmem_cache *trans_cache;
|
||||
mempool_t *trans_pool;
|
||||
|
||||
/* This entity scans transaction tree */
|
||||
struct delayed_work trans_work;
|
||||
|
||||
wait_queue_head_t wait;
|
||||
};
|
||||
|
||||
/* Kernel representation of the security attribute */
|
||||
struct dst_secure
|
||||
{
|
||||
struct list_head sec_entry;
|
||||
struct dst_secure_user sec;
|
||||
};
|
||||
|
||||
int dst_process_bio(struct dst_node *n, struct bio *bio);
|
||||
|
||||
int dst_node_init_connected(struct dst_node *n, struct dst_network_ctl *r);
|
||||
int dst_node_init_listened(struct dst_node *n, struct dst_export_ctl *le);
|
||||
|
||||
static inline struct dst_state *dst_state_get(struct dst_state *st)
|
||||
{
|
||||
BUG_ON(atomic_read(&st->refcnt) == 0);
|
||||
atomic_inc(&st->refcnt);
|
||||
return st;
|
||||
}
|
||||
|
||||
void dst_state_put(struct dst_state *st);
|
||||
|
||||
struct dst_state *dst_state_alloc(struct dst_node *n);
|
||||
int dst_state_socket_create(struct dst_state *st);
|
||||
void dst_state_socket_release(struct dst_state *st);
|
||||
|
||||
void dst_state_exit_connected(struct dst_state *st);
|
||||
|
||||
int dst_state_schedule_receiver(struct dst_state *st);
|
||||
|
||||
void dst_dump_addr(struct socket *sk, struct sockaddr *sa, char *str);
|
||||
|
||||
static inline void dst_state_lock(struct dst_state *st)
|
||||
{
|
||||
mutex_lock(&st->state_lock);
|
||||
}
|
||||
|
||||
static inline void dst_state_unlock(struct dst_state *st)
|
||||
{
|
||||
mutex_unlock(&st->state_lock);
|
||||
}
|
||||
|
||||
void dst_poll_exit(struct dst_state *st);
|
||||
int dst_poll_init(struct dst_state *st);
|
||||
|
||||
static inline unsigned int dst_state_poll(struct dst_state *st)
|
||||
{
|
||||
unsigned int revents = POLLHUP | POLLERR;
|
||||
|
||||
dst_state_lock(st);
|
||||
if (st->socket)
|
||||
revents = st->socket->ops->poll(NULL, st->socket, NULL);
|
||||
dst_state_unlock(st);
|
||||
|
||||
return revents;
|
||||
}
|
||||
|
||||
static inline int dst_thread_setup(void *private, void *data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dst_node_put(struct dst_node *n);
|
||||
|
||||
static inline struct dst_node *dst_node_get(struct dst_node *n)
|
||||
{
|
||||
atomic_inc(&n->refcnt);
|
||||
return n;
|
||||
}
|
||||
|
||||
int dst_data_recv(struct dst_state *st, void *data, unsigned int size);
|
||||
int dst_recv_cdata(struct dst_state *st, void *cdata);
|
||||
int dst_data_send_header(struct socket *sock,
|
||||
void *data, unsigned int size, int more);
|
||||
|
||||
int dst_send_bio(struct dst_state *st, struct dst_cmd *cmd, struct bio *bio);
|
||||
|
||||
int dst_process_io(struct dst_state *st);
|
||||
int dst_export_crypto(struct dst_node *n, struct bio *bio);
|
||||
int dst_export_send_bio(struct bio *bio);
|
||||
int dst_start_export(struct dst_node *n);
|
||||
|
||||
int __init dst_export_init(void);
|
||||
void dst_export_exit(void);
|
||||
|
||||
/* Private structure for export block IO requests */
|
||||
struct dst_export_priv
|
||||
{
|
||||
struct list_head request_entry;
|
||||
struct dst_state *state;
|
||||
struct bio *bio;
|
||||
struct dst_cmd cmd;
|
||||
};
|
||||
|
||||
static inline void dst_trans_get(struct dst_trans *t)
|
||||
{
|
||||
atomic_inc(&t->refcnt);
|
||||
}
|
||||
|
||||
struct dst_trans *dst_trans_search(struct dst_node *node, dst_gen_t gen);
|
||||
int dst_trans_remove(struct dst_trans *t);
|
||||
int dst_trans_remove_nolock(struct dst_trans *t);
|
||||
void dst_trans_put(struct dst_trans *t);
|
||||
|
||||
/*
|
||||
* Convert bio into network command.
|
||||
*/
|
||||
static inline void dst_bio_to_cmd(struct bio *bio, struct dst_cmd *cmd,
|
||||
u32 command, u64 id)
|
||||
{
|
||||
cmd->cmd = command;
|
||||
cmd->flags = (bio->bi_flags << BIO_POOL_BITS) >> BIO_POOL_BITS;
|
||||
cmd->rw = bio->bi_rw;
|
||||
cmd->size = bio->bi_size;
|
||||
cmd->csize = 0;
|
||||
cmd->id = id;
|
||||
cmd->sector = bio->bi_sector;
|
||||
};
|
||||
|
||||
int dst_trans_send(struct dst_trans *t);
|
||||
int dst_trans_crypto(struct dst_trans *t);
|
||||
|
||||
int dst_node_crypto_init(struct dst_node *n, struct dst_crypto_ctl *ctl);
|
||||
void dst_node_crypto_exit(struct dst_node *n);
|
||||
|
||||
static inline int dst_need_crypto(struct dst_node *n)
|
||||
{
|
||||
struct dst_crypto_ctl *c = &n->crypto;
|
||||
/*
|
||||
* Logical OR is appropriate here, but boolean one produces
|
||||
* more optimal code, so it is used instead.
|
||||
*/
|
||||
return (c->hash_algo[0] | c->cipher_algo[0]);
|
||||
}
|
||||
|
||||
int dst_node_trans_init(struct dst_node *n, unsigned int size);
|
||||
void dst_node_trans_exit(struct dst_node *n);
|
||||
|
||||
/*
|
||||
* Pool of threads.
|
||||
* Ready list contains threads currently free to be used,
|
||||
* active one contains threads with some work scheduled for them.
|
||||
* Caller can wait in given queue when thread is ready.
|
||||
*/
|
||||
struct thread_pool
|
||||
{
|
||||
int thread_num;
|
||||
struct mutex thread_lock;
|
||||
struct list_head ready_list, active_list;
|
||||
|
||||
wait_queue_head_t wait;
|
||||
};
|
||||
|
||||
void thread_pool_del_worker(struct thread_pool *p);
|
||||
void thread_pool_del_worker_id(struct thread_pool *p, unsigned int id);
|
||||
int thread_pool_add_worker(struct thread_pool *p,
|
||||
char *name,
|
||||
unsigned int id,
|
||||
void *(* init)(void *data),
|
||||
void (* cleanup)(void *data),
|
||||
void *data);
|
||||
|
||||
void thread_pool_destroy(struct thread_pool *p);
|
||||
struct thread_pool *thread_pool_create(int num, char *name,
|
||||
void *(* init)(void *data),
|
||||
void (* cleanup)(void *data),
|
||||
void *data);
|
||||
|
||||
int thread_pool_schedule(struct thread_pool *p,
|
||||
int (* setup)(void *stored_private, void *setup_data),
|
||||
int (* action)(void *stored_private, void *setup_data),
|
||||
void *setup_data, long timeout);
|
||||
int thread_pool_schedule_private(struct thread_pool *p,
|
||||
int (* setup)(void *private, void *data),
|
||||
int (* action)(void *private, void *data),
|
||||
void *data, long timeout, void *id);
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
#endif /* __DST_H */
|
Loading…
Reference in New Issue